From fec05321858751a91848d1d636fba30f3d8dd8b5 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Wed, 26 Jul 2023 17:25:41 +0300 Subject: [PATCH 01/26] Components: Introduce a basic ProgressBar --- docs/manifest.json | 6 ++ packages/components/src/index.ts | 1 + .../components/src/progress-bar/README.md | 47 +++++++++++ .../components/src/progress-bar/index.tsx | 42 ++++++++++ .../src/progress-bar/stories/index.tsx | 35 ++++++++ .../components/src/progress-bar/style.scss | 37 +++++++++ .../test/__snapshots__/index.tsx.snap | 51 ++++++++++++ .../src/progress-bar/test/index.tsx | 83 +++++++++++++++++++ packages/components/src/progress-bar/types.ts | 21 +++++ packages/components/src/style.scss | 1 + 10 files changed, 324 insertions(+) create mode 100644 packages/components/src/progress-bar/README.md create mode 100644 packages/components/src/progress-bar/index.tsx create mode 100644 packages/components/src/progress-bar/stories/index.tsx create mode 100644 packages/components/src/progress-bar/style.scss create mode 100644 packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap create mode 100644 packages/components/src/progress-bar/test/index.tsx create mode 100644 packages/components/src/progress-bar/types.ts diff --git a/docs/manifest.json b/docs/manifest.json index 5f75e49924f355..a6ca6fb7503a61 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1115,6 +1115,12 @@ "markdown_source": "../packages/components/src/popover/README.md", "parent": "components" }, + { + "title": "ProgressBar", + "slug": "progress-bar", + "markdown_source": "../packages/components/src/progress-bar/README.md", + "parent": "components" + }, { "title": "QueryControls", "slug": "query-controls", diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index b17d82a81bee67..ee69b80e11636f 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -128,6 +128,7 @@ export { default as PanelHeader } from './panel/header'; export { default as PanelRow } from './panel/row'; export { default as Placeholder } from './placeholder'; export { default as Popover } from './popover'; +export { default as __experimentalProgressBar } from './progress-bar'; export { default as QueryControls } from './query-controls'; export { default as __experimentalRadio } from './radio-group/radio'; export { default as __experimentalRadioGroup } from './radio-group'; diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md new file mode 100644 index 00000000000000..ba5dd434f9a4ea --- /dev/null +++ b/packages/components/src/progress-bar/README.md @@ -0,0 +1,47 @@ +# ProgressBar + +A simple horizontal progress bar component. + +Supports two modes: determinate and indeterminate. A progress bar is determinate when a specific progress value has been specified (from 0 to 100), and indeterminate when a value hasn't been specified. + +### Usage + +```jsx +/** + * WordPress dependencies + */ +import { __experimentalProgressBar as ProgressBar } from '@wordpress/components'; + +export const MyProgressBar = () => { + return ; +}; +``` + +### Props + +The component accepts the following props: + +#### `value`: `number` + +The progress value, a number from 0 to 100. +If a `value` is not specified, the progress bar will be considered indeterminate. + +- Required: No + +#### `trackColor`: `string` + +Optional color of the progress bar track. + +- Required: No + +#### `indicatorColor`: `string` + +Optional color of the progress bar indicator. + +- Required: No + +##### `className`: `string` + +A CSS class to apply to the underlying `div` element, serving as a progress bar track. + +- Required: No diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx new file mode 100644 index 00000000000000..7d573eca95fc90 --- /dev/null +++ b/packages/components/src/progress-bar/index.tsx @@ -0,0 +1,42 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * Internal dependencies + */ +import type { ProgressBarProps } from './types'; +import type { WordPressComponentProps } from '../ui/context'; + +// Width of the indicator for the indeterminate progress bar +export const INDETERMINATE_TRACK_WIDTH = 50; + +export function ProgressBar( + props: WordPressComponentProps< ProgressBarProps, 'div', false > +) { + const { className, value, indicatorColor, trackColor } = props; + const isIndeterminate = ! Number.isFinite( value ); + const wrapperClasses = classnames( 'components-progress-bar', className, { + 'is-indeterminate': isIndeterminate, + } ); + const trackStyle = { + backgroundColor: trackColor ? trackColor : undefined, + }; + const indicatorStyle = { + width: `${ isIndeterminate ? INDETERMINATE_TRACK_WIDTH : value }%`, + backgroundColor: indicatorColor ? indicatorColor : undefined, + }; + + return ( +
+
+ +
+ ); +} + +export default ProgressBar; diff --git a/packages/components/src/progress-bar/stories/index.tsx b/packages/components/src/progress-bar/stories/index.tsx new file mode 100644 index 00000000000000..217a1930418750 --- /dev/null +++ b/packages/components/src/progress-bar/stories/index.tsx @@ -0,0 +1,35 @@ +/** + * External dependencies + */ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; + +/** + * Internal dependencies + */ +import { ProgressBar } from '..'; + +const meta: ComponentMeta< typeof ProgressBar > = { + component: ProgressBar, + title: 'Components/ProgressBar', + argTypes: { + indicatorColor: { control: { type: 'color' } }, + trackColor: { control: { type: 'color' } }, + value: { control: { type: 'number', min: 0, max: 100, step: 1 } }, + }, + parameters: { + controls: { + expanded: true, + }, + docs: { source: { state: 'open' } }, + }, +}; +export default meta; + +const Template: ComponentStory< typeof ProgressBar > = ( { ...args } ) => { + return ; +}; + +export const Default: ComponentStory< typeof ProgressBar > = Template.bind( + {} +); +Default.args = {}; diff --git a/packages/components/src/progress-bar/style.scss b/packages/components/src/progress-bar/style.scss new file mode 100644 index 00000000000000..7e28a6437ea655 --- /dev/null +++ b/packages/components/src/progress-bar/style.scss @@ -0,0 +1,37 @@ +.components-progress-bar { + position: relative; + overflow: hidden; + width: 100%; + height: 5px; + background-color: $components-color-gray-100; + + progress { + display: none; + } + + .components-progress-bar__indicator { + display: inline-block; + position: absolute; + top: 0; + height: 100%; + background-color: $components-color-accent; + } + + &.is-indeterminate .components-progress-bar__indicator { + animation-duration: 1.5s; + animation-timing-function: ease-in-out; + animation-iteration-count: infinite; + animation-name: progress-bar-indication; + + @include reduce-motion("animation"); + } +} + +@keyframes progress-bar-indication { + from { + left: -50%; + } + to { + left: 100%; + } +} diff --git a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap new file mode 100644 index 00000000000000..7687837b9ba0f4 --- /dev/null +++ b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ProgressBar should be able to specify custom track and indicator colors 1`] = ` +
+
+
+ +
+
+`; + +exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\` is not provided 1`] = ` +
+
+
+ +
+
+`; + +exports[`ProgressBar should not have an \`is-indeterminate\` className if \`value\` is provided 1`] = ` +
+
+
+ +
+
+`; diff --git a/packages/components/src/progress-bar/test/index.tsx b/packages/components/src/progress-bar/test/index.tsx new file mode 100644 index 00000000000000..2ad7da2933c4f6 --- /dev/null +++ b/packages/components/src/progress-bar/test/index.tsx @@ -0,0 +1,83 @@ +/** + * External dependencies + */ +import { render, screen } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import { ProgressBar, INDETERMINATE_TRACK_WIDTH } from '..'; + +describe( 'ProgressBar', () => { + it( 'should render an indeterminate semantic progress bar element', () => { + render( ); + + const progressBar = screen.getByRole( 'progressbar' ); + + expect( progressBar ).toBeVisible(); + expect( progressBar ).not.toHaveValue(); + } ); + + it( 'should render a determinate semantic progress bar element', () => { + render( ); + + const progressBar = screen.getByRole( 'progressbar' ); + + expect( progressBar ).toBeVisible(); + expect( progressBar ).toHaveValue( 55 ); + } ); + + it( 'should use `INDETERMINATE_TRACK_WIDTH`% as track width for indeterminate progress bar', () => { + const { container } = render( ); + + /** + * We're intentionally not using an accessible selector, because + * the track is an intentionally non-interactive presentation element. + */ + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const indicator = container.querySelector( + '.components-progress-bar__indicator' + ); + + expect( indicator ).toHaveStyle( { + width: `${ INDETERMINATE_TRACK_WIDTH }%`, + } ); + } ); + + it( 'should use `value`% as width for determinate progress bar', () => { + const { container } = render( ); + + /** + * We're intentionally not using an accessible selector, because + * the track is an intentionally non-interactive presentation element. + */ + // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access + const indicator = container.querySelector( + '.components-progress-bar__indicator' + ); + + expect( indicator ).toHaveStyle( { + width: '55%', + } ); + } ); + + it( 'should have an `is-indeterminate` className if `value` is not provided', () => { + const { container } = render( ); + + expect( container ).toMatchSnapshot(); + } ); + + it( 'should not have an `is-indeterminate` className if `value` is provided', () => { + const { container } = render( ); + + expect( container ).toMatchSnapshot(); + } ); + + it( 'should be able to specify custom track and indicator colors', () => { + const { container } = render( + + ); + + expect( container ).toMatchSnapshot(); + } ); +} ); diff --git a/packages/components/src/progress-bar/types.ts b/packages/components/src/progress-bar/types.ts new file mode 100644 index 00000000000000..986143381d5a39 --- /dev/null +++ b/packages/components/src/progress-bar/types.ts @@ -0,0 +1,21 @@ +/** + * External dependencies + */ +import type { CSSProperties } from 'react'; + +export type ProgressBarProps = { + /** + * Value of the progress bar. + */ + value?: number; + + /** + * Color of the progress bar indicator. + */ + indicatorColor?: CSSProperties[ 'color' ]; + + /** + * Color of the progress bar track. + */ + trackColor?: CSSProperties[ 'color' ]; +}; diff --git a/packages/components/src/style.scss b/packages/components/src/style.scss index 02dce83f66dcc6..2fa0b30bbf949c 100644 --- a/packages/components/src/style.scss +++ b/packages/components/src/style.scss @@ -39,6 +39,7 @@ @import "./panel/style.scss"; @import "./placeholder/style.scss"; @import "./popover/style.scss"; +@import "./progress-bar/style.scss"; @import "./radio-control/style.scss"; @import "./resizable-box/style.scss"; @import "./responsive-wrapper/style.scss"; From 5452f8a064e64d81014c43dbf7ba2428481e19d5 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 27 Jul 2023 15:12:04 +0300 Subject: [PATCH 02/26] Add a CHANGELOG entry --- packages/components/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index c903989f456288..d2bc4e93cf85af 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### New Feature + +- Add a new `ProgressBar` component. ([#53030](https://github.com/WordPress/gutenberg/pull/53030)). + ### Enhancements - `ColorPalette`, `BorderControl`: Don't hyphenate hex value in `aria-label` ([#52932](https://github.com/WordPress/gutenberg/pull/52932)). From cafb1d86f78ff2937783a07010b69efdfc41500a Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 27 Jul 2023 16:14:57 +0300 Subject: [PATCH 03/26] Expose as a private API --- packages/components/src/index.ts | 1 - packages/components/src/private-apis.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/src/index.ts b/packages/components/src/index.ts index ee69b80e11636f..b17d82a81bee67 100644 --- a/packages/components/src/index.ts +++ b/packages/components/src/index.ts @@ -128,7 +128,6 @@ export { default as PanelHeader } from './panel/header'; export { default as PanelRow } from './panel/row'; export { default as Placeholder } from './placeholder'; export { default as Popover } from './popover'; -export { default as __experimentalProgressBar } from './progress-bar'; export { default as QueryControls } from './query-controls'; export { default as __experimentalRadio } from './radio-group/radio'; export { default as __experimentalRadioGroup } from './radio-group'; diff --git a/packages/components/src/private-apis.ts b/packages/components/src/private-apis.ts index 641ba5c26d40b6..b144f348143c60 100644 --- a/packages/components/src/private-apis.ts +++ b/packages/components/src/private-apis.ts @@ -8,6 +8,7 @@ import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/pri */ import { default as CustomSelectControl } from './custom-select-control'; import { positionToPlacement as __experimentalPopoverLegacyPositionToPlacement } from './popover/utils'; +import { default as ProgressBar } from './progress-bar'; import { createPrivateSlotFill } from './slot-fill'; import { DropdownMenu as DropdownMenuV2, @@ -45,4 +46,5 @@ lock( privateApis, { DropdownMenuSeparatorV2, DropdownSubMenuV2, DropdownSubMenuTriggerV2, + ProgressBar, } ); From 43d2dc2e424cfc8777e33d5cc35aa8c334a8be17 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 27 Jul 2023 18:05:34 +0300 Subject: [PATCH 04/26] Add missing className in type --- packages/components/src/progress-bar/types.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/components/src/progress-bar/types.ts b/packages/components/src/progress-bar/types.ts index 986143381d5a39..d3733c574da894 100644 --- a/packages/components/src/progress-bar/types.ts +++ b/packages/components/src/progress-bar/types.ts @@ -18,4 +18,9 @@ export type ProgressBarProps = { * Color of the progress bar track. */ trackColor?: CSSProperties[ 'color' ]; + + /** + * A CSS class to apply to the progress bar wrapper (track) element. + */ + className?: string; }; From f1d5c809214c6df3e36c0c49aee6f7c18df0ba28 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Thu, 27 Jul 2023 18:16:45 +0300 Subject: [PATCH 05/26] Render progressbar element invisibly --- packages/components/src/progress-bar/style.scss | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/components/src/progress-bar/style.scss b/packages/components/src/progress-bar/style.scss index 7e28a6437ea655..58d52705a4a135 100644 --- a/packages/components/src/progress-bar/style.scss +++ b/packages/components/src/progress-bar/style.scss @@ -6,7 +6,12 @@ background-color: $components-color-gray-100; progress { - display: none; + position: absolute; + top: 0; + left: 0; + opacity: 0; + width: 100%; + height: 100%; } .components-progress-bar__indicator { From c6273f4d43a2856b5245e305134393d7fac67941 Mon Sep 17 00:00:00 2001 From: James Koster Date: Thu, 27 Jul 2023 18:31:17 +0100 Subject: [PATCH 06/26] Update appearance --- packages/components/src/progress-bar/style.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/src/progress-bar/style.scss b/packages/components/src/progress-bar/style.scss index 58d52705a4a135..d8f80beb30a02c 100644 --- a/packages/components/src/progress-bar/style.scss +++ b/packages/components/src/progress-bar/style.scss @@ -2,8 +2,9 @@ position: relative; overflow: hidden; width: 100%; - height: 5px; + height: var(--wp-admin-border-width-focus); background-color: $components-color-gray-100; + border-radius: $radius-block-ui; progress { position: absolute; From b28b7b51fcabf9daf1387af4aaabd30d70a552f7 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Fri, 28 Jul 2023 12:05:34 +0300 Subject: [PATCH 07/26] Mark the component story as experimental Co-authored-by: Lena Morita --- packages/components/src/progress-bar/stories/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/progress-bar/stories/index.tsx b/packages/components/src/progress-bar/stories/index.tsx index 217a1930418750..6085c83dfd9091 100644 --- a/packages/components/src/progress-bar/stories/index.tsx +++ b/packages/components/src/progress-bar/stories/index.tsx @@ -10,7 +10,7 @@ import { ProgressBar } from '..'; const meta: ComponentMeta< typeof ProgressBar > = { component: ProgressBar, - title: 'Components/ProgressBar', + title: 'Components (Experimental)/ProgressBar', argTypes: { indicatorColor: { control: { type: 'color' } }, trackColor: { control: { type: 'color' } }, From ac381777a8057b05336479d9173a9d14ba6baca9 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Fri, 28 Jul 2023 12:06:11 +0300 Subject: [PATCH 08/26] Add an experimental alert in the component README Co-authored-by: Lena Morita --- packages/components/src/progress-bar/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md index ba5dd434f9a4ea..6af78322e1fd20 100644 --- a/packages/components/src/progress-bar/README.md +++ b/packages/components/src/progress-bar/README.md @@ -1,5 +1,9 @@ # ProgressBar +
+This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes. +
+ A simple horizontal progress bar component. Supports two modes: determinate and indeterminate. A progress bar is determinate when a specific progress value has been specified (from 0 to 100), and indeterminate when a value hasn't been specified. From a4d5de9f8b3d5395d9e63c210954f311f7d8977a Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 12:11:21 +0300 Subject: [PATCH 09/26] Remove usage from README --- packages/components/src/progress-bar/README.md | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md index 6af78322e1fd20..aa181c42f6f70a 100644 --- a/packages/components/src/progress-bar/README.md +++ b/packages/components/src/progress-bar/README.md @@ -8,19 +8,6 @@ A simple horizontal progress bar component. Supports two modes: determinate and indeterminate. A progress bar is determinate when a specific progress value has been specified (from 0 to 100), and indeterminate when a value hasn't been specified. -### Usage - -```jsx -/** - * WordPress dependencies - */ -import { __experimentalProgressBar as ProgressBar } from '@wordpress/components'; - -export const MyProgressBar = () => { - return ; -}; -``` - ### Props The component accepts the following props: From 50651641e624caea1f5600adf37e20112b4b5d8d Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 12:12:05 +0300 Subject: [PATCH 10/26] Remove README from manifest --- docs/manifest.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/docs/manifest.json b/docs/manifest.json index a6ca6fb7503a61..5f75e49924f355 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1115,12 +1115,6 @@ "markdown_source": "../packages/components/src/popover/README.md", "parent": "components" }, - { - "title": "ProgressBar", - "slug": "progress-bar", - "markdown_source": "../packages/components/src/progress-bar/README.md", - "parent": "components" - }, { "title": "QueryControls", "slug": "query-controls", From bbfbfccb2427288560c657df3e4297d13720de3c Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 12:15:09 +0300 Subject: [PATCH 11/26] Add border radius to indicator as well --- packages/components/src/progress-bar/style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/progress-bar/style.scss b/packages/components/src/progress-bar/style.scss index d8f80beb30a02c..b316bf3622bbd6 100644 --- a/packages/components/src/progress-bar/style.scss +++ b/packages/components/src/progress-bar/style.scss @@ -20,6 +20,7 @@ position: absolute; top: 0; height: 100%; + border-radius: $radius-block-ui; background-color: $components-color-accent; } From 166ae8d0fce590cbf2a2e55797e5f768a11d114e Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 13:07:13 +0300 Subject: [PATCH 12/26] Refactor from SCSS to Emotion --- .../components/src/progress-bar/index.tsx | 16 +++--- .../components/src/progress-bar/style.scss | 44 -------------- .../components/src/progress-bar/styles.ts | 57 +++++++++++++++++++ packages/components/src/style.scss | 1 - 4 files changed, 66 insertions(+), 52 deletions(-) delete mode 100644 packages/components/src/progress-bar/style.scss create mode 100644 packages/components/src/progress-bar/styles.ts diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index 7d573eca95fc90..b22054891ac23c 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -6,6 +6,7 @@ import classnames from 'classnames'; /** * Internal dependencies */ +import * as ProgressBarStyled from './styles'; import type { ProgressBarProps } from './types'; import type { WordPressComponentProps } from '../ui/context'; @@ -23,19 +24,20 @@ export function ProgressBar( const trackStyle = { backgroundColor: trackColor ? trackColor : undefined, }; + const indicatorStyle = { width: `${ isIndeterminate ? INDETERMINATE_TRACK_WIDTH : value }%`, backgroundColor: indicatorColor ? indicatorColor : undefined, }; return ( -
-
- -
+ + + + ); } diff --git a/packages/components/src/progress-bar/style.scss b/packages/components/src/progress-bar/style.scss deleted file mode 100644 index b316bf3622bbd6..00000000000000 --- a/packages/components/src/progress-bar/style.scss +++ /dev/null @@ -1,44 +0,0 @@ -.components-progress-bar { - position: relative; - overflow: hidden; - width: 100%; - height: var(--wp-admin-border-width-focus); - background-color: $components-color-gray-100; - border-radius: $radius-block-ui; - - progress { - position: absolute; - top: 0; - left: 0; - opacity: 0; - width: 100%; - height: 100%; - } - - .components-progress-bar__indicator { - display: inline-block; - position: absolute; - top: 0; - height: 100%; - border-radius: $radius-block-ui; - background-color: $components-color-accent; - } - - &.is-indeterminate .components-progress-bar__indicator { - animation-duration: 1.5s; - animation-timing-function: ease-in-out; - animation-iteration-count: infinite; - animation-name: progress-bar-indication; - - @include reduce-motion("animation"); - } -} - -@keyframes progress-bar-indication { - from { - left: -50%; - } - to { - left: 100%; - } -} diff --git a/packages/components/src/progress-bar/styles.ts b/packages/components/src/progress-bar/styles.ts new file mode 100644 index 00000000000000..cb08dbb5b40e11 --- /dev/null +++ b/packages/components/src/progress-bar/styles.ts @@ -0,0 +1,57 @@ +/** + * External dependencies + */ +import styled from '@emotion/styled'; +import { keyframes } from '@emotion/react'; + +/** + * Internal dependencies + */ +import { COLORS, CONFIG } from '../utils'; + +const animateProgressBar = keyframes( { + '0%': { + left: '-50%', + }, + '100%': { + left: '100%', + }, +} ); + +export const Track = styled.div` + position: relative; + overflow: hidden; + width: 100%; + height: ${ CONFIG.borderWidthFocus }; + background-color: ${ COLORS.gray[ '100' ] }; + border-radius: ${ CONFIG.radiusBlockUi }; +`; + +export const Indicator = styled.div` + display: inline-block; + position: absolute; + top: 0; + height: 100%; + border-radius: ${ CONFIG.radiusBlockUi }; + background-color: ${ COLORS.ui.theme }; + + .is-indeterminate & { + animation-duration: 1.5s; + animation-timing-function: ease-in-out; + animation-iteration-count: infinite; + animation-name: ${ animateProgressBar }; + + @media ( prefers-reduced-motion ) { + animation-duration: 0s; + } + } +`; + +export const ProgressElement = styled.progress` + position: absolute; + top: 0; + left: 0; + opacity: 0; + width: 100%; + height: 100%; +`; diff --git a/packages/components/src/style.scss b/packages/components/src/style.scss index 2fa0b30bbf949c..02dce83f66dcc6 100644 --- a/packages/components/src/style.scss +++ b/packages/components/src/style.scss @@ -39,7 +39,6 @@ @import "./panel/style.scss"; @import "./placeholder/style.scss"; @import "./popover/style.scss"; -@import "./progress-bar/style.scss"; @import "./radio-control/style.scss"; @import "./resizable-box/style.scss"; @import "./responsive-wrapper/style.scss"; From e00dc4f161c8763fa846b857f4a7152f67c83d42 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 13:19:49 +0300 Subject: [PATCH 13/26] Remove color props --- .../components/src/progress-bar/README.md | 12 ---------- .../components/src/progress-bar/index.tsx | 23 ++++++++----------- .../src/progress-bar/stories/index.tsx | 2 -- packages/components/src/progress-bar/types.ts | 15 ------------ 4 files changed, 9 insertions(+), 43 deletions(-) diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md index aa181c42f6f70a..db0a33d2c6c629 100644 --- a/packages/components/src/progress-bar/README.md +++ b/packages/components/src/progress-bar/README.md @@ -19,18 +19,6 @@ If a `value` is not specified, the progress bar will be considered indeterminate - Required: No -#### `trackColor`: `string` - -Optional color of the progress bar track. - -- Required: No - -#### `indicatorColor`: `string` - -Optional color of the progress bar indicator. - -- Required: No - ##### `className`: `string` A CSS class to apply to the underlying `div` element, serving as a progress bar track. diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index b22054891ac23c..bc4dfdd047298c 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -16,26 +16,21 @@ export const INDETERMINATE_TRACK_WIDTH = 50; export function ProgressBar( props: WordPressComponentProps< ProgressBarProps, 'div', false > ) { - const { className, value, indicatorColor, trackColor } = props; + const { className, value } = props; const isIndeterminate = ! Number.isFinite( value ); const wrapperClasses = classnames( 'components-progress-bar', className, { 'is-indeterminate': isIndeterminate, } ); - const trackStyle = { - backgroundColor: trackColor ? trackColor : undefined, - }; - - const indicatorStyle = { - width: `${ isIndeterminate ? INDETERMINATE_TRACK_WIDTH : value }%`, - backgroundColor: indicatorColor ? indicatorColor : undefined, - }; return ( - - + + ); diff --git a/packages/components/src/progress-bar/stories/index.tsx b/packages/components/src/progress-bar/stories/index.tsx index 6085c83dfd9091..1499d68a10bbbd 100644 --- a/packages/components/src/progress-bar/stories/index.tsx +++ b/packages/components/src/progress-bar/stories/index.tsx @@ -12,8 +12,6 @@ const meta: ComponentMeta< typeof ProgressBar > = { component: ProgressBar, title: 'Components (Experimental)/ProgressBar', argTypes: { - indicatorColor: { control: { type: 'color' } }, - trackColor: { control: { type: 'color' } }, value: { control: { type: 'number', min: 0, max: 100, step: 1 } }, }, parameters: { diff --git a/packages/components/src/progress-bar/types.ts b/packages/components/src/progress-bar/types.ts index d3733c574da894..9beb28317e58aa 100644 --- a/packages/components/src/progress-bar/types.ts +++ b/packages/components/src/progress-bar/types.ts @@ -1,24 +1,9 @@ -/** - * External dependencies - */ -import type { CSSProperties } from 'react'; - export type ProgressBarProps = { /** * Value of the progress bar. */ value?: number; - /** - * Color of the progress bar indicator. - */ - indicatorColor?: CSSProperties[ 'color' ]; - - /** - * Color of the progress bar track. - */ - trackColor?: CSSProperties[ 'color' ]; - /** * A CSS class to apply to the progress bar wrapper (track) element. */ From 05245ac8be27fadae0e7a9af0c05687ee8adc5d0 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 13:19:59 +0300 Subject: [PATCH 14/26] Update tests --- .../test/__snapshots__/index.tsx.snap | 137 +++++++++++++++--- .../src/progress-bar/test/index.tsx | 22 +-- 2 files changed, 122 insertions(+), 37 deletions(-) diff --git a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap index 7687837b9ba0f4..e5f17cd5e61e78 100644 --- a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap +++ b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap @@ -1,32 +1,71 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`ProgressBar should be able to specify custom track and indicator colors 1`] = ` -
-
-
- -
-
-`; - exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\` is not provided 1`] = ` +@keyframes animation-0 { + 0% { + left: -50%; + } + + 100% { + left: 100%; + } +} + +.emotion-0 { + position: relative; + overflow: hidden; + width: 100%; + height: 1.5px; + background-color: #f0f0f0; + border-radius: 2px; +} + +.emotion-2 { + display: inline-block; + position: absolute; + top: 0; + height: 100%; + border-radius: 2px; + background-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); +} + +.is-indeterminate .emotion-2 { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-name: animation-0; + animation-name: animation-0; +} + +@media ( prefers-reduced-motion ) { + .is-indeterminate .emotion-2 { + -webkit-animation-duration: 0s; + animation-duration: 0s; + } +} + +.emotion-4 { + position: absolute; + top: 0; + left: 0; + opacity: 0; + width: 100%; + height: 100%; +} +
@@ -34,15 +73,71 @@ exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\` `; exports[`ProgressBar should not have an \`is-indeterminate\` className if \`value\` is provided 1`] = ` +@keyframes animation-0 { + 0% { + left: -50%; + } + + 100% { + left: 100%; + } +} + +.emotion-0 { + position: relative; + overflow: hidden; + width: 100%; + height: 1.5px; + background-color: #f0f0f0; + border-radius: 2px; +} + +.emotion-2 { + display: inline-block; + position: absolute; + top: 0; + height: 100%; + border-radius: 2px; + background-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); +} + +.is-indeterminate .emotion-2 { + -webkit-animation-duration: 1.5s; + animation-duration: 1.5s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; + -webkit-animation-name: animation-0; + animation-name: animation-0; +} + +@media ( prefers-reduced-motion ) { + .is-indeterminate .emotion-2 { + -webkit-animation-duration: 0s; + animation-duration: 0s; + } +} + +.emotion-4 { + position: absolute; + top: 0; + left: 0; + opacity: 0; + width: 100%; + height: 100%; +} +
diff --git a/packages/components/src/progress-bar/test/index.tsx b/packages/components/src/progress-bar/test/index.tsx index 2ad7da2933c4f6..ce45e11918d207 100644 --- a/packages/components/src/progress-bar/test/index.tsx +++ b/packages/components/src/progress-bar/test/index.tsx @@ -14,7 +14,8 @@ describe( 'ProgressBar', () => { const progressBar = screen.getByRole( 'progressbar' ); - expect( progressBar ).toBeVisible(); + expect( progressBar ).toBeInTheDocument(); + expect( progressBar ).not.toBeVisible(); expect( progressBar ).not.toHaveValue(); } ); @@ -23,7 +24,8 @@ describe( 'ProgressBar', () => { const progressBar = screen.getByRole( 'progressbar' ); - expect( progressBar ).toBeVisible(); + expect( progressBar ).toBeInTheDocument(); + expect( progressBar ).not.toBeVisible(); expect( progressBar ).toHaveValue( 55 ); } ); @@ -35,9 +37,7 @@ describe( 'ProgressBar', () => { * the track is an intentionally non-interactive presentation element. */ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access - const indicator = container.querySelector( - '.components-progress-bar__indicator' - ); + const indicator = container.firstChild?.firstChild; expect( indicator ).toHaveStyle( { width: `${ INDETERMINATE_TRACK_WIDTH }%`, @@ -52,9 +52,7 @@ describe( 'ProgressBar', () => { * the track is an intentionally non-interactive presentation element. */ // eslint-disable-next-line testing-library/no-container, testing-library/no-node-access - const indicator = container.querySelector( - '.components-progress-bar__indicator' - ); + const indicator = container.firstChild?.firstChild; expect( indicator ).toHaveStyle( { width: '55%', @@ -72,12 +70,4 @@ describe( 'ProgressBar', () => { expect( container ).toMatchSnapshot(); } ); - - it( 'should be able to specify custom track and indicator colors', () => { - const { container } = render( - - ); - - expect( container ).toMatchSnapshot(); - } ); } ); From d6d70445073a250ed166b1d44892189415d8ac39 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 13:25:24 +0300 Subject: [PATCH 15/26] Add an aria-label to the underlying progress element --- packages/components/src/progress-bar/index.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index bc4dfdd047298c..795f84f41e9ea8 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -3,6 +3,11 @@ */ import classnames from 'classnames'; +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + /** * Internal dependencies */ @@ -31,7 +36,11 @@ export function ProgressBar( }%`, } } /> - + ); } From fef81d210598e4b95e5cd79d684d34ff81e567df Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Fri, 28 Jul 2023 13:37:58 +0300 Subject: [PATCH 16/26] Update snapshots --- .../src/progress-bar/test/__snapshots__/index.tsx.snap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap index e5f17cd5e61e78..9c0a29f6eaa8e8 100644 --- a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap +++ b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap @@ -65,6 +65,7 @@ exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\` style="width: 50%;" /> @@ -137,6 +138,7 @@ exports[`ProgressBar should not have an \`is-indeterminate\` className if \`valu style="width: 55%;" /> Date: Fri, 28 Jul 2023 13:59:15 +0300 Subject: [PATCH 17/26] Intentionally ignore ProgressBar README from docs manifest --- docs/tool/manifest.js | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tool/manifest.js b/docs/tool/manifest.js index d3ed5d61dc0bb1..b061fa5149c698 100644 --- a/docs/tool/manifest.js +++ b/docs/tool/manifest.js @@ -15,6 +15,7 @@ const componentPaths = glob( 'packages/components/src/*/**/README.md', { 'packages/components/src/theme/README.md', 'packages/components/src/view/README.md', 'packages/components/src/dropdown-menu-v2/README.md', + 'packages/components/src/progress-bar/README.md', ], } ); const packagePaths = glob( 'packages/*/package.json' ) From 2bda78e471c3cabbf70d47320f9635ddf79a91af Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Mon, 31 Jul 2023 12:00:40 +0300 Subject: [PATCH 18/26] Use the components gray color variable Co-authored-by: Lena Morita --- packages/components/src/progress-bar/styles.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/components/src/progress-bar/styles.ts b/packages/components/src/progress-bar/styles.ts index cb08dbb5b40e11..c7b99ecdef8e75 100644 --- a/packages/components/src/progress-bar/styles.ts +++ b/packages/components/src/progress-bar/styles.ts @@ -23,7 +23,10 @@ export const Track = styled.div` overflow: hidden; width: 100%; height: ${ CONFIG.borderWidthFocus }; - background-color: ${ COLORS.gray[ '100' ] }; + background-color: var( + --wp-components-color-gray-100, + ${ COLORS.gray[ 100 ] } + ); border-radius: ${ CONFIG.radiusBlockUi }; `; From 453f5d108043f0ea5b71297b6ef6b144ca241f01 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Mon, 31 Jul 2023 12:03:48 +0300 Subject: [PATCH 19/26] Add TODO for using the :indeterminate pseudo-class --- packages/components/src/progress-bar/index.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index 795f84f41e9ea8..880169c2792e54 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -24,6 +24,11 @@ export function ProgressBar( const { className, value } = props; const isIndeterminate = ! Number.isFinite( value ); const wrapperClasses = classnames( 'components-progress-bar', className, { + /** + * @todo Use the `:indeterminate` pseudo-class once supported. + * + * @see https://caniuse.com/mdn-css_selectors_indeterminate_progress + */ 'is-indeterminate': isIndeterminate, } ); From 7b630997cef222004e4ef66042ddc75ef64e1677 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Mon, 31 Jul 2023 12:05:28 +0300 Subject: [PATCH 20/26] Remove default className --- packages/components/src/progress-bar/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index 880169c2792e54..8ab716a987a27b 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -23,7 +23,7 @@ export function ProgressBar( ) { const { className, value } = props; const isIndeterminate = ! Number.isFinite( value ); - const wrapperClasses = classnames( 'components-progress-bar', className, { + const wrapperClasses = classnames( className, { /** * @todo Use the `:indeterminate` pseudo-class once supported. * From 4c1c86e2dea7dcb5254a8f1f881a62ef0acc5d0d Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Mon, 31 Jul 2023 12:17:20 +0300 Subject: [PATCH 21/26] Add a max-width --- packages/components/src/progress-bar/styles.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/components/src/progress-bar/styles.ts b/packages/components/src/progress-bar/styles.ts index c7b99ecdef8e75..0e50b46f248b9a 100644 --- a/packages/components/src/progress-bar/styles.ts +++ b/packages/components/src/progress-bar/styles.ts @@ -22,6 +22,7 @@ export const Track = styled.div` position: relative; overflow: hidden; width: 100%; + max-width: 160px; height: ${ CONFIG.borderWidthFocus }; background-color: var( --wp-components-color-gray-100, From 2e16c12986cd25cda43bc489e166e2a56cd8e230 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Mon, 31 Jul 2023 12:18:00 +0300 Subject: [PATCH 22/26] Update snapshots --- .../test/__snapshots__/index.tsx.snap | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap index 9c0a29f6eaa8e8..01019b6f230782 100644 --- a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap +++ b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap @@ -15,8 +15,12 @@ exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\` position: relative; overflow: hidden; width: 100%; + max-width: 160px; height: 1.5px; - background-color: #f0f0f0; + background-color: var( + --wp-components-color-gray-100, + #f0f0f0 + ); border-radius: 2px; } @@ -58,7 +62,7 @@ exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\`
Date: Mon, 31 Jul 2023 14:05:24 +0300 Subject: [PATCH 23/26] Add support for ID and ref --- packages/components/src/progress-bar/README.md | 6 ++++++ packages/components/src/progress-bar/index.tsx | 15 ++++++++++++--- .../test/__snapshots__/index.tsx.snap | 2 ++ .../components/src/progress-bar/test/index.tsx | 8 ++++++++ packages/components/src/progress-bar/types.ts | 6 ++++++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md index db0a33d2c6c629..021549d3f2b36f 100644 --- a/packages/components/src/progress-bar/README.md +++ b/packages/components/src/progress-bar/README.md @@ -24,3 +24,9 @@ If a `value` is not specified, the progress bar will be considered indeterminate A CSS class to apply to the underlying `div` element, serving as a progress bar track. - Required: No + +##### `id`: `string` + +The HTML `id` of the control element. This is necessary to be able to accessibly associate the label with that element. + +- Required: No diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index 8ab716a987a27b..961fca5af4f9de 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -2,11 +2,14 @@ * External dependencies */ import classnames from 'classnames'; +import type { ForwardedRef } from 'react'; /** * WordPress dependencies */ import { __ } from '@wordpress/i18n'; +import { forwardRef } from '@wordpress/element'; +import { useInstanceId } from '@wordpress/compose'; /** * Internal dependencies @@ -18,10 +21,12 @@ import type { WordPressComponentProps } from '../ui/context'; // Width of the indicator for the indeterminate progress bar export const INDETERMINATE_TRACK_WIDTH = 50; -export function ProgressBar( - props: WordPressComponentProps< ProgressBarProps, 'div', false > +function UnforwardedProgressBar( + props: WordPressComponentProps< ProgressBarProps, 'div', false >, + ref: ForwardedRef< HTMLProgressElement > ) { - const { className, value } = props; + const { className, id: idProp, value } = props; + const id = useInstanceId( ProgressBar, 'progress-bar', idProp ); const isIndeterminate = ! Number.isFinite( value ); const wrapperClasses = classnames( className, { /** @@ -45,9 +50,13 @@ export function ProgressBar( max={ 100 } value={ value } aria-label={ __( 'Loading …' ) } + id={ id } + ref={ ref } /> ); } +export const ProgressBar = forwardRef( UnforwardedProgressBar ); + export default ProgressBar; diff --git a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap index 01019b6f230782..6451156589993b 100644 --- a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap +++ b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap @@ -71,6 +71,7 @@ exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\`
@@ -148,6 +149,7 @@ exports[`ProgressBar should not have an \`is-indeterminate\` className if \`valu diff --git a/packages/components/src/progress-bar/test/index.tsx b/packages/components/src/progress-bar/test/index.tsx index ce45e11918d207..df3a0b3a1a62cf 100644 --- a/packages/components/src/progress-bar/test/index.tsx +++ b/packages/components/src/progress-bar/test/index.tsx @@ -70,4 +70,12 @@ describe( 'ProgressBar', () => { expect( container ).toMatchSnapshot(); } ); + + it( 'should allow a custom `id` attribute to be specified', () => { + const id = 'foo-bar-123'; + + render( ); + + expect( screen.getByRole( 'progressbar' ) ).toHaveAttribute( 'id', id ); + } ); } ); diff --git a/packages/components/src/progress-bar/types.ts b/packages/components/src/progress-bar/types.ts index 9beb28317e58aa..9037d4fc6f3da0 100644 --- a/packages/components/src/progress-bar/types.ts +++ b/packages/components/src/progress-bar/types.ts @@ -8,4 +8,10 @@ export type ProgressBarProps = { * A CSS class to apply to the progress bar wrapper (track) element. */ className?: string; + + /** + * The HTML `id` of the `progress` control element. + * This is necessary to be able to accessibly associate the label with that element. + */ + id?: string; }; From 664a4de3ed670177ca8d55284cd01d1a94a87553 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Mon, 31 Jul 2023 14:17:44 +0300 Subject: [PATCH 24/26] Fix docs --- packages/components/src/progress-bar/README.md | 2 +- packages/components/src/progress-bar/types.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md index 021549d3f2b36f..fe095ff7834cd7 100644 --- a/packages/components/src/progress-bar/README.md +++ b/packages/components/src/progress-bar/README.md @@ -27,6 +27,6 @@ A CSS class to apply to the underlying `div` element, serving as a progress bar ##### `id`: `string` -The HTML `id` of the control element. This is necessary to be able to accessibly associate the label with that element. +The HTML `id` of the `progress` element. This is necessary to be able to accessibly associate the label with that element. - Required: No diff --git a/packages/components/src/progress-bar/types.ts b/packages/components/src/progress-bar/types.ts index 9037d4fc6f3da0..ba125df8367cf8 100644 --- a/packages/components/src/progress-bar/types.ts +++ b/packages/components/src/progress-bar/types.ts @@ -10,7 +10,7 @@ export type ProgressBarProps = { className?: string; /** - * The HTML `id` of the `progress` control element. + * The HTML `id` of the `progress` element. * This is necessary to be able to accessibly associate the label with that element. */ id?: string; From 2df2d48caa94f99a6de00c913c954d60667787a3 Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 1 Aug 2023 12:55:34 +0300 Subject: [PATCH 25/26] Use emotion for indeterminate and value-based styling --- .../components/src/progress-bar/index.tsx | 21 +-- .../components/src/progress-bar/styles.ts | 30 ++-- .../test/__snapshots__/index.tsx.snap | 158 ------------------ .../src/progress-bar/test/index.tsx | 15 +- 4 files changed, 23 insertions(+), 201 deletions(-) delete mode 100644 packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index 961fca5af4f9de..ea65723cf09a7e 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -1,7 +1,6 @@ /** * External dependencies */ -import classnames from 'classnames'; import type { ForwardedRef } from 'react'; /** @@ -18,9 +17,6 @@ import * as ProgressBarStyled from './styles'; import type { ProgressBarProps } from './types'; import type { WordPressComponentProps } from '../ui/context'; -// Width of the indicator for the indeterminate progress bar -export const INDETERMINATE_TRACK_WIDTH = 50; - function UnforwardedProgressBar( props: WordPressComponentProps< ProgressBarProps, 'div', false >, ref: ForwardedRef< HTMLProgressElement > @@ -28,23 +24,12 @@ function UnforwardedProgressBar( const { className, id: idProp, value } = props; const id = useInstanceId( ProgressBar, 'progress-bar', idProp ); const isIndeterminate = ! Number.isFinite( value ); - const wrapperClasses = classnames( className, { - /** - * @todo Use the `:indeterminate` pseudo-class once supported. - * - * @see https://caniuse.com/mdn-css_selectors_indeterminate_progress - */ - 'is-indeterminate': isIndeterminate, - } ); return ( - + ` display: inline-block; position: absolute; top: 0; @@ -39,16 +45,16 @@ export const Indicator = styled.div` border-radius: ${ CONFIG.radiusBlockUi }; background-color: ${ COLORS.ui.theme }; - .is-indeterminate & { - animation-duration: 1.5s; - animation-timing-function: ease-in-out; - animation-iteration-count: infinite; - animation-name: ${ animateProgressBar }; - - @media ( prefers-reduced-motion ) { - animation-duration: 0s; - } - } + ${ ( { isIndeterminate, value } ) => + isIndeterminate + ? css( { + animationDuration: '1.5s', + animationTimingFunction: 'ease-in-out', + animationIterationCount: 'infinite', + animationName: animateProgressBar, + width: `${ INDETERMINATE_TRACK_WIDTH }%`, + } ) + : css( { width: `${ value }%` } ) }; `; export const ProgressElement = styled.progress` diff --git a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap b/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap deleted file mode 100644 index 6451156589993b..00000000000000 --- a/packages/components/src/progress-bar/test/__snapshots__/index.tsx.snap +++ /dev/null @@ -1,158 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ProgressBar should have an \`is-indeterminate\` className if \`value\` is not provided 1`] = ` -@keyframes animation-0 { - 0% { - left: -50%; - } - - 100% { - left: 100%; - } -} - -.emotion-0 { - position: relative; - overflow: hidden; - width: 100%; - max-width: 160px; - height: 1.5px; - background-color: var( - --wp-components-color-gray-100, - #f0f0f0 - ); - border-radius: 2px; -} - -.emotion-2 { - display: inline-block; - position: absolute; - top: 0; - height: 100%; - border-radius: 2px; - background-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); -} - -.is-indeterminate .emotion-2 { - -webkit-animation-duration: 1.5s; - animation-duration: 1.5s; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; - -webkit-animation-name: animation-0; - animation-name: animation-0; -} - -@media ( prefers-reduced-motion ) { - .is-indeterminate .emotion-2 { - -webkit-animation-duration: 0s; - animation-duration: 0s; - } -} - -.emotion-4 { - position: absolute; - top: 0; - left: 0; - opacity: 0; - width: 100%; - height: 100%; -} - -
-
-
- -
-
-`; - -exports[`ProgressBar should not have an \`is-indeterminate\` className if \`value\` is provided 1`] = ` -@keyframes animation-0 { - 0% { - left: -50%; - } - - 100% { - left: 100%; - } -} - -.emotion-0 { - position: relative; - overflow: hidden; - width: 100%; - max-width: 160px; - height: 1.5px; - background-color: var( - --wp-components-color-gray-100, - #f0f0f0 - ); - border-radius: 2px; -} - -.emotion-2 { - display: inline-block; - position: absolute; - top: 0; - height: 100%; - border-radius: 2px; - background-color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); -} - -.is-indeterminate .emotion-2 { - -webkit-animation-duration: 1.5s; - animation-duration: 1.5s; - -webkit-animation-timing-function: ease-in-out; - animation-timing-function: ease-in-out; - -webkit-animation-iteration-count: infinite; - animation-iteration-count: infinite; - -webkit-animation-name: animation-0; - animation-name: animation-0; -} - -@media ( prefers-reduced-motion ) { - .is-indeterminate .emotion-2 { - -webkit-animation-duration: 0s; - animation-duration: 0s; - } -} - -.emotion-4 { - position: absolute; - top: 0; - left: 0; - opacity: 0; - width: 100%; - height: 100%; -} - -
-
-
- -
-
-`; diff --git a/packages/components/src/progress-bar/test/index.tsx b/packages/components/src/progress-bar/test/index.tsx index df3a0b3a1a62cf..a9ce52c22bbdfd 100644 --- a/packages/components/src/progress-bar/test/index.tsx +++ b/packages/components/src/progress-bar/test/index.tsx @@ -6,7 +6,8 @@ import { render, screen } from '@testing-library/react'; /** * Internal dependencies */ -import { ProgressBar, INDETERMINATE_TRACK_WIDTH } from '..'; +import { ProgressBar } from '..'; +import { INDETERMINATE_TRACK_WIDTH } from '../styles'; describe( 'ProgressBar', () => { it( 'should render an indeterminate semantic progress bar element', () => { @@ -59,18 +60,6 @@ describe( 'ProgressBar', () => { } ); } ); - it( 'should have an `is-indeterminate` className if `value` is not provided', () => { - const { container } = render( ); - - expect( container ).toMatchSnapshot(); - } ); - - it( 'should not have an `is-indeterminate` className if `value` is provided', () => { - const { container } = render( ); - - expect( container ).toMatchSnapshot(); - } ); - it( 'should allow a custom `id` attribute to be specified', () => { const id = 'foo-bar-123'; From f0c3be6d7ca283c5e71d7338675cdd20c542113d Mon Sep 17 00:00:00 2001 From: Marin Atanasov Date: Tue, 1 Aug 2023 13:03:41 +0300 Subject: [PATCH 26/26] Remove ID, pass rest props down to the progress element --- packages/components/src/progress-bar/README.md | 6 ++---- packages/components/src/progress-bar/index.tsx | 8 +++----- packages/components/src/progress-bar/test/index.tsx | 13 +++++++++++-- packages/components/src/progress-bar/types.ts | 6 ------ 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/packages/components/src/progress-bar/README.md b/packages/components/src/progress-bar/README.md index fe095ff7834cd7..d0f62ce7e3be57 100644 --- a/packages/components/src/progress-bar/README.md +++ b/packages/components/src/progress-bar/README.md @@ -25,8 +25,6 @@ A CSS class to apply to the underlying `div` element, serving as a progress bar - Required: No -##### `id`: `string` +#### Inherited props -The HTML `id` of the `progress` element. This is necessary to be able to accessibly associate the label with that element. - -- Required: No +Any additional props will be passed the underlying `` element. diff --git a/packages/components/src/progress-bar/index.tsx b/packages/components/src/progress-bar/index.tsx index ea65723cf09a7e..16f2630953840a 100644 --- a/packages/components/src/progress-bar/index.tsx +++ b/packages/components/src/progress-bar/index.tsx @@ -8,7 +8,6 @@ import type { ForwardedRef } from 'react'; */ import { __ } from '@wordpress/i18n'; import { forwardRef } from '@wordpress/element'; -import { useInstanceId } from '@wordpress/compose'; /** * Internal dependencies @@ -18,11 +17,10 @@ import type { ProgressBarProps } from './types'; import type { WordPressComponentProps } from '../ui/context'; function UnforwardedProgressBar( - props: WordPressComponentProps< ProgressBarProps, 'div', false >, + props: WordPressComponentProps< ProgressBarProps, 'progress', false >, ref: ForwardedRef< HTMLProgressElement > ) { - const { className, id: idProp, value } = props; - const id = useInstanceId( ProgressBar, 'progress-bar', idProp ); + const { className, value, ...progressProps } = props; const isIndeterminate = ! Number.isFinite( value ); return ( @@ -35,8 +33,8 @@ function UnforwardedProgressBar( max={ 100 } value={ value } aria-label={ __( 'Loading …' ) } - id={ id } ref={ ref } + { ...progressProps } /> ); diff --git a/packages/components/src/progress-bar/test/index.tsx b/packages/components/src/progress-bar/test/index.tsx index a9ce52c22bbdfd..425c54ce8a3022 100644 --- a/packages/components/src/progress-bar/test/index.tsx +++ b/packages/components/src/progress-bar/test/index.tsx @@ -60,11 +60,20 @@ describe( 'ProgressBar', () => { } ); } ); - it( 'should allow a custom `id` attribute to be specified', () => { + it( 'should pass any additional props down to the underlying `progress` element', () => { const id = 'foo-bar-123'; + const ariaLabel = 'in progress...'; + const style = { opacity: 1 }; - render( ); + render( + + ); expect( screen.getByRole( 'progressbar' ) ).toHaveAttribute( 'id', id ); + expect( screen.getByRole( 'progressbar' ) ).toHaveAttribute( + 'aria-label', + ariaLabel + ); + expect( screen.getByRole( 'progressbar' ) ).toHaveStyle( style ); } ); } ); diff --git a/packages/components/src/progress-bar/types.ts b/packages/components/src/progress-bar/types.ts index ba125df8367cf8..9beb28317e58aa 100644 --- a/packages/components/src/progress-bar/types.ts +++ b/packages/components/src/progress-bar/types.ts @@ -8,10 +8,4 @@ export type ProgressBarProps = { * A CSS class to apply to the progress bar wrapper (track) element. */ className?: string; - - /** - * The HTML `id` of the `progress` element. - * This is necessary to be able to accessibly associate the label with that element. - */ - id?: string; };