From 38c471414c8ab5db4797954b44ee0ce9e1add9a3 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Thu, 24 Mar 2022 13:58:35 -0700 Subject: [PATCH 01/20] Initial Spinner Implementation --- .../src/components/Spinner/DefaultSvg.tsx | 61 +++++++ .../src/components/Spinner/Spinner.types.ts | 38 +++- .../src/components/Spinner/renderSpinner.tsx | 10 +- .../src/components/Spinner/useSpinner.ts | 28 --- .../src/components/Spinner/useSpinner.tsx | 42 +++++ .../components/Spinner/useSpinnerStyles.ts | 172 ++++++++++++++++-- 6 files changed, 305 insertions(+), 46 deletions(-) create mode 100644 packages/react-spinner/src/components/Spinner/DefaultSvg.tsx delete mode 100644 packages/react-spinner/src/components/Spinner/useSpinner.ts create mode 100644 packages/react-spinner/src/components/Spinner/useSpinner.tsx diff --git a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx new file mode 100644 index 00000000000000..ff4273fbac2fa2 --- /dev/null +++ b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx @@ -0,0 +1,61 @@ +import * as React from 'react'; +import { SpinnerProps } from './Spinner.types'; + +export const DefaultSvg: React.FC = props => { + const { size } = props; + // Stroke widths for the Spinner + let spinnerStrokeWidth = 3; + switch (size) { + case 'tiny': + case 'extra-small': + case 'small': + spinnerStrokeWidth = 2; + break; + case 'huge': + spinnerStrokeWidth = 4; + } + let dynamicSize = 32; + switch (size) { + case 'tiny': + dynamicSize = 20; + break; + case 'extra-small': + dynamicSize = 24; + break; + case 'small': + dynamicSize = 28; + break; + case 'large': + dynamicSize = 36; + break; + case 'extra-large': + dynamicSize = 40; + break; + case 'huge': + dynamicSize = 44; + } + return ( + <> + + + + + + ); +}; diff --git a/packages/react-spinner/src/components/Spinner/Spinner.types.ts b/packages/react-spinner/src/components/Spinner/Spinner.types.ts index 6d446f122c3bd0..96dcc98f7247f8 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.types.ts +++ b/packages/react-spinner/src/components/Spinner/Spinner.types.ts @@ -1,17 +1,51 @@ import type { ComponentProps, ComponentState, Slot } from '@fluentui/react-utilities'; +import { Label } from '@fluentui/react-label'; export type SpinnerSlots = { + /** + * The root of the Spinner. + * The root slot receives the `className` and `style` specified directly on the ``. + */ root: Slot<'div'>; + /** + * The slot for the animated svg. + * The spinner slot receives the `className` and `style` that handles the spinning animation. + * An svg is also rendered as a child of this slot + */ + spinner: Slot<'span'>; + /** + * The label of the Slider. + * The label slot receives the styling related to the text associated with the Spinner. + */ + label: Slot; }; type SpinnerCommons = { - // TODO Add things shared between props and state here + /** + * The appearance of the Spinner. Defaults to primary + */ + appearance?: 'primary' | 'inverted'; + + /** + * Where the label is positioned relative to the Spinner + */ + labelPosition?: 'above' | 'below' | 'before' | 'after'; + + /** + * The size of the spinner. Defaults to medium + */ + size?: 'tiny' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large' | 'huge'; + + /** + * The status of the Spinner. Defaults to active + */ + status?: 'active' | 'inactive'; }; /** * Spinner Props */ -export type SpinnerProps = ComponentProps & SpinnerCommons; +export type SpinnerProps = Omit, 'size'> & Partial; /** * State used in rendering Spinner diff --git a/packages/react-spinner/src/components/Spinner/renderSpinner.tsx b/packages/react-spinner/src/components/Spinner/renderSpinner.tsx index 2d4bcf8956567c..90da874a6a75d1 100644 --- a/packages/react-spinner/src/components/Spinner/renderSpinner.tsx +++ b/packages/react-spinner/src/components/Spinner/renderSpinner.tsx @@ -7,7 +7,13 @@ import type { SpinnerState, SpinnerSlots } from './Spinner.types'; */ export const renderSpinner_unstable = (state: SpinnerState) => { const { slots, slotProps } = getSlots(state); - + const { labelPosition } = state; // TODO Add additional slots in the appropriate place - return ; + return ( + + {(labelPosition === 'above' || labelPosition === 'before') && } + + {(labelPosition === 'below' || labelPosition === 'after') && } + + ); }; diff --git a/packages/react-spinner/src/components/Spinner/useSpinner.ts b/packages/react-spinner/src/components/Spinner/useSpinner.ts deleted file mode 100644 index 9b47a50f884a55..00000000000000 --- a/packages/react-spinner/src/components/Spinner/useSpinner.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from 'react'; -import { getNativeElementProps } from '@fluentui/react-utilities'; -import type { SpinnerProps, SpinnerState } from './Spinner.types'; - -/** - * Create the state required to render Spinner. - * - * The returned state can be modified with hooks such as useSpinnerStyles_unstable, - * before being passed to renderSpinner_unstable. - * - * @param props - props from this instance of Spinner - * @param ref - reference to root HTMLElement of Spinner - */ -export const useSpinner_unstable = (props: SpinnerProps, ref: React.Ref): SpinnerState => { - return { - // TODO add appropriate props/defaults - components: { - // TODO add each slot's element type or component - root: 'div', - }, - // TODO add appropriate slots, for example: - // mySlot: resolveShorthand(props.mySlot), - root: getNativeElementProps('div', { - ref, - ...props, - }), - }; -}; diff --git a/packages/react-spinner/src/components/Spinner/useSpinner.tsx b/packages/react-spinner/src/components/Spinner/useSpinner.tsx new file mode 100644 index 00000000000000..8c76e5358a320b --- /dev/null +++ b/packages/react-spinner/src/components/Spinner/useSpinner.tsx @@ -0,0 +1,42 @@ +import * as React from 'react'; +import { getNativeElementProps, resolveShorthand } from '@fluentui/react-utilities'; +import type { SpinnerProps, SpinnerState } from './Spinner.types'; +import { Label } from '@fluentui/react-label'; +import { DefaultSvg } from './DefaultSvg'; + +/** + * Create the state required to render Spinner. + * + * The returned state can be modified with hooks such as useSpinnerStyles_unstable, + * before being passed to renderSpinner_unstable. + * + * @param props - props from this instance of Spinner + * @param ref - reference to root HTMLElement of Spinner + */ +export const useSpinner_unstable = (props: SpinnerProps, ref: React.Ref): SpinnerState => { + // Props + const { appearance = 'primary', labelPosition, size = 'medium', status = 'active' } = props; + + const state: SpinnerState = { + appearance, + labelPosition, + size, + status, + components: { + root: 'div', + spinner: 'span', + label: Label, + }, + root: getNativeElementProps('div', { ref, ...props }, ['size']), + spinner: resolveShorthand(props.spinner, { + required: true, + defaultProps: { + children: , + }, + }), + label: resolveShorthand(props.label, { + required: false, + }), + }; + return state; +}; diff --git a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts index 470ab188e041d4..55dd441af007d7 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts +++ b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts @@ -1,34 +1,178 @@ -import { SlotClassNames } from '@fluentui/react-utilities'; -import { makeStyles, mergeClasses } from '@griffel/react'; -import type { SpinnerSlots, SpinnerState } from './Spinner.types'; +import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { tokens } from '@fluentui/react-theme'; +import type { SpinnerState, SpinnerSlots } from './Spinner.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; -/** - * @deprecated Use `spinnerClassNames.root` instead. - */ -export const spinnerClassName = 'fui-Spinner'; export const spinnerClassNames: SlotClassNames = { root: 'fui-Spinner', + spinner: 'fui-Spinner__spinner', + label: 'fui-Spinner__label', +}; + +// Sizes for the Spinner +const spinnnerSizes = { + tiny: '20px', + extraSmall: '24px', + small: '28px', + medium: '32px', + large: '36px', + extraLarge: '40px', + huge: '44px', +}; + +// Stroke widths for the Spinner +const spinnerStrokeWidth = { + sWidth: '2px', + mWidth: '3px', + lWidth: '4px', }; + /** * Styles for the root slot */ -const useStyles = makeStyles({ +const useRootStyles = makeStyles({ root: { - // TODO Add default styles for the root element + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + ...shorthands.gap('8px'), + }, + + horizontal: { + flexDirection: 'row', + }, + + vertical: { + flexDirection: 'column', + }, +}); + +const useLoaderStyles = makeStyles({ + // global SVG class + spinnerSVG: { + animationName: 'rotate', + animationDuration: '3s', + animationIterationCount: 'infinite', + animationTimingFunction: 'linear', + backgroundColor: 'transparent', + }, + + tiny: { + height: spinnnerSizes.tiny, + width: spinnnerSizes.tiny, + strokeWidth: spinnerStrokeWidth.sWidth, + }, + + extraSmall: { + height: spinnnerSizes.extraSmall, + width: spinnnerSizes.extraSmall, + strokeWidth: spinnerStrokeWidth.sWidth, + }, + + small: { + height: spinnnerSizes.small, + width: spinnnerSizes.small, + strokeWidth: spinnerStrokeWidth.sWidth, }, - // TODO add additional classes for different states and/or slots + medium: { + height: spinnnerSizes.medium, + width: spinnnerSizes.medium, + strokeWidth: spinnerStrokeWidth.mWidth, + }, + + large: { + height: spinnnerSizes.large, + width: spinnnerSizes.large, + strokeWidth: spinnerStrokeWidth.mWidth, + }, + + extraLarge: { + height: spinnnerSizes.extraLarge, + width: spinnnerSizes.extraLarge, + strokeWidth: spinnerStrokeWidth.mWidth, + }, + + huge: { + height: spinnnerSizes.huge, + width: spinnnerSizes.huge, + strokeWidth: spinnerStrokeWidth.lWidth, + }, + + // global class for Spinner track + spinnerTrack: { + stroke: tokens.colorBrandStroke2, + }, + + // modifier class for Spinner track if appearance="inverted" + spinnerTrackInverted: { + stroke: 'rgba(255,255,255,0.2)', + }, + + // global Spinner trail class + spinnerTail: { + stroke: tokens.colorBrandStroke1, + animationName: 'dash', + animationDuration: '1.5s', + animationIterationCount: 'infinite', + // --easyEasy token + animationTimingFunction: 'cubic-bezier(0.33,0,0.67,1)', + zIndex: 999, + strokeLinecap: 'round', + transform: 'rotate(-90deg)', + transformOrigin: '50% 50%', + }, + // modifier class for Spinner trail + + spinnerTailInverted: { + stroke: tokens.colorNeutralStrokeOnBrand2, + }, +}); + +const useLabelStyles = makeStyles({ + // style for label + spinnerLabel: { + color: tokens.colorNeutralForeground1, + }, + + spinnerLabelInverted: { + color: tokens.colorNeutralStrokeOnBrand2, + }, }); /** * Apply styling to the Spinner slots based on the state */ export const useSpinnerStyles_unstable = (state: SpinnerState): SpinnerState => { - const styles = useStyles(); - state.root.className = mergeClasses(spinnerClassNames.root, styles.root, state.root.className); + const { labelPosition, size = 'medium' } = state; + const rootStyles = useRootStyles(); + const spinnerStyles = useLoaderStyles(); + const labelStyles = useLabelStyles(); - // TODO Add class names to slots, for example: - // state.mySlot.className = mergeClasses(styles.mySlot, state.mySlot.className); + state.root.className = mergeClasses( + spinnerClassNames.root, + rootStyles.root, + (labelPosition === 'above' || labelPosition === 'below') && rootStyles.vertical, + (labelPosition === 'before' || labelPosition === 'after') && rootStyles.horizontal, + state.root.className, + ); + if (state.spinner) { + state.spinner.className = mergeClasses( + spinnerClassNames.spinner, + spinnerStyles.spinnerSVG, + size === 'extra-small' && spinnerStyles.extraSmall, + size === 'extra-large' && spinnerStyles.extraLarge, + size !== 'extra-large' && size !== 'extra-small' && spinnerStyles[size], + state.appearance === 'inverted' ? spinnerStyles.spinnerTrackInverted : spinnerStyles.spinnerTrack, + state.appearance === 'inverted' ? spinnerStyles.spinnerTailInverted : spinnerStyles.spinnerTail, + ); + } + if (state.label) { + state.label.className = mergeClasses( + spinnerClassNames.label, + state.appearance === 'inverted' ? labelStyles.spinnerLabelInverted : labelStyles.spinnerLabel, + ); + } return state; }; From 19e3cf032e03c43a917a2ac3e0705ed81a3c223f Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Fri, 25 Mar 2022 02:40:28 -0700 Subject: [PATCH 02/20] Update styling and useSpinner --- .../src/components/Spinner/DefaultSvg.tsx | 65 +------- .../src/components/Spinner/useSpinner.tsx | 2 +- .../components/Spinner/useSpinnerStyles.ts | 156 +++++++++++++----- 3 files changed, 123 insertions(+), 100 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx index ff4273fbac2fa2..0d85f011269632 100644 --- a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx +++ b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx @@ -1,61 +1,8 @@ import * as React from 'react'; -import { SpinnerProps } from './Spinner.types'; -export const DefaultSvg: React.FC = props => { - const { size } = props; - // Stroke widths for the Spinner - let spinnerStrokeWidth = 3; - switch (size) { - case 'tiny': - case 'extra-small': - case 'small': - spinnerStrokeWidth = 2; - break; - case 'huge': - spinnerStrokeWidth = 4; - } - let dynamicSize = 32; - switch (size) { - case 'tiny': - dynamicSize = 20; - break; - case 'extra-small': - dynamicSize = 24; - break; - case 'small': - dynamicSize = 28; - break; - case 'large': - dynamicSize = 36; - break; - case 'extra-large': - dynamicSize = 40; - break; - case 'huge': - dynamicSize = 44; - } - return ( - <> - - - - - - ); -}; +export const DefaultSvg = () => ( + + + + +); diff --git a/packages/react-spinner/src/components/Spinner/useSpinner.tsx b/packages/react-spinner/src/components/Spinner/useSpinner.tsx index 8c76e5358a320b..a2f3619ad549bd 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinner.tsx +++ b/packages/react-spinner/src/components/Spinner/useSpinner.tsx @@ -31,7 +31,7 @@ export const useSpinner_unstable = (props: SpinnerProps, ref: React.Ref, + children: , }, }), label: resolveShorthand(props.label, { diff --git a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts index 55dd441af007d7..8c89ef4cd4b976 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts +++ b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts @@ -9,6 +9,15 @@ export const spinnerClassNames: SlotClassNames = { label: 'fui-Spinner__label', }; +const rvalues = { + tiny: '9', + extraSmall: '11', + small: '13', + medium: '14.5', + large: '16.5', + extraLarge: '18.5', + huge: '20', +}; // Sizes for the Spinner const spinnnerSizes = { tiny: '20px', @@ -50,82 +59,149 @@ const useRootStyles = makeStyles({ const useLoaderStyles = makeStyles({ // global SVG class spinnerSVG: { - animationName: 'rotate', - animationDuration: '3s', - animationIterationCount: 'infinite', - animationTimingFunction: 'linear', - backgroundColor: 'transparent', + [`& > svg`]: { + animationName: { + '0%': { transform: 'rotate(0deg)' }, + '100%': { transform: 'rotate(360deg)' }, + }, + animationDuration: '3s', + animationIterationCount: 'infinite', + animationTimingFunction: 'linear', + backgroundColor: 'transparent', + }, + [`& > svg > circle`]: { + cx: '50%', + cy: '50%', + fill: 'none', + }, }, tiny: { - height: spinnnerSizes.tiny, - width: spinnnerSizes.tiny, - strokeWidth: spinnerStrokeWidth.sWidth, + [`& > svg`]: { + height: spinnnerSizes.tiny, + width: spinnnerSizes.tiny, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.sWidth, + r: rvalues.tiny, + }, }, extraSmall: { - height: spinnnerSizes.extraSmall, - width: spinnnerSizes.extraSmall, - strokeWidth: spinnerStrokeWidth.sWidth, + [`& > svg`]: { + height: spinnnerSizes.extraSmall, + width: spinnnerSizes.extraSmall, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.sWidth, + r: rvalues.extraSmall, + }, }, small: { - height: spinnnerSizes.small, - width: spinnnerSizes.small, - strokeWidth: spinnerStrokeWidth.sWidth, + [`& > svg`]: { + height: spinnnerSizes.small, + width: spinnnerSizes.small, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.sWidth, + r: rvalues.small, + }, }, medium: { - height: spinnnerSizes.medium, - width: spinnnerSizes.medium, - strokeWidth: spinnerStrokeWidth.mWidth, + [`& > svg`]: { + height: spinnnerSizes.medium, + width: spinnnerSizes.medium, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.mWidth, + r: rvalues.medium, + }, }, large: { - height: spinnnerSizes.large, - width: spinnnerSizes.large, - strokeWidth: spinnerStrokeWidth.mWidth, + [`& > svg`]: { + height: spinnnerSizes.large, + width: spinnnerSizes.large, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.mWidth, + r: rvalues.large, + }, }, extraLarge: { - height: spinnnerSizes.extraLarge, - width: spinnnerSizes.extraLarge, - strokeWidth: spinnerStrokeWidth.mWidth, + [`& > svg`]: { + height: spinnnerSizes.extraLarge, + width: spinnnerSizes.extraLarge, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.mWidth, + r: rvalues.extraLarge, + }, }, huge: { - height: spinnnerSizes.huge, - width: spinnnerSizes.huge, - strokeWidth: spinnerStrokeWidth.lWidth, + [`& > svg`]: { + height: spinnnerSizes.huge, + width: spinnnerSizes.huge, + }, + [`& > svg > circle`]: { + strokeWidth: spinnerStrokeWidth.lWidth, + r: rvalues.huge, + }, }, // global class for Spinner track spinnerTrack: { - stroke: tokens.colorBrandStroke2, + [`& > svg > circle#track`]: { + stroke: tokens.colorBrandStroke2, + }, }, // modifier class for Spinner track if appearance="inverted" spinnerTrackInverted: { - stroke: 'rgba(255,255,255,0.2)', + [`& > svg > circle#track`]: { + stroke: 'rgba(255,255,255,0.2)', + }, }, // global Spinner trail class spinnerTail: { - stroke: tokens.colorBrandStroke1, - animationName: 'dash', - animationDuration: '1.5s', - animationIterationCount: 'infinite', - // --easyEasy token - animationTimingFunction: 'cubic-bezier(0.33,0,0.67,1)', - zIndex: 999, - strokeLinecap: 'round', - transform: 'rotate(-90deg)', - transformOrigin: '50% 50%', + [`& > svg > circle#tail`]: { + stroke: tokens.colorBrandStroke1, + animationName: { + '0%': { + strokeDasharray: '1,150', + strokeDashoffset: '0', + }, + + '50%': { + strokeDasharray: '90,150', + strokeDashoffset: '-35', + }, + + '100%': { + strokeDasharray: '90,150', + strokeDashoffset: '-124', + }, + }, + animationDuration: '1.5s', + animationIterationCount: 'infinite', + animationTimingFunction: 'cubic-bezier(0.33,0,0.67,1)', + //zIndex: 999, + strokeLinecap: 'round', + transform: 'rotate(-90deg)', + transformOrigin: '50% 50%', + }, }, - // modifier class for Spinner trail + // modifier class for Spinner trail spinnerTailInverted: { - stroke: tokens.colorNeutralStrokeOnBrand2, + [`& > svg > circle#tail`]: { + stroke: tokens.colorNeutralStrokeOnBrand2, + }, }, }); From de3795794f7acd1540fabd01fe6b9721b63a4a91 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Fri, 25 Mar 2022 12:14:54 -0700 Subject: [PATCH 03/20] update index files --- .../react-spinner/src/components/Spinner/index.ts | 1 + packages/react-spinner/src/index.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/index.ts b/packages/react-spinner/src/components/Spinner/index.ts index 13a43eb7f804ee..1cb06bcb4018b2 100644 --- a/packages/react-spinner/src/components/Spinner/index.ts +++ b/packages/react-spinner/src/components/Spinner/index.ts @@ -3,3 +3,4 @@ export * from './Spinner.types'; export * from './renderSpinner'; export * from './useSpinner'; export * from './useSpinnerStyles'; +export * from './DefaultSvg'; diff --git a/packages/react-spinner/src/index.ts b/packages/react-spinner/src/index.ts index c86731e7b2b49d..62a72b8ef840f0 100644 --- a/packages/react-spinner/src/index.ts +++ b/packages/react-spinner/src/index.ts @@ -1,3 +1,9 @@ -// TODO: replace with real exports -export {}; -export * from './Spinner'; +export { + Spinner, + spinnerClassNames, + renderSpinner_unstable, + useSpinner_unstable, + DefaultSvg, + useSpinnerStyles_unstable, +} from './Spinner'; +export type { SpinnerProps, SpinnerSlots, SpinnerState } from './Spinner'; From 6eb6961b32af20b758cfc0f4df25cec8afc56b62 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Fri, 25 Mar 2022 13:02:31 -0700 Subject: [PATCH 04/20] api update --- packages/react-spinner/etc/react-spinner.api.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/react-spinner/etc/react-spinner.api.md b/packages/react-spinner/etc/react-spinner.api.md index 3f75a72e264fea..bca9b4324568b9 100644 --- a/packages/react-spinner/etc/react-spinner.api.md +++ b/packages/react-spinner/etc/react-spinner.api.md @@ -7,9 +7,13 @@ import type { ComponentProps } from '@fluentui/react-utilities'; import type { ComponentState } from '@fluentui/react-utilities'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; +import { Label } from '@fluentui/react-label'; import * as React_2 from 'react'; import type { Slot } from '@fluentui/react-utilities'; -import { SlotClassNames } from '@fluentui/react-utilities'; +import type { SlotClassNames } from '@fluentui/react-utilities'; + +// @public (undocumented) +export const DefaultSvg: () => JSX.Element; // @public export const renderSpinner_unstable: (state: SpinnerState) => JSX.Element; @@ -17,20 +21,19 @@ export const renderSpinner_unstable: (state: SpinnerState) => JSX.Element; // @public export const Spinner: ForwardRefComponent; -// @public @deprecated (undocumented) -export const spinnerClassName = "fui-Spinner"; - // @public (undocumented) export const spinnerClassNames: SlotClassNames; // Warning: (ae-forgotten-export) The symbol "SpinnerCommons" needs to be exported by the entry point index.d.ts // // @public -export type SpinnerProps = ComponentProps & SpinnerCommons; +export type SpinnerProps = Omit, 'size'> & Partial; // @public (undocumented) export type SpinnerSlots = { root: Slot<'div'>; + spinner: Slot<'span'>; + label: Slot; }; // @public From 4cdfb16f17e12f6b7e148ef187683736ef17ea2e Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Fri, 25 Mar 2022 13:33:41 -0700 Subject: [PATCH 05/20] Make spinner and label slots optional and update api --- packages/react-spinner/etc/react-spinner.api.md | 4 ++-- .../react-spinner/src/components/Spinner/Spinner.types.ts | 4 ++-- .../react-spinner/src/components/Spinner/renderSpinner.tsx | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/react-spinner/etc/react-spinner.api.md b/packages/react-spinner/etc/react-spinner.api.md index bca9b4324568b9..5fc94234a8fccb 100644 --- a/packages/react-spinner/etc/react-spinner.api.md +++ b/packages/react-spinner/etc/react-spinner.api.md @@ -32,8 +32,8 @@ export type SpinnerProps = Omit, 'size'> & Partial< // @public (undocumented) export type SpinnerSlots = { root: Slot<'div'>; - spinner: Slot<'span'>; - label: Slot; + spinner?: Slot<'span'>; + label?: Slot; }; // @public diff --git a/packages/react-spinner/src/components/Spinner/Spinner.types.ts b/packages/react-spinner/src/components/Spinner/Spinner.types.ts index 96dcc98f7247f8..39c0f506ba1ab6 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.types.ts +++ b/packages/react-spinner/src/components/Spinner/Spinner.types.ts @@ -12,12 +12,12 @@ export type SpinnerSlots = { * The spinner slot receives the `className` and `style` that handles the spinning animation. * An svg is also rendered as a child of this slot */ - spinner: Slot<'span'>; + spinner?: Slot<'span'>; /** * The label of the Slider. * The label slot receives the styling related to the text associated with the Spinner. */ - label: Slot; + label?: Slot; }; type SpinnerCommons = { diff --git a/packages/react-spinner/src/components/Spinner/renderSpinner.tsx b/packages/react-spinner/src/components/Spinner/renderSpinner.tsx index 90da874a6a75d1..0b07a373c89a73 100644 --- a/packages/react-spinner/src/components/Spinner/renderSpinner.tsx +++ b/packages/react-spinner/src/components/Spinner/renderSpinner.tsx @@ -11,9 +11,9 @@ export const renderSpinner_unstable = (state: SpinnerState) => { // TODO Add additional slots in the appropriate place return ( - {(labelPosition === 'above' || labelPosition === 'before') && } - - {(labelPosition === 'below' || labelPosition === 'after') && } + {slots.label && (labelPosition === 'above' || labelPosition === 'before') && } + {slots.spinner && } + {slots.label && (labelPosition === 'below' || labelPosition === 'after') && } ); }; From d54a4e5e338989efeccce942bed6a022e7656d07 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Fri, 25 Mar 2022 13:55:45 -0700 Subject: [PATCH 06/20] Add react-label dependency --- packages/react-spinner/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-spinner/package.json b/packages/react-spinner/package.json index b91a8930e4b613..e320228f787084 100644 --- a/packages/react-spinner/package.json +++ b/packages/react-spinner/package.json @@ -34,6 +34,7 @@ }, "dependencies": { "@fluentui/react-theme": "9.0.0-rc.4", + "@fluentui/react-label": "9.0.0-beta.9", "@fluentui/react-utilities": "9.0.0-rc.5", "@griffel/react": "1.0.0", "tslib": "^2.1.0" From 98d93a7ae110e27e5139f6c2702776cb9c042688 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Sun, 27 Mar 2022 16:52:43 -0700 Subject: [PATCH 07/20] update conformance tests and snapshots --- .../src/components/Spinner/Spinner.test.tsx | 5 +++++ .../Spinner/__snapshots__/Spinner.test.tsx.snap | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx index 5ed2dc68b04ff2..70312a404eb1b5 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx +++ b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx @@ -7,6 +7,11 @@ describe('Spinner', () => { isConformant({ Component: Spinner, displayName: 'Spinner', + disabledTests: [ + 'component-has-static-classname', + 'component-has-static-classname-exported', + 'component-has-static-classnames-object', + ], }); // TODO add more tests here, and create visual regression tests in /apps/vr-tests diff --git a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap index d24d2fc0ad0aad..d586da6e1b48f9 100644 --- a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap +++ b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap @@ -5,7 +5,20 @@ exports[`Spinner renders a default state 1`] = `
- Default Spinner + + + + + +
`; From a604688c2ca71284497422b275da1072dd02e9cb Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Tue, 29 Mar 2022 17:16:05 -0700 Subject: [PATCH 08/20] Add stories and update styling --- .../src/components/Spinner/DefaultSvg.tsx | 4 +- .../src/components/Spinner/Spinner.test.tsx | 6 +- .../src/components/Spinner/index.ts | 1 - .../src/components/Spinner/renderSpinner.tsx | 5 +- .../src/components/Spinner/useSpinner.tsx | 2 +- .../components/Spinner/useSpinnerStyles.ts | 86 +++++++++++++++++-- packages/react-spinner/src/index.ts | 1 - .../src/stories/Spinner.stories.tsx | 3 + .../src/stories/SpinnerAppearance.stories.tsx | 28 ++++++ .../src/stories/SpinnerLabel.stories.tsx | 26 ++++++ .../src/stories/SpinnerSize.stories.tsx | 48 +++++++++++ 11 files changed, 191 insertions(+), 19 deletions(-) create mode 100644 packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx create mode 100644 packages/react-spinner/src/stories/SpinnerLabel.stories.tsx create mode 100644 packages/react-spinner/src/stories/SpinnerSize.stories.tsx diff --git a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx index 0d85f011269632..27cbccdf3b1372 100644 --- a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx +++ b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; export const DefaultSvg = () => ( - - + + ); diff --git a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx index 70312a404eb1b5..f1dd26a60a966e 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx +++ b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx @@ -7,11 +7,7 @@ describe('Spinner', () => { isConformant({ Component: Spinner, displayName: 'Spinner', - disabledTests: [ - 'component-has-static-classname', - 'component-has-static-classname-exported', - 'component-has-static-classnames-object', - ], + disabledTests: ['component-has-static-classname'], }); // TODO add more tests here, and create visual regression tests in /apps/vr-tests diff --git a/packages/react-spinner/src/components/Spinner/index.ts b/packages/react-spinner/src/components/Spinner/index.ts index 1cb06bcb4018b2..13a43eb7f804ee 100644 --- a/packages/react-spinner/src/components/Spinner/index.ts +++ b/packages/react-spinner/src/components/Spinner/index.ts @@ -3,4 +3,3 @@ export * from './Spinner.types'; export * from './renderSpinner'; export * from './useSpinner'; export * from './useSpinnerStyles'; -export * from './DefaultSvg'; diff --git a/packages/react-spinner/src/components/Spinner/renderSpinner.tsx b/packages/react-spinner/src/components/Spinner/renderSpinner.tsx index 0b07a373c89a73..54800d88dcc088 100644 --- a/packages/react-spinner/src/components/Spinner/renderSpinner.tsx +++ b/packages/react-spinner/src/components/Spinner/renderSpinner.tsx @@ -7,12 +7,11 @@ import type { SpinnerState, SpinnerSlots } from './Spinner.types'; */ export const renderSpinner_unstable = (state: SpinnerState) => { const { slots, slotProps } = getSlots(state); - const { labelPosition } = state; - // TODO Add additional slots in the appropriate place + const { labelPosition, status } = state; return ( {slots.label && (labelPosition === 'above' || labelPosition === 'before') && } - {slots.spinner && } + {slots.spinner && status === 'active' && } {slots.label && (labelPosition === 'below' || labelPosition === 'after') && } ); diff --git a/packages/react-spinner/src/components/Spinner/useSpinner.tsx b/packages/react-spinner/src/components/Spinner/useSpinner.tsx index a2f3619ad549bd..7c7f385b037494 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinner.tsx +++ b/packages/react-spinner/src/components/Spinner/useSpinner.tsx @@ -15,7 +15,7 @@ import { DefaultSvg } from './DefaultSvg'; */ export const useSpinner_unstable = (props: SpinnerProps, ref: React.Ref): SpinnerState => { // Props - const { appearance = 'primary', labelPosition, size = 'medium', status = 'active' } = props; + const { appearance = 'primary', labelPosition = 'after', size = 'medium', status = 'active' } = props; const state: SpinnerState = { appearance, diff --git a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts index 8c89ef4cd4b976..17af30c8f3cc0c 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts +++ b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts @@ -36,6 +36,24 @@ const spinnerStrokeWidth = { lWidth: '4px', }; +// Label sizes for the Label slot +const labelSizeTokens = { + body1: { + fontSize: tokens.fontSizeBase300, + lineHeight: tokens.lineHeightBase300, + }, + + subtitle2: { + fontSize: tokens.fontSizeBase400, + lineHeight: tokens.lineHeightBase400, + }, + + subtitle1: { + fontSize: tokens.fontSizeBase500, + lineHeight: tokens.lineHeightBase500, + }, +}; + /** * Styles for the root slot */ @@ -155,21 +173,21 @@ const useLoaderStyles = makeStyles({ // global class for Spinner track spinnerTrack: { - [`& > svg > circle#track`]: { - stroke: tokens.colorBrandStroke2, + [`& > svg > circle.spinner_Track`]: { + stroke: tokens.colorNeutralBackground4, }, }, // modifier class for Spinner track if appearance="inverted" spinnerTrackInverted: { - [`& > svg > circle#track`]: { - stroke: 'rgba(255,255,255,0.2)', + [`& > svg > circle.spinner_Track`]: { + stroke: tokens.colorNeutralBackgroundInverted, }, }, // global Spinner trail class spinnerTail: { - [`& > svg > circle#tail`]: { + [`& > svg > circle.spinner_Tail`]: { stroke: tokens.colorBrandStroke1, animationName: { '0%': { @@ -199,8 +217,31 @@ const useLoaderStyles = makeStyles({ // modifier class for Spinner trail spinnerTailInverted: { - [`& > svg > circle#tail`]: { + [`& > svg > circle.spinner_Tail`]: { stroke: tokens.colorNeutralStrokeOnBrand2, + animationName: { + '0%': { + strokeDasharray: '1,150', + strokeDashoffset: '0', + }, + + '50%': { + strokeDasharray: '90,150', + strokeDashoffset: '-35', + }, + + '100%': { + strokeDasharray: '90,150', + strokeDashoffset: '-124', + }, + }, + animationDuration: '1.5s', + animationIterationCount: 'infinite', + animationTimingFunction: 'cubic-bezier(0.33,0,0.67,1)', + //zIndex: 999, + strokeLinecap: 'round', + transform: 'rotate(-90deg)', + transformOrigin: '50% 50%', }, }, }); @@ -214,6 +255,34 @@ const useLabelStyles = makeStyles({ spinnerLabelInverted: { color: tokens.colorNeutralStrokeOnBrand2, }, + + tiny: { + ...labelSizeTokens.body1, + }, + + extraSmall: { + ...labelSizeTokens.body1, + }, + + small: { + ...labelSizeTokens.body1, + }, + + medium: { + ...labelSizeTokens.subtitle2, + }, + + large: { + ...labelSizeTokens.subtitle2, + }, + + extraLarge: { + ...labelSizeTokens.subtitle2, + }, + + huge: { + ...labelSizeTokens.subtitle1, + }, }); /** @@ -241,12 +310,17 @@ export const useSpinnerStyles_unstable = (state: SpinnerState): SpinnerState => size !== 'extra-large' && size !== 'extra-small' && spinnerStyles[size], state.appearance === 'inverted' ? spinnerStyles.spinnerTrackInverted : spinnerStyles.spinnerTrack, state.appearance === 'inverted' ? spinnerStyles.spinnerTailInverted : spinnerStyles.spinnerTail, + state.spinner.className, ); } if (state.label) { state.label.className = mergeClasses( spinnerClassNames.label, + size === 'extra-small' && labelStyles.extraSmall, + size === 'extra-large' && labelStyles.extraLarge, + size !== 'extra-large' && size !== 'extra-small' && labelStyles[size], state.appearance === 'inverted' ? labelStyles.spinnerLabelInverted : labelStyles.spinnerLabel, + state.label.className, ); } diff --git a/packages/react-spinner/src/index.ts b/packages/react-spinner/src/index.ts index 62a72b8ef840f0..9aa0dbaa3627cf 100644 --- a/packages/react-spinner/src/index.ts +++ b/packages/react-spinner/src/index.ts @@ -3,7 +3,6 @@ export { spinnerClassNames, renderSpinner_unstable, useSpinner_unstable, - DefaultSvg, useSpinnerStyles_unstable, } from './Spinner'; export type { SpinnerProps, SpinnerSlots, SpinnerState } from './Spinner'; diff --git a/packages/react-spinner/src/stories/Spinner.stories.tsx b/packages/react-spinner/src/stories/Spinner.stories.tsx index 89405f4c5ea137..e7372c5421c311 100644 --- a/packages/react-spinner/src/stories/Spinner.stories.tsx +++ b/packages/react-spinner/src/stories/Spinner.stories.tsx @@ -4,6 +4,9 @@ import descriptionMd from './SpinnerDescription.md'; import bestPracticesMd from './SpinnerBestPractices.md'; export { Default } from './SpinnerDefault.stories'; +export { Appearance } from './SpinnerAppearance.stories'; +export { Labels } from './SpinnerLabel.stories'; +export { Size } from './SpinnerSize.stories'; export default { title: 'Components/Spinner', diff --git a/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx b/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx new file mode 100644 index 00000000000000..6c937875182513 --- /dev/null +++ b/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx @@ -0,0 +1,28 @@ +import * as React from 'react'; +import { useId } from '@fluentui/react-utilities'; +import { Label } from '@fluentui/react-label'; +import { makeStyles, shorthands } from '@griffel/react'; +import { Spinner } from '../index'; + +const useStyles = makeStyles({ + container: { + '> div': { ...shorthands.padding('20px') }, + '& label': { display: 'block', marginBottom: '10px' }, + }, +}); + +export const Appearance = () => { + const invertedId = useId('inverted'); + const primaryId = useId('primary'); + const styles = useStyles(); + + return ( +
+ + + + + +
+ ); +}; diff --git a/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx b/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx new file mode 100644 index 00000000000000..48460dce1d2e45 --- /dev/null +++ b/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx @@ -0,0 +1,26 @@ +import * as React from 'react'; +import { Label } from '@fluentui/react-label'; +import { makeStyles, shorthands } from '@griffel/react'; +import { Spinner } from '../index'; + +const useStyles = makeStyles({ + container: { + '> div': { ...shorthands.padding('20px') }, + '& label': { display: 'block', marginBottom: '10px' }, + }, +}); + +export const Labels = () => { + const styles = useStyles(); + return ( +
+ Label Position Before...} /> + + Label Position After...} /> + + Label Position Above...} /> + + Label Position Below...} /> +
+ ); +}; diff --git a/packages/react-spinner/src/stories/SpinnerSize.stories.tsx b/packages/react-spinner/src/stories/SpinnerSize.stories.tsx new file mode 100644 index 00000000000000..d922b3087feb9a --- /dev/null +++ b/packages/react-spinner/src/stories/SpinnerSize.stories.tsx @@ -0,0 +1,48 @@ +import * as React from 'react'; +import { useId } from '@fluentui/react-utilities'; +import { Label } from '@fluentui/react-label'; +import { makeStyles, shorthands } from '@griffel/react'; +import { Spinner } from '../index'; + +const useStyles = makeStyles({ + container: { + '> div': { ...shorthands.padding('20px') }, + '& label': { display: 'block', marginBottom: '10px' }, + }, +}); + +export const Size = () => { + const tinyId = useId('tiny'); + const extraSmallId = useId('extra-small'); + const smallId = useId('small'); + const mediumId = useId('medium'); + const largeId = useId('large'); + const extraLargeId = useId('extra-large'); + const hugeId = useId('huge'); + const styles = useStyles(); + + return ( +
+ + + + + + + + + + + + + + + + + + + + +
+ ); +}; From 0608aa6f7bbe4307b65e6397bcf7d926fee2a4ad Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Tue, 29 Mar 2022 18:44:50 -0700 Subject: [PATCH 09/20] api update --- packages/react-spinner/etc/react-spinner.api.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/react-spinner/etc/react-spinner.api.md b/packages/react-spinner/etc/react-spinner.api.md index 5fc94234a8fccb..ed8c5330659a69 100644 --- a/packages/react-spinner/etc/react-spinner.api.md +++ b/packages/react-spinner/etc/react-spinner.api.md @@ -12,9 +12,6 @@ import * as React_2 from 'react'; import type { Slot } from '@fluentui/react-utilities'; import type { SlotClassNames } from '@fluentui/react-utilities'; -// @public (undocumented) -export const DefaultSvg: () => JSX.Element; - // @public export const renderSpinner_unstable: (state: SpinnerState) => JSX.Element; From 1675276f96546003e8dcd3a029976d71ede47094 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Tue, 29 Mar 2022 23:43:07 -0700 Subject: [PATCH 10/20] update tests --- .../react-spinner/src/components/Spinner/Spinner.test.tsx | 2 +- .../components/Spinner/__snapshots__/Spinner.test.tsx.snap | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx index f1dd26a60a966e..8d62a4fb669f00 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx +++ b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx @@ -7,7 +7,7 @@ describe('Spinner', () => { isConformant({ Component: Spinner, displayName: 'Spinner', - disabledTests: ['component-has-static-classname'], + disabledTests: ['component-has-static-classname', 'component-has-static-classnames-object'], }); // TODO add more tests here, and create visual regression tests in /apps/vr-tests diff --git a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap index d586da6e1b48f9..f053ac9c037ce4 100644 --- a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap +++ b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap @@ -12,10 +12,10 @@ exports[`Spinner renders a default state 1`] = ` role="progressbar" > From 0941f0a37c02294be6e2fd842a6d9d474d57ada0 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Wed, 30 Mar 2022 00:25:45 -0700 Subject: [PATCH 11/20] Update classnames --- .../src/components/Spinner/DefaultSvg.tsx | 4 +-- .../src/components/Spinner/Spinner.test.tsx | 6 +++- .../src/components/Spinner/Spinner.types.ts | 10 +++++-- .../components/Spinner/useSpinnerStyles.ts | 30 +++++++++++++------ 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx index 27cbccdf3b1372..bc07c5266ab68d 100644 --- a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx +++ b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; export const DefaultSvg = () => ( - - + + ); diff --git a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx index 8d62a4fb669f00..70312a404eb1b5 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx +++ b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx @@ -7,7 +7,11 @@ describe('Spinner', () => { isConformant({ Component: Spinner, displayName: 'Spinner', - disabledTests: ['component-has-static-classname', 'component-has-static-classnames-object'], + disabledTests: [ + 'component-has-static-classname', + 'component-has-static-classname-exported', + 'component-has-static-classnames-object', + ], }); // TODO add more tests here, and create visual regression tests in /apps/vr-tests diff --git a/packages/react-spinner/src/components/Spinner/Spinner.types.ts b/packages/react-spinner/src/components/Spinner/Spinner.types.ts index 39c0f506ba1ab6..5ecb870d8901cb 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.types.ts +++ b/packages/react-spinner/src/components/Spinner/Spinner.types.ts @@ -22,22 +22,26 @@ export type SpinnerSlots = { type SpinnerCommons = { /** - * The appearance of the Spinner. Defaults to primary + * The appearance of the Spinner. + * @defaultValue 'primary' */ appearance?: 'primary' | 'inverted'; /** * Where the label is positioned relative to the Spinner + * @defaultValue 'after' */ labelPosition?: 'above' | 'below' | 'before' | 'after'; /** - * The size of the spinner. Defaults to medium + * The size of the spinner. + * @defaultValue 'medium' */ size?: 'tiny' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large' | 'huge'; /** - * The status of the Spinner. Defaults to active + * The status of the Spinner. + * @defaultValue 'active' */ status?: 'active' | 'inactive'; }; diff --git a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts index 17af30c8f3cc0c..1c77a8148f0c1a 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts +++ b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts @@ -9,6 +9,10 @@ export const spinnerClassNames: SlotClassNames = { label: 'fui-Spinner__label', }; +/* + * TODO: Update with proper tokens when added + * Radii for the Spinner circles + */ const rvalues = { tiny: '9', extraSmall: '11', @@ -18,7 +22,11 @@ const rvalues = { extraLarge: '18.5', huge: '20', }; -// Sizes for the Spinner + +/* + * TODO: Update with proper tokens when added + * Sizes for the Spinner + */ const spinnnerSizes = { tiny: '20px', extraSmall: '24px', @@ -29,14 +37,20 @@ const spinnnerSizes = { huge: '44px', }; -// Stroke widths for the Spinner +/* + * TODO: Update with proper tokens when added + * Stroke widths for the Spinner + */ const spinnerStrokeWidth = { sWidth: '2px', mWidth: '3px', lWidth: '4px', }; -// Label sizes for the Label slot +/* + * TODO: Update with proper tokens when added + * Label sizes for the Spinner + */ const labelSizeTokens = { body1: { fontSize: tokens.fontSizeBase300, @@ -173,21 +187,21 @@ const useLoaderStyles = makeStyles({ // global class for Spinner track spinnerTrack: { - [`& > svg > circle.spinner_Track`]: { + [`& > svg > circle.fui-spinner__Track`]: { stroke: tokens.colorNeutralBackground4, }, }, // modifier class for Spinner track if appearance="inverted" spinnerTrackInverted: { - [`& > svg > circle.spinner_Track`]: { + [`& > svg > circle.fui-spinner__Track`]: { stroke: tokens.colorNeutralBackgroundInverted, }, }, // global Spinner trail class spinnerTail: { - [`& > svg > circle.spinner_Tail`]: { + [`& > svg > circle.fui-spinner__Tail`]: { stroke: tokens.colorBrandStroke1, animationName: { '0%': { @@ -208,7 +222,6 @@ const useLoaderStyles = makeStyles({ animationDuration: '1.5s', animationIterationCount: 'infinite', animationTimingFunction: 'cubic-bezier(0.33,0,0.67,1)', - //zIndex: 999, strokeLinecap: 'round', transform: 'rotate(-90deg)', transformOrigin: '50% 50%', @@ -217,7 +230,7 @@ const useLoaderStyles = makeStyles({ // modifier class for Spinner trail spinnerTailInverted: { - [`& > svg > circle.spinner_Tail`]: { + [`& > svg > circle.fui-spinner__Tail`]: { stroke: tokens.colorNeutralStrokeOnBrand2, animationName: { '0%': { @@ -238,7 +251,6 @@ const useLoaderStyles = makeStyles({ animationDuration: '1.5s', animationIterationCount: 'infinite', animationTimingFunction: 'cubic-bezier(0.33,0,0.67,1)', - //zIndex: 999, strokeLinecap: 'round', transform: 'rotate(-90deg)', transformOrigin: '50% 50%', From 64fa1661256a76528cadf3a499f76b62a3d07665 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Wed, 30 Mar 2022 08:39:40 -0700 Subject: [PATCH 12/20] update snapshots --- .../components/Spinner/__snapshots__/Spinner.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap index f053ac9c037ce4..2613583d59db19 100644 --- a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap +++ b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap @@ -12,10 +12,10 @@ exports[`Spinner renders a default state 1`] = ` role="progressbar" > From 02fedb7896d35b476356d2290c3ebbe7760d39f6 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Wed, 30 Mar 2022 12:47:07 -0700 Subject: [PATCH 13/20] update tests --- .../src/components/Spinner/Spinner.test.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx index 70312a404eb1b5..0b50ddca4b4195 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx +++ b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx @@ -7,11 +7,16 @@ describe('Spinner', () => { isConformant({ Component: Spinner, displayName: 'Spinner', - disabledTests: [ - 'component-has-static-classname', - 'component-has-static-classname-exported', - 'component-has-static-classnames-object', - ], + testOptions: { + 'has-static-classnames': [ + { + props: { + label: 'Test Label', + }, + }, + ], + }, + disabledTests: ['component-has-static-classname'], }); // TODO add more tests here, and create visual regression tests in /apps/vr-tests From e5f8a74d4e29afb921a2312f03444d7df2e173d5 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Wed, 30 Mar 2022 12:58:15 -0700 Subject: [PATCH 14/20] update tests --- packages/react-spinner/src/components/Spinner/Spinner.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx index 0b50ddca4b4195..2bbd2c6e7aebc3 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.test.tsx +++ b/packages/react-spinner/src/components/Spinner/Spinner.test.tsx @@ -16,7 +16,7 @@ describe('Spinner', () => { }, ], }, - disabledTests: ['component-has-static-classname'], + disabledTests: ['component-has-static-classname', 'component-has-static-classname-exported'], }); // TODO add more tests here, and create visual regression tests in /apps/vr-tests From cce0d5abca7f7ee9c5ee464fda4b7dddf8284824 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Wed, 30 Mar 2022 17:43:00 -0700 Subject: [PATCH 15/20] Add NonNullable to root and update stories --- .../react-spinner/etc/react-spinner.api.md | 2 +- .../src/components/Spinner/Spinner.types.ts | 2 +- .../src/stories/SpinnerLabel.stories.tsx | 10 +++--- .../src/stories/SpinnerSize.stories.tsx | 31 +++++-------------- 4 files changed, 13 insertions(+), 32 deletions(-) diff --git a/packages/react-spinner/etc/react-spinner.api.md b/packages/react-spinner/etc/react-spinner.api.md index ed8c5330659a69..cdf5eec39992da 100644 --- a/packages/react-spinner/etc/react-spinner.api.md +++ b/packages/react-spinner/etc/react-spinner.api.md @@ -28,7 +28,7 @@ export type SpinnerProps = Omit, 'size'> & Partial< // @public (undocumented) export type SpinnerSlots = { - root: Slot<'div'>; + root: NonNullable>; spinner?: Slot<'span'>; label?: Slot; }; diff --git a/packages/react-spinner/src/components/Spinner/Spinner.types.ts b/packages/react-spinner/src/components/Spinner/Spinner.types.ts index 5ecb870d8901cb..3a22632499d13d 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.types.ts +++ b/packages/react-spinner/src/components/Spinner/Spinner.types.ts @@ -6,7 +6,7 @@ export type SpinnerSlots = { * The root of the Spinner. * The root slot receives the `className` and `style` specified directly on the ``. */ - root: Slot<'div'>; + root: NonNullable>; /** * The slot for the animated svg. * The spinner slot receives the `className` and `style` that handles the spinning animation. diff --git a/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx b/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx index 48460dce1d2e45..443a137180ab6b 100644 --- a/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx +++ b/packages/react-spinner/src/stories/SpinnerLabel.stories.tsx @@ -1,12 +1,10 @@ import * as React from 'react'; -import { Label } from '@fluentui/react-label'; import { makeStyles, shorthands } from '@griffel/react'; import { Spinner } from '../index'; const useStyles = makeStyles({ container: { '> div': { ...shorthands.padding('20px') }, - '& label': { display: 'block', marginBottom: '10px' }, }, }); @@ -14,13 +12,13 @@ export const Labels = () => { const styles = useStyles(); return (
- Label Position Before...} /> + - Label Position After...} /> + - Label Position Above...} /> + - Label Position Below...} /> +
); }; diff --git a/packages/react-spinner/src/stories/SpinnerSize.stories.tsx b/packages/react-spinner/src/stories/SpinnerSize.stories.tsx index d922b3087feb9a..6269b1ba54e3bc 100644 --- a/packages/react-spinner/src/stories/SpinnerSize.stories.tsx +++ b/packages/react-spinner/src/stories/SpinnerSize.stories.tsx @@ -1,48 +1,31 @@ import * as React from 'react'; -import { useId } from '@fluentui/react-utilities'; -import { Label } from '@fluentui/react-label'; import { makeStyles, shorthands } from '@griffel/react'; import { Spinner } from '../index'; const useStyles = makeStyles({ container: { '> div': { ...shorthands.padding('20px') }, - '& label': { display: 'block', marginBottom: '10px' }, }, }); export const Size = () => { - const tinyId = useId('tiny'); - const extraSmallId = useId('extra-small'); - const smallId = useId('small'); - const mediumId = useId('medium'); - const largeId = useId('large'); - const extraLargeId = useId('extra-large'); - const hugeId = useId('huge'); const styles = useStyles(); return (
- - + - - + - - + - - + - - + - - + - - +
); }; From 68f30dd16b6bec2ce54355f6786e95d1a6da2093 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Wed, 30 Mar 2022 17:45:46 -0700 Subject: [PATCH 16/20] Update appearance story --- .../src/stories/SpinnerAppearance.stories.tsx | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx b/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx index 6c937875182513..771cf769777a6a 100644 --- a/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx +++ b/packages/react-spinner/src/stories/SpinnerAppearance.stories.tsx @@ -1,28 +1,21 @@ import * as React from 'react'; -import { useId } from '@fluentui/react-utilities'; -import { Label } from '@fluentui/react-label'; import { makeStyles, shorthands } from '@griffel/react'; import { Spinner } from '../index'; const useStyles = makeStyles({ container: { '> div': { ...shorthands.padding('20px') }, - '& label': { display: 'block', marginBottom: '10px' }, }, }); export const Appearance = () => { - const invertedId = useId('inverted'); - const primaryId = useId('primary'); const styles = useStyles(); return (
- - + - - +
); }; From c94bb18782a32dfc071df4452ef3f31ee4fdf2e3 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Thu, 31 Mar 2022 15:22:42 -0700 Subject: [PATCH 17/20] Update styles --- .../react-spinner/src/components/Spinner/DefaultSvg.tsx | 6 +++--- .../react-spinner/src/components/Spinner/Spinner.types.ts | 8 ++++---- .../Spinner/__snapshots__/Spinner.test.tsx.snap | 4 ++-- .../src/components/Spinner/useSpinnerStyles.ts | 6 +----- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx index bc07c5266ab68d..ed8a1529422c2d 100644 --- a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx +++ b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx @@ -1,8 +1,8 @@ import * as React from 'react'; export const DefaultSvg = () => ( - - - + + + ); diff --git a/packages/react-spinner/src/components/Spinner/Spinner.types.ts b/packages/react-spinner/src/components/Spinner/Spinner.types.ts index 3a22632499d13d..684097560c9e4f 100644 --- a/packages/react-spinner/src/components/Spinner/Spinner.types.ts +++ b/packages/react-spinner/src/components/Spinner/Spinner.types.ts @@ -23,25 +23,25 @@ export type SpinnerSlots = { type SpinnerCommons = { /** * The appearance of the Spinner. - * @defaultValue 'primary' + * @default 'primary' */ appearance?: 'primary' | 'inverted'; /** * Where the label is positioned relative to the Spinner - * @defaultValue 'after' + * @default 'after' */ labelPosition?: 'above' | 'below' | 'before' | 'after'; /** * The size of the spinner. - * @defaultValue 'medium' + * @default 'medium' */ size?: 'tiny' | 'extra-small' | 'small' | 'medium' | 'large' | 'extra-large' | 'huge'; /** * The status of the Spinner. - * @defaultValue 'active' + * @default 'active' */ status?: 'active' | 'inactive'; }; diff --git a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap index 2613583d59db19..a6230ac3051773 100644 --- a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap +++ b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap @@ -12,10 +12,10 @@ exports[`Spinner renders a default state 1`] = ` role="progressbar" > diff --git a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts index 1c77a8148f0c1a..fc6ecc8aa0b6f1 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts +++ b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts @@ -260,10 +260,6 @@ const useLoaderStyles = makeStyles({ const useLabelStyles = makeStyles({ // style for label - spinnerLabel: { - color: tokens.colorNeutralForeground1, - }, - spinnerLabelInverted: { color: tokens.colorNeutralStrokeOnBrand2, }, @@ -331,7 +327,7 @@ export const useSpinnerStyles_unstable = (state: SpinnerState): SpinnerState => size === 'extra-small' && labelStyles.extraSmall, size === 'extra-large' && labelStyles.extraLarge, size !== 'extra-large' && size !== 'extra-small' && labelStyles[size], - state.appearance === 'inverted' ? labelStyles.spinnerLabelInverted : labelStyles.spinnerLabel, + state.appearance === 'inverted' && labelStyles.spinnerLabelInverted, state.label.className, ); } From 17a6bca86191e5734ce200b70180262a4b0c3964 Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Thu, 31 Mar 2022 15:30:10 -0700 Subject: [PATCH 18/20] Add svg className --- packages/react-spinner/src/components/Spinner/DefaultSvg.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx index ed8a1529422c2d..4cab26d8432720 100644 --- a/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx +++ b/packages/react-spinner/src/components/Spinner/DefaultSvg.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; export const DefaultSvg = () => ( - + From f58a8b4997c77c5c21bde12dfb161e954a8ac76b Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Thu, 31 Mar 2022 16:23:45 -0700 Subject: [PATCH 19/20] Update snap and styling --- .../__snapshots__/Spinner.test.tsx.snap | 1 + .../components/Spinner/useSpinnerStyles.ts | 74 +++++++++++-------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap index a6230ac3051773..0a20f860e92d01 100644 --- a/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap +++ b/packages/react-spinner/src/components/Spinner/__snapshots__/Spinner.test.tsx.snap @@ -9,6 +9,7 @@ exports[`Spinner renders a default state 1`] = ` class="fui-Spinner__spinner" > = { * TODO: Update with proper tokens when added * Radii for the Spinner circles */ -const rvalues = { +const rValues = { tiny: '9', extraSmall: '11', small: '13', @@ -47,6 +47,19 @@ const spinnerStrokeWidth = { lWidth: '4px', }; +/* + * TODO: Update with proper tokens when added + * Animation for Spinner + */ +const spinnerAnimation = { + container: { + animationDuration: '3s', + animationIterationCount: 'infinite', + animationTimingFunction: 'linear', + backgroundColor: 'transparent', + }, +}; + /* * TODO: Update with proper tokens when added * Label sizes for the Spinner @@ -91,17 +104,14 @@ const useRootStyles = makeStyles({ const useLoaderStyles = makeStyles({ // global SVG class spinnerSVG: { - [`& > svg`]: { + ['& > svg']: { animationName: { '0%': { transform: 'rotate(0deg)' }, '100%': { transform: 'rotate(360deg)' }, }, - animationDuration: '3s', - animationIterationCount: 'infinite', - animationTimingFunction: 'linear', - backgroundColor: 'transparent', + ...spinnerAnimation.container, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { cx: '50%', cy: '50%', fill: 'none', @@ -109,99 +119,99 @@ const useLoaderStyles = makeStyles({ }, tiny: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.tiny, width: spinnnerSizes.tiny, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.sWidth, - r: rvalues.tiny, + r: rValues.tiny, }, }, extraSmall: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.extraSmall, width: spinnnerSizes.extraSmall, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.sWidth, - r: rvalues.extraSmall, + r: rValues.extraSmall, }, }, small: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.small, width: spinnnerSizes.small, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.sWidth, - r: rvalues.small, + r: rValues.small, }, }, medium: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.medium, width: spinnnerSizes.medium, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.mWidth, - r: rvalues.medium, + r: rValues.medium, }, }, large: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.large, width: spinnnerSizes.large, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.mWidth, - r: rvalues.large, + r: rValues.large, }, }, extraLarge: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.extraLarge, width: spinnnerSizes.extraLarge, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.mWidth, - r: rvalues.extraLarge, + r: rValues.extraLarge, }, }, huge: { - [`& > svg`]: { + ['& > svg']: { height: spinnnerSizes.huge, width: spinnnerSizes.huge, }, - [`& > svg > circle`]: { + ['& > svg > circle']: { strokeWidth: spinnerStrokeWidth.lWidth, - r: rvalues.huge, + r: rValues.huge, }, }, // global class for Spinner track spinnerTrack: { - [`& > svg > circle.fui-spinner__Track`]: { + ['& > svg > circle.fui-spinner__Track']: { stroke: tokens.colorNeutralBackground4, }, }, // modifier class for Spinner track if appearance="inverted" spinnerTrackInverted: { - [`& > svg > circle.fui-spinner__Track`]: { + ['& > svg > circle.fui-spinner__Track']: { stroke: tokens.colorNeutralBackgroundInverted, }, }, // global Spinner trail class spinnerTail: { - [`& > svg > circle.fui-spinner__Tail`]: { + ['& > svg > circle.fui-spinner__Tail']: { stroke: tokens.colorBrandStroke1, animationName: { '0%': { @@ -230,7 +240,7 @@ const useLoaderStyles = makeStyles({ // modifier class for Spinner trail spinnerTailInverted: { - [`& > svg > circle.fui-spinner__Tail`]: { + ['& > svg > circle.fui-spinner__Tail']: { stroke: tokens.colorNeutralStrokeOnBrand2, animationName: { '0%': { From a83054eb57598d42eec5390201ed4e1f333b0bfb Mon Sep 17 00:00:00 2001 From: Tomi Olubeko Date: Fri, 1 Apr 2022 15:37:25 -0700 Subject: [PATCH 20/20] update styling --- .../components/Spinner/useSpinnerStyles.ts | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts index 68fb9f9d1526e6..a929acb590b370 100644 --- a/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts +++ b/packages/react-spinner/src/components/Spinner/useSpinnerStyles.ts @@ -194,25 +194,12 @@ const useLoaderStyles = makeStyles({ r: rValues.huge, }, }, +}); - // global class for Spinner track - spinnerTrack: { - ['& > svg > circle.fui-spinner__Track']: { - stroke: tokens.colorNeutralBackground4, - }, - }, - - // modifier class for Spinner track if appearance="inverted" - spinnerTrackInverted: { - ['& > svg > circle.fui-spinner__Track']: { - stroke: tokens.colorNeutralBackgroundInverted, - }, - }, - - // global Spinner trail class - spinnerTail: { - ['& > svg > circle.fui-spinner__Tail']: { - stroke: tokens.colorBrandStroke1, +const useTrackStyles = makeStyles({ + inverted: { + ['& > svg > circle.fui-Spinner__Tail']: { + stroke: tokens.colorNeutralStrokeOnBrand2, animationName: { '0%': { strokeDasharray: '1,150', @@ -236,12 +223,14 @@ const useLoaderStyles = makeStyles({ transform: 'rotate(-90deg)', transformOrigin: '50% 50%', }, - }, - // modifier class for Spinner trail - spinnerTailInverted: { - ['& > svg > circle.fui-spinner__Tail']: { - stroke: tokens.colorNeutralStrokeOnBrand2, + ['& > svg > circle.fui-Spinner__Track']: { + stroke: tokens.colorNeutralBackgroundInverted, + }, + }, + primary: { + ['& > svg > circle.fui-Spinner__Tail']: { + stroke: tokens.colorBrandStroke1, animationName: { '0%': { strokeDasharray: '1,150', @@ -265,14 +254,14 @@ const useLoaderStyles = makeStyles({ transform: 'rotate(-90deg)', transformOrigin: '50% 50%', }, + ['& > svg > circle.fui-Spinner__Track']: { + stroke: tokens.colorNeutralBackground4, + }, }, }); const useLabelStyles = makeStyles({ // style for label - spinnerLabelInverted: { - color: tokens.colorNeutralStrokeOnBrand2, - }, tiny: { ...labelSizeTokens.body1, @@ -311,6 +300,7 @@ export const useSpinnerStyles_unstable = (state: SpinnerState): SpinnerState => const rootStyles = useRootStyles(); const spinnerStyles = useLoaderStyles(); const labelStyles = useLabelStyles(); + const trackStyles = useTrackStyles(); state.root.className = mergeClasses( spinnerClassNames.root, @@ -319,15 +309,14 @@ export const useSpinnerStyles_unstable = (state: SpinnerState): SpinnerState => (labelPosition === 'before' || labelPosition === 'after') && rootStyles.horizontal, state.root.className, ); - if (state.spinner) { + if (state.spinner && state.appearance) { state.spinner.className = mergeClasses( spinnerClassNames.spinner, spinnerStyles.spinnerSVG, size === 'extra-small' && spinnerStyles.extraSmall, size === 'extra-large' && spinnerStyles.extraLarge, size !== 'extra-large' && size !== 'extra-small' && spinnerStyles[size], - state.appearance === 'inverted' ? spinnerStyles.spinnerTrackInverted : spinnerStyles.spinnerTrack, - state.appearance === 'inverted' ? spinnerStyles.spinnerTailInverted : spinnerStyles.spinnerTail, + trackStyles[state.appearance], state.spinner.className, ); } @@ -337,7 +326,6 @@ export const useSpinnerStyles_unstable = (state: SpinnerState): SpinnerState => size === 'extra-small' && labelStyles.extraSmall, size === 'extra-large' && labelStyles.extraLarge, size !== 'extra-large' && size !== 'extra-small' && labelStyles[size], - state.appearance === 'inverted' && labelStyles.spinnerLabelInverted, state.label.className, ); }