From 2026f13a17381f5bf36c84b141db071ccb27a028 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 17 Aug 2022 16:05:01 +0900 Subject: [PATCH] ToggleGroupControl: Improve stories for Docs view (#43265) * ToggleGroupControl: Improve stories for Docs view * Add usage clarification re: TabPanel * Add changelog * Mark as non-polymorphic --- packages/components/CHANGELOG.md | 1 + .../src/toggle-group-control/stories/index.js | 211 ------------------ .../toggle-group-control/stories/index.tsx | 127 +++++++++++ .../toggle-group-control/README.md | 2 + .../toggle-group-control/component.tsx | 15 +- .../src/toggle-group-control/types.ts | 3 +- 6 files changed, 141 insertions(+), 218 deletions(-) delete mode 100644 packages/components/src/toggle-group-control/stories/index.js create mode 100644 packages/components/src/toggle-group-control/stories/index.tsx diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 543b6b9df3b76..4208345ef5954 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -8,6 +8,7 @@ ### Enhancements +- `ToggleGroupControl`: Improve TypeScript documentation ([#43265](https://github.com/WordPress/gutenberg/pull/43265)). - `ComboboxControl`: Normalize hyphen-like characters to an ASCII hyphen ([#42942](https://github.com/WordPress/gutenberg/pull/42942)). - `FormTokenField`: Refactor away from `_.difference()` ([#43224](https://github.com/WordPress/gutenberg/pull/43224/)). diff --git a/packages/components/src/toggle-group-control/stories/index.js b/packages/components/src/toggle-group-control/stories/index.js deleted file mode 100644 index 13cb5829ea257..0000000000000 --- a/packages/components/src/toggle-group-control/stories/index.js +++ /dev/null @@ -1,211 +0,0 @@ -/** - * External dependencies - */ -import { boolean, text } from '@storybook/addon-knobs'; - -/** - * WordPress dependencies - */ -import { useState } from '@wordpress/element'; -import { formatLowercase, formatUppercase } from '@wordpress/icons'; - -/** - * Internal dependencies - */ -import { - ToggleGroupControl, - ToggleGroupControlOption, - ToggleGroupControlOptionIcon, -} from '../index'; -import { View } from '../../view'; -import { HStack } from '../../h-stack'; -import Button from '../../button'; - -export default { - component: ToggleGroupControl, - title: 'Components (Experimental)/ToggleGroupControl', - subcomponents: { ToggleGroupControlOption, ToggleGroupControlOptionIcon }, - argTypes: { - __experimentalIsIconGroup: { control: { type: 'boolean' } }, - __nextHasNoMarginBottom: { control: 'boolean' }, - size: { - control: 'radio', - options: [ 'default', '__unstable-large' ], - }, - }, - parameters: { - knobs: { disable: false }, - }, -}; - -const KNOBS_GROUPS = { - ToggleGroupControl: 'ToggleGroupControl', - ToggleGroupControlOption: 'ToggleGroupControlOption', -}; - -const _default = ( { options, ...props } ) => { - const [ value, setValue ] = useState( options[ 0 ].value ); - const label = text( - `${ KNOBS_GROUPS.ToggleGroupControl }: label`, - 'Toggle Group Control', - KNOBS_GROUPS.ToggleGroupControl - ); - - const hideLabelFromVision = boolean( - `${ KNOBS_GROUPS.ToggleGroupControl }: hideLabelFromVision`, - false, - KNOBS_GROUPS.ToggleGroupControl - ); - const isBlock = boolean( - `${ KNOBS_GROUPS.ToggleGroupControl }: isBlock (render as a css block element)`, - false, - KNOBS_GROUPS.ToggleGroupControl - ); - const help = text( - `${ KNOBS_GROUPS.ToggleGroupControl }: help`, - undefined, - KNOBS_GROUPS.ToggleGroupControl - ); - const isAdaptiveWidth = boolean( - `${ KNOBS_GROUPS.ToggleGroupControl }: isAdaptiveWidth`, - false, - KNOBS_GROUPS.ToggleGroupControl - ); - - const controlOptions = options.map( ( option, index ) => ( - - ) ); - - return ( - - - { controlOptions } - - - ); -}; - -export const Default = _default.bind( {} ); -Default.args = { - options: [ - { value: 'left', label: 'Left' }, - { value: 'center', label: 'Center' }, - { value: 'right', label: 'Right' }, - { value: 'justify', label: 'Justify' }, - ], - size: 'default', -}; - -export const WithTooltip = _default.bind( {} ); -WithTooltip.args = { - ...Default.args, - options: [ - { value: 1, label: '1', showTooltip: true, 'aria-label': 'One' }, - { value: 2, label: '2', showTooltip: true, 'aria-label': 'Two' }, - { value: 3, label: '3', showTooltip: true, 'aria-label': 'Three' }, - ], -}; - -export const WithAriaLabel = _default.bind( {} ); -WithAriaLabel.args = { - ...Default.args, - options: [ - { value: 'asc', label: 'A→Z', 'aria-label': 'Ascending' }, - { value: 'desc', label: 'Z→A', 'aria-label': 'Descending' }, - ], -}; - -/** - * The `` component can be used for icon options. - * In this case, the `__experimentalIsIconGroup` style is preferred. - */ -export const WithIcons = ( props ) => { - const [ state, setState ] = useState(); - return ( - - - - - ); -}; -WithIcons.args = { - ...Default.args, - __experimentalIsIconGroup: true, -}; - -export const WithReset = ( props ) => { - const [ alignState, setAlignState ] = useState(); - const aligns = [ 'Left', 'Center', 'Right' ]; - const alignOptions = aligns.map( ( key, index ) => ( - - ) ); - return ( - - - { alignOptions } - - - - ); -}; -WithReset.args = { - ...Default.args, - __nextHasNoMarginBottom: true, -}; diff --git a/packages/components/src/toggle-group-control/stories/index.tsx b/packages/components/src/toggle-group-control/stories/index.tsx new file mode 100644 index 0000000000000..e6f142c542a7c --- /dev/null +++ b/packages/components/src/toggle-group-control/stories/index.tsx @@ -0,0 +1,127 @@ +/** + * External dependencies + */ +import type { ComponentMeta, ComponentStory } from '@storybook/react'; + +/** + * WordPress dependencies + */ +import { useState } from '@wordpress/element'; +import { formatLowercase, formatUppercase } from '@wordpress/icons'; + +/** + * Internal dependencies + */ +import { + ToggleGroupControl, + ToggleGroupControlOption, + ToggleGroupControlOptionIcon, +} from '../index'; +import type { + ToggleGroupControlOptionProps, + ToggleGroupControlOptionIconProps, + ToggleGroupControlProps, +} from '../types'; + +const meta: ComponentMeta< typeof ToggleGroupControl > = { + component: ToggleGroupControl, + title: 'Components (Experimental)/ToggleGroupControl', + subcomponents: { ToggleGroupControlOption, ToggleGroupControlOptionIcon }, + argTypes: { + help: { control: { type: 'text' } }, + onChange: { action: 'onChange' }, + value: { control: { type: null } }, + }, + parameters: { + controls: { expanded: true }, + docs: { source: { state: 'open' } }, + }, +}; +export default meta; + +const Template: ComponentStory< typeof ToggleGroupControl > = ( { + onChange, + ...props +} ) => { + const [ value, setValue ] = + useState< ToggleGroupControlProps[ 'value' ] >(); + + return ( + { + setValue( ...changeArgs ); + onChange?.( ...changeArgs ); + } } + value={ value } + /> + ); +}; + +const mapPropsToOptionComponent = ( { + value, + ...props +}: ToggleGroupControlOptionProps ) => ( + +); + +const mapPropsToOptionIconComponent = ( { + value, + ...props +}: ToggleGroupControlOptionIconProps ) => ( + +); + +export const Default: ComponentStory< typeof ToggleGroupControl > = + Template.bind( {} ); +Default.args = { + children: [ + { value: 'left', label: 'Left' }, + { value: 'center', label: 'Center' }, + { value: 'right', label: 'Right' }, + { value: 'justify', label: 'Justify' }, + ].map( mapPropsToOptionComponent ), + label: 'Label', +}; + +/** + * A tooltip can be shown for each option by enabling the `showTooltip` prop. + * The `aria-label` will be used in the tooltip if provided. Otherwise, the + * `label` will be used. + */ +export const WithTooltip: ComponentStory< typeof ToggleGroupControl > = + Template.bind( {} ); +WithTooltip.args = { + ...Default.args, + children: [ + { + value: 'asc', + label: 'A→Z', + 'aria-label': 'Ascending', + showTooltip: true, + }, + { + value: 'desc', + label: 'Z→A', + 'aria-label': 'Descending', + showTooltip: true, + }, + ].map( mapPropsToOptionComponent ), +}; + +/** + * The `ToggleGroupControlOptionIcon` component can be used for icon options. A `label` is required + * on each option for accessibility, which will be shown in a tooltip. + * + * When using icon options within `ToggleGroupControl`, the `__experimentalIsIconGroup` style is preferred. + */ +export const WithIcons: ComponentStory< typeof ToggleGroupControl > = + Template.bind( {} ); +WithIcons.args = { + ...Default.args, + __experimentalIsIconGroup: true, + children: [ + { value: 'uppercase', label: 'Uppercase', icon: formatUppercase }, + { value: 'lowercase', label: 'Lowercase', icon: formatLowercase }, + ].map( mapPropsToOptionIconComponent ), +}; diff --git a/packages/components/src/toggle-group-control/toggle-group-control/README.md b/packages/components/src/toggle-group-control/toggle-group-control/README.md index cf15d47923524..cfbf6b12ed0b2 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/README.md +++ b/packages/components/src/toggle-group-control/toggle-group-control/README.md @@ -6,6 +6,8 @@ This feature is still experimental. “Experimental” means this is an early im `ToggleGroupControl` is a form component that lets users choose options represented in horizontal segments. To render options for this control use [`ToggleGroupControlOption`](/packages/components/src/toggle-group-control/toggle-group-control-option/README.md) component. +This component is intended for selecting a single persistent value from a set of options, similar to a how a radio button group would work. If you simply want a toggle to switch between views, use a [`TabPanel`](/packages/components/src/tab-panel/README.md) instead. + Only use this control when you know for sure the labels of items inside won't wrap. For items with longer labels, you can consider a [`SelectControl`](/packages/components/src/select-control/README.md) or a [`CustomSelectControl`](/packages/components/src/custom-select-control/README.md) component instead. ## Usage diff --git a/packages/components/src/toggle-group-control/toggle-group-control/component.tsx b/packages/components/src/toggle-group-control/toggle-group-control/component.tsx index b17cadc6411c7..05603a602ba06 100644 --- a/packages/components/src/toggle-group-control/toggle-group-control/component.tsx +++ b/packages/components/src/toggle-group-control/toggle-group-control/component.tsx @@ -35,8 +35,8 @@ import * as styles from './styles'; const noop = () => {}; -function ToggleGroupControl( - props: WordPressComponentProps< ToggleGroupControlProps, 'input' >, +function UnconnectedToggleGroupControl( + props: WordPressComponentProps< ToggleGroupControlProps, 'input', false >, forwardedRef: ForwardedRef< any > ) { const { @@ -135,11 +135,14 @@ function ToggleGroupControl( * represented in horizontal segments. To render options for this control use * `ToggleGroupControlOption` component. * + * This component is intended for selecting a single persistent value from a set of options, + * similar to a how a radio button group would work. If you simply want a toggle to switch between views, + * use a `TabPanel` instead. + * * Only use this control when you know for sure the labels of items inside won't * wrap. For items with longer labels, you can consider a `SelectControl` or a * `CustomSelectControl` component instead. * - * @example * ```jsx * import { * __experimentalToggleGroupControl as ToggleGroupControl, @@ -156,9 +159,9 @@ function ToggleGroupControl( * } * ``` */ -const ConnectedToggleGroupControl = contextConnect( - ToggleGroupControl, +export const ToggleGroupControl = contextConnect( + UnconnectedToggleGroupControl, 'ToggleGroupControl' ); -export default ConnectedToggleGroupControl; +export default ToggleGroupControl; diff --git a/packages/components/src/toggle-group-control/types.ts b/packages/components/src/toggle-group-control/types.ts index f42ef84f83660..525e0a4e4442e 100644 --- a/packages/components/src/toggle-group-control/types.ts +++ b/packages/components/src/toggle-group-control/types.ts @@ -114,7 +114,8 @@ export type ToggleGroupControlProps = Omit< */ value?: ReactText; /** - * React children + * The options to render in the `ToggleGroupControl`, using either the `ToggleGroupControlOption` or + * `ToggleGroupControlOptionIcon` components. */ children: ReactNode; /**