diff --git a/packages/react-components/react-progress/etc/react-progress.api.md b/packages/react-components/react-progress/etc/react-progress.api.md index e68d89f5ffb96b..4673ffc4a7968e 100644 --- a/packages/react-components/react-progress/etc/react-progress.api.md +++ b/packages/react-components/react-progress/etc/react-progress.api.md @@ -19,22 +19,19 @@ export const progressClassNames: SlotClassNames; // @public export type ProgressProps = Omit, 'size'> & { - indeterminate?: boolean; - percentComplete?: number; + value?: number; + max?: number; thickness?: 'medium' | 'large'; }; // @public (undocumented) export type ProgressSlots = { root: NonNullable>; - label?: Slot<'span'>; bar?: NonNullable>; - track?: NonNullable>; - description?: Slot<'span'>; }; // @public -export type ProgressState = ComponentState & Required>; +export type ProgressState = ComponentState & Required> & Pick; // @public export const renderProgress_unstable: (state: ProgressState) => JSX.Element; diff --git a/packages/react-components/react-progress/src/components/Progress/Progress.types.ts b/packages/react-components/react-progress/src/components/Progress/Progress.types.ts index 9c20d7f6b78906..c35c7e2d109f99 100644 --- a/packages/react-components/react-progress/src/components/Progress/Progress.types.ts +++ b/packages/react-components/react-progress/src/components/Progress/Progress.types.ts @@ -2,30 +2,13 @@ import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utili export type ProgressSlots = { /** - * The root of the Progress - * The root slot receives the `className` and `style` specified directly on the ``. + * The track behind the progress bar */ root: NonNullable>; /** - * The title of the Progress. - * The label slot receives the styling related to the title associated with the Progress. - */ - label?: Slot<'span'>; - /** - * The animated slot of the Progress - * The bar slot receives the styling related to the loading bar associated with the Progress + * The filled portion of the progress bar. Animated in the indeterminate state, when no value is provided. */ bar?: NonNullable>; - /** - * The track slot of the Progress - * The track slot receives the styling related to the loading bar track associated with the Progress - */ - track?: NonNullable>; - /** - * The description slot of the Progress - * The description slot receives the styling related to the description associated with the Progress - */ - description?: Slot<'span'>; }; /** @@ -33,14 +16,18 @@ export type ProgressSlots = { */ export type ProgressProps = Omit, 'size'> & { /** - * Prop to set whether the Progress is determinate or indeterminate - * @default false + * A decimal number between `0` and `1` (or between `0` and `max` if given), + * which specifies how much of the task has been completed. + * + * If `undefined` (default), the Progress will display an **indeterminate** state. */ - indeterminate?: boolean; + value?: number; /** - * Percentage of the operation's completeness, numerically between 0 and 100. + * The maximum value, which indicates the task is complete. + * The progress bar will be full when `value` equals `max`. + * @default 1 */ - percentComplete?: number; + max?: number; /** * The thickness of the Progress bar * @default 'medium' @@ -51,5 +38,4 @@ export type ProgressProps = Omit, 'size'> & { /** * State used in rendering Progress */ -export type ProgressState = ComponentState & - Required>; +export type ProgressState = ComponentState & Required> & Pick; diff --git a/packages/react-components/react-progress/src/components/Progress/__snapshots__/Progress.test.tsx.snap b/packages/react-components/react-progress/src/components/Progress/__snapshots__/Progress.test.tsx.snap index de2329fcb86dfe..e3869fcb8905d1 100644 --- a/packages/react-components/react-progress/src/components/Progress/__snapshots__/Progress.test.tsx.snap +++ b/packages/react-components/react-progress/src/components/Progress/__snapshots__/Progress.test.tsx.snap @@ -7,14 +7,7 @@ exports[`Progress renders a default state 1`] = ` role="progressbar" >
-
diff --git a/packages/react-components/react-progress/src/components/Progress/renderProgress.tsx b/packages/react-components/react-progress/src/components/Progress/renderProgress.tsx index 3816b3b4d9ea11..c47b019565485e 100644 --- a/packages/react-components/react-progress/src/components/Progress/renderProgress.tsx +++ b/packages/react-components/react-progress/src/components/Progress/renderProgress.tsx @@ -7,12 +7,5 @@ import type { ProgressState, ProgressSlots } from './Progress.types'; */ export const renderProgress_unstable = (state: ProgressState) => { const { slots, slotProps } = getSlots(state); - return ( - - {slots.label && } - {slots.track && } - {slots.bar && } - {slots.description && } - - ); + return {slots.bar && }; }; diff --git a/packages/react-components/react-progress/src/components/Progress/useProgress.tsx b/packages/react-components/react-progress/src/components/Progress/useProgress.tsx index 1e9c0eea257e6c..47eca9757ae664 100644 --- a/packages/react-components/react-progress/src/components/Progress/useProgress.tsx +++ b/packages/react-components/react-progress/src/components/Progress/useProgress.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { getNativeElementProps, resolveShorthand, useId } from '@fluentui/react-utilities'; +import { getNativeElementProps, resolveShorthand } from '@fluentui/react-utilities'; import type { ProgressProps, ProgressState } from './Progress.types'; /** @@ -13,56 +13,29 @@ import type { ProgressProps, ProgressState } from './Progress.types'; */ export const useProgress_unstable = (props: ProgressProps, ref: React.Ref): ProgressState => { // Props - const { thickness = 'medium', indeterminate = false, percentComplete = 0 } = props; - const baseId = useId('progress-'); + const { thickness = 'medium', value, max = 1.0 } = props; const root = getNativeElementProps('div', { ref, role: 'progressbar', ...props }); - const label = resolveShorthand(props.label, { - defaultProps: { - id: baseId + '__label', - }, - }); - - const description = resolveShorthand(props.description, { - defaultProps: { - id: baseId + '__description', - }, - }); - const bar = resolveShorthand(props.bar, { required: true, defaultProps: { - 'aria-valuemin': indeterminate ? undefined : 0, - 'aria-valuemax': indeterminate ? undefined : 100, - 'aria-valuenow': indeterminate ? undefined : Math.floor(percentComplete), + 'aria-valuemin': value ? 0 : undefined, + 'aria-valuemax': value ? max : undefined, + 'aria-valuenow': value, }, }); - const track = resolveShorthand(props.track, { - required: true, - }); - - if (label && !root['aria-label'] && !root['aria-labelledby']) { - root['aria-labelledby'] = label.id; - } - const state: ProgressState = { - indeterminate, - percentComplete, + max, thickness, + value, components: { root: 'div', bar: 'div', - track: 'div', - label: 'span', - description: 'span', }, root, bar, - track, - label, - description, }; return state; diff --git a/packages/react-components/react-progress/src/components/Progress/useProgressStyles.ts b/packages/react-components/react-progress/src/components/Progress/useProgressStyles.ts index 949fdd8f9ceb93..132597ab1bc5b3 100644 --- a/packages/react-components/react-progress/src/components/Progress/useProgressStyles.ts +++ b/packages/react-components/react-progress/src/components/Progress/useProgressStyles.ts @@ -1,5 +1,5 @@ import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; -import { tokens, typographyStyles } from '@fluentui/react-theme'; +import { tokens } from '@fluentui/react-theme'; import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts'; import type { ProgressState, ProgressSlots } from './Progress.types'; import type { SlotClassNames } from '@fluentui/react-utilities'; @@ -7,20 +7,12 @@ import type { SlotClassNames } from '@fluentui/react-utilities'; export const progressClassNames: SlotClassNames = { root: 'fui-Progress', bar: 'fui-Progress__bar', - track: 'fui-Progress__track', - label: 'fui-Progress__label', - description: 'fui-Progress__description', }; // If the percentComplete is near 0, don't animate it. // This prevents animations on reset to 0 scenarios. const ZERO_THRESHOLD = 0.01; -// Internal CSS vars -export const progressCssVars = { - percentageCssVar: '--fui-Progress--percentage', -}; - const barThicknessValues = { medium: '2px', large: '4px', @@ -40,31 +32,19 @@ const indeterminateProgress = { */ const useRootStyles = makeStyles({ root: { - display: 'grid', - rowGap: '8px', + display: 'block', + backgroundColor: tokens.colorNeutralBackground6, ...shorthands.overflow('hidden'), - }, -}); -/** - * Styles for the title - */ -const useLabelStyles = makeStyles({ - base: { - gridRowStart: '1', - ...typographyStyles.body1, - color: tokens.colorNeutralForeground1, + '@media screen and (forced-colors: active)': { + ...shorthands.borderBottom('1px', 'solid', 'CanvasText'), + }, }, -}); - -/** - * Styles for the description - */ -const useDescriptionStyles = makeStyles({ - base: { - gridRowStart: '3', - ...typographyStyles.caption1, - color: tokens.colorNeutralForeground2, + medium: { + height: barThicknessValues.medium, + }, + large: { + height: barThicknessValues.large, }, }); @@ -73,8 +53,6 @@ const useDescriptionStyles = makeStyles({ */ const useBarStyles = makeStyles({ base: { - gridColumnStart: '1', - gridRowStart: '2', backgroundColor: tokens.colorCompoundBrandBackground, '@media screen and (forced-colors: active)': { @@ -87,9 +65,6 @@ const useBarStyles = makeStyles({ large: { height: barThicknessValues.large, }, - determinate: { - width: `var(${progressCssVars.percentageCssVar})`, - }, nonZeroDeterminate: { transitionProperty: 'width', transitionDuration: '0.3s', @@ -114,75 +89,37 @@ const useBarStyles = makeStyles({ }, }); -const useTrackStyles = makeStyles({ - base: { - gridRowStart: '2', - gridColumnStart: '1', - backgroundColor: tokens.colorNeutralBackground6, - - '@media screen and (forced-colors: active)': { - ...shorthands.borderBottom('1px', 'solid', 'CanvasText'), - }, - }, - medium: { - height: barThicknessValues.medium, - }, - large: { - height: barThicknessValues.large, - }, -}); - /** * Apply styling to the Progress slots based on the state */ export const useProgressStyles_unstable = (state: ProgressState): ProgressState => { - const { indeterminate, thickness, percentComplete } = state; + const { max, thickness, value } = state; const rootStyles = useRootStyles(); const barStyles = useBarStyles(); - const trackStyles = useTrackStyles(); - const labelStyles = useLabelStyles(); - const descriptionStyles = useDescriptionStyles(); const { dir } = useFluent(); - state.root.className = mergeClasses(progressClassNames.root, rootStyles.root, state.root.className); + state.root.className = mergeClasses( + progressClassNames.root, + rootStyles.root, + rootStyles[thickness], + state.root.className, + ); if (state.bar) { state.bar.className = mergeClasses( progressClassNames.bar, barStyles.base, - indeterminate && barStyles.indeterminate, - indeterminate && dir === 'rtl' && barStyles.rtl, + value === undefined && barStyles.indeterminate, + value === undefined && dir === 'rtl' && barStyles.rtl, barStyles[thickness], - !indeterminate && barStyles.determinate, - !indeterminate && percentComplete > ZERO_THRESHOLD && barStyles.nonZeroDeterminate, + value !== undefined && value > ZERO_THRESHOLD && barStyles.nonZeroDeterminate, state.bar.className, ); } - if (state.track) { - state.track.className = mergeClasses( - progressClassNames.track, - trackStyles.base, - trackStyles[thickness], - state.track.className, - ); - } - - if (state.label) { - state.label.className = mergeClasses(progressClassNames.label, labelStyles.base, state.label.className); - } - - if (state.description) { - state.description.className = mergeClasses( - progressClassNames.description, - descriptionStyles.base, - state.description.className, - ); - } - - if (state.bar && !indeterminate) { + if (state.bar && value !== undefined) { state.bar.style = { - [progressCssVars.percentageCssVar]: Math.min(100, Math.max(0, percentComplete)) + '%', + width: Math.min(100, Math.max(0, (value / max) * 100)) + '%', ...state.bar.style, }; } diff --git a/packages/react-components/react-progress/src/stories/Progress/ProgressAppearance.stories.tsx b/packages/react-components/react-progress/src/stories/Progress/ProgressAppearance.stories.tsx deleted file mode 100644 index 87156421e399e4..00000000000000 --- a/packages/react-components/react-progress/src/stories/Progress/ProgressAppearance.stories.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import * as React from 'react'; -import { makeStyles, shorthands } from '@fluentui/react-components'; -import { Progress } from '@fluentui/react-progress'; - -const useStyles = makeStyles({ - container: { - ...shorthands.padding('20px'), - }, -}); - -export const Appearance = () => { - const styles = useStyles(); - - return ( -
- - - - - - - -
- ); -}; - -Appearance.parameters = { - docs: { - description: { - story: - `Progress can be shown in a few different ways.\n` + - `It can be shown as just the bar, with the bar, label and description, with just the bar and label, and with - just the bar and description`, - }, - }, -}; diff --git a/packages/react-components/react-progress/src/stories/Progress/ProgressBarThickness.stories.tsx b/packages/react-components/react-progress/src/stories/Progress/ProgressBarThickness.stories.tsx index 44f1417e65d081..266183e429b02d 100644 --- a/packages/react-components/react-progress/src/stories/Progress/ProgressBarThickness.stories.tsx +++ b/packages/react-components/react-progress/src/stories/Progress/ProgressBarThickness.stories.tsx @@ -4,7 +4,7 @@ import { Progress } from '@fluentui/react-progress'; const useStyles = makeStyles({ container: { - ...shorthands.padding('20px', '0px'), + ...shorthands.margin('20px', '0px'), }, }); @@ -13,9 +13,9 @@ export const Thickness = () => { return (
- + - +
); }; diff --git a/packages/react-components/react-progress/src/stories/Progress/ProgressDefault.stories.tsx b/packages/react-components/react-progress/src/stories/Progress/ProgressDefault.stories.tsx index 7ce82ea9e01756..a3202a17220824 100644 --- a/packages/react-components/react-progress/src/stories/Progress/ProgressDefault.stories.tsx +++ b/packages/react-components/react-progress/src/stories/Progress/ProgressDefault.stories.tsx @@ -2,13 +2,5 @@ import * as React from 'react'; import { Progress, ProgressProps } from '@fluentui/react-progress'; export const Default = (props: Partial) => { - return ; -}; - -Default.parameters = { - docs: { - description: { - story: `Default determinate Progress bar`, - }, - }, + return ; }; diff --git a/packages/react-components/react-progress/src/stories/Progress/ProgressIndeterminate.stories.tsx b/packages/react-components/react-progress/src/stories/Progress/ProgressIndeterminate.stories.tsx index 5ed4f128c41d55..29f8e45c015a1a 100644 --- a/packages/react-components/react-progress/src/stories/Progress/ProgressIndeterminate.stories.tsx +++ b/packages/react-components/react-progress/src/stories/Progress/ProgressIndeterminate.stories.tsx @@ -2,14 +2,14 @@ import * as React from 'react'; import { Progress } from '@fluentui/react-progress'; export const Indeterminate = () => { - return ; + return ; }; Indeterminate.parameters = { docs: { description: { - story: `Progress can also come in an indeterminate form. - The indeterminate form is useful for showing a buffer or loading state.`, + story: `Progress is indeterminate when 'value' is undefined. + Indeterminate Progress is best used to show that an operation is being executed.`, }, }, }; diff --git a/packages/react-components/react-progress/src/stories/Progress/ProgressMax.stories.tsx b/packages/react-components/react-progress/src/stories/Progress/ProgressMax.stories.tsx new file mode 100644 index 00000000000000..6693ed86d3b8b9 --- /dev/null +++ b/packages/react-components/react-progress/src/stories/Progress/ProgressMax.stories.tsx @@ -0,0 +1,16 @@ +import * as React from 'react'; +import { Progress } from '@fluentui/react-progress'; + +export const Max = () => { + return ; +}; + +Max.parameters = { + docs: { + description: { + story: `You can specify the maximum value of the determinate Progress. + This is useful for instances where you want to show capacity, or how much of a total has been + uploaded/downloaded.`, + }, + }, +}; diff --git a/packages/react-components/react-progress/src/stories/Progress/index.stories.tsx b/packages/react-components/react-progress/src/stories/Progress/index.stories.tsx index 34db5475de66b7..3d69a736432548 100644 --- a/packages/react-components/react-progress/src/stories/Progress/index.stories.tsx +++ b/packages/react-components/react-progress/src/stories/Progress/index.stories.tsx @@ -4,9 +4,9 @@ import descriptionMd from './ProgressDescription.md'; import bestPracticesMd from './ProgressBestPractices.md'; export { Default } from './ProgressDefault.stories'; -export { Appearance } from './ProgressAppearance.stories'; export { Thickness } from './ProgressBarThickness.stories'; export { Indeterminate } from './ProgressIndeterminate.stories'; +export { Max } from './ProgressMax.stories'; export default { title: 'Preview Components/Progress',