@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.
- package/CHANGELOG.md +68 -0
- package/README.md +24 -15
- package/dist/Collapsible/Collapsible.d.ts +11 -1
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +36 -4
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +4 -3
- package/dist/ContextMenu/index.d.ts +3 -0
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +7 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +8 -4
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +89 -0
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +170 -0
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -1
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +18 -0
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +69 -0
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +70 -0
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +69 -0
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +178 -0
- package/dist/DropdownMenu/index.d.ts +5 -1
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +10 -1
- package/dist/DropdownMenu/menuItemRoles.d.ts +13 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -0
- package/dist/DropdownMenu/menuItemRoles.js +15 -0
- package/dist/Icon/Icon.d.ts +17 -12
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +28 -20
- package/dist/Kbd/Kbd.js +1 -1
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +2 -0
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/index.d.ts +2 -0
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -0
- package/dist/Table/plugins/tree/index.d.ts +5 -0
- package/dist/Table/plugins/tree/index.d.ts.map +1 -0
- package/dist/Table/plugins/tree/index.js +4 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +38 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -0
- package/dist/Table/plugins/tree/useTableTreeData.js +358 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +51 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -0
- package/dist/Table/plugins/tree/useTableTreeState.js +175 -0
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +6 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +8 -1
- package/dist/astryx.css +18 -2
- package/dist/astryx.umd.js +46 -46
- package/dist/astryx.umd.js.map +4 -4
- package/dist/theme/Theme.js +1 -1
- package/dist/theme/defineTheme.d.ts +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/hct.d.ts +0 -1
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +0 -3
- package/locales/en.json +8 -0
- package/locales/pseudo.json +6 -0
- package/package.json +1 -1
- package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
- package/src/Collapsible/Collapsible.doc.mjs +7 -0
- package/src/Collapsible/Collapsible.test.tsx +80 -0
- package/src/Collapsible/Collapsible.tsx +58 -5
- package/src/ContextMenu/ContextMenu.test.tsx +75 -1
- package/src/ContextMenu/ContextMenu.tsx +10 -5
- package/src/ContextMenu/index.ts +15 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +23 -0
- package/src/DropdownMenu/DropdownMenu.tsx +11 -6
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +95 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +237 -0
- package/src/DropdownMenu/DropdownMenuContext.tsx +29 -1
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +7 -1
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +80 -0
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +119 -0
- package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +80 -0
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +232 -0
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +163 -0
- package/src/DropdownMenu/index.ts +23 -3
- package/src/DropdownMenu/menuItemRoles.ts +22 -0
- package/src/Field/Field.doc.mjs +1 -1
- package/src/Field/FieldLabel.doc.mjs +1 -1
- package/src/Icon/Icon.test.tsx +46 -0
- package/src/Icon/Icon.tsx +37 -24
- package/src/Kbd/Kbd.test.tsx +26 -0
- package/src/Kbd/Kbd.tsx +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +2 -2
- package/src/Selector/SelectorOption.doc.mjs +1 -1
- package/src/SideNav/SideNavItem.doc.mjs +2 -2
- package/src/Switch/Switch.doc.mjs +1 -1
- package/src/TabList/Tab.tsx +5 -1
- package/src/TabList/TabList.doc.mjs +3 -3
- package/src/TabList/TabList.test.tsx +66 -0
- package/src/TabList/TabList.tsx +8 -0
- package/src/TabList/TabMenu.tsx +4 -1
- package/src/Table/Table.doc.mjs +2 -0
- package/src/Table/index.ts +7 -0
- package/src/Table/plugins/tree/index.ts +12 -0
- package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +163 -0
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +594 -0
- package/src/Table/plugins/tree/useTableTreeData.tsx +495 -0
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +636 -0
- package/src/Table/plugins/tree/useTableTreeState.tsx +253 -0
- package/src/Table/useBaseTablePlugins.ts +6 -2
- package/src/Table/useTableTreeData.doc.mjs +75 -0
- package/src/Table/useTableTreeState.doc.mjs +98 -0
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextInput/TextInput.doc.mjs +1 -1
- package/src/Toolbar/Toolbar.tsx +10 -3
- package/src/theme/Theme.doc.mjs +4 -4
- package/src/theme/Theme.tsx +1 -1
- package/src/theme/defineTheme.ts +1 -1
- 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?**
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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;
|
|
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:
|
|
219
|
+
onClick: handleToggle,
|
|
220
|
+
"aria-disabled": isDisabled || undefined,
|
|
198
221
|
"aria-expanded": isOpen,
|
|
199
|
-
"aria-controls": contentId
|
|
200
|
-
|
|
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
|
-
...
|
|
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;
|
|
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:
|
|
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(
|
|
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
|
|
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;
|
|
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:
|
|
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(
|
|
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
|
|
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"}
|