diff --git a/cypress/integration/sitemap-vrt/constants.ts b/cypress/integration/sitemap-vrt/constants.ts index 2236b5b160..9b0f2f0c32 100644 --- a/cypress/integration/sitemap-vrt/constants.ts +++ b/cypress/integration/sitemap-vrt/constants.ts @@ -153,6 +153,9 @@ export const SITEMAP = [ "/components/product-switcher/", "/components/product-switcher/api", "/components/product-switcher/changelog", + "/components/progress-bar/", + "/components/progress-bar/api", + "/components/progress-bar/changelog", "/components/progress-steps/", "/components/progress-steps/api", "/components/progress-steps/changelog", diff --git a/packages/paste-core/components/progress-bar/package.json b/packages/paste-core/components/progress-bar/package.json index 5253a90d84..7f0ca574ef 100644 --- a/packages/paste-core/components/progress-bar/package.json +++ b/packages/paste-core/components/progress-bar/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "category": "feedback", "status": "alpha", - "description": "A Progress Bar visually displays the progression/duration of a system operation such as downloading, uploading, or processing information.", + "description": "A Progress Bar communicates the completion status of a process or task.", "author": "Twilio Inc.", "license": "MIT", "main:dev": "src/index.tsx", diff --git a/packages/paste-core/components/progress-bar/stories/index.stories.tsx b/packages/paste-core/components/progress-bar/stories/index.stories.tsx index 958d6a81fe..71a31f9b6d 100644 --- a/packages/paste-core/components/progress-bar/stories/index.stories.tsx +++ b/packages/paste-core/components/progress-bar/stories/index.stories.tsx @@ -1,8 +1,9 @@ import { Anchor } from "@twilio-paste/anchor"; import { Box } from "@twilio-paste/box"; import { Button } from "@twilio-paste/button"; -import { Form, FormControl } from "@twilio-paste/form"; import { HelpText } from "@twilio-paste/help-text"; +import { AcceptIcon } from "@twilio-paste/icons/esm/AcceptIcon"; +import { Separator } from "@twilio-paste/separator"; import { useUID } from "@twilio-paste/uid-library"; import * as React from "react"; @@ -13,8 +14,6 @@ export default { title: "Components/ProgressBar", }; -const NumberFormatter = new Intl.NumberFormat("en-US"); - export const Default = (): React.ReactNode => { const progressBarId = useUID(); const helpTextId = useUID(); @@ -31,7 +30,7 @@ export const Default = (): React.ReactNode => { setRerun(0); return 100; } - const newValue = previousValue + Math.random() * 12; + const newValue = previousValue + Math.random() * 20; /* * intentionally causes another loop for UX so that the @@ -48,11 +47,16 @@ export const Default = (): React.ReactNode => { }, [rerun]); return ( - -
- + + {value >= 100 ? ( + + + Your submission has been approved! + + ) : ( + - Downloading more ram + Reviewing submission { value={value} valueLabel={`${Math.round(value)}%`} /> - - Increasing your ram helps your computer run faster. {NumberFormatter.format(value)}% complete. - - - -
+ Automatically reviewing your submission with our AI agents. +
+ )} + ); }; export const Indeterminate = (): React.ReactNode => { - const progressBarId = useUID(); + const progressBarIdA = useUID(); + const progressBarIdB = useUID(); const helpTextId = useUID(); return ( - -
- - Downloading more ram - - Increasing your ram helps your computer run faster. - -
+ + Uploading sunrise_video.mov... + + + Converting files... + + + Connection lost. Check your connection and refresh the page to get up-to-date information. + ); }; @@ -101,18 +105,14 @@ export const ErrorStory = (): React.ReactNode => { const helpTextId = useUID(); return ( - -
- - - mtn_sunrise.png - - - - Upload failed. Retry upload - - -
+ + + mtn_sunrise.png + + + + Upload failed. Retry upload + ); }; @@ -123,18 +123,14 @@ export const DisabledStory = (): React.ReactNode => { const helpTextId = useUID(); return ( - -
- - - Campaign registration - - - - Your profile is in review. You will receive an email about your application status in 3-5 business days. - - -
+ + + Campaign registration + + + + Your profile is in review. You will receive an email about your application status in 3-5 business days. + ); }; @@ -144,16 +140,12 @@ export const LabelingApproaches = (): React.ReactNode => { const labelId = useUID(); return ( - -
- - Using aria-labelledby - - - Using aria-label - - -
+ + Using aria-labelledby + + + Using aria-label + ); }; @@ -162,15 +154,11 @@ export const CustomRange = (): React.ReactNode => { const progressBarId = useUID(); return ( - -
- - - Friends coming to your birthday - - - -
+ + + mtn_sunrise.png + + ); }; @@ -179,21 +167,17 @@ export const CustomValueText = (): React.ReactNode => { const progressBarId = useUID(); return ( - -
- - - Friends coming to your birthday - - - -
+ + + Friends coming to your birthday + + ); }; diff --git a/packages/paste-website/src/components/shortcodes/StoryPreview.tsx b/packages/paste-website/src/components/shortcodes/StoryPreview.tsx index e64b30dafb..ae40f4cc4c 100644 --- a/packages/paste-website/src/components/shortcodes/StoryPreview.tsx +++ b/packages/paste-website/src/components/shortcodes/StoryPreview.tsx @@ -6,12 +6,18 @@ export interface StoryPreviewProps { storyID: string; title: string; code: string; + height?: string; } const ENV = process.env.NODE_ENV || "development"; const BASE_URL = ENV === "production" ? "https://paste-storybook.twilio.design" : "http://localhost:9001"; -const StoryPreview: React.FC> = ({ storyID, title, code }) => { +const StoryPreview: React.FC> = ({ + storyID, + title, + code, + height = "500px", +}) => { return ( > = ({ st src={`${BASE_URL}/iframe.html?args=&id=${storyID}&viewMode=story`} style={{ width: "100%", - height: "500px", + height, border: 0, overflow: "hidden", padding: "1.5rem", diff --git a/packages/paste-website/src/pages/components/progress-bar/api.mdx b/packages/paste-website/src/pages/components/progress-bar/api.mdx new file mode 100644 index 0000000000..a19956c718 --- /dev/null +++ b/packages/paste-website/src/pages/components/progress-bar/api.mdx @@ -0,0 +1,72 @@ +export const meta = { + title: 'Progress Bar - API', + package: '@twilio-paste/progress-bar', + description: 'A Progress Bar communicates the completion status of a process or task.', + slug: '/components/progress-bar/api', +}; + +import Changelog from '@twilio-paste/progress-bar/CHANGELOG.md'; // I don't know why this is needed but if you remove it the page fails to render +import packageJson from '@twilio-paste/progress-bar/package.json'; + +import {SidebarCategoryRoutes} from '../../../constants'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData, getComponentApi} from '../../../utils/api'; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Progress Bar'); + const {componentApi, componentApiTocData} = getComponentApi('@twilio-paste/progress-bar'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + componentApi, + mdxHeadings: [...mdxHeadings, ...componentApiTocData], + navigationData, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/progress-bar', + storybookUrl: '/?path=/story/components-progressbar--default', + }, + }, + }; +}; + +## Installation + +```bash +yarn add @twilio-paste/progress-bar - or - yarn add @twilio-paste/core +``` + +## Usage + + +```jsx +import {ProgressBar, ProgressBarLabel} from '@twilio-paste/core/progress-bar'; +import {Box} from '@twilio-paste/core/box'; +import {HelpText} from '@twilio-paste/core/help-text'; +import {useUID} from '@twilio-paste/core/uid-library'; + +const AlertDialogExample = () => { + const progressBarId = useUID(); + const helpTextId = useUID(); + + return ( + + Downloading more RAM + + Increasing your RAM helps your computer run faster. + + ); +}; +``` + +## Props + + + + diff --git a/packages/paste-website/src/pages/components/progress-bar/changelog.mdx b/packages/paste-website/src/pages/components/progress-bar/changelog.mdx new file mode 100644 index 0000000000..a0f2832edb --- /dev/null +++ b/packages/paste-website/src/pages/components/progress-bar/changelog.mdx @@ -0,0 +1,38 @@ +export const meta = { + title: 'Progress Bar - Changelog', + package: '@twilio-paste/progress-bar', + description: 'A Progress Bar communicates the completion status of a process or task.', + slug: '/components/progress-bar/changelog', +}; + +import Changelog from '@twilio-paste/progress-bar/CHANGELOG.md'; +import packageJson from '@twilio-paste/progress-bar/package.json'; + +import {SidebarCategoryRoutes} from '../../../constants'; +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; +import {getFeature, getNavigationData} from '../../../utils/api'; + +export default ComponentPageLayout; + +export const getStaticProps = async () => { + const navigationData = await getNavigationData(); + const feature = await getFeature('Progress Bar'); + return { + props: { + data: { + ...packageJson, + ...feature, + }, + navigationData, + mdxHeadings, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/progress-bar', + storybookUrl: '/?path=/story/components-progressbar--default', + }, + }, + }; +}; + + + diff --git a/packages/paste-website/src/pages/components/progress-bar/index.mdx b/packages/paste-website/src/pages/components/progress-bar/index.mdx index 975eab9d02..dd0210b239 100644 --- a/packages/paste-website/src/pages/components/progress-bar/index.mdx +++ b/packages/paste-website/src/pages/components/progress-bar/index.mdx @@ -1,23 +1,24 @@ export const meta = { - title: 'Meter', - package: '@twilio-paste/meter', - description: 'Meter is a visual representation of a numerical value within a known range.', - slug: '/components/meter/', + title: 'Progress Bar', + package: '@twilio-paste/progress-bar', + description: 'A Progress Bar communicates the completion status of a process or task.', + slug: '/components/progress-bar/', }; import Changelog from '@twilio-paste/progress-bar/CHANGELOG.md'; import packageJson from '@twilio-paste/progress-bar/package.json'; -import {InDevelopment} from '../../../components/empty-state/InDevelopment'; -import DefaultLayout from '../../../layouts/DefaultLayout'; + +import ComponentPageLayout from '../../../layouts/ComponentPageLayout'; import {SidebarCategoryRoutes} from '../../../constants'; import {getFeature, getNavigationData} from '../../../utils/api'; -export default DefaultLayout; +export default ComponentPageLayout; + export const getStaticProps = async () => { const navigationData = await getNavigationData(); - const feature = await getFeature('Progress bar'); + const feature = await getFeature('Progress Bar'); return { props: { data: { @@ -25,31 +26,303 @@ export const getStaticProps = async () => { ...feature, }, navigationData, + mdxHeadings, + pageHeaderData: { + categoryRoute: SidebarCategoryRoutes.COMPONENTS, + githubUrl: 'https://github.com/twilio-labs/paste/tree/main/packages/paste-core/components/progress-bar', + storybookUrl: '/?path=/story/components-progressbar--default', + }, }, }; }; - + {value >= 100 ? ( + + + Your submission has been approved! + + ) : ( + + + Reviewing submission + + + Automatically reviewing your submission with our AI agents. + + )} + +`} /> ---- +## Guidelines + +### About Progress Bar + +A Progress Bar communicates the completion status of a process, like +downloads and data processing, or a task, like filling out a form. A +Progress Bar enhances user understanding of where they are in a task +or where the system is in a process. + +### Progress Bar vs. Meter + +A Progress Bar represents only completion progress, like a file upload +or filling out a form. If you're not displaying progress, use a [Meter](/components/meter). + +One way to check if you need a Progress Bar or a Meter is to ask +yourself: _Could you substitute your UI element for [Progress Steps](/components/progress-steps)? +Would it communicate roughly the same intent?_ If yes, then Progress +Bar is probably the right element to use. + + +### Progress Bar vs. Progress Steps + +Use Progress Bar for tasks that are short, straightforward, and linear +that don't need the extra layer of information that Progress Steps +provides. Example: A sign-up flow that a customer can reasonably +complete without leaving the flow. + +In contrast, [Progress Steps](/components/progress-steps) are a visual representation of a complex +task broken up into multiple steps. They indicate what has and what +needs to be done to fully complete the task. Use Progress Steps when +the task is nonlinear or can't be completed in one sitting. Example: +A task that requires a customer to go to a third-party application +to configure their settings before returning to Twilio to complete +the full task. + + +### Accessibility + +- A label is required when using Progress Bar. Use one of these options: + - Visible label using `ProgressBarLabel`, with `htmlFor` set equal to + the `id` of the Progress Bar (preferred) + - Visible label that's associated to the Progress Bar with `aria-labelledby` + - Label directly using `aria-label` +- A numerical `value` is required, between 0 and any maximum value provided. + + +## Examples + +### Default + +Use a Progress Bar to communicate the completion status of a process or task. +Use the `valueLabel` prop to show a visible value. + +If you don't show a visible value, communicate what kind of process is +happening through `ProgressBarLabel`. For example, the Progress Bar Label should say +“Uploading filename.png…” not just “filename.png” if you don't show the completion percentage. +If the label starts with a verb and the Progress Bar is not disabled, use an ellipsis at the +end of the label. + + + + {value >= 100 ? ( + + + Your submission has been approved! + + ) : ( + + + Reviewing submission + + + Automatically reviewing your submission with our AI agents. + + )} + +
`} +/> + +When the process or task is complete, swap the Progress Bar out with an +element that represents the completed process or task. For example, for +a file upload, that could be a card representing the file. + + +### Min and max values + +By default, Progress Bar has a value of 0 (represented as a percentage) +and range of 0 to 100. Pass `maxValue` to Progress Bar to set a custom +max value. The min value is always 0. + +To show a visible max value, use the `valueLabel` prop to show +“[current value] of [max value]”. Consider what type of value would +be most useful for a user. For example, choose either “50%” or “5,000 +of 10,000”, not both. + + + + mtn_sunrise.png + +`} +/> + +## States + +### Indeterminate + +Use an indeterminate Progress Bar when progress is being made, but +you can't calculate how much progress or you don't know the value. +This is common when computing the progress value interferes with +showing an accurate value, or when connection is lost but the +process is still continuing. + +For indeterminate states, communicate what kind of process is +happening through `ProgressBarLabel`. If the label starts with a +verb, use an ellipsis at the end of the label. For example, the +Progress Bar Label should say “Uploading filename.png…” not just +“filename.png”. + +Uploading sunrise_video.mov... + + + + +Converting files... + + + Connection lost. Check your connection and refresh the page to get up-to-date information. +`} +/> + +### Error + +Use the error state to show a process has stopped, and the user +must do something to continue it. + +Use [error Help Text](/components/help-text#error-help-text) to +describe the error and what needs to be done to fix it. For +additional guidance on how to compose error messages, refer +to the [error state pattern](/patterns/error-state). + + + mtn_sunrise.png + + + + Upload failed. Retry upload +`} +/> + +### Disabled + +Use a disabled Progress Bar to show a task has stopped, and +the system needs to do something before the user can continue +the task. Let users know when they can expect their next steps. + +Do not include an ellipsis on a disabled Progress Bar. + + + Campaign registration + + + + Your profile is in review. You will receive an email about your application status in 3-5 business days. +`} +/> + +## Composition Notes + +The Progress Bar label should communicate what the Progress Bar +is measuring. Where possible, avoid a label that wraps onto two lines. + +A Progress Bar can include a numerical value through `valueLabel`. +When using a custom value label, consider what type of value would +be most useful for a user to see (for example, “50%” vs. “5000 of 10,000”). - +If you don't show a visible value through `valueLabel`, or if the +Progress Bar is indeterminate, communicate what kind of process is +happening through `ProgressBarLabel`. If the label starts with a +verb and the Progress Bar is not disabled, use an ellipsis at the +end of the label. For example, the Progress Bar Label should say +“Uploading filename.png…” not just “filename.png”. - +Use Help Text to offer additional information to contextualize or +help the user understand the Progress Bar, especially if the +process is complex or has a long wait time to better communicate +current status with users. - - +## When to use Progress Bar - - - + + + + - + + + + - + + + +