@windmorph/react 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dist/components/autocomplete/Autocomplete.js +1 -1
  2. package/dist/components/autocomplete/Autocomplete.js.map +1 -1
  3. package/dist/components/carousel/carousel-styles.d.ts +6 -15
  4. package/dist/components/carousel/carousel-styles.js +4 -7
  5. package/dist/components/carousel/carousel-styles.js.map +1 -1
  6. package/dist/components/checkbox/checkbox-tokens.d.ts +1 -1
  7. package/dist/components/date-picker/DatePicker.js +11 -4
  8. package/dist/components/date-picker/DatePicker.js.map +1 -1
  9. package/dist/components/date-picker/date-picker-styles.d.ts +3 -3
  10. package/dist/components/fab-menu/FabMenu.js +2 -2
  11. package/dist/components/fab-menu/FabMenu.js.map +1 -1
  12. package/dist/components/list/List.d.ts +9 -0
  13. package/dist/components/list/List.js +7 -4
  14. package/dist/components/list/List.js.map +1 -1
  15. package/dist/components/list/list-styles.js +6 -6
  16. package/dist/components/list/list-styles.js.map +1 -1
  17. package/dist/components/list/list-tokens.d.ts +1 -1
  18. package/dist/components/list/list-tokens.js +50 -0
  19. package/dist/components/list/list-tokens.js.map +1 -1
  20. package/dist/components/menu/Menu.d.ts +13 -0
  21. package/dist/components/menu/Menu.js +14 -1
  22. package/dist/components/menu/Menu.js.map +1 -1
  23. package/dist/components/navigation/NavigationRail.js +52 -15
  24. package/dist/components/navigation/NavigationRail.js.map +1 -1
  25. package/dist/components/navigation/navigation-styles.js +1 -1
  26. package/dist/components/navigation/navigation-styles.js.map +1 -1
  27. package/dist/components/search/SearchBar.js +19 -34
  28. package/dist/components/search/SearchBar.js.map +1 -1
  29. package/dist/components/search/SearchField.d.ts +111 -0
  30. package/dist/components/search/SearchField.js +128 -0
  31. package/dist/components/search/SearchField.js.map +1 -0
  32. package/dist/components/search/search-field-frame.js +36 -0
  33. package/dist/components/search/search-field-frame.js.map +1 -0
  34. package/dist/components/search/search-styles.d.ts +58 -0
  35. package/dist/components/search/search-styles.js +29 -4
  36. package/dist/components/search/search-styles.js.map +1 -1
  37. package/dist/components/select/search-list.js +8 -13
  38. package/dist/components/select/search-list.js.map +1 -1
  39. package/dist/components/slider/Slider.js +5 -1
  40. package/dist/components/slider/Slider.js.map +1 -1
  41. package/dist/components/snackbar/snackbar-tokens.d.ts +1 -1
  42. package/dist/components/text-field/TextField.js +19 -5
  43. package/dist/components/text-field/TextField.js.map +1 -1
  44. package/dist/components/text-field/text-field-styles.js +2 -2
  45. package/dist/components/text-field/text-field-styles.js.map +1 -1
  46. package/dist/components/toolbar/toolbar-styles.js +2 -2
  47. package/dist/components/toolbar/toolbar-styles.js.map +1 -1
  48. package/dist/index.d.ts +3 -2
  49. package/dist/index.js +3 -2
  50. package/dist/primitives/use-m3-interaction.js +10 -6
  51. package/dist/primitives/use-m3-interaction.js.map +1 -1
  52. package/dist/styles/generated/components.css +5 -0
  53. package/dist/styles/utilities.css +22 -15
  54. package/dist/styles.compiled.css +1 -1
  55. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"list-styles.js","names":[],"sources":["../../../src/components/list/list-styles.ts"],"sourcesContent":["import { tv, type VariantProps } from '../../utils/tv';\n\n/*\n * Values follow the M3 Expressive list spec (m3.material.io) with Compose Material 3's\n * Expressive list tokens (ListItem.kt's interactive overloads, SegmentedListItem,\n * ListItemDefaults, ListTokens' `*Expressive*` values; 2026-10-13).\n *\n * Item: 16px start / end and 10px top / bottom padding, 12px between leading content, the\n * text and trailing content. The 12px belongs to the leading and trailing cells (rendered\n * only when present), so a text-only item's text spans 16px to 16px. At least 56px tall with one line, 72px with two (overline or\n * supporting text) and 88px with three (both), where content aligns to the top. Headline\n * `body-large` `on-surface`; supporting text `body-medium`, overline `label-small`, leading\n * and trailing content `on-surface-variant` (trailing text `label-small`, 20px icons). Selected\n * items show a trailing check as a second cue besides colour. Selected items\n * are `secondary-container` with `on-secondary-container` content; disabled content is\n * `on-surface` 38%.\n *\n * Shape (interactive items): 4px at rest, 12px hovered, 16px focused, selected or pressed,\n * morphing on the fast spatial spring; colours change on the default effects spring.\n * Segmented lists put 2px between items and round the outer corners of the first and last\n * items to 16px at rest. Static items in a standard list have no corners.\n *\n * Leading images are 56dp squares and video thumbnails 100 × 56dp (small) or 114 × 64dp\n * (large), all with 8dp corners; avatars are 40dp circles in `primary-container`\n * (`ListMedia.tsx`). The item grows to fit them. Expandable items indent their nested items\n * 16dp per level and end with a chevron that turns over on the fast spatial spring; their\n * nested items open and close their height on the default spatial spring while fading on\n * the default effects spring (only the fade under reduced motion). Dividers (standard lists) are 1px of\n * `outline-variant` on the item's bottom edge, full width or 16dp in from each side, drawn\n * by its `::after` (the state layer uses its background), never under the last item.\n *\n * Web density (`--md-sys-density`, 0 to -3; M3: a list \"can adjust margins, spacing, or\n * density\"): each step takes 2px off the padding above and below an item (10 → 4px) and 4px off\n * its minimum height (56 → 44px, 72 → 60px, 88 → 76px), so items that media make taller lose\n * 4px a step too, as in Material Components Web's list density (every item height 4px a step).\n * Section subheaders lose 4px a step (48 → 36px). Items are stacked rows, so dense ones keep\n * non-overlapping full-row targets above WCAG 2.5.8's 24px, and the expand chevron's target is\n * at most a one-line item's height.\n *\n * Sections (`ListSection`) put a subheader above their items: 48dp tall, `title-small`\n * `on-surface-variant`, 16dp from each side. The M3 spec defines no list subheader, so this\n * follows the deprecated navigation drawer's section headline. Items take their position\n * (segmented corners, dividers) within their section.\n *\n * Item colours come from the list's component tokens (`list-tokens.ts`,\n * `--md-comp-list-list-item-*`): the root and each item carry `data-tokens=\"md-comp-list\"`\n * and `data-variant`. A consumer class still wins in `cn()`.\n *\n * Every class is written out in full so Tailwind can find it.\n */\n\n/** Variant definitions for {@link List}; extend them to add variants. */\nexport const listStyles = tv({\n slots: {\n root: 'm-0 flex list-none flex-col p-0 outline-none',\n // A `ListSection`: its subheader, then its items' group.\n section: 'flex flex-col',\n // The M3 spec has no list subheader; this follows the deprecated navigation drawer's\n // section headline (`title-small`, `on-surface-variant`), on a 48dp row with the items'\n // 16dp side padding, so its text lines up with the headlines below it.\n subheader:\n 'flex min-h-[calc(48px+var(--md-sys-density,0)*4px)] items-center ps-[16px] pe-[16px] text-title-small text-on-surface-variant',\n group: 'm-0 flex list-none flex-col p-0',\n item: [\n 'group/list-item flex ps-[16px] pe-[16px] pt-[calc(10px+var(--md-sys-density,0)*2px)] pb-[calc(10px+var(--md-sys-density,0)*2px)] text-start outline-none',\n 'bg-[var(--_md-comp-list-container-color)] data-selected:bg-[var(--_md-comp-list-list-item-selected-container-color)]',\n '[--m3-transition-property:border-radius,background-color,color]',\n '[--m3-transition-duration:var(--md-sys-motion-spring-spatial-fast-duration),var(--md-sys-motion-spring-effects-default-duration),var(--md-sys-motion-spring-effects-default-duration)]',\n '[--m3-transition-easing:var(--md-sys-motion-spring-spatial-fast-easing),var(--md-sys-motion-spring-effects-default-easing),var(--md-sys-motion-spring-effects-default-easing)]',\n '[--m3-transition-delay:0s,0s,0s]',\n ],\n // The item's content grid (the grid cell of an interactive item).\n cell: 'grid w-full grid-cols-[auto_minmax(0,1fr)_auto]',\n leading: [\n 'col-start-1 me-[12px] flex items-center gap-x-[12px] text-title-medium text-[color:var(--_md-comp-list-list-item-leading-icon-color)] [&>svg]:size-[20px]',\n 'group-data-selected/list-item:text-on-secondary-container',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n text: 'col-start-2 flex min-w-0 flex-col',\n overline: [\n 'text-label-small text-[color:var(--_md-comp-list-list-item-overline-color)]',\n 'group-data-selected/list-item:text-on-secondary-container',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n headline: [\n 'text-body-large text-[color:var(--_md-comp-list-list-item-label-text-color)]',\n 'group-data-selected/list-item:text-on-secondary-container',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n supporting: [\n 'text-body-medium text-[color:var(--_md-comp-list-list-item-supporting-text-color)]',\n 'group-data-selected/list-item:text-on-secondary-container',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n trailing: [\n 'col-start-3 ms-[12px] flex items-center gap-x-[12px] text-label-small text-[color:var(--_md-comp-list-list-item-trailing-icon-color)] [&>svg]:size-[20px]',\n 'group-data-selected/list-item:text-on-secondary-container',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n // The check a selected item shows besides its colour (M3: two cues for selection).\n selectionIndicator: [\n 'inline-flex size-[20px] shrink-0 items-center justify-center opacity-0 [&>svg]:size-full',\n 'group-data-selected/list-item:opacity-100 group-data-selected/list-item:text-on-secondary-container',\n 'transition-opacity duration-(--md-sys-motion-spring-effects-fast-duration) ease-(--md-sys-motion-spring-effects-fast-easing)',\n ],\n // An expandable item's chevron: a button (out of the Tab order) with a 48px target.\n expand: [\n 'relative inline-flex size-[24px] shrink-0 cursor-pointer items-center justify-center rounded-full',\n 'state-layer [&>svg]:size-[20px] [&>svg]:fill-current',\n '[&>svg]:transition-transform [&>svg]:duration-(--md-sys-motion-spring-spatial-fast-duration) [&>svg]:ease-(--md-sys-motion-spring-spatial-fast-easing)',\n 'group-aria-expanded/list-item:[&>svg]:rotate-180 motion-reduce:[&>svg]:transition-none',\n 'data-disabled:cursor-default',\n ],\n // A tree row's wrapper: nested rows open and close their height (grid rows 0fr ↔ 1fr)\n // on the default spatial spring and fade on the default effects spring; under reduced\n // motion they only fade.\n reveal: [\n 'grid grid-rows-[1fr] opacity-100',\n '[transition-property:grid-template-rows,opacity] motion-reduce:[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-spatial-default-duration),var(--md-sys-motion-spring-effects-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-spatial-default-easing),var(--md-sys-motion-spring-effects-default-easing)]',\n // Reduced motion: the fade alone, still on the default effects spring.\n 'motion-reduce:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n 'motion-reduce:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n // The height opens and closes only with motion: under reduced motion a leaving row\n // stays open and fades where it is (with no height transition, a closed height would\n // apply in the first frame and hide the fade).\n 'motion-safe:data-appear:starting:grid-rows-[0fr] data-appear:starting:opacity-0',\n 'motion-safe:data-exiting:grid-rows-[0fr] data-exiting:opacity-0',\n // A closing row is never the scroll anchor: the browser would pick it (its top stays\n // put) and let a row pressed below it slide up by its height. The pressed row is held\n // in place by the tree itself when the anchor is above it (2026-10-17).\n 'data-exiting:[overflow-anchor:none]',\n ],\n // Lets the row's height close to nothing inside the reveal.\n revealClip: 'flex min-h-0 flex-col overflow-hidden',\n // The drawn checkbox, radio button or switch of an item that is one. Decorative: the\n // item is the control, so the drawing only follows its state attributes.\n control: 'group/control inline-flex shrink-0 items-center justify-center',\n // A link item's leading and trailing content: above the link's overlay, but only its\n // controls take the pointer, so a press anywhere else reaches the link.\n raised:\n 'pointer-events-none relative z-1 [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto',\n // A link item's anchor: its overlay covers the item, so the whole item is the link.\n link: \"outline-none after:absolute after:inset-0 after:content-['']\",\n },\n variants: {\n variant: {\n // Item colours are tokens: a standard item is see-through, so it takes its\n // container's colour (a sheet, a card); a segmented item is `surface`.\n standard: {},\n segmented: {\n // A tree's 2px gaps are inside each row's reveal (above every row but the first), so\n // a closing row takes its gap with it: a gap left between rows of no height would\n // shift what follows by 2px per row as the ghosts are removed, and the browser's\n // scroll anchoring then scrolled the page by as much (2026-10-17).\n root: 'gap-[2px] [&[role=treegrid]]:gap-0',\n group: 'gap-[2px]',\n reveal: 'not-first:[&>*>*]:mt-[2px]',\n },\n },\n interactive: {\n true: {\n item: [\n 'cursor-pointer state-layer focus-ring-inset select-none',\n 'data-disabled:cursor-default',\n // One shape state at a time (see `data-shape`), so no two rules compete.\n 'data-[shape=rest]:rounded-corner-extra-small',\n 'data-[shape=hovered]:rounded-corner-medium',\n 'data-[shape=active]:rounded-corner-large',\n ],\n },\n false: {},\n },\n lines: {\n 1: {\n item: 'min-h-[calc(56px+var(--md-sys-density,0)*4px)] items-center',\n cell: 'items-center',\n },\n 2: {\n item: 'min-h-[calc(72px+var(--md-sys-density,0)*4px)] items-center',\n cell: 'items-center',\n },\n 3: {\n item: 'min-h-[calc(88px+var(--md-sys-density,0)*4px)] items-start',\n cell: 'items-start',\n },\n },\n dividers: {\n none: {},\n full: {\n item: [\n \"relative after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-outline-variant after:content-['']\",\n 'data-[position=last]:after:hidden data-[position=only]:after:hidden',\n // A plain list's item is last in its group by structure too, so the server's HTML\n // is right before the list learns where its sections are (see \\`segmented\\`).\n '[&[data-list-entry]:where(:last-child,:has(+[data-slot=section]))]:after:hidden',\n '[[data-list-entry]:where(:last-child,:has(+[data-slot=section]))>&]:after:hidden',\n 'forced-colors:after:bg-[GrayText] forced-colors:after:forced-color-adjust-none',\n ],\n },\n inset: {\n item: [\n \"relative after:pointer-events-none after:absolute after:inset-x-[16px] after:bottom-0 after:h-px after:bg-outline-variant after:content-['']\",\n 'data-[position=last]:after:hidden data-[position=only]:after:hidden',\n // A plain list's item is last in its group by structure too, so the server's HTML\n // is right before the list learns where its sections are (see \\`segmented\\`).\n '[&[data-list-entry]:where(:last-child,:has(+[data-slot=section]))]:after:hidden',\n '[[data-list-entry]:where(:last-child,:has(+[data-slot=section]))>&]:after:hidden',\n 'forced-colors:after:bg-[GrayText] forced-colors:after:forced-color-adjust-none',\n ],\n },\n },\n // How many lines a headline or supporting text shows (the `text` slot's children).\n headlineLines: {\n 1: { headline: 'line-clamp-1' },\n 2: { headline: 'line-clamp-2' },\n 3: { headline: 'line-clamp-3' },\n },\n supportingTextLines: {\n 1: { supporting: 'line-clamp-1' },\n 2: { supporting: 'line-clamp-2' },\n 3: { supporting: 'line-clamp-3' },\n },\n // Nested items of an expandable list, indented 16dp per level (`--m3-list-level`).\n nested: {\n true: { item: 'ps-[calc(16px+var(--m3-list-level,0)*16px)]' },\n false: {},\n },\n // Whether a section shows a subheader.\n titled: { true: {}, false: {} },\n // Overrides the alignment that follows from the line count.\n align: {\n center: { item: 'items-center', cell: 'items-center' },\n top: { item: 'items-start', cell: 'items-start' },\n },\n },\n compoundVariants: [\n // Segmented sections without a subheader stand 16dp apart, so each reads as its own group.\n { variant: 'segmented', titled: false, class: { section: 'not-first:pt-[16px]' } },\n // Segmented lists round the outer corners of the group at rest (static items too).\n // A plain list's items (\\`data-list-entry\\`, the item or the \\`li\\` holding it) also take\n // them from their place among their siblings: a group starts at the first child or after\n // a section and ends at the last child or before one. The list learns which entries are\n // sections only once it renders on the client, so without these the server's HTML would\n // show loose items next to a section with square corners until hydration.\n {\n variant: 'segmented',\n class: {\n item: [\n 'data-[shape=rest]:rounded-corner-extra-small',\n 'data-[shape=rest]:data-[position=first]:rounded-t-corner-large',\n 'data-[shape=rest]:data-[position=last]:rounded-b-corner-large',\n 'data-[shape=rest]:data-[position=only]:rounded-corner-large',\n 'data-[shape=rest]:[&[data-list-entry]:where(:first-child,[data-slot=section]+*)]:rounded-t-corner-large',\n 'data-[shape=rest]:[[data-list-entry]:where(:first-child,[data-slot=section]+*)>&]:rounded-t-corner-large',\n 'data-[shape=rest]:[&[data-list-entry]:where(:last-child,:has(+[data-slot=section]))]:rounded-b-corner-large',\n 'data-[shape=rest]:[[data-list-entry]:where(:last-child,:has(+[data-slot=section]))>&]:rounded-b-corner-large',\n ],\n },\n },\n ],\n defaultVariants: { variant: 'standard', interactive: false, lines: 1, dividers: 'none' },\n});\n\n/**\n * The variants of {@link listStyles}, for building on its styles. They are the recipe's keys, not\n * component props: their names (`hasIcon`, `isOpen`…) follow the classes and may change.\n */\nexport type ListStyleProps = VariantProps<typeof listStyles>;\nexport type ListVariant = NonNullable<ListStyleProps['variant']>;\nexport type ListDividers = Exclude<NonNullable<ListStyleProps['dividers']>, 'none'>;\n\n/** Variant definitions for `ListItemImage`, `ListItemVideo` and `ListItemAvatar` (M3's leading media). */\nexport const listMediaStyles = tv({\n slots: {\n // 8dp corners (M3 Expressive's `corner-small`), the image cropped to fill, faded with a\n // disabled item. The tonal fill shows behind a fallback icon.\n frame: [\n 'relative flex shrink-0 items-center justify-center overflow-hidden',\n 'bg-secondary-container text-on-secondary-container [&>svg]:size-[24px] [&>svg]:fill-current',\n '[&>img]:size-full [&>img]:object-cover',\n 'group-data-disabled/list-item:opacity-38',\n ],\n badge: [\n 'absolute flex size-[24px] items-center justify-center rounded-full',\n 'bg-inverse-surface/70 text-inverse-on-surface [&>svg]:size-[16px] [&>svg]:fill-current',\n 'forced-colors:border forced-colors:border-solid forced-colors:border-[CanvasText]',\n ],\n duration:\n 'absolute end-[4px] bottom-[4px] rounded-corner-extra-small bg-inverse-surface/80 px-[4px] text-label-small text-inverse-on-surface',\n },\n variants: {\n kind: {\n image: { frame: 'size-[56px] rounded-corner-small' },\n video: { frame: 'rounded-corner-small' },\n // A 40dp circle in `primary-container`, its initials `title-medium`.\n avatar: {\n frame:\n 'size-[40px] rounded-full bg-primary-container text-title-medium text-on-primary-container',\n },\n },\n size: {\n sm: {},\n lg: {},\n },\n },\n compoundVariants: [\n { kind: 'video', size: 'sm', class: { frame: 'h-[56px] w-[100px]' } },\n { kind: 'video', size: 'lg', class: { frame: 'h-[64px] w-[114px]' } },\n ],\n defaultVariants: { kind: 'image', size: 'sm' },\n});\n"],"mappings":";;;AAoDA,MAAa,aAAa,GAAG;CAC3B,OAAO;EACL,MAAM;EAEN,SAAS;EAIT,WACE;EACF,OAAO;EACP,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;EACF;EAEA,MAAM;EACN,SAAS;GACP;GACA;GACA;EACF;EACA,MAAM;EACN,UAAU;GACR;GACA;GACA;EACF;EACA,UAAU;GACR;GACA;GACA;EACF;EACA,YAAY;GACV;GACA;GACA;EACF;EACA,UAAU;GACR;GACA;GACA;EACF;EAEA,oBAAoB;GAClB;GACA;GACA;EACF;EAEA,QAAQ;GACN;GACA;GACA;GACA;GACA;EACF;EAIA,QAAQ;GACN;GACA;GACA;GACA;GAEA;GACA;GAIA;GACA;GAIA;EACF;EAEA,YAAY;EAGZ,SAAS;EAGT,QACE;EAEF,MAAM;CACR;CACA,UAAU;EACR,SAAS;GAGP,UAAU,CAAC;GACX,WAAW;IAKT,MAAM;IACN,OAAO;IACP,QAAQ;GACV;EACF;EACA,aAAa;GACX,MAAM,EACJ,MAAM;IACJ;IACA;IAEA;IACA;IACA;GACF,EACF;GACA,OAAO,CAAC;EACV;EACA,OAAO;GACL,GAAG;IACD,MAAM;IACN,MAAM;GACR;GACA,GAAG;IACD,MAAM;IACN,MAAM;GACR;GACA,GAAG;IACD,MAAM;IACN,MAAM;GACR;EACF;EACA,UAAU;GACR,MAAM,CAAC;GACP,MAAM,EACJ,MAAM;IACJ;IACA;IAGA;IACA;IACA;GACF,EACF;GACA,OAAO,EACL,MAAM;IACJ;IACA;IAGA;IACA;IACA;GACF,EACF;EACF;EAEA,eAAe;GACb,GAAG,EAAE,UAAU,eAAe;GAC9B,GAAG,EAAE,UAAU,eAAe;GAC9B,GAAG,EAAE,UAAU,eAAe;EAChC;EACA,qBAAqB;GACnB,GAAG,EAAE,YAAY,eAAe;GAChC,GAAG,EAAE,YAAY,eAAe;GAChC,GAAG,EAAE,YAAY,eAAe;EAClC;EAEA,QAAQ;GACN,MAAM,EAAE,MAAM,8CAA8C;GAC5D,OAAO,CAAC;EACV;EAEA,QAAQ;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;EAE9B,OAAO;GACL,QAAQ;IAAE,MAAM;IAAgB,MAAM;GAAe;GACrD,KAAK;IAAE,MAAM;IAAe,MAAM;GAAc;EAClD;CACF;CACA,kBAAkB,CAEhB;EAAE,SAAS;EAAa,QAAQ;EAAO,OAAO,EAAE,SAAS,sBAAsB;CAAE,GAOjF;EACE,SAAS;EACT,OAAO,EACL,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,EACF;CACF,CACF;CACA,iBAAiB;EAAE,SAAS;EAAY,aAAa;EAAO,OAAO;EAAG,UAAU;CAAO;AACzF,CAAC;;AAWD,MAAa,kBAAkB,GAAG;CAChC,OAAO;EAGL,OAAO;GACL;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;EACF;EACA,UACE;CACJ;CACA,UAAU;EACR,MAAM;GACJ,OAAO,EAAE,OAAO,mCAAmC;GACnD,OAAO,EAAE,OAAO,uBAAuB;GAEvC,QAAQ,EACN,OACE,4FACJ;EACF;EACA,MAAM;GACJ,IAAI,CAAC;GACL,IAAI,CAAC;EACP;CACF;CACA,kBAAkB,CAChB;EAAE,MAAM;EAAS,MAAM;EAAM,OAAO,EAAE,OAAO,qBAAqB;CAAE,GACpE;EAAE,MAAM;EAAS,MAAM;EAAM,OAAO,EAAE,OAAO,qBAAqB;CAAE,CACtE;CACA,iBAAiB;EAAE,MAAM;EAAS,MAAM;CAAK;AAC/C,CAAC"}
