diff --git a/change/@ni-nimble-components-1996d396-34af-4f72-95dd-d141df4ad7e4.json b/change/@ni-nimble-components-1996d396-34af-4f72-95dd-d141df4ad7e4.json new file mode 100644 index 0000000000..000b12a582 --- /dev/null +++ b/change/@ni-nimble-components-1996d396-34af-4f72-95dd-d141df4ad7e4.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Add design tokens for additional spinner sizes, and update docs.", + "packageName": "@ni/nimble-components", + "email": "20709258+msmithNI@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/nimble-components/src/spinner/styles.ts b/packages/nimble-components/src/spinner/styles.ts index d217bf4a7d..9990d07435 100644 --- a/packages/nimble-components/src/spinner/styles.ts +++ b/packages/nimble-components/src/spinner/styles.ts @@ -5,6 +5,7 @@ import { Black91, White } from '@ni/nimble-tokens/dist/styledictionary/js/tokens'; +import { spinnerSmallHeight } from '../theme-provider/design-tokens'; import { Theme } from '../theme-provider/types'; import { themeBehavior } from '../utilities/style/theme'; @@ -12,8 +13,8 @@ export const styles = css` ${display('inline-flex')} :host { - width: 16px; - height: 16px; + height: ${spinnerSmallHeight}; + aspect-ratio: 1 / 1; } div.container { diff --git a/packages/nimble-components/src/spinner/tests/spinner-matrix.stories.ts b/packages/nimble-components/src/spinner/tests/spinner-matrix.stories.ts index 71c0e30a33..14c95bfe39 100644 --- a/packages/nimble-components/src/spinner/tests/spinner-matrix.stories.ts +++ b/packages/nimble-components/src/spinner/tests/spinner-matrix.stories.ts @@ -9,7 +9,11 @@ import { createMatrixThemeStory, createStory } from '../../utilities/tests/storybook'; -import { bodyFontColor } from '../../theme-provider/design-tokens'; +import { + bodyFontColor, + spinnerLargeHeight, + spinnerMediumHeight +} from '../../theme-provider/design-tokens'; import { hiddenWrapper } from '../../utilities/tests/hidden'; import '../../all-components'; @@ -28,8 +32,9 @@ const metadata: Meta = { export default metadata; const sizeStates = [ - ['16x16', 'width: 16px; height: 16px'], - ['32x32', 'width: 32px; height: 32px'] + ['Small (16x16)', ''], + ['Medium (32x32)', `height: var(${spinnerMediumHeight.cssCustomProperty})`], + ['Large (64x64)', `height: var(${spinnerLargeHeight.cssCustomProperty})`] ]; type SizeState = typeof sizeStates[number]; diff --git a/packages/nimble-components/src/spinner/tests/spinner.stories.ts b/packages/nimble-components/src/spinner/tests/spinner.stories.ts index 97bde923bd..c82d14af1a 100644 --- a/packages/nimble-components/src/spinner/tests/spinner.stories.ts +++ b/packages/nimble-components/src/spinner/tests/spinner.stories.ts @@ -3,12 +3,31 @@ import type { Meta, StoryObj } from '@storybook/html'; import { withXD } from 'storybook-addon-xd-designs'; import { createUserSelectedThemeStory } from '../../utilities/tests/storybook'; import '../../all-components'; +import { + spinnerLargeHeight, + spinnerMediumHeight +} from '../../theme-provider/design-tokens'; +import { + scssPropertyFromTokenName, + scssPropertySetterMarkdown, + tokenNames +} from '../../theme-provider/design-token-names'; -const overviewText = 'The `nimble-spinner` is an animating indicator that can be placed in a particular region of a page to represent loading progress, or an ongoing operation, of an indeterminate / unknown duration.' - + '

The default spinner size is 16x16. Other sizes can be set via width/height CSS styles on the component, and it will scale appropriately.

' - + '

Other sizes suggested by the Nimble designers: 32x32, 48x48, 64x64, 96x96, 128x128.

'; +const spinnerSize = { + small: null, + medium: `height: var(${spinnerMediumHeight.cssCustomProperty});`, + large: `height: var(${spinnerLargeHeight.cssCustomProperty});` +} as const; -const metadata: Meta = { +interface SpinnerArgs { + size: keyof typeof spinnerSize; +} + +const overviewText = '

The `nimble-spinner` is an animating indicator that can be placed in a particular region of a page to represent ' + + 'loading progress, or an ongoing operation, of an indeterminate / unknown duration.

' + + '

See the `size` argument details for information on customizing the spinner size.

'; + +const metadata: Meta = { title: 'Spinner', decorators: [withXD], parameters: { @@ -22,15 +41,53 @@ const metadata: Meta = { 'https://xd.adobe.com/view/33ffad4a-eb2c-4241-b8c5-ebfff1faf6f6-66ac/screen/dece308f-79e7-48ec-ab41-011f3376b49b/specs/' } }, - argTypes: {}, + argTypes: { + size: { + description: + 'Size of the spinner component.
Usage detailsTo customize its size, set its CSS ' + + 'height to a design token, and its width will automatically match its height:
`, + options: Object.keys(spinnerSize), + table: { defaultValue: { summary: 'Small (16x16)' } }, + control: { + type: 'radio', + labels: { + small: `Small - 16x16 (default) - ${scssPropertyFromTokenName( + tokenNames.spinnerSmallHeight + )}`, + medium: `Medium - 32x32 - ${scssPropertyFromTokenName( + tokenNames.spinnerMediumHeight + )}`, + large: `Large - 64x64 - ${scssPropertyFromTokenName( + tokenNames.spinnerLargeHeight + )}` + } + } + } + }, // prettier-ignore render: createUserSelectedThemeStory(html` - + `), - args: {} + args: { + size: 'small' + } }; export default metadata; -export const spinner: StoryObj = {}; +export const spinner: StoryObj = {}; diff --git a/packages/nimble-components/src/theme-provider/design-token-comments.ts b/packages/nimble-components/src/theme-provider/design-token-comments.ts index a24bced8ee..40667edcc6 100644 --- a/packages/nimble-components/src/theme-provider/design-token-comments.ts +++ b/packages/nimble-components/src/theme-provider/design-token-comments.ts @@ -40,6 +40,9 @@ export const comments: { readonly [key in TokenName]: string | null } = { iconSize: 'Standard layout height for all icons', groupHeaderTextTransform: 'CSS text-transform string to use for headers', drawerWidth: 'TODO: delete when able', + spinnerSmallHeight: 'Small height (16px) for a spinner component', + spinnerMediumHeight: 'Medium height (32px) for a spinner component', + spinnerLargeHeight: 'Large height (64px) for a spinner component', smallDelay: 'Elements with small transition areas, such as icons and selection controls, have short durations.', mediumDelay: diff --git a/packages/nimble-components/src/theme-provider/design-token-names.ts b/packages/nimble-components/src/theme-provider/design-token-names.ts index 4751bc0969..e78f583d5a 100644 --- a/packages/nimble-components/src/theme-provider/design-token-names.ts +++ b/packages/nimble-components/src/theme-provider/design-token-names.ts @@ -36,6 +36,9 @@ export const tokenNames: { readonly [key in TokenName]: string } = { iconSize: 'icon-size', groupHeaderTextTransform: 'group-header-text-transform', drawerWidth: 'drawer-width', + spinnerSmallHeight: 'spinner-small-height', + spinnerMediumHeight: 'spinner-medium-height', + spinnerLargeHeight: 'spinner-large-height', smallDelay: 'small-delay', mediumDelay: 'medium-delay', largeDelay: 'large-delay', @@ -213,6 +216,10 @@ const prefix = 'ni-nimble'; export const styleNameFromTokenName = (tokenName: string): string => `${prefix}-${tokenName}`; export const cssPropertyFromTokenName = (tokenName: string): string => `--${prefix}-${tokenName}`; export const scssPropertyFromTokenName = (tokenName: string): string => `$${prefix}-${tokenName}`; +export const scssPropertySetterMarkdown = ( + tokenName: string, + cssProperty: string +): string => `\`${cssProperty}: $${prefix}-${tokenName};\``; export const scssInternalPropertyFromTokenName = (tokenName: string): string => `$${prefix}-internal-${tokenName}`; export const scssInternalPropertySetterMarkdown = ( tokenName: string, diff --git a/packages/nimble-components/src/theme-provider/design-tokens.ts b/packages/nimble-components/src/theme-provider/design-tokens.ts index b403cf7a96..386641fd34 100644 --- a/packages/nimble-components/src/theme-provider/design-tokens.ts +++ b/packages/nimble-components/src/theme-provider/design-tokens.ts @@ -214,6 +214,16 @@ export const drawerWidth = DesignToken.create( styleNameFromTokenName(tokenNames.drawerWidth) ).withDefault('784px'); +export const spinnerSmallHeight = DesignToken.create( + styleNameFromTokenName(tokenNames.spinnerSmallHeight) +).withDefault('16px'); +export const spinnerMediumHeight = DesignToken.create( + styleNameFromTokenName(tokenNames.spinnerMediumHeight) +).withDefault('32px'); +export const spinnerLargeHeight = DesignToken.create( + styleNameFromTokenName(tokenNames.spinnerLargeHeight) +).withDefault('64px'); + // Drop Shadow Tokens export const elevation1BoxShadow = DesignToken.create( styleNameFromTokenName(tokenNames.elevation1BoxShadow)