@astryxdesign/core 0.1.6-canary.ff5dfca → 0.1.7-canary.04cd8f7

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 (121) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +24 -15
  3. package/dist/Collapsible/Collapsible.d.ts +11 -1
  4. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  5. package/dist/Collapsible/Collapsible.js +36 -4
  6. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  7. package/dist/ContextMenu/ContextMenu.js +4 -3
  8. package/dist/ContextMenu/index.d.ts +3 -0
  9. package/dist/ContextMenu/index.d.ts.map +1 -1
  10. package/dist/ContextMenu/index.js +7 -1
  11. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  12. package/dist/DropdownMenu/DropdownMenu.js +8 -4
  13. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +89 -0
  14. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -0
  15. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +170 -0
  16. package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -1
  17. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  18. package/dist/DropdownMenu/DropdownMenuContext.js +18 -0
  19. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +69 -0
  20. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -0
  21. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +70 -0
  22. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +69 -0
  23. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -0
  24. package/dist/DropdownMenu/DropdownMenuRadioItem.js +178 -0
  25. package/dist/DropdownMenu/index.d.ts +5 -1
  26. package/dist/DropdownMenu/index.d.ts.map +1 -1
  27. package/dist/DropdownMenu/index.js +10 -1
  28. package/dist/DropdownMenu/menuItemRoles.d.ts +13 -0
  29. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -0
  30. package/dist/DropdownMenu/menuItemRoles.js +15 -0
  31. package/dist/Icon/Icon.d.ts +17 -12
  32. package/dist/Icon/Icon.d.ts.map +1 -1
  33. package/dist/Icon/Icon.js +28 -20
  34. package/dist/Kbd/Kbd.js +1 -1
  35. package/dist/TabList/Tab.d.ts.map +1 -1
  36. package/dist/TabList/Tab.js +2 -2
  37. package/dist/TabList/TabList.d.ts.map +1 -1
  38. package/dist/TabList/TabList.js +2 -0
  39. package/dist/TabList/TabMenu.d.ts.map +1 -1
  40. package/dist/TabList/TabMenu.js +1 -1
  41. package/dist/Table/index.d.ts +2 -0
  42. package/dist/Table/index.d.ts.map +1 -1
  43. package/dist/Table/index.js +1 -0
  44. package/dist/Table/plugins/tree/index.d.ts +5 -0
  45. package/dist/Table/plugins/tree/index.d.ts.map +1 -0
  46. package/dist/Table/plugins/tree/index.js +4 -0
  47. package/dist/Table/plugins/tree/useTableTreeData.d.ts +38 -0
  48. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -0
  49. package/dist/Table/plugins/tree/useTableTreeData.js +358 -0
  50. package/dist/Table/plugins/tree/useTableTreeState.d.ts +51 -0
  51. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -0
  52. package/dist/Table/plugins/tree/useTableTreeState.js +175 -0
  53. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  54. package/dist/Table/useBaseTablePlugins.js +6 -3
  55. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  56. package/dist/Toolbar/Toolbar.js +8 -1
  57. package/dist/astryx.css +18 -2
  58. package/dist/astryx.umd.js +46 -46
  59. package/dist/astryx.umd.js.map +4 -4
  60. package/dist/theme/Theme.js +1 -1
  61. package/dist/theme/defineTheme.d.ts +1 -1
  62. package/dist/theme/defineTheme.js +1 -1
  63. package/dist/theme/hct.d.ts +0 -1
  64. package/dist/theme/hct.d.ts.map +1 -1
  65. package/dist/theme/hct.js +0 -3
  66. package/locales/en.json +8 -0
  67. package/locales/pseudo.json +6 -0
  68. package/package.json +1 -1
  69. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  70. package/src/Collapsible/Collapsible.doc.mjs +7 -0
  71. package/src/Collapsible/Collapsible.test.tsx +80 -0
  72. package/src/Collapsible/Collapsible.tsx +58 -5
  73. package/src/ContextMenu/ContextMenu.test.tsx +75 -1
  74. package/src/ContextMenu/ContextMenu.tsx +10 -5
  75. package/src/ContextMenu/index.ts +15 -0
  76. package/src/DropdownMenu/DropdownMenu.doc.mjs +23 -0
  77. package/src/DropdownMenu/DropdownMenu.tsx +11 -6
  78. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +95 -0
  79. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +237 -0
  80. package/src/DropdownMenu/DropdownMenuContext.tsx +29 -1
  81. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +7 -1
  82. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +80 -0
  83. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +119 -0
  84. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +80 -0
  85. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +232 -0
  86. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +163 -0
  87. package/src/DropdownMenu/index.ts +23 -3
  88. package/src/DropdownMenu/menuItemRoles.ts +22 -0
  89. package/src/Field/Field.doc.mjs +1 -1
  90. package/src/Field/FieldLabel.doc.mjs +1 -1
  91. package/src/Icon/Icon.test.tsx +46 -0
  92. package/src/Icon/Icon.tsx +37 -24
  93. package/src/Kbd/Kbd.test.tsx +26 -0
  94. package/src/Kbd/Kbd.tsx +1 -1
  95. package/src/NumberInput/NumberInput.doc.mjs +2 -2
  96. package/src/Selector/SelectorOption.doc.mjs +1 -1
  97. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  98. package/src/Switch/Switch.doc.mjs +1 -1
  99. package/src/TabList/Tab.tsx +5 -1
  100. package/src/TabList/TabList.doc.mjs +3 -3
  101. package/src/TabList/TabList.test.tsx +66 -0
  102. package/src/TabList/TabList.tsx +8 -0
  103. package/src/TabList/TabMenu.tsx +4 -1
  104. package/src/Table/Table.doc.mjs +2 -0
  105. package/src/Table/index.ts +7 -0
  106. package/src/Table/plugins/tree/index.ts +12 -0
  107. package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +163 -0
  108. package/src/Table/plugins/tree/useTableTreeData.test.tsx +594 -0
  109. package/src/Table/plugins/tree/useTableTreeData.tsx +495 -0
  110. package/src/Table/plugins/tree/useTableTreeState.test.tsx +636 -0
  111. package/src/Table/plugins/tree/useTableTreeState.tsx +253 -0
  112. package/src/Table/useBaseTablePlugins.ts +6 -2
  113. package/src/Table/useTableTreeData.doc.mjs +75 -0
  114. package/src/Table/useTableTreeState.doc.mjs +98 -0
  115. package/src/TextArea/TextArea.doc.mjs +1 -1
  116. package/src/TextInput/TextInput.doc.mjs +1 -1
  117. package/src/Toolbar/Toolbar.tsx +10 -3
  118. package/src/theme/Theme.doc.mjs +4 -4
  119. package/src/theme/Theme.tsx +1 -1
  120. package/src/theme/defineTheme.ts +1 -1
  121. package/src/theme/hct.ts +0 -4
