From ec19d18ae8781bd538c7d7e1665a8e31a7577e47 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 31 Jan 2024 18:24:27 +0000 Subject: [PATCH 1/4] Storybook: Show badges in sidebar --- .../stories/index.story.tsx | 1 + .../dropdown-menu-v2/stories/index.story.tsx | 1 + .../src/progress-bar/stories/index.story.tsx | 1 + .../src/tabs/stories/index.story.tsx | 1 + .../src/theme/stories/index.story.tsx | 1 + storybook/badges.js | 25 +++++++ storybook/manager.js | 2 + storybook/preview.js | 25 +------ storybook/sidebar.js | 68 +++++++++++++++++++ 9 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 storybook/badges.js create mode 100644 storybook/sidebar.js diff --git a/packages/components/src/custom-select-control-v2/stories/index.story.tsx b/packages/components/src/custom-select-control-v2/stories/index.story.tsx index 7714edc86157c7..625dce2a307f54 100644 --- a/packages/components/src/custom-select-control-v2/stories/index.story.tsx +++ b/packages/components/src/custom-select-control-v2/stories/index.story.tsx @@ -25,6 +25,7 @@ const meta: Meta< typeof CustomSelect > = { renderSelectedValue: { control: { type: null } }, value: { control: { type: null } }, }, + tags: [ 'sb-wip' ], parameters: { badges: [ 'wip' ], actions: { argTypesRegex: '^on.*' }, diff --git a/packages/components/src/dropdown-menu-v2/stories/index.story.tsx b/packages/components/src/dropdown-menu-v2/stories/index.story.tsx index 9e606770caa3ae..57cac2007d6b1d 100644 --- a/packages/components/src/dropdown-menu-v2/stories/index.story.tsx +++ b/packages/components/src/dropdown-menu-v2/stories/index.story.tsx @@ -56,6 +56,7 @@ const meta: Meta< typeof DropdownMenu > = { children: { control: { type: null } }, trigger: { control: { type: null } }, }, + tags: [ 'sb-private' ], parameters: { actions: { argTypesRegex: '^on.*' }, badges: [ 'private' ], diff --git a/packages/components/src/progress-bar/stories/index.story.tsx b/packages/components/src/progress-bar/stories/index.story.tsx index e213ea34db139a..fc197175a46d85 100644 --- a/packages/components/src/progress-bar/stories/index.story.tsx +++ b/packages/components/src/progress-bar/stories/index.story.tsx @@ -14,6 +14,7 @@ const meta: Meta< typeof ProgressBar > = { argTypes: { value: { control: { type: 'number', min: 0, max: 100, step: 1 } }, }, + tags: [ 'sb-private' ], parameters: { badges: [ 'private' ], controls: { diff --git a/packages/components/src/tabs/stories/index.story.tsx b/packages/components/src/tabs/stories/index.story.tsx index 632aaf0ac9242c..eefea403dbb227 100644 --- a/packages/components/src/tabs/stories/index.story.tsx +++ b/packages/components/src/tabs/stories/index.story.tsx @@ -28,6 +28,7 @@ const meta: Meta< typeof Tabs > = { // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 'Tabs.TabPanel': Tabs.TabPanel, }, + tags: [ 'sb-private' ], parameters: { actions: { argTypesRegex: '^on.*' }, badges: [ 'private' ], diff --git a/packages/components/src/theme/stories/index.story.tsx b/packages/components/src/theme/stories/index.story.tsx index 4e231cf2624cd2..af8364b00604b4 100644 --- a/packages/components/src/theme/stories/index.story.tsx +++ b/packages/components/src/theme/stories/index.story.tsx @@ -18,6 +18,7 @@ const meta: Meta< typeof Theme > = { accent: { control: { type: 'color' } }, background: { control: { type: 'color' } }, }, + tags: [ 'sb-private' ], parameters: { badges: [ 'private' ], controls: { expanded: true }, diff --git a/storybook/badges.js b/storybook/badges.js new file mode 100644 index 00000000000000..d3b60e051bd815 --- /dev/null +++ b/storybook/badges.js @@ -0,0 +1,25 @@ +export default { + private: { + icon: '🔒', + title: '🔒 Private', + tooltip: { + title: 'Component is locked as a private API', + desc: 'We do not yet recommend using this outside of the Gutenberg codebase.', + links: [ + { + title: 'About @wordpress/private-apis', + href: 'https://developer.wordpress.org/block-editor/reference-guides/packages/packages-private-apis/', + }, + ], + }, + }, + wip: { + icon: '🚧', + title: '🚧 WIP', + styles: { backgroundColor: '#FFF0BD' }, + tooltip: { + title: 'Component is a work in progress', + desc: 'This component is not ready for use in production, including the Gutenberg codebase. DO NOT export outside of @wordpress/components.', + }, + }, +}; diff --git a/storybook/manager.js b/storybook/manager.js index 25969095c8c49c..c63f15efe11d02 100644 --- a/storybook/manager.js +++ b/storybook/manager.js @@ -7,7 +7,9 @@ import { addons } from '@storybook/addons'; * Internal dependencies */ import theme from './theme'; +import sidebar from './sidebar'; addons.setConfig( { + sidebar, theme, } ); diff --git a/storybook/preview.js b/storybook/preview.js index 02b3ab22ed355f..a426faa41c2d71 100644 --- a/storybook/preview.js +++ b/storybook/preview.js @@ -18,6 +18,7 @@ import { WithMarginChecker } from './decorators/with-margin-checker'; import { WithMaxWidthWrapper } from './decorators/with-max-width-wrapper'; import { WithRTL } from './decorators/with-rtl'; import { WithTheme } from './decorators/with-theme'; +import badgesConfig from './badges'; export const globalTypes = { direction: { @@ -100,29 +101,7 @@ export const decorators = [ export const parameters = { // For @geometricpanda/storybook-addon-badges - badgesConfig: { - private: { - title: '🔒 Private', - tooltip: { - title: 'Component is locked as a private API', - desc: 'We do not yet recommend using this outside of the Gutenberg codebase.', - links: [ - { - title: 'About @wordpress/private-apis', - href: 'https://developer.wordpress.org/block-editor/reference-guides/packages/packages-private-apis/', - }, - ], - }, - }, - wip: { - title: '🚧 WIP', - styles: { backgroundColor: '#FFF0BD' }, - tooltip: { - title: 'Component is a work in progress', - desc: 'This component is not ready for use in production, including the Gutenberg codebase. DO NOT export outside of @wordpress/components.', - }, - }, - }, + badgesConfig, controls: { sort: 'requiredFirst', }, diff --git a/storybook/sidebar.js b/storybook/sidebar.js new file mode 100644 index 00000000000000..c2391db2607d2e --- /dev/null +++ b/storybook/sidebar.js @@ -0,0 +1,68 @@ +/** + * External dependencies + */ +// eslint-disable-next-line @typescript-eslint/no-restricted-imports +import { createElement, useMemo } from 'react'; +import { useStorybookApi } from '@storybook/manager-api'; +import { styled } from '@storybook/theming'; + +/** + * Internal dependencies + */ +import badges from './badges'; + +const STEM = 'sb-'; + +const Wrapper = styled.span( { + flexGrow: 1, + display: 'flex', + paddingRight: '20px', +} ); + +const Title = styled.span( { + flexGrow: 1, +} ); + +const Icons = styled.span( {} ); + +const Icon = styled.span( {} ); + +function useIcons( item ) { + const api = useStorybookApi(); + + return useMemo( () => { + let data = {}; + + if ( item.isComponent && item.children?.length ) { + data = api.getData( item.children[ 0 ] ) ?? {}; + } + + const { tags = [] } = data; + + return tags + .filter( ( tag ) => tag.startsWith( STEM ) ) + .map( ( tag ) => badges[ tag.substring( STEM.length ) ] ) + .map( ( { icon, title, tooltip } ) => + icon + ? createElement( + Icon, + { title: tooltip?.title ?? title }, + icon + ) + : null + ); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ item.id ] ); +} + +function Label( { item } ) { + const iconSet = useIcons( item ); + const title = createElement( Title, {}, item.name ); + const icons = createElement( Icons, { 'aria-hidden': true }, ...iconSet ); + + return createElement( Wrapper, {}, title, icons ); +} + +export default { + renderLabel: ( item ) => createElement( Label, { item } ), +}; From d450598f70bb8be90fc415943850b1b7c6f47c05 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Thu, 15 Feb 2024 16:01:37 +0000 Subject: [PATCH 2/4] Changing sidebar icon prefix to `status-` --- .../src/custom-select-control-v2/stories/default.story.tsx | 2 +- .../src/dropdown-menu-v2/stories/index.story.tsx | 2 +- .../components/src/progress-bar/stories/index.story.tsx | 2 +- packages/components/src/tabs/stories/index.story.tsx | 2 +- packages/components/src/theme/stories/index.story.tsx | 2 +- storybook/sidebar.js | 7 +++---- 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/components/src/custom-select-control-v2/stories/default.story.tsx b/packages/components/src/custom-select-control-v2/stories/default.story.tsx index 204a6d56c16976..ee7dba0694c278 100644 --- a/packages/components/src/custom-select-control-v2/stories/default.story.tsx +++ b/packages/components/src/custom-select-control-v2/stories/default.story.tsx @@ -25,7 +25,7 @@ const meta: Meta< typeof CustomSelect > = { children: { control: { type: null } }, value: { control: { type: null } }, }, - tags: [ 'sb-wip' ], + tags: [ 'status-wip' ], parameters: { badges: [ 'wip' ], actions: { argTypesRegex: '^on.*' }, diff --git a/packages/components/src/dropdown-menu-v2/stories/index.story.tsx b/packages/components/src/dropdown-menu-v2/stories/index.story.tsx index 57cac2007d6b1d..11f3c8fb1a6b1b 100644 --- a/packages/components/src/dropdown-menu-v2/stories/index.story.tsx +++ b/packages/components/src/dropdown-menu-v2/stories/index.story.tsx @@ -56,7 +56,7 @@ const meta: Meta< typeof DropdownMenu > = { children: { control: { type: null } }, trigger: { control: { type: null } }, }, - tags: [ 'sb-private' ], + tags: [ 'status-private' ], parameters: { actions: { argTypesRegex: '^on.*' }, badges: [ 'private' ], diff --git a/packages/components/src/progress-bar/stories/index.story.tsx b/packages/components/src/progress-bar/stories/index.story.tsx index fc197175a46d85..dad1958bf0e66e 100644 --- a/packages/components/src/progress-bar/stories/index.story.tsx +++ b/packages/components/src/progress-bar/stories/index.story.tsx @@ -14,7 +14,7 @@ const meta: Meta< typeof ProgressBar > = { argTypes: { value: { control: { type: 'number', min: 0, max: 100, step: 1 } }, }, - tags: [ 'sb-private' ], + tags: [ 'status-private' ], parameters: { badges: [ 'private' ], controls: { diff --git a/packages/components/src/tabs/stories/index.story.tsx b/packages/components/src/tabs/stories/index.story.tsx index eefea403dbb227..1fe593df385361 100644 --- a/packages/components/src/tabs/stories/index.story.tsx +++ b/packages/components/src/tabs/stories/index.story.tsx @@ -28,7 +28,7 @@ const meta: Meta< typeof Tabs > = { // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 'Tabs.TabPanel': Tabs.TabPanel, }, - tags: [ 'sb-private' ], + tags: [ 'status-private' ], parameters: { actions: { argTypesRegex: '^on.*' }, badges: [ 'private' ], diff --git a/packages/components/src/theme/stories/index.story.tsx b/packages/components/src/theme/stories/index.story.tsx index af8364b00604b4..c26e0a752c0d45 100644 --- a/packages/components/src/theme/stories/index.story.tsx +++ b/packages/components/src/theme/stories/index.story.tsx @@ -18,7 +18,7 @@ const meta: Meta< typeof Theme > = { accent: { control: { type: 'color' } }, background: { control: { type: 'color' } }, }, - tags: [ 'sb-private' ], + tags: [ 'status-private' ], parameters: { badges: [ 'private' ], controls: { expanded: true }, diff --git a/storybook/sidebar.js b/storybook/sidebar.js index c2391db2607d2e..d0c60a27d2c4ee 100644 --- a/storybook/sidebar.js +++ b/storybook/sidebar.js @@ -11,8 +11,6 @@ import { styled } from '@storybook/theming'; */ import badges from './badges'; -const STEM = 'sb-'; - const Wrapper = styled.span( { flexGrow: 1, display: 'flex', @@ -29,6 +27,7 @@ const Icon = styled.span( {} ); function useIcons( item ) { const api = useStorybookApi(); + const prefix = 'status-'; return useMemo( () => { let data = {}; @@ -40,8 +39,8 @@ function useIcons( item ) { const { tags = [] } = data; return tags - .filter( ( tag ) => tag.startsWith( STEM ) ) - .map( ( tag ) => badges[ tag.substring( STEM.length ) ] ) + .filter( ( tag ) => tag.startsWith( prefix ) ) + .map( ( tag ) => badges[ tag.substring( prefix.length ) ] ) .map( ( { icon, title, tooltip } ) => icon ? createElement( From 874b85e46a7507583836c6929bb72ccae64acd0a Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Thu, 15 Feb 2024 16:07:11 +0000 Subject: [PATCH 3/4] Resolving `exhaustive-deps` issue --- storybook/sidebar.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storybook/sidebar.js b/storybook/sidebar.js index d0c60a27d2c4ee..b540ee9ac0e3fc 100644 --- a/storybook/sidebar.js +++ b/storybook/sidebar.js @@ -50,8 +50,7 @@ function useIcons( item ) { ) : null ); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ item.id ] ); + }, [ api, item.children, item.isComponent ] ); } function Label( { item } ) { From 4d63235f76e84657cbe77434a3be1d84a6f31554 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Thu, 15 Feb 2024 16:21:10 +0000 Subject: [PATCH 4/4] Adding some doc blocks --- storybook/badges.js | 5 +++++ storybook/sidebar.js | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/storybook/badges.js b/storybook/badges.js index d3b60e051bd815..7787a9a67121e6 100644 --- a/storybook/badges.js +++ b/storybook/badges.js @@ -1,3 +1,8 @@ +/** + * Provides badge configuration options. + * See https://github.com/geometricpanda/storybook-addon-badges + */ + export default { private: { icon: '🔒', diff --git a/storybook/sidebar.js b/storybook/sidebar.js index b540ee9ac0e3fc..d8ff2ba777dd7d 100644 --- a/storybook/sidebar.js +++ b/storybook/sidebar.js @@ -1,3 +1,8 @@ +/** + * Provides sidebar configuration options. + * See https://storybook.js.org/docs/configure/features-and-behavior + */ + /** * External dependencies */ @@ -25,6 +30,10 @@ const Icons = styled.span( {} ); const Icon = styled.span( {} ); +/** + * Fetches tags from the Storybook API, and returns Icon + * elements for any that have matching badge data + */ function useIcons( item ) { const api = useStorybookApi(); const prefix = 'status-'; @@ -53,6 +62,9 @@ function useIcons( item ) { }, [ api, item.children, item.isComponent ] ); } +/** + * Renders the item name and any associated badge icons. + */ function Label( { item } ) { const iconSet = useIcons( item ); const title = createElement( Title, {}, item.name ); @@ -62,5 +74,6 @@ function Label( { item } ) { } export default { + // Renders status icons for items tagged with `status-*` renderLabel: ( item ) => createElement( Label, { item } ), };