Skip to content

Commit

Permalink
Merge pull request #241 from US-CBP/feature/loader_requirements
Browse files Browse the repository at this point in the history
Loader component
  • Loading branch information
bagrub authored Jan 21, 2025
2 parents c5426a2 + 5ea7087 commit 11f2662
Show file tree
Hide file tree
Showing 6 changed files with 455 additions and 27 deletions.
5 changes: 5 additions & 0 deletions packages/web-components/src/components/cbp-icon/cbp-icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ export class CbpIcon {
viewbox: "0 0 448 512",
path: "M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z",
},
"check-circle": {
name: 'check-circle',
viewbox: '0 0 512 512',
path : "M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z",
},
"chevron-right": {
name: "chevron-right",
viewbox: "0 0 320 512",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Meta, Markdown } from "@storybook/blocks";
import Docs from './readme.md?raw';

<Meta title="Components/Loader/API Docs" />

<Markdown>{Docs}</Markdown>
249 changes: 248 additions & 1 deletion packages/web-components/src/components/cbp-loader/cbp-loader.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,250 @@
/**
* @Prop --cbp-loader-color: var(--cbp-color-info-dark);
* @Prop --cbp-loader-color-dark: var(--cbp-color-info-light);
* @Prop --cbp-loader-center-color: var(--cbp-color-branding-cbp-light);
* @Prop --cbp-loader-center-color-dark: var(--cbp-color-branding-cbp-dark);
* @Prop --cbp-loader-track-color: var(--cbp-color-gray-cool-20);
* @Prop --cbp-loader-track-color-dark: var(--cbp-color-gray-cool-60);
* @Prop --cbp-loader-status-description-color: var(--cbp-color-text-darkest);
* @Prop --cbp-loader-status-description-color-dark: var(--cbp-color-text-lightest);
* @Prop --cbp-loader-status-indicator-color: var(--cbp-color-white);
* @Prop --cbp-loader-status-indicator-color-dark: var(--cbp-color-black);
* @Prop --cbp-loader-linear-height: var(--cbp-space-2x);
* @Prop --cbp-loader-linear-width: 100%;
* @Prop --cbp-loader-linear-status-width: var(--cbp-loader-linear-width);
* @Prop --cbp-loader-linear-flex-direction: column;
* @Prop --cbp-loader-linear-gap: var(--cbp-space-2x);
* @Prop --cbp-loader-diameter: var(--cbp-space-12x);
* @Prop --cbp-loader-gutter-width: var(--cbp-space-2x);
* @Prop --cbp-loader-status-indicator-diameter: var(--cbp-space-4x);
* @Prop --cbp-loader-circular-determinate: var(--cbp-loader-track-color);
*/

:root{
--cbp-loader-color: var(--cbp-color-info-dark);
--cbp-loader-color-dark: var(--cbp-color-info-light);
--cbp-loader-center-color: var(--cbp-color-branding-cbp-light);
--cbp-loader-center-color-dark: var(--cbp-color-branding-cbp-dark);
--cbp-loader-track-color: var(--cbp-color-gray-cool-20);
--cbp-loader-track-color-dark: var(--cbp-color-gray-cool-60);

--cbp-loader-status-description-color: var(--cbp-color-text-darkest);
--cbp-loader-status-description-color-dark: var(--cbp-color-text-lightest);
--cbp-loader-status-description-line-height: 3.5;
--cbp-loader-status-indicator-color: var(--cbp-color-white);
--cbp-loader-status-indicator-color-dark: var(--cbp-color-black);

--cbp-loader-linear-height: var(--cbp-space-2x);
--cbp-loader-linear-width: 100%;
--cbp-loader-linear-status-width: var(--cbp-loader-linear-width);
--cbp-loader-linear-flex-direction: column;
--cbp-loader-linear-gap: var(--cbp-space-2x);

--cbp-loader-diameter: var(--cbp-space-12x);
--cbp-loader-gutter-width: var(--cbp-space-2x);

--cbp-loader-status-indicator-diameter: var(--cbp-space-4x);

--cbp-loader-circular-determinate: var(--cbp-loader-track-color);
}

[data-cbp-theme=light] cbp-loader[context*=dark]:not([context=light-always]),
[data-cbp-theme=dark] cbp-loader:not([context=dark-inverts]):not([context=light-always]) {

--cbp-loader-color: var(--cbp-loader-color-dark);
--cbp-loader-center-color: var(--cbp-loader-center-color-dark);
--cbp-loader-track-color: var(--cbp-loader-track-color-dark);

--cbp-loader-status-description-color: var(--cbp-loader-status-description-color-dark);
--cbp-loader-status-indicator-color: var(--cbp-loader-status-indicator-color-dark);}

