Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Menu: auto-generate README #68249

Open
wants to merge 5 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
591 changes: 418 additions & 173 deletions packages/components/src/menu/README.md

Large diffs are not rendered by default.

24 changes: 12 additions & 12 deletions packages/components/src/menu/checkbox-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ import { Icon, check } from '@wordpress/icons';
* Internal dependencies
*/
import type { WordPressComponentProps } from '../context';
import { MenuContext } from './context';
import type { MenuCheckboxItemProps } from './types';
import { Context } from './context';
import type { CheckboxItemProps } from './types';
import * as Styled from './styles';

export const MenuCheckboxItem = forwardRef<
export const CheckboxItem = forwardRef<
HTMLDivElement,
WordPressComponentProps< MenuCheckboxItemProps, 'div', false >
>( function MenuCheckboxItem(
WordPressComponentProps< CheckboxItemProps, 'div', false >
>( function CheckboxItem(
{ suffix, children, disabled = false, hideOnClick = false, ...props },
ref
) {
const menuContext = useContext( MenuContext );
const menuContext = useContext( Context );

if ( ! menuContext?.store ) {
throw new Error(
Expand All @@ -33,7 +33,7 @@ export const MenuCheckboxItem = forwardRef<
}

return (
<Styled.MenuCheckboxItem
<Styled.CheckboxItem
ref={ ref }
{ ...props }
accessibleWhenDisabled
Expand All @@ -50,17 +50,17 @@ export const MenuCheckboxItem = forwardRef<
<Icon icon={ check } size={ 24 } />
</Ariakit.MenuItemCheck>

<Styled.MenuItemContentWrapper>
<Styled.MenuItemChildrenWrapper>
<Styled.ItemContentWrapper>
<Styled.ItemChildrenWrapper>
{ children }
</Styled.MenuItemChildrenWrapper>
</Styled.ItemChildrenWrapper>

{ suffix && (
<Styled.ItemSuffixWrapper>
{ suffix }
</Styled.ItemSuffixWrapper>
) }
</Styled.MenuItemContentWrapper>
</Styled.MenuCheckboxItem>
</Styled.ItemContentWrapper>
</Styled.CheckboxItem>
);
} );
6 changes: 2 additions & 4 deletions packages/components/src/menu/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { createContext } from '@wordpress/element';
/**
* Internal dependencies
*/
import type { MenuContext as MenuContextType } from './types';
import type { ContextProps } from './types';

export const MenuContext = createContext< MenuContextType | undefined >(
undefined
);
export const Context = createContext< ContextProps | undefined >( undefined );
62 changes: 62 additions & 0 deletions packages/components/src/menu/docs-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"$schema": "../../schemas/docs-manifest.json",
"displayName": "Menu",
"filePath": "./index.tsx",
"subcomponents": [
{
"displayName": "TriggerButton",
"preferredDisplayName": "Menu.TriggerButton",
"filePath": "./trigger-button.tsx"
},
{
"displayName": "Popover",
"preferredDisplayName": "Menu.Popover",
"filePath": "./popover.tsx"
},
{
"displayName": "Item",
"preferredDisplayName": "Menu.Item",
"filePath": "./item.tsx"
},
{
"displayName": "RadioItem",
"preferredDisplayName": "Menu.RadioItem",
"filePath": "./radio-item.tsx"
},
{
"displayName": "CheckboxItem",
"preferredDisplayName": "Menu.CheckboxItem",
"filePath": "./checkbox-item.tsx"
},
{
"displayName": "ItemLabel",
"preferredDisplayName": "Menu.ItemLabel",
"filePath": "./item-label.tsx"
},
{
"displayName": "ItemHelpText",
"preferredDisplayName": "Menu.ItemHelpText",
"filePath": "./item-help-text.tsx"
},
{
"displayName": "Group",
"preferredDisplayName": "Menu.Group",
"filePath": "./group.tsx"
},
{
"displayName": "GroupLabel",
"preferredDisplayName": "Menu.GroupLabel",
"filePath": "./group-label.tsx"
},
{
"displayName": "Separator",
"preferredDisplayName": "Menu.Separator",
"filePath": "./separator.tsx"
},
{
"displayName": "SubmenuTriggerItem",
"preferredDisplayName": "Menu.SubmenuTriggerItem",
"filePath": "./submenu-trigger-item.tsx"
}
]
}
14 changes: 7 additions & 7 deletions packages/components/src/menu/group-label.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ import { forwardRef, useContext } from '@wordpress/element';
* Internal dependencies
*/
import type { WordPressComponentProps } from '../context';
import { MenuContext } from './context';
import { Context } from './context';
import { Text } from '../text';
import type { MenuGroupLabelProps } from './types';
import type { GroupLabelProps } from './types';
import * as Styled from './styles';

export const MenuGroupLabel = forwardRef<
export const GroupLabel = forwardRef<
HTMLDivElement,
WordPressComponentProps< MenuGroupLabelProps, 'div', false >
>( function MenuGroup( props, ref ) {
const menuContext = useContext( MenuContext );
WordPressComponentProps< GroupLabelProps, 'div', false >
>( function Group( props, ref ) {
const menuContext = useContext( Context );

if ( ! menuContext?.store ) {
throw new Error(
Expand All @@ -25,7 +25,7 @@ export const MenuGroupLabel = forwardRef<
}

return (
<Styled.MenuGroupLabel
<Styled.GroupLabel
ref={ ref }
render={
// @ts-expect-error The `children` prop is passed
Expand Down
18 changes: 7 additions & 11 deletions packages/components/src/menu/group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { forwardRef, useContext } from '@wordpress/element';
* Internal dependencies
*/
import type { WordPressComponentProps } from '../context';
import { MenuContext } from './context';
import type { MenuGroupProps } from './types';
import { Context } from './context';
import type { GroupProps } from './types';
import * as Styled from './styles';

export const MenuGroup = forwardRef<
export const Group = forwardRef<
HTMLDivElement,
WordPressComponentProps< MenuGroupProps, 'div', false >
>( function MenuGroup( props, ref ) {
const menuContext = useContext( MenuContext );
WordPressComponentProps< GroupProps, 'div', false >
>( function Group( props, ref ) {
const menuContext = useContext( Context );

if ( ! menuContext?.store ) {
throw new Error(
Expand All @@ -24,10 +24,6 @@ export const MenuGroup = forwardRef<
}

return (
<Styled.MenuGroup
ref={ ref }
{ ...props }
store={ menuContext.store }
/>
<Styled.Group ref={ ref } { ...props } store={ menuContext.store } />
);
} );
142 changes: 111 additions & 31 deletions packages/components/src/menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,31 @@ import { isRTL as isRTLFn } from '@wordpress/i18n';
* Internal dependencies
*/
import { useContextSystem, contextConnectWithoutRef } from '../context';
import type { MenuContext as MenuContextType, MenuProps } from './types';
import { MenuContext } from './context';
import { MenuItem } from './item';
import { MenuCheckboxItem } from './checkbox-item';
import { MenuRadioItem } from './radio-item';
import { MenuGroup } from './group';
import { MenuGroupLabel } from './group-label';
import { MenuSeparator } from './separator';
import { MenuItemLabel } from './item-label';
import { MenuItemHelpText } from './item-help-text';
import { MenuTriggerButton } from './trigger-button';
import { MenuSubmenuTriggerItem } from './submenu-trigger-item';
import { MenuPopover } from './popover';
import type { ContextProps, Props } from './types';
import { Context } from './context';
import { Item } from './item';
import { CheckboxItem } from './checkbox-item';
import { RadioItem } from './radio-item';
import { Group } from './group';
import { GroupLabel } from './group-label';
import { Separator } from './separator';
import { ItemLabel } from './item-label';
import { ItemHelpText } from './item-help-text';
import { TriggerButton } from './trigger-button';
import { SubmenuTriggerItem } from './submenu-trigger-item';
import { Popover } from './popover';

const UnconnectedMenu = ( props: MenuProps ) => {
/**
* Menu is a collection of React components that combine to render
* ARIA-compliant [menu](https://www.w3.org/WAI/ARIA/apg/patterns/menu/) and
* [menu button](https://www.w3.org/WAI/ARIA/apg/patterns/menubutton/) patterns.
*
* `Menu` itself is a wrapper component and context provider.
* It is responsible for managing the state of the menu and its items, and for
* rendering the `Menu.TriggerButton` (or the `Menu.SubmenuTriggerItem`)
* component, and the `Menu.Popover` component.
*/
const UnconnectedMenu = ( props: Props ) => {
const {
children,
defaultOpen = false,
Expand All @@ -39,10 +49,10 @@ const UnconnectedMenu = ( props: MenuProps ) => {
variant,
} = useContextSystem<
// @ts-expect-error TODO: missing 'className' in MenuProps
typeof props & Pick< MenuContextType, 'variant' >
typeof props & Pick< ContextProps, 'variant' >
>( props, 'Menu' );

const parentContext = useContext( MenuContext );
const parentContext = useContext( Context );

const rtl = isRTLFn();

Expand Down Expand Up @@ -84,49 +94,119 @@ const UnconnectedMenu = ( props: MenuProps ) => {
);

return (
<MenuContext.Provider value={ contextValue }>
{ children }
</MenuContext.Provider>
<Context.Provider value={ contextValue }>{ children }</Context.Provider>
);
};

/**
* Menu is a collection of React components that combine to render
* ARIA-compliant [menu](https://www.w3.org/WAI/ARIA/apg/patterns/menu/) and
* [menu button](https://www.w3.org/WAI/ARIA/apg/patterns/menubutton/) patterns.
*
* `Menu` itself is a wrapper component and context provider.
* It is responsible for managing the state of the menu and its items, and for
* rendering the `Menu.TriggerButton` (or the `Menu.SubmenuTriggerItem`)
* component, and the `Menu.Popover` component.
*/
export const Menu = Object.assign(
contextConnectWithoutRef( UnconnectedMenu, 'Menu' ),
{
Context: Object.assign( MenuContext, {
Context: Object.assign( Context, {
displayName: 'Menu.Context',
} ),
Item: Object.assign( MenuItem, {
/**
* Renders a menu item inside the `Menu.Popover` or `Menu.Group` components.
*
* It can optionally contain one instance of the `Menu.ItemLabel` component
* and one instance of the `Menu.ItemHelpText` component.
*/
Item: Object.assign( Item, {
Copy link
Contributor Author

@ciampo ciampo Dec 23, 2024

Choose a reason for hiding this comment

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

With the previous subcomponent named export scheme (ie. MenuItem being assigned to the Item property of the Menu object), the README generator could not pick up the JSDoc correctly,

I managed to fix it by changing the internal naming convention of all subcomponent by removing the Menu prefix: for example, MenuItem got renamed to Item. A lot of the code changes in this file are related to this refactor and were applied as a single commit. You can review the rest of the changes commit by commit to remove the noise.

displayName: 'Menu.Item',
} ),
RadioItem: Object.assign( MenuRadioItem, {
/**
* Renders a radio menu item inside the `Menu.Popover` or `Menu.Group`
* components.
*
* It can optionally contain one instance of the `Menu.ItemLabel` component
* and one instance of the `Menu.ItemHelpText` component.
*/
RadioItem: Object.assign( RadioItem, {
displayName: 'Menu.RadioItem',
} ),
CheckboxItem: Object.assign( MenuCheckboxItem, {
/**
* Renders a checkbox menu item inside the `Menu.Popover` or `Menu.Group`
* components.
*
* It can optionally contain one instance of the `Menu.ItemLabel` component
* and one instance of the `Menu.ItemHelpText` component.
*/
CheckboxItem: Object.assign( CheckboxItem, {
displayName: 'Menu.CheckboxItem',
} ),
Group: Object.assign( MenuGroup, {
/**
* Renders a group for menu items.
*
* It should contain one instance of `Menu.GroupLabel` and one or more
* instances of `Menu.Item`, `Menu.RadioItem`, or `Menu.CheckboxItem`.
*/
Group: Object.assign( Group, {
displayName: 'Menu.Group',
} ),
GroupLabel: Object.assign( MenuGroupLabel, {
/**
* Renders a label in a menu group.
*
* This component should be wrapped with `Menu.Group` so the
* `aria-labelledby` is correctly set on the group element.
*/
GroupLabel: Object.assign( GroupLabel, {
displayName: 'Menu.GroupLabel',
} ),
Separator: Object.assign( MenuSeparator, {
/**
* Renders a divider between menu items or menu groups.
*/
Separator: Object.assign( Separator, {
displayName: 'Menu.Separator',
} ),
ItemLabel: Object.assign( MenuItemLabel, {
/**
* Renders a menu item's label text. It should be wrapped with `Menu.Item`,
* `Menu.RadioItem`, or `Menu.CheckboxItem`.
*/
ItemLabel: Object.assign( ItemLabel, {
displayName: 'Menu.ItemLabel',
} ),
ItemHelpText: Object.assign( MenuItemHelpText, {
/**
* Renders a menu item's help text. It should be wrapped with `Menu.Item`,
* `Menu.RadioItem`, or `Menu.CheckboxItem`.
*/
ItemHelpText: Object.assign( ItemHelpText, {
displayName: 'Menu.ItemHelpText',
} ),
Popover: Object.assign( MenuPopover, {
/**
* Renders a dropdown menu element that's controlled by a sibling
* `Menu.TriggerButton` component. It renders a popover and automatically
* focuses on items when the menu is shown.
*
* The only valid children of `Menu.Popover` are `Menu.Item`,
* `Menu.RadioItem`, `Menu.CheckboxItem`, `Menu.Group`, `Menu.Separator`,
* and `Menu` (for nested dropdown menus).
*/
Popover: Object.assign( Popover, {
displayName: 'Menu.Popover',
} ),
TriggerButton: Object.assign( MenuTriggerButton, {
/**
* Renders a menu button that toggles the visibility of a sibling
* `Menu.Popover` component when clicked or when using arrow keys.
*/
TriggerButton: Object.assign( TriggerButton, {
displayName: 'Menu.TriggerButton',
} ),
SubmenuTriggerItem: Object.assign( MenuSubmenuTriggerItem, {
/**
* Renders a menu item that toggles the visibility of a sibling
* `Menu.Popover` component when clicked or when using arrow keys.
*
* This component is used to create a nested dropdown menu.
*/
SubmenuTriggerItem: Object.assign( SubmenuTriggerItem, {
displayName: 'Menu.SubmenuTriggerItem',
} ),
}
Expand Down
Loading
Loading