Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Use args.children when possible
  • Loading branch information
ciampo committed Dec 22, 2024
commit 980c20e1cd38a906f8e8021b2ae3ed850d98f0f1
203 changes: 104 additions & 99 deletions packages/components/src/menu/stories/index.story.tsx
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hiding whitespace changes removes a lot of noise while reviewing

Original file line number Diff line number Diff line change
Expand Up @@ -68,112 +68,117 @@ const meta: Meta< typeof Menu > = {
export default meta;

export const Default: StoryObj< typeof Menu > = {
render: ( props: MenuProps ) => (
<Menu { ...props }>
<Menu.TriggerButton
render={ <Button __next40pxDefaultSize variant="secondary" /> }
>
Open menu
</Menu.TriggerButton>
<Menu.Popover>
<Menu.Item>
<Menu.ItemLabel>Label</Menu.ItemLabel>
</Menu.Item>
<Menu.Item>
<Menu.ItemLabel>Label</Menu.ItemLabel>
<Menu.ItemHelpText>Help text</Menu.ItemHelpText>
</Menu.Item>
<Menu.Item>
<Menu.ItemLabel>Label</Menu.ItemLabel>
<Menu.ItemHelpText>
The menu item help text is automatically truncated when
there are more than two lines of text
</Menu.ItemHelpText>
</Menu.Item>
<Menu.Item hideOnClick={ false }>
<Menu.ItemLabel>Label</Menu.ItemLabel>
<Menu.ItemHelpText>
This item doesn&apos;t close the menu on click
</Menu.ItemHelpText>
</Menu.Item>
<Menu.Item disabled>Disabled item</Menu.Item>
<Menu.Separator />
<Menu.Group>
<Menu.GroupLabel>Group label</Menu.GroupLabel>
<Menu.Item
prefix={ <Icon icon={ customLink } size={ 24 } /> }
>
<Menu.ItemLabel>With prefix</Menu.ItemLabel>
args: {
children: (
Comment on lines +71 to +72
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The csf-2-to-3 codemod would use render: () => { ... } instead of args.children. What's the difference? Seems like it allows you to specify the props type inline when passing it to render:

export const Default: StoryObj< typeof Menu > = {
	render: ( props: MenuProps ) => (
		<Menu { ...props }>
			/// ...
		</Menu>
	),

	args: {},
};

One difference to note is that the codemod uses render: but also specifically adds this to all stories that inherit from Default:

	args: {
		...Default.args,
	},

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was working on some of the TypeScript compilation hotspots, I noticed that not having a render function is better for performance, since it can bypass a lot of work. So we should avoid render and prefer children when possible.

Copy link
Contributor Author

@ciampo ciampo Dec 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Lena points out, the reason why I used children at the beginning was because I thought it'd be more idiomatic / more performant.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me 👍

However, how do we maintain it as other people work on stories and introduce CSF3 ones? Should we add some docs or introduce linting? Any better ideas?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could document it, and we usually point it out in code review, but that's about as far as I think it needs to be "enforced". No biggie.

This was already a thing in CSF2, where some people would write completely new templates instead of just changing args.children.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I know, using args over custom "render" function has always been a best practice, even prior to CSF3.

In case it helps, Storybook docs also point out that using args is preferred: https://storybook.js.org/docs/8.5/writing-stories#working-with-react-hooks:~:text=We%20recommend%20args%20as%20much%20as%20possible%20when%20writing%20your%20own%20stories.

Not sure if we should spend time writing docs or lining Storybook files?

<>
<Menu.TriggerButton
render={
<Button __next40pxDefaultSize variant="secondary" />
}
>
Open menu
</Menu.TriggerButton>
<Menu.Popover>
<Menu.Item>
<Menu.ItemLabel>Label</Menu.ItemLabel>
</Menu.Item>
<Menu.Item suffix="⌘S">With suffix</Menu.Item>
<Menu.Item
disabled
prefix={
<Icon icon={ formatCapitalize } size={ 24 } />
}
suffix="⌥⌘T"
>
<Menu.ItemLabel>
Disabled with prefix and suffix
</Menu.ItemLabel>
<Menu.ItemHelpText>And help text</Menu.ItemHelpText>
<Menu.Item>
<Menu.ItemLabel>Label</Menu.ItemLabel>
<Menu.ItemHelpText>Help text</Menu.ItemHelpText>
</Menu.Item>
</Menu.Group>
</Menu.Popover>
</Menu>
),

args: {},
};

export const WithSubmenu: StoryObj< typeof Menu > = {
render: ( props: MenuProps ) => (
<Menu { ...props }>
<Menu.TriggerButton
render={ <Button __next40pxDefaultSize variant="secondary" /> }
>
Open menu
</Menu.TriggerButton>
<Menu.Popover>
<Menu.Item>Level 1 item</Menu.Item>
<Menu>
<Menu.SubmenuTriggerItem suffix="Suffix">
<Menu.ItemLabel>
Submenu trigger item with a long label
</Menu.ItemLabel>
</Menu.SubmenuTriggerItem>
<Menu.Popover>
<Menu.Item>
<Menu.ItemLabel>Level 2 item</Menu.ItemLabel>
<Menu.Item>
<Menu.ItemLabel>Label</Menu.ItemLabel>
<Menu.ItemHelpText>
The menu item help text is automatically truncated
when there are more than two lines of text
</Menu.ItemHelpText>
</Menu.Item>
<Menu.Item hideOnClick={ false }>
<Menu.ItemLabel>Label</Menu.ItemLabel>
<Menu.ItemHelpText>
This item doesn&apos;t close the menu on click
</Menu.ItemHelpText>
</Menu.Item>
<Menu.Item disabled>Disabled item</Menu.Item>
<Menu.Separator />
<Menu.Group>
<Menu.GroupLabel>Group label</Menu.GroupLabel>
<Menu.Item
prefix={ <Icon icon={ customLink } size={ 24 } /> }
>
<Menu.ItemLabel>With prefix</Menu.ItemLabel>
</Menu.Item>
<Menu.Item>
<Menu.ItemLabel>Level 2 item</Menu.ItemLabel>
<Menu.Item suffix="⌘S">With suffix</Menu.Item>
<Menu.Item
disabled
prefix={
<Icon icon={ formatCapitalize } size={ 24 } />
}
suffix="⌥⌘T"
>
<Menu.ItemLabel>
Disabled with prefix and suffix
</Menu.ItemLabel>
<Menu.ItemHelpText>And help text</Menu.ItemHelpText>
</Menu.Item>
<Menu>
<Menu.SubmenuTriggerItem>
<Menu.ItemLabel>Submenu trigger</Menu.ItemLabel>
</Menu.SubmenuTriggerItem>
<Menu.Popover>
<Menu.Item>
<Menu.ItemLabel>
Level 3 item
</Menu.ItemLabel>
</Menu.Item>
<Menu.Item>
<Menu.ItemLabel>
Level 3 item
</Menu.ItemLabel>
</Menu.Item>
</Menu.Popover>
</Menu>
</Menu.Popover>
</Menu>
</Menu.Popover>
</Menu>
),
</Menu.Group>
</Menu.Popover>
</>
),
},
};

export const WithSubmenu: StoryObj< typeof Menu > = {
args: {
...Default.args,
children: (
<>
<Menu.TriggerButton
render={
<Button __next40pxDefaultSize variant="secondary" />
}
>
Open menu
</Menu.TriggerButton>
<Menu.Popover>
<Menu.Item>Level 1 item</Menu.Item>
<Menu>
<Menu.SubmenuTriggerItem suffix="Suffix">
<Menu.ItemLabel>
Submenu trigger item with a long label
</Menu.ItemLabel>
</Menu.SubmenuTriggerItem>
<Menu.Popover>
<Menu.Item>
<Menu.ItemLabel>Level 2 item</Menu.ItemLabel>
</Menu.Item>
<Menu.Item>
<Menu.ItemLabel>Level 2 item</Menu.ItemLabel>
</Menu.Item>
<Menu>
<Menu.SubmenuTriggerItem>
<Menu.ItemLabel>
Submenu trigger
</Menu.ItemLabel>
</Menu.SubmenuTriggerItem>
<Menu.Popover>
<Menu.Item>
<Menu.ItemLabel>
Level 3 item
</Menu.ItemLabel>
</Menu.Item>
<Menu.Item>
<Menu.ItemLabel>
Level 3 item
</Menu.ItemLabel>
</Menu.Item>
</Menu.Popover>
</Menu>
</Menu.Popover>
</Menu>
</Menu.Popover>
</>
),
},
};

Expand Down
Loading