diff --git a/packages/components/src/menu/stories/index.story.tsx b/packages/components/src/menu/stories/index.story.tsx index dcd890370a1e0a..37ebb6f905dc84 100644 --- a/packages/components/src/menu/stories/index.story.tsx +++ b/packages/components/src/menu/stories/index.story.tsx @@ -1,7 +1,7 @@ /** * External dependencies */ -import type { Meta, StoryFn } from '@storybook/react'; +import type { StoryObj, Meta } from '@storybook/react'; import { css } from '@emotion/react'; /** @@ -67,315 +67,279 @@ const meta: Meta< typeof Menu > = { }; export default meta; -export const Default: StoryFn< typeof Menu > = ( props: MenuProps ) => ( - - } - > - Open menu - - - - Label - - - Label - Help text - - - Label - - The menu item help text is automatically truncated when - there are more than two lines of text - - - - Label - - This item doesn't close the menu on click - - - Disabled item - - - Group label - }> - With prefix - - With suffix - } - suffix="⌥⌘T" +export const Default: StoryObj< typeof Menu > = { + args: { + children: ( + <> + + } > - - Disabled with prefix and suffix - - And help text - - - - -); -Default.args = {}; - -export const WithSubmenu: StoryFn< typeof Menu > = ( props: MenuProps ) => ( - - } - > - Open menu - - - Level 1 item - - - - Submenu trigger item with a long label - - + Open menu + - Level 2 item + Label + + + Label + Help text - Level 2 item + Label + + The menu item help text is automatically truncated + when there are more than two lines of text + + + + Label + + This item doesn't close the menu on click + + Disabled item + + + Group label + } + > + With prefix + + With suffix + + } + suffix="⌥⌘T" + > + + Disabled with prefix and suffix + + And help text + + + + + ), + }, +}; + +export const WithSubmenu: StoryObj< typeof Menu > = { + args: { + ...Default.args, + children: ( + <> + + } + > + Open menu + + + Level 1 item - - Submenu trigger + + + Submenu trigger item with a long label + - Level 3 item + Level 2 item - Level 3 item + Level 2 item + + + + Submenu trigger + + + + + + Level 3 item + + + + + Level 3 item + + + + - - - -); -WithSubmenu.args = { - ...Default.args, + + ), + }, }; -export const WithCheckboxes: StoryFn< typeof Menu > = ( props: MenuProps ) => { - const [ isAChecked, setAChecked ] = useState( false ); - const [ isBChecked, setBChecked ] = useState( true ); - const [ multipleCheckboxesValue, setMultipleCheckboxesValue ] = useState< - string[] - >( [ 'b' ] ); - - const onMultipleCheckboxesCheckedChange: React.ComponentProps< - typeof Menu.CheckboxItem - >[ 'onChange' ] = ( e ) => { - setMultipleCheckboxesValue( ( prevValues ) => { - if ( prevValues.includes( e.target.value ) ) { - return prevValues.filter( ( val ) => val !== e.target.value ); - } - return [ ...prevValues, e.target.value ]; - } ); - }; +export const WithCheckboxes: StoryObj< typeof Menu > = { + render: function WithCheckboxes( props: MenuProps ) { + const [ isAChecked, setAChecked ] = useState( false ); + const [ isBChecked, setBChecked ] = useState( true ); + const [ multipleCheckboxesValue, setMultipleCheckboxesValue ] = + useState< string[] >( [ 'b' ] ); - return ( - - } - > - Open menu - - - - - Single selection, uncontrolled - - - Checkbox item A - - Initially unchecked - - - - Checkbox item B - Initially checked - - - - - - Single selection, controlled - - { - setAChecked( e.target.checked ); - } } - > - Checkbox item A - - Initially unchecked - - - setBChecked( e.target.checked ) } - > - Checkbox item B - Initially checked - - - - - - Multiple selection, uncontrolled - - - Checkbox item A - - Initially unchecked - - - - Checkbox item B - Initially checked - - - - - - Multiple selection, controlled - - - Checkbox item A - - Initially unchecked - - - - Checkbox item B - Initially checked - - - - - ); -}; -WithCheckboxes.args = { - ...Default.args, -}; + const onMultipleCheckboxesCheckedChange: React.ComponentProps< + typeof Menu.CheckboxItem + >[ 'onChange' ] = ( e ) => { + setMultipleCheckboxesValue( ( prevValues ) => { + if ( prevValues.includes( e.target.value ) ) { + return prevValues.filter( + ( val ) => val !== e.target.value + ); + } + return [ ...prevValues, e.target.value ]; + } ); + }; -export const WithRadios: StoryFn< typeof Menu > = ( props: MenuProps ) => { - const [ radioValue, setRadioValue ] = useState( 'two' ); - const onRadioChange: React.ComponentProps< - typeof Menu.RadioItem - >[ 'onChange' ] = ( e ) => setRadioValue( e.target.value ); + return ( + + + } + > + Open menu + + + + + Single selection, uncontrolled + + + Checkbox item A + + Initially unchecked + + + + Checkbox item B + + Initially checked + + + + + + + Single selection, controlled + + { + setAChecked( e.target.checked ); + } } + > + Checkbox item A + + Initially unchecked + + + + setBChecked( e.target.checked ) + } + > + Checkbox item B + + Initially checked + + + + + + + Multiple selection, uncontrolled + + + Checkbox item A + + Initially unchecked + + + + Checkbox item B + + Initially checked + + + + + + + Multiple selection, controlled + + + Checkbox item A + + Initially unchecked + + + + Checkbox item B + + Initially checked + + + + + + ); + }, - return ( - - } - > - Open menu - - - - Uncontrolled - - Radio item 1 - - Initially unchecked - - - - Radio item 2 - Initially checked - - - - - Controlled - - Radio item 1 - - Initially unchecked - - - - Radio item 2 - Initially checked - - - - - ); -}; -WithRadios.args = { - ...Default.args, + args: { + ...Default.args, + }, }; -const modalOnTopOfMenuPopover = css` - && { - z-index: 1000000; - } -`; - -// For more examples with `Modal`, check https://ariakit.org/examples/menu-wordpress-modal -export const WithModals: StoryFn< typeof Menu > = ( props: MenuProps ) => { - const [ isOuterModalOpen, setOuterModalOpen ] = useState( false ); - const [ isInnerModalOpen, setInnerModalOpen ] = useState( false ); - - const cx = useCx(); - const modalOverlayClassName = cx( modalOnTopOfMenuPopover ); +export const WithRadios: StoryObj< typeof Menu > = { + render: function WithRadios( props: MenuProps ) { + const [ radioValue, setRadioValue ] = useState( 'two' ); + const onRadioChange: React.ComponentProps< + typeof Menu.RadioItem + >[ 'onChange' ] = ( e ) => setRadioValue( e.target.value ); - return ( - <> + return ( = ( props: MenuProps ) => { Open menu - setOuterModalOpen( true ) } - hideOnClick={ false } - > - Open outer modal - - setInnerModalOpen( true ) } - hideOnClick={ false } - > - Open inner modal - - { isInnerModalOpen && ( - setInnerModalOpen( false ) } - overlayClassName={ modalOverlayClassName } + + Uncontrolled + + Radio item 1 + + Initially unchecked + + + - Modal's contents - - - ) } + Radio item 2 + + Initially checked + + + + + + Controlled + + Radio item 1 + + Initially unchecked + + + + Radio item 2 + + Initially checked + + + - { isOuterModalOpen && ( - setOuterModalOpen( false ) } - overlayClassName={ modalOverlayClassName } - > - Modal's contents - - - ) } - - ); + ); + }, + + args: { + ...Default.args, + }, }; -WithModals.args = { - ...Default.args, + +const modalOnTopOfMenuPopover = css` + && { + z-index: 1000000; + } +`; + +export const WithModals: StoryObj< typeof Menu > = { + render: function WithModals( props: MenuProps ) { + const [ isOuterModalOpen, setOuterModalOpen ] = useState( false ); + const [ isInnerModalOpen, setInnerModalOpen ] = useState( false ); + + const cx = useCx(); + const modalOverlayClassName = cx( modalOnTopOfMenuPopover ); + + return ( + <> + + + } + > + Open menu + + + setOuterModalOpen( true ) } + hideOnClick={ false } + > + Open outer modal + + setInnerModalOpen( true ) } + hideOnClick={ false } + > + Open inner modal + + { isInnerModalOpen && ( + + setInnerModalOpen( false ) + } + overlayClassName={ modalOverlayClassName } + > + Modal's contents + + + ) } + + + { isOuterModalOpen && ( + setOuterModalOpen( false ) } + overlayClassName={ modalOverlayClassName } + > + Modal's contents + + + ) } + + ); + }, + + args: { + ...Default.args, + }, }; const ExampleSlotFill = createSlotFill( 'Example' ); @@ -478,9 +526,62 @@ const Fill = ( { children }: { children: React.ReactNode } ) => { ); }; -export const WithSlotFill: StoryFn< typeof Menu > = ( props: MenuProps ) => { - return ( - +export const WithSlotFill: StoryObj< typeof Menu > = { + render: ( props: MenuProps ) => { + return ( + + + + } + > + Open menu + + + + Item + + + + + + + + Item from fill + + + + Submenu from fill + + + + + Submenu item from fill + + + + + + + ); + }, + + args: { + ...Default.args, + }, +}; + +const toolbarVariantContextValue = { + Menu: { + variant: 'toolbar', + }, +}; + +export const ToolbarVariant: StoryObj< typeof Menu > = { + render: ( props: MenuProps ) => ( + // TODO: add toolbar + = ( props: MenuProps ) => { - Item + Level 1 item - + + Level 1 item + + + + + Submenu trigger + + + + Level 2 item + + + + + ), - - - Item from fill - - - - Submenu from fill - - - - - Submenu item from fill - - - - - - - ); -}; -WithSlotFill.args = { - ...Default.args, -}; - -const toolbarVariantContextValue = { - Menu: { - variant: 'toolbar', + args: { + ...Default.args, }, }; -export const ToolbarVariant: StoryFn< typeof Menu > = ( props: MenuProps ) => ( - // TODO: add toolbar - - - } - > - Open menu - - - - Level 1 item - - - Level 1 item - - - - - Submenu trigger - - - - Level 2 item - - - - - - -); -ToolbarVariant.args = { - ...Default.args, -}; -export const InsideModal: StoryFn< typeof Menu > = ( props: MenuProps ) => { - const [ isModalOpen, setModalOpen ] = useState( false ); - return ( - <> - - { isModalOpen && ( - setModalOpen( false ) } - title="Menu inside modal" +export const InsideModal: StoryObj< typeof Menu > = { + render: function InsideModal( props: MenuProps ) { + const [ isModalOpen, setModalOpen ] = useState( false ); + return ( + <> + + { isModalOpen && ( + setModalOpen( false ) } + title="Menu inside modal" + > + + + } + > + Open menu + + + - Submenu trigger + Level 1 item - - - + + + + Level 1 item + + + + + - Level 2 item + Submenu trigger - - - - - - - - ) } - - ); -}; -InsideModal.args = { - ...Default.args, -}; -InsideModal.parameters = { - docs: { - source: { type: 'code' }, + + + + + Level 2 item + + + + + + + + + ) } + + ); + }, + + args: { + ...Default.args, + }, + + parameters: { + docs: { + source: { type: 'code' }, + }, }, };