Skip to content

Commit

Permalink
Spinner size followup (using design tokens) (#988)
Browse files Browse the repository at this point in the history
# Pull Request

## 🤨 Rationale

Associated feature 
- #346 

Nathan Mitchell, Fred Visser, Jesse Attas, and myself had a followup
discussion about spinner sizes. The end result was that we wanted it to
be easier for users to use the designer-prescribed spinner sizes. Nathan
followed up with Brandon O'Keefe to confirm the 3 spinner sizes desired
(they still went with 16/32/64, which also matches the spec).
Separately I looked at the spinner usages in SystemLink Enterprise, and
the vast majority are also 16x16, so I'm keeping 16x16 the default size
as it was previously.

After discussion with the dev team, we decided to use design tokens to
provide the designer-provided `small` `medium` and `large` sizes
(instead of a `size` DOM attribute). Consumers can set the `height` to a
token as outlined in the spinner Storybook docs/examples.

## 👩‍💻 Implementation

- Add design tokens `spinnerSmallHeight` (16px), `spinnerMediumHeight`
(32px), and `spinnerLargeHeight` (64px). 16px (small) is the default, so
using that token is optional.
- Add `aspect-ratio: 1 / 1` to the spinner styling, so consumers can
just set height (instead of both width and height)
- Update Storybook docs to cover the 3 sizes and explain how to set
them, and some examples of where they should be used in a page
- Update theme matrix story to have those 3 sizes

## 🧪 Testing

- Autotests
- Looked at updated stories

## ✅ Checklist

- [x] I have updated the project documentation to reflect my changes or
determined no changes are needed.
  • Loading branch information
msmithNI authored Jan 24, 2023
1 parent 7cff2a5 commit 3c778c0
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -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"
}
5 changes: 3 additions & 2 deletions packages/nimble-components/src/spinner/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ 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';

export const styles = css`
${display('inline-flex')}
:host {
width: 16px;
height: 16px;
height: ${spinnerSmallHeight};
aspect-ratio: 1 / 1;
}
div.container {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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];

Expand Down
73 changes: 65 additions & 8 deletions packages/nimble-components/src/spinner/tests/spinner.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.'
+ '<p>The default spinner size is 16x16. Other sizes can be set via width/height CSS styles on the component, and it will scale appropriately.</p>'
+ '<p>Other sizes suggested by the Nimble designers: 32x32, 48x48, 64x64, 96x96, 128x128.</p>';
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 = '<p>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.</p>'
+ '<p>See the `size` argument details for information on customizing the spinner size.</p>';

const metadata: Meta<SpinnerArgs> = {
title: 'Spinner',
decorators: [withXD],
parameters: {
Expand All @@ -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.<details><summary>Usage details</summary>To customize its size, set its CSS '
+ '<span style="font-family: monospace;">height</span> to a design token, and its width will automatically match its height:<br/><ul>'
+ `<li>For Small (16x16): ${scssPropertySetterMarkdown(
tokenNames.spinnerSmallHeight,
'height'
)}</li>`
+ `<li>For Medium (32x32): ${scssPropertySetterMarkdown(
tokenNames.spinnerMediumHeight,
'height'
)}</li>`
+ `<li>For Large (64x64): ${scssPropertySetterMarkdown(
tokenNames.spinnerLargeHeight,
'height'
)}</li></ul></details>`,
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`
<nimble-spinner>
<nimble-spinner
style="${x => spinnerSize[x.size]}"
>
</nimble-spinner>
`),
args: {}
args: {
size: 'small'
}
};

export default metadata;

export const spinner: StoryObj = {};
export const spinner: StoryObj<SpinnerArgs> = {};
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions packages/nimble-components/src/theme-provider/design-tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ export const drawerWidth = DesignToken.create<string>(
styleNameFromTokenName(tokenNames.drawerWidth)
).withDefault('784px');

export const spinnerSmallHeight = DesignToken.create<string>(
styleNameFromTokenName(tokenNames.spinnerSmallHeight)
).withDefault('16px');
export const spinnerMediumHeight = DesignToken.create<string>(
styleNameFromTokenName(tokenNames.spinnerMediumHeight)
).withDefault('32px');
export const spinnerLargeHeight = DesignToken.create<string>(
styleNameFromTokenName(tokenNames.spinnerLargeHeight)
).withDefault('64px');

// Drop Shadow Tokens
export const elevation1BoxShadow = DesignToken.create<string>(
styleNameFromTokenName(tokenNames.elevation1BoxShadow)
Expand Down

0 comments on commit 3c778c0

Please sign in to comment.