@astryxdesign/core 0.7.2 → 0.7.3-canary.0bf23bd
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/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +8 -4
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +7 -0
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +19 -24
- package/dist/ClickableCard/ClickableCard.d.ts +2 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +11 -9
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +11 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +23 -5
- package/dist/DateInput/DateInput.d.ts +4 -4
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +27 -20
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +14 -8
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +14 -10
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +9 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +52 -10
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +34 -1
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +15 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +21 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +375 -42
- package/dist/DropdownMenu/menuRegionStops.d.ts +2 -2
- package/dist/DropdownMenu/menuRegionStops.js +2 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +14 -12
- package/dist/Link/Link.d.ts +2 -3
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +11 -19
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +48 -15
- package/dist/MultiSelector/MultiSelector.d.ts +4 -4
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts +2 -0
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.js +48 -0
- package/dist/MultiSelector/MultiSelector.js +25 -18
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +8 -4
- package/dist/Selector/Selector.d.ts +4 -4
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +23 -14
- package/dist/Selector/SelectorOption.d.ts.map +1 -1
- package/dist/Selector/SelectorOption.js +1 -0
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -14
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +25 -17
- package/dist/Switch/switch.markers.stylex.d.ts +2 -0
- package/dist/Switch/switch.markers.stylex.d.ts.map +1 -1
- package/dist/Switch/switch.markers.stylex.js +6 -0
- package/dist/TimeInput/TimeInput.d.ts +2 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +8 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +36 -14
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +11 -2
- package/dist/TopNav/TopNav.d.ts.map +1 -1
- package/dist/TopNav/TopNav.js +2 -2
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +1 -0
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +14 -2
- package/dist/astryx.css +8 -2
- package/dist/hooks/useMenuPress.d.ts +11 -1
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +43 -5
- package/dist/utils/disabledInteraction.d.ts +21 -0
- package/dist/utils/disabledInteraction.d.ts.map +1 -0
- package/dist/utils/disabledInteraction.js +33 -0
- package/dist/utils/timeParser.d.ts +4 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +9 -2
- package/package.json +4 -4
- package/scripts/agent-doc-state.mjs +35 -8
- package/src/Banner/Banner.spec.md +37 -32
- package/src/BottomSheet/BottomSheet.spec.md +13 -6
- package/src/BottomSheet/BottomSheet.test.tsx +29 -0
- package/src/BottomSheet/BottomSheet.tsx +8 -4
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +121 -51
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +26 -0
- package/src/BottomSheet/BottomSheetSwitcher.tsx +6 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +44 -5
- package/src/CheckboxInput/CheckboxInput.tsx +16 -26
- package/src/CheckboxInput/__tests__/Checkbox.a11y.states.ts +3 -3
- package/src/CheckboxList/CheckboxList.test.tsx +9 -6
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
- package/src/ClickableCard/ClickableCard.test.tsx +5 -4
- package/src/ClickableCard/ClickableCard.tsx +9 -9
- package/src/CodeBlock/CodeBlock.highlightStyles.test.tsx +87 -0
- package/src/CodeBlock/CodeBlock.tsx +11 -1
- package/src/ComplexSelector/ComplexSelector.focusableDisabled.test.tsx +76 -0
- package/src/ComplexSelector/ComplexSelector.tsx +21 -4
- package/src/ContextMenu/ContextMenu.test.tsx +41 -0
- package/src/DateInput/DateInput.doc.mjs +9 -8
- package/src/DateInput/DateInput.test.tsx +88 -13
- package/src/DateInput/DateInput.tsx +49 -21
- package/src/DateInput/DateInputTouch.test.tsx +22 -1
- package/src/DateInput/NativeDateField.test.tsx +29 -3
- package/src/DateInput/NativeDateField.tsx +20 -7
- package/src/DateInput/TouchDateField.tsx +24 -9
- package/src/DateRangeInput/DateRangeInput.spec.md +13 -13
- package/src/Dialog/Dialog.test.tsx +39 -0
- package/src/Dialog/Dialog.tsx +9 -4
- package/src/DropdownMenu/DropdownMenu.spec.md +33 -2
- package/src/DropdownMenu/DropdownMenu.tsx +79 -8
- package/src/DropdownMenu/DropdownMenuContext.public.test.ts +22 -0
- package/src/DropdownMenu/DropdownMenuContext.tsx +39 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +16 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +623 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +556 -99
- package/src/DropdownMenu/__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts +267 -0
- package/src/DropdownMenu/menuRegionStops.ts +2 -2
- package/src/DropdownMenu/modules/useMenuPress.spec.md +9 -0
- package/src/FieldStatus/FieldStatus.spec.md +3 -2
- package/src/FileInput/FileInput.test.tsx +30 -7
- package/src/FileInput/FileInput.tsx +21 -11
- package/src/Link/Link.test.tsx +21 -7
- package/src/Link/Link.tsx +16 -24
- package/src/Link/__tests__/Link.a11y.states.ts +1 -1
- package/src/Markdown/Markdown.rerender.test.tsx +143 -0
- package/src/Markdown/Markdown.tsx +89 -35
- package/src/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.ts +71 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +5 -5
- package/src/MultiSelector/MultiSelector.focusableDisabled.test.tsx +121 -0
- package/src/MultiSelector/MultiSelector.test.tsx +49 -7
- package/src/MultiSelector/MultiSelector.tsx +53 -29
- package/src/Popover/Popover.test.tsx +15 -0
- package/src/Popover/Popover.tsx +19 -8
- package/src/PowerSearch/PowerSearchFilterEditor.test.tsx +3 -2
- package/src/PowerSearch/PowerSearchToken.test.tsx +7 -5
- package/src/Selector/Selector.doc.mjs +4 -4
- package/src/Selector/Selector.focusableDisabled.test.tsx +127 -0
- package/src/Selector/Selector.spec.md +11 -11
- package/src/Selector/Selector.test.tsx +64 -6
- package/src/Selector/Selector.tsx +51 -21
- package/src/Selector/SelectorOption.tsx +4 -0
- package/src/SideNav/SideNav.test.tsx +35 -0
- package/src/Slider/Slider.spec.md +11 -11
- package/src/Slider/Slider.test.tsx +3 -3
- package/src/Slider/Slider.tsx +8 -15
- package/src/Switch/Switch.test.tsx +85 -8
- package/src/Switch/Switch.tsx +26 -16
- package/src/Switch/__tests__/Switch.a11y.states.ts +2 -2
- package/src/Switch/switch.markers.stylex.ts +4 -0
- package/src/Table/Table.spec.md +2 -0
- package/src/Table/plugins/infiniteScroll/useTableInfiniteScroll.spec.md +244 -0
- package/src/Table/plugins/selection/useTableSelection.test.tsx +5 -3
- package/src/Table/plugins/virtualization/useTableVirtualization.spec.md +266 -0
- package/src/TimeInput/TimeInput.doc.mjs +5 -3
- package/src/TimeInput/TimeInput.test.tsx +20 -0
- package/src/TimeInput/TimeInput.tsx +2 -1
- package/src/Token/Token.test.tsx +26 -4
- package/src/Token/Token.tsx +6 -2
- package/src/Tokenizer/Tokenizer.spec.md +28 -28
- package/src/Tooltip/Tooltip.test.tsx +51 -6
- package/src/Tooltip/Tooltip.tsx +41 -18
- package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +129 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.renders.tsx +86 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.states.ts +132 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.test.tsx +126 -0
- package/src/Tooltip/__tests__/TooltipHoverBridge.a11y.chromium.spec.ts +74 -0
- package/src/Tooltip/useTooltip.test.tsx +23 -0
- package/src/Tooltip/useTooltip.tsx +22 -9
- package/src/TopNav/TopNav.tsx +11 -1
- package/src/TopNav/TopNavHeading.tsx +1 -0
- package/src/TopNav/__tests__/TopNavMobileLongHeading.a11y.chromium.spec.ts +74 -0
- package/src/Typeahead/Typeahead.test.tsx +89 -0
- package/src/Typeahead/Typeahead.tsx +15 -2
- package/src/hooks/useMenuPress.ts +45 -7
- package/src/utils/disabledInteraction.ts +40 -0
- package/src/utils/timeParser.test.ts +11 -0
- package/src/utils/timeParser.ts +9 -2
|
@@ -61,7 +61,10 @@ import {
|
|
|
61
61
|
import {
|
|
62
62
|
DropdownMenuContext,
|
|
63
63
|
DropdownMenuRootOpenContext,
|
|
64
|
+
DropdownMenuSurfaceContext,
|
|
64
65
|
type DropdownMenuContextValue,
|
|
66
|
+
type DropdownMenuSurfaceHost,
|
|
67
|
+
type DropdownMenuSurfaceValue,
|
|
65
68
|
} from './DropdownMenuContext';
|
|
66
69
|
import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
|
|
67
70
|
import {useListFocus} from '../hooks/useListFocus';
|
|
@@ -112,6 +115,14 @@ const MENU_MAX_BLOCK_SIZE = `min(${MENU_BLOCK_CAP}, ${layerViewportInset.maxBloc
|
|
|
112
115
|
const MENU_MAX_BLOCK_SIZE_FALLBACK = `min(${MENU_BLOCK_CAP}, ${layerViewportInset.maxBlockSizeFallback})`;
|
|
113
116
|
const MENU_TRIGGER_OPEN_BACKGROUND = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
|
|
114
117
|
|
|
118
|
+
// A sub-menu's drilled-in view with a header or footer renders in the surface
|
|
119
|
+
// host that follows the menu, as the frame marked
|
|
120
|
+
// `data-astryx-submenu-regions="view"` (hidden while a deeper view shows).
|
|
121
|
+
// While one shows, the menu and its header and footer step aside. The rule
|
|
122
|
+
// reads that from the DOM, so no state mirrors which view shows.
|
|
123
|
+
const STEPS_ASIDE_FOR_VIEW =
|
|
124
|
+
':has(~ * > [data-astryx-submenu-regions="view"]:not([hidden]))';
|
|
125
|
+
|
|
115
126
|
const styles = stylex.create({
|
|
116
127
|
triggerOpen: {
|
|
117
128
|
backgroundImage: MENU_TRIGGER_OPEN_BACKGROUND,
|
|
@@ -125,7 +136,12 @@ const styles = stylex.create({
|
|
|
125
136
|
},
|
|
126
137
|
dropdown: {
|
|
127
138
|
boxSizing: 'border-box',
|
|
128
|
-
display:
|
|
139
|
+
display: {
|
|
140
|
+
default: 'flex',
|
|
141
|
+
// A sub-menu's drilled-in view with a header or footer shows in its
|
|
142
|
+
// place (see `stepsAsideForView`).
|
|
143
|
+
[STEPS_ASIDE_FOR_VIEW]: 'none',
|
|
144
|
+
},
|
|
129
145
|
flexDirection: 'column',
|
|
130
146
|
gap: spacingVars['--spacing-0-5'],
|
|
131
147
|
// Pointer opens focus this container so subsequent arrow keys and Escape
|
|
@@ -175,6 +191,22 @@ const styles = stylex.create({
|
|
|
175
191
|
flexShrink: 1,
|
|
176
192
|
minBlockSize: 0,
|
|
177
193
|
},
|
|
194
|
+
// Where a sub-menu with a header or footer renders its surface: beside the
|
|
195
|
+
// menu, never inside it. It owns no box, so the popover's layout is
|
|
196
|
+
// unchanged.
|
|
197
|
+
surfaceHost: {
|
|
198
|
+
display: 'contents',
|
|
199
|
+
},
|
|
200
|
+
// While a sub-menu's drilled-in view with its own header or footer shows
|
|
201
|
+
// in the surface host, the header and footer step aside for it, as the menu
|
|
202
|
+
// does (see `dropdown`). Derived from the DOM by the rule itself: the view
|
|
203
|
+
// is the frame in the host that is not hidden.
|
|
204
|
+
stepsAsideForView: {
|
|
205
|
+
display: {
|
|
206
|
+
default: null,
|
|
207
|
+
[STEPS_ASIDE_FOR_VIEW]: 'none',
|
|
208
|
+
},
|
|
209
|
+
},
|
|
178
210
|
region: {
|
|
179
211
|
flexShrink: 0,
|
|
180
212
|
padding: spacingVars['--spacing-1'],
|
|
@@ -1455,12 +1487,39 @@ function DropdownMenuPopover({
|
|
|
1455
1487
|
|
|
1456
1488
|
// The drill-in view stack for sub-menus on a phone.
|
|
1457
1489
|
const {drillIn, wrapContent} = useMenuDrillIn(isOpen);
|
|
1490
|
+
// The surface host is owned through a ref. State keeps only a key that
|
|
1491
|
+
// changes whenever a host element attaches, the host included when it
|
|
1492
|
+
// moves (a header or footer coming or going), so sub-menus re-render into
|
|
1493
|
+
// the element that is mounted.
|
|
1494
|
+
const surfaceHostRef = useRef<HTMLDivElement | null>(null);
|
|
1495
|
+
const [surfaceHostKey, setSurfaceHostKey] = useState(0);
|
|
1496
|
+
const attachSurfaceHost = useCallback((node: HTMLDivElement | null) => {
|
|
1497
|
+
surfaceHostRef.current = node;
|
|
1498
|
+
if (node != null) {
|
|
1499
|
+
setSurfaceHostKey(key => key + 1);
|
|
1500
|
+
}
|
|
1501
|
+
}, []);
|
|
1502
|
+
const surfaceHost = useMemo<DropdownMenuSurfaceHost>(
|
|
1503
|
+
() => ({
|
|
1504
|
+
getElement: () => (surfaceHostKey > 0 ? surfaceHostRef.current : null),
|
|
1505
|
+
}),
|
|
1506
|
+
[surfaceHostKey],
|
|
1507
|
+
);
|
|
1458
1508
|
const resolvedMaxHeight = menuMaxHeight == null ? null : `${menuMaxHeight}px`;
|
|
1459
1509
|
// Context for compound items
|
|
1460
1510
|
const contextValue = useMemo<DropdownMenuContextValue>(
|
|
1461
1511
|
() => ({closeMenu, menuSize, drillIn, menuLabel}),
|
|
1462
1512
|
[closeMenu, menuSize, drillIn, menuLabel],
|
|
1463
1513
|
);
|
|
1514
|
+
// What a sub-menu with a header or footer needs, on an internal context.
|
|
1515
|
+
const surfaceValue = useMemo<DropdownMenuSurfaceValue>(
|
|
1516
|
+
() => ({
|
|
1517
|
+
host: surfaceHost,
|
|
1518
|
+
ownerId: menuId,
|
|
1519
|
+
menuMaxHeight: resolvedMaxHeight ?? undefined,
|
|
1520
|
+
}),
|
|
1521
|
+
[surfaceHost, menuId, resolvedMaxHeight],
|
|
1522
|
+
);
|
|
1464
1523
|
|
|
1465
1524
|
// Resolve menu content: data-driven items become components
|
|
1466
1525
|
const menuContent = wrapContent(
|
|
@@ -1469,7 +1528,13 @@ function DropdownMenuPopover({
|
|
|
1469
1528
|
const hasOverflow = useMenuOverflow(listRef, menuContent, popover.isOpen);
|
|
1470
1529
|
|
|
1471
1530
|
// The header and footer sit beside the menu inside the popover, never inside
|
|
1472
|
-
// the role="menu" element: a menu holds only its rows.
|
|
1531
|
+
// the role="menu" element: a menu holds only its rows. The surface host
|
|
1532
|
+
// follows the menu, so a sub-menu with a header or footer renders beside the
|
|
1533
|
+
// menu too; while such a sub-menu's drilled-in view shows there, the menu and
|
|
1534
|
+
// the regions step aside (STEPS_ASIDE_FOR_VIEW).
|
|
1535
|
+
const surfaceHostElement = (
|
|
1536
|
+
<div ref={attachSurfaceHost} {...stylex.props(styles.surfaceHost)} />
|
|
1537
|
+
);
|
|
1473
1538
|
const renderWithRegions = (menu: ReactNode): ReactNode =>
|
|
1474
1539
|
hasRegions ? (
|
|
1475
1540
|
<div
|
|
@@ -1482,7 +1547,7 @@ function DropdownMenuPopover({
|
|
|
1482
1547
|
<div
|
|
1483
1548
|
ref={headerRef}
|
|
1484
1549
|
onKeyDown={handleRegionKeyDown}
|
|
1485
|
-
{...stylex.props(styles.region)}>
|
|
1550
|
+
{...stylex.props(styles.region, styles.stepsAsideForView)}>
|
|
1486
1551
|
{header}
|
|
1487
1552
|
</div>
|
|
1488
1553
|
)}
|
|
@@ -1491,13 +1556,17 @@ function DropdownMenuPopover({
|
|
|
1491
1556
|
<div
|
|
1492
1557
|
ref={footerRef}
|
|
1493
1558
|
onKeyDown={handleRegionKeyDown}
|
|
1494
|
-
{...stylex.props(styles.region)}>
|
|
1559
|
+
{...stylex.props(styles.region, styles.stepsAsideForView)}>
|
|
1495
1560
|
{footer}
|
|
1496
1561
|
</div>
|
|
1497
1562
|
)}
|
|
1563
|
+
{surfaceHostElement}
|
|
1498
1564
|
</div>
|
|
1499
1565
|
) : (
|
|
1500
|
-
|
|
1566
|
+
<>
|
|
1567
|
+
{menu}
|
|
1568
|
+
{surfaceHostElement}
|
|
1569
|
+
</>
|
|
1501
1570
|
);
|
|
1502
1571
|
|
|
1503
1572
|
const triggerProps: DropdownMenuTriggerProps = {
|
|
@@ -1636,9 +1705,11 @@ function DropdownMenuPopover({
|
|
|
1636
1705
|
)}>
|
|
1637
1706
|
<MenuRegionsContext value={hasRegions}>
|
|
1638
1707
|
<DropdownMenuContext value={contextValue}>
|
|
1639
|
-
<
|
|
1640
|
-
{
|
|
1641
|
-
|
|
1708
|
+
<DropdownMenuSurfaceContext value={surfaceValue}>
|
|
1709
|
+
<DropdownMenuRootOpenContext value={isOpen}>
|
|
1710
|
+
{menuContent}
|
|
1711
|
+
</DropdownMenuRootOpenContext>
|
|
1712
|
+
</DropdownMenuSurfaceContext>
|
|
1642
1713
|
</DropdownMenuContext>
|
|
1643
1714
|
</MenuRegionsContext>
|
|
1644
1715
|
</div>,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file DropdownMenuContext.public.test.ts
|
|
5
|
+
* @input The DropdownMenu barrel and its public `DropdownMenuContextValue`
|
|
6
|
+
* @output Guards that the menu context keeps its members and that the internal
|
|
7
|
+
* surface context a sub-menu with a header or footer reads is not exported
|
|
8
|
+
* @position Public API test guarding @astryxdesign/core/DropdownMenu
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {describe, expect, expectTypeOf, it} from 'vitest';
|
|
12
|
+
import * as dropdownMenu from './index';
|
|
13
|
+
import type {DropdownMenuContextValue} from './index';
|
|
14
|
+
|
|
15
|
+
describe('DropdownMenu public context', () => {
|
|
16
|
+
it('keeps its members and exports no surface context', () => {
|
|
17
|
+
expectTypeOf<keyof DropdownMenuContextValue>().toEqualTypeOf<
|
|
18
|
+
'closeMenu' | 'menuSize' | 'drillIn' | 'menuLabel'
|
|
19
|
+
>();
|
|
20
|
+
expect('DropdownMenuSurfaceContext' in dropdownMenu).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -45,7 +45,10 @@ export interface DropdownMenuDrillIn {
|
|
|
45
45
|
viewStack: ReadonlyArray<string>;
|
|
46
46
|
/** The element a shown view renders its rows into (a portal target). */
|
|
47
47
|
host: HTMLElement | null;
|
|
48
|
-
/**
|
|
48
|
+
/**
|
|
49
|
+
* Show a sub-menu's view in place of the current rows. A view with a header
|
|
50
|
+
* or footer renders into the root's surface host instead of `host`.
|
|
51
|
+
*/
|
|
49
52
|
push: (viewId: string) => void;
|
|
50
53
|
/** Return to the rows the shown view replaced. */
|
|
51
54
|
pop: () => void;
|
|
@@ -65,6 +68,41 @@ export interface DropdownMenuContextValue {
|
|
|
65
68
|
menuLabel?: string;
|
|
66
69
|
}
|
|
67
70
|
|
|
71
|
+
/**
|
|
72
|
+
* The root's surface host. The root owns the element through a ref; this
|
|
73
|
+
* object is new whenever a new element attaches, so a sub-menu re-renders
|
|
74
|
+
* into it.
|
|
75
|
+
*/
|
|
76
|
+
export interface DropdownMenuSurfaceHost {
|
|
77
|
+
/** The host element, or `null` before it attaches. */
|
|
78
|
+
getElement: () => HTMLElement | null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** What a sub-menu with a header or footer needs from the root. Internal. */
|
|
82
|
+
export interface DropdownMenuSurfaceValue {
|
|
83
|
+
/**
|
|
84
|
+
* An element inside the root's popover but outside every `role="menu"`
|
|
85
|
+
* element, where such a sub-menu renders its surface (its flyout layer, or
|
|
86
|
+
* its drilled-in view, while which the root's menu and regions step aside).
|
|
87
|
+
*/
|
|
88
|
+
host: DropdownMenuSurfaceHost;
|
|
89
|
+
/**
|
|
90
|
+
* The root menu's `id`, which a sub-menu's menu in the host names so the
|
|
91
|
+
* press model counts it, and only it, as nested in the root.
|
|
92
|
+
*/
|
|
93
|
+
ownerId: string;
|
|
94
|
+
/** The root's resolved `menuMaxHeight`, which a drilled-in view caps at. */
|
|
95
|
+
menuMaxHeight?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The root's surface; `null` under a root with none (ContextMenu). Internal,
|
|
100
|
+
* off the public menu context, and layer-scoped, so each flyout re-provides it.
|
|
101
|
+
*/
|
|
102
|
+
export const DropdownMenuSurfaceContext =
|
|
103
|
+
createLayerScopedContext<DropdownMenuSurfaceValue | null>(null);
|
|
104
|
+
DropdownMenuSurfaceContext.displayName = 'DropdownMenuSurfaceContext';
|
|
105
|
+
|
|
68
106
|
/**
|
|
69
107
|
* Whether the root menu of this layer tree is open; internal companion to
|
|
70
108
|
* `DropdownMenuContext`, on its own unexported context so the public
|
|
@@ -67,6 +67,18 @@ export const docs = {
|
|
|
67
67
|
"How the sub-menu shows its rows. 'flyout' opens them beside the row; 'drill-in' replaces the menu's rows with them and a Back row, in the same box; 'adaptive' drills in when a finger opened the menu (a coarse pointer, decided when the menu opened) and flies out otherwise.",
|
|
68
68
|
default: "'adaptive'",
|
|
69
69
|
},
|
|
70
|
+
{
|
|
71
|
+
name: 'header',
|
|
72
|
+
type: 'ReactNode',
|
|
73
|
+
description:
|
|
74
|
+
'Content above the sub-menu\'s rows and outside its menu, a field that filters them, say. It keeps its own keys and presses. With a header or footer the sub-menu\'s surface (the flyout, or the drilled-in view on a phone) is a modal dialog named by the row, beside the menu rather than inside it: the row says aria-haspopup="dialog", Tab and Shift+Tab move through the header, the rows and the footer and wrap, Escape returns to the row, and a pointer leaving the flyout closes it only once focus leaves too. A ContextMenu does not show it.',
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'footer',
|
|
78
|
+
type: 'ReactNode',
|
|
79
|
+
description:
|
|
80
|
+
"Content below the sub-menu's rows and outside its menu, a door to where the options are managed, say. Same rules as header.",
|
|
81
|
+
},
|
|
70
82
|
{
|
|
71
83
|
name: 'xstyle',
|
|
72
84
|
type: 'StyleXStyles',
|
|
@@ -77,7 +89,7 @@ export const docs = {
|
|
|
77
89
|
name: 'ref',
|
|
78
90
|
type: 'React.Ref<HTMLElement>',
|
|
79
91
|
description:
|
|
80
|
-
'Ref forwarded to the trigger row, the element carrying role="menuitem" and aria-haspopup="menu".',
|
|
92
|
+
'Ref forwarded to the trigger row, the element carrying role="menuitem" and aria-haspopup="menu" ("dialog" with a header or footer).',
|
|
81
93
|
},
|
|
82
94
|
],
|
|
83
95
|
};
|
|
@@ -100,6 +112,9 @@ export const docsDense = {
|
|
|
100
112
|
onOpenChange: 'called when flyout opens/closes',
|
|
101
113
|
presentation:
|
|
102
114
|
"'flyout' beside the row | 'drill-in' replaces the rows + Back row | 'adaptive' (default) drills in on a coarse pointer",
|
|
115
|
+
header:
|
|
116
|
+
'content above the rows, outside the menu; surface becomes a modal dialog named by the row (Tab wraps, Escape returns to the row)',
|
|
117
|
+
footer: 'content below the rows, outside the menu; same rules as header',
|
|
103
118
|
xstyle: 'StyleX styles for the trigger row',
|
|
104
119
|
ref: 'ref to the trigger row (role="menuitem")',
|
|
105
120
|
},
|