package/CHANGELOG.md CHANGED
@@ -1,5 +1,73 @@
1
1
  # @xds/core
2
2
 
3
+ # 0.1.7
4
+
5
+ #### Breaking Changes
6
+
7
+ - Table plugin render-prop interfaces (`TableRenderProps`, `HeaderRowRenderProps`, `HeaderCellRenderProps`, `BodyRowRenderProps`, `BodyCellRenderProps`, `ScrollWrapperRenderProps`) and the `scrollWrapper` component contract rename their StyleX array field `styles` → `xstyle`, matching the prop name sub-components receive it under. Custom plugin authors: rename `props.styles` reads and `styles:` writes in transform functions (#3679)
8
+ **Codemod:** `npx astryx upgrade --codemod rename-table-renderprops-styles-to-xstyle`
9
+
10
+ #### New Features
11
+
12
+ - Export the authoring factories from `@astryxdesign/core`: `createConfig` at `@astryxdesign/core/config` and `createIntegration`/`createPageTemplate`/`createBlockTemplate`/`createComponentDoc`/`createFunctionDoc`/`createDoc` at `@astryxdesign/core/authoring`. Authoring a config or integration no longer requires depending on the CLI. Existing `@astryxdesign/cli/*` imports keep working via re-export.
13
+ - Button: new `width` prop following the input field width convention (`SizeValue`: numbers are pixels, strings are used as-is). `width="100%"` removes the need for a `width: '100%'` xstyle override or a stretch layout wrapper for full-width CTAs in auth forms, dialogs, and mobile layouts (#2600).
14
+ - **Astryx components are now translatable.** Wrap your app in `<InternationalizationProvider locale="...">` and pass one or more locale catalogs to render astryx UI in the language of your choice; call `useTranslator()` inside your own components to translate consumer strings against the active locale. Astryx ships an English catalog with BCP 47 regional fallback (e.g. `pt-BR` → `pt` → `en`), so consumers who never render a provider see today's English strings unchanged.
15
+ - **Translation coverage now spans the full component set** — PowerSearch (UI chrome, value-editor labels/placeholders, the 21 built-in operator labels, and ICU-pluralized result counts), plus AlertDialog, AppShell, Banner, Breadcrumbs, Calendar, Chat, CommandPalette, ContextMenu, date/time inputs, Dialog, DropdownMenu, Lightbox, Link, Markdown, mobile/side/top nav, Outline, Popover, Resizable, Selector/MultiSelector, Table (and its filter/selection/sort plugins), Toast, Tokenizer, Typeahead, and related interactive affordances. Placeholder strings that used `...` are normalized to `…` (U+2026) in the English catalog; consumers who snapshot-test the exact three-dot form will see a diff, and consumers passing an explicit `placeholder` are unaffected.
16
+ - Two i18n-related **type refinements** (source-compatible for existing usage): `PowerSearchOperator` is now a discriminated union — `{key, value, label}` (raw text) or `{key, value, i18nKey}` (astryx-translated); passing `label` compiles and behaves unchanged, while a bare `{key, value}` (neither `label` nor `i18nKey`) becomes a compile-time error. `Markdown.renderBlock` gains a `t: TranslatorFn` parameter threaded from the top-level `Markdown`; direct `renderBlock` consumers pass a translator.
17
+ - New ESLint rules in `@astryx/eslint-plugin-astryx` (`astryx.configs.strict` / `recommended`): `@astryx/i18n-key-format` enforces camelCase path segments for `@astryx.*` catalog keys, and `@astryx/no-hardcoded-i18n-string` flags hardcoded English string literals on user-facing props — now also inside ternaries, logical expressions, and template literals (e.g. `aria-label={isOpen ? 'Close' : 'Open'}`). Both are filesystem-agnostic; downstream packages can enable them with the standard `files` / `ignores` pattern and will see additional violations flagged after upgrading.
18
+
19
+ #### Fixes
20
+
21
+ - Fix Banner chevron transition to honor `prefers-reduced-motion: reduce`.
22
+ - Round the trailing corner of the last ButtonGroup member, even when it renders a layer (#2508)
23
+ ButtonGroup keyed its trailing border-radius off `:last-child`. But several members render an invisible layer element _after_ their button — a `Button` with a `tooltip` returns `button + tooltip layer`, and `DropdownMenu` returns `trigger + popover`, both rendered inline by `useLayer` rather than portaled. The layer took the `:last-child` slot, so the real trailing button silently kept square outer corners and the group ended in a flat-edged stub.
24
+ - Calendar: month navigation now announces the newly visible month (e.g. "March 2026") to screen readers via a polite live region. Previously the grid changed silently. (#3724)
25
+ - Chat: opening a conversation that already has content (history, replay, session switching) no longer spring-scrolls from the top — the first fill positions instantly, whether the content is present at mount or arrives asynchronously. Subsequent growth (streaming) springs as before. `useChatStreamScroll`'s `scrollToBottom` accepts `{behavior: 'instant'}` for one-frame programmatic jumps, mirroring the DOM's `scrollTo({behavior})`. Exports the `ChatScrollToBottomOptions` type. (#3795)
26
+ - CheckboxInput/Switch: descriptions stay linked via aria-describedby when the label is visually hidden, instead of being orphaned in the DOM.
27
+ - CodeBlock keeps line numbers aligned with wrapped lines when `isWrapped` is enabled
28
+ - Forward rest props in Dialog and DialogHeader. DialogHeader now passes through data-testid, aria-*, and other attributes. Dialog's inline path forwards all rest props. Standard path spreads rest before contract props so onClick, onCancel, aria-modal, and role cannot be clobbered.
29
+ - Anchor --dense / --zh doc overlays to their base sections (#2182)
30
+ The compressed and translated reference docs were merged into the base doc **by array position**, so an overlay whose sections were ordered differently — or which omitted one — grafted every title onto the wrong body.
31
+ - FileInput: don't drop the drag-over highlight when dragging over dropzone children
32
+ Dragging a file across the dropzone's own icon/text fired a dragleave on the container and cleared the drag-over state, so the "Drop files here" highlight flickered mid-drag. A dragleave whose relatedTarget is still inside the dropzone is now ignored; only actually exiting the dropzone ends the drag-over state.
33
+ - Fix consumer rest props clobbering component contract props in ButtonGroup, Calendar, and Carousel
34
+ Components that set `role`, `aria-roledescription`, or `onKeyDown` on their root element now spread `{...rest}` before those props so a consumer cannot accidentally override the component's semantic contract. `onKeyDown` is composed via `composeEventHandlers` so both the consumer's and the component's handlers fire.
35
+ - Kbd: pass-through props no longer clobber the computed role and spoken accessible name (rest-spread precedence corrected, mirroring Avatar).
36
+ - Layer: centered layers near a viewport edge no longer render clipped (#3671). Flip fallbacks are a no-op for center alignment, so centered placements now append span-based `position-try-fallbacks` that slide the layer along its alignment axis.
37
+ - Link: disabled links no longer carry a live href/onClick — programmatic focus or AT activation can no longer trigger navigation.
38
+ - Selector: searching within the options popover now announces the number of matching results ("3 results" / "No results found") to screen readers, mirroring Typeahead. Previously filtering happened silently. (#3725)
39
+ - Table now honors the standard root styling props: `className`, `style`, `xstyle`, `id`, `aria-*`, `data-*`, and other HTML attributes reach the root `<table>` element instead of being silently dropped. `tableProps` is deprecated (still works, loses conflicts to direct props); the computed column min-width still wins over a consumer `style.minWidth`, but no longer clobbers it when columns compute none (#3679)
40
+ - Timestamp: the absolute-time tooltip is now reachable by keyboard — the timestamp is focusable while a tooltip is attached, per WCAG content-on-hover requirements.
41
+ - TopNav: the `<nav>` landmark now defaults its accessible name to "Top navigation" when the `label` prop is omitted, matching SideNav ("Side navigation"), Breadcrumbs, and Pagination. Previously an omitted `label` shipped an unnamed navigation landmark, leaving screen-reader users with multiple indistinguishable "navigation" landmarks on pages that compose SideNav + TopNav + Breadcrumbs. An explicit `label` still wins.
42
+
43
+ #### Documentation
44
+
45
+ - Point AI agents to the CLI from the core README.
46
+ `@astryxdesign/core`'s README now leads with a callout telling AI agents to run `npx astryx init` first, which installs the CLI's component index into `AGENTS.md`/`CLAUDE.md`. In an isolated cold-start test, this took agents from 0/5 to 4/5 on discovering and using the CLI (matching the AGENTS.md ceiling); a first-run nudge alone did 0/5.
47
+ - Surface literal values for union types in component docs (#1645)
48
+ Prop docs named their union types without ever showing the values behind them — `gap: SpacingStep`, `align: GridAlignment`, `sort: TableSortState<TSortKey>`, `status: InputStatus`. Readers without an IDE (agents especially) had to guess, and guessed wrong: `gap={16}` (pixels, not a scale step), `direction: 'desc'` (the type says `'descending'`).
49
+
50
+ #### Other Changes
51
+
52
+ - Migrate the duplicated charts/lab color parsers onto the shared `@astryxdesign/core/utils/color` module: adds `toGLFloats(rgba)` for RGBA→GL float conversion with a neutral non-NaN fallback, replacing the four `hexToGL` copies, and rebuilds `lerpHex`/`hexAlpha` on `parseHex`/`formatHex`/`parseColor`/`formatColor` (#3739)
53
+
54
+ #### Contributors
55
+
56
+ Thanks to everyone who contributed to this release:
57
+
58
+ - @AKnassa
59
+ - @arham766
60
+ - @bhamodi
61
+ - @cixzhang
62
+ - @ejhammond
63
+ - @jiunshinn
64
+ - @joeyfarina
65
+ - @nynexman4464
66
+ - @yyq1025
67
+ - @zeroryu
68
+
69
+ ---
70
+
3
71
  # 0.1.6
4
72
 
5
73
  #### New Features
package/README.md CHANGED
@@ -2,7 +2,14 @@
2
2
 
3
3
  Core UI components, theme system, and utilities for the Astryx design system. For project setup, see [Quick Start](#quick-start) below.
4
4
 
5
- > **Building with an AI agent?** Run **`npx astryx init`** first. It installs the Astryx CLI's component index into your `AGENTS.md`/`CLAUDE.md` so your agent discovers components, templates, and design tokens instead of guessing. Without it, agents can't see the CLI — see [XDS CLI](#xds-cli).
5
+ > **Building with an AI agent?** Add the CLI, then run `init`:
6
+ >
7
+ > ```bash
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
10
+ > ```
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).
6
13
 
7
14
  ## Component Docs
8
15
 
@@ -25,9 +32,9 @@ global navigation.
25
32
  Requires `@astryxdesign/cli` (`npm install -D @astryxdesign/cli`):
26
33
 
27
34
  ```bash
28
- npx astryx template --list # browse all page and block templates
29
- npx astryx template dashboard # emit full page source
30
- npx astryx template settings --skeleton # layout skeleton with spatial annotations
35
+ astryx template --list # browse all page and block templates
36
+ astryx template dashboard # emit full page source
37
+ astryx template settings --skeleton # layout skeleton with spatial annotations
31
38
  ```
32
39
 
33
40
  ## Astryx CLI
@@ -35,19 +42,21 @@ npx astryx template settings --skeleton # layout skeleton with spatial annotatio
35
42
  The CLI (`@astryxdesign/cli`) provides additional tooling:
36
43
 
37
44
  ```bash
38
- npx astryx --help # full listing of all commands
39
- npx astryx component Button # full docs + related block templates
40
- npx astryx docs # reference docs (principles, tokens, theming, styling)
41
- npx astryx docs theme # theming guide (Theme, defineTheme, light/dark)
42
- npx astryx docs tokens # spacing, color, radius, typography token reference
43
- npx astryx init # initialize Astryx in your project
44
- npx astryx theme build # build theme CSS for production
45
- npx astryx swizzle Button # eject component source for customization
46
- npx astryx upgrade --apply # run codemods to migrate between versions
47
- npx astryx discover # discover external Astryx packages
48
- npx astryx gap-report # report a missing capability
45
+ astryx --help # full listing of all commands
46
+ astryx component Button # full docs + related block templates
47
+ astryx docs # reference docs (principles, tokens, theming, styling)
48
+ astryx docs theme # theming guide (Theme, defineTheme, light/dark)
49
+ astryx docs tokens # spacing, color, radius, typography token reference
50
+ astryx init # initialize Astryx in your project
51
+ astryx theme build # build theme CSS for production
52
+ astryx swizzle Button # eject component source for customization
53
+ astryx upgrade --apply # run codemods to migrate between versions
54
+ astryx discover # discover external Astryx packages
55
+ astryx gap-report # report a missing capability
49
56
  ```
50
57
 
58
+ > Prefix these with your runner: `npx astryx …` / `pnpm exec astryx …` once the CLI is installed, or `npx @astryxdesign/cli …` to run without installing.
59
+
51
60
  ## Related Packages
52
61
 
53
62
  | Package | Description |
@@ -45,6 +45,16 @@ export interface CollapsibleProps extends BaseProps {
45
45
  * Controlled open state. When provided, the component is fully controlled.
46
46
  */
47
47
  isOpen?: boolean;
48
+ /**
49
+ * Whether the collapsible is disabled. A disabled item can't be toggled —
50
+ * its trigger is non-interactive and dimmed. Following the system-wide
51
+ * disabled convention, the trigger uses `aria-disabled` (not the native
52
+ * `disabled` attribute) and drops out of the tab order, staying perceivable
53
+ * to assistive tech. The content stays in whatever open state it was;
54
+ * disabling doesn't collapse an already-open item.
55
+ * @default false
56
+ */
57
+ isDisabled?: boolean;
48
58
  /**
49
59
  * Callback when the open state changes.
50
60
  */
@@ -96,7 +106,7 @@ export interface CollapsibleProps extends BaseProps {
96
106
  * </CollapsibleGroup>
97
107
  * ```
98
108
  */
99
- export declare function Collapsible({ trigger, children, defaultIsOpen, isOpen: controlledIsOpen, onOpenChange, value, ref, xstyle, className, style, ...props }: CollapsibleProps): import("react").JSX.Element;
109
+ export declare function Collapsible({ trigger, children, defaultIsOpen, isOpen: controlledIsOpen, isDisabled, onOpenChange, value, ref, xstyle, className, style, ...props }: CollapsibleProps): import("react").JSX.Element;
100
110
  export declare namespace Collapsible {
101
111
  var displayName: string;
102
112
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Collapsible.d.ts","sourceRoot":"","sources":["../../src/Collapsible/Collapsible.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAgBjD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkG5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,OAAO,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAM,EAAE,gBAAgB,EACxB,YAAY,EACZ,KAAK,EACL,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,gBAAgB,+BAqElB;yBAjFe,WAAW"}
1
+ {"version":3,"file":"Collapsible.d.ts","sourceRoot":"","sources":["../../src/Collapsible/Collapsible.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAa,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAiBjD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAkH5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,OAAO,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;;;;;;OAQG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IAEzC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAM,EAAE,gBAAgB,EACxB,UAAkB,EAClB,YAAY,EACZ,KAAK,EACL,GAAG,EACH,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,gBAAgB,+BA6FlB;yBA1Ge,WAAW"}
@@ -58,12 +58,22 @@ const styles = {
58
58
  kInvED: "x1wfwxd8 x7s97pk",
59
59
  $$css: true
60
60
  },
61
+ triggerDisabled: {
62
+ kkrTdU: "x1h6gzvc",
63
+ kSiTet: "xbyyjgo",
64
+ $$css: true
65
+ },
61
66
  contentHidden: {
62
67
  k1xSpc: "x1s85apg",
63
68
  $$css: true
64
69
  },
65
70
  content: {
66
71
  kLKAdn: "xfsso4q",
72
+ kMv6JI: "x9ynric",
73
+ kGuDYH: "xjm74w1",
74
+ k63SB2: "xxovm9e",
75
+ kLWn49: "xw6l6zx",
76
+ kMwMTN: "x1tgivj0",
67
77
  $$css: true
68
78
  },
69
79
  divided: {
@@ -155,6 +165,7 @@ export function Collapsible({
155
165
  children,
156
166
  defaultIsOpen,
157
167
  isOpen: controlledIsOpen,
168
+ isDisabled = false,
158
169
  onOpenChange,
159
170
  value,
160
171
  ref,
@@ -178,6 +189,17 @@ export function Collapsible({
178
189
  isCollapsible: collapsibleConfig,
179
190
  value
180
191
  });
192
+
193
+ // Activation is blocked by this guard rather than the native `disabled`
194
+ // attribute, so the trigger keeps `aria-disabled` semantics and stays
195
+ // discoverable. A native `disabled` button would silently swallow events
196
+ // (e.g. a wrapping tooltip's hover) — the system-wide disabled convention.
197
+ const handleToggle = () => {
198
+ if (isDisabled) {
199
+ return;
200
+ }
201
+ toggle();
202
+ };
181
203
  const presentation = use(CollapsibleGroupPresentationContext);
182
204
  const isDivided = presentation?.hasDividers ?? false;
183
205
  const density = presentation?.density ?? null;
@@ -194,10 +216,18 @@ export function Collapsible({
194
216
  ...props,
195
217
  children: [/*#__PURE__*/_jsxs("button", {
196
218
  type: "button",
197
- onClick: toggle,
219
+ onClick: handleToggle,
220
+ "aria-disabled": isDisabled || undefined,
198
221
  "aria-expanded": isOpen,
199
- "aria-controls": contentId,
200
- ...stylex.props(styles.trigger, density != null && triggerDensity[density]),
222
+ "aria-controls": contentId
223
+ // A disabled trigger drops out of the tab order so it isn't a silently
224
+ // dead tab stop; activation stays blocked by the handleToggle guard,
225
+ // and aria-disabled keeps the state perceivable to assistive tech —
226
+ // the system-wide disabled convention (never native `disabled`, which
227
+ // would swallow events like a wrapping tooltip's hover).
228
+ ,
229
+ tabIndex: isDisabled ? -1 : undefined,
230
+ ...stylex.props(styles.trigger, density != null && triggerDensity[density], isDisabled && styles.triggerDisabled),
201
231
  children: [/*#__PURE__*/_jsx("span", {
202
232
  ...{
203
233
  className: "x1b2iylo xwgcxoh"
@@ -216,7 +246,9 @@ export function Collapsible({
216
246
  })]
217
247
  }), /*#__PURE__*/_jsx("div", {
218
248
  id: contentId,
219
- ...stylex.props(styles.content, density != null && contentDensity[density], !isOpen && styles.contentHidden),
249
+ ...mergeProps(themeProps('collapsible-content', {
250
+ density: density ?? undefined
251
+ }), stylex.props(styles.content, density != null && contentDensity[density], !isOpen && styles.contentHidden)),
220
252
  children: presentation != null ? /*#__PURE__*/_jsx(CollapsibleGroupPresentationContext, {
221
253
  value: null,
222
254
  children: children
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMenu.d.ts","sourceRoot":"","sources":["../../src/ContextMenu/ContextMenu.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAON,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAqBrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAGjD,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAqDtC,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAMnD,UAAU,oBAAqB,SAAQ,SAAS;IAC9C,oDAAoD;IACpD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IAC9C,+DAA+D;IAC/D,QAAQ,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,wCAAwC;IACxC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,gDAAgD;IAChD,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,UAAU,wBAAyB,SAAQ,oBAAoB;IAC7D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+CAA+C;IAC/C,WAAW,EAAE,SAAS,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,wBAAwB,CAAC;AAM/E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,SAAS,EACT,IAAW,EACX,KAAK,EAAE,cAAc,EACrB,UAAkB,EAClB,YAAY,EACZ,GAAG,EACH,SAAS,EACT,KAAK,EACL,MAAM,EACN,aAAa,EACb,aAAa,EAAE,MAAM,EACrB,GAAG,KAAK,EACT,EAAE,gBAAgB,qBAiRlB;yBA/Re,WAAW"}
1
+ {"version":3,"file":"ContextMenu.d.ts","sourceRoot":"","sources":["../../src/ContextMenu/ContextMenu.tsx"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAON,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAyBrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC;AAGjD,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,8BAA8B,CAAC;AAqDtC,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAErD,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;AAMnD,UAAU,oBAAqB,SAAQ,SAAS;IAC9C,oDAAoD;IACpD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;;;OAKG;IACH,aAAa,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAC;IAC9C,+DAA+D;IAC/D,QAAQ,EAAE,SAAS,CAAC;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,wCAAwC;IACxC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,oBAAqB,SAAQ,oBAAoB;IACzD,gDAAgD;IAChD,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,UAAU,wBAAyB,SAAQ,oBAAoB;IAC7D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+CAA+C;IAC/C,WAAW,EAAE,SAAS,CAAC;CACxB;AAED,MAAM,MAAM,gBAAgB,GAAG,oBAAoB,GAAG,wBAAwB,CAAC;AAM/E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,QAAQ,EACR,SAAS,EACT,IAAW,EACX,KAAK,EAAE,cAAc,EACrB,UAAkB,EAClB,YAAY,EACZ,GAAG,EACH,SAAS,EACT,KAAK,EACL,MAAM,EACN,aAAa,EACb,aAAa,EAAE,MAAM,EACrB,GAAG,KAAK,EACT,EAAE,gBAAgB,qBAkRlB;yBAhSe,WAAW"}
@@ -34,6 +34,7 @@ import * as stylex from '@stylexjs/stylex';
34
34
  import { useLayer } from "../Layer/useLayer.js";
35
35
  import { renderDropdownItems } from "../DropdownMenu/renderDropdownItems.js";
36
36
  import { DropdownMenuContext } from "../DropdownMenu/DropdownMenuContext.js";
37
+ import { MENU_ITEM_ROLES, MENU_ITEM_SELECTOR } from "../DropdownMenu/menuItemRoles.js";
37
38
  import { useListFocus } from "../hooks/useListFocus.js";
38
39
  import { useTypeahead } from "../hooks/useTypeahead.js";
39
40
  import { useLongPress } from "../hooks/useLongPress.js";
@@ -178,13 +179,13 @@ export function ContextMenu({
178
179
  focusFirst,
179
180
  focusItem
180
181
  } = useListFocus({
181
- itemSelector: '[role="menuitem"]:not([aria-disabled="true"])',
182
+ itemSelector: MENU_ITEM_SELECTOR,
182
183
  wrap: false,
183
184
  onEscape: closeMenu
184
185
  });
185
186
 
186
187
  // First-character typeahead over the enabled menu items (menus-11).
187
- const getMenuItems = useCallback(() => listRef.current ? Array.from(listRef.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')) : [], [listRef]);
188
+ const getMenuItems = useCallback(() => listRef.current ? Array.from(listRef.current.querySelectorAll(MENU_ITEM_SELECTOR)) : [], [listRef]);
188
189
  const typeahead = useTypeahead({
189
190
  getItemLabels: () => getMenuItems().map(el => el.textContent),
190
191
  onMatch: focusItem,
@@ -238,7 +239,7 @@ export function ContextMenu({
238
239
  if (e.key === 'Enter' || e.key === ' ') {
239
240
  e.preventDefault();
240
241
  const focused = document.activeElement;
241
- if (focused?.getAttribute('role') === 'menuitem') {
242
+ if (focused && MENU_ITEM_ROLES.has(focused.getAttribute('role') ?? '')) {
242
243
  focused.click();
243
244
  }
244
245
  return;
@@ -5,4 +5,7 @@
5
5
  */
6
6
  export { ContextMenu, type ContextMenuProps, type ContextMenuItemData, type ContextMenuDivider, type ContextMenuSection, type ContextMenuOption, } from './ContextMenu';
7
7
  export { DropdownMenuItem as ContextMenuItem, type DropdownMenuItemProps as ContextMenuItemProps, } from '../DropdownMenu/DropdownMenuItem';
8
+ export { DropdownMenuCheckboxItem as ContextMenuCheckboxItem, type DropdownMenuCheckboxItemProps as ContextMenuCheckboxItemProps, } from '../DropdownMenu/DropdownMenuCheckboxItem';
9
+ export { DropdownMenuRadioGroup as ContextMenuRadioGroup, type DropdownMenuRadioGroupProps as ContextMenuRadioGroupProps, } from '../DropdownMenu/DropdownMenuRadioGroup';
10
+ export { DropdownMenuRadioItem as ContextMenuRadioItem, type DropdownMenuRadioItemProps as ContextMenuRadioItemProps, } from '../DropdownMenu/DropdownMenuRadioItem';
8
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ContextMenu/index.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,IAAI,eAAe,EACnC,KAAK,qBAAqB,IAAI,oBAAoB,GACnD,MAAM,kCAAkC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ContextMenu/index.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AAEH,OAAO,EACL,WAAW,EACX,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,GACvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,gBAAgB,IAAI,eAAe,EACnC,KAAK,qBAAqB,IAAI,oBAAoB,GACnD,MAAM,kCAAkC,CAAC;AAI1C,OAAO,EACL,wBAAwB,IAAI,uBAAuB,EACnD,KAAK,6BAA6B,IAAI,4BAA4B,GACnE,MAAM,0CAA0C,CAAC;AAClD,OAAO,EACL,sBAAsB,IAAI,qBAAqB,EAC/C,KAAK,2BAA2B,IAAI,0BAA0B,GAC/D,MAAM,wCAAwC,CAAC;AAChD,OAAO,EACL,qBAAqB,IAAI,oBAAoB,EAC7C,KAAK,0BAA0B,IAAI,yBAAyB,GAC7D,MAAM,uCAAuC,CAAC"}
@@ -7,4 +7,10 @@
7
7
  * @position Public API entry point
8
8
  */
9
9
  export { ContextMenu } from "./ContextMenu.js";
10
- export { DropdownMenuItem as ContextMenuItem } from "../DropdownMenu/DropdownMenuItem.js";
10
+ export { DropdownMenuItem as ContextMenuItem } from "../DropdownMenu/DropdownMenuItem.js";
11
+
12
+ // Selectable items work inside a ContextMenu too — re-exported under the
13
+ // ContextMenu name for a coherent API.
14
+ export { DropdownMenuCheckboxItem as ContextMenuCheckboxItem } from "../DropdownMenu/DropdownMenuCheckboxItem.js";
15
+ export { DropdownMenuRadioGroup as ContextMenuRadioGroup } from "../DropdownMenu/DropdownMenuRadioGroup.js";
16
+ export { DropdownMenuRadioItem as ContextMenuRadioItem } from "../DropdownMenu/DropdownMenuRadioItem.js";
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,EAAS,KAAK,WAAW,EAAC,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AAUtC,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,mBAAmB,CAAC;AAQtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAyC5C,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,kBAAkB,GAC5B,oBAAoB,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAMnE,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAEnE,UAAU,qBAAsB,SAAQ,SAAS;IAC/C,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,qBAAsB,SAAQ,qBAAqB;IAC3D,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,UAAU,yBAA0B,SAAQ,qBAAqB;IAC/D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,MAAM,iBAAiB,GAC3B,qBAAqB,GAAG,yBAAyB,CAAC;AA+BpD,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,gBAAgB,EAC5B,YAAY,EACZ,SAAS,EACT,OAAO,EACP,UAAiB,EACjB,SAAmB,EACnB,SAAS,EACT,KAAK,EACL,MAAM,EACN,aAAa,EAAE,MAAM,EACrB,GAAG,KAAK,EACT,EAAE,iBAAiB,qBAwQnB;yBArRe,YAAY"}
1
+ {"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAGf,OAAO,EAAS,KAAK,WAAW,EAAC,MAAM,WAAW,CAAC;AAEnD,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AAWtC,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,mBAAmB,CAAC;AAQtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAyC5C,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,oBAAoB,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,kBAAkB,GAC5B,oBAAoB,GAAG,mBAAmB,GAAG,mBAAmB,CAAC;AAMnE,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AAEnE,UAAU,qBAAsB,SAAQ,SAAS;IAC/C,MAAM,CAAC,EAAE,uBAAuB,CAAC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,UAAU,qBAAsB,SAAQ,qBAAqB;IAC3D,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,UAAU,yBAA0B,SAAQ,qBAAqB;IAC/D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,MAAM,MAAM,iBAAiB,GAC3B,qBAAqB,GAAG,yBAAyB,CAAC;AA+BpD,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,gBAAgB,EAC5B,YAAY,EACZ,SAAS,EACT,OAAO,EACP,UAAiB,EACjB,SAAmB,EACnB,SAAS,EACT,KAAK,EACL,MAAM,EACN,aAAa,EAAE,MAAM,EACrB,GAAG,KAAK,EACT,EAAE,iBAAiB,qBA4QnB;yBAzRe,YAAY"}
@@ -27,6 +27,7 @@ import { usePopover } from "../Popover/usePopover.js";
27
27
  import { Button } from "../Button/index.js";
28
28
  import { Icon } from "../Icon/index.js";
29
29
  import { renderDropdownItems } from "./renderDropdownItems.js";
30
+ import { MENU_ITEM_ROLES, MENU_ITEM_SELECTOR } from "./menuItemRoles.js";
30
31
  import { DropdownMenuContext } from "./DropdownMenuContext.js";
31
32
  import { useListFocus } from "../hooks/useListFocus.js";
32
33
  import { useTypeahead } from "../hooks/useTypeahead.js";
@@ -186,21 +187,24 @@ export function DropdownMenu({
186
187
  popover.hide();
187
188
  }, [popover]);
188
189
 
189
- // Single keyboard navigation path for both modes
190
+ // Single keyboard navigation path for both modes.
191
+ // The selector matches plain items plus selectable items
192
+ // (menuitemradio/menuitemcheckbox) so lab checkbox/radio rows are reachable
193
+ // and roved to alongside plain items — not just role="menuitem".
190
194
  const {
191
195
  listRef,
192
196
  handleKeyDown: listNavKeyDown,
193
197
  focusFirst,
194
198
  focusItem
195
199
  } = useListFocus({
196
- itemSelector: '[role="menuitem"]:not([aria-disabled="true"])',
200
+ itemSelector: MENU_ITEM_SELECTOR,
197
201
  wrap: false,
198
202
  onEscape: closeMenu
199
203
  });
200
204
 
201
205
  // First-character typeahead over the (enabled) menu items — jump to the next
202
206
  // item whose label starts with the typed text (menus-11).
203
- const getMenuItems = useCallback(() => listRef.current ? Array.from(listRef.current.querySelectorAll('[role="menuitem"]:not([aria-disabled="true"])')) : [], [listRef]);
207
+ const getMenuItems = useCallback(() => listRef.current ? Array.from(listRef.current.querySelectorAll(MENU_ITEM_SELECTOR)) : [], [listRef]);
204
208
  const typeahead = useTypeahead({
205
209
  getItemLabels: () => getMenuItems().map(el => el.textContent),
206
210
  onMatch: focusItem,
@@ -224,7 +228,7 @@ export function DropdownMenu({
224
228
  if (e.key === 'Enter' || e.key === ' ') {
225
229
  e.preventDefault();
226
230
  const focused = document.activeElement;
227
- if (focused?.getAttribute('role') === 'menuitem') {
231
+ if (focused && MENU_ITEM_ROLES.has(focused.getAttribute('role') ?? '')) {
228
232
  focused.click();
229
233
  }
230
234
  return;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @file DropdownMenuCheckboxItem.tsx
3
+ * @input React, stylex, Item + Icon + DropdownMenu context + tokens from core
4
+ * @output DropdownMenuCheckboxItem — a standalone checkable menu item.
5
+ * @position Sub-component; used inside DropdownMenu.
6
+ *
7
+ * A menu item that toggles an independent boolean (role="menuitemcheckbox").
8
+ * Unlike CheckboxInput, there is no nested native <input>: the row itself owns
9
+ * the role and aria-checked, per the WAI-ARIA menuitemcheckbox pattern.
10
+ * Keyboard navigation (arrows/typeahead) and Enter/Space activation come from
11
+ * the parent DropdownMenu's useListFocus + activation path, which matches
12
+ * menuitemcheckbox alongside plain menuitem rows.
13
+ *
14
+ * The square checkbox visual is decorative (aria-hidden) — the row owns the
15
+ * checked state. Its size is derived from the menu's item size (a `sm` menu
16
+ * gets the compact control; `md`/`lg` get the standard one) and it swaps to the
17
+ * inline-end of the row on coarse-pointer (touch) devices via CSS `order`, so
18
+ * it lands where selection toggles are conventionally placed on mobile. The
19
+ * checkmark uses the `check` icon from the active theme's icon registry.
20
+ */
21
+ import { type ReactNode } from 'react';
22
+ import { type IconType } from '../Icon';
23
+ import type { BaseProps } from '../BaseProps';
24
+ export interface DropdownMenuCheckboxItemProps extends Omit<BaseProps, 'onChange' | 'role' | 'aria-checked' | 'tabIndex'> {
25
+ /**
26
+ * Primary label text identifying the item.
27
+ */
28
+ label: ReactNode;
29
+ /**
30
+ * Secondary description text displayed below the label.
31
+ */
32
+ description?: ReactNode;
33
+ /**
34
+ * Icon to display before the label. Accepts a semantic icon name (see
35
+ * `npx astryx docs icons`) or a rendered node.
36
+ */
37
+ icon?: ReactNode | IconType;
38
+ /**
39
+ * Whether the item is checked. Controlled — pair with `onChange`.
40
+ */
41
+ value: boolean;
42
+ /**
43
+ * Callback fired with the next checked state when the item is toggled.
44
+ */
45
+ onChange?: (checked: boolean) => void;
46
+ /**
47
+ * Whether the item is disabled. Disabled items stay focusable (via
48
+ * `aria-disabled`) so they remain discoverable by keyboard and assistive
49
+ * technology, but activation is blocked.
50
+ * @default false
51
+ */
52
+ isDisabled?: boolean;
53
+ /**
54
+ * Whether toggling the item closes the menu. Checkbox items default to
55
+ * staying open so several can be toggled in a single session, unlike radio
56
+ * items which default to closing on selection.
57
+ * @default false
58
+ */
59
+ hasCloseOnSelect?: boolean;
60
+ /**
61
+ * Content to render after the label and description, such as a keyboard
62
+ * shortcut hint or badge.
63
+ */
64
+ endContent?: ReactNode;
65
+ }
66
+ /**
67
+ * A checkable dropdown menu item (role="menuitemcheckbox").
68
+ *
69
+ * Must be used inside a DropdownMenu. Toggles an independent boolean; for a
70
+ * one-of-N choice use DropdownMenuRadioGroup + DropdownMenuRadioItem instead.
71
+ *
72
+ * @example
73
+ * ```
74
+ * * import {DropdownMenuCheckboxItem} from '@astryxdesign/core/DropdownMenu';
75
+ *
76
+ * <DropdownMenu button={{label: 'View'}}>
77
+ * <DropdownMenuCheckboxItem
78
+ * label="Show archived"
79
+ * value={showArchived}
80
+ * onChange={setShowArchived}
81
+ * />
82
+ * </DropdownMenu>
83
+ * ```
84
+ */
85
+ export declare function DropdownMenuCheckboxItem({ label, description, icon, value, onChange, isDisabled, hasCloseOnSelect, endContent, xstyle, className, style, ...rest }: DropdownMenuCheckboxItemProps): import("react").JSX.Element;
86
+ export declare namespace DropdownMenuCheckboxItem {
87
+ var displayName: string;
88
+ }
89
+ //# sourceMappingURL=DropdownMenuCheckboxItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DropdownMenuCheckboxItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuCheckboxItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAc,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAElD,OAAO,EAAuB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAY5D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA6D5C,MAAM,WAAW,6BAA8B,SAAQ,IAAI,CACzD,SAAS,EACT,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAClD;IACC;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,WAAW,EACX,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,UAAkB,EAClB,gBAAwB,EACxB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,6BAA6B,+BAwD/B;yBArEe,wBAAwB"}