From 4f696087e1d8d6a0ee84408ccc6ad16fe25d2ab7 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 14 Apr 2025 10:24:19 +0200 Subject: [PATCH 1/4] Added docs for Menu Signed-off-by: Charles de Dreuille --- .../src/app/(docs)/components/menu/page.mdx | 140 +++++++++++++++++ .../src/app/(docs)/components/menu/props.ts | 142 ++++++++++++++++++ canon-docs/src/snippets/stories-snippets.tsx | 8 + canon-docs/src/utils/data.ts | 5 + canon-docs/src/utils/propDefs.ts | 8 + .../src/components/Menu/Menu.stories.tsx | 21 ++- 6 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 canon-docs/src/app/(docs)/components/menu/page.mdx create mode 100644 canon-docs/src/app/(docs)/components/menu/props.ts diff --git a/canon-docs/src/app/(docs)/components/menu/page.mdx b/canon-docs/src/app/(docs)/components/menu/page.mdx new file mode 100644 index 0000000000..baa719375f --- /dev/null +++ b/canon-docs/src/app/(docs)/components/menu/page.mdx @@ -0,0 +1,140 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { Tabs } from '@/components/Tabs'; +import { CodeBlock } from '@/components/CodeBlock'; +import { MenuSnippet, ButtonSnippet } from '@/snippets/stories-snippets'; +import { BaseUI } from '@/components/HeadlessBanners/BaseUI'; +import { + menuRootPropDefs, + menuTriggerPropDefs, + menuPositionerPropDefs, + menuItemPropDefs, +} from './props'; + +# Menu + +A list of actions in a dropdown, enhanced with keyboard navigation. + +} + code={` + ( + + )} + /> + + + + Settings + Invite new members + Download app + Log out + + + + `} +/> + + + + Usage + Theming + + + + + + + + + + + + `} + /> + + + We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with + your brand. For additional flexibility, you can use the provided class names for each element listed below. + `} + /> + + + + +## API reference + + + +### Menu.Root + + + +### Menu.Trigger + +The trigger by default render a simple unstyled button. Because menus can be rendered in different ways, we recommend +using the `render` prop to render a custom trigger. + + + )} + /> + + + + Settings + Invite new members + Download app + Log out + + + + `} +/> diff --git a/canon-docs/src/app/(docs)/components/menu/props.ts b/canon-docs/src/app/(docs)/components/menu/props.ts new file mode 100644 index 0000000000..5cf41fa5f9 --- /dev/null +++ b/canon-docs/src/app/(docs)/components/menu/props.ts @@ -0,0 +1,142 @@ +import { + classNamePropDefs, + stylePropDefs, + renderPropDefs, +} from '@/utils/propDefs'; +import type { PropDef } from '@/utils/propDefs'; + +export const menuRootPropDefs: Record = { + defaultOpen: { + type: 'boolean', + default: 'false', + }, + open: { + type: 'boolean', + }, + onOpenChange: { + type: 'enum', + values: ['(open, event) => void'], + }, + closeParentOnEsc: { + type: 'boolean', + default: 'true', + }, + modal: { + type: 'boolean', + default: 'true', + }, + onOpenChangeComplete: { + type: 'enum', + values: ['(open) => void'], + }, + disabled: { + type: 'boolean', + default: 'false', + }, + openOnHover: { + type: 'boolean', + }, + delay: { + type: 'number', + default: '100', + }, + loop: { + type: 'boolean', + default: 'true', + }, + orientation: { + type: 'enum', + values: ['horizontal', 'vertical'], + default: 'vertical', + }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const menuTriggerPropDefs: Record = { + ...renderPropDefs, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const menuPositionerPropDefs: Record = { + align: { + type: 'enum', + values: ['start', 'center', 'end'], + default: 'center', + }, + alignOffset: { + type: 'enum', + values: ['number', '(data) => number'], + default: '0', + }, + side: { + type: 'enum', + values: ['bottom', 'inline-end', 'inline-start', 'left', 'right', 'top'], + default: 'bottom', + }, + sideOffset: { + type: 'enum', + values: ['number', '(data) => number'], + default: '0', + }, + arrowPadding: { + type: 'number', + default: '5', + }, + anchor: { + type: 'enum', + values: [ + 'React.Ref', + 'Element', + 'VirtualElement', + '(() => Element | VirtualElement | null)', + 'null', + ], + }, + collisionBoundary: { + type: 'enum', + values: ['clipping-ancestors', 'Element', 'Element[]', 'Rect'], + default: 'clipping-ancestors', + }, + collisionPadding: { + type: 'enum', + values: ['number', 'Rect'], + default: '5', + }, + sticky: { + type: 'boolean', + default: 'false', + }, + positionMethod: { + type: 'enum', + values: ['absolute', 'fixed'], + default: 'absolute', + }, + trackAnchor: { + type: 'boolean', + default: 'true', + }, + ...classNamePropDefs, + ...stylePropDefs, +}; + +export const menuItemPropDefs: Record = { + label: { + type: 'string', + }, + onClick: { + type: 'enum', + values: ['(event) => void'], + }, + closeOnClick: { + type: 'boolean', + default: 'true', + }, + disabled: { + type: 'boolean', + default: 'false', + }, + ...classNamePropDefs, + ...stylePropDefs, +}; diff --git a/canon-docs/src/snippets/stories-snippets.tsx b/canon-docs/src/snippets/stories-snippets.tsx index 5c363d6fc7..9536ba16a2 100644 --- a/canon-docs/src/snippets/stories-snippets.tsx +++ b/canon-docs/src/snippets/stories-snippets.tsx @@ -13,6 +13,7 @@ import * as TextFieldStories from '../../../packages/canon/src/components/TextFi import * as TextStories from '../../../packages/canon/src/components/Text/Text.stories'; import * as FlexStories from '../../../packages/canon/src/components/Flex/Flex.stories'; import * as SelectStories from '../../../packages/canon/src/components/Select/Select.stories'; +import * as MenuStories from '../../../packages/canon/src/components/Menu/Menu.stories'; export const BoxSnippet = ({ story }: { story: keyof typeof BoxStories }) => { const stories = composeStories(BoxStories); @@ -125,3 +126,10 @@ export const SelectSnippet = ({ return StoryComponent ? : null; }; + +export const MenuSnippet = ({ story }: { story: keyof typeof MenuStories }) => { + const stories = composeStories(MenuStories); + const StoryComponent = stories[story as keyof typeof stories]; + + return StoryComponent ? : null; +}; diff --git a/canon-docs/src/utils/data.ts b/canon-docs/src/utils/data.ts index fd4625cd20..43a457d268 100644 --- a/canon-docs/src/utils/data.ts +++ b/canon-docs/src/utils/data.ts @@ -91,6 +91,11 @@ export const components: Page[] = [ slug: 'icon-button', status: 'alpha', }, + { + title: 'Menu', + slug: 'menu', + status: 'alpha', + }, { title: 'Select', slug: 'select', diff --git a/canon-docs/src/utils/propDefs.ts b/canon-docs/src/utils/propDefs.ts index f087d6188f..3805665346 100644 --- a/canon-docs/src/utils/propDefs.ts +++ b/canon-docs/src/utils/propDefs.ts @@ -203,3 +203,11 @@ export const childrenPropDefs: Record = { responsive: false, }, }; + +export const renderPropDefs: Record = { + render: { + type: 'enum', + values: ['React.ReactElement', '(props, state) => React.ReactElement'], + responsive: false, + }, +}; diff --git a/packages/canon/src/components/Menu/Menu.stories.tsx b/packages/canon/src/components/Menu/Menu.stories.tsx index 77bff661e3..d1b8f831c5 100644 --- a/packages/canon/src/components/Menu/Menu.stories.tsx +++ b/packages/canon/src/components/Menu/Menu.stories.tsx @@ -32,7 +32,12 @@ export const Default: Story = { <> ( - )} @@ -40,9 +45,10 @@ export const Default: Story = { - Item 1 - Item 2 - Item 3 + Settings + Invite new members + Download app + Log out @@ -57,3 +63,10 @@ export const Open: Story = { open: true, }, }; + +export const OpenOnHover: Story = { + args: { + ...Default.args, + openOnHover: true, + }, +}; From f6745b7c5d1e3959b80b0bdc647f311192a64a1e Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 14 Apr 2025 11:31:15 +0200 Subject: [PATCH 2/4] Update page.mdx Signed-off-by: Charles de Dreuille --- canon-docs/src/app/(docs)/components/menu/page.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/canon-docs/src/app/(docs)/components/menu/page.mdx b/canon-docs/src/app/(docs)/components/menu/page.mdx index baa719375f..aca381da18 100644 --- a/canon-docs/src/app/(docs)/components/menu/page.mdx +++ b/canon-docs/src/app/(docs)/components/menu/page.mdx @@ -82,6 +82,8 @@ A list of actions in a dropdown, enhanced with keyboard navigation. ### Menu.Root +Groups all parts of the menu. Doesn't render its own HTML element. + ### Menu.Trigger @@ -95,10 +97,14 @@ using the `render` prop to render a custom trigger. ### Menu.Positioner +Positions the menu popup against the trigger. Renders a `
` element. + ### Menu.Item +An individual interactive item in the menu. Renders a `
` element. + ## Examples From aafb0dbb5c5a50a7a9fff15bc9218b5e38e9ab7d Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 14 Apr 2025 13:25:10 +0200 Subject: [PATCH 3/4] Add Link page Signed-off-by: Charles de Dreuille --- .../src/app/(docs)/components/link/page.mdx | 84 +++++++++++++++++++ .../src/app/(docs)/components/link/props.ts | 26 ++++++ .../src/app/(docs)/components/menu/page.mdx | 21 +++-- canon-docs/src/snippets/stories-snippets.tsx | 8 ++ canon-docs/src/utils/data.ts | 5 ++ 5 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 canon-docs/src/app/(docs)/components/link/page.mdx create mode 100644 canon-docs/src/app/(docs)/components/link/props.ts diff --git a/canon-docs/src/app/(docs)/components/link/page.mdx b/canon-docs/src/app/(docs)/components/link/page.mdx new file mode 100644 index 0000000000..64a3261590 --- /dev/null +++ b/canon-docs/src/app/(docs)/components/link/page.mdx @@ -0,0 +1,84 @@ +import { PropsTable } from '@/components/PropsTable'; +import { Snippet } from '@/components/Snippet'; +import { Tabs } from '@/components/Tabs'; +import { CodeBlock } from '@/components/CodeBlock'; +import { + MenuSnippet, + ButtonSnippet, + LinkSnippet, +} from '@/snippets/stories-snippets'; +import { linkPropDefs } from './props'; + +# Link + +A link component that renders a `` element. + +} + code={`Sign up for Backstage`} +/> + + + + Usage + Theming + + + Sign up for Backstage`} + /> + + + We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with + your brand. For additional flexibility, you can use the provided class names for each element listed below. + - `canon-Link` + - `canon-Link[data-variant='body']` + - `canon-Link[data-variant='subtitle']` + - `canon-Link[data-variant='caption']` + - `canon-Link[data-variant='label']` + - `canon-Link[data-weight='regular']` + - `canon-Link[data-weight='bold']` + + + +## API reference + + + +## Examples + +### Variants + +Here's a view when links have different variants. + +} + code={` + + + + + `} +/> + +### Weights + +Here's a view when links have different weights. + +} + code={` + + + `} +/> diff --git a/canon-docs/src/app/(docs)/components/link/props.ts b/canon-docs/src/app/(docs)/components/link/props.ts new file mode 100644 index 0000000000..d0b15808e9 --- /dev/null +++ b/canon-docs/src/app/(docs)/components/link/props.ts @@ -0,0 +1,26 @@ +import { + classNamePropDefs, + stylePropDefs, + renderPropDefs, +} from '@/utils/propDefs'; +import type { PropDef } from '@/utils/propDefs'; + +export const linkPropDefs: Record = { + to: { + type: 'string', + }, + variant: { + type: 'enum', + values: ['subtitle', 'body', 'caption', 'label'], + default: 'body', + responsive: true, + }, + weight: { + type: 'enum', + values: ['regular', 'bold'], + default: 'regular', + responsive: true, + }, + ...classNamePropDefs, + ...stylePropDefs, +}; diff --git a/canon-docs/src/app/(docs)/components/menu/page.mdx b/canon-docs/src/app/(docs)/components/menu/page.mdx index aca381da18..98c4949438 100644 --- a/canon-docs/src/app/(docs)/components/menu/page.mdx +++ b/canon-docs/src/app/(docs)/components/menu/page.mdx @@ -2,7 +2,7 @@ import { PropsTable } from '@/components/PropsTable'; import { Snippet } from '@/components/Snippet'; import { Tabs } from '@/components/Tabs'; import { CodeBlock } from '@/components/CodeBlock'; -import { MenuSnippet, ButtonSnippet } from '@/snippets/stories-snippets'; +import { MenuSnippet } from '@/snippets/stories-snippets'; import { BaseUI } from '@/components/HeadlessBanners/BaseUI'; import { menuRootPropDefs, @@ -69,10 +69,21 @@ A list of actions in a dropdown, enhanced with keyboard navigation. We recommend starting with our [global tokens](/theme/theming) to customize the library and align it with your brand. For additional flexibility, you can use the provided class names for each element listed below. - `} - /> - + - `canon-MenuTrigger` + - `canon-MenuBackdrop` + - `canon-MenuPositioner` + - `canon-MenuPopup` + - `canon-MenuArrow` + - `canon-MenuItem` + - `canon-MenuGroup` + - `canon-MenuGroupLabel` + - `canon-MenuRadioGroup` + - `canon-MenuRadioItem` + - `canon-MenuRadioItemIndicator` + - `canon-MenuCheckboxItem` + - `canon-MenuCheckboxItemIndicator` + - `canon-MenuSubmenuTrigger` + - `canon-MenuSeparator` diff --git a/canon-docs/src/snippets/stories-snippets.tsx b/canon-docs/src/snippets/stories-snippets.tsx index 9536ba16a2..6b54f5dc4d 100644 --- a/canon-docs/src/snippets/stories-snippets.tsx +++ b/canon-docs/src/snippets/stories-snippets.tsx @@ -14,6 +14,7 @@ import * as TextStories from '../../../packages/canon/src/components/Text/Text.s import * as FlexStories from '../../../packages/canon/src/components/Flex/Flex.stories'; import * as SelectStories from '../../../packages/canon/src/components/Select/Select.stories'; import * as MenuStories from '../../../packages/canon/src/components/Menu/Menu.stories'; +import * as LinkStories from '../../../packages/canon/src/components/Link/Link.stories'; export const BoxSnippet = ({ story }: { story: keyof typeof BoxStories }) => { const stories = composeStories(BoxStories); @@ -133,3 +134,10 @@ export const MenuSnippet = ({ story }: { story: keyof typeof MenuStories }) => { return StoryComponent ? : null; }; + +export const LinkSnippet = ({ story }: { story: keyof typeof LinkStories }) => { + const stories = composeStories(LinkStories); + const StoryComponent = stories[story as keyof typeof stories]; + + return StoryComponent ? : null; +}; diff --git a/canon-docs/src/utils/data.ts b/canon-docs/src/utils/data.ts index 43a457d268..48274ea1a2 100644 --- a/canon-docs/src/utils/data.ts +++ b/canon-docs/src/utils/data.ts @@ -91,6 +91,11 @@ export const components: Page[] = [ slug: 'icon-button', status: 'alpha', }, + { + title: 'Link', + slug: 'link', + status: 'alpha', + }, { title: 'Menu', slug: 'menu', From b0364ebbb5f7693b97b1af5c87bd4e7afcb11757 Mon Sep 17 00:00:00 2001 From: Charles de Dreuille Date: Mon, 14 Apr 2025 14:21:49 +0200 Subject: [PATCH 4/4] Update props.ts Signed-off-by: Charles de Dreuille --- canon-docs/src/app/(docs)/components/link/props.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/canon-docs/src/app/(docs)/components/link/props.ts b/canon-docs/src/app/(docs)/components/link/props.ts index d0b15808e9..83507c5594 100644 --- a/canon-docs/src/app/(docs)/components/link/props.ts +++ b/canon-docs/src/app/(docs)/components/link/props.ts @@ -1,8 +1,4 @@ -import { - classNamePropDefs, - stylePropDefs, - renderPropDefs, -} from '@/utils/propDefs'; +import { classNamePropDefs, stylePropDefs } from '@/utils/propDefs'; import type { PropDef } from '@/utils/propDefs'; export const linkPropDefs: Record = {