1
+ {"version":3,"file":"list-styles.js","names":[],"sources":["../../../src/components/list/list-styles.ts"],"sourcesContent":["import { tv, type VariantProps } from '../../utils/tv';\n\n/*\n * Values follow the M3 Expressive list spec (m3.material.io) with Compose Material 3's\n * Expressive list tokens (ListItem.kt's interactive overloads, SegmentedListItem,\n * ListItemDefaults, ListTokens' `*Expressive*` values; 2026-10-13).\n *\n * Item: 16px start / end and 10px top / bottom padding, 12px between leading content, the\n * text and trailing content. The 12px belongs to the leading and trailing cells (rendered\n * only when present), so a text-only item's text spans 16px to 16px. At least 56px tall with one line, 72px with two (overline or\n * supporting text) and 88px with three (both), where content aligns to the top. Headline\n * `body-large` `on-surface`; supporting text `body-medium`, overline `label-small`, leading\n * and trailing content `on-surface-variant` (trailing text `label-small`, 20px icons). Selected\n * items show a trailing check as a second cue besides colour. Selected items\n * are `secondary-container` with `on-secondary-container` content (the `selected-*` tokens);\n * a switch item that's on stays plain unless it asks for them (`selectedWhenChecked`);\n * disabled content is `on-surface` 38%.\n *\n * Shape (interactive items): 4px at rest, 12px hovered, 16px focused, selected or pressed,\n * morphing on the fast spatial spring; colours change on the default effects spring.\n * Segmented lists put 2px between items and round the outer corners of the first and last\n * items to 16px at rest. Static items in a standard list have no corners.\n *\n * Leading images are 56dp squares and video thumbnails 100 × 56dp (small) or 114 × 64dp\n * (large), all with 8dp corners; avatars are 40dp circles in `primary-container`\n * (`ListMedia.tsx`). The item grows to fit them. Expandable items indent their nested items\n * 16dp per level and end with a chevron that turns over on the fast spatial spring; their\n * nested items open and close their height on the default spatial spring while fading on\n * the default effects spring (only the fade under reduced motion). Dividers (standard lists) are 1px of\n * `outline-variant` on the item's bottom edge, full width or 16dp in from each side, drawn\n * by its `::after` (the state layer uses its background), never under the last item.\n *\n * Web density (`--md-sys-density`, 0 to -3; M3: a list \"can adjust margins, spacing, or\n * density\"): each step takes 2px off the padding above and below an item (10 → 4px) and 4px off\n * its minimum height (56 → 44px, 72 → 60px, 88 → 76px), so items that media make taller lose\n * 4px a step too, as in Material Components Web's list density (every item height 4px a step).\n * Section subheaders lose 4px a step (48 → 36px). Items are stacked rows, so dense ones keep\n * non-overlapping full-row targets above WCAG 2.5.8's 24px, and the expand chevron's target is\n * at most a one-line item's height.\n *\n * Sections (`ListSection`) put a subheader above their items: 48dp tall, `title-small`\n * `on-surface-variant`, 16dp from each side. The M3 spec defines no list subheader, so this\n * follows the deprecated navigation drawer's section headline. Items take their position\n * (segmented corners, dividers) within their section.\n *\n * Item colours come from the list's component tokens (`list-tokens.ts`,\n * `--md-comp-list-list-item-*`): the root and each item carry `data-tokens=\"md-comp-list\"`\n * and `data-variant`. A consumer class still wins in `cn()`.\n *\n * Every class is written out in full so Tailwind can find it.\n */\n\n/** Variant definitions for {@link List}; extend them to add variants. */\nexport const listStyles = tv({\n slots: {\n root: 'm-0 flex list-none flex-col p-0 outline-none',\n // A `ListSection`: its subheader, then its items' group.\n section: 'flex flex-col',\n // The M3 spec has no list subheader; this follows the deprecated navigation drawer's\n // section headline (`title-small`, `on-surface-variant`), on a 48dp row with the items'\n // 16dp side padding, so its text lines up with the headlines below it.\n subheader:\n 'flex min-h-[calc(48px+var(--md-sys-density,0)*4px)] items-center ps-[16px] pe-[16px] text-title-small text-on-surface-variant',\n group: 'm-0 flex list-none flex-col p-0',\n item: [\n 'group/list-item flex ps-[16px] pe-[16px] pt-[calc(10px+var(--md-sys-density,0)*2px)] pb-[calc(10px+var(--md-sys-density,0)*2px)] text-start outline-none',\n 'bg-[var(--_md-comp-list-container-color)] data-selected:bg-[var(--_md-comp-list-list-item-selected-container-color)]',\n '[--m3-transition-property:border-radius,background-color,color]',\n '[--m3-transition-duration:var(--md-sys-motion-spring-spatial-fast-duration),var(--md-sys-motion-spring-effects-default-duration),var(--md-sys-motion-spring-effects-default-duration)]',\n '[--m3-transition-easing:var(--md-sys-motion-spring-spatial-fast-easing),var(--md-sys-motion-spring-effects-default-easing),var(--md-sys-motion-spring-effects-default-easing)]',\n '[--m3-transition-delay:0s,0s,0s]',\n ],\n // The item's content grid (the grid cell of an interactive item).\n cell: 'grid w-full grid-cols-[auto_minmax(0,1fr)_auto]',\n leading: [\n 'col-start-1 me-[12px] flex items-center gap-x-[12px] text-title-medium text-[color:var(--_md-comp-list-list-item-leading-icon-color)] [&>svg]:size-[20px]',\n 'group-data-selected/list-item:text-[color:var(--_md-comp-list-list-item-selected-leading-icon-color)]',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n text: 'col-start-2 flex min-w-0 flex-col',\n overline: [\n 'text-label-small text-[color:var(--_md-comp-list-list-item-overline-color)]',\n 'group-data-selected/list-item:text-[color:var(--_md-comp-list-list-item-selected-overline-color)]',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n headline: [\n 'text-body-large text-[color:var(--_md-comp-list-list-item-label-text-color)]',\n 'group-data-selected/list-item:text-[color:var(--_md-comp-list-list-item-selected-label-text-color)]',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n supporting: [\n 'text-body-medium text-[color:var(--_md-comp-list-list-item-supporting-text-color)]',\n 'group-data-selected/list-item:text-[color:var(--_md-comp-list-list-item-selected-supporting-text-color)]',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n trailing: [\n 'col-start-3 ms-[12px] flex items-center gap-x-[12px] text-label-small text-[color:var(--_md-comp-list-list-item-trailing-icon-color)] [&>svg]:size-[20px]',\n 'group-data-selected/list-item:text-[color:var(--_md-comp-list-list-item-selected-trailing-icon-color)]',\n 'group-data-disabled/list-item:text-on-surface/38',\n ],\n // The check a selected item shows besides its colour (M3: two cues for selection).\n selectionIndicator: [\n 'inline-flex size-[20px] shrink-0 items-center justify-center opacity-0 [&>svg]:size-full',\n 'group-data-selected/list-item:opacity-100 group-data-selected/list-item:text-[color:var(--_md-comp-list-list-item-selected-trailing-icon-color)]',\n 'transition-opacity duration-(--md-sys-motion-spring-effects-fast-duration) ease-(--md-sys-motion-spring-effects-fast-easing)',\n ],\n // An expandable item's chevron: a button (out of the Tab order) with a 48px target.\n expand: [\n 'relative inline-flex size-[24px] shrink-0 cursor-pointer items-center justify-center rounded-full',\n 'state-layer [&>svg]:size-[20px] [&>svg]:fill-current',\n '[&>svg]:transition-transform [&>svg]:duration-(--md-sys-motion-spring-spatial-fast-duration) [&>svg]:ease-(--md-sys-motion-spring-spatial-fast-easing)',\n 'group-aria-expanded/list-item:[&>svg]:rotate-180 motion-reduce:[&>svg]:transition-none',\n 'data-disabled:cursor-default',\n ],\n // A tree row's wrapper: nested rows open and close their height (grid rows 0fr ↔ 1fr)\n // on the default spatial spring and fade on the default effects spring; under reduced\n // motion they only fade.\n reveal: [\n 'grid grid-rows-[1fr] opacity-100',\n '[transition-property:grid-template-rows,opacity] motion-reduce:[transition-property:opacity]',\n '[transition-duration:var(--md-sys-motion-spring-spatial-default-duration),var(--md-sys-motion-spring-effects-default-duration)]',\n '[transition-timing-function:var(--md-sys-motion-spring-spatial-default-easing),var(--md-sys-motion-spring-effects-default-easing)]',\n // Reduced motion: the fade alone, still on the default effects spring.\n 'motion-reduce:[transition-duration:var(--md-sys-motion-spring-effects-default-duration)]',\n 'motion-reduce:[transition-timing-function:var(--md-sys-motion-spring-effects-default-easing)]',\n // The height opens and closes only with motion: under reduced motion a leaving row\n // stays open and fades where it is (with no height transition, a closed height would\n // apply in the first frame and hide the fade).\n 'motion-safe:data-appear:starting:grid-rows-[0fr] data-appear:starting:opacity-0',\n 'motion-safe:data-exiting:grid-rows-[0fr] data-exiting:opacity-0',\n // A closing row is never the scroll anchor: the browser would pick it (its top stays\n // put) and let a row pressed below it slide up by its height. The pressed row is held\n // in place by the tree itself when the anchor is above it (2026-10-17).\n 'data-exiting:[overflow-anchor:none]',\n ],\n // Lets the row's height close to nothing inside the reveal.\n revealClip: 'flex min-h-0 flex-col overflow-hidden',\n // The drawn checkbox, radio button or switch of an item that is one. Decorative: the\n // item is the control, so the drawing only follows its state attributes.\n control: 'group/control inline-flex shrink-0 items-center justify-center',\n // A link item's leading and trailing content: above the link's overlay, but only its\n // controls take the pointer, so a press anywhere else reaches the link.\n raised:\n 'pointer-events-none relative z-1 [&_a]:pointer-events-auto [&_button]:pointer-events-auto [&_input]:pointer-events-auto [&_select]:pointer-events-auto [&_textarea]:pointer-events-auto',\n // A link item's anchor: its overlay covers the item, so the whole item is the link.\n link: \"outline-none after:absolute after:inset-0 after:content-['']\",\n },\n variants: {\n variant: {\n // Item colours are tokens: a standard item is see-through, so it takes its\n // container's colour (a sheet, a card); a segmented item is `surface`.\n standard: {},\n segmented: {\n // A tree's 2px gaps are inside each row's reveal (above every row but the first), so\n // a closing row takes its gap with it: a gap left between rows of no height would\n // shift what follows by 2px per row as the ghosts are removed, and the browser's\n // scroll anchoring then scrolled the page by as much (2026-10-17).\n root: 'gap-[2px] [&[role=treegrid]]:gap-0',\n group: 'gap-[2px]',\n reveal: 'not-first:[&>*>*]:mt-[2px]',\n },\n },\n interactive: {\n true: {\n item: [\n 'cursor-pointer state-layer focus-ring-inset select-none',\n 'data-disabled:cursor-default',\n // One shape state at a time (see `data-shape`), so no two rules compete.\n 'data-[shape=rest]:rounded-corner-extra-small',\n 'data-[shape=hovered]:rounded-corner-medium',\n 'data-[shape=active]:rounded-corner-large',\n ],\n },\n false: {},\n },\n lines: {\n 1: {\n item: 'min-h-[calc(56px+var(--md-sys-density,0)*4px)] items-center',\n cell: 'items-center',\n },\n 2: {\n item: 'min-h-[calc(72px+var(--md-sys-density,0)*4px)] items-center',\n cell: 'items-center',\n },\n 3: {\n item: 'min-h-[calc(88px+var(--md-sys-density,0)*4px)] items-start',\n cell: 'items-start',\n },\n },\n dividers: {\n none: {},\n full: {\n item: [\n \"relative after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:h-px after:bg-outline-variant after:content-['']\",\n 'data-[position=last]:after:hidden data-[position=only]:after:hidden',\n // A plain list's item is last in its group by structure too, so the server's HTML\n // is right before the list learns where its sections are (see \\`segmented\\`).\n '[&[data-list-entry]:where(:last-child,:has(+[data-slot=section]))]:after:hidden',\n '[[data-list-entry]:where(:last-child,:has(+[data-slot=section]))>&]:after:hidden',\n 'forced-colors:after:bg-[GrayText] forced-colors:after:forced-color-adjust-none',\n ],\n },\n inset: {\n item: [\n \"relative after:pointer-events-none after:absolute after:inset-x-[16px] after:bottom-0 after:h-px after:bg-outline-variant after:content-['']\",\n 'data-[position=last]:after:hidden data-[position=only]:after:hidden',\n // A plain list's item is last in its group by structure too, so the server's HTML\n // is right before the list learns where its sections are (see \\`segmented\\`).\n '[&[data-list-entry]:where(:last-child,:has(+[data-slot=section]))]:after:hidden',\n '[[data-list-entry]:where(:last-child,:has(+[data-slot=section]))>&]:after:hidden',\n 'forced-colors:after:bg-[GrayText] forced-colors:after:forced-color-adjust-none',\n ],\n },\n },\n // How many lines a headline or supporting text shows (the `text` slot's children).\n headlineLines: {\n 1: { headline: 'line-clamp-1' },\n 2: { headline: 'line-clamp-2' },\n 3: { headline: 'line-clamp-3' },\n },\n supportingTextLines: {\n 1: { supporting: 'line-clamp-1' },\n 2: { supporting: 'line-clamp-2' },\n 3: { supporting: 'line-clamp-3' },\n },\n // Nested items of an expandable list, indented 16dp per level (`--m3-list-level`).\n nested: {\n true: { item: 'ps-[calc(16px+var(--m3-list-level,0)*16px)]' },\n false: {},\n },\n // Whether a section shows a subheader.\n titled: { true: {}, false: {} },\n // Overrides the alignment that follows from the line count.\n align: {\n center: { item: 'items-center', cell: 'items-center' },\n top: { item: 'items-start', cell: 'items-start' },\n },\n },\n compoundVariants: [\n // Segmented sections without a subheader stand 16dp apart, so each reads as its own group.\n { variant: 'segmented', titled: false, class: { section: 'not-first:pt-[16px]' } },\n // Segmented lists round the outer corners of the group at rest (static items too).\n // A plain list's items (\\`data-list-entry\\`, the item or the \\`li\\` holding it) also take\n // them from their place among their siblings: a group starts at the first child or after\n // a section and ends at the last child or before one. The list learns which entries are\n // sections only once it renders on the client, so without these the server's HTML would\n // show loose items next to a section with square corners until hydration.\n {\n variant: 'segmented',\n class: {\n item: [\n 'data-[shape=rest]:rounded-corner-extra-small',\n 'data-[shape=rest]:data-[position=first]:rounded-t-corner-large',\n 'data-[shape=rest]:data-[position=last]:rounded-b-corner-large',\n 'data-[shape=rest]:data-[position=only]:rounded-corner-large',\n 'data-[shape=rest]:[&[data-list-entry]:where(:first-child,[data-slot=section]+*)]:rounded-t-corner-large',\n 'data-[shape=rest]:[[data-list-entry]:where(:first-child,[data-slot=section]+*)>&]:rounded-t-corner-large',\n 'data-[shape=rest]:[&[data-list-entry]:where(:last-child,:has(+[data-slot=section]))]:rounded-b-corner-large',\n 'data-[shape=rest]:[[data-list-entry]:where(:last-child,:has(+[data-slot=section]))>&]:rounded-b-corner-large',\n ],\n },\n },\n ],\n defaultVariants: { variant: 'standard', interactive: false, lines: 1, dividers: 'none' },\n});\n\n/**\n * The variants of {@link listStyles}, for building on its styles. They are the recipe's keys, not\n * component props: their names (`hasIcon`, `isOpen`…) follow the classes and may change.\n */\nexport type ListStyleProps = VariantProps<typeof listStyles>;\nexport type ListVariant = NonNullable<ListStyleProps['variant']>;\nexport type ListDividers = Exclude<NonNullable<ListStyleProps['dividers']>, 'none'>;\n\n/** Variant definitions for `ListItemImage`, `ListItemVideo` and `ListItemAvatar` (M3's leading media). */\nexport const listMediaStyles = tv({\n slots: {\n // 8dp corners (M3 Expressive's `corner-small`), the image cropped to fill, faded with a\n // disabled item. The tonal fill shows behind a fallback icon.\n frame: [\n 'relative flex shrink-0 items-center justify-center overflow-hidden',\n 'bg-secondary-container text-on-secondary-container [&>svg]:size-[24px] [&>svg]:fill-current',\n '[&>img]:size-full [&>img]:object-cover',\n 'group-data-disabled/list-item:opacity-38',\n ],\n badge: [\n 'absolute flex size-[24px] items-center justify-center rounded-full',\n 'bg-inverse-surface/70 text-inverse-on-surface [&>svg]:size-[16px] [&>svg]:fill-current',\n 'forced-colors:border forced-colors:border-solid forced-colors:border-[CanvasText]',\n ],\n duration:\n 'absolute end-[4px] bottom-[4px] rounded-corner-extra-small bg-inverse-surface/80 px-[4px] text-label-small text-inverse-on-surface',\n },\n variants: {\n kind: {\n image: { frame: 'size-[56px] rounded-corner-small' },\n video: { frame: 'rounded-corner-small' },\n // A 40dp circle in `primary-container`, its initials `title-medium`.\n avatar: {\n frame:\n 'size-[40px] rounded-full bg-primary-container text-title-medium text-on-primary-container',\n },\n },\n size: {\n sm: {},\n lg: {},\n },\n },\n compoundVariants: [\n { kind: 'video', size: 'sm', class: { frame: 'h-[56px] w-[100px]' } },\n { kind: 'video', size: 'lg', class: { frame: 'h-[64px] w-[114px]' } },\n ],\n defaultVariants: { kind: 'image', size: 'sm' },\n});\n"],"mappings":";;;AAqDA,MAAa,aAAa,GAAG;CAC3B,OAAO;EACL,MAAM;EAEN,SAAS;EAIT,WACE;EACF,OAAO;EACP,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;EACF;EAEA,MAAM;EACN,SAAS;GACP;GACA;GACA;EACF;EACA,MAAM;EACN,UAAU;GACR;GACA;GACA;EACF;EACA,UAAU;GACR;GACA;GACA;EACF;EACA,YAAY;GACV;GACA;GACA;EACF;EACA,UAAU;GACR;GACA;GACA;EACF;EAEA,oBAAoB;GAClB;GACA;GACA;EACF;EAEA,QAAQ;GACN;GACA;GACA;GACA;GACA;EACF;EAIA,QAAQ;GACN;GACA;GACA;GACA;GAEA;GACA;GAIA;GACA;GAIA;EACF;EAEA,YAAY;EAGZ,SAAS;EAGT,QACE;EAEF,MAAM;CACR;CACA,UAAU;EACR,SAAS;GAGP,UAAU,CAAC;GACX,WAAW;IAKT,MAAM;IACN,OAAO;IACP,QAAQ;GACV;EACF;EACA,aAAa;GACX,MAAM,EACJ,MAAM;IACJ;IACA;IAEA;IACA;IACA;GACF,EACF;GACA,OAAO,CAAC;EACV;EACA,OAAO;GACL,GAAG;IACD,MAAM;IACN,MAAM;GACR;GACA,GAAG;IACD,MAAM;IACN,MAAM;GACR;GACA,GAAG;IACD,MAAM;IACN,MAAM;GACR;EACF;EACA,UAAU;GACR,MAAM,CAAC;GACP,MAAM,EACJ,MAAM;IACJ;IACA;IAGA;IACA;IACA;GACF,EACF;GACA,OAAO,EACL,MAAM;IACJ;IACA;IAGA;IACA;IACA;GACF,EACF;EACF;EAEA,eAAe;GACb,GAAG,EAAE,UAAU,eAAe;GAC9B,GAAG,EAAE,UAAU,eAAe;GAC9B,GAAG,EAAE,UAAU,eAAe;EAChC;EACA,qBAAqB;GACnB,GAAG,EAAE,YAAY,eAAe;GAChC,GAAG,EAAE,YAAY,eAAe;GAChC,GAAG,EAAE,YAAY,eAAe;EAClC;EAEA,QAAQ;GACN,MAAM,EAAE,MAAM,8CAA8C;GAC5D,OAAO,CAAC;EACV;EAEA,QAAQ;GAAE,MAAM,CAAC;GAAG,OAAO,CAAC;EAAE;EAE9B,OAAO;GACL,QAAQ;IAAE,MAAM;IAAgB,MAAM;GAAe;GACrD,KAAK;IAAE,MAAM;IAAe,MAAM;GAAc;EAClD;CACF;CACA,kBAAkB,CAEhB;EAAE,SAAS;EAAa,QAAQ;EAAO,OAAO,EAAE,SAAS,sBAAsB;CAAE,GAOjF;EACE,SAAS;EACT,OAAO,EACL,MAAM;GACJ;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACF,EACF;CACF,CACF;CACA,iBAAiB;EAAE,SAAS;EAAY,aAAa;EAAO,OAAO;EAAG,UAAU;CAAO;AACzF,CAAC;;AAWD,MAAa,kBAAkB,GAAG;CAChC,OAAO;EAGL,OAAO;GACL;GACA;GACA;GACA;EACF;EACA,OAAO;GACL;GACA;GACA;EACF;EACA,UACE;CACJ;CACA,UAAU;EACR,MAAM;GACJ,OAAO,EAAE,OAAO,mCAAmC;GACnD,OAAO,EAAE,OAAO,uBAAuB;GAEvC,QAAQ,EACN,OACE,4FACJ;EACF;EACA,MAAM;GACJ,IAAI,CAAC;GACL,IAAI,CAAC;EACP;CACF;CACA,kBAAkB,CAChB;EAAE,MAAM;EAAS,MAAM;EAAM,OAAO,EAAE,OAAO,qBAAqB;CAAE,GACpE;EAAE,MAAM;EAAS,MAAM;EAAM,OAAO,EAAE,OAAO,qBAAqB;CAAE,CACtE;CACA,iBAAiB;EAAE,MAAM;EAAS,MAAM;CAAK;AAC/C,CAAC"}
@@ -2,6 +2,6 @@ import { ComponentTokenSet } from "../../tokens/component.js";
2
2
  import "../../index.js";
