@astryxdesign/core 0.7.0-canary.fe57f54 → 0.7.0
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 +186 -0
- package/dist/BottomSheet/BottomSheet.d.ts +5 -4
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts +1 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +1 -1
- package/dist/Calendar/styles.d.ts +6 -6
- package/dist/Chat/ChatComposerInput.d.ts +0 -11
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +0 -11
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +1 -1
- package/dist/CommandPalette/CommandPaletteList.d.ts +3 -2
- package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteList.js +3 -2
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +4 -1
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +29 -13
- package/dist/DropdownMenu/DropdownMenu.d.ts +11 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +173 -11
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +13 -2
- package/dist/DropdownMenu/menuRegionsContext.d.ts +2 -0
- package/dist/DropdownMenu/menuRegionsContext.d.ts.map +1 -0
- package/dist/DropdownMenu/menuRegionsContext.js +17 -0
- package/dist/Field/inputStyles.stylex.d.ts +3 -3
- package/dist/Layout/container.stylex.d.ts +18 -20
- package/dist/Layout/container.stylex.d.ts.map +1 -1
- package/dist/Layout/container.stylex.js +15 -25
- package/dist/Layout/padding.stylex.d.ts +231 -231
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +15 -6
- package/dist/Markdown/plugins/protocol.d.ts.map +1 -1
- package/dist/Markdown/plugins/protocol.js +33 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts +5 -5
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +21 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +30 -15
- package/dist/Stack/stack.stylex.d.ts +22 -22
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +89 -14
- package/dist/Table/table.stylex.d.ts +6 -6
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
- package/dist/TimeInput/TouchTimeField.js +4 -1
- package/dist/Tokenizer/Tokenizer.d.ts +1 -12
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +1 -13
- package/dist/Typeahead/BaseTypeahead.d.ts +0 -11
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +1 -9
- package/dist/Typeahead/Typeahead.d.ts +1 -12
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +1 -13
- package/dist/astryx.css +17 -12
- package/dist/hooks/useFocusTrap.d.ts +8 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +5 -1
- package/dist/hooks/useRenamedProp.d.ts +6 -6
- package/dist/hooks/useRenamedProp.js +6 -6
- package/dist/reset.a11y.chromium.spec.d.ts +2 -0
- package/dist/reset.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/reset.a11y.chromium.spec.js +176 -0
- package/dist/theme/tokens.stylex.d.ts +30 -30
- package/dist/theme/tokens.stylex.d.ts.map +1 -1
- package/dist/theme/tokens.stylex.js +18 -15
- package/dist/theme/useTheme.d.ts +1 -1
- package/package.json +4 -4
- package/src/BottomSheet/BottomSheet.doc.mjs +4 -4
- package/src/BottomSheet/BottomSheet.tsx +5 -4
- package/src/BottomSheet/BottomSheetPanel.test.tsx +6 -9
- package/src/BottomSheet/BottomSheetPanel.tsx +2 -3
- package/src/Chat/ChatComposerInput.doc.mjs +3 -3
- package/src/Chat/ChatComposerInput.test.tsx +7 -55
- package/src/Chat/ChatComposerInput.tsx +0 -36
- package/src/Chat/useTriggerMenu.tsx +1 -4
- package/src/CommandPalette/CommandPalette.spec.md +2 -0
- package/src/CommandPalette/CommandPaletteList.spec.md +189 -0
- package/src/CommandPalette/CommandPaletteList.test.tsx +47 -0
- package/src/CommandPalette/CommandPaletteList.tsx +3 -2
- package/src/DateInput/TouchDateField.tsx +3 -1
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +60 -1
- package/src/DateTimeInput/TouchDateTimeField.tsx +31 -14
- package/src/DropdownMenu/DropdownMenu.doc.mjs +12 -0
- package/src/DropdownMenu/DropdownMenu.spec.md +65 -40
- package/src/DropdownMenu/DropdownMenu.test.tsx +457 -0
- package/src/DropdownMenu/DropdownMenu.tsx +278 -49
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +6 -3
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +2 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +11 -1
- package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +195 -0
- package/src/DropdownMenu/menuRegionsContext.ts +17 -0
- package/src/Layout/container.stylex.ts +11 -21
- package/src/Lightbox/Lightbox.test.tsx +58 -0
- package/src/Lightbox/Lightbox.tsx +12 -6
- package/src/Markdown/plugins/protocol.ts +45 -12
- package/src/Markdown/plugins/sourceLines.test.tsx +121 -0
- package/src/PowerSearch/PowerSearch.tsx +28 -1
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +284 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +41 -13
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +33 -9
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +81 -18
- package/src/TimeInput/TouchTimeField.tsx +3 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +0 -16
- package/src/Tokenizer/Tokenizer.test.tsx +12 -63
- package/src/Tokenizer/Tokenizer.tsx +1 -25
- package/src/Toolbar/Toolbar.test.tsx +29 -0
- package/src/Typeahead/BaseTypeahead.doc.mjs +0 -16
- package/src/Typeahead/BaseTypeahead.test.tsx +1 -1
- package/src/Typeahead/BaseTypeahead.tsx +1 -21
- package/src/Typeahead/Typeahead.doc.mjs +0 -7
- package/src/Typeahead/Typeahead.test.tsx +24 -42
- package/src/Typeahead/Typeahead.tsx +1 -25
- package/src/hooks/useFocusTrap.ts +5 -1
- package/src/hooks/useRenamedProp.ts +6 -6
- package/src/reset.a11y.chromium.spec.ts +178 -0
- package/src/reset.css +8 -8
- package/src/reset.test.ts +112 -0
- package/src/theme/__tests__/SpacingRootFontSize.a11y.chromium.spec.ts +198 -0
- package/src/theme/tokens.stylex.ts +18 -15
- package/src/theme/tokens.test.ts +1 -1
- package/src/theme/useTheme.test.tsx +4 -4
- package/src/theme/useTheme.ts +1 -1
|
@@ -17,6 +17,7 @@ verified_by:
|
|
|
17
17
|
packages/core/src/DropdownMenu/DropdownMenuSubMenu.test.tsx,
|
|
18
18
|
packages/core/src/DropdownMenu/__tests__/DropdownMenuDrillIn.a11y.chromium.spec.ts,
|
|
19
19
|
packages/core/src/DropdownMenu/__tests__/MenuPress.a11y.chromium.spec.ts,
|
|
20
|
+
packages/core/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts,
|
|
20
21
|
packages/core/src/BottomSheet/BottomSheet.test.tsx,
|
|
21
22
|
packages/core/src/List/List.test.tsx,
|
|
22
23
|
packages/core/src/Indicator/Indicator.test.tsx,
|
|
@@ -85,35 +86,37 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
85
86
|
## Public concepts
|
|
86
87
|
|
|
87
88
|
Consumer props, item shapes, subcomponents, and presentation policy remain
|
|
88
|
-
documented in `DropdownMenu.doc.mjs` and the subcomponent docs.
|
|
89
|
-
released default.
|
|
89
|
+
documented in `DropdownMenu.doc.mjs` and the subcomponent docs. Three component-local concepts are added, by DEC-2, DEC-3 and DEC-8; each
|
|
90
|
+
keeps its released default.
|
|
90
91
|
|
|
91
|
-
| Concept
|
|
92
|
-
|
|
|
93
|
-
| Menu height cap
|
|
94
|
-
| Trigger source
|
|
92
|
+
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
93
|
+
| ----------------- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | -------- | ------------------------ | --------- | --------------------------------------------------- |
|
|
94
|
+
| Menu height cap | `menuMaxHeight`: a number of pixels | Lifts the 300px cap for a menu that must fit its rows; the viewport still bounds it. | Pointer presentation | `300px` | `component:DropdownMenu` | stable | Ignored by the touch sheet. |
|
|
95
|
+
| Trigger source | `button` (Button props) or `renderTrigger` (render prop) | Which control the menu hangs off. `trigger` receives `DropdownMenuTriggerProps` — the press model, keyboard opens, toggle click and ARIA wiring — and names the menu. | Both presentations | `button` | `component:DropdownMenu` | stable | Both given: `trigger` wins and a dev warning fires. |
|
|
96
|
+
| Header and footer | `header`, `footer`: any React node | Content above and below the rows, beside the menu inside the same popover or sheet — never inside the `role="menu"` element. | Both presentations | none | `component:DropdownMenu` | stable | A false or empty value renders no region. |
|
|
95
97
|
|
|
96
98
|
## Behavioral and layout contract
|
|
97
99
|
|
|
98
|
-
| ID | Candidate invariant
|
|
99
|
-
| --------------------- |
|
|
100
|
-
| FR1 | Every current render contains a Trigger button. Pointer presentation renders a Pointer menu surface with pointer-owned rows and optional pointer headings, dividers, indicators, and nested flyouts. Touch presentation renders a Touch sheet frame containing a Touch menu surface, Touch heading, Touch action list, and Touch action rows.
|
|
101
|
-
| FR2 | The six current local targets are `dropdown-menu`, `dropdown-menu-item`, `dropdown-menu-radio`, `dropdown-menu-section-heading`, `dropdown-menu-divider`, and `dropdown-menu-indicator-icon`; every target remains on its current painted element.
|
|
102
|
-
| FR3 | Button owns the Trigger button, BottomSheet owns the Touch sheet frame, List owns the Touch action list and Touch action rows, Indicator owns checkbox chrome, and Icon owns ordinary rendered icons.
|
|
103
|
-
| FR4 | The same `dropdown-menu` target reaches the alternative Pointer menu surface and Touch menu surface. Pointer action rows retain `dropdown-menu-item`; touch action rows instead use List's `list-item` target.
|
|
104
|
-
| FR5 | Both menu surfaces carry `data-astryx-menu-press` and follow `module:DropdownMenu/useMenuPress` FR1–FR7: the row under the release acts, the highlight follows a held pointer, a mouse released outside closes and a finger leaves the menu open, the browser's stray click never acts, and the Pointer menu surface declares `touch-action` by overflow. Trigger opening and keyboard navigation are unchanged.
|
|
105
|
-
| FR6 | When the pointer menu closes, focus returns to the Trigger button with a visible ring only when the menu was driven by keyboard; a press outside that landed on a focusable control keeps focus there.
|
|
106
|
-
| FR7 | `menuMaxHeight` MUST replace the 300px term of the menu's and its popover viewport's block-size cap while the viewport gutters still bound both; the touch sheet ignores it.
|
|
107
|
-
| FR8 | The Trigger button opens the pointer menu on a mouse press-down and on a finger held for the long-press delay, with the module's settle rule on the opening release; pressing the trigger of an open menu closes it without reopening in the same gesture; a tap and the keyboard open as before (`module:DropdownMenu/useMenuPress` proposed FR8, FR9).
|
|
108
|
-
| Trigger source | `button` (Button props) or `renderTrigger` (render prop)
|
|
109
|
-
| FR9 | With `renderTrigger`, the rendered control MUST carry `aria-haspopup`, `aria-expanded`, `aria-controls` and the `id` the menu's `aria-labelledby` points at, and MUST receive the same press-model, keyboard-open and toggle-click handlers as the Button path; the menu is named by that control. `button` and `trigger` are mutually exclusive: both given, `trigger` wins and a dev warning fires, in both presentations. A drilled-in Back row (FR11) returns to the menu by that same name: the caller's `aria-label` when given, else the control's accessible name, read as the menu opens.
|
|
110
|
-
| Row destination | `href` (+ `target`, `rel`) on an action item
|
|
111
|
-
| FR10 | An action row with `href` MUST render as one anchor carrying `role="menuitem"` (the pointer menu) or the touch sheet's link row, routed through `LinkProvider`; a plain click MUST run `onClick`, then close the menu (`hasCloseOnSelect`), then let the browser navigate; a modified click or middle click MUST be left to the browser and MUST NOT run `onClick`; Enter and Space MUST activate through a synthesized click that carries the key's modifiers. A disabled link row has no `href`.
|
|
112
|
-
| Sub-menu presentation | `presentation` on a sub-menu row: `flyout`, `drill-in`, `adaptive`
|
|
113
|
-
| FR11 | When a compact touch display opened the pointer menu (`COMPACT_TOUCH_PRESENTATION_QUERY`, the same query the root presentation uses for its bottom sheet, sampled once as it opens) an `adaptive` sub-menu row MUST drill in: its rows and a leading Back row named "Back to <parent>" replace the menu's rows in the same Pointer menu surface, no flyout opens, the drilled list is a `menu` named by the row's label, and Back, Escape and ArrowLeft MUST return to the row with focus on it; a pick inside closes the whole menu. Roving focus and typeahead scope to the shown rows; sibling rows and dividers need no knowledge of it. `presentation="flyout"` keeps the flyout; `"drill-in"` drills in on any pointer.
|
|
114
|
-
| FR12 | In the pointer menu ArrowDown on the last enabled row wraps to the first and ArrowUp on the first to the last; PageDown and PageUp move to the last and first fully visible enabled row and, pressed there again, one viewport further without wrapping; ArrowUp on the trigger opens with the last enabled row highlighted; the key that opened the menu and its auto-repeats do not activate; typeahead matches the row's label element alone and ignores Control/Command chords and input-method composition.
|
|
115
|
-
| FR13 | On a mouse, a nested flyout stays open while the pointer is inside the triangle from where it left its row to the flyout's near edge — including while the pointer is paused there — and closes after the existing delay once the pointer has left both the row and that triangle. The row's click toggle and its guard window are unchanged.
|
|
116
|
-
| FR14 | A compound `DropdownMenuGroup` is one `role="group"` named by its heading through `aria-labelledby`; the heading carries `dropdown-menu-section-heading`, is plain text rather than a menu item, and is skipped by roving focus and typeahead. An untitled group is an unnamed `role="group"`.
|
|
100
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
101
|
+
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
102
|
+
| FR1 | Every current render contains a Trigger button. Pointer presentation renders a Pointer menu surface with pointer-owned rows and optional pointer headings, dividers, indicators, and nested flyouts. Touch presentation renders a Touch sheet frame containing a Touch menu surface, Touch heading, Touch action list, and Touch action rows. | Current source, docs, and tests | Verified current behavior; no new behavior decided |
|
|
103
|
+
| FR2 | The six current local targets are `dropdown-menu`, `dropdown-menu-item`, `dropdown-menu-radio`, `dropdown-menu-section-heading`, `dropdown-menu-divider`, and `dropdown-menu-indicator-icon`; every target remains on its current painted element. | Current source, docs, and tests | Verified current inventory; no target change |
|
|
104
|
+
| FR3 | Button owns the Trigger button, BottomSheet owns the Touch sheet frame, List owns the Touch action list and Touch action rows, Indicator owns checkbox chrome, and Icon owns ordinary rendered icons. | Current source and owner docs | Verified current delegation; no ownership change |
|
|
105
|
+
| FR4 | The same `dropdown-menu` target reaches the alternative Pointer menu surface and Touch menu surface. Pointer action rows retain `dropdown-menu-item`; touch action rows instead use List's `list-item` target. | Current source and tests | Verified modality split; no target change |
|
|
106
|
+
| FR5 | Both menu surfaces carry `data-astryx-menu-press` and follow `module:DropdownMenu/useMenuPress` FR1–FR7: the row under the release acts, the highlight follows a held pointer, a mouse released outside closes and a finger leaves the menu open, the browser's stray click never acts, and the Pointer menu surface declares `touch-action` by overflow. Trigger opening and keyboard navigation are unchanged. | `module:DropdownMenu/useMenuPress`; `DropdownMenu.test.tsx` press model suite | Proposed; verified in jsdom and real Chromium |
|
|
107
|
+
| FR6 | When the pointer menu closes, focus returns to the Trigger button with a visible ring only when the menu was driven by keyboard; a press outside that landed on a focusable control keeps focus there. | `architecture:interaction-modality` INV1; proposed in this change; `DropdownMenu.test.tsx` closing suite | Proposed; verified in jsdom, pending owner review |
|
|
108
|
+
| FR7 | `menuMaxHeight` MUST replace the 300px term of the menu's and its popover viewport's block-size cap while the viewport gutters still bound both; the touch sheet ignores it. | `component:DropdownMenu/DEC-3` | Proposed; verified in jsdom; owner to confirm DEC-3 |
|
|
109
|
+
| FR8 | The Trigger button opens the pointer menu on a mouse press-down and on a finger held for the long-press delay, with the module's settle rule on the opening release; pressing the trigger of an open menu closes it without reopening in the same gesture; a tap and the keyboard open as before (`module:DropdownMenu/useMenuPress` proposed FR8, FR9). | Proposed `module:DropdownMenu/useMenuPress/DEC-4`; `DropdownMenu.test.tsx` press model suite | Proposed; verified in jsdom, pending owner review |
|
|
110
|
+
| Trigger source | `button` (Button props) or `renderTrigger` (render prop) | Which control the menu hangs off. `trigger` receives `DropdownMenuTriggerProps` — the press model, keyboard opens, toggle click and ARIA wiring — and names the menu. | Both presentations | `button` | `component:DropdownMenu` | stable | Both given: `trigger` wins and a dev warning fires. |
|
|
111
|
+
| FR9 | With `renderTrigger`, the rendered control MUST carry `aria-haspopup`, `aria-expanded`, `aria-controls` and the `id` the menu's `aria-labelledby` points at, and MUST receive the same press-model, keyboard-open and toggle-click handlers as the Button path; the menu is named by that control. `button` and `trigger` are mutually exclusive: both given, `trigger` wins and a dev warning fires, in both presentations. A drilled-in Back row (FR11) returns to the menu by that same name: the caller's `aria-label` when given, else the control's accessible name, read as the menu opens. | `component:DropdownMenu/DEC-2` | Proposed; verified in jsdom; owner to confirm DEC-2 |
|
|
112
|
+
| Row destination | `href` (+ `target`, `rel`) on an action item | The row's act is navigation: the row itself is the link (`family:navigation-destinations`). | Pointer action row and Touch action row, compound and data mode | none (an action row) | `component:DropdownMenu` | stable | Blocked schemes follow the family rule; a disabled row has none. |
|
|
113
|
+
| FR10 | An action row with `href` MUST render as one anchor carrying `role="menuitem"` (the pointer menu) or the touch sheet's link row, routed through `LinkProvider`; a plain click MUST run `onClick`, then close the menu (`hasCloseOnSelect`), then let the browser navigate; a modified click or middle click MUST be left to the browser and MUST NOT run `onClick`; Enter and Space MUST activate through a synthesized click that carries the key's modifiers. A disabled link row has no `href`. | `component:DropdownMenu/DEC-2`; `family:navigation-destinations` | Proposed; verified in jsdom; owner to confirm DEC-1 |
|
|
114
|
+
| Sub-menu presentation | `presentation` on a sub-menu row: `flyout`, `drill-in`, `adaptive` | Whether a sub-menu opens beside its row or replaces the menu's rows with its own and a Back row, in the same box. `adaptive` drills in when a coarse pointer opened the menu. | Pointer presentation, compound and data mode | `adaptive` | `component:DropdownMenu` | stable | An unknown value reads as `adaptive`. |
|
|
115
|
+
| FR11 | When a compact touch display opened the pointer menu (`COMPACT_TOUCH_PRESENTATION_QUERY`, the same query the root presentation uses for its bottom sheet, sampled once as it opens) an `adaptive` sub-menu row MUST drill in: its rows and a leading Back row named "Back to <parent>" replace the menu's rows in the same Pointer menu surface, no flyout opens, the drilled list is a `menu` named by the row's label, and Back, Escape and ArrowLeft MUST return to the row with focus on it; a pick inside closes the whole menu. Roving focus and typeahead scope to the shown rows; sibling rows and dividers need no knowledge of it. `presentation="flyout"` keeps the flyout; `"drill-in"` drills in on any pointer. | `component:DropdownMenu/DEC-2`; `architecture:interaction-modality` | Proposed; verified in jsdom and Chromium (coarse pointer); owner to confirm DEC-5 |
|
|
116
|
+
| FR12 | In the pointer menu ArrowDown on the last enabled row wraps to the first and ArrowUp on the first to the last; PageDown and PageUp move to the last and first fully visible enabled row and, pressed there again, one viewport further without wrapping; ArrowUp on the trigger opens with the last enabled row highlighted; the key that opened the menu and its auto-repeats do not activate; typeahead matches the row's label element alone and ignores Control/Command chords and input-method composition. | Proposed in this change; `DropdownMenu.test.tsx` keyboard suite, `useListFocus.test.tsx`, `useTypeahead.test.tsx` | Proposed; verified in jsdom, pending owner review |
|
|
117
|
+
| FR13 | On a mouse, a nested flyout stays open while the pointer is inside the triangle from where it left its row to the flyout's near edge — including while the pointer is paused there — and closes after the existing delay once the pointer has left both the row and that triangle. The row's click toggle and its guard window are unchanged. | Proposed in this change; `DropdownMenuSubMenu.test.tsx` safe-triangle suite, `useMenuHover.test.tsx` | Proposed; verified in jsdom, pending owner review |
|
|
118
|
+
| FR14 | A compound `DropdownMenuGroup` is one `role="group"` named by its heading through `aria-labelledby`; the heading carries `dropdown-menu-section-heading`, is plain text rather than a menu item, and is skipped by roving focus and typeahead. An untitled group is an unnamed `role="group"`. | DEC-1, docs, and tests | Proposed; awaiting owner approval |
|
|
119
|
+
| FR15 | With `header` or `footer`, the pointer popover holds the header, then the `role="menu"` element, then the footer, and the menu element holds only its rows. A region keeps its own keys and presses: neither the menu's key handling nor its press model claims an event that begins there. The menu is one Tab stop between the regions. Tab from the menu moves to the footer, and Shift+Tab to the header, when that region holds a control Tab can reach; otherwise Tab closes the menu as before. Tab past the footer's last control or Shift+Tab before the header's first closes the menu, and focus returns to the trigger. From a row of an open sub-menu, Tab and Shift+Tab close every open flyout and continue as they do from a row of the root menu. Escape closes from anywhere in the popover. The bottom sheet shows the header above the actions and the footer below them. Without either, the menu renders and behaves exactly as it does without the props. | DEC-8, docs, and tests | Proposed; awaiting owner approval |
|
|
117
120
|
|
|
118
121
|
### Allowed variation
|
|
119
122
|
|
|
@@ -261,21 +264,22 @@ than adding a DropdownMenu-owned heading target.
|
|
|
261
264
|
|
|
262
265
|
## Verification map
|
|
263
266
|
|
|
264
|
-
| Contract | Verification | Representative states
|
|
265
|
-
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
266
|
-
| FR1, FR4 | `DropdownMenu.test.tsx` pointer, bottom-sheet, adaptive, section, divider, and drill-in suites | Root pointer, nested pointer, root touch, drill-in
|
|
267
|
-
| FR2 | DropdownMenu target suites, source inspection, and theming target inventories | All six local targets
|
|
268
|
-
| FR3 | `DropdownMenuSelectable.test.tsx` plus BottomSheet, List, Indicator, Icon, and Divider owner tests | Trigger, touch actions, icons, checkbox, radio
|
|
269
|
-
| Layer relationships | `DropdownMenu.test.tsx`, `DropdownMenuSubMenu.test.tsx`, and current layer/dismissal architecture records | Light dismiss, nested flyout, sheet dismissal
|
|
270
|
-
| FR5 | `DropdownMenu.test.tsx` press model suite; the module record's own map | Finger slide across rows, outside release by mouse and finger, `touch-action`, root marker
|
|
271
|
-
| FR6 | `DropdownMenu.test.tsx` dismissal, closing and press model suites; `__tests__/MenuPress.a11y.chromium.spec.ts` in real Chromium | keyboard/pointer dismissal, Escape after press-open, press outside on a control, pointer pick, closed menu
|
|
272
|
-
| FR7 | `menuMaxHeight` MUST replace the 300px term of the menu's and its popover viewport's block-size cap while the viewport gutters still bound both; the touch sheet ignores it. | `component:DropdownMenu/DEC-3`
|
|
273
|
-
| Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and current target inventory
|
|
274
|
-
| FR8 | `DropdownMenu.test.tsx` press model suite (trigger cases) | Press-open + drag-release, unsettled opening release, trigger toggle, held touch, tap
|
|
275
|
-
| FR9 | `DropdownMenu.test.tsx` custom trigger suite; `DropdownMenuSubMenu.test.tsx` custom-trigger Back row cases | Icon button, chip, list row; open, toggle, keyboard open, name; drill-in Back row
|
|
276
|
-
| FR8, AR2 | `DropdownMenu.test.tsx` "DropdownMenuItem href" suite (pointer menu and bottom sheet) | Plain click, ⌘-click, Enter with modifiers, disabled link row
|
|
277
|
-
| FR12, AR3 | `DropdownMenuSubMenu.test.tsx` "drill-in on a phone" suite; `__tests__/DropdownMenuDrillIn.a11y.chromium.spec.ts` (real Chromium, coarse pointer) | Drill in, Back, Escape, ArrowLeft, nested level, scoped typeahead, forced presentations, close resets
|
|
278
|
-
| FR10 | `DropdownMenuSubMenu.test.tsx` safe-triangle suite; `useMenuHover.test.tsx` `isPointInSafeTriangle` and click-guard suites | diagonal path toward the flyout, a pause inside it, path away, click-opened and hover-opened guard windows
|
|
267
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
268
|
+
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
|
|
269
|
+
| FR1, FR4 | `DropdownMenu.test.tsx` pointer, bottom-sheet, adaptive, section, divider, and drill-in suites | Root pointer, nested pointer, root touch, drill-in | Collapsing presentation-specific parts or owners fails structure, target, or role assertions. | `audit:DropdownMenu/anatomy` |
|
|
270
|
+
| FR2 | DropdownMenu target suites, source inspection, and theming target inventories | All six local targets | Removing, renaming, or assigning a current target to the wrong part fails evidence or inventory. | `audit:DropdownMenu/theming` |
|
|
271
|
+
| FR3 | `DropdownMenuSelectable.test.tsx` plus BottomSheet, List, Indicator, Icon, and Divider owner tests | Trigger, touch actions, icons, checkbox, radio | A composed part loses its owner target or is documented as a new local target. | `audit:DropdownMenu/theming` |
|
|
272
|
+
| Layer relationships | `DropdownMenu.test.tsx`, `DropdownMenuSubMenu.test.tsx`, and current layer/dismissal architecture records | Light dismiss, nested flyout, sheet dismissal | Documentation claims a shared owner where current source retains local behavior, or the reverse. | `audit:DropdownMenu/behavior` |
|
|
273
|
+
| FR5 | `DropdownMenu.test.tsx` press model suite; the module record's own map | Finger slide across rows, outside release by mouse and finger, `touch-action`, root marker | A row acting on the press or the stray click, a lost `touch-action`, or a finger release that closes fails. | `audit:DropdownMenu/behavior` |
|
|
274
|
+
| FR6 | `DropdownMenu.test.tsx` dismissal, closing and press model suites; `__tests__/MenuPress.a11y.chromium.spec.ts` in real Chromium | keyboard/pointer dismissal, Escape after press-open, press outside on a control, pointer pick, closed menu | Focus left on the body after a pointer pick, on the control focused before a press-open, or a ring after pointer input, fails. | `audit:DropdownMenu/behavior` |
|
|
275
|
+
| FR7 | `menuMaxHeight` MUST replace the 300px term of the menu's and its popover viewport's block-size cap while the viewport gutters still bound both; the touch sheet ignores it. | `component:DropdownMenu/DEC-3` | Proposed; verified in jsdom; owner to confirm DEC-3 |
|
|
276
|
+
| Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and current target inventory | Missing, extra, prefixed, stale, or unclassified mappings fail repository validation. | `audit:DropdownMenu/theming` |
|
|
277
|
+
| FR8 | `DropdownMenu.test.tsx` press model suite (trigger cases) | Press-open + drag-release, unsettled opening release, trigger toggle, held touch, tap | A menu that does not open on a mouse press, an unsettled release that acts, or a trigger that reopens in the same gesture fails. | `audit:DropdownMenu/behavior` |
|
|
278
|
+
| FR9 | `DropdownMenu.test.tsx` custom trigger suite; `DropdownMenuSubMenu.test.tsx` custom-trigger Back row cases | Icon button, chip, list row; open, toggle, keyboard open, name; drill-in Back row | A rendered control missing `aria-haspopup`, `aria-expanded` or `aria-controls`, an unnamed menu, a lost keyboard open, or a "Back to Menu" row, fails. | `audit:DropdownMenu/anatomy` |
|
|
279
|
+
| FR8, AR2 | `DropdownMenu.test.tsx` "DropdownMenuItem href" suite (pointer menu and bottom sheet) | Plain click, ⌘-click, Enter with modifiers, disabled link row | A row rendering an inner anchor, running `onClick` on a modified click, or a synthesized click dropping the modifiers fails. | `audit:DropdownMenu/behavior` |
|
|
280
|
+
| FR12, AR3 | `DropdownMenuSubMenu.test.tsx` "drill-in on a phone" suite; `__tests__/DropdownMenuDrillIn.a11y.chromium.spec.ts` (real Chromium, coarse pointer) | Drill in, Back, Escape, ArrowLeft, nested level, scoped typeahead, forced presentations, close resets | A flyout opening on a coarse pointer, a missing Back row, sibling rows staying in the order, or focus not returning to the row fails. | `audit:DropdownMenu/behavior` |
|
|
281
|
+
| FR10 | `DropdownMenuSubMenu.test.tsx` safe-triangle suite; `useMenuHover.test.tsx` `isPointInSafeTriangle` and click-guard suites | diagonal path toward the flyout, a pause inside it, path away, click-opened and hover-opened guard windows | A flyout that closes while the pointer is inside the triangle or paused in it, one that never closes after leaving it, or a changed guard-window rule, fails. | `audit:DropdownMenu/behavior` |
|
|
282
|
+
| FR15 | `DropdownMenu.test.tsx` header and footer suite; `__tests__/MenuHeaderFooter.a11y.chromium.spec.ts` in real Chromium | regions outside the menu element, typing in a header field, Tab walk header → menu → footer → close, Tab and Shift+Tab from an open sub-menu, Escape from the header, a finger tap on a footer button, bottom sheet order, no regions | A region rendered inside the menu element, a header key taken by typeahead, a Tab that leaves the menu open with focus outside it, or a footer tap swallowed by the press model fails. |
|
|
279
283
|
|
|
280
284
|
## Decision log
|
|
281
285
|
|
|
@@ -440,3 +444,24 @@ The value is a number of pixels. Rejected: an arbitrary CSS length (`50vh`,
|
|
|
440
444
|
`calc(...)`), which is product-shaped tuning on a shared component that
|
|
441
445
|
`spec:AST-002` does not admit, and which lets a caller write a cap the
|
|
442
446
|
viewport term cannot reason about.
|
|
447
|
+
|
|
448
|
+
### DEC-8 — Controls beside the rows go in `header` and `footer`
|
|
449
|
+
|
|
450
|
+
**Reference:** `component:DropdownMenu/DEC-8`
|
|
451
|
+
**Decider:** `cixzhang`, 2026-10-11
|
|
452
|
+
|
|
453
|
+
`role="menu"` admits only menu items, groups and separators. A filter field
|
|
454
|
+
or a "Create" button placed among the rows makes the menu invalid to a screen
|
|
455
|
+
reader, and makes the menu's key handling and press model fight the control.
|
|
456
|
+
The control belongs beside the menu, not in it. `header` and `footer` place it
|
|
457
|
+
there: in the same popover or sheet, outside the menu element. Outside the
|
|
458
|
+
menu element, the menu never claims the control's keys or presses. Because
|
|
459
|
+
`children` stay rows only, nothing can be placed between rows; the component
|
|
460
|
+
needs no inspection of its children to keep that true.
|
|
461
|
+
|
|
462
|
+
The menu becomes one Tab stop between the regions, so the popover reads as
|
|
463
|
+
one Tab sequence: header, menu, footer. Leaving it past either end closes the
|
|
464
|
+
menu, as Tab from the rows always has. Focus on open is unchanged. Rejected:
|
|
465
|
+
letting the menu's handlers step aside for controls placed among the rows —
|
|
466
|
+
that makes invalid structure work instead of fixing it; and a caller-wrapped
|
|
467
|
+
items element, which leaves "nothing between the rows" to convention.
|