diff --git a/.changeset/stale-trains-push.md b/.changeset/stale-trains-push.md new file mode 100644 index 00000000000..e4dcc7db912 --- /dev/null +++ b/.changeset/stale-trains-push.md @@ -0,0 +1,5 @@ +--- +"@kaizen/components": minor +--- + +Migrate ProgressBar from kaizen-legacy diff --git a/packages/components/src/ProgressBar/ProgressBar.module.scss b/packages/components/src/ProgressBar/ProgressBar.module.scss new file mode 100644 index 00000000000..a8b09603222 --- /dev/null +++ b/packages/components/src/ProgressBar/ProgressBar.module.scss @@ -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; + } +} diff --git a/packages/components/src/ProgressBar/ProgressBar.spec.tsx b/packages/components/src/ProgressBar/ProgressBar.spec.tsx new file mode 100644 index 00000000000..f2bb7dc4bc9 --- /dev/null +++ b/packages/components/src/ProgressBar/ProgressBar.spec.tsx @@ -0,0 +1,25 @@ +import React from "react" +import { render, screen } from "@testing-library/react" +import { ProgressBar } from "./ProgressBar" + +describe("", () => { + it("has an accessible progress value expressed as a percentage", () => { + const expectedAccessiblePercent: string = "60" + + render( + + ) + expect(screen.getByTestId("id--progress-bar")).toHaveAttribute( + "aria-valuenow", + expectedAccessiblePercent + ) + }) +}) diff --git a/packages/components/src/ProgressBar/ProgressBar.tsx b/packages/components/src/ProgressBar/ProgressBar.tsx new file mode 100644 index 00000000000..c7e962af8d7 --- /dev/null +++ b/packages/components/src/ProgressBar/ProgressBar.tsx @@ -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> + +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 ( +
+ {label &&