3
3
  //#region src/components/list/list-tokens.d.ts
4
4
  /** The tokens of {@link List}: `--md-comp-list-list-item-<part>`. */
5
- export declare const listTokenSet: ComponentTokenSet<"list-item-label-text-color" | "list-item-supporting-text-color" | "list-item-overline-color" | "list-item-leading-icon-color" | "list-item-trailing-icon-color" | "list-item-selected-container-color">;
5
+ export declare const listTokenSet: ComponentTokenSet<"list-item-label-text-color" | "list-item-supporting-text-color" | "list-item-overline-color" | "list-item-leading-icon-color" | "list-item-trailing-icon-color" | "list-item-selected-container-color" | "list-item-selected-label-text-color" | "list-item-selected-supporting-text-color" | "list-item-selected-overline-color" | "list-item-selected-leading-icon-color" | "list-item-selected-trailing-icon-color">;
6
6
  //#endregion
7
7
  //# sourceMappingURL=list-tokens.d.ts.map
@@ -57,6 +57,56 @@ const listTokenSet = defineComponentTokens({
57
57
  property: "background-color",
58
58
  state: "selected"
59
59
  }
60
+ },
61
+ "list-item-selected-label-text-color": {
62
+ value: color("on-secondary-container"),
63
+ description: "A selected item's headline.",
64
+ compose: "ListTokens.ItemSelectedLabelTextColor",
65
+ paints: {
66
+ property: "color",
67
+ slot: "headline",
68
+ state: "selected"
69
+ }
70
+ },
71
+ "list-item-selected-supporting-text-color": {
72
+ value: color("on-secondary-container"),
73
+ description: "A selected item's supporting text.",
74
+ compose: "ListTokens.ItemSelectedSupportingTextColor",
75
+ paints: {
76
+ property: "color",
77
+ slot: "supporting",
78
+ state: "selected"
79
+ }
80
+ },
81
+ "list-item-selected-overline-color": {
82
+ value: color("on-secondary-container"),
83
+ description: "A selected item's overline.",
84
+ compose: "ListTokens.ItemSelectedOverlineColor",
85
+ paints: {
86
+ property: "color",
87
+ slot: "overline",
88
+ state: "selected"
89
+ }
90
+ },
91
+ "list-item-selected-leading-icon-color": {
92
+ value: color("on-secondary-container"),
93
+ description: "A selected item's leading content.",
94
+ compose: "ListTokens.ItemSelectedLeadingIconColor",
95
+ paints: {
96
+ property: "color",
97
+ slot: "leading",
98
+ state: "selected"
99
+ }
100
+ },
101
+ "list-item-selected-trailing-icon-color": {
102
+ value: color("on-secondary-container"),
103
+ description: "A selected item's trailing content and its check.",
104
+ compose: "ListTokens.ItemSelectedTrailingIconColor",
105
+ paints: {
106
+ property: "color",
107
+ slot: "trailing",
108
+ state: "selected"
109
+ }
60
110
  }
61
111
  },
