-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Migrate ProgressBar from kaizen-legacy (#4254)
* Migrate ProgressBar from @kaizen/legacy * Update folder architecture * Move Label into subcomponents * Move calculatePercentage into util * Update documentation, stories and add basic tests
- Loading branch information
1 parent
b2cc312
commit 53c59af
Showing
14 changed files
with
484 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@kaizen/components": minor | ||
--- | ||
|
||
Migrate ProgressBar from kaizen-legacy |
88 changes: 88 additions & 0 deletions
88
packages/components/src/ProgressBar/ProgressBar.module.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
@import "~@kaizen/design-tokens/sass/color"; | ||
@import "~@kaizen/design-tokens/sass/spacing"; | ||
|
||
$height: 10px; | ||
|
||
@mixin animation-background($color) { | ||
background: linear-gradient(90deg, transparent, #{$color} 75%, transparent); | ||
} | ||
|
||
.subtext { | ||
color: $color-purple-800; | ||
padding-top: $spacing-6; | ||
text-align: center; | ||
opacity: 80%; | ||
} | ||
|
||
.progressBackground { | ||
width: 100%; | ||
background: $color-gray-300; | ||
border-radius: $height; | ||
height: $height; | ||
overflow: hidden; | ||
position: relative; | ||
} | ||
|
||
@keyframes pulse { | ||
0% { | ||
transform: translateX(-100%); | ||
} | ||
|
||
100% { | ||
transform: translateX(200%); | ||
} | ||
} | ||
|
||
.progress { | ||
position: absolute; | ||
inset: 0; | ||
border-radius: $height; | ||
overflow: hidden; | ||
transition: transform 200ms ease; | ||
} | ||
|
||
.positive { | ||
composes: progress; | ||
background: $color-green-400; | ||
|
||
&::after { | ||
@include animation-background($color-green-300); | ||
} | ||
} | ||
|
||
.informative { | ||
composes: progress; | ||
background: $color-blue-400; | ||
|
||
&::after { | ||
@include animation-background($color-blue-300); | ||
} | ||
} | ||
|
||
.cautionary { | ||
composes: progress; | ||
background: $color-yellow-400; | ||
|
||
&::after { | ||
@include animation-background($color-yellow-300); | ||
} | ||
} | ||
|
||
.negative { | ||
composes: progress; | ||
background: $color-red-400; | ||
} | ||
|
||
.isAnimating { | ||
&::after { | ||
opacity: 100%; | ||
content: ""; | ||
position: absolute; | ||
top: 0; | ||
bottom: 0; | ||
left: 0; | ||
width: 50%; | ||
animation: pulse 2s infinite; | ||
transition: opacity 0.2s; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from "react" | ||
import { render, screen } from "@testing-library/react" | ||
import { ProgressBar } from "./ProgressBar" | ||
|
||
describe("<ProgressBar />", () => { | ||
it("has an accessible progress value expressed as a percentage", () => { | ||
const expectedAccessiblePercent: string = "60" | ||
|
||
render( | ||
<ProgressBar | ||
value={3} | ||
max={5} | ||
label="" | ||
isReversed={false} | ||
isAnimating={false} | ||
mood="positive" | ||
data-testid="id--progress-bar" | ||
/> | ||
) | ||
expect(screen.getByTestId("id--progress-bar")).toHaveAttribute( | ||
"aria-valuenow", | ||
expectedAccessiblePercent | ||
) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import React, { HTMLAttributes } from "react" | ||
import classnames from "classnames" | ||
import { Heading } from "~components/Heading" | ||
import { OverrideClassName } from "~types/OverrideClassName" | ||
import { Label } from "./subcomponents/Label" | ||
import { calculatePercentage } from "./utils/calculatePercentage" | ||
import styles from "./ProgressBar.module.scss" | ||
|
||
export type ProgressBarProps = { | ||
/** A value that represents completed progress */ | ||
value: number | ||
/** A value that sets the maximum progress that can be achieved */ | ||
max: number | ||
/** Adds an animated state to indicate loading progress */ | ||
isAnimating: boolean | ||
mood: Mood | ||
subtext?: string | ||
label?: string | ||
isReversed: boolean | ||
} & OverrideClassName<HTMLAttributes<HTMLDivElement>> | ||
|
||
type Mood = "positive" | "informative" | "negative" | "cautionary" | ||
|
||
/** | ||
* {@link https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3081896891/Progress+Bar Guidance} | | ||
* {@link https://cultureamp.design/?path=/docs/components-progress-bar--docs Storybook} | ||
*/ | ||
export const ProgressBar = ({ | ||
value, | ||
max, | ||
isAnimating, | ||
mood, | ||
subtext, | ||
label, | ||
classNameOverride, | ||
isReversed = false, | ||
...restProps | ||
}: ProgressBarProps): JSX.Element => { | ||
const percentage = calculatePercentage({ value, max }) | ||
return ( | ||
<div | ||
role="progressbar" | ||
aria-valuenow={percentage} | ||
aria-valuemin={0} | ||
aria-valuemax={100} | ||
className={classNameOverride} | ||
{...restProps} | ||
> | ||
{label && <Label content={label} isReversed={isReversed} />} | ||
<div className={styles.progressBackground}> | ||
<div | ||
className={classnames( | ||
styles[mood], | ||
isAnimating && styles.isAnimating | ||
)} | ||
style={{ transform: `translateX(-${100 - percentage}%` }} | ||
/> | ||
</div> | ||
{subtext && ( | ||
<div className={styles.subtext}> | ||
<Heading | ||
variant="heading-6" | ||
tag="p" | ||
color={isReversed ? "white" : "dark"} | ||
> | ||
{subtext} | ||
</Heading> | ||
</div> | ||
)} | ||
</div> | ||
) | ||
} | ||
|
||
ProgressBar.displayName = "ProgressBar" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Canvas, Controls, DocsStory, Meta } from "@storybook/blocks" | ||
import { ResourceLinks, KaioNotification, Installation } from "~storybook/components" | ||
import * as ProgressBarStickersheetStories from "./ProgressBar.stickersheet.stories" | ||
import * as ProgressBarStories from "./ProgressBar.stories" | ||
|
||
<Meta of={ProgressBarStories} /> | ||
|
||
# ProgressBar | ||
|
||
<ResourceLinks | ||
sourceCode="https://github.com/cultureamp/kaizen-design-system/tree/main/packages/components/src/ProgressBar" | ||
figma="https://www.figma.com/file/eZKEE5kXbEMY3lx84oz8iN/%F0%9F%92%9C-UI-Kit%3A-Heart?type=design&node-id=1929%3A20889&mode=design&t=mSqG0g2n5Iquqx6m-1" | ||
designGuidelines="https://cultureamp.atlassian.net/wiki/spaces/DesignSystem/pages/3081896891/Progress+Bar" | ||
className="!mb-8" | ||
/> | ||
|
||
<KaioNotification /> | ||
|
||
<Installation | ||
installCommand="yarn add @kaizen/components" | ||
importStatement='import { ProgressBar } from "@kaizen/components"' | ||
/> | ||
|
||
## Overview | ||
|
||
Progress bars show continuous progress through a process, such as a percentage value. They show how much progress is complete and how much remains. | ||
|
||
<Canvas of={ProgressBarStories.Playground} /> | ||
<Controls of={ProgressBarStories.Playground} /> | ||
|
||
## API | ||
|
||
### isAnimating | ||
|
||
Adds an animated state that indicates system processes, such as downloading, uploading, or processing. | ||
|
||
<Canvas of={ProgressBarStories.IsAnimating} /> | ||
|
||
### Moods | ||
|
||
<Canvas of={ProgressBarStickersheetStories.StickerSheetDefault} /> | ||
|
||
### Value and max | ||
|
||
While `value` and `max` can be used to represent progress as either a percentage or fraction, screen readers will always announce this as a calculated percentage. | ||
|
||
<Canvas of={ProgressBarStories.ValueAndMax} /> | ||
|
||
<DocsStory of={ProgressBarStories.Reversed} /> | ||
|
||
### Accessible context | ||
|
||
Due to the optional `label` prop, the progress bar does not have an accessible name. You can provide context for assistive technologies with aria attributes such as `aria-label` or `aria-labelledby`. | ||
|
||
|
||
<Canvas of={ProgressBarStories.AccessibleName} /> |
101 changes: 101 additions & 0 deletions
101
packages/components/src/ProgressBar/_docs/ProgressBar.stickersheet.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import React from "react" | ||
import { Meta } from "@storybook/react" | ||
import { | ||
StickerSheet, | ||
StickerSheetStory, | ||
} from "~storybook/components/StickerSheet" | ||
import { ProgressBar } from "../index" | ||
|
||
export default { | ||
title: "Components/ProgressBar", | ||
parameters: { | ||
chromatic: { disable: false, pauseAnimationAtEnd: true }, | ||
controls: { disable: true }, | ||
a11y: { | ||
config: { | ||
rules: [ | ||
{ | ||
// `label` is an optional prop so this has no accessible by default. consumers can pass in `aria-labelledby` or `aria-label` which can provide an accessible description pending a refactor. | ||
id: "aria-progressbar-name", | ||
enabled: false, | ||
}, | ||
], | ||
}, | ||
}, | ||
}, | ||
} satisfies Meta | ||
|
||
const StickerSheetTemplate: StickerSheetStory = { | ||
render: ({ isReversed = false }) => ( | ||
<StickerSheet className="w-full" isReversed={isReversed}> | ||
<StickerSheet.Body> | ||
<StickerSheet.Row rowTitle="Positive" rowTitleWidth="100px"> | ||
<ProgressBar | ||
value={25} | ||
max={100} | ||
mood="positive" | ||
isAnimating={false} | ||
label="25%" | ||
subtext="Subtext" | ||
isReversed={isReversed} | ||
/> | ||
</StickerSheet.Row> | ||
<StickerSheet.Row rowTitle="Informative"> | ||
<ProgressBar | ||
value={25} | ||
max={100} | ||
mood="informative" | ||
isAnimating={false} | ||
label="25%" | ||
subtext="Subtext" | ||
isReversed={isReversed} | ||
/> | ||
</StickerSheet.Row> | ||
<StickerSheet.Row rowTitle="Negative"> | ||
<ProgressBar | ||
value={25} | ||
max={100} | ||
mood="negative" | ||
isAnimating={false} | ||
label="25%" | ||
subtext="Subtext" | ||
isReversed={isReversed} | ||
/> | ||
</StickerSheet.Row> | ||
<StickerSheet.Row rowTitle="Cautionary"> | ||
<ProgressBar | ||
value={25} | ||
max={100} | ||
mood="cautionary" | ||
isAnimating={false} | ||
label="25%" | ||
subtext="Subtext" | ||
isReversed={isReversed} | ||
/> | ||
</StickerSheet.Row> | ||
</StickerSheet.Body> | ||
</StickerSheet> | ||
), | ||
} | ||
|
||
export const StickerSheetDefault: StickerSheetStory = { | ||
...StickerSheetTemplate, | ||
name: "Sticker Sheet (Default)", | ||
} | ||
|
||
export const StickerSheetReversed: StickerSheetStory = { | ||
...StickerSheetTemplate, | ||
name: "Sticker Sheet (Reversed)", | ||
parameters: { | ||
backgrounds: { default: "Purple 700" }, | ||
}, | ||
args: { isReversed: true }, | ||
} | ||
|
||
export const StickerSheetRTL: StickerSheetStory = { | ||
...StickerSheetTemplate, | ||
name: "Sticker Sheet (RTL)", | ||
parameters: { | ||
textDirection: "rtl", | ||
}, | ||
} |
Oops, something went wrong.