@keyframes spin {
0% {clip-path:polygon(50% 50%,0 0,0 0,0 0,0 0,0 0)}
25% {clip-path:polygon(50% 50%,0 0,100% 0,100% 0,100% 0,100% 0)}
50% {clip-path:polygon(50% 50%,0 0,100% 0,100% 100%,100% 100%,100% 100%)}
75% {clip-path:polygon(50% 50%,0 0,100% 0,100% 100%,0 100%,0 100%)}
100% {clip-path:polygon(50% 50%,0 0,100% 0,100% 100%,0 100%,0 0)}
}

@keyframes slide {
0%{transform: translateX(0%);}
100%{transform: translateX(400%);}
}

cbp-loader {
display: block;

/** styling for the linear variant of the loader*/
&[variant="linear"]{
height: var(--cbp-loader-linear-height);
width: var(--cbp-loader-linear-width);
display: inline-flex;
flex-direction: var(--cbp-loader-linear-flex-direction);
align-items: center;
gap: var(--cbp-loader-linear-gap);

progress{
appearance: none; //Needed to use the below psuedo classes/ affect the progress styles
display: inline-block;

&::-webkit-progress-bar{
background-color: var(--cbp-loader-track-color);
}

&::-webkit-progress-value{
background-color: var(--cbp-loader-color);
}
}

&:not([determinate]):not([error]):not([success]) progress:before{
content: '';
display: block;
height: var(--cbp-loader-linear-height);
width: 20%;
background-color: var(--cbp-loader-color);
position: absolute;
animation: slide 2s cubic-bezier(0.2, 0, 0.38, 0.9) infinite;
}

&[determinate]{

label{
color: var(--cbp-loader-status-description-color);
display: inline-flex;
width: var(--cbp-loader-linear-status-width);
height: var(--cbp-space-4x);
white-space: nowrap;

span:last-of-type{
margin-left: auto
}
}
}
}

/** styling for the circular variant of the loader*/
&[variant="circular"]{
height: var(--cbp-loader-diameter);
width: var(--cbp-loader-diameter);
display: inline-flex;

progress{
display: flex;
align-items: center;
justify-content: center;
border-radius: var(--cbp-border-radius-circle);
overflow: hidden;
padding: 0;

//hide the visuals for the value/max relationship for the cirular loader.
&::-webkit-progress-bar{
display: none;
}

&:before{
content: "";
position: absolute;
z-index: var(--cbp-z-index-level-1);
height: var(--cbp-loader-diameter);
width: var(--cbp-loader-diameter);
border-radius: calc(var(--cbp-border-radius-circle) / 2);
margin: auto auto;
background: var(--cbp-loader-color);

}

&:after{
content: "";
position: absolute;
z-index: var(--cbp-z-index-level-2);
height: calc(var(--cbp-loader-diameter) - var(--cbp-loader-gutter-width));
width: calc(var(--cbp-loader-diameter) - var(--cbp-loader-gutter-width));
border-radius: calc(var(--cbp-border-radius-circle) / 2);
margin: auto auto;
background: var(--cbp-loader-center-color);

}
}

&:not([determinate]):not([error]):not([success]) ::before{
animation: spin 2s linear infinite;
}

&[determinate]{

progress{

&:before{
background: var(--cbp-loader-circular-determinate);
}
}

.cbp-loader-desc{
position: absolute;
width: inherit;
line-height: var(--cbp-loader-status-description-line-height);
text-align: center;
z-index: var(--cbp-z-index-level-3);
color: var(--cbp-loader-color);
font-weight: var(--cbp-font-weight-bold);
}
}
}

/** Color variations for Loader */
&[error]{
--cbp-loader-color: var(--cbp-color-danger-dark);
--cbp-loader-color-dark: var(--cbp-color-danger-light);
--cbp-loader-track-color: var(--cbp-color-danger-dark);
--cbp-loader-track-color-dark: var(--cbp-color-danger-light);
--cbp-loader-status-description-color: var(--cbp-color-danger-dark);
--cbp-loader-status-description-color-dark: var(--cbp-color-danger-light);
--cbp-loader-status-indicator-color: var(--cbp-color-danger-base);
--cbp-loader-status-indicator-color-dark: var(--cbp-color-danger-light);

}

&[success]{
--cbp-loader-color: var(--cbp-color-success-dark);
--cbp-loader-color-dark: var(--cbp-color-success-light);
--cbp-loader-track-color: var(--cbp-color-success-dark);
--cbp-loader-track-color-dark: var(--cbp-color-success-light);
--cbp-loader-status-description-color: var(--cbp-color-success-base);
--cbp-loader-status-description-color-dark: var(--cbp-color-success-light);
--cbp-loader-status-indicator-color: var(--cbp-color-success-base);
--cbp-loader-status-indicator-color-dark: var(--cbp-color-success-light);
}

/** Size variations for Loader */

&[size="large"]{
--cbp-loader-diameter: var(--cbp-space-12x);
--cbp-loader-gutter-width: var(--cbp-space-2x);
--cbp-loader-linear-height: var(--cbp-space-2x);
--cbp-loader-linear-flex-direction: column;
--cbp-loader-linear-status-width: var(--cbp-loader-linear-width);
--cbp-loader-linear-gap: var(--cbp-space-2x);

&[determinate]{
--cbp-loader-linear-height: calc(var(--cbp-space-2x) + var(--cbp-space-4x) + var(--cbp-space-2x));
}
}

&[size="small"]{
--cbp-loader-diameter: var(--cbp-space-4x);
--cbp-loader-gutter-width: var(--cbp-space-1x); --cbp-loader-linear-height: var(--cbp-space-1x);
--cbp-loader-linear-flex-direction: row;
--cbp-loader-linear-status-width: min-content;
--cbp-loader-linear-gap: var(--cbp-space-1x);
}

/** generic style reset/ cross variant styles */
progress{
height: inherit;
width: inherit;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,39 @@ import { Meta } from '@storybook/addon-docs';

## Purpose

* the loader is used to have a visual indicator of progress during waiting periods for the User
* the Loader is used to have a visual indicator of progress during waiting periods for the User

## Functional Requirements

* Loader will render as 'progress' while loading and will either finish as a 'success' or an 'error'
* Please note the 'error' state does not display details about the error, only changes the visual state of the loader component
* Loader will render as 'progress' while loading and will either finish as a 'success' or an 'error' as determined by app logic
* Please note the 'error' state does not display details about the error, only changes the visual state of the Loader component
* In both circular and linear forms both the 'success' & 'error' state have associated icons which are not present in the 'progress' state
* Text text for the describing the current state is present in the circular loader small size & in both sizes of the linear loader

* The text for the describing the current state is present in the circular Loader small size & in both sizes of the linear Loader

## Technical Specifications

* use HTML tag progress for the render
* Variant property is used to specify if the render returns a circular loader or a linear progress bar
* Color property is used to determine the visual state of the loader. options include progress, success, & error
* Size property is used to determine the size of rendered loader. options include small or large
* Determinate is used to determine if the loader is displaying the progress completed. options include determinate or indeterminate
*TODO: determinate may not be the best name for this prop. need to look into other systems to see what makes sense
* Determinate needs both a current & total value as props(?) to be able to display as current / total (include a min value default it to 0)
* make this a boolean if, if set to true it is displaying determinate
* that determinate have an optional additional prop for unit to be display instead of percentage
* Variant property is used to specify if the render returns a circular Loader or a linear Loader
* Success is a property used indicate when the Loader has finished successfuly. Setting the boolean to be true will change the associated color & icons
* Error is a property used indicate when the Loader has an issue and has stopped. Setting the boolean to be true will change the associated color & icons
* Size property is used to determine the size of rendered Loader. options include small or large
* Determinate is used to determine if the Loader is displaying the progress completed. Loader will default to indeterminate but if value is true it will support the below props as a determinate loader
* Value specifics how much of the current task is completed. this is used to populate the html attribute value of the progress
* Max specifies the current task requires, meeting this would be considered 'complete'. this is uesed to populate the html attribute max of the progress
* Uid is used to set a unique id for the component, users can set a custom value or used the default generated value prefixed by 'cbp-loader'

### User Interactions

* the loader doesn't have any user interactions (hover, focus, selected, or disabled)
* The Success and Error properties are independent, allowing the app logic to determine what state is appropriate. If both are set to true then the success override the error colors & icon
* the Loader doesn't have any user interactions (hover, focus, selected, or disabled)

### Responsiveness

* linear loaders are 100% width to match parents spacing, circular loaders will are set with specific width/height
* linear Loaders are 100% width to match parents spacing, circular Loaders will are set with specific width/height

### Accessibility

* the loader will have a role of 'progressbar' for screen readers
* aria-busy to be added will the loader is 'in process' and removed when complete or no longer running
* the 'value' value of the progress ( or aria-valuenow if render is different ) would map to the determinate variant current value prop
* the 'max' value of the progress ( or aria-valuemax if render is different ) would map to the determinate variant total value prop
* aria-label or aria-labelledby would display a description of the loader
* aria-labelledby is added to the slotted label of text for the Loader. this is visible in the determinate linear case of the component

### Additional Notes and Considerations

* TODO: good resource for developement: https://mui.com/material-ui/react-progress/?srsltid=AfmBOorlhwpo9rkA2LOPLIeJMc-BtjAfFuj4ZKcWcwY6uTsdXaTN4sHd
* See documentation for progress tag: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/progress
Loading

0 comments on commit 11f2662

Please sign in to comment.