62
112
  scopes: { variant: {
@@ -1 +1 @@
1
- {"version":3,"file":"list-tokens.js","names":[],"sources":["../../../src/components/list/list-tokens.ts"],"sourcesContent":["import { color, defineComponentTokens } from '../../tokens/component';\n\n/*\n * The list's component tokens, M3's `md.comp.list.list-item.*` names (checked against\n * m3.material.io's token tables, 2026-10-14), with the defaults of `list-styles.ts`.\n *\n * The list's root and each item carry `data-tokens=\"md-comp-list\"` and `data-variant`, so an\n * item's own state (`data-selected`) picks its colours. A standard item is see-through by\n * default (it takes its container's colour: a sheet, a card); a segmented item is `surface`.\n * Selected content, hover, focus, press, disabled and the item shapes stay classes.\n */\n\n/** The tokens of {@link List}: `--md-comp-list-list-item-<part>`. */\nexport const listTokenSet = defineComponentTokens({\n name: 'md-comp-list',\n tokens: {\n 'list-item-label-text-color': {\n value: color('on-surface'),\n description: 'The headline.',\n compose: 'ListTokens.ItemLabelTextColor',\n paints: { property: 'color', slot: 'headline' },\n },\n 'list-item-supporting-text-color': {\n value: color('on-surface-variant'),\n description: 'The supporting text.',\n compose: 'ListTokens.ItemSupportingTextColor',\n paints: { property: 'color', slot: 'supporting' },\n },\n 'list-item-overline-color': {\n value: color('on-surface-variant'),\n description: 'The overline.',\n compose: 'ListTokens.ItemOverlineColor',\n paints: { property: 'color', slot: 'overline' },\n },\n 'list-item-leading-icon-color': {\n value: color('on-surface-variant'),\n description: 'The leading content: an icon, or text.',\n compose: 'ListTokens.ItemLeadingIconColor',\n paints: { property: 'color', slot: 'leading' },\n },\n 'list-item-trailing-icon-color': {\n value: color('on-surface-variant'),\n description: 'The trailing content: an icon, or supporting text.',\n compose: 'ListTokens.ItemTrailingIconColor',\n paints: { property: 'color', slot: 'trailing' },\n },\n 'list-item-selected-container-color': {\n value: color('secondary-container'),\n description: 'A selected item.',\n compose: 'ListTokens.ItemSelectedContainerColor',\n paints: { property: 'background-color', state: 'selected' },\n },\n },\n scopes: {\n variant: {\n standard: {\n prefix: 'md-comp-list-list-item',\n tokens: {\n 'container-color': {\n value: 'transparent',\n description: \"An item in a standard list: see-through, on its container's colour.\",\n compose: 'ListTokens.ItemContainerColor',\n paints: { property: 'background-color', slot: 'item' },\n },\n },\n },\n segmented: {\n prefix: 'md-comp-list-list-item-segmented',\n tokens: {\n 'container-color': {\n value: color('surface'),\n description: 'An item in a segmented list.',\n compose: 'ListTokens.ItemSegmentedContainerColor',\n paints: { property: 'background-color', slot: 'item' },\n },\n },\n },\n },\n },\n});\n"],"mappings":";;;AAaA,MAAa,eAAe,sBAAsB;CAChD,MAAM;CACN,QAAQ;EACN,8BAA8B;GAC5B,OAAO,MAAM,YAAY;GACzB,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAW;EAChD;EACA,mCAAmC;GACjC,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAa;EAClD;EACA,4BAA4B;GAC1B,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAW;EAChD;EACA,gCAAgC;GAC9B,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAU;EAC/C;EACA,iCAAiC;GAC/B,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAW;EAChD;EACA,sCAAsC;GACpC,OAAO,MAAM,qBAAqB;GAClC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAoB,OAAO;GAAW;EAC5D;CACF;CACA,QAAQ,EACN,SAAS;EACP,UAAU;GACR,QAAQ;GACR,QAAQ,EACN,mBAAmB;IACjB,OAAO;IACP,aAAa;IACb,SAAS;IACT,QAAQ;KAAE,UAAU;KAAoB,MAAM;IAAO;GACvD,EACF;EACF;EACA,WAAW;GACT,QAAQ;GACR,QAAQ,EACN,mBAAmB;IACjB,OAAO,MAAM,SAAS;IACtB,aAAa;IACb,SAAS;IACT,QAAQ;KAAE,UAAU;KAAoB,MAAM;IAAO;GACvD,EACF;EACF;CACF,EACF;AACF,CAAC"}
1
+ {"version":3,"file":"list-tokens.js","names":[],"sources":["../../../src/components/list/list-tokens.ts"],"sourcesContent":["import { color, defineComponentTokens } from '../../tokens/component';\n\n/*\n * The list's component tokens, M3's `md.comp.list.list-item.*` names (checked against\n * m3.material.io's token tables, 2026-10-14), with the defaults of `list-styles.ts`.\n *\n * The list's root and each item carry `data-tokens=\"md-comp-list\"` and `data-variant`, so an\n * item's own state (`data-selected`) picks its colours. A standard item is see-through by\n * default (it takes its container's colour: a sheet, a card); a segmented item is `surface`.\n * Hover, focus, press, disabled and the item shapes stay classes.\n */\n\n/** The tokens of {@link List}: `--md-comp-list-list-item-<part>`. */\nexport const listTokenSet = defineComponentTokens({\n name: 'md-comp-list',\n tokens: {\n 'list-item-label-text-color': {\n value: color('on-surface'),\n description: 'The headline.',\n compose: 'ListTokens.ItemLabelTextColor',\n paints: { property: 'color', slot: 'headline' },\n },\n 'list-item-supporting-text-color': {\n value: color('on-surface-variant'),\n description: 'The supporting text.',\n compose: 'ListTokens.ItemSupportingTextColor',\n paints: { property: 'color', slot: 'supporting' },\n },\n 'list-item-overline-color': {\n value: color('on-surface-variant'),\n description: 'The overline.',\n compose: 'ListTokens.ItemOverlineColor',\n paints: { property: 'color', slot: 'overline' },\n },\n 'list-item-leading-icon-color': {\n value: color('on-surface-variant'),\n description: 'The leading content: an icon, or text.',\n compose: 'ListTokens.ItemLeadingIconColor',\n paints: { property: 'color', slot: 'leading' },\n },\n 'list-item-trailing-icon-color': {\n value: color('on-surface-variant'),\n description: 'The trailing content: an icon, or supporting text.',\n compose: 'ListTokens.ItemTrailingIconColor',\n paints: { property: 'color', slot: 'trailing' },\n },\n 'list-item-selected-container-color': {\n value: color('secondary-container'),\n description: 'A selected item.',\n compose: 'ListTokens.ItemSelectedContainerColor',\n paints: { property: 'background-color', state: 'selected' },\n },\n 'list-item-selected-label-text-color': {\n value: color('on-secondary-container'),\n description: \"A selected item's headline.\",\n compose: 'ListTokens.ItemSelectedLabelTextColor',\n paints: { property: 'color', slot: 'headline', state: 'selected' },\n },\n 'list-item-selected-supporting-text-color': {\n value: color('on-secondary-container'),\n description: \"A selected item's supporting text.\",\n compose: 'ListTokens.ItemSelectedSupportingTextColor',\n paints: { property: 'color', slot: 'supporting', state: 'selected' },\n },\n 'list-item-selected-overline-color': {\n value: color('on-secondary-container'),\n description: \"A selected item's overline.\",\n compose: 'ListTokens.ItemSelectedOverlineColor',\n paints: { property: 'color', slot: 'overline', state: 'selected' },\n },\n 'list-item-selected-leading-icon-color': {\n value: color('on-secondary-container'),\n description: \"A selected item's leading content.\",\n compose: 'ListTokens.ItemSelectedLeadingIconColor',\n paints: { property: 'color', slot: 'leading', state: 'selected' },\n },\n 'list-item-selected-trailing-icon-color': {\n value: color('on-secondary-container'),\n description: \"A selected item's trailing content and its check.\",\n compose: 'ListTokens.ItemSelectedTrailingIconColor',\n paints: { property: 'color', slot: 'trailing', state: 'selected' },\n },\n },\n scopes: {\n variant: {\n standard: {\n prefix: 'md-comp-list-list-item',\n tokens: {\n 'container-color': {\n value: 'transparent',\n description: \"An item in a standard list: see-through, on its container's colour.\",\n compose: 'ListTokens.ItemContainerColor',\n paints: { property: 'background-color', slot: 'item' },\n },\n },\n },\n segmented: {\n prefix: 'md-comp-list-list-item-segmented',\n tokens: {\n 'container-color': {\n value: color('surface'),\n description: 'An item in a segmented list.',\n compose: 'ListTokens.ItemSegmentedContainerColor',\n paints: { property: 'background-color', slot: 'item' },\n },\n },\n },\n },\n },\n});\n"],"mappings":";;;AAaA,MAAa,eAAe,sBAAsB;CAChD,MAAM;CACN,QAAQ;EACN,8BAA8B;GAC5B,OAAO,MAAM,YAAY;GACzB,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAW;EAChD;EACA,mCAAmC;GACjC,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAa;EAClD;EACA,4BAA4B;GAC1B,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAW;EAChD;EACA,gCAAgC;GAC9B,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAU;EAC/C;EACA,iCAAiC;GAC/B,OAAO,MAAM,oBAAoB;GACjC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;GAAW;EAChD;EACA,sCAAsC;GACpC,OAAO,MAAM,qBAAqB;GAClC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAoB,OAAO;GAAW;EAC5D;EACA,uCAAuC;GACrC,OAAO,MAAM,wBAAwB;GACrC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;IAAY,OAAO;GAAW;EACnE;EACA,4CAA4C;GAC1C,OAAO,MAAM,wBAAwB;GACrC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;IAAc,OAAO;GAAW;EACrE;EACA,qCAAqC;GACnC,OAAO,MAAM,wBAAwB;GACrC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;IAAY,OAAO;GAAW;EACnE;EACA,yCAAyC;GACvC,OAAO,MAAM,wBAAwB;GACrC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;IAAW,OAAO;GAAW;EAClE;EACA,0CAA0C;GACxC,OAAO,MAAM,wBAAwB;GACrC,aAAa;GACb,SAAS;GACT,QAAQ;IAAE,UAAU;IAAS,MAAM;IAAY,OAAO;GAAW;EACnE;CACF;CACA,QAAQ,EACN,SAAS;EACP,UAAU;GACR,QAAQ;GACR,QAAQ,EACN,mBAAmB;IACjB,OAAO;IACP,aAAa;IACb,SAAS;IACT,QAAQ;KAAE,UAAU;KAAoB,MAAM;IAAO;GACvD,EACF;EACF;EACA,WAAW;GACT,QAAQ;GACR,QAAQ,EACN,mBAAmB;IACjB,OAAO,MAAM,SAAS;IACtB,aAAa;IACb,SAAS;IACT,QAAQ;KAAE,UAAU;KAAoB,MAAM;IAAO;GACvD,EACF;EACF;CACF,EACF;AACF,CAAC"}
@@ -26,6 +26,19 @@ export interface MenuItemProps {
26
26
  shortcut?: string;
27
27
  /** Icon at the end (an item with a submenu shows an arrow by default). */
28
28
  trailingIcon?: ReactNode;
29
+ /**
30
+ * Makes the item a link: a real `<a>` with the item's look, role and keys, so the browser's
31
+ * link menu (open in a new tab, copy or save the link) and modified clicks work. A press,
32
+ * Enter or Space follows it, through a `RouterProvider` (such as `NextRouterProvider`) on a
33
+ * plain click, and closes the menu. A disabled item, or one that opens a submenu, isn't a link.
34
+ */
35
+ href?: string;
36
+ /** A link item's target; `_blank` adds `rel="noopener noreferrer"` unless `rel` is given. */
37
+ target?: string;
38
+ /** A link item's `rel`, e.g. `"nofollow"`. */
39
+ rel?: string;
40
+ /** Downloads the link item's file instead of opening it (optionally with a file name). */
41
+ download?: boolean | string;
29
42
  /** Accessible name when the label isn't plain text. */
30
43
  'aria-label'?: string;
31
44
  /** Classes for the item, merged after `classNames.item`; consumer classes win. */
@@ -28,6 +28,15 @@ const CheckIcon = () => /* @__PURE__ */ jsx("svg", {
28
28
  fill: "currentColor",
29
29
  children: /* @__PURE__ */ jsx("path", { d: "M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z" })
30
30
  });
31
+ /** Clears the link attributes `useMenuItem` copies from an item's props onto one that isn't a link. */
32
+ const NOT_A_LINK = {
33
+ href: void 0,
34
+ target: void 0,
35
+ rel: void 0,
36
+ download: void 0,
37
+ ping: void 0,
38
+ referrerPolicy: void 0
39
+ };
31
40
  /** The default submenu arrow (Material Symbols `arrow_right`), mirrored in RTL. */
32
41
  const SubmenuIcon = () => /* @__PURE__ */ jsx("svg", {
33
42
  viewBox: "0 -960 960 960",
@@ -633,6 +642,9 @@ function MenuItemView({ node, state, variant, top, bottom, classNames, triggerPr
633
642
  role: "menuitem",
634
643
  "aria-checked": void 0
635
644
  } : ariaItemProps;
645
+ const link = props.href != null && !isDisabled && !props.submenu;
646
+ const Root = link ? "a" : "div";
647
+ const linkAttributes = link ? { rel: props.rel ?? (props.target === "_blank" ? "noopener noreferrer" : void 0) } : NOT_A_LINK;
636
648
  const { interactionProps, dataAttributes } = useM3Interaction({
637
649
  isPressed,
638
650
  isDisabled,
@@ -648,8 +660,9 @@ function MenuItemView({ node, state, variant, top, bottom, classNames, triggerPr
648
660
  const trailingIcon = props.trailingIcon ?? (props.submenu ? /* @__PURE__ */ jsx(SubmenuIcon, {}) : null);
649
661
  const badgeId = useId();
650
662
  const describedBy = [props.shortcut ? keyboardShortcutProps.id : void 0, props.badge ? badgeId : void 0].filter(Boolean).join(" ") || void 0;
651
- return /* @__PURE__ */ jsxs("div", {
663
+ return /* @__PURE__ */ jsxs(Root, {
652
664
  ...mergeProps(menuItemProps, interactionProps),
665
+ ...linkAttributes,
653
666
  ...dataAttributes,
654
667
  "aria-labelledby": void 0,
655
668
  "aria-describedby": describedBy,
@@ -1 +1 @@
1
- {"version":3,"file":"Menu.js","names":["Overlay"],"sources":["../../../src/components/menu/Menu.tsx"],"sourcesContent":["'use client';\n\nimport {\n cloneElement,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type FocusEvent,\n type JSX,\n type Key,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefObject,\n} from 'react';\nimport {\n DismissButton,\n I18nProvider,\n mergeProps,\n useLocale,\n useMenu,\n useMenuItem,\n useMenuSection,\n useObjectRef,\n usePopover,\n useButton,\n useSubmenuTrigger,\n type AriaMenuItemProps,\n type AriaMenuOptions,\n type AriaMenuProps,\n type AriaPopoverProps,\n type Placement,\n} from 'react-aria';\nimport {\n Item,\n Section,\n useSubmenuTriggerState,\n useTreeState,\n type Node,\n type RootMenuTriggerState,\n type SubmenuTriggerState,\n type TreeState,\n} from 'react-stately';\nimport { localeWithDirection } from '../../primitives/locale-with-direction';\nimport { Overlay } from '../../primitives/Overlay';\nimport { TriggerContext } from '../../primitives/TriggerContext';\nimport { useM3Interaction } from '../../primitives/use-m3-interaction';\nimport { usePresence } from '../../primitives/use-presence';\nimport { densityAttribute, type Density } from '../../tokens/density';\nimport { toAriaPlacement } from '../../utils/placement';\nimport { assertCollectionChildren } from '../../utils/assert-collection-children';\nimport { cn } from '../../utils/cn';\nimport { useTypeaheadDelegate } from '../../utils/typeahead';\nimport { COMPACT_WINDOW, useMediaQuery } from '../date-picker/use-media-query';\nimport { Divider } from '../divider/Divider';\nimport { LazyBottomSheet, usePreloadBottomSheet } from '../sheet/lazy-bottom-sheet';\nimport { BackIcon } from '../sheet/sheet-icons';\nimport { useRevealEntering } from './use-reveal-entering';\nimport { menuOwnWidth, menuStyles, type MenuLayout, type MenuVariant } from './menu-styles';\nimport { MenuTriggerContext, type MenuTriggerContextValue } from './menu-trigger';\n\nexport {\n ContextMenuTrigger,\n MenuTrigger,\n type ContextMenuTriggerProps,\n type MenuTriggerProps,\n} from './menu-trigger';\nimport { mergeDataTokens } from '../../utils/merge-data-tokens';\nimport { splitRootProps, type RootDOMProps } from '../../utils/root-props';\n\nconst CheckIcon = () => (\n <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\">\n <path d=\"M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z\" />\n </svg>\n);\n\n/** The default submenu arrow (Material Symbols `arrow_right`), mirrored in RTL. */\nconst SubmenuIcon = () => (\n <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\" className=\"rtl:-scale-x-100\">\n <path d=\"M400-280v-400l200 200-200 200Z\" />\n </svg>\n);\n\n/** Props of a {@link MenuItem}; the React `key` identifies it for `onAction` and selection. */\nexport interface MenuItemProps {\n /** The label. */\n children: ReactNode;\n /** Plain-text label for typeahead when `children` is not a string. */\n textValue?: string;\n /** Icon before the label. */\n leadingIcon?: ReactNode;\n /** Icon shown while selected (defaults to a check in selectable menus). */\n selectedIcon?: ReactNode;\n /** Second line of text (supporting text), read as part of the item's name after the label. */\n description?: ReactNode;\n /**\n * A badge before the trailing text or icon (M3 anatomy), such as a `Badge` with a count.\n * It's read after the name, as the item's description.\n */\n badge?: ReactNode;\n /** Keyboard shortcut shown at the end, e.g. \"⌘C\", read as the item's description. */\n shortcut?: string;\n /** Icon at the end (an item with a submenu shows an arrow by default). */\n trailingIcon?: ReactNode;\n /** Accessible name when the label isn't plain text. */\n 'aria-label'?: string;\n /** Classes for the item, merged after `classNames.item`; consumer classes win. */\n className?: string;\n}\n\n/** An item in a `Menu` (a React Stately collection item: identify it with `key`). */\nexport const MenuItem = Item as unknown as (props: MenuItemProps) => JSX.Element;\n\nexport interface MenuGroupProps {\n /** Group label shown above its items. */\n title?: ReactNode;\n /** Accessible name for the group when it has no `title`. */\n 'aria-label'?: string;\n /** `MenuItem`s and `SubmenuTrigger`s. */\n children: ReactElement | ReactElement[];\n}\n\n/**\n * A group of items (a React Stately collection section): set off by dividers in the\n * `divider` layout, its own surface in the `gap` layout.\n */\nexport const MenuGroup = Section as unknown as (props: MenuGroupProps) => JSX.Element;\n\nexport interface SubmenuTriggerProps {\n /** The `MenuItem` that opens the submenu, then the submenu's `Menu`. */\n children: [ReactElement<MenuItemProps>, ReactElement<MenuProps>];\n /** How long (ms) the pointer rests on the item before the submenu opens. @default 200 */\n delay?: number;\n}\n\n/** What a `SubmenuTrigger` adds to its item's collection node. */\ninterface SubmenuItemProps extends MenuItemProps {\n submenu?: ReactElement<MenuProps>;\n submenuDelay?: number;\n /** See {@link CheckableMenuItemProps}. */\n checkable?: boolean;\n}\n\n/**\n * Props of a {@link CheckableMenuItem}, for the library's own menus (not exported from the\n * package): in a selectable menu, `checkable={false}` makes an item a plain action, with the\n * `menuitem` role, no checked state and no check, that closes the menu like any action.\n */\nexport interface CheckableMenuItemProps extends MenuItemProps {\n /** Whether the item can be checked in a selectable menu. @default true */\n checkable?: boolean;\n}\n\n/** A {@link MenuItem} that can opt out of the menu's selection (library-internal). */\nexport const CheckableMenuItem = Item as unknown as (props: CheckableMenuItemProps) => JSX.Element;\n\n/** Only a menu collection reads a `SubmenuTrigger`; rendered on its own it's nothing. */\nfunction SubmenuTriggerElement(): null {\n return null;\n}\n\n/** React Stately builds the item's node from this, with the submenu on its props. */\nSubmenuTriggerElement.getCollectionNode = function* getCollectionNode({\n children: [item, submenu],\n delay,\n}: SubmenuTriggerProps) {\n // `cloneElement` keeps the item's own `key`.\n yield { element: cloneElement(item, { submenu, submenuDelay: delay } as SubmenuItemProps) };\n};\n\n/**\n * Gives a menu item a submenu (M3: \"On web, menus can open submenus\"). It opens beside the\n * item, without covering it, on hover, press, Enter, Space or the arrow key pointing away\n * from the menu (Left in right-to-left), and closes with the opposite arrow or Escape.\n * While it's open, the item shows its active (pressed) layer, and the menu holding focus\n * takes rounder corners than the other one.\n *\n * @example\n * <SubmenuTrigger>\n * <MenuItem key=\"share\">Share</MenuItem>\n * <Menu onAction={(key) => share(key)}>\n * <MenuItem key=\"email\">Email</MenuItem>\n * <MenuItem key=\"link\">Copy link</MenuItem>\n * </Menu>\n * </SubmenuTrigger>\n */\nexport const SubmenuTrigger = SubmenuTriggerElement as unknown as (\n props: SubmenuTriggerProps,\n) => JSX.Element;\n\nexport interface MenuClassNames {\n /**\n * The menu's surface (the `menu` element): its colour, corners, size and the list that\n * scrolls. In a sheet it spans the sheet, without a surface of its own.\n */\n panel?: string;\n /**\n * The bottom sheet the menu opens in (`presentation=\"sheet\"`, or `\"auto\"` on compact\n * windows): the sheet's surface, as its `classNames.panel`.\n */\n sheet?: string;\n /** Each group of items (its own surface in the `gap` layout). */\n group?: string;\n /** Each `MenuGroup`'s heading. */\n heading?: string;\n /** Each item. */\n item?: string;\n /** Each item's leading icon, or the icon marking a selected item. */\n icon?: string;\n /** Each item's `description` line. */\n description?: string;\n /** Each item's keyboard `shortcut`. */\n shortcut?: string;\n /** Each item's trailing icon, including a submenu's arrow. */\n trailingIcon?: string;\n /** The dividers between groups in the `divider` layout. */\n divider?: string;\n}\n\nexport interface MenuProps\n extends\n Omit<\n AriaMenuProps<object>,\n | 'children'\n | 'items'\n | 'onClose'\n | 'autoFocus'\n | 'disallowEmptySelection'\n // The arrow keys always wrap and Escape always closes the menu, as M3's menus do.\n | 'shouldFocusWrap'\n | 'escapeKeyBehavior'\n >,\n Omit<RootDOMProps, keyof AriaMenuProps<object>> {\n /**\n * With `selectionMode`: the last selected item can be deselected, leaving none. `false` keeps\n * at least one item selected. @default true\n */\n deselectable?: boolean;\n /**\n * The keys of items that can't be chosen. They stay focusable, as M3 asks (\"Disabled menu\n * items can receive focus but aren't selectable\").\n */\n disabledKeys?: AriaMenuProps<object>['disabledKeys'];\n /** `MenuItem`s, `MenuGroup`s and `SubmenuTrigger`s. */\n children: ReactNode;\n /** `standard` (surface colours) or `vibrant` (tertiary container). @default \"standard\" */\n variant?: MenuVariant;\n /**\n * How groups are set apart. `divider`: one surface with dividers between groups, which M3\n * recommends on the web and for menus that scroll. `gap`: each group is its own surface,\n * 2px apart; a `gap` menu that has to scroll switches to dividers, since M3 doesn't use\n * gaps in scrolling menus. A submenu takes its parent's layout and variant unless it\n * sets its own.\n * @default \"divider\"\n */\n layout?: MenuLayout;\n /**\n * Web density (M3: \"On web only … Increasing density decreases the top and bottom\n * padding\"): each step down takes 4px off the items' height (44px at 0, 32px at -3) and 2px\n * off the space around dividers. Left out, the menu takes the density of the nearest\n * `ThemeProvider` or `ThemeScope`; a submenu takes its parent menu's. Keep 0 for touch.\n * @default 0\n */\n density?: Density;\n /**\n * Placement relative to the trigger: a side, then optionally the edge to align with\n * (`start` / `end` follow the text direction). A submenu always opens beside its item.\n * @default \"bottom-start\"\n */\n placement?: MenuPlacement;\n /** Gap between the trigger and the menu, in px (a split button's menu sits 4px away). @default 0 */\n offset?: number;\n /**\n * The least space kept between the menu and the window's edges, in px. A split button\n * passes 0, so its menu lines up with the trailing button even at the edge of the screen.\n * @default 12\n */\n containerPadding?: number;\n /**\n * Where the menu opens. `popover`: anchored to its trigger. `sheet`: in a modal bottom\n * sheet. `auto`: a sheet on compact windows (below 600px wide) and a popover on larger\n * ones (M3: \"Consider adapting menus into bottom sheets on small screens\"). Set it on the\n * root menu.\n * @default \"popover\"\n */\n presentation?: MenuPresentation;\n /** Words the menu shows in a sheet. Set them on the root menu. */\n labels?: Partial<MenuLabels>;\n /**\n * Open and close with no motion (M3: \"In dense products, such as on desktop, menus can\n * open instantly to reduce motion\"). Submenus follow their root menu. Popovers only: a menu\n * shown as a bottom sheet (`presentation=\"sheet\"`, or `auto` on a compact window) keeps the\n * sheet's slide, as M3's and Compose's modal bottom sheets always animate; under reduced\n * motion it fades instead.\n * @default false\n */\n instant?: boolean;\n /**\n * Goes with `style` on the menu's outermost element: the box React Aria places against the\n * trigger, or the bottom sheet's outermost element in a sheet. The surface inside keeps\n * its size and its place against the trigger whatever layout class lands here (the box\n * keeps the menu's own width); style it with `classNames.panel`.\n */\n className?: string;\n /** Classes for each part, by slot. */\n classNames?: MenuClassNames;\n /** Goes on the menu's outermost element, with `className`. */\n style?: CSSProperties;\n /** Ref to the menu's list, the `role=\"menu\"` element, in a popover or a sheet. */\n ref?: Ref<HTMLDivElement>;\n}\n\n/** Where a {@link Menu} sits against its trigger: a side, then optionally the edge it aligns with. */\nexport type MenuPlacement =\n | 'top'\n | 'bottom'\n | 'start'\n | 'end'\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end'\n | 'start-top'\n | 'start-bottom'\n | 'end-top'\n | 'end-bottom';\n\n/** Where a {@link Menu} opens. */\nexport type MenuPresentation = 'popover' | 'sheet' | 'auto';\n\n/** Words a {@link Menu} shows. */\nexport interface MenuLabels {\n /**\n * In a sheet, the button above a submenu that goes back to the menu that opened it.\n * @default \"Back\"\n */\n back: string;\n}\n\nconst DEFAULT_LABELS: MenuLabels = { back: 'Back' };\n\n/**\n * M3 Expressive menu: items on one surface with dividers between groups (or on grouped\n * surfaces), standard or vibrant colours, optional single or multiple selection with a\n * selected shape and check, submenus, keyboard navigation and typeahead (React Aria\n * `useMenu`). Must be inside a `MenuTrigger` or `ContextMenuTrigger`; it opens anchored to\n * the trigger in a portal that keeps the surrounding theme and direction.\n *\n * @example\n * <MenuTrigger>\n * <IconButton icon={<MoreIcon />} aria-label=\"More\" />\n * <Menu onAction={(key) => run(key)}>\n * <MenuGroup>\n * <MenuItem key=\"copy\" shortcut=\"⌘C\">Copy</MenuItem>\n * <MenuItem key=\"paste\" shortcut=\"⌘V\">Paste</MenuItem>\n * </MenuGroup>\n * <MenuGroup>\n * <MenuItem key=\"delete\">Delete</MenuItem>\n * </MenuGroup>\n * </Menu>\n * </MenuTrigger>\n */\nexport function Menu({ presentation = 'popover', instant = false, ...props }: MenuProps) {\n const trigger = useContext(MenuTriggerContext);\n if (!trigger) throw new Error('[@windmorph/react] <Menu> must be used inside <MenuTrigger>.');\n const compact = useMediaQuery(COMPACT_WINDOW);\n const presence = usePresence(trigger.state.isOpen);\n const asSheet = presentation === 'sheet' || (presentation === 'auto' && compact);\n usePreloadBottomSheet(trigger.triggerRef, asSheet);\n if (asSheet) return <MenuSheet {...props} trigger={trigger} />;\n // An instant menu leaves at once, without waiting for an exit transition.\n const isPresent = instant ? trigger.state.isOpen : presence.isPresent;\n const isExiting = !instant && presence.isExiting;\n if (!isPresent) return null;\n return (\n <Overlay exiting={isExiting}>\n <MenuPopover\n {...props}\n trigger={trigger}\n instant={instant}\n isExiting={isExiting}\n exitProps={presence.exitProps}\n />\n </Overlay>\n );\n}\n\n/**\n * The menu in a modal bottom sheet (M3: menus can adapt into bottom sheets on small\n * screens). The sheet is a dialog named like the menu; the menu inside keeps its role,\n * keyboard, typeahead and initial focus, and spans the sheet without a surface of its own.\n * The sheet's code loads on first open (or when the trigger is hovered or focused), so a\n * menu that only opens as a popover doesn't carry it.\n */\nfunction MenuSheet({\n trigger,\n layout: _layout,\n placement: _placement,\n offset: _offset,\n variant = 'standard',\n labels,\n className,\n style,\n ...props\n}: Omit<MenuProps, 'presentation' | 'instant'> & { trigger: MenuTriggerContextValue }) {\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const [activeLevel, setActiveLevel] = useState(0);\n const menuProps = mergeProps(trigger.menuProps, props);\n const label = menuProps['aria-label'];\n const naming =\n label != null\n ? { 'aria-label': label }\n : { 'aria-labelledby': menuProps['aria-labelledby'] ?? '' };\n return (\n <LazyBottomSheet\n {...naming}\n // A menu sheet opens at its own height (up to the window, the list scrolling inside):\n // at half the window, a short phone left its last items off-screen, where the arrow\n // keys could still move focus.\n skipPartiallyExpanded\n open={trigger.state.isOpen}\n onOpenChange={(open) => (open ? trigger.state.open() : trigger.state.close())}\n className={className}\n style={style}\n classNames={props.classNames?.sheet ? { panel: props.classNames.sheet } : undefined}\n >\n <div ref={setContainer} className={menuStyles().sheetContent()}>\n <TriggerContext value={null}>\n <MenuTreeContext\n value={{\n rootState: trigger.state,\n container,\n activeLevel,\n setActiveLevel,\n layout: 'divider',\n variant,\n density: props.density,\n instant: false,\n sheet: true,\n labels: { ...DEFAULT_LABELS, ...labels },\n }}\n >\n <MenuList\n {...menuProps}\n layout=\"divider\"\n variant={variant}\n level={0}\n embedded\n onClose={trigger.state.close}\n autoFocus={trigger.state.focusStrategy ?? 'first'}\n />\n </MenuTreeContext>\n </TriggerContext>\n </div>\n </LazyBottomSheet>\n );\n}\n\n/** Shared by a menu and its submenus. */\ninterface MenuTreeContextValue {\n rootState: RootMenuTriggerState;\n /** The root popover, which submenus portal into (inside its focus scope, never inert). */\n container: HTMLElement | null;\n /** The level of the menu holding focus (0 is the root menu). */\n activeLevel: number;\n setActiveLevel: (level: number) => void;\n /** What submenus inherit. */\n layout: MenuLayout;\n variant: MenuVariant;\n density: MenuProps['density'];\n /** Submenus open and close with no motion too. */\n instant: boolean;\n /**\n * In a sheet, a submenu takes the sheet's place of the menu that opened it, below a back\n * button, instead of opening beside its item.\n */\n sheet: boolean;\n labels: MenuLabels;\n}\n\nconst MenuTreeContext = createContext<MenuTreeContextValue | null>(null);\n\n/** The menu element an item is rendered in (a submenu's parent). */\nconst MenuListContext = createContext<RefObject<HTMLDivElement | null> | null>(null);\n\nconst subscribeToNothing = () => () => {};\n\n/**\n * React Aria resolves `start` / `end` from its locale context, not the DOM `dir`, so an\n * RTL region without an `I18nProvider` would align the menu to the wrong edge. Resolve\n * them to physical sides from the trigger's computed direction instead.\n */\nfunction toPhysicalPlacement(placement: MenuPlacement, direction: string): Placement {\n return toAriaPlacement(placement, direction === 'rtl');\n}\n\ntype ExitProps = ReturnType<typeof usePresence>['exitProps'];\n\nfunction MenuPopover({\n trigger,\n instant,\n isExiting,\n exitProps,\n placement = 'bottom-start',\n offset = 0,\n containerPadding = 12,\n layout = 'divider',\n variant = 'standard',\n labels,\n className,\n style,\n ...props\n}: Omit<MenuProps, 'presentation' | 'instant'> & {\n trigger: MenuTriggerContextValue;\n instant: boolean;\n isExiting: boolean;\n exitProps: ExitProps;\n}) {\n const popoverRef = useRef<HTMLDivElement>(null);\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const setPopover = useCallback((element: HTMLDivElement | null) => {\n popoverRef.current = element;\n setContainer(element);\n }, []);\n const [activeLevel, setActiveLevel] = useState(0);\n // The DOM is the source of truth for direction; read it like an external store.\n const direction = useSyncExternalStore(\n subscribeToNothing,\n () =>\n trigger.triggerRef.current ? getComputedStyle(trigger.triggerRef.current).direction : 'ltr',\n () => 'ltr',\n );\n // Submenus' arrow keys and placement follow the locale's direction: give it the DOM's.\n const { locale, direction: localeDirection } = useLocale();\n const menuLocale =\n direction === localeDirection\n ? locale\n : localeWithDirection(locale, direction === 'rtl' ? 'rtl' : 'ltr');\n const {\n popoverProps,\n underlayProps,\n placement: actualPlacement,\n } = usePopover(\n {\n triggerRef: trigger.triggerRef,\n popoverRef,\n placement: toPhysicalPlacement(placement, direction),\n offset,\n containerPadding,\n },\n trigger.state,\n );\n const revealRef = useRef<HTMLDivElement>(null);\n const entering = useRevealEntering(actualPlacement, revealRef);\n const close = trigger.state.close;\n // Tab moves on from an open menu and closes it and its submenus (the APG menu button\n // pattern). React Aria's focus scope moves focus past the trigger, or back to it when\n // nothing follows; without the close, the menu stayed open with focus outside it. That\n // scope handles Tab on the document's capture phase and stops it, so this listens on the\n // window's, which comes first.\n useEffect(() => {\n const view = container?.ownerDocument.defaultView;\n if (!container || !view) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Tab' || event.altKey || event.ctrlKey || event.metaKey) return;\n if (container.contains(container.ownerDocument.activeElement)) close();\n };\n view.addEventListener('keydown', onKeyDown, true);\n return () => view.removeEventListener('keydown', onKeyDown, true);\n }, [container, close]);\n const styles = menuStyles();\n return (\n <>\n <div {...underlayProps} className=\"fixed inset-0\" />\n <div\n {...popoverProps}\n ref={setPopover}\n // React Aria's placement wins over a consumer style's and, through the attribute\n // (styles/utilities.css), over consumer inset classes.\n style={{ ...style, ...popoverProps.style }}\n data-overlay-placement=\"\"\n className={styles.popover({ class: cn(menuOwnWidth, className) })}\n >\n <DismissButton onDismiss={trigger.state.close} />\n <div\n {...exitProps}\n ref={revealRef}\n data-entering={entering || undefined}\n data-exiting={isExiting || undefined}\n data-placement={actualPlacement ?? undefined}\n className={menuStyles({ instant }).reveal()}\n >\n <TriggerContext value={null}>\n <I18nProvider locale={menuLocale}>\n <MenuTreeContext\n value={{\n rootState: trigger.state,\n container,\n activeLevel,\n setActiveLevel,\n layout,\n variant,\n density: props.density,\n instant,\n sheet: false,\n labels: { ...DEFAULT_LABELS, ...labels },\n }}\n >\n <MenuList\n {...mergeProps(trigger.menuProps, props)}\n layout={layout}\n variant={variant}\n level={0}\n onClose={trigger.state.close}\n autoFocus={trigger.state.focusStrategy ?? 'first'}\n />\n </MenuTreeContext>\n </I18nProvider>\n </TriggerContext>\n </div>\n <DismissButton onDismiss={trigger.state.close} />\n </div>\n </>\n );\n}\n\ntype Position = 'only' | 'first' | 'middle' | 'last';\ntype Edges = { top: boolean; bottom: boolean };\n\nconst positionOf = (index: number, count: number): Position =>\n count === 1 ? 'only' : index === 0 ? 'first' : index === count - 1 ? 'last' : 'middle';\n\n/** Which of a group's edges have the outer corners (the others have 8px). */\nconst roundEdges = (position: Position): Edges => ({\n top: position === 'only' || position === 'first',\n bottom: position === 'only' || position === 'last',\n});\n\n/** Sections become groups; runs of loose items between them form implicit groups. */\nfunction toGroups(nodes: Node<object>[]): (Node<object> | Node<object>[])[] {\n const groups: (Node<object> | Node<object>[])[] = [];\n let run: Node<object>[] = [];\n for (const node of nodes) {\n if (node.type === 'section') {\n if (run.length) groups.push(run);\n run = [];\n groups.push(node);\n } else {\n run.push(node);\n }\n }\n if (run.length) groups.push(run);\n return groups;\n}\n\ntype MenuListProps = Omit<\n MenuProps,\n 'placement' | 'layout' | 'variant' | 'presentation' | 'instant' | 'className' | 'style'\n> &\n Pick<AriaMenuOptions<object>, 'onClose' | 'autoFocus' | 'onKeyDown' | 'onKeyUp'> & {\n layout: MenuLayout;\n variant: MenuVariant;\n /** 0 for the root menu, then one more per submenu. */\n level: number;\n listRef?: RefObject<HTMLDivElement | null>;\n /** In a sheet: the list spans it, with no surface of its own. */\n embedded?: boolean;\n };\n\n/**\n * Whether the list has had to scroll, from a `ResizeObserver` (so it's measured only when\n * its size changes). Once true it stays true while the menu is open, so a `gap` menu that\n * switches to dividers can't flip back and forth.\n */\nfunction useHasScrolled(ref: RefObject<HTMLElement | null>, enabled: boolean) {\n const [scrolls, setScrolls] = useState(false);\n useLayoutEffect(() => {\n const element = ref.current;\n if (!enabled || scrolls || !element || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => {\n if (element.scrollHeight > element.clientHeight + 1) setScrolls(true);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, enabled, scrolls]);\n return scrolls;\n}\n\nfunction MenuList({\n deselectable = true,\n variant,\n layout: requestedLayout,\n density,\n level,\n classNames,\n listRef,\n embedded = false,\n ref: forwardedRef,\n ...allProps\n}: MenuListProps) {\n // The menu list is the menu's root (its `ref` and `id` land there): its DOM attributes too.\n const { root, rest: props } = splitRootProps(allProps);\n // MenuItem / MenuGroup are React Stately Item / Section, so children are a collection.\n assertCollectionChildren(\n props.children,\n 'Menu',\n 'MenuItem, MenuGroup and SubmenuTrigger elements',\n );\n const tree = useContext(MenuTreeContext);\n // M3: \"Disabled menu items can receive focus but aren't selectable.\"\n const state = useTreeState({\n ...(props as AriaMenuProps<object>),\n disallowEmptySelection: !deselectable,\n disabledBehavior: 'selection',\n });\n const ownRef = useObjectRef(forwardedRef);\n const ref = listRef ?? ownRef;\n // M3 keyboard table: \"Letters — Focus moves to the next menu item starting with letter\".\n const keyboardDelegate = useTypeaheadDelegate(state, ref);\n const { menuProps } = useMenu(\n // The arrow keys wrap from the last item to the first and back, as M3's menus and the rest\n // of the library's collections do (APG makes it optional).\n { ...(props as AriaMenuOptions<object>), keyboardDelegate, shouldFocusWrap: true },\n state,\n ref,\n );\n const groups = toGroups([...state.collection]);\n const scrolled = useHasScrolled(ref, requestedLayout === 'gap');\n const layout: MenuLayout = scrolled ? 'divider' : requestedLayout;\n const styles = menuStyles({ variant, layout, embedded });\n // While a submenu is open, the menu holding focus is rounder than the others (M3).\n const submenuOpen = Boolean(tree && tree.rootState.expandedKeysStack.length > 0);\n const shape = !submenuOpen ? undefined : tree?.activeLevel === level ? 'active' : 'inactive';\n const setActive = tree?.setActiveLevel;\n\n return (\n <div\n {...mergeProps(root, menuProps, {\n // Focus events bubble through portals: count only focus inside this menu's element.\n onFocus: (event: FocusEvent<HTMLDivElement>) => {\n if (event.currentTarget.contains(event.target)) setActive?.(level);\n },\n })}\n ref={ref}\n {...densityAttribute(density)}\n data-tokens={mergeDataTokens('md-comp-menus', root)}\n data-variant={variant}\n data-layout={layout}\n data-shape={shape}\n className={styles.menu({ class: classNames?.panel })}\n >\n <MenuListContext value={ref}>\n {groups.map((group, index) => {\n const position = positionOf(index, groups.length);\n // In the divider layout the menu is the surface: its first and last items nest in\n // its corners, and dividers go between groups.\n const edges: Edges =\n layout === 'divider'\n ? { top: index === 0, bottom: index === groups.length - 1 }\n : roundEdges(position);\n const groupStyles = menuStyles({ variant, layout, groupPosition: position, morph: true });\n return (\n <GroupWithDivider\n key={Array.isArray(group) ? group[0]!.key : group.key}\n divider={\n layout === 'divider' && index > 0 ? (\n // A menu's divider is a `separator` between its groups (WAI-ARIA menu).\n <Divider\n decorative={false}\n className={styles.divider({ class: classNames?.divider })}\n />\n ) : null\n }\n >\n {Array.isArray(group) ? (\n <div\n role=\"presentation\"\n className={groupStyles.group({ class: classNames?.group })}\n >\n <MenuItems\n nodes={group}\n state={state}\n variant={variant}\n edges={edges}\n classNames={classNames}\n />\n </div>\n ) : (\n <MenuSection\n section={group}\n state={state}\n variant={variant}\n className={groupStyles.group({ class: classNames?.group })}\n headingClassName={groupStyles.heading({ class: classNames?.heading })}\n edges={edges}\n classNames={classNames}\n />\n )}\n </GroupWithDivider>\n );\n })}\n </MenuListContext>\n </div>\n );\n}\n\nfunction GroupWithDivider({ divider, children }: { divider: ReactNode; children: ReactNode }) {\n return (\n <>\n {divider}\n {children}\n </>\n );\n}\n\nfunction MenuSection({\n section,\n state,\n variant,\n className,\n headingClassName,\n edges,\n classNames,\n}: {\n section: Node<object>;\n state: TreeState<object>;\n variant: MenuVariant;\n className: string;\n headingClassName: string;\n edges: Edges;\n classNames?: MenuClassNames;\n}) {\n const { itemProps, headingProps, groupProps } = useMenuSection({\n heading: section.rendered,\n 'aria-label': section['aria-label'],\n });\n return (\n <div {...itemProps} className={className}>\n {section.rendered && (\n <span {...headingProps} className={headingClassName}>\n {section.rendered}\n </span>\n )}\n <div {...groupProps} className=\"flex flex-col\">\n <MenuItems\n nodes={[...section.childNodes]}\n state={state}\n variant={variant}\n // A heading takes the group's top edge, so the first item doesn't touch it.\n edges={{ ...edges, top: !section.rendered && edges.top }}\n classNames={classNames}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Items nest their corners inside the container's: an item on an outer edge gets the\n * outer corner less the 4px padding, and every other corner is 4px.\n */\nfunction MenuItems({\n nodes,\n state,\n variant,\n edges,\n classNames,\n}: {\n nodes: Node<object>[];\n state: TreeState<object>;\n variant: MenuVariant;\n edges: Edges;\n classNames?: MenuClassNames;\n}) {\n return nodes.map((node, index) => {\n const itemProps: MenuItemViewProps = {\n node,\n state,\n variant,\n top: index === 0 && edges.top ? 'outer' : 'plain',\n bottom: index === nodes.length - 1 && edges.bottom ? 'outer' : 'plain',\n classNames,\n };\n return (node.props as SubmenuItemProps).submenu ? (\n <SubmenuItemView key={node.key} {...itemProps} />\n ) : (\n <MenuItemView key={node.key} {...itemProps} />\n );\n });\n}\n\ninterface MenuItemViewProps {\n node: Node<object>;\n state: TreeState<object>;\n variant: MenuVariant;\n top: 'outer' | 'plain';\n bottom: 'outer' | 'plain';\n classNames?: MenuClassNames;\n /** A submenu trigger's props (from `useSubmenuTrigger`) and ref. */\n triggerProps?: Partial<AriaMenuItemProps>;\n itemRef?: RefObject<HTMLDivElement | null>;\n /** Whether the item's submenu is open (its active state). */\n submenuOpen?: boolean;\n}\n\n/** An item that opens a submenu, and the submenu's popover. */\nfunction SubmenuItemView(props: MenuItemViewProps) {\n const tree = useContext(MenuTreeContext)!;\n const parentMenuRef = useContext(MenuListContext)!;\n const { submenu, submenuDelay } = props.node.props as SubmenuItemProps;\n const submenuState = useSubmenuTriggerState({ triggerKey: props.node.key }, tree.rootState);\n const itemRef = useRef<HTMLDivElement>(null);\n const submenuRef = useRef<HTMLDivElement>(null);\n const { submenuTriggerProps, submenuProps, popoverProps } = useSubmenuTrigger(\n {\n parentMenuRef,\n submenuRef,\n delay: submenuDelay,\n isDisabled: props.state.disabledKeys.has(props.node.key),\n },\n submenuState,\n itemRef,\n );\n // In a sheet a submenu replaces its menu, so hovering an item doesn't open it.\n const { isOpen, onHoverChange, ...triggerProps } = submenuTriggerProps;\n // A sheet's submenu hides the item that opened it, so React Aria's focus on the item when\n // the submenu closes (← or Escape) finds it hidden. Once the menu shows again, the item\n // takes focus back from the closed submenu (or the back button), unless every menu closed.\n const wasOpen = useRef(isOpen);\n useLayoutEffect(() => {\n const closed = wasOpen.current && !isOpen;\n wasOpen.current = isOpen;\n const item = itemRef.current;\n if (!closed || !tree.sheet || !tree.rootState.isOpen || !item) return;\n const active = item.ownerDocument.activeElement;\n if (active == null || active === item.ownerDocument.body) item.focus();\n });\n return (\n <>\n <MenuItemView\n {...props}\n triggerProps={tree.sheet ? triggerProps : { ...triggerProps, onHoverChange }}\n itemRef={itemRef}\n submenuOpen={isOpen}\n />\n {tree.sheet ? (\n <SubmenuSheetPanel\n state={submenuState}\n submenuRef={submenuRef}\n menuProps={submenuProps}\n submenu={submenu!}\n title={props.node.rendered}\n />\n ) : (\n <SubmenuPopover\n state={submenuState}\n triggerRef={itemRef}\n submenuRef={submenuRef}\n menuProps={submenuProps}\n popoverProps={popoverProps}\n submenu={submenu!}\n />\n )}\n </>\n );\n}\n\n/**\n * A submenu in a sheet (M3 adapts menus into bottom sheets on small screens, where there's\n * no room beside an item): it takes the place of the menu that opened it, which the sheet\n * hides while it's open, below a back button and its item's label. ← (→ in right-to-left),\n * Escape and the back button go back. It's portalled into the sheet after its menu, so the\n * sheet's focus scope covers it.\n */\nfunction SubmenuSheetPanel({\n state,\n submenuRef,\n menuProps,\n submenu,\n title,\n}: Pick<SubmenuPopoverProps, 'state' | 'submenuRef' | 'menuProps' | 'submenu'> & {\n title: ReactNode;\n}) {\n const tree = useContext(MenuTreeContext)!;\n if (!state.isOpen || !tree.container) return null;\n const { submenuLevel, ...ariaMenuProps } = menuProps;\n const own = submenu.props;\n const variant = own.variant ?? tree.variant;\n const styles = menuStyles({ variant });\n return (\n <Overlay portalContainer={tree.container} disableFocusManagement>\n <div data-submenu-panel=\"\" className={styles.sheetPanel()}>\n <div className={styles.sheetHeader()}>\n <SheetBackButton\n label={tree.labels.back}\n onPress={() => state.close()}\n className={styles.sheetBack()}\n />\n <span className={styles.sheetTitle()}>{title}</span>\n </div>\n <MenuList\n {...mergeProps(ariaMenuProps, own)}\n listRef={submenuRef}\n layout=\"divider\"\n variant={variant}\n density={own.density ?? tree.density}\n level={submenuLevel + 1}\n embedded\n // However it opened (a touch leaves focus on the item, now hidden), focus moves in.\n autoFocus={state.focusStrategy ?? 'first'}\n />\n </div>\n </Overlay>\n );\n}\n\n/** The back button above a sheet's submenu: 48px, with an outline focus ring. */\nfunction SheetBackButton({\n label,\n onPress,\n className,\n}: {\n label: string;\n onPress: () => void;\n className: string;\n}) {\n const ref = useRef<HTMLButtonElement>(null);\n const { buttonProps, isPressed } = useButton({ onPress, 'aria-label': label }, ref);\n const { interactionProps, dataAttributes } = useM3Interaction({ isPressed }, ref);\n return (\n <button\n {...mergeProps(buttonProps, interactionProps)}\n {...dataAttributes}\n ref={ref}\n className={className}\n >\n <BackIcon />\n </button>\n );\n}\n\ninterface SubmenuPopoverProps {\n state: SubmenuTriggerState;\n triggerRef: RefObject<HTMLDivElement | null>;\n submenuRef: RefObject<HTMLDivElement | null>;\n menuProps: ReturnType<typeof useSubmenuTrigger>['submenuProps'];\n popoverProps: ReturnType<typeof useSubmenuTrigger>['popoverProps'];\n submenu: ReactElement<MenuProps>;\n}\n\nfunction SubmenuPopover(props: SubmenuPopoverProps) {\n const tree = useContext(MenuTreeContext)!;\n const presence = usePresence(props.state.isOpen);\n const isPresent = tree.instant ? props.state.isOpen : presence.isPresent;\n const isExiting = !tree.instant && presence.isExiting;\n const { exitProps } = presence;\n if (!isPresent || !tree.container) return null;\n // Inside the root popover: its focus scope and outside-press handling cover the submenu,\n // and the modal root menu doesn't make it inert.\n return (\n <Overlay portalContainer={tree.container} disableFocusManagement exiting={isExiting}>\n <SubmenuPopoverContent {...props} isExiting={isExiting} exitProps={exitProps} />\n </Overlay>\n );\n}\n\nfunction SubmenuPopoverContent({\n state,\n triggerRef,\n submenuRef,\n menuProps,\n popoverProps,\n submenu,\n isExiting,\n exitProps,\n}: SubmenuPopoverProps & { isExiting: boolean; exitProps: ExitProps }) {\n const tree = useContext(MenuTreeContext)!;\n const popoverRef = useRef<HTMLDivElement>(null);\n const { submenuLevel, ...ariaMenuProps } = menuProps;\n const { popoverProps: positionProps, placement } = usePopover(\n {\n ...popoverProps,\n // React Aria handles this as a submenu's popover (dismissable, non-modal).\n ...({ trigger: 'SubmenuTrigger' } as Partial<AriaPopoverProps>),\n triggerRef,\n popoverRef,\n placement: 'end top',\n // Beside the parent menu (the 4px padding around the item and a 2px gap), with its\n // first item level with the item that opened it.\n offset: 6,\n crossOffset: -4,\n },\n state,\n );\n const revealRef = useRef<HTMLDivElement>(null);\n const entering = useRevealEntering(placement, revealRef);\n const { className, style, ...own } = submenu.props;\n const styles = menuStyles();\n return (\n // `w-max` (`menuOwnWidth`): positioned inside the narrower root popover, it would otherwise shrink to fit\n // what's left of that popover's width and wrap every label. Like the root menu's, the\n // submenu's `className` and `style` go on this outermost element.\n <div\n {...positionProps}\n ref={popoverRef}\n style={{ ...style, ...positionProps.style }}\n data-overlay-placement=\"\"\n className={styles.popover({ class: cn(menuOwnWidth, className) })}\n >\n <div\n {...exitProps}\n ref={revealRef}\n data-entering={entering || undefined}\n data-exiting={isExiting || undefined}\n data-placement={placement ?? undefined}\n className={menuStyles({ instant: tree.instant }).reveal()}\n >\n <MenuList\n {...mergeProps(ariaMenuProps, own)}\n listRef={submenuRef}\n layout={own.layout ?? tree.layout}\n variant={own.variant ?? tree.variant}\n density={own.density ?? tree.density}\n level={submenuLevel + 1}\n />\n </div>\n </div>\n );\n}\n\nfunction MenuItemView({\n node,\n state,\n variant,\n top,\n bottom,\n classNames,\n triggerProps,\n itemRef,\n submenuOpen = false,\n}: MenuItemViewProps) {\n const ownRef = useRef<HTMLDivElement>(null);\n const ref = itemRef ?? ownRef;\n const props = node.props as SubmenuItemProps;\n const isDisabled = state.disabledKeys.has(node.key);\n // A plain action in a selectable menu (`checkable={false}`) is never checked.\n const selectable = state.selectionManager.selectionMode !== 'none' && props.checkable !== false;\n const plainInSelectable = state.selectionManager.selectionMode !== 'none' && !selectable;\n const multiple = selectable && state.selectionManager.selectionMode === 'multiple';\n const {\n menuItemProps: ariaItemProps,\n keyboardShortcutProps,\n isSelected,\n isPressed,\n } = useMenuItem(\n {\n ...triggerProps,\n key: node.key,\n 'aria-label': props['aria-label'],\n // Disabled items stay focusable (the menu's `disabledBehavior`) but do nothing.\n isDisabled,\n isSelected: plainInSelectable ? false : undefined,\n // M3: multi-select menus stay open until they're dismissed, Enter included; a plain\n // action closes the menu, as in any menu.\n closeOnSelect: multiple ? false : plainInSelectable ? true : undefined,\n },\n state,\n ref,\n );\n const menuItemProps =\n plainInSelectable && !props.submenu\n ? { ...ariaItemProps, role: 'menuitem', 'aria-checked': undefined }\n : ariaItemProps;\n const { interactionProps, dataAttributes } = useM3Interaction(\n { isPressed, isDisabled, isSelected },\n ref,\n );\n const styles = menuStyles({\n variant,\n itemTop: top,\n itemBottom: bottom,\n hasDescription: Boolean(props.description),\n });\n const selectedIcon = props.selectedIcon ?? (selectable ? <CheckIcon /> : null);\n const trailingIcon = props.trailingIcon ?? (props.submenu ? <SubmenuIcon /> : null);\n const badgeId = useId();\n // Named by its content: the label and supporting text in the order they show, each read\n // once. React Aria names it by the label alone and describes it by the supporting text,\n // which leaves visible text out of its name (WCAG 2.5.3), as List options did. The shortcut\n // and the badge are extra information, not the item's label: they stay its description,\n // hidden from the content so they're read once.\n const describedBy =\n [props.shortcut ? keyboardShortcutProps.id : undefined, props.badge ? badgeId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <div\n {...mergeProps(menuItemProps, interactionProps)}\n {...dataAttributes}\n aria-labelledby={undefined}\n aria-describedby={describedBy}\n data-menu-open={submenuOpen || undefined}\n // Each item resolves the menu's tokens, so its selection picks its colours.\n data-tokens={mergeDataTokens('md-comp-menus', menuItemProps)}\n data-variant={variant}\n data-slot=\"item\"\n ref={ref}\n className={styles.item({ class: cn(classNames?.item, props.className) })}\n >\n {props.leadingIcon && selectedIcon ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"leading-icon\"\n className={styles.icon({ class: classNames?.icon })}\n >\n {isSelected ? selectedIcon : props.leadingIcon}\n </span>\n ) : props.leadingIcon ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"leading-icon\"\n className={styles.icon({ class: classNames?.icon })}\n >\n {props.leadingIcon}\n </span>\n ) : selectedIcon ? (\n // No leading icon: the selected icon expands in when selected (Compose).\n <span aria-hidden=\"true\" className={styles.selectedIcon()}>\n <span className={styles.selectedIconInner()}>\n <span className={styles.icon({ class: classNames?.icon })}>{selectedIcon}</span>\n </span>\n </span>\n ) : null}\n <span className={styles.text()}>\n <span>{node.rendered}</span>\n {props.description && (\n <span className={styles.description({ class: classNames?.description })}>\n {props.description}\n </span>\n )}\n </span>\n {props.badge && (\n <span id={badgeId} aria-hidden=\"true\" className={styles.badge()}>\n {props.badge}\n </span>\n )}\n {props.shortcut && (\n <kbd\n {...keyboardShortcutProps}\n aria-hidden=\"true\"\n className={styles.trailing({ class: cn('font-plain', classNames?.shortcut) })}\n >\n {props.shortcut}\n </kbd>\n )}\n {trailingIcon && (\n <span\n aria-hidden=\"true\"\n data-slot=\"trailing-icon\"\n className={styles.trailing({ class: classNames?.trailingIcon })}\n >\n {trailingIcon}\n </span>\n )}\n </div>\n );\n}\n\nexport type { Key as MenuKey };\n"],"mappings":"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"}
1
+ {"version":3,"file":"Menu.js","names":["Overlay"],"sources":["../../../src/components/menu/Menu.tsx"],"sourcesContent":["'use client';\n\nimport {\n cloneElement,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n useSyncExternalStore,\n type CSSProperties,\n type ElementType,\n type FocusEvent,\n type JSX,\n type Key,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefObject,\n} from 'react';\nimport {\n DismissButton,\n I18nProvider,\n mergeProps,\n useLocale,\n useMenu,\n useMenuItem,\n useMenuSection,\n useObjectRef,\n usePopover,\n useButton,\n useSubmenuTrigger,\n type AriaMenuItemProps,\n type AriaMenuOptions,\n type AriaMenuProps,\n type AriaPopoverProps,\n type Placement,\n} from 'react-aria';\nimport {\n Item,\n Section,\n useSubmenuTriggerState,\n useTreeState,\n type Node,\n type RootMenuTriggerState,\n type SubmenuTriggerState,\n type TreeState,\n} from 'react-stately';\nimport { localeWithDirection } from '../../primitives/locale-with-direction';\nimport { Overlay } from '../../primitives/Overlay';\nimport { TriggerContext } from '../../primitives/TriggerContext';\nimport { useM3Interaction } from '../../primitives/use-m3-interaction';\nimport { usePresence } from '../../primitives/use-presence';\nimport { densityAttribute, type Density } from '../../tokens/density';\nimport { toAriaPlacement } from '../../utils/placement';\nimport { assertCollectionChildren } from '../../utils/assert-collection-children';\nimport { cn } from '../../utils/cn';\nimport { useTypeaheadDelegate } from '../../utils/typeahead';\nimport { COMPACT_WINDOW, useMediaQuery } from '../date-picker/use-media-query';\nimport { Divider } from '../divider/Divider';\nimport { LazyBottomSheet, usePreloadBottomSheet } from '../sheet/lazy-bottom-sheet';\nimport { BackIcon } from '../sheet/sheet-icons';\nimport { useRevealEntering } from './use-reveal-entering';\nimport { menuOwnWidth, menuStyles, type MenuLayout, type MenuVariant } from './menu-styles';\nimport { MenuTriggerContext, type MenuTriggerContextValue } from './menu-trigger';\n\nexport {\n ContextMenuTrigger,\n MenuTrigger,\n type ContextMenuTriggerProps,\n type MenuTriggerProps,\n} from './menu-trigger';\nimport { mergeDataTokens } from '../../utils/merge-data-tokens';\nimport { splitRootProps, type RootDOMProps } from '../../utils/root-props';\n\nconst CheckIcon = () => (\n <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\">\n <path d=\"M382-240 154-468l57-57 171 171 367-367 57 57-424 424Z\" />\n </svg>\n);\n\n/** Clears the link attributes `useMenuItem` copies from an item's props onto one that isn't a link. */\nconst NOT_A_LINK = {\n href: undefined,\n target: undefined,\n rel: undefined,\n download: undefined,\n ping: undefined,\n referrerPolicy: undefined,\n};\n\n/** The default submenu arrow (Material Symbols `arrow_right`), mirrored in RTL. */\nconst SubmenuIcon = () => (\n <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\" className=\"rtl:-scale-x-100\">\n <path d=\"M400-280v-400l200 200-200 200Z\" />\n </svg>\n);\n\n/** Props of a {@link MenuItem}; the React `key` identifies it for `onAction` and selection. */\nexport interface MenuItemProps {\n /** The label. */\n children: ReactNode;\n /** Plain-text label for typeahead when `children` is not a string. */\n textValue?: string;\n /** Icon before the label. */\n leadingIcon?: ReactNode;\n /** Icon shown while selected (defaults to a check in selectable menus). */\n selectedIcon?: ReactNode;\n /** Second line of text (supporting text), read as part of the item's name after the label. */\n description?: ReactNode;\n /**\n * A badge before the trailing text or icon (M3 anatomy), such as a `Badge` with a count.\n * It's read after the name, as the item's description.\n */\n badge?: ReactNode;\n /** Keyboard shortcut shown at the end, e.g. \"⌘C\", read as the item's description. */\n shortcut?: string;\n /** Icon at the end (an item with a submenu shows an arrow by default). */\n trailingIcon?: ReactNode;\n /**\n * Makes the item a link: a real `<a>` with the item's look, role and keys, so the browser's\n * link menu (open in a new tab, copy or save the link) and modified clicks work. A press,\n * Enter or Space follows it, through a `RouterProvider` (such as `NextRouterProvider`) on a\n * plain click, and closes the menu. A disabled item, or one that opens a submenu, isn't a link.\n */\n href?: string;\n /** A link item's target; `_blank` adds `rel=\"noopener noreferrer\"` unless `rel` is given. */\n target?: string;\n /** A link item's `rel`, e.g. `\"nofollow\"`. */\n rel?: string;\n /** Downloads the link item's file instead of opening it (optionally with a file name). */\n download?: boolean | string;\n /** Accessible name when the label isn't plain text. */\n 'aria-label'?: string;\n /** Classes for the item, merged after `classNames.item`; consumer classes win. */\n className?: string;\n}\n\n/** An item in a `Menu` (a React Stately collection item: identify it with `key`). */\nexport const MenuItem = Item as unknown as (props: MenuItemProps) => JSX.Element;\n\nexport interface MenuGroupProps {\n /** Group label shown above its items. */\n title?: ReactNode;\n /** Accessible name for the group when it has no `title`. */\n 'aria-label'?: string;\n /** `MenuItem`s and `SubmenuTrigger`s. */\n children: ReactElement | ReactElement[];\n}\n\n/**\n * A group of items (a React Stately collection section): set off by dividers in the\n * `divider` layout, its own surface in the `gap` layout.\n */\nexport const MenuGroup = Section as unknown as (props: MenuGroupProps) => JSX.Element;\n\nexport interface SubmenuTriggerProps {\n /** The `MenuItem` that opens the submenu, then the submenu's `Menu`. */\n children: [ReactElement<MenuItemProps>, ReactElement<MenuProps>];\n /** How long (ms) the pointer rests on the item before the submenu opens. @default 200 */\n delay?: number;\n}\n\n/** What a `SubmenuTrigger` adds to its item's collection node. */\ninterface SubmenuItemProps extends MenuItemProps {\n submenu?: ReactElement<MenuProps>;\n submenuDelay?: number;\n /** See {@link CheckableMenuItemProps}. */\n checkable?: boolean;\n}\n\n/**\n * Props of a {@link CheckableMenuItem}, for the library's own menus (not exported from the\n * package): in a selectable menu, `checkable={false}` makes an item a plain action, with the\n * `menuitem` role, no checked state and no check, that closes the menu like any action.\n */\nexport interface CheckableMenuItemProps extends MenuItemProps {\n /** Whether the item can be checked in a selectable menu. @default true */\n checkable?: boolean;\n}\n\n/** A {@link MenuItem} that can opt out of the menu's selection (library-internal). */\nexport const CheckableMenuItem = Item as unknown as (props: CheckableMenuItemProps) => JSX.Element;\n\n/** Only a menu collection reads a `SubmenuTrigger`; rendered on its own it's nothing. */\nfunction SubmenuTriggerElement(): null {\n return null;\n}\n\n/** React Stately builds the item's node from this, with the submenu on its props. */\nSubmenuTriggerElement.getCollectionNode = function* getCollectionNode({\n children: [item, submenu],\n delay,\n}: SubmenuTriggerProps) {\n // `cloneElement` keeps the item's own `key`.\n yield { element: cloneElement(item, { submenu, submenuDelay: delay } as SubmenuItemProps) };\n};\n\n/**\n * Gives a menu item a submenu (M3: \"On web, menus can open submenus\"). It opens beside the\n * item, without covering it, on hover, press, Enter, Space or the arrow key pointing away\n * from the menu (Left in right-to-left), and closes with the opposite arrow or Escape.\n * While it's open, the item shows its active (pressed) layer, and the menu holding focus\n * takes rounder corners than the other one.\n *\n * @example\n * <SubmenuTrigger>\n * <MenuItem key=\"share\">Share</MenuItem>\n * <Menu onAction={(key) => share(key)}>\n * <MenuItem key=\"email\">Email</MenuItem>\n * <MenuItem key=\"link\">Copy link</MenuItem>\n * </Menu>\n * </SubmenuTrigger>\n */\nexport const SubmenuTrigger = SubmenuTriggerElement as unknown as (\n props: SubmenuTriggerProps,\n) => JSX.Element;\n\nexport interface MenuClassNames {\n /**\n * The menu's surface (the `menu` element): its colour, corners, size and the list that\n * scrolls. In a sheet it spans the sheet, without a surface of its own.\n */\n panel?: string;\n /**\n * The bottom sheet the menu opens in (`presentation=\"sheet\"`, or `\"auto\"` on compact\n * windows): the sheet's surface, as its `classNames.panel`.\n */\n sheet?: string;\n /** Each group of items (its own surface in the `gap` layout). */\n group?: string;\n /** Each `MenuGroup`'s heading. */\n heading?: string;\n /** Each item. */\n item?: string;\n /** Each item's leading icon, or the icon marking a selected item. */\n icon?: string;\n /** Each item's `description` line. */\n description?: string;\n /** Each item's keyboard `shortcut`. */\n shortcut?: string;\n /** Each item's trailing icon, including a submenu's arrow. */\n trailingIcon?: string;\n /** The dividers between groups in the `divider` layout. */\n divider?: string;\n}\n\nexport interface MenuProps\n extends\n Omit<\n AriaMenuProps<object>,\n | 'children'\n | 'items'\n | 'onClose'\n | 'autoFocus'\n | 'disallowEmptySelection'\n // The arrow keys always wrap and Escape always closes the menu, as M3's menus do.\n | 'shouldFocusWrap'\n | 'escapeKeyBehavior'\n >,\n Omit<RootDOMProps, keyof AriaMenuProps<object>> {\n /**\n * With `selectionMode`: the last selected item can be deselected, leaving none. `false` keeps\n * at least one item selected. @default true\n */\n deselectable?: boolean;\n /**\n * The keys of items that can't be chosen. They stay focusable, as M3 asks (\"Disabled menu\n * items can receive focus but aren't selectable\").\n */\n disabledKeys?: AriaMenuProps<object>['disabledKeys'];\n /** `MenuItem`s, `MenuGroup`s and `SubmenuTrigger`s. */\n children: ReactNode;\n /** `standard` (surface colours) or `vibrant` (tertiary container). @default \"standard\" */\n variant?: MenuVariant;\n /**\n * How groups are set apart. `divider`: one surface with dividers between groups, which M3\n * recommends on the web and for menus that scroll. `gap`: each group is its own surface,\n * 2px apart; a `gap` menu that has to scroll switches to dividers, since M3 doesn't use\n * gaps in scrolling menus. A submenu takes its parent's layout and variant unless it\n * sets its own.\n * @default \"divider\"\n */\n layout?: MenuLayout;\n /**\n * Web density (M3: \"On web only … Increasing density decreases the top and bottom\n * padding\"): each step down takes 4px off the items' height (44px at 0, 32px at -3) and 2px\n * off the space around dividers. Left out, the menu takes the density of the nearest\n * `ThemeProvider` or `ThemeScope`; a submenu takes its parent menu's. Keep 0 for touch.\n * @default 0\n */\n density?: Density;\n /**\n * Placement relative to the trigger: a side, then optionally the edge to align with\n * (`start` / `end` follow the text direction). A submenu always opens beside its item.\n * @default \"bottom-start\"\n */\n placement?: MenuPlacement;\n /** Gap between the trigger and the menu, in px (a split button's menu sits 4px away). @default 0 */\n offset?: number;\n /**\n * The least space kept between the menu and the window's edges, in px. A split button\n * passes 0, so its menu lines up with the trailing button even at the edge of the screen.\n * @default 12\n */\n containerPadding?: number;\n /**\n * Where the menu opens. `popover`: anchored to its trigger. `sheet`: in a modal bottom\n * sheet. `auto`: a sheet on compact windows (below 600px wide) and a popover on larger\n * ones (M3: \"Consider adapting menus into bottom sheets on small screens\"). Set it on the\n * root menu.\n * @default \"popover\"\n */\n presentation?: MenuPresentation;\n /** Words the menu shows in a sheet. Set them on the root menu. */\n labels?: Partial<MenuLabels>;\n /**\n * Open and close with no motion (M3: \"In dense products, such as on desktop, menus can\n * open instantly to reduce motion\"). Submenus follow their root menu. Popovers only: a menu\n * shown as a bottom sheet (`presentation=\"sheet\"`, or `auto` on a compact window) keeps the\n * sheet's slide, as M3's and Compose's modal bottom sheets always animate; under reduced\n * motion it fades instead.\n * @default false\n */\n instant?: boolean;\n /**\n * Goes with `style` on the menu's outermost element: the box React Aria places against the\n * trigger, or the bottom sheet's outermost element in a sheet. The surface inside keeps\n * its size and its place against the trigger whatever layout class lands here (the box\n * keeps the menu's own width); style it with `classNames.panel`.\n */\n className?: string;\n /** Classes for each part, by slot. */\n classNames?: MenuClassNames;\n /** Goes on the menu's outermost element, with `className`. */\n style?: CSSProperties;\n /** Ref to the menu's list, the `role=\"menu\"` element, in a popover or a sheet. */\n ref?: Ref<HTMLDivElement>;\n}\n\n/** Where a {@link Menu} sits against its trigger: a side, then optionally the edge it aligns with. */\nexport type MenuPlacement =\n | 'top'\n | 'bottom'\n | 'start'\n | 'end'\n | 'top-start'\n | 'top-end'\n | 'bottom-start'\n | 'bottom-end'\n | 'start-top'\n | 'start-bottom'\n | 'end-top'\n | 'end-bottom';\n\n/** Where a {@link Menu} opens. */\nexport type MenuPresentation = 'popover' | 'sheet' | 'auto';\n\n/** Words a {@link Menu} shows. */\nexport interface MenuLabels {\n /**\n * In a sheet, the button above a submenu that goes back to the menu that opened it.\n * @default \"Back\"\n */\n back: string;\n}\n\nconst DEFAULT_LABELS: MenuLabels = { back: 'Back' };\n\n/**\n * M3 Expressive menu: items on one surface with dividers between groups (or on grouped\n * surfaces), standard or vibrant colours, optional single or multiple selection with a\n * selected shape and check, submenus, keyboard navigation and typeahead (React Aria\n * `useMenu`). Must be inside a `MenuTrigger` or `ContextMenuTrigger`; it opens anchored to\n * the trigger in a portal that keeps the surrounding theme and direction.\n *\n * @example\n * <MenuTrigger>\n * <IconButton icon={<MoreIcon />} aria-label=\"More\" />\n * <Menu onAction={(key) => run(key)}>\n * <MenuGroup>\n * <MenuItem key=\"copy\" shortcut=\"⌘C\">Copy</MenuItem>\n * <MenuItem key=\"paste\" shortcut=\"⌘V\">Paste</MenuItem>\n * </MenuGroup>\n * <MenuGroup>\n * <MenuItem key=\"delete\">Delete</MenuItem>\n * </MenuGroup>\n * </Menu>\n * </MenuTrigger>\n */\nexport function Menu({ presentation = 'popover', instant = false, ...props }: MenuProps) {\n const trigger = useContext(MenuTriggerContext);\n if (!trigger) throw new Error('[@windmorph/react] <Menu> must be used inside <MenuTrigger>.');\n const compact = useMediaQuery(COMPACT_WINDOW);\n const presence = usePresence(trigger.state.isOpen);\n const asSheet = presentation === 'sheet' || (presentation === 'auto' && compact);\n usePreloadBottomSheet(trigger.triggerRef, asSheet);\n if (asSheet) return <MenuSheet {...props} trigger={trigger} />;\n // An instant menu leaves at once, without waiting for an exit transition.\n const isPresent = instant ? trigger.state.isOpen : presence.isPresent;\n const isExiting = !instant && presence.isExiting;\n if (!isPresent) return null;\n return (\n <Overlay exiting={isExiting}>\n <MenuPopover\n {...props}\n trigger={trigger}\n instant={instant}\n isExiting={isExiting}\n exitProps={presence.exitProps}\n />\n </Overlay>\n );\n}\n\n/**\n * The menu in a modal bottom sheet (M3: menus can adapt into bottom sheets on small\n * screens). The sheet is a dialog named like the menu; the menu inside keeps its role,\n * keyboard, typeahead and initial focus, and spans the sheet without a surface of its own.\n * The sheet's code loads on first open (or when the trigger is hovered or focused), so a\n * menu that only opens as a popover doesn't carry it.\n */\nfunction MenuSheet({\n trigger,\n layout: _layout,\n placement: _placement,\n offset: _offset,\n variant = 'standard',\n labels,\n className,\n style,\n ...props\n}: Omit<MenuProps, 'presentation' | 'instant'> & { trigger: MenuTriggerContextValue }) {\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const [activeLevel, setActiveLevel] = useState(0);\n const menuProps = mergeProps(trigger.menuProps, props);\n const label = menuProps['aria-label'];\n const naming =\n label != null\n ? { 'aria-label': label }\n : { 'aria-labelledby': menuProps['aria-labelledby'] ?? '' };\n return (\n <LazyBottomSheet\n {...naming}\n // A menu sheet opens at its own height (up to the window, the list scrolling inside):\n // at half the window, a short phone left its last items off-screen, where the arrow\n // keys could still move focus.\n skipPartiallyExpanded\n open={trigger.state.isOpen}\n onOpenChange={(open) => (open ? trigger.state.open() : trigger.state.close())}\n className={className}\n style={style}\n classNames={props.classNames?.sheet ? { panel: props.classNames.sheet } : undefined}\n >\n <div ref={setContainer} className={menuStyles().sheetContent()}>\n <TriggerContext value={null}>\n <MenuTreeContext\n value={{\n rootState: trigger.state,\n container,\n activeLevel,\n setActiveLevel,\n layout: 'divider',\n variant,\n density: props.density,\n instant: false,\n sheet: true,\n labels: { ...DEFAULT_LABELS, ...labels },\n }}\n >\n <MenuList\n {...menuProps}\n layout=\"divider\"\n variant={variant}\n level={0}\n embedded\n onClose={trigger.state.close}\n autoFocus={trigger.state.focusStrategy ?? 'first'}\n />\n </MenuTreeContext>\n </TriggerContext>\n </div>\n </LazyBottomSheet>\n );\n}\n\n/** Shared by a menu and its submenus. */\ninterface MenuTreeContextValue {\n rootState: RootMenuTriggerState;\n /** The root popover, which submenus portal into (inside its focus scope, never inert). */\n container: HTMLElement | null;\n /** The level of the menu holding focus (0 is the root menu). */\n activeLevel: number;\n setActiveLevel: (level: number) => void;\n /** What submenus inherit. */\n layout: MenuLayout;\n variant: MenuVariant;\n density: MenuProps['density'];\n /** Submenus open and close with no motion too. */\n instant: boolean;\n /**\n * In a sheet, a submenu takes the sheet's place of the menu that opened it, below a back\n * button, instead of opening beside its item.\n */\n sheet: boolean;\n labels: MenuLabels;\n}\n\nconst MenuTreeContext = createContext<MenuTreeContextValue | null>(null);\n\n/** The menu element an item is rendered in (a submenu's parent). */\nconst MenuListContext = createContext<RefObject<HTMLDivElement | null> | null>(null);\n\nconst subscribeToNothing = () => () => {};\n\n/**\n * React Aria resolves `start` / `end` from its locale context, not the DOM `dir`, so an\n * RTL region without an `I18nProvider` would align the menu to the wrong edge. Resolve\n * them to physical sides from the trigger's computed direction instead.\n */\nfunction toPhysicalPlacement(placement: MenuPlacement, direction: string): Placement {\n return toAriaPlacement(placement, direction === 'rtl');\n}\n\ntype ExitProps = ReturnType<typeof usePresence>['exitProps'];\n\nfunction MenuPopover({\n trigger,\n instant,\n isExiting,\n exitProps,\n placement = 'bottom-start',\n offset = 0,\n containerPadding = 12,\n layout = 'divider',\n variant = 'standard',\n labels,\n className,\n style,\n ...props\n}: Omit<MenuProps, 'presentation' | 'instant'> & {\n trigger: MenuTriggerContextValue;\n instant: boolean;\n isExiting: boolean;\n exitProps: ExitProps;\n}) {\n const popoverRef = useRef<HTMLDivElement>(null);\n const [container, setContainer] = useState<HTMLDivElement | null>(null);\n const setPopover = useCallback((element: HTMLDivElement | null) => {\n popoverRef.current = element;\n setContainer(element);\n }, []);\n const [activeLevel, setActiveLevel] = useState(0);\n // The DOM is the source of truth for direction; read it like an external store.\n const direction = useSyncExternalStore(\n subscribeToNothing,\n () =>\n trigger.triggerRef.current ? getComputedStyle(trigger.triggerRef.current).direction : 'ltr',\n () => 'ltr',\n );\n // Submenus' arrow keys and placement follow the locale's direction: give it the DOM's.\n const { locale, direction: localeDirection } = useLocale();\n const menuLocale =\n direction === localeDirection\n ? locale\n : localeWithDirection(locale, direction === 'rtl' ? 'rtl' : 'ltr');\n const {\n popoverProps,\n underlayProps,\n placement: actualPlacement,\n } = usePopover(\n {\n triggerRef: trigger.triggerRef,\n popoverRef,\n placement: toPhysicalPlacement(placement, direction),\n offset,\n containerPadding,\n },\n trigger.state,\n );\n const revealRef = useRef<HTMLDivElement>(null);\n const entering = useRevealEntering(actualPlacement, revealRef);\n const close = trigger.state.close;\n // Tab moves on from an open menu and closes it and its submenus (the APG menu button\n // pattern). React Aria's focus scope moves focus past the trigger, or back to it when\n // nothing follows; without the close, the menu stayed open with focus outside it. That\n // scope handles Tab on the document's capture phase and stops it, so this listens on the\n // window's, which comes first.\n useEffect(() => {\n const view = container?.ownerDocument.defaultView;\n if (!container || !view) return;\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Tab' || event.altKey || event.ctrlKey || event.metaKey) return;\n if (container.contains(container.ownerDocument.activeElement)) close();\n };\n view.addEventListener('keydown', onKeyDown, true);\n return () => view.removeEventListener('keydown', onKeyDown, true);\n }, [container, close]);\n const styles = menuStyles();\n return (\n <>\n <div {...underlayProps} className=\"fixed inset-0\" />\n <div\n {...popoverProps}\n ref={setPopover}\n // React Aria's placement wins over a consumer style's and, through the attribute\n // (styles/utilities.css), over consumer inset classes.\n style={{ ...style, ...popoverProps.style }}\n data-overlay-placement=\"\"\n className={styles.popover({ class: cn(menuOwnWidth, className) })}\n >\n <DismissButton onDismiss={trigger.state.close} />\n <div\n {...exitProps}\n ref={revealRef}\n data-entering={entering || undefined}\n data-exiting={isExiting || undefined}\n data-placement={actualPlacement ?? undefined}\n className={menuStyles({ instant }).reveal()}\n >\n <TriggerContext value={null}>\n <I18nProvider locale={menuLocale}>\n <MenuTreeContext\n value={{\n rootState: trigger.state,\n container,\n activeLevel,\n setActiveLevel,\n layout,\n variant,\n density: props.density,\n instant,\n sheet: false,\n labels: { ...DEFAULT_LABELS, ...labels },\n }}\n >\n <MenuList\n {...mergeProps(trigger.menuProps, props)}\n layout={layout}\n variant={variant}\n level={0}\n onClose={trigger.state.close}\n autoFocus={trigger.state.focusStrategy ?? 'first'}\n />\n </MenuTreeContext>\n </I18nProvider>\n </TriggerContext>\n </div>\n <DismissButton onDismiss={trigger.state.close} />\n </div>\n </>\n );\n}\n\ntype Position = 'only' | 'first' | 'middle' | 'last';\ntype Edges = { top: boolean; bottom: boolean };\n\nconst positionOf = (index: number, count: number): Position =>\n count === 1 ? 'only' : index === 0 ? 'first' : index === count - 1 ? 'last' : 'middle';\n\n/** Which of a group's edges have the outer corners (the others have 8px). */\nconst roundEdges = (position: Position): Edges => ({\n top: position === 'only' || position === 'first',\n bottom: position === 'only' || position === 'last',\n});\n\n/** Sections become groups; runs of loose items between them form implicit groups. */\nfunction toGroups(nodes: Node<object>[]): (Node<object> | Node<object>[])[] {\n const groups: (Node<object> | Node<object>[])[] = [];\n let run: Node<object>[] = [];\n for (const node of nodes) {\n if (node.type === 'section') {\n if (run.length) groups.push(run);\n run = [];\n groups.push(node);\n } else {\n run.push(node);\n }\n }\n if (run.length) groups.push(run);\n return groups;\n}\n\ntype MenuListProps = Omit<\n MenuProps,\n 'placement' | 'layout' | 'variant' | 'presentation' | 'instant' | 'className' | 'style'\n> &\n Pick<AriaMenuOptions<object>, 'onClose' | 'autoFocus' | 'onKeyDown' | 'onKeyUp'> & {\n layout: MenuLayout;\n variant: MenuVariant;\n /** 0 for the root menu, then one more per submenu. */\n level: number;\n listRef?: RefObject<HTMLDivElement | null>;\n /** In a sheet: the list spans it, with no surface of its own. */\n embedded?: boolean;\n };\n\n/**\n * Whether the list has had to scroll, from a `ResizeObserver` (so it's measured only when\n * its size changes). Once true it stays true while the menu is open, so a `gap` menu that\n * switches to dividers can't flip back and forth.\n */\nfunction useHasScrolled(ref: RefObject<HTMLElement | null>, enabled: boolean) {\n const [scrolls, setScrolls] = useState(false);\n useLayoutEffect(() => {\n const element = ref.current;\n if (!enabled || scrolls || !element || typeof ResizeObserver === 'undefined') return;\n const observer = new ResizeObserver(() => {\n if (element.scrollHeight > element.clientHeight + 1) setScrolls(true);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref, enabled, scrolls]);\n return scrolls;\n}\n\nfunction MenuList({\n deselectable = true,\n variant,\n layout: requestedLayout,\n density,\n level,\n classNames,\n listRef,\n embedded = false,\n ref: forwardedRef,\n ...allProps\n}: MenuListProps) {\n // The menu list is the menu's root (its `ref` and `id` land there): its DOM attributes too.\n const { root, rest: props } = splitRootProps(allProps);\n // MenuItem / MenuGroup are React Stately Item / Section, so children are a collection.\n assertCollectionChildren(\n props.children,\n 'Menu',\n 'MenuItem, MenuGroup and SubmenuTrigger elements',\n );\n const tree = useContext(MenuTreeContext);\n // M3: \"Disabled menu items can receive focus but aren't selectable.\"\n const state = useTreeState({\n ...(props as AriaMenuProps<object>),\n disallowEmptySelection: !deselectable,\n disabledBehavior: 'selection',\n });\n const ownRef = useObjectRef(forwardedRef);\n const ref = listRef ?? ownRef;\n // M3 keyboard table: \"Letters — Focus moves to the next menu item starting with letter\".\n const keyboardDelegate = useTypeaheadDelegate(state, ref);\n const { menuProps } = useMenu(\n // The arrow keys wrap from the last item to the first and back, as M3's menus and the rest\n // of the library's collections do (APG makes it optional).\n { ...(props as AriaMenuOptions<object>), keyboardDelegate, shouldFocusWrap: true },\n state,\n ref,\n );\n const groups = toGroups([...state.collection]);\n const scrolled = useHasScrolled(ref, requestedLayout === 'gap');\n const layout: MenuLayout = scrolled ? 'divider' : requestedLayout;\n const styles = menuStyles({ variant, layout, embedded });\n // While a submenu is open, the menu holding focus is rounder than the others (M3).\n const submenuOpen = Boolean(tree && tree.rootState.expandedKeysStack.length > 0);\n const shape = !submenuOpen ? undefined : tree?.activeLevel === level ? 'active' : 'inactive';\n const setActive = tree?.setActiveLevel;\n\n return (\n <div\n {...mergeProps(root, menuProps, {\n // Focus events bubble through portals: count only focus inside this menu's element.\n onFocus: (event: FocusEvent<HTMLDivElement>) => {\n if (event.currentTarget.contains(event.target)) setActive?.(level);\n },\n })}\n ref={ref}\n {...densityAttribute(density)}\n data-tokens={mergeDataTokens('md-comp-menus', root)}\n data-variant={variant}\n data-layout={layout}\n data-shape={shape}\n className={styles.menu({ class: classNames?.panel })}\n >\n <MenuListContext value={ref}>\n {groups.map((group, index) => {\n const position = positionOf(index, groups.length);\n // In the divider layout the menu is the surface: its first and last items nest in\n // its corners, and dividers go between groups.\n const edges: Edges =\n layout === 'divider'\n ? { top: index === 0, bottom: index === groups.length - 1 }\n : roundEdges(position);\n const groupStyles = menuStyles({ variant, layout, groupPosition: position, morph: true });\n return (\n <GroupWithDivider\n key={Array.isArray(group) ? group[0]!.key : group.key}\n divider={\n layout === 'divider' && index > 0 ? (\n // A menu's divider is a `separator` between its groups (WAI-ARIA menu).\n <Divider\n decorative={false}\n className={styles.divider({ class: classNames?.divider })}\n />\n ) : null\n }\n >\n {Array.isArray(group) ? (\n <div\n role=\"presentation\"\n className={groupStyles.group({ class: classNames?.group })}\n >\n <MenuItems\n nodes={group}\n state={state}\n variant={variant}\n edges={edges}\n classNames={classNames}\n />\n </div>\n ) : (\n <MenuSection\n section={group}\n state={state}\n variant={variant}\n className={groupStyles.group({ class: classNames?.group })}\n headingClassName={groupStyles.heading({ class: classNames?.heading })}\n edges={edges}\n classNames={classNames}\n />\n )}\n </GroupWithDivider>\n );\n })}\n </MenuListContext>\n </div>\n );\n}\n\nfunction GroupWithDivider({ divider, children }: { divider: ReactNode; children: ReactNode }) {\n return (\n <>\n {divider}\n {children}\n </>\n );\n}\n\nfunction MenuSection({\n section,\n state,\n variant,\n className,\n headingClassName,\n edges,\n classNames,\n}: {\n section: Node<object>;\n state: TreeState<object>;\n variant: MenuVariant;\n className: string;\n headingClassName: string;\n edges: Edges;\n classNames?: MenuClassNames;\n}) {\n const { itemProps, headingProps, groupProps } = useMenuSection({\n heading: section.rendered,\n 'aria-label': section['aria-label'],\n });\n return (\n <div {...itemProps} className={className}>\n {section.rendered && (\n <span {...headingProps} className={headingClassName}>\n {section.rendered}\n </span>\n )}\n <div {...groupProps} className=\"flex flex-col\">\n <MenuItems\n nodes={[...section.childNodes]}\n state={state}\n variant={variant}\n // A heading takes the group's top edge, so the first item doesn't touch it.\n edges={{ ...edges, top: !section.rendered && edges.top }}\n classNames={classNames}\n />\n </div>\n </div>\n );\n}\n\n/**\n * Items nest their corners inside the container's: an item on an outer edge gets the\n * outer corner less the 4px padding, and every other corner is 4px.\n */\nfunction MenuItems({\n nodes,\n state,\n variant,\n edges,\n classNames,\n}: {\n nodes: Node<object>[];\n state: TreeState<object>;\n variant: MenuVariant;\n edges: Edges;\n classNames?: MenuClassNames;\n}) {\n return nodes.map((node, index) => {\n const itemProps: MenuItemViewProps = {\n node,\n state,\n variant,\n top: index === 0 && edges.top ? 'outer' : 'plain',\n bottom: index === nodes.length - 1 && edges.bottom ? 'outer' : 'plain',\n classNames,\n };\n return (node.props as SubmenuItemProps).submenu ? (\n <SubmenuItemView key={node.key} {...itemProps} />\n ) : (\n <MenuItemView key={node.key} {...itemProps} />\n );\n });\n}\n\ninterface MenuItemViewProps {\n node: Node<object>;\n state: TreeState<object>;\n variant: MenuVariant;\n top: 'outer' | 'plain';\n bottom: 'outer' | 'plain';\n classNames?: MenuClassNames;\n /** A submenu trigger's props (from `useSubmenuTrigger`) and ref. */\n triggerProps?: Partial<AriaMenuItemProps>;\n itemRef?: RefObject<HTMLDivElement | null>;\n /** Whether the item's submenu is open (its active state). */\n submenuOpen?: boolean;\n}\n\n/** An item that opens a submenu, and the submenu's popover. */\nfunction SubmenuItemView(props: MenuItemViewProps) {\n const tree = useContext(MenuTreeContext)!;\n const parentMenuRef = useContext(MenuListContext)!;\n const { submenu, submenuDelay } = props.node.props as SubmenuItemProps;\n const submenuState = useSubmenuTriggerState({ triggerKey: props.node.key }, tree.rootState);\n const itemRef = useRef<HTMLDivElement>(null);\n const submenuRef = useRef<HTMLDivElement>(null);\n const { submenuTriggerProps, submenuProps, popoverProps } = useSubmenuTrigger(\n {\n parentMenuRef,\n submenuRef,\n delay: submenuDelay,\n isDisabled: props.state.disabledKeys.has(props.node.key),\n },\n submenuState,\n itemRef,\n );\n // In a sheet a submenu replaces its menu, so hovering an item doesn't open it.\n const { isOpen, onHoverChange, ...triggerProps } = submenuTriggerProps;\n // A sheet's submenu hides the item that opened it, so React Aria's focus on the item when\n // the submenu closes (← or Escape) finds it hidden. Once the menu shows again, the item\n // takes focus back from the closed submenu (or the back button), unless every menu closed.\n const wasOpen = useRef(isOpen);\n useLayoutEffect(() => {\n const closed = wasOpen.current && !isOpen;\n wasOpen.current = isOpen;\n const item = itemRef.current;\n if (!closed || !tree.sheet || !tree.rootState.isOpen || !item) return;\n const active = item.ownerDocument.activeElement;\n if (active == null || active === item.ownerDocument.body) item.focus();\n });\n return (\n <>\n <MenuItemView\n {...props}\n triggerProps={tree.sheet ? triggerProps : { ...triggerProps, onHoverChange }}\n itemRef={itemRef}\n submenuOpen={isOpen}\n />\n {tree.sheet ? (\n <SubmenuSheetPanel\n state={submenuState}\n submenuRef={submenuRef}\n menuProps={submenuProps}\n submenu={submenu!}\n title={props.node.rendered}\n />\n ) : (\n <SubmenuPopover\n state={submenuState}\n triggerRef={itemRef}\n submenuRef={submenuRef}\n menuProps={submenuProps}\n popoverProps={popoverProps}\n submenu={submenu!}\n />\n )}\n </>\n );\n}\n\n/**\n * A submenu in a sheet (M3 adapts menus into bottom sheets on small screens, where there's\n * no room beside an item): it takes the place of the menu that opened it, which the sheet\n * hides while it's open, below a back button and its item's label. ← (→ in right-to-left),\n * Escape and the back button go back. It's portalled into the sheet after its menu, so the\n * sheet's focus scope covers it.\n */\nfunction SubmenuSheetPanel({\n state,\n submenuRef,\n menuProps,\n submenu,\n title,\n}: Pick<SubmenuPopoverProps, 'state' | 'submenuRef' | 'menuProps' | 'submenu'> & {\n title: ReactNode;\n}) {\n const tree = useContext(MenuTreeContext)!;\n if (!state.isOpen || !tree.container) return null;\n const { submenuLevel, ...ariaMenuProps } = menuProps;\n const own = submenu.props;\n const variant = own.variant ?? tree.variant;\n const styles = menuStyles({ variant });\n return (\n <Overlay portalContainer={tree.container} disableFocusManagement>\n <div data-submenu-panel=\"\" className={styles.sheetPanel()}>\n <div className={styles.sheetHeader()}>\n <SheetBackButton\n label={tree.labels.back}\n onPress={() => state.close()}\n className={styles.sheetBack()}\n />\n <span className={styles.sheetTitle()}>{title}</span>\n </div>\n <MenuList\n {...mergeProps(ariaMenuProps, own)}\n listRef={submenuRef}\n layout=\"divider\"\n variant={variant}\n density={own.density ?? tree.density}\n level={submenuLevel + 1}\n embedded\n // However it opened (a touch leaves focus on the item, now hidden), focus moves in.\n autoFocus={state.focusStrategy ?? 'first'}\n />\n </div>\n </Overlay>\n );\n}\n\n/** The back button above a sheet's submenu: 48px, with an outline focus ring. */\nfunction SheetBackButton({\n label,\n onPress,\n className,\n}: {\n label: string;\n onPress: () => void;\n className: string;\n}) {\n const ref = useRef<HTMLButtonElement>(null);\n const { buttonProps, isPressed } = useButton({ onPress, 'aria-label': label }, ref);\n const { interactionProps, dataAttributes } = useM3Interaction({ isPressed }, ref);\n return (\n <button\n {...mergeProps(buttonProps, interactionProps)}\n {...dataAttributes}\n ref={ref}\n className={className}\n >\n <BackIcon />\n </button>\n );\n}\n\ninterface SubmenuPopoverProps {\n state: SubmenuTriggerState;\n triggerRef: RefObject<HTMLDivElement | null>;\n submenuRef: RefObject<HTMLDivElement | null>;\n menuProps: ReturnType<typeof useSubmenuTrigger>['submenuProps'];\n popoverProps: ReturnType<typeof useSubmenuTrigger>['popoverProps'];\n submenu: ReactElement<MenuProps>;\n}\n\nfunction SubmenuPopover(props: SubmenuPopoverProps) {\n const tree = useContext(MenuTreeContext)!;\n const presence = usePresence(props.state.isOpen);\n const isPresent = tree.instant ? props.state.isOpen : presence.isPresent;\n const isExiting = !tree.instant && presence.isExiting;\n const { exitProps } = presence;\n if (!isPresent || !tree.container) return null;\n // Inside the root popover: its focus scope and outside-press handling cover the submenu,\n // and the modal root menu doesn't make it inert.\n return (\n <Overlay portalContainer={tree.container} disableFocusManagement exiting={isExiting}>\n <SubmenuPopoverContent {...props} isExiting={isExiting} exitProps={exitProps} />\n </Overlay>\n );\n}\n\nfunction SubmenuPopoverContent({\n state,\n triggerRef,\n submenuRef,\n menuProps,\n popoverProps,\n submenu,\n isExiting,\n exitProps,\n}: SubmenuPopoverProps & { isExiting: boolean; exitProps: ExitProps }) {\n const tree = useContext(MenuTreeContext)!;\n const popoverRef = useRef<HTMLDivElement>(null);\n const { submenuLevel, ...ariaMenuProps } = menuProps;\n const { popoverProps: positionProps, placement } = usePopover(\n {\n ...popoverProps,\n // React Aria handles this as a submenu's popover (dismissable, non-modal).\n ...({ trigger: 'SubmenuTrigger' } as Partial<AriaPopoverProps>),\n triggerRef,\n popoverRef,\n placement: 'end top',\n // Beside the parent menu (the 4px padding around the item and a 2px gap), with its\n // first item level with the item that opened it.\n offset: 6,\n crossOffset: -4,\n },\n state,\n );\n const revealRef = useRef<HTMLDivElement>(null);\n const entering = useRevealEntering(placement, revealRef);\n const { className, style, ...own } = submenu.props;\n const styles = menuStyles();\n return (\n // `w-max` (`menuOwnWidth`): positioned inside the narrower root popover, it would otherwise shrink to fit\n // what's left of that popover's width and wrap every label. Like the root menu's, the\n // submenu's `className` and `style` go on this outermost element.\n <div\n {...positionProps}\n ref={popoverRef}\n style={{ ...style, ...positionProps.style }}\n data-overlay-placement=\"\"\n className={styles.popover({ class: cn(menuOwnWidth, className) })}\n >\n <div\n {...exitProps}\n ref={revealRef}\n data-entering={entering || undefined}\n data-exiting={isExiting || undefined}\n data-placement={placement ?? undefined}\n className={menuStyles({ instant: tree.instant }).reveal()}\n >\n <MenuList\n {...mergeProps(ariaMenuProps, own)}\n listRef={submenuRef}\n layout={own.layout ?? tree.layout}\n variant={own.variant ?? tree.variant}\n density={own.density ?? tree.density}\n level={submenuLevel + 1}\n />\n </div>\n </div>\n );\n}\n\nfunction MenuItemView({\n node,\n state,\n variant,\n top,\n bottom,\n classNames,\n triggerProps,\n itemRef,\n submenuOpen = false,\n}: MenuItemViewProps) {\n const ownRef = useRef<HTMLElement>(null);\n const ref = itemRef ?? ownRef;\n const props = node.props as SubmenuItemProps;\n const isDisabled = state.disabledKeys.has(node.key);\n // A plain action in a selectable menu (`checkable={false}`) is never checked.\n const selectable = state.selectionManager.selectionMode !== 'none' && props.checkable !== false;\n const plainInSelectable = state.selectionManager.selectionMode !== 'none' && !selectable;\n const multiple = selectable && state.selectionManager.selectionMode === 'multiple';\n const {\n menuItemProps: ariaItemProps,\n keyboardShortcutProps,\n isSelected,\n isPressed,\n } = useMenuItem(\n {\n ...triggerProps,\n key: node.key,\n 'aria-label': props['aria-label'],\n // Disabled items stay focusable (the menu's `disabledBehavior`) but do nothing.\n isDisabled,\n isSelected: plainInSelectable ? false : undefined,\n // M3: multi-select menus stay open until they're dismissed, Enter included; a plain\n // action closes the menu, as in any menu.\n closeOnSelect: multiple ? false : plainInSelectable ? true : undefined,\n },\n state,\n ref,\n );\n const menuItemProps =\n plainInSelectable && !props.submenu\n ? { ...ariaItemProps, role: 'menuitem', 'aria-checked': undefined }\n : ariaItemProps;\n // A link item is a real `<a>`: `useMenuItem` gives it the link's attributes, routes a plain\n // click and closes the menu. A disabled item, or one that opens a submenu, stays a plain\n // element without them, so it can't be followed.\n const link = props.href != null && !isDisabled && !props.submenu;\n // Widened, so the item's ref (an element of either kind) fits both.\n const Root = (link ? 'a' : 'div') as ElementType;\n const linkAttributes = link\n ? { rel: props.rel ?? (props.target === '_blank' ? 'noopener noreferrer' : undefined) }\n : NOT_A_LINK;\n const { interactionProps, dataAttributes } = useM3Interaction(\n { isPressed, isDisabled, isSelected },\n ref,\n );\n const styles = menuStyles({\n variant,\n itemTop: top,\n itemBottom: bottom,\n hasDescription: Boolean(props.description),\n });\n const selectedIcon = props.selectedIcon ?? (selectable ? <CheckIcon /> : null);\n const trailingIcon = props.trailingIcon ?? (props.submenu ? <SubmenuIcon /> : null);\n const badgeId = useId();\n // Named by its content: the label and supporting text in the order they show, each read\n // once. React Aria names it by the label alone and describes it by the supporting text,\n // which leaves visible text out of its name (WCAG 2.5.3), as List options did. The shortcut\n // and the badge are extra information, not the item's label: they stay its description,\n // hidden from the content so they're read once.\n const describedBy =\n [props.shortcut ? keyboardShortcutProps.id : undefined, props.badge ? badgeId : undefined]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return (\n <Root\n {...mergeProps(menuItemProps, interactionProps)}\n {...linkAttributes}\n {...dataAttributes}\n aria-labelledby={undefined}\n aria-describedby={describedBy}\n data-menu-open={submenuOpen || undefined}\n // Each item resolves the menu's tokens, so its selection picks its colours.\n data-tokens={mergeDataTokens('md-comp-menus', menuItemProps)}\n data-variant={variant}\n data-slot=\"item\"\n ref={ref}\n className={styles.item({ class: cn(classNames?.item, props.className) })}\n >\n {props.leadingIcon && selectedIcon ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"leading-icon\"\n className={styles.icon({ class: classNames?.icon })}\n >\n {isSelected ? selectedIcon : props.leadingIcon}\n </span>\n ) : props.leadingIcon ? (\n <span\n aria-hidden=\"true\"\n data-slot=\"leading-icon\"\n className={styles.icon({ class: classNames?.icon })}\n >\n {props.leadingIcon}\n </span>\n ) : selectedIcon ? (\n // No leading icon: the selected icon expands in when selected (Compose).\n <span aria-hidden=\"true\" className={styles.selectedIcon()}>\n <span className={styles.selectedIconInner()}>\n <span className={styles.icon({ class: classNames?.icon })}>{selectedIcon}</span>\n </span>\n </span>\n ) : null}\n <span className={styles.text()}>\n <span>{node.rendered}</span>\n {props.description && (\n <span className={styles.description({ class: classNames?.description })}>\n {props.description}\n </span>\n )}\n </span>\n {props.badge && (\n <span id={badgeId} aria-hidden=\"true\" className={styles.badge()}>\n {props.badge}\n </span>\n )}\n {props.shortcut && (\n <kbd\n {...keyboardShortcutProps}\n aria-hidden=\"true\"\n className={styles.trailing({ class: cn('font-plain', classNames?.shortcut) })}\n >\n {props.shortcut}\n </kbd>\n )}\n {trailingIcon && (\n <span\n aria-hidden=\"true\"\n data-slot=\"trailing-icon\"\n className={styles.trailing({ class: classNames?.trailingIcon })}\n >\n {trailingIcon}\n </span>\n )}\n </Root>\n );\n}\n\nexport type { Key as MenuKey };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,MAAM,kBACJ,oBAAC,OAAD;CAAK,SAAQ;CAAiB,MAAK;CACjC,UAAA,oBAAC,QAAD,EAAM,GAAE,wDAAyD,CAAA;AAC9D,CAAA;;AAIP,MAAM,aAAa;CACjB,MAAM,KAAA;CACN,QAAQ,KAAA;CACR,KAAK,KAAA;CACL,UAAU,KAAA;CACV,MAAM,KAAA;CACN,gBAAgB,KAAA;AAClB;;AAGA,MAAM,oBACJ,oBAAC,OAAD;CAAK,SAAQ;CAAiB,MAAK;CAAe,WAAU;CAC1D,UAAA,oBAAC,QAAD,EAAM,GAAE,iCAAkC,CAAA;AACvC,CAAA;;AA4CP,MAAa,WAAW;;;;;AAexB,MAAa,YAAY;;AA4BzB,MAAa,oBAAoB;;AAGjC,SAAS,wBAA8B;CACrC,OAAO;AACT;;AAGA,sBAAsB,oBAAoB,UAAU,kBAAkB,EACpE,UAAU,CAAC,MAAM,UACjB,SACsB;CAEtB,MAAM,EAAE,SAAS,aAAa,MAAM;EAAE;EAAS,cAAc;CAAM,CAAqB,EAAE;AAC5F;;;;;;;;;;;;;;;;;AAkBA,MAAa,iBAAiB;AAyJ9B,MAAM,iBAA6B,EAAE,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;AAuBlD,SAAgB,KAAK,EAAE,eAAe,WAAW,UAAU,OAAO,GAAG,SAAoB;CACvF,MAAM,UAAU,WAAW,kBAAkB;CAC7C,IAAI,CAAC,SAAS,MAAM,IAAI,MAAM,8DAA8D;CAC5F,MAAM,UAAU,cAAc,cAAc;CAC5C,MAAM,WAAW,YAAY,QAAQ,MAAM,MAAM;CACjD,MAAM,UAAU,iBAAiB,WAAY,iBAAiB,UAAU;CACxE,sBAAsB,QAAQ,YAAY,OAAO;CACjD,IAAI,SAAS,OAAO,oBAAC,WAAD;EAAW,GAAI;EAAgB;CAAU,CAAA;CAE7D,MAAM,YAAY,UAAU,QAAQ,MAAM,SAAS,SAAS;CAC5D,MAAM,YAAY,CAAC,WAAW,SAAS;CACvC,IAAI,CAAC,WAAW,OAAO;CACvB,OACE,oBAACA,WAAD;EAAS,SAAS;EAChB,UAAA,oBAAC,aAAD;GACE,GAAI;GACK;GACA;GACE;GACX,WAAW,SAAS;EACrB,CAAA;CACM,CAAA;AAEb;;;;;;;;AASA,SAAS,UAAU,EACjB,SACA,QAAQ,SACR,WAAW,YACX,QAAQ,SACR,UAAU,YACV,QACA,WACA,OACA,GAAG,SACkF;CACrF,MAAM,CAAC,WAAW,gBAAgB,SAAgC,IAAI;CACtE,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAChD,MAAM,YAAY,WAAW,QAAQ,WAAW,KAAK;CACrD,MAAM,QAAQ,UAAU;CACxB,MAAM,SACJ,SAAS,OACL,EAAE,cAAc,MAAM,IACtB,EAAE,mBAAmB,UAAU,sBAAsB,GAAG;CAC9D,OACE,oBAAC,iBAAD;EACE,GAAI;EAIJ,uBAAA;EACA,MAAM,QAAQ,MAAM;EACpB,eAAe,SAAU,OAAO,QAAQ,MAAM,KAAK,IAAI,QAAQ,MAAM,MAAM;EAChE;EACJ;EACP,YAAY,MAAM,YAAY,QAAQ,EAAE,OAAO,MAAM,WAAW,MAAM,IAAI,KAAA;EAE1E,UAAA,oBAAC,OAAD;GAAK,KAAK;GAAc,WAAW,WAAW,CAAC,CAAC,aAAa;GAC3D,UAAA,oBAAC,gBAAD;IAAgB,OAAO;IACrB,UAAA,oBAAC,iBAAD;KACE,OAAO;MACL,WAAW,QAAQ;MACnB;MACA;MACA;MACA,QAAQ;MACR;MACA,SAAS,MAAM;MACf,SAAS;MACT,OAAO;MACP,QAAQ;OAAE,GAAG;OAAgB,GAAG;MAAO;KACzC;KAEA,UAAA,oBAAC,UAAD;MACE,GAAI;MACJ,QAAO;MACE;MACT,OAAO;MACP,UAAA;MACA,SAAS,QAAQ,MAAM;MACvB,WAAW,QAAQ,MAAM,iBAAiB;KAC3C,CAAA;IACc,CAAA;GACH,CAAA;EACb,CAAA;CACU,CAAA;AAErB;AAwBA,MAAM,kBAAkB,cAA2C,IAAI;;AAGvE,MAAM,kBAAkB,cAAuD,IAAI;AAEnF,MAAM,iCAAiC,CAAC;;;;;;AAOxC,SAAS,oBAAoB,WAA0B,WAA8B;CACnF,OAAO,gBAAgB,WAAW,cAAc,KAAK;AACvD;AAIA,SAAS,YAAY,EACnB,SACA,SACA,WACA,WACA,YAAY,gBACZ,SAAS,GACT,mBAAmB,IACnB,SAAS,WACT,UAAU,YACV,QACA,WACA,OACA,GAAG,SAMF;CACD,MAAM,aAAa,OAAuB,IAAI;CAC9C,MAAM,CAAC,WAAW,gBAAgB,SAAgC,IAAI;CACtE,MAAM,aAAa,aAAa,YAAmC;EACjE,WAAW,UAAU;EACrB,aAAa,OAAO;CACtB,GAAG,CAAC,CAAC;CACL,MAAM,CAAC,aAAa,kBAAkB,SAAS,CAAC;CAEhD,MAAM,YAAY,qBAChB,0BAEE,QAAQ,WAAW,UAAU,iBAAiB,QAAQ,WAAW,OAAO,CAAC,CAAC,YAAY,aAClF,KACR;CAEA,MAAM,EAAE,QAAQ,WAAW,oBAAoB,UAAU;CACzD,MAAM,aACJ,cAAc,kBACV,SACA,oBAAoB,QAAQ,cAAc,QAAQ,QAAQ,KAAK;CACrE,MAAM,EACJ,cACA,eACA,WAAW,oBACT,WACF;EACE,YAAY,QAAQ;EACpB;EACA,WAAW,oBAAoB,WAAW,SAAS;EACnD;EACA;CACF,GACA,QAAQ,KACV;CACA,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,WAAW,kBAAkB,iBAAiB,SAAS;CAC7D,MAAM,QAAQ,QAAQ,MAAM;CAM5B,gBAAgB;EACd,MAAM,OAAO,WAAW,cAAc;EACtC,IAAI,CAAC,aAAa,CAAC,MAAM;EACzB,MAAM,aAAa,UAAyB;GAC1C,IAAI,MAAM,QAAQ,SAAS,MAAM,UAAU,MAAM,WAAW,MAAM,SAAS;GAC3E,IAAI,UAAU,SAAS,UAAU,cAAc,aAAa,GAAG,MAAM;EACvE;EACA,KAAK,iBAAiB,WAAW,WAAW,IAAI;EAChD,aAAa,KAAK,oBAAoB,WAAW,WAAW,IAAI;CAClE,GAAG,CAAC,WAAW,KAAK,CAAC;CACrB,MAAM,SAAS,WAAW;CAC1B,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,GAAI;EAAe,WAAU;CAAiB,CAAA,GACnD,qBAAC,OAAD;EACE,GAAI;EACJ,KAAK;EAGL,OAAO;GAAE,GAAG;GAAO,GAAG,aAAa;EAAM;EACzC,0BAAuB;EACvB,WAAW,OAAO,QAAQ,EAAE,OAAO,GAAG,cAAc,SAAS,EAAE,CAAC;EAPlE,UAAA;GASE,oBAAC,eAAD,EAAe,WAAW,QAAQ,MAAM,MAAQ,CAAA;GAChD,oBAAC,OAAD;IACE,GAAI;IACJ,KAAK;IACL,iBAAe,YAAY,KAAA;IAC3B,gBAAc,aAAa,KAAA;IAC3B,kBAAgB,mBAAmB,KAAA;IACnC,WAAW,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO;IAE1C,UAAA,oBAAC,gBAAD;KAAgB,OAAO;KACrB,UAAA,oBAAC,cAAD;MAAc,QAAQ;MACpB,UAAA,oBAAC,iBAAD;OACE,OAAO;QACL,WAAW,QAAQ;QACnB;QACA;QACA;QACA;QACA;QACA,SAAS,MAAM;QACf;QACA,OAAO;QACP,QAAQ;SAAE,GAAG;SAAgB,GAAG;QAAO;OACzC;OAEA,UAAA,oBAAC,UAAD;QACE,GAAI,WAAW,QAAQ,WAAW,KAAK;QAC/B;QACC;QACT,OAAO;QACP,SAAS,QAAQ,MAAM;QACvB,WAAW,QAAQ,MAAM,iBAAiB;OAC3C,CAAA;MACc,CAAA;KACL,CAAA;IACA,CAAA;GACb,CAAA;GACL,oBAAC,eAAD,EAAe,WAAW,QAAQ,MAAM,MAAQ,CAAA;EAC7C;CACL,CAAA,CAAA,EAAA,CAAA;AAEN;AAKA,MAAM,cAAc,OAAe,UACjC,UAAU,IAAI,SAAS,UAAU,IAAI,UAAU,UAAU,QAAQ,IAAI,SAAS;;AAGhF,MAAM,cAAc,cAA+B;CACjD,KAAK,aAAa,UAAU,aAAa;CACzC,QAAQ,aAAa,UAAU,aAAa;AAC9C;;AAGA,SAAS,SAAS,OAA0D;CAC1E,MAAM,SAA4C,CAAC;CACnD,IAAI,MAAsB,CAAC;CAC3B,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,WAAW;EAC3B,IAAI,IAAI,QAAQ,OAAO,KAAK,GAAG;EAC/B,MAAM,CAAC;EACP,OAAO,KAAK,IAAI;CAClB,OACE,IAAI,KAAK,IAAI;CAGjB,IAAI,IAAI,QAAQ,OAAO,KAAK,GAAG;CAC/B,OAAO;AACT;;;;;;AAqBA,SAAS,eAAe,KAAoC,SAAkB;CAC5E,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAC5C,sBAAsB;EACpB,MAAM,UAAU,IAAI;EACpB,IAAI,CAAC,WAAW,WAAW,CAAC,WAAW,OAAO,mBAAmB,aAAa;EAC9E,MAAM,WAAW,IAAI,qBAAqB;GACxC,IAAI,QAAQ,eAAe,QAAQ,eAAe,GAAG,WAAW,IAAI;EACtE,CAAC;EACD,SAAS,QAAQ,OAAO;EACxB,aAAa,SAAS,WAAW;CACnC,GAAG;EAAC;EAAK;EAAS;CAAO,CAAC;CAC1B,OAAO;AACT;AAEA,SAAS,SAAS,EAChB,eAAe,MACf,SACA,QAAQ,iBACR,SACA,OACA,YACA,SACA,WAAW,OACX,KAAK,cACL,GAAG,YACa;CAEhB,MAAM,EAAE,MAAM,MAAM,UAAU,eAAe,QAAQ;CAErD,yBACE,MAAM,UACN,QACA,iDACF;CACA,MAAM,OAAO,WAAW,eAAe;CAEvC,MAAM,QAAQ,aAAa;EACzB,GAAI;EACJ,wBAAwB,CAAC;EACzB,kBAAkB;CACpB,CAAC;CACD,MAAM,SAAS,aAAa,YAAY;CACxC,MAAM,MAAM,WAAW;CAEvB,MAAM,mBAAmB,qBAAqB,OAAO,GAAG;CACxD,MAAM,EAAE,cAAc,QAGpB;EAAE,GAAI;EAAmC;EAAkB,iBAAiB;CAAK,GACjF,OACA,GACF;CACA,MAAM,SAAS,SAAS,CAAC,GAAG,MAAM,UAAU,CAAC;CAE7C,MAAM,SADW,eAAe,KAAK,oBAAoB,KACvB,IAAI,YAAY;CAClD,MAAM,SAAS,WAAW;EAAE;EAAS;EAAQ;CAAS,CAAC;CAGvD,MAAM,QAAQ,CADM,QAAQ,QAAQ,KAAK,UAAU,kBAAkB,SAAS,CACrD,IAAI,KAAA,IAAY,MAAM,gBAAgB,QAAQ,WAAW;CAClF,MAAM,YAAY,MAAM;CAExB,OACE,oBAAC,OAAD;EACE,GAAI,WAAW,MAAM,WAAW,EAE9B,UAAU,UAAsC;GAC9C,IAAI,MAAM,cAAc,SAAS,MAAM,MAAM,GAAG,YAAY,KAAK;EACnE,EACF,CAAC;EACI;EACL,GAAI,iBAAiB,OAAO;EAC5B,eAAa,gBAAgB,iBAAiB,IAAI;EAClD,gBAAc;EACd,eAAa;EACb,cAAY;EACZ,WAAW,OAAO,KAAK,EAAE,OAAO,YAAY,MAAM,CAAC;EAEnD,UAAA,oBAAC,iBAAD;GAAiB,OAAO;GACrB,UAAA,OAAO,KAAK,OAAO,UAAU;IAC5B,MAAM,WAAW,WAAW,OAAO,OAAO,MAAM;IAGhD,MAAM,QACJ,WAAW,YACP;KAAE,KAAK,UAAU;KAAG,QAAQ,UAAU,OAAO,SAAS;IAAE,IACxD,WAAW,QAAQ;IACzB,MAAM,cAAc,WAAW;KAAE;KAAS;KAAQ,eAAe;KAAU,OAAO;IAAK,CAAC;IACxF,OACE,oBAAC,kBAAD;KAEE,SACE,WAAW,aAAa,QAAQ,IAE9B,oBAAC,SAAD;MACE,YAAY;MACZ,WAAW,OAAO,QAAQ,EAAE,OAAO,YAAY,QAAQ,CAAC;KACzD,CAAA,IACC;KAGL,UAAA,MAAM,QAAQ,KAAK,IAClB,oBAAC,OAAD;MACE,MAAK;MACL,WAAW,YAAY,MAAM,EAAE,OAAO,YAAY,MAAM,CAAC;MAEzD,UAAA,oBAAC,WAAD;OACE,OAAO;OACA;OACE;OACF;OACK;MACb,CAAA;KACE,CAAA,IAEL,oBAAC,aAAD;MACE,SAAS;MACF;MACE;MACT,WAAW,YAAY,MAAM,EAAE,OAAO,YAAY,MAAM,CAAC;MACzD,kBAAkB,YAAY,QAAQ,EAAE,OAAO,YAAY,QAAQ,CAAC;MAC7D;MACK;KACb,CAAA;IAEa,GAnCX,MAAM,QAAQ,KAAK,IAAI,MAAM,EAAE,CAAE,MAAM,MAAM,GAmClC;GAEtB,CAAC;EACc,CAAA;CACd,CAAA;AAET;AAEA,SAAS,iBAAiB,EAAE,SAAS,YAAyD;CAC5F,OACE,qBAAA,YAAA,EAAA,UAAA,CACG,SACA,QACD,EAAA,CAAA;AAEN;AAEA,SAAS,YAAY,EACnB,SACA,OACA,SACA,WACA,kBACA,OACA,cASC;CACD,MAAM,EAAE,WAAW,cAAc,eAAe,eAAe;EAC7D,SAAS,QAAQ;EACjB,cAAc,QAAQ;CACxB,CAAC;CACD,OACE,qBAAC,OAAD;EAAK,GAAI;EAAsB;EAA/B,UAAA,CACG,QAAQ,YACP,oBAAC,QAAD;GAAM,GAAI;GAAc,WAAW;GAChC,UAAA,QAAQ;EACL,CAAA,GAER,oBAAC,OAAD;GAAK,GAAI;GAAY,WAAU;GAC7B,UAAA,oBAAC,WAAD;IACE,OAAO,CAAC,GAAG,QAAQ,UAAU;IACtB;IACE;IAET,OAAO;KAAE,GAAG;KAAO,KAAK,CAAC,QAAQ,YAAY,MAAM;IAAI;IAC3C;GACb,CAAA;EACE,CAAA,CACF;;AAET;;;;;AAMA,SAAS,UAAU,EACjB,OACA,OACA,SACA,OACA,cAOC;CACD,OAAO,MAAM,KAAK,MAAM,UAAU;EAChC,MAAM,YAA+B;GACnC;GACA;GACA;GACA,KAAK,UAAU,KAAK,MAAM,MAAM,UAAU;GAC1C,QAAQ,UAAU,MAAM,SAAS,KAAK,MAAM,SAAS,UAAU;GAC/D;EACF;EACA,OAAQ,KAAK,MAA2B,UACtC,oBAAC,iBAAD,EAAgC,GAAI,UAAY,GAA1B,KAAK,GAAqB,IAEhD,oBAAC,cAAD,EAA6B,GAAI,UAAY,GAA1B,KAAK,GAAqB;CAEjD,CAAC;AACH;;AAiBA,SAAS,gBAAgB,OAA0B;CACjD,MAAM,OAAO,WAAW,eAAe;CACvC,MAAM,gBAAgB,WAAW,eAAe;CAChD,MAAM,EAAE,SAAS,iBAAiB,MAAM,KAAK;CAC7C,MAAM,eAAe,uBAAuB,EAAE,YAAY,MAAM,KAAK,IAAI,GAAG,KAAK,SAAS;CAC1F,MAAM,UAAU,OAAuB,IAAI;CAC3C,MAAM,aAAa,OAAuB,IAAI;CAC9C,MAAM,EAAE,qBAAqB,cAAc,iBAAiB,kBAC1D;EACE;EACA;EACA,OAAO;EACP,YAAY,MAAM,MAAM,aAAa,IAAI,MAAM,KAAK,GAAG;CACzD,GACA,cACA,OACF;CAEA,MAAM,EAAE,QAAQ,eAAe,GAAG,iBAAiB;CAInD,MAAM,UAAU,OAAO,MAAM;CAC7B,sBAAsB;EACpB,MAAM,SAAS,QAAQ,WAAW,CAAC;EACnC,QAAQ,UAAU;EAClB,MAAM,OAAO,QAAQ;EACrB,IAAI,CAAC,UAAU,CAAC,KAAK,SAAS,CAAC,KAAK,UAAU,UAAU,CAAC,MAAM;EAC/D,MAAM,SAAS,KAAK,cAAc;EAClC,IAAI,UAAU,QAAQ,WAAW,KAAK,cAAc,MAAM,KAAK,MAAM;CACvE,CAAC;CACD,OACE,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,cAAD;EACE,GAAI;EACJ,cAAc,KAAK,QAAQ,eAAe;GAAE,GAAG;GAAc;EAAc;EAClE;EACT,aAAa;CACd,CAAA,GACA,KAAK,QACJ,oBAAC,mBAAD;EACE,OAAO;EACK;EACZ,WAAW;EACF;EACT,OAAO,MAAM,KAAK;CACnB,CAAA,IAED,oBAAC,gBAAD;EACE,OAAO;EACP,YAAY;EACA;EACZ,WAAW;EACG;EACL;CACV,CAAA,CAEH,EAAA,CAAA;AAEN;;;;;;;;AASA,SAAS,kBAAkB,EACzB,OACA,YACA,WACA,SACA,SAGC;CACD,MAAM,OAAO,WAAW,eAAe;CACvC,IAAI,CAAC,MAAM,UAAU,CAAC,KAAK,WAAW,OAAO;CAC7C,MAAM,EAAE,cAAc,GAAG,kBAAkB;CAC3C,MAAM,MAAM,QAAQ;CACpB,MAAM,UAAU,IAAI,WAAW,KAAK;CACpC,MAAM,SAAS,WAAW,EAAE,QAAQ,CAAC;CACrC,OACE,oBAACA,WAAD;EAAS,iBAAiB,KAAK;EAAW,wBAAA;EACxC,UAAA,qBAAC,OAAD;GAAK,sBAAmB;GAAG,WAAW,OAAO,WAAW;GAAxD,UAAA,CACE,qBAAC,OAAD;IAAK,WAAW,OAAO,YAAY;IAAnC,UAAA,CACE,oBAAC,iBAAD;KACE,OAAO,KAAK,OAAO;KACnB,eAAe,MAAM,MAAM;KAC3B,WAAW,OAAO,UAAU;IAC7B,CAAA,GACD,oBAAC,QAAD;KAAM,WAAW,OAAO,WAAW;KAAI,UAAA;IAAY,CAAA,CAChD;GACL,CAAA,GAAA,oBAAC,UAAD;IACE,GAAI,WAAW,eAAe,GAAG;IACjC,SAAS;IACT,QAAO;IACE;IACT,SAAS,IAAI,WAAW,KAAK;IAC7B,OAAO,eAAe;IACtB,UAAA;IAEA,WAAW,MAAM,iBAAiB;GACnC,CAAA,CACE;;CACE,CAAA;AAEb;;AAGA,SAAS,gBAAgB,EACvB,OACA,SACA,aAKC;CACD,MAAM,MAAM,OAA0B,IAAI;CAC1C,MAAM,EAAE,aAAa,cAAc,UAAU;EAAE;EAAS,cAAc;CAAM,GAAG,GAAG;CAClF,MAAM,EAAE,kBAAkB,mBAAmB,iBAAiB,EAAE,UAAU,GAAG,GAAG;CAChF,OACE,oBAAC,UAAD;EACE,GAAI,WAAW,aAAa,gBAAgB;EAC5C,GAAI;EACC;EACM;EAEX,UAAA,oBAAC,UAAD,CAAW,CAAA;CACL,CAAA;AAEZ;AAWA,SAAS,eAAe,OAA4B;CAClD,MAAM,OAAO,WAAW,eAAe;CACvC,MAAM,WAAW,YAAY,MAAM,MAAM,MAAM;CAC/C,MAAM,YAAY,KAAK,UAAU,MAAM,MAAM,SAAS,SAAS;CAC/D,MAAM,YAAY,CAAC,KAAK,WAAW,SAAS;CAC5C,MAAM,EAAE,cAAc;CACtB,IAAI,CAAC,aAAa,CAAC,KAAK,WAAW,OAAO;CAG1C,OACE,oBAACA,WAAD;EAAS,iBAAiB,KAAK;EAAW,wBAAA;EAAuB,SAAS;EACxE,UAAA,oBAAC,uBAAD;GAAuB,GAAI;GAAkB;GAAsB;EAAY,CAAA;CACxE,CAAA;AAEb;AAEA,SAAS,sBAAsB,EAC7B,OACA,YACA,YACA,WACA,cACA,SACA,WACA,aACqE;CACrE,MAAM,OAAO,WAAW,eAAe;CACvC,MAAM,aAAa,OAAuB,IAAI;CAC9C,MAAM,EAAE,cAAc,GAAG,kBAAkB;CAC3C,MAAM,EAAE,cAAc,eAAe,cAAc,WACjD;EACE,GAAG;EAEG,SAAS;EACf;EACA;EACA,WAAW;EAGX,QAAQ;EACR,aAAa;CACf,GACA,KACF;CACA,MAAM,YAAY,OAAuB,IAAI;CAC7C,MAAM,WAAW,kBAAkB,WAAW,SAAS;CACvD,MAAM,EAAE,WAAW,OAAO,GAAG,QAAQ,QAAQ;CAC7C,MAAM,SAAS,WAAW;CAC1B,OAIE,oBAAC,OAAD;EACE,GAAI;EACJ,KAAK;EACL,OAAO;GAAE,GAAG;GAAO,GAAG,cAAc;EAAM;EAC1C,0BAAuB;EACvB,WAAW,OAAO,QAAQ,EAAE,OAAO,GAAG,cAAc,SAAS,EAAE,CAAC;EAEhE,UAAA,oBAAC,OAAD;GACE,GAAI;GACJ,KAAK;GACL,iBAAe,YAAY,KAAA;GAC3B,gBAAc,aAAa,KAAA;GAC3B,kBAAgB,aAAa,KAAA;GAC7B,WAAW,WAAW,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO;GAExD,UAAA,oBAAC,UAAD;IACE,GAAI,WAAW,eAAe,GAAG;IACjC,SAAS;IACT,QAAQ,IAAI,UAAU,KAAK;IAC3B,SAAS,IAAI,WAAW,KAAK;IAC7B,SAAS,IAAI,WAAW,KAAK;IAC7B,OAAO,eAAe;GACvB,CAAA;EACE,CAAA;CACF,CAAA;AAET;AAEA,SAAS,aAAa,EACpB,MACA,OACA,SACA,KACA,QACA,YACA,cACA,SACA,cAAc,SACM;CACpB,MAAM,SAAS,OAAoB,IAAI;CACvC,MAAM,MAAM,WAAW;CACvB,MAAM,QAAQ,KAAK;CACnB,MAAM,aAAa,MAAM,aAAa,IAAI,KAAK,GAAG;CAElD,MAAM,aAAa,MAAM,iBAAiB,kBAAkB,UAAU,MAAM,cAAc;CAC1F,MAAM,oBAAoB,MAAM,iBAAiB,kBAAkB,UAAU,CAAC;CAC9E,MAAM,WAAW,cAAc,MAAM,iBAAiB,kBAAkB;CACxE,MAAM,EACJ,eAAe,eACf,uBACA,YACA,cACE,YACF;EACE,GAAG;EACH,KAAK,KAAK;EACV,cAAc,MAAM;EAEpB;EACA,YAAY,oBAAoB,QAAQ,KAAA;EAGxC,eAAe,WAAW,QAAQ,oBAAoB,OAAO,KAAA;CAC/D,GACA,OACA,GACF;CACA,MAAM,gBACJ,qBAAqB,CAAC,MAAM,UACxB;EAAE,GAAG;EAAe,MAAM;EAAY,gBAAgB,KAAA;CAAU,IAChE;CAIN,MAAM,OAAO,MAAM,QAAQ,QAAQ,CAAC,cAAc,CAAC,MAAM;CAEzD,MAAM,OAAQ,OAAO,MAAM;CAC3B,MAAM,iBAAiB,OACnB,EAAE,KAAK,MAAM,QAAQ,MAAM,WAAW,WAAW,wBAAwB,KAAA,GAAW,IACpF;CACJ,MAAM,EAAE,kBAAkB,mBAAmB,iBAC3C;EAAE;EAAW;EAAY;CAAW,GACpC,GACF;CACA,MAAM,SAAS,WAAW;EACxB;EACA,SAAS;EACT,YAAY;EACZ,gBAAgB,QAAQ,MAAM,WAAW;CAC3C,CAAC;CACD,MAAM,eAAe,MAAM,iBAAiB,aAAa,oBAAC,WAAD,CAAY,CAAA,IAAI;CACzE,MAAM,eAAe,MAAM,iBAAiB,MAAM,UAAU,oBAAC,aAAD,CAAc,CAAA,IAAI;CAC9E,MAAM,UAAU,MAAM;CAMtB,MAAM,cACJ,CAAC,MAAM,WAAW,sBAAsB,KAAK,KAAA,GAAW,MAAM,QAAQ,UAAU,KAAA,CAAS,CAAC,CACvF,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,KAAK,KAAA;CAElB,OACE,qBAAC,MAAD;EACE,GAAI,WAAW,eAAe,gBAAgB;EAC9C,GAAI;EACJ,GAAI;EACJ,mBAAiB,KAAA;EACjB,oBAAkB;EAClB,kBAAgB,eAAe,KAAA;EAE/B,eAAa,gBAAgB,iBAAiB,aAAa;EAC3D,gBAAc;EACd,aAAU;EACL;EACL,WAAW,OAAO,KAAK,EAAE,OAAO,GAAG,YAAY,MAAM,MAAM,SAAS,EAAE,CAAC;EAZzE,UAAA;GAcG,MAAM,eAAe,eACpB,oBAAC,QAAD;IACE,eAAY;IACZ,aAAU;IACV,WAAW,OAAO,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;IAEjD,UAAA,aAAa,eAAe,MAAM;GAC/B,CAAA,IACJ,MAAM,cACR,oBAAC,QAAD;IACE,eAAY;IACZ,aAAU;IACV,WAAW,OAAO,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;IAEjD,UAAA,MAAM;GACH,CAAA,IACJ,eAEF,oBAAC,QAAD;IAAM,eAAY;IAAO,WAAW,OAAO,aAAa;IACtD,UAAA,oBAAC,QAAD;KAAM,WAAW,OAAO,kBAAkB;KACxC,UAAA,oBAAC,QAAD;MAAM,WAAW,OAAO,KAAK,EAAE,OAAO,YAAY,KAAK,CAAC;MAAI,UAAA;KAAmB,CAAA;IAC3E,CAAA;GACF,CAAA,IACJ;GACJ,qBAAC,QAAD;IAAM,WAAW,OAAO,KAAK;IAA7B,UAAA,CACE,oBAAC,QAAD,EAAA,UAAO,KAAK,SAAe,CAAA,GAC1B,MAAM,eACL,oBAAC,QAAD;KAAM,WAAW,OAAO,YAAY,EAAE,OAAO,YAAY,YAAY,CAAC;KACnE,UAAA,MAAM;IACH,CAAA,CAEJ;;GACL,MAAM,SACL,oBAAC,QAAD;IAAM,IAAI;IAAS,eAAY;IAAO,WAAW,OAAO,MAAM;IAC3D,UAAA,MAAM;GACH,CAAA;GAEP,MAAM,YACL,oBAAC,OAAD;IACE,GAAI;IACJ,eAAY;IACZ,WAAW,OAAO,SAAS,EAAE,OAAO,GAAG,cAAc,YAAY,QAAQ,EAAE,CAAC;IAE3E,UAAA,MAAM;GACJ,CAAA;GAEN,gBACC,oBAAC,QAAD;IACE,eAAY;IACZ,aAAU;IACV,WAAW,OAAO,SAAS,EAAE,OAAO,YAAY,aAAa,CAAC;IAE7D,UAAA;GACG,CAAA;EAEJ;;AAEV"}