@astryxdesign/core 0.7.2-canary.fdd384f → 0.7.2

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 (132) hide show
  1. package/CHANGELOG.md +156 -2
  2. package/README.md +4 -4
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +8 -1
  5. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  6. package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
  7. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  8. package/dist/Chat/ChatLayoutScrollButton.js +1 -0
  9. package/dist/CheckboxList/CheckboxList.d.ts +1 -1
  10. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  11. package/dist/CheckboxList/CheckboxList.js +6 -2
  12. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
  13. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  14. package/dist/DropdownMenu/DropdownMenu.js +38 -110
  15. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -1
  16. package/dist/DropdownMenu/DropdownMenuGroup.d.ts +6 -4
  17. package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
  18. package/dist/DropdownMenu/DropdownMenuGroup.js +4 -3
  19. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  20. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +24 -0
  21. package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -0
  22. package/dist/DropdownMenu/lazyMenuBottomSheet.js +46 -0
  23. package/dist/DropdownMenu/menuRegionStops.d.ts +38 -0
  24. package/dist/DropdownMenu/menuRegionStops.d.ts.map +1 -0
  25. package/dist/DropdownMenu/menuRegionStops.js +131 -0
  26. package/dist/FormLayout/FormLayout.d.ts +5 -4
  27. package/dist/FormLayout/FormLayout.d.ts.map +1 -1
  28. package/dist/FormLayout/FormLayout.js +1 -1
  29. package/dist/FormLayout/FormLayoutContext.d.ts +3 -3
  30. package/dist/FormLayout/FormLayoutContext.js +3 -3
  31. package/dist/Grid/Grid.d.ts +8 -7
  32. package/dist/Grid/Grid.d.ts.map +1 -1
  33. package/dist/Grid/Grid.js +5 -4
  34. package/dist/Grid/GridSpan.d.ts +1 -1
  35. package/dist/Markdown/parser.d.ts.map +1 -1
  36. package/dist/Markdown/parser.js +8 -2
  37. package/dist/Markdown/plugins/headingLinks.d.ts.map +1 -1
  38. package/dist/Markdown/plugins/headingLinks.js +9 -1
  39. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  40. package/dist/PowerSearch/PowerSearch.js +5 -0
  41. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  42. package/dist/PowerSearch/PowerSearchValueEditor.js +45 -11
  43. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  44. package/dist/SideNav/SideNavItem.js +6 -2
  45. package/dist/Token/Token.js +1 -1
  46. package/dist/TopNav/TopNavMegaMenu.js +2 -0
  47. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  48. package/dist/TopNav/TopNavMenu.js +2 -0
  49. package/dist/astryx.css +1 -1
  50. package/dist/reset.a11y.chromium.spec.js +50 -1
  51. package/docs.mjs +4 -4
  52. package/package.json +4 -4
  53. package/scripts/agent-doc-state.mjs +66 -6
  54. package/scripts/postinstall.mjs +44 -3
  55. package/src/Avatar/Avatar.tsx +11 -2
  56. package/src/AvatarGroup/AvatarGroupOverflow.test.tsx +24 -1
  57. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -0
  58. package/src/Chat/ChatLayoutScrollButton.test.tsx +13 -0
  59. package/src/Chat/ChatLayoutScrollButton.tsx +4 -2
  60. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +64 -19
  61. package/src/CheckboxList/CheckboxList.fr10.test.tsx +29 -2
  62. package/src/CheckboxList/CheckboxList.tsx +4 -1
  63. package/src/Code/Code.doc.mjs +1 -0
  64. package/src/CommandPalette/CommandPalette.doc.mjs +2 -0
  65. package/src/ContextMenu/ContextMenu.test.tsx +12 -2
  66. package/src/Drawer/Drawer.doc.mjs +1 -0
  67. package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +57 -0
  68. package/src/DropdownMenu/DropdownMenu.test.tsx +17 -5
  69. package/src/DropdownMenu/DropdownMenu.tsx +43 -142
  70. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +1 -1
  71. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -1
  72. package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +169 -10
  73. package/src/DropdownMenu/DropdownMenuGroup.tsx +6 -4
  74. package/src/DropdownMenu/DropdownMenuLazySheet.test.tsx +126 -0
  75. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +1 -1
  76. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
  77. package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +334 -0
  78. package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +43 -0
  79. package/src/DropdownMenu/lazyMenuBottomSheet.ts +71 -0
  80. package/src/DropdownMenu/menuRegionStops.ts +167 -0
  81. package/src/Field/FieldLabel.doc.mjs +133 -26
  82. package/src/Field/FieldLabel.spec.md +172 -0
  83. package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +296 -0
  84. package/src/FormLayout/FormLayout.doc.mjs +6 -3
  85. package/src/FormLayout/FormLayout.spec.md +192 -0
  86. package/src/FormLayout/FormLayout.test.tsx +15 -0
  87. package/src/FormLayout/FormLayout.tsx +7 -6
  88. package/src/FormLayout/FormLayoutContext.ts +3 -3
  89. package/src/Grid/Grid.doc.mjs +7 -1
  90. package/src/Grid/Grid.spec.md +93 -113
  91. package/src/Grid/Grid.test.tsx +22 -0
  92. package/src/Grid/Grid.tsx +10 -9
  93. package/src/Grid/GridSpan.doc.mjs +3 -3
  94. package/src/Grid/GridSpan.tsx +1 -1
  95. package/src/Icon/Icon.doc.mjs +36 -0
  96. package/src/Indicator/Indicator.doc.mjs +3 -3
  97. package/src/Layout/LayoutHeader.doc.mjs +5 -0
  98. package/src/Markdown/parser.ts +8 -2
  99. package/src/Markdown/plugins/headingLinks.ts +9 -1
  100. package/src/MetadataList/MetadataList.doc.mjs +1 -1
  101. package/src/MoreMenu/MoreMenu.test.tsx +5 -1
  102. package/src/PowerSearch/PowerSearch.test.tsx +62 -0
  103. package/src/PowerSearch/PowerSearch.tsx +9 -0
  104. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +71 -0
  105. package/src/PowerSearch/PowerSearchValueEditor.tsx +45 -0
  106. package/src/ProgressBar/ProgressBar.doc.mjs +1 -0
  107. package/src/Resizable/useResizable.doc.mjs +2 -0
  108. package/src/ScrollableArea/ScrollableArea.doc.mjs +1 -1
  109. package/src/SideNav/SideNav.spec.md +227 -0
  110. package/src/SideNav/SideNav.test.tsx +41 -0
  111. package/src/SideNav/SideNavItem.tsx +5 -2
  112. package/src/Spinner/Spinner.doc.mjs +1 -1
  113. package/src/Table/Table.spec.md +6 -1
  114. package/src/Table/plugins/activation/useTableActivation.spec.md +254 -0
  115. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  116. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +4 -0
  117. package/src/Token/Token.tsx +1 -1
  118. package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +86 -0
  119. package/src/Toolbar/Toolbar.test.tsx +0 -8
  120. package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +163 -0
  121. package/src/Toolbar/__tests__/Toolbar.a11y.renders.tsx +63 -0
  122. package/src/Toolbar/__tests__/Toolbar.a11y.states.ts +142 -0
  123. package/src/Toolbar/__tests__/Toolbar.a11y.test.tsx +126 -0
  124. package/src/TopNav/TopNavMegaMenu.test.tsx +25 -0
  125. package/src/TopNav/TopNavMegaMenu.tsx +2 -0
  126. package/src/TopNav/TopNavMenu.test.tsx +27 -1
  127. package/src/TopNav/TopNavMenu.tsx +2 -0
  128. package/src/postinstall.test.mjs +79 -0
  129. package/src/reset.a11y.chromium.spec.ts +52 -1
  130. package/src/reset.css +9 -0
  131. package/src/reset.test.ts +11 -0
  132. package/src/unicodePropertyEscapes.source-build.test.mjs +69 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,159 @@
1
1
  # @xds/core
2
2
 
3
+ # 0.7.2
4
+
5
+ #### Experimental APIs
6
+
7
+ - Drawer's full-viewport mobile coverage ships as experimental: `experimental={{isFullWidthOnMobile: true}}` fills the viewport below 640px instead of keeping the 56px page reveal. Anything inside Drawer's `experimental` prop may change or be removed in a patch release; omitting it keeps the stable behavior.
8
+
9
+ #### New Components
10
+
11
+ - Promote `Drawer` and `DrawerHeader` from the canary-only Lab package to Core, imported from `@astryxdesign/core/Drawer` or the package root. The stable package now ships the full-height side panel with modal and non-modal presentation, the shared dismissal stack, Dialog's `purpose` dismissal policy, a `DrawerHeader` whose close button appears when given `onOpenChange`, and Dialog-style container padding (`--spacing-4` by default, `padding` prop, or a theme's `drawer` padding), plus Core documentation and runnable examples. Canary users importing from `@astryxdesign/lab` switch to `@astryxdesign/core/Drawer`.
12
+
13
+ #### New Features
14
+
15
+ - An integration can set the command its users run the CLI with: a new `cliCommand` field in `astryx.integration.*`, such as `cliCommand: 'acme astryx'`. In a project that loads that integration, every command the CLI prints starts with it instead of the package-manager prefix (`npx astryx`, `pnpm exec astryx`): next-step hints, errors, suggestions, Doctor fixes, `--help`, the setup reminder, the agent-docs block, and doc text. If two loaded integrations set different commands, neither is used, and the new `cli-command` check in `astryx doctor` warns. An invalid `cliCommand` is ignored with an `invalid_cli_command` warning; the rest of the manifest still loads.
16
+ Docs, including an integration's, are now written with bare `astryx ...` commands, and `astryx docs` prefixes them for the project when it prints them. JSON output keeps every command bare, as before. The install-time setup reminder from `@astryxdesign/core` and `@astryxdesign/cli` names the command the project's package manager runs, instead of always `npx @astryxdesign/cli`.
17
+ - Adds the `@astryx.diffViewer.*` keys to the `en` catalog so the lab `DiffViewer` reads its file-status badges, line counts, line-number button labels, per-line "Added"/"Removed" labels, and empty-state messages from the translation runtime. No existing string changes; locales without a translation fall back to English.
18
+ - `Item` accepts `align="first-line"`, which centers each start and end slot on the label's first line. A small status dot, radio, checkbox, or timestamp beside a wrapping label now stays level with the first line, where `center` drops it to the middle of the row and `start` leaves it above the line. A slot taller than the first line moves the text down rather than leaving the row, and a one-line row with no description looks the same as `center`. `ListItem`, `RadioListItem`, and `CheckboxListItem` accept the same `align` and pass it to their row. Themes can style these rows through the `item` target's `align` axis. The default stays `center`, so existing rows don't change.
19
+ - i18n catalog: add the English messages used by the Lab CommentComposer for its input, image upload, inline quote, emoji action, cancel action, and retry affordance.
20
+ - i18n catalog: add the English messages used by the Lab CommentThread for replies, reactions, edit history, resolution, errors, comment actions, and the unsaved-draft warning it announces when a dismissal would discard a reply or edit.
21
+ - i18n catalog: add the English messages used by the Lab Comments panel for its region, empty/loading states, pagination, and posting errors.
22
+ - i18n catalog: add the English messages used by the Lab EmojiPicker so locale catalogs and provider overrides can replace its labels, search status, loading state, and group names.
23
+ - `List`: add `edge` to choose where each row's text, dividers, and hover and selection backgrounds sit. `padded` (default) keeps today's look. `flush` drops the rows' side padding, so text and dividers start on the same line as the list header and a heading above, with no container needed. `outset` keeps backgrounds' room around the text while reaching into the padding of a Card, Section, or Dialog, so text lands on the heading's line. `bleed` reaches rows to the container's edges with square corners, like Table rows in a Card. `edgeCompensation="inline"` is deprecated in favor of `edge="outset"` and keeps working; its rows' outer room is no longer cut off by the list's swipe clip. Run `astryx upgrade` to rename it.
24
+ - `Pagination`: `variant="compact"` shows first/last buttons around previous/next when `hasFirstLast` is `true` and the page count is known. Compact still omits them by default, and the `input` variant still shows them unless `hasFirstLast` is `false`.
25
+ - `reset.css`: in Chromium, the dropdown marker of an `<input>` with a `list` sits in the middle of the field. Chromium sets the marker on the field's line-height, so above a line-height of 1 it sits low, and the reset makes every field inherit the page's 1.5: the marker sat 3.5px below the middle of a 40px field, and further down on taller lines. Date and time fields, whose calendar icon uses the same part, keep their icon where it was. To keep the old placement, add `input[list]::-webkit-calendar-picker-indicator { line-height: inherit; }` after the reset.
26
+ - `SideNavItem`: nested items now span the full width of the nav list, like top-level items, so their hover and selected fill lines up with the rows above them. Before, a nested item started 24px in from the list edge. The indent now sits inside the row, one `--spacing-6` step per nesting level, so icons and labels stay exactly where they were. The indent area is now part of the nested row, so it shows hover feedback and clicking it activates the item. Content placed directly inside a `SideNavItem` that is not itself a `SideNavItem` is no longer inset by the children group. There is no supported way to keep the old inset look.
27
+ - `TabMenu` passes host attributes and DOM event handlers to its trigger button. The trigger keeps its button semantics, tab stop, and menu disclosure attributes; a caller's `onClick` runs after the menu toggle.
28
+ - Tables draw a line on every cell edge, not only between rows, on both `Markdown` and the RichText surfaces, and the grid closes at the table's rim. A reader following one row across never needed vertical lines, but someone editing a table has to aim at a cell and judge where a selection stops, and the empty 3×3 a toolbar insert produces was three horizontal rules with no sign it had three columns. The line is the same `--color-border` already used between rows, the rim merges with it into one rule rather than doubling at the edge, and both surfaces move together — the read and edit renderings match block for block, more closely than before.
29
+ - `TreeList`: nested rows now span the full width of the list, like root rows, so their hover and selected fill lines up with the rows above them. Before, a nested row started at its indent. The indent now sits inside the row, so chevrons, icons and labels stay exactly where they were. The indent area is now part of the row, so it shows hover feedback, and clicking it activates the row: clicking a folder's indent toggles the folder, and clicking a row whose only action is its link anywhere outside its label follows the link, as Enter already did: modifier keys are kept, so Cmd/Ctrl-click opens a new tab, and a middle-click opens one too. Controls in a row's start or end content keep their own clicks, including role-based ones such as a `role="switch"` element, which no longer also toggle the row or run its `onClick`. Guide lines draw above the rows, so a hover or selected fill doesn't break them, and they let clicks pass through to the row underneath. The one exception is a row with keyboard focus: it draws above the guides so they never cut its focus ring, which means that if it is also filled (selected or hovered), its fill covers the guides at that row. Padding set on a row through the `tree-list-item` theme target or an item's `className`, `style` or `xstyle` still composes with the indent. `--tree-list-indent` still retunes the indent step. There is no supported way to keep the old inset rows.
30
+
31
+ #### Fixes
32
+
33
+ - Allow MetadataList label width without an explicit position while preserving single- and multi-column label defaults (#6310)
34
+ - AppShell: defer hiding the mobile nav's Activity boundary until its close animation finishes (#5701)
35
+ `AppShell` mounts the mobile nav drawer inside a `React.Activity` boundary that flipped to `mode="hidden"` in the same commit as the drawer closing. React's `Activity` hides its subtree with `display: none !important` synchronously and re-runs the cleanup of every effect inside it, which cut off `MobileNav`'s own slide-out CSS transition and cancelled its delayed `dialog.close()` before either could run. The drawer still closed correctly (a safety-net effect force-closed the native dialog on that same cleanup), just with the close animation skipped entirely.
36
+
37
+ `AppShell` now holds the `Activity` boundary visible for a beat after the drawer closes, strictly longer than `MobileNav`'s own worst-case close delay, so `MobileNav`'s normal close effect gets a real chance to run its transition and its own timed `dialog.close()` before `Activity` ever hides the subtree.
38
+
39
+ `MobileNav` also keeps its dialog rendered from the commit that closes it until its delayed `close()` has run, instead of relying on the dialog's discrete `display` transition to do so. A browser that does not hold that transition (WebKit) dropped the dialog to `display: none` at once while it was still an open modal, so for about 200ms nothing was visible and the page stayed inert. The slide-out itself is unchanged.
40
+
41
+ - `AspectRatio`'s `fit="cover"` and `fit="contain"` now fill the box on the documented Tailwind setups. The fit rules lived in `reset.css`, in the `reset` layer, and the setup guides put Tailwind's preflight in a layer above it, so preflight's `img, video { height: auto }` won and a fitted image kept its own aspect ratio. The fit sizing now ships with the component's own styles in `astryx-base`: above preflight, and below Tailwind's utilities, so a utility class on the child still wins. `reset.css` no longer carries AspectRatio rules.
42
+ With `fit="cover"` or `fit="contain"`, a direct child's own Astryx styles (an Astryx component's own size or `object-fit`) no longer override the fill. To keep a child's own size, set it with an inline style, unlayered CSS or a rule in a later layer, or leave `fit` unset.
43
+ - The static `AvatarGroupOverflow` chip (no `onClick`) is exposed to assistive technology as an image named by its count label ("5 more"). Before, it was a span with an `aria-label` but no role, a name the generic role does not allow, so screen readers could skip the count. This meets WCAG 2.2 SC 4.1.2 Name, Role, Value. Nothing changes visually; the clickable chip stays a button, and a `role` passed by the caller still wins.
44
+ - `Button` (and `IconButton`) no longer use the native `disabled` attribute while a busy state (`isLoading`, or a non-interruptible `clickAction` in flight) is the only reason the button can't be clicked. A natively disabled element can't hold focus, so the browser moved focus to `<body>` the instant an action started and never restored it — the classic reason busy state should be visual-only. Busy now uses `aria-disabled` (button stays focusable) with `aria-busy` and the spinner, matching the documented "Disabled vs Busy" API convention and the behavior input components already follow. `isDisabled` (and `isDisabled` together with a busy state) is unchanged — that still uses native `disabled`. `isInterruptible` is also unchanged.
45
+ `aria-disabled`, unlike native `disabled`, still lets the button dispatch a click — the busy guard already called `preventDefault()` to block the button's own action, but a click on a busy button could still bubble to a wrapping ancestor's own click handler (a clickable row, card, or backdrop), which the previous native-`disabled` behavior never allowed. `handleClick` now also calls `stopPropagation()` in that guard, containing an unavailable click at the Button boundary the way a natively disabled control always did.
46
+
47
+ The `href`-rendered anchor path had the same gap for keyboard activation: it only wired `onClick` to the busy guard, not `onKeyDown`, so a consumer's own `onKeyDown` still received Enter/Space on a busy-only anchor Button while it was announced `aria-disabled`. The anchor path now wires the same `handleKeyDown` suppression the button path already had, so Enter/Space are swallowed and every other key still reaches the consumer, on both render paths.
48
+
49
+ - `ChatLayoutScrollButton`: the scroll-to-bottom pill now gives up keyboard focus, and refuses new focus, as soon as it starts to hide. Previously focus stayed on the fading pill for about half a second, until `visibility: hidden` applied, so it could sit on a control that was fading out or already transparent (WCAG 2.2 SC 2.4.7 Focus Visible). (#7738)
50
+ - Preserve caller-provided IDs on CheckboxInput and keep labels associated with the native input.
51
+ - CheckboxList keeps a caller's `aria-labelledby`. The group always replaced it with its own label id, so the caller's ids never reached the accessible name. The group is now named by its label and then the caller's ids, the same order RadioList and TimeInput use.
52
+ - The setup reminder, the swizzle StyleX note, and one doctor line say only what is true
53
+ - `CommandPaletteInput`: the query field now draws the shared keyboard focus ring. Previously it suppressed the browser outline without replacing it, so keyboard users could not see which field held focus.
54
+ - Source builds through Next.js's Babel no longer fail with `Unknown property: L` (or `Zs`, `Letter`) when the app sets no browserslist or targets a browser without Unicode property escapes. `Avatar`'s initials and the Markdown parser's emphasis and heading-link rules now build their `\p{…}` regular expressions at runtime, as `NumberInput` already does, so there is no literal for Babel to rewrite. Matching is unchanged.
55
+ - `DrawerHeader` now renders numeric zero `startContent` inside its start slot and preserves numeric zero `endContent` when no close button is present.
56
+ - `Drawer` now slides from the correct logical edge when `dir="rtl"` is set directly on the drawer, matching inherited right-to-left regions.
57
+ - `DropdownMenuDivider` now forwards host attributes and DOM handlers (`id`, `data-*`, `aria-*`, event handlers) to its separator, as other DOM-owning components do. Before, it accepted only `xstyle`, `className`, `style` and `ref` and dropped everything else, so a separator could not carry a test id or an accessible label. Its `role="separator"` and orientation stay component-owned.
58
+ - DropdownMenu: load the touch bottom sheet only when a menu shows it
59
+ `DropdownMenu` imported its touch sheet (BottomSheet, its gestures, and the touch action list) up front, so every page with a dropdown shipped it, even when the menu only ever opens as an anchored popover. The sheet now loads on demand, the way `ContextMenu` already loads it. A popover-only dropdown's own code drops by about a third (about 23 KB gzipped). Bottom-sheet and adaptive menus behave as before. The sheet starts loading when the trigger mounts, and a menu opened from the keyboard before it arrives still focuses its first action once it loads.
60
+ - `EmptyState` no longer leaves blank icon or action spacing when those optional slots receive a boolean or an empty string. An empty description also omits its theme target. The docs now describe configurable heading levels and map the container anatomy to the public theme target.
61
+ - Keep `Field`'s horizontal-label layout marker authoritative when callers pass conflicting data attributes, and keep hidden descriptions visually hidden in that layout. Correct its custom label-icon type, all three status placements, complete anatomy, and guidance for controls that cannot safely use attached status.
62
+ - `FieldStatus` (and any element using `useEntryAnimation`) no longer causes a hydration mismatch on server-rendered pages. An element that arrives in the server's HTML now hydrates without the entry style and never plays its entry animation, even when hydration runs after the page has painted; elements mounted after hydration still animate. `useEntryAnimation` no longer documents server rendering as unsupported.
63
+ - Keep `FormLayout`'s direction metadata authoritative when callers pass conflicting data attributes.
64
+ - `GridSpan` keeps its content inside the span. A child whose min-content width is wider than the span, such as a `Tokenizer` with a long token, used to stretch the span's column past the grid cell; it now gets the span's width and truncates the way it does outside a Grid (#7438)
65
+ - Keep `Grid`'s theming metadata authoritative when callers pass conflicting data attributes.
66
+ - `useHoverCard`: closing a hover card with `hide()` or Escape while the pointer rests on the card no longer leaves the next open stuck. The hook kept believing the pointer was still over the card, because a card closed that way unmounts without a `mouseleave`, so the trigger's next hover-open never closed on leave or after `hideDelay`. Both paths now clear that state, as the touch dismissal already did.
67
+ - Compute ISO week numbers (`Calendar hasWeekNumbers`, `getWeekNumber`) on UTC anchors instead of local-time `Date` arithmetic. In timezones whose DST ends after New Year (Sydney, Auckland, Santiago), the local-millisecond difference between the week's Thursday and January 1 carried the DST offset, and in years whose January 1 is a Friday that extra hour rounded a whole week up: the entire ISO week 14 of April 2021 displayed as week 15. Week numbers are now identical in every timezone.
68
+ - Anchored layers (`Popover`, `DropdownMenu`, and every component built on them) now keep their safe-area gutter and dynamic-viewport size cap in the shipped stylesheet. The compiled CSS referenced an undefined variable for the preferred value, so every browser used the fallback: on a phone with a dynamic toolbar or a notch, a tall layer could run past the visible screen or under a declared bottom bar. Desktop sizes are unchanged.
69
+ - `createMarkdownFrontmatter` now hands its `parse` function a plain object, so a parser that returns the decoded fields unchanged (`parse: fields => fields`) is accepted as metadata. Before, the record had no prototype, failed the JSON-like metadata check, and the document fell back to readable text with its frontmatter still showing.
70
+ - `MultiSelector`: the row action cell the keyboard reaches with the inline-end arrow draws the standard focus ring. Before, its outline read four CSS variables that nothing declared, so no ring showed on the active action cell.
71
+ - PowerSearch: clear every filter with one press of the clear-all button instead of removing only the last filter.
72
+ - Prevent pressing a built-in PowerSearch filter token with the mouse from opening search suggestions before the filter editor. Token editing, removal, and keyboard navigation retain their existing behavior.
73
+ - Keep built-in PowerSearch value controls disabled in read-only filter editors, matching custom editors.
74
+ - RadioList keeps a caller's `aria-labelledby`. The radiogroup always replaced it with its own label id, so the caller's ids never reached the accessible name. The group is now named by its label and then the caller's ids, the same order TimeInput uses.
75
+ - Restore focus to the element that opened a Dialog when its content mounts in the open commit. The opener was captured in the Dialog's passive effect, which runs after a freshly mounted DialogHeader's autofocus effect had already moved focus to the dialog's own title — closing then restored focus to that detached title and the user's focus landed on `<body>`. The capture now runs in a layout effect, before any descendant's passive effect. (#5637)
76
+ - `astryx search` finds more of what a reader means when the words differ from the catalog's.
77
+ - `astryx search` ranks a match on more of your words above a shorter named entry.
78
+ - `SideNavItem` keeps a caller's `className` on its row element (the link or button, and the collapsed rail item) next to its own classes. Before, the row's generated class replaced it, so a class passed to style the row (for example, a cursor while a row is dragged) never reached the DOM, even though `style`, ARIA, data attributes and handlers did.
79
+ - Shrink Token's invisible remove-button target from 44px to 24px without changing the visible icon. Clicking adjacent text or values in PowerSearch now edits the filter instead of accidentally removing it.
80
+ - DropdownMenu submenu flyouts close with their menu when it is light-dismissed: previously a submenu opened by tap or a fast click stayed open (and re-anchored to the viewport corner) after the menu was dismissed and reopened. A hover-open scheduled on a submenu trigger before the menu closed from elsewhere is also cancelled, so it can no longer reopen a flyout behind the dismissed menu
81
+ - `Switch` now adds a caller's `aria-describedby` to the switch control, ahead of its own description, status, and disabled-reason ids. Before, the value landed on the field wrapper, so a hint rendered elsewhere on the page could not describe the switch to assistive technology.
82
+ - `Switch` now puts a caller's `aria-labelledby` on the switch control. Before, the value landed on the field wrapper, so a visible title elsewhere in the row could not name the switch for assistive technology.
83
+ - A truncated `Text` or `Heading` (`maxLines`) now re-measures when its content changes, not only when its box resizes. A fixed-width single-line status whose message changed kept showing the first message in its truncation tooltip, and a new short message could keep a tooltip while a new long one lacked one. `useTruncation` now also observes the element's text, so the tooltip text and the truncated state follow the current content.
84
+ - `ToggleButton` keeps toggling when it also receives an `onClick`, for example from a wrapper that renders it as its trigger. That `onClick` used to replace the toggle's own click handling, so `onPressedChange` never ran and a `ToggleButtonGroup` member never asked its group to toggle (`pressedChangeAction` still ran). The caller's `onClick` now runs first and the toggle request follows. On a standalone `ToggleButton`, calling `preventDefault()` in that `onClick` cancels the request: neither `onPressedChange` nor `pressedChangeAction` runs.
85
+ - `useTooltip` (and every component built on it, such as `Button`'s `tooltip` prop) now drops a show that is still waiting out its delay when `isEnabled` turns `false`. Before, hovering a trigger and then disabling its tooltip within the delay let the timer fire anyway: the tooltip opened after its triggers were turned off, with no pointer-leave listener left to close it. A pending hide still runs, and an enabled tooltip is unchanged.
86
+ - Tooltip: an icon-only trigger now opens instead of throwing. The layer passed its trigger to `showPopover` as the invoker `source`, which the Popover API declares as an `HTMLElement`; a caller-rendered icon is an `SVGElement`, whose dictionary conversion throws before the popover opens, so the hint never appeared. An icon trigger now reaches `showPopover` without a source — positioning is unchanged, since the layer is anchored by its anchor-name pair, and only the invoker's focus order is given up.
87
+ - A collapsed `TopNavMenu` or `TopNavMegaMenu` section in the mobile drawer is now `inert` and hidden from assistive technology, so Tab no longer moves focus onto links that are not shown and screen readers no longer list them under a section announced as collapsed.
88
+ - An expanded `TopNavMenu` or `TopNavMegaMenu` section in the mobile drawer no longer clips the focus ring of its items. The section still clips while collapsed and while it animates open or closed.
89
+ - `Typeahead`, `Tokenizer`, and `PowerSearch`: clear loading state and stop busy indicator when search source is replaced (#7457)
90
+
91
+ #### Performance
92
+
93
+ - `Text` and `Heading` with `maxLines` and `hasTruncateTooltip={false}` no longer measure their text or observe it for resizes and content changes. Only the tooltip uses that measurement, so with the tooltip off the text is cut by CSS alone, and a long table of truncated cells no longer pays a layout read per cell. Rendering is unchanged; with the tooltip enabled (the default) nothing changes.
94
+
95
+ #### Documentation
96
+
97
+ - `Avatar` and `AvatarGroup` docs list the numeric sizes `size` accepts (16, 20, 24, 32, 36, 40, 48, 60, 64, 72, 96, 128, 144, 180) instead of implying any pixel value, and say that an `AvatarGroup`'s size always overrides a child `Avatar`'s size, including the group's default.
98
+ - Docs and CLI examples import each Core export from the path `astryx component <Name>` prints.
99
+ - `ContextMenu` docs now state that data-driven `items` and compound `menuContent` are mutually exclusive choices instead of marking `items` as unconditionally required.
100
+ - Document DropdownMenuGroup's complete wrapper props, group semantics, and non-interactive heading guidance.
101
+ - Document FieldLabel's complete public prop surface, group-label semantics, and supporting descriptions.
102
+ - Make `FormLayout` documentation match logical fractional grid tracks and viewport collapse, and make the public layout target discoverable from component anatomy.
103
+ - Make `Grid` and `GridSpan` documentation match fractional track sizing, responsive repeat behavior, implicit rows, and explicit-column spans.
104
+ - `useCombobox`, the single-select combobox hook exported from `@astryxdesign/core/Selector` that powers `Selector` and `CommandPalette`, now has hook docs, so `astryx hook useCombobox` and `astryx search combobox` return it with its options, its return fields, and how to wire `aria-activedescendant` while focus stays on the control.
105
+ - The `useMultiCombobox` hook docs now say that ArrowDown or ArrowUp opening the list lands on the first or last option even with `hasSearch` or a disabled end option, and that the hook still handles Home and End with `hasSearch`, so a search input that keeps those keys for the caret stops them first and relies on PageUp and PageDown.
106
+ - `useMultiCombobox`, the multi-select combobox hook exported from `@astryxdesign/core/MultiSelector` that powers `MultiSelector`, now has hook docs, so `astryx hook useMultiCombobox` and `astryx search combobox` return it with its options, including the grid rows with an action cell, its return fields, and how to wire `aria-activedescendant` while focus stays on the control.
107
+ - InternationalizationProvider documentation now names its nonvisual provider boundary so the new component contract can map its anatomy without implying rendered DOM. (#6048)
108
+ - `ListItem`'s docs now list `label` as a `ReactNode`, matching its props type: a string is truncated to one line, and any other node renders as given. They used to say `string`, which told readers a rich label had to be restructured away.
109
+
110
+ #### Other Changes
111
+
112
+ - `VStack` and `HStack` come from `@astryxdesign/core/VStack` and `@astryxdesign/core/HStack`, `Heading` from `@astryxdesign/core/Heading`, `Text` from `@astryxdesign/core/Text`, and `Theme` and `defineTheme` from `@astryxdesign/core/theme`.
113
+ - This covers the guides, the `Card` docs, the next steps `astryx init` prints, the install example `astryx theme build` prints, the wiring example `theme add` prints, the build rules, the theme-module fix `astryx doctor` prints, and the annotated theme template.
114
+ - Every path was already exported. Nothing else changes.
115
+ - The "run init to finish setup" reminder no longer prints where agents already have the Astryx prompt. In a git repository it looks for init's block in the agent docs from the project up to the repository root, because coding agents read every agent doc in between, so a package in a monorepo that ran `init` at its root stays quiet. This holds for every command and for the reminder printed when `@astryxdesign/core` or `@astryxdesign/cli` is installed. Running the CLI from its own source checkout, inside that checkout, prints no reminder. A project with no block in reach still gets it, and `--json` never prints it.
116
+ - `astryx swizzle` no longer says StyleX components "render unstyled (no error)" without a StyleX compiler. Importing them throws StyleX's "Unexpected 'stylex.create' call at runtime" error and the page does not render, and the note now says so.
117
+ - In an integration package, where the package's own manifest loads, `astryx doctor`'s implicit-integrations line no longer says that "every loaded integration is named in astryx.config". It names the package's own manifest: as the only loaded integration, or beside the integrations astryx.config names.
118
+
119
+ Classification: contract-restoring. Only message text changes: JSON keys, check ids, statuses, and exit codes are unchanged. The doctor line's new text also appears in its `--json` `message`.
120
+
121
+ - Internal groundwork for a sub-menu's header and footer: `DropdownMenu`'s Tab walk through its header, menu and footer moves, unchanged, into a module of its own, so another menu level with regions can share it. `DropdownMenu`'s behavior does not change.
122
+ - Adjacent query words that join into a component, hook, or template name, or into a one-word keyword, match it: `table header cell with sort arrow` finds `TableHeaderCell`, `tree view folders` the `treeview` keyword, and a hook answers to its words without `use`. Most of a name, a name's leading words, or a run of its words also count for components and hooks, a step below the full name.
123
+ - A query that is one camelCase identifier and matches nothing as typed is read as the words it spells, so an unknown API name such as `useTablePaginationState` reaches `useTablePagination`. In a query of several words each identifier stays one term.
124
+ - When the whole query is an entry's name, these readings add no near siblings beside it. A match on a joined keyword never ranks above an entry the query names, and a match on part of another name does only when it spans more query words than that entry's name.
125
+ - A gerund matches its verb (`spacing` and `space`, `dragging` and `drag`), and a plural can start a longer word through its singular (`tokens` and `Tokenizer`).
126
+ - Core component docs declare more keywords: other libraries' names (`scrollarea`, `togglegroup`, `pageheader`, `splitpane`, `circularprogress`, `linearprogress`, `commandmenu`, `relativetime`, `sidesheet`, `descriptionlist`, `inlinecode`) and common glyph names on `Icon`, since any icon library's glyph renders through it.
127
+ - The JSON shape is unchanged.
128
+ - A match on part of a longer name that reads more of the query than the entry the query names is no longer held below it: `dropdown menu radio options` leads with `DropdownMenuRadioItem`, not `DropdownMenu`.
129
+ - `useResizable` drops the `splitview` keyword, which put it ahead of the side-panels guide.
130
+
131
+ #### Contributors
132
+
133
+ Thanks to everyone who contributed to this release:
134
+
135
+ - @azure-553
136
+ - @cixzhang
137
+ - @ernestt
138
+ - @Geervan
139
+ - @harjothkhara
140
+ - @HelloOjasMutreja
141
+ - @imdreamrunner
142
+ - @josephfarina
143
+ - @kentonquatman
144
+ - @korkt-kim
145
+ - @kyu-rong
146
+ - @latxh
147
+ - @ManoharPaturi
148
+ - @nynexman4464
149
+ - @potatowagon
150
+ - @Pushpak731
151
+ - @rapsealk
152
+ - @vjeux
153
+ - @WeAreResilience
154
+
155
+ ---
156
+
3
157
  # 0.7.1
4
158
 
5
159
  #### New Features
@@ -12,9 +166,9 @@
12
166
  - `CodeBlock` gains `isDiff`, a diff layer over any `language`, and Markdown renders a ```diff fence as tinted diff rows instead of plain text. (#7389)
13
167
  With `isDiff`, lines starting with `+` sit on a success-tinted row, `-` on an error-tinted row, `@@` hunk headers (and a `--- `/`+++ ` file-header pair directly before one) on a quiet muted row, and the rest of every line keeps the language's syntax highlighting. The glyph renders in its own column so the code's indentation lines up on every row and stays in the copied text. A changed row's margin reads the change: the tint runs under the line-number gutter too and spans the full scroll width of a long line, and the line number and the glyph take the row's marker colour, while the code keeps the syntax theme's colours. These are five new syntax-theme slots — `--color-syntax-added`, `--color-syntax-removed`, `--color-syntax-diff-header` (row paints, defaulting to `--color-success-muted` and `--color-error-muted` at 25% strength and to `--color-background-muted`; a defined syntax theme that leaves the header paint unset gets none, its header rows sitting on its own background in its punctuation colour) and `--color-syntax-added-marker`, `--color-syntax-removed-marker` (defaulting to `--color-text-green` and `--color-text-red` in the default syntax theme; a defined syntax theme that leaves them unset keeps its own line-number colour) — so existing and custom syntax themes need no change and may override them.
14
168
 
15
- Markdown maps a ```diff-<lang> fence to the layer over `<lang>` (labelled `<lang> diff`) and a ```diff fence to the layer over plaintext (labelled `diff`), so a diff keeps its header, copy button, disclosure, and a viewport name that still says `diff`.
169
+ Markdown maps a ``diff-<lang> fence to the layer over `<lang>` (labelled `<lang> diff`) and a ``diff fence to the layer over plaintext (labelled `diff`), so a diff keeps its header, copy button, disclosure, and a viewport name that still says `diff`.
16
170
 
17
- A ```diff fence that should stay plain text can use ```text. A custom `components.code` renderer is unchanged: it keeps receiving the fence's leading word characters in `language` (`diff` for both ```diff and ```diff-tsx, as today), so an existing `language === 'diff'` check still matches, and receives nothing new.
171
+ A `diff fence that should stay plain text can use `text. A custom `components.code` renderer is unchanged: it keeps receiving the fence's leading word characters in `language` (`diff` for both `diff and `diff-tsx, as today), so an existing `language === 'diff'` check still matches, and receives nothing new.
18
172
 
19
173
  - Clearable inputs: the clear button's tooltip now reads just "Clear" (localized) instead of repeating the field's label, so a long label no longer turns into awkward tooltip copy such as "Clear Assigned engineering partner". The button's accessible name is unchanged and still names the field, such as "Clear Search". Applies to every input that renders the shared clear button, including `TextInput`, `NumberInput`, the date and time inputs, `FileInput`, `Selector`, `MultiSelector`, `Typeahead`, and `Tokenizer`. Override the new `@astryx.inputClearButton.tooltip` catalog key to change the wording. (#7476)
20
174
  - `Markdown` fenced code blocks wrap long lines instead of scrolling them sideways. A reader on a narrow screen sees the whole line without a horizontal scroll, and where `Markdown` and RichText give a code block the same width, a long line takes the same number of lines in both. Only the appearance changes: the code's text, line numbers, syntax colours and what Copy returns are unchanged, and a code block whose lines no longer overflow also no longer takes the scroll region's Tab stop, as a code block that fits never has. To keep the old sideways-scrolling look, render code yourself through the `components.code` prop with a `CodeBlock` that leaves `isWrapped` off. (#7564)
package/README.md CHANGED
@@ -6,10 +6,10 @@ Core UI components, theme system, and utilities for the Astryx design system. Fo
6
6
  >
7
7
  > ```bash
8
8
  > npm install -D @astryxdesign/cli # or: pnpm add -D / yarn add -D / bun add -d
9
- > npx astryx init # resolves to the CLI you just installed
9
+ > npx @astryxdesign/cli init # the CLI you just installed
10
10
  > ```
11
11
  >
12
- > `init` writes the Astryx component index into your `AGENTS.md`/`CLAUDE.md` so your agent discovers components, templates, and design tokens instead of guessing. Need a single command without installing? Use the scoped package directly — `npx @astryxdesign/cli <cmd>` (or `pnpm dlx`/`bunx @astryxdesign/cli`). Bare `npx astryx` only works once `@astryxdesign/cli` is a dependency; before that npm resolves it to an unrelated package. See [XDS CLI](#xds-cli).
12
+ > `init` writes the Astryx component index into your `AGENTS.md`/`CLAUDE.md` so your agent discovers components, templates, and design tokens instead of guessing. Need a single command without installing? The same scoped command works: `npx @astryxdesign/cli <cmd>`. Always use the scoped name: the unscoped `astryx` resolves to an unrelated npm package until `@astryxdesign/cli` is a dependency. See [XDS CLI](#xds-cli).
13
13
 
14
14
  ## Component Docs
15
15
 
@@ -21,7 +21,7 @@ npx @astryxdesign/cli component Button # full docs for a component
21
21
  npx @astryxdesign/cli component --list # list all components
22
22
  ```
23
23
 
24
- > Use the scoped `@astryxdesign/cli` to run without installing; bare `npx astryx` only resolves once the CLI is a dependency.
24
+ > Use the scoped `@astryxdesign/cli`: it runs with or without installing, while the unscoped `astryx` resolves to an unrelated npm package until the CLI is a dependency.
25
25
 
26
26
  ## Page Layouts
27
27
 
@@ -57,7 +57,7 @@ astryx discover # discover external Astryx packages
57
57
  astryx gap-report # report a missing capability
58
58
  ```
59
59
 
60
- > Prefix these with your runner: `npx astryx …` / `pnpm exec astryx …` once the CLI is installed, or `npx @astryxdesign/cli …` to run without installing.
60
+ > Run these as `npx @astryxdesign/cli …`, or `pnpm exec astryx …` (or your package manager's equivalent) once the CLI is installed.
61
61
 
62
62
  ## Related Packages
63
63
 
@@ -1 +1 @@
1
- {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/Avatar/Avatar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAqB3C,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AA4BrD;;;;;;GAMG;AACH,KAAK,eAAe,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzD;;GAEG;AACH,KAAK,iBAAiB,GACpB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAgBpD;AASD,eAAO,MAAM,WAAW;;;;;;;;;;EAUtB,CAAC;AA8IH,MAAM,WAAW,WAAY,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC5D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;CAChD;AA6ID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,EACrB,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,WAAW,EACX,IAAI,EACJ,IAAW,EACX,KAAgB,EAChB,GAAG,EACH,MAAM,EACN,OAAc,EACd,IAAI,EACJ,EAAE,EACF,MAAM,EACN,GAAG,EACH,OAAO,EACP,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,+BAyVb;yBA7We,MAAM"}
1
+ {"version":3,"file":"Avatar.d.ts","sourceRoot":"","sources":["../../src/Avatar/Avatar.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAqB3C,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,eAAe,CAAC;AA4BrD;;;;;;GAMG;AACH,KAAK,eAAe,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzD;;GAEG;AACH,KAAK,iBAAiB,GACpB,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzE;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE7D;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAgBpD;AASD,eAAO,MAAM,WAAW;;;;;;;;;;EAUtB,CAAC;AA8IH,MAAM,WAAW,WAAY,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC5D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,EAAE,CAAC,EAAE,iBAAiB,CAAC;IACvB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,WAAW,CAAC,CAAC;CAChD;AAsJD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,EACrB,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,WAAW,EACX,IAAI,EACJ,IAAW,EACX,KAAgB,EAChB,GAAG,EACH,MAAM,EACN,OAAc,EACd,IAAI,EACJ,EAAE,EACF,MAAM,EACN,GAAG,EACH,OAAO,EACP,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,WAAW,+BAyVb;yBA7We,MAAM"}
@@ -232,8 +232,15 @@ const groupDynamicStyles = {
232
232
  /**
233
233
  * A character that can stand for a word in initials: a letter, a digit, or an
234
234
  * emoji. Punctuation and other symbols, such as `(`, `"` or `-`, cannot.
235
+ *
236
+ * Built at runtime, not written as a literal: for targets without property
237
+ * escapes, or when no browserslist is set, Babel's
238
+ * transform-unicode-property-regex rewrites a `\p{…}` literal, and the copy
239
+ * bundled with Next.js lacks the Unicode data it needs, so a source build fails
240
+ * with "Unknown property". A literal is safe once Next's bundled Babel ships
241
+ * that data.
235
242
  */
236
- const INITIAL_CHARACTER = /[\p{L}\p{N}\p{Extended_Pictographic}\p{Regional_Indicator}]/u;
243
+ const INITIAL_CHARACTER = new RegExp('[\\p{L}\\p{N}\\p{Extended_Pictographic}\\p{Regional_Indicator}]', 'u');
237
244
 
238
245
  /**
239
246
  * The first character of a word that can stand for it in initials, skipping
@@ -1 +1 @@
1
- {"version":3,"file":"AvatarGroupOverflow.d.ts","sourceRoot":"","sources":["../../src/AvatarGroup/AvatarGroupOverflow.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAa5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAU5C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,SAAS,CAAC,WAAW,CAAC,EACtB,SAAS,CACV;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA8ED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,wBAAwB,GAAG,SAAS,CAqEtC;yBA9Ee,mBAAmB"}
1
+ {"version":3,"file":"AvatarGroupOverflow.d.ts","sourceRoot":"","sources":["../../src/AvatarGroup/AvatarGroupOverflow.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,EAAC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAa5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAU5C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CACpD,SAAS,CAAC,WAAW,CAAC,EACtB,SAAS,CACV;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AA8ED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,GAAG,EACH,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,wBAAwB,GAAG,SAAS,CAuEtC;yBAhFe,mBAAmB"}
@@ -142,7 +142,10 @@ export function AvatarGroupOverflow({
142
142
  });
143
143
  }
144
144
  return /*#__PURE__*/_jsx("span", {
145
- ref: ref,
145
+ ref: ref
146
+ // Before the caller's props so a caller-supplied role still wins.
147
+ ,
148
+ role: "img",
146
149
  ...rest,
147
150
  "aria-label": label,
148
151
  ...mergeProps(themeProps('avatar-group-overflow', {
@@ -1 +1 @@
1
- {"version":3,"file":"ChatLayoutScrollButton.d.ts","sourceRoot":"","sources":["../../src/Chat/ChatLayoutScrollButton.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAS5C,MAAM,WAAW,2BAA4B,SAAQ,IAAI,CACvD,SAAS,CAAC,cAAc,CAAC,EACzB,SAAS,CACV;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,qCAAqC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAsED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,GAAG,EACH,SAAS,EACT,KAAK,EACL,OAAO,EACP,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,2BAA2B,qBAuC7B;yBAhDe,sBAAsB"}
1
+ {"version":3,"file":"ChatLayoutScrollButton.d.ts","sourceRoot":"","sources":["../../src/Chat/ChatLayoutScrollButton.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAS5C,MAAM,WAAW,2BAA4B,SAAQ,IAAI,CACvD,SAAS,CAAC,cAAc,CAAC,EACzB,SAAS,CACV;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,qCAAqC;IACrC,SAAS,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAuED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,GAAG,EACH,SAAS,EACT,KAAK,EACL,OAAO,EACP,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,2BAA2B,qBAwC7B;yBAjDe,sBAAsB"}
@@ -89,6 +89,7 @@ export function ChatLayoutScrollButton({
89
89
  ...mergeProps(stylex.props(styles.wrapper, xstyle), className, style),
90
90
  ...rest,
91
91
  children: /*#__PURE__*/_jsx("div", {
92
+ inert: !isVisible,
92
93
  ...mergeProps(themeProps('chat-layout-scroll-button'), {
93
94
  0: {
94
95
  className: "xawy1a7 xb3r6kr xjspbzw x1prclbq x14hfi27 x1ueg155 xrgg2z9 xlr8y92 x2rcmwa x12w9bfk xg01cxk x47corl xlshs6z x1jys5uj"
@@ -115,7 +115,7 @@ export interface CheckboxListProps extends Omit<FieldInputBaseProps<HTMLDivEleme
115
115
  * </CheckboxList>
116
116
  * ```
117
117
  */
118
- export declare function CheckboxList({ label, isLabelHidden, description, status, value, onChange, changeAction, density, hasDividers, isDisabled, disabledMessage, isReadOnly, children, ref, width, containerXstyle, containerClassName, containerStyle, controlXstyle, controlClassName, controlStyle, 'aria-describedby': ariaDescribedByProp, ...restProps }: CheckboxListProps): import("react").JSX.Element;
118
+ export declare function CheckboxList({ label, isLabelHidden, description, status, value, onChange, changeAction, density, hasDividers, isDisabled, disabledMessage, isReadOnly, children, ref, width, containerXstyle, containerClassName, containerStyle, controlXstyle, controlClassName, controlStyle, 'aria-labelledby': ariaLabelledByProp, 'aria-describedby': ariaDescribedByProp, ...restProps }: CheckboxListProps): import("react").JSX.Element;
119
119
  export declare namespace CheckboxList {
120
120
  var displayName: string;
121
121
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxList.d.ts","sourceRoot":"","sources":["../../src/CheckboxList/CheckboxList.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,qBAAqB,CAAC;AAYrD,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,mBAAmB,CAAC,cAAc,CAAC,EACnC,UAAU,CACX;IACC,mDAAmD;IACnD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,MAAM,EACN,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,OAAoB,EACpB,WAAmB,EACnB,UAAkB,EAClB,eAAe,EACf,UAAkB,EAClB,QAAQ,EACR,GAAG,EACH,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,EAAE,mBAAmB,EACvC,GAAG,SAAS,EACb,EAAE,iBAAiB,+BA0InB;yBAlKe,YAAY"}
1
+ {"version":3,"file":"CheckboxList.d.ts","sourceRoot":"","sources":["../../src/CheckboxList/CheckboxList.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAE9C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAEhD,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,qBAAqB,CAAC;AAarD,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAC7C,mBAAmB,CAAC,cAAc,CAAC,EACnC,UAAU,CACX;IACC,mDAAmD;IACnD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D;;;OAGG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;OAUG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,MAAM,EACN,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,OAAoB,EACpB,WAAmB,EACnB,UAAkB,EAClB,eAAe,EACf,UAAkB,EAClB,QAAQ,EACR,GAAG,EACH,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EAAE,kBAAkB,EACrC,kBAAkB,EAAE,mBAAmB,EACvC,GAAG,SAAS,EACb,EAAE,iBAAiB,+BA2InB;yBApKe,YAAY"}
@@ -24,6 +24,7 @@ import { useTooltip } from "../Tooltip/index.js";
24
24
  import * as stylex from '@stylexjs/stylex';
25
25
  import { mergeProps } from "../utils/index.js";
26
26
  import { themeProps } from "../utils/themeProps.js";
27
+ import { joinAriaIDs } from "../utils/inputAria.js";
27
28
  import { CheckboxListContext } from "./CheckboxListContext.js";
28
29
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
29
30
  const EMPTY_ARRAY = [];
@@ -67,6 +68,7 @@ export function CheckboxList({
67
68
  controlXstyle,
68
69
  controlClassName,
69
70
  controlStyle,
71
+ 'aria-labelledby': ariaLabelledByProp,
70
72
  'aria-describedby': ariaDescribedByProp,
71
73
  ...restProps
72
74
  }) {
@@ -152,8 +154,10 @@ export function CheckboxList({
152
154
  // internally by isEnabled, so attaching unconditionally is safe.
153
155
  ref: useMergedRefs(ref, disabledMessageTooltip.ref),
154
156
  ...mergeProps(stylex.props(controlXstyle), controlClassName, controlStyle),
155
- role: "group",
156
- "aria-labelledby": labelID,
157
+ role: "group"
158
+ // A caller aria-labelledby names the group together with its label.
159
+ ,
160
+ "aria-labelledby": joinAriaIDs(labelID, ariaLabelledByProp),
157
161
  "aria-describedby": [ariaDescribedByProp, description ? descriptionID : null, status?.message ? statusMessageID : null, showsDisabledMessage ? disabledMessageTooltip.describedBy : null].filter(Boolean).join(' ') || undefined,
158
162
  children: /*#__PURE__*/_jsx(List, {
159
163
  density: density,
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @file DropdownMenu.tsx
3
- * @input Uses React, StyleX, usePopover, MenuBottomSheet, Button, List,
3
+ * @input Uses React, StyleX, usePopover, MenuBottomSheet (lazy), Button, List,
4
4
  * useListFocus, and the shared viewport-safe menu-width resolver
5
5
  * @output Exports DropdownMenu with caller-selected popover or bottom-sheet
6
6
  * presentation
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenu.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenu.tsx"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file DropdownMenu.tsx
7
- * @input Uses React, StyleX, usePopover, MenuBottomSheet, Button, List,
7
+ * @input Uses React, StyleX, usePopover, MenuBottomSheet (lazy), Button, List,
8
8
  * useListFocus, and the shared viewport-safe menu-width resolver
9
9
  * @output Exports DropdownMenu with caller-selected popover or bottom-sheet
10
10
  * presentation
@@ -51,15 +51,15 @@ import { useFocusReturnVisibility } from "../hooks/useFocusReturnVisibility.js";
51
51
  import { focusForLastInput } from "../utils/focusReturn.js";
52
52
  import { useMenuOverflow } from "./useMenuOverflow.js";
53
53
  import { MenuRegionsContext } from "./menuRegionsContext.js";
54
- import { getFocusableElements } from "../hooks/useFocusTrap.js";
54
+ import { moveRegionsTab } from "./menuRegionStops.js";
55
55
  import { useDevWarning } from "../hooks/useDevWarning.js";
56
56
  import { useMenuDrillIn } from "./useMenuDrillIn.js";
57
57
  import { resolveMenuWidth } from "./menuWidth.js";
58
58
  import "../Layer/layerViewportInset.stylex.js";
59
59
  import { layerViewportInset } from "../Layer/layerViewportInset.stylex.js";
60
60
  import { useAdaptivePresentation } from "../hooks/useAdaptivePresentation.js";
61
- import { MenuBottomSheet } from "./MenuBottomSheet.js";
62
- import { MenuBottomSheetActionList } from "./MenuBottomSheetActionList.js";
61
+ // Loaded on demand: only the bottom-sheet presentation renders the sheet.
62
+ import { MenuBottomSheet, MenuBottomSheetActionList } from "./lazyMenuBottomSheet.js";
63
63
  import { layerAnimations } from "../Layer/layerAnimations.stylex.js";
64
64
  import "../theme/tokens.stylex.js";
65
65
  import { spacingVars, colorVars, radiusVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
@@ -76,80 +76,6 @@ const MENU_BLOCK_CAP = '300px';
76
76
  const MENU_MAX_BLOCK_SIZE = `min(${MENU_BLOCK_CAP}, ${layerViewportInset.maxBlockSize})`;
77
77
  const MENU_MAX_BLOCK_SIZE_FALLBACK = `min(${MENU_BLOCK_CAP}, ${layerViewportInset.maxBlockSizeFallback})`;
78
78
  const MENU_TRIGGER_OPEN_BACKGROUND = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
79
-
80
- /**
81
- * The elements Tab reaches inside a header or footer region, in order. Hidden
82
- * controls (`hidden`, `display: none`, `visibility: hidden`, inert or
83
- * aria-hidden subtrees) are not reachable, judged by the popover focus trap's
84
- * own test so the two never disagree about where Tab can go.
85
- */
86
- /**
87
- * Collapse each named radio group to the one Tab stop a browser gives it: the
88
- * focused radio, else the checked one, else the first radio moving forward or
89
- * the last moving backward. The stop takes the group's first position.
90
- */
91
- function collapseRadioGroups(elements, active, isBackward) {
92
- const groups = new Map();
93
- const groupKey = el => el instanceof HTMLInputElement && el.getAttribute('type') === 'radio' && el.name !== '' ? `${el.form?.id ?? ''}\u0000${el.name}` : null;
94
- for (const el of elements) {
95
- const key = groupKey(el);
96
- if (key != null) {
97
- const members = groups.get(key) ?? [];
98
- members.push(el);
99
- groups.set(key, members);
100
- }
101
- }
102
- const placed = new Set();
103
- const result = [];
104
- for (const el of elements) {
105
- const key = groupKey(el);
106
- if (key == null) {
107
- result.push(el);
108
- continue;
109
- }
110
- if (placed.has(key)) {
111
- continue;
112
- }
113
- placed.add(key);
114
- const members = groups.get(key) ?? [];
115
- const stop = members.find(radio => radio === active) ?? members.find(radio => radio.checked) ?? (isBackward ? members[members.length - 1] : members[0]);
116
- result.push(stop);
117
- }
118
- return result;
119
- }
120
- function tabbablesIn(region) {
121
- if (region == null) {
122
- return [];
123
- }
124
- return getFocusableElements(region).filter(element => element.tabIndex >= 0 && !isInsideHiddenWrapper(element, region));
125
- }
126
-
127
- /**
128
- * Whether a `display: none` ancestor between the element and its region hides
129
- * it — a control in a wrapper hidden at some widths, say. The trap's test reads
130
- * only the element's own display.
131
- */
132
- function isInsideHiddenWrapper(element, region) {
133
- if (typeof window === 'undefined' || !window.getComputedStyle) {
134
- return false;
135
- }
136
- for (let node = element.parentElement; node != null && node !== region.parentElement; node = node.parentElement) {
137
- if (window.getComputedStyle(node).display === 'none') {
138
- return true;
139
- }
140
- }
141
- return false;
142
- }
143
-
144
- /**
145
- * Move focus to a Tab stop in the dialog. Reports whether focus actually
146
- * arrived, so a caller can fall back to the menu instead of stranding focus on
147
- * the page.
148
- */
149
- function focusRegionControl(element) {
150
- element.focus();
151
- return element.ownerDocument.activeElement === element;
152
- }
153
79
  const _temp = {
154
80
  kzqmXN: "x1uyokj7",
155
81
  "$$css": true
@@ -491,12 +417,41 @@ function DropdownMenuBottomSheet({
491
417
  if (!isOpen || openModalityRef.current !== 'keyboard') {
492
418
  return;
493
419
  }
494
- const frame = requestAnimationFrame(() => {
495
- actionListRef.current?.querySelector('button:not(:disabled), a[href]')?.focus({
496
- preventScroll: true
420
+ const findFirstAction = () => actionListRef.current?.querySelector('button:not(:disabled), a[href]') ?? null;
421
+ let observer = null;
422
+ let frame = requestAnimationFrame(() => {
423
+ const action = findFirstAction();
424
+ if (action != null) {
425
+ action.focus({
426
+ preventScroll: true
427
+ });
428
+ return;
429
+ }
430
+ // The sheet loads on demand, so a keyboard open can arrive before its
431
+ // rows exist. Wait for them, then focus a frame later so the sheet's
432
+ // own open-focus has already run.
433
+ observer = new MutationObserver(() => {
434
+ const loaded = findFirstAction();
435
+ if (loaded == null) {
436
+ return;
437
+ }
438
+ observer?.disconnect();
439
+ observer = null;
440
+ frame = requestAnimationFrame(() => {
441
+ loaded.focus({
442
+ preventScroll: true
443
+ });
444
+ });
445
+ });
446
+ observer.observe(document.body, {
447
+ childList: true,
448
+ subtree: true
497
449
  });
498
450
  });
499
- return () => cancelAnimationFrame(frame);
451
+ return () => {
452
+ cancelAnimationFrame(frame);
453
+ observer?.disconnect();
454
+ };
500
455
  }, [currentItems, isOpen]);
501
456
  useEffect(() => {
502
457
  if (!isOpen) {
@@ -928,34 +883,7 @@ function DropdownMenuPopover({
928
883
  // popover's own focus trap, which listens on the document, never reads it a
929
884
  // second time.
930
885
  const moveDialogTab = useCallback((e, isFromFlyout = false) => {
931
- const menu = listRef.current;
932
- if (menu == null) {
933
- return;
934
- }
935
- e.preventDefault();
936
- e.stopPropagation();
937
- // A named radio group is one stop, as the browser's own Tab order has it.
938
- const cycle = collapseRadioGroups([...tabbablesIn(headerRef.current), menu, ...tabbablesIn(footerRef.current)], document.activeElement, e.shiftKey);
939
- if (cycle.length === 1) {
940
- // Nothing else to reach: focus stays in the menu. From a flyout that
941
- // has just closed itself, that is the menu's own stop.
942
- if (isFromFlyout) {
943
- menu.focus();
944
- }
945
- return;
946
- }
947
- const active = document.activeElement;
948
- const menuIndex = cycle.indexOf(menu);
949
- // A row, or a row of an open flyout, counts as the menu's stop.
950
- let index = menu.contains(active) ? menuIndex : cycle.findIndex(el => el === active || el.contains(active));
951
- if (index < 0) {
952
- index = menuIndex;
953
- }
954
- const step = e.shiftKey ? -1 : 1;
955
- const next = cycle[(index + step + cycle.length) % cycle.length];
956
- if (!focusRegionControl(next)) {
957
- menu.focus();
958
- }
886
+ moveRegionsTab(e, listRef.current, headerRef.current, footerRef.current, isFromFlyout);
959
887
  }, [listRef]);
960
888
 
961
889
  // Extend useListFocus with Enter/Space activation + typeahead
@@ -35,7 +35,7 @@ export interface DropdownMenuCheckboxItemProps extends Omit<BaseProps, 'onChange
35
35
  description?: ReactNode;
36
36
  /**
37
37
  * Icon to display before the label. Accepts a semantic icon name (see
38
- * `npx @astryxdesign/cli docs icons`) or a rendered node.
38
+ * `astryx docs icons`) or a rendered node.
39
39
  */
40
40
  icon?: ReactNode | IconType;
41
41
  /**
@@ -23,7 +23,8 @@ import type { BaseProps } from '../BaseProps';
23
23
  export interface DropdownMenuGroupProps extends Pick<BaseProps, 'xstyle' | 'className' | 'style'> {
24
24
  /**
25
25
  * Heading shown above the group's rows and used as the group's accessible
26
- * name (`aria-labelledby`). Omit it for an unnamed group.
26
+ * name (`aria-labelledby`). Omit it for an unnamed group. Keep this content
27
+ * non-interactive; controls belong in DropdownMenu's `header` or `footer`.
27
28
  */
28
29
  title?: ReactNode;
29
30
  /** The rows of the group: menu items, selectable items, sub-menus. */
@@ -34,9 +35,10 @@ export interface DropdownMenuGroupProps extends Pick<BaseProps, 'xstyle' | 'clas
34
35
  /**
35
36
  * A titled group of menu rows.
36
37
  *
37
- * Renders `role="group"` named by its heading. The heading is plain text, not
38
- * a `menuitem`, so it is never a stop in the menu's arrow-key order and
39
- * typeahead never lands on it. The compound peer of
38
+ * Renders `role="group"` named by its heading. The heading is not a
39
+ * `menuitem`, so arrow-key navigation and typeahead skip it. Keep heading
40
+ * content non-interactive; place controls in DropdownMenu's `header` or
41
+ * `footer`. The compound peer of
40
42
  * `{type: 'section', title, items}` in the `items` data API.
41
43
  *
42
44
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenuGroup.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuGroup.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAQ,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAQ5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAgB5C,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,mDAAmD;IACnD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,GACJ,EAAE,sBAAsB,+BAuBxB;yBA9Be,iBAAiB"}
1
+ {"version":3,"file":"DropdownMenuGroup.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuGroup.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAQ,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAQ5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAgB5C,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAClD,SAAS,EACT,QAAQ,GAAG,WAAW,GAAG,OAAO,CACjC;IACC;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,mDAAmD;IACnD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,GACJ,EAAE,sBAAsB,+BAuBxB;yBA9Be,iBAAiB"}