@astryxdesign/core 0.7.2-canary.fe2c655 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +156 -2
- package/README.md +4 -4
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +40 -1
- package/dist/AspectRatio/AspectRatio.d.ts +6 -8
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +44 -3
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +8 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +5 -2
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +1 -0
- package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +3 -1
- package/dist/CheckboxList/CheckboxList.d.ts +1 -1
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +6 -2
- package/dist/CheckboxList/CheckboxListItem.d.ts +9 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +4 -2
- package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +37 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +5 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +20 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +84 -113
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -0
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +21 -0
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts +5 -3
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuDivider.js +7 -3
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts +6 -4
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuGroup.js +4 -3
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +15 -4
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +24 -0
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -0
- package/dist/DropdownMenu/lazyMenuBottomSheet.js +46 -0
- package/dist/DropdownMenu/menuRegionStops.d.ts +38 -0
- package/dist/DropdownMenu/menuRegionStops.d.ts.map +1 -0
- package/dist/DropdownMenu/menuRegionStops.js +131 -0
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +4 -10
- package/dist/Field/Field.d.ts +1 -1
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +8 -4
- package/dist/FormLayout/FormLayout.d.ts +5 -4
- package/dist/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/FormLayout/FormLayout.js +1 -1
- package/dist/FormLayout/FormLayoutContext.d.ts +3 -3
- package/dist/FormLayout/FormLayoutContext.js +3 -3
- package/dist/Grid/Grid.d.ts +8 -7
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +5 -4
- package/dist/Grid/GridSpan.d.ts +1 -1
- package/dist/Grid/GridSpan.d.ts.map +1 -1
- package/dist/Grid/GridSpan.js +1 -0
- package/dist/Heading/Heading.d.ts.map +1 -1
- package/dist/Heading/Heading.js +4 -2
- package/dist/Item/Item.d.ts +6 -2
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +19 -4
- package/dist/List/List.d.ts +46 -19
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +28 -10
- package/dist/List/ListContext.d.ts +8 -3
- package/dist/List/ListContext.d.ts.map +1 -1
- package/dist/List/ListContext.js +7 -2
- package/dist/List/ListItem.d.ts +13 -5
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +21 -8
- package/dist/List/index.d.ts +1 -1
- package/dist/List/index.d.ts.map +1 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +8 -1
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +8 -2
- package/dist/Markdown/plugins/headingLinks.d.ts.map +1 -1
- package/dist/Markdown/plugins/headingLinks.js +9 -1
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +5 -1
- package/dist/MetadataList/MetadataListContext.d.ts +1 -1
- package/dist/MetadataList/MetadataListContext.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.d.ts +9 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +30 -3
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +5 -0
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +45 -11
- package/dist/RadioList/RadioList.d.ts +1 -1
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +6 -2
- package/dist/RadioList/RadioListItem.d.ts +9 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +2 -0
- package/dist/SideNav/SideNavItem.d.ts +8 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +76 -10
- package/dist/Text/Text.d.ts.map +1 -1
- package/dist/Text/Text.js +4 -2
- package/dist/ToggleButton/ToggleButton.d.ts +3 -2
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +12 -1
- package/dist/Token/Token.js +1 -1
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +5 -3
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +5 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +1 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +2 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +57 -9
- package/dist/astryx.css +27 -4
- package/dist/hooks/useMenuHover.d.ts.map +1 -1
- package/dist/hooks/useMenuHover.js +18 -13
- package/dist/reset.a11y.chromium.spec.js +50 -1
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +15 -9
- package/docs.mjs +4 -4
- package/package.json +4 -4
- package/scripts/agent-doc-state.mjs +66 -6
- package/scripts/postinstall.mjs +44 -3
- package/src/AppShell/AppShell.tsx +45 -1
- package/src/AspectRatio/AspectRatio.test.tsx +44 -43
- package/src/AspectRatio/AspectRatio.tsx +38 -18
- package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +157 -0
- package/src/Avatar/Avatar.doc.mjs +5 -3
- package/src/Avatar/Avatar.tsx +11 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +3 -2
- package/src/AvatarGroup/AvatarGroupOverflow.test.tsx +24 -1
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +4 -1
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +30 -1
- package/src/Card/Card.doc.mjs +1 -1
- package/src/Chat/ChatLayoutScrollButton.test.tsx +13 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +4 -2
- package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +64 -19
- package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +3 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
- package/src/CheckboxInput/CheckboxInput.tsx +3 -1
- package/src/CheckboxList/CheckboxList.fr10.test.tsx +29 -2
- package/src/CheckboxList/CheckboxList.test.tsx +22 -0
- package/src/CheckboxList/CheckboxList.tsx +4 -1
- package/src/CheckboxList/CheckboxListItem.doc.mjs +16 -0
- package/src/CheckboxList/CheckboxListItem.tsx +10 -0
- package/src/Code/Code.doc.mjs +1 -0
- package/src/CommandPalette/CommandPalette.doc.mjs +2 -0
- package/src/CommandPalette/CommandPaletteInput.test.tsx +53 -4
- package/src/CommandPalette/CommandPaletteInput.tsx +33 -3
- package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +335 -0
- package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +292 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +2 -3
- package/src/ContextMenu/ContextMenu.test.tsx +12 -2
- package/src/ContextMenu/ContextMenu.tsx +4 -1
- package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +438 -0
- package/src/Dialog/Dialog.test.tsx +46 -0
- package/src/Dialog/Dialog.tsx +20 -7
- package/src/Dialog/__tests__/Dialog.a11y.known-failures.ts +0 -14
- package/src/Drawer/Drawer.doc.mjs +1 -0
- package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +57 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +79 -6
- package/src/DropdownMenu/DropdownMenu.tsx +88 -144
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +1 -1
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -1
- package/src/DropdownMenu/DropdownMenuContext.tsx +24 -0
- package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +2 -2
- package/src/DropdownMenu/DropdownMenuDivider.spec.md +192 -0
- package/src/DropdownMenu/DropdownMenuDivider.tsx +9 -5
- package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +169 -10
- package/src/DropdownMenu/DropdownMenuGroup.tsx +6 -4
- package/src/DropdownMenu/DropdownMenuLazySheet.test.tsx +126 -0
- package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +1 -1
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +185 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +17 -3
- package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +280 -0
- package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +334 -0
- package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +43 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +71 -0
- package/src/DropdownMenu/menuRegionStops.ts +167 -0
- package/src/EmptyState/EmptyState.doc.mjs +3 -2
- package/src/EmptyState/EmptyState.spec.md +189 -0
- package/src/EmptyState/EmptyState.test.tsx +74 -3
- package/src/EmptyState/EmptyState.tsx +4 -8
- package/src/Field/Field.doc.mjs +14 -8
- package/src/Field/Field.spec.md +217 -0
- package/src/Field/Field.test.tsx +60 -2
- package/src/Field/Field.tsx +17 -8
- package/src/Field/FieldLabel.doc.mjs +133 -26
- package/src/Field/FieldLabel.spec.md +172 -0
- package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +296 -0
- package/src/FormLayout/FormLayout.doc.mjs +6 -3
- package/src/FormLayout/FormLayout.spec.md +192 -0
- package/src/FormLayout/FormLayout.test.tsx +15 -0
- package/src/FormLayout/FormLayout.tsx +7 -6
- package/src/FormLayout/FormLayoutContext.ts +3 -3
- package/src/Grid/Grid.doc.mjs +7 -1
- package/src/Grid/Grid.spec.md +93 -113
- package/src/Grid/Grid.test.tsx +22 -0
- package/src/Grid/Grid.tsx +10 -9
- package/src/Grid/GridSpan.doc.mjs +3 -3
- package/src/Grid/GridSpan.tsx +4 -1
- package/src/Heading/Heading.test.tsx +57 -0
- package/src/Heading/Heading.tsx +6 -2
- package/src/Icon/Icon.doc.mjs +36 -0
- package/src/Indicator/Indicator.doc.mjs +3 -3
- package/src/Item/Item.doc.mjs +12 -8
- package/src/Item/Item.test.tsx +61 -0
- package/src/Item/Item.tsx +40 -4
- package/src/Layout/LayoutHeader.doc.mjs +5 -0
- package/src/List/List.doc.mjs +14 -1
- package/src/List/List.spec.md +129 -77
- package/src/List/List.test.tsx +163 -94
- package/src/List/List.tsx +74 -18
- package/src/List/ListContext.tsx +9 -3
- package/src/List/ListItem.doc.mjs +16 -0
- package/src/List/ListItem.tsx +56 -27
- package/src/List/index.ts +1 -1
- package/src/Markdown/Markdown.tsx +14 -1
- package/src/Markdown/parser.ts +8 -2
- package/src/Markdown/plugins/headingLinks.ts +9 -1
- package/src/MetadataList/MetadataList.doc.mjs +3 -3
- package/src/MetadataList/MetadataList.test.tsx +38 -0
- package/src/MetadataList/MetadataList.tsx +8 -1
- package/src/MetadataList/MetadataListContext.tsx +1 -1
- package/src/MobileNav/MobileNav.tsx +30 -3
- package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +173 -15
- package/src/MoreMenu/MoreMenu.test.tsx +5 -1
- package/src/PowerSearch/PowerSearch.test.tsx +62 -0
- package/src/PowerSearch/PowerSearch.tsx +9 -0
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +71 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +45 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +1 -0
- package/src/RadioList/RadioList.fr10.test.tsx +45 -2
- package/src/RadioList/RadioList.test.tsx +22 -0
- package/src/RadioList/RadioList.tsx +4 -1
- package/src/RadioList/RadioListItem.doc.mjs +16 -0
- package/src/RadioList/RadioListItem.tsx +10 -1
- package/src/Resizable/useResizable.doc.mjs +2 -0
- package/src/ScrollableArea/ScrollableArea.doc.mjs +1 -1
- package/src/SideNav/SideNav.spec.md +227 -0
- package/src/SideNav/SideNav.test.tsx +220 -0
- package/src/SideNav/SideNavItem.doc.mjs +2 -2
- package/src/SideNav/SideNavItem.tsx +99 -17
- package/src/Slider/Slider.spec.md +39 -18
- package/src/Spinner/Spinner.doc.mjs +1 -1
- package/src/TabList/TabList.spec.md +57 -44
- package/src/Table/Table.spec.md +6 -1
- package/src/Table/plugins/activation/useTableActivation.spec.md +254 -0
- package/src/Text/Text.test.tsx +57 -0
- package/src/Text/Text.tsx +6 -2
- package/src/TimeInput/TimeInput.fr10.test.tsx +15 -0
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/ToggleButton/ToggleButton.test.tsx +95 -0
- package/src/ToggleButton/ToggleButton.tsx +12 -1
- package/src/ToggleButton/ToggleButtonGroup.doc.mjs +4 -0
- package/src/Token/Token.tsx +1 -1
- package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +86 -0
- package/src/Toolbar/Toolbar.test.tsx +0 -8
- package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +163 -0
- package/src/Toolbar/__tests__/Toolbar.a11y.renders.tsx +63 -0
- package/src/Toolbar/__tests__/Toolbar.a11y.states.ts +142 -0
- package/src/Toolbar/__tests__/Toolbar.a11y.test.tsx +126 -0
- package/src/TopNav/TopNavMegaMenu.test.tsx +47 -0
- package/src/TopNav/TopNavMegaMenu.tsx +9 -3
- package/src/TopNav/TopNavMenu.test.tsx +46 -1
- package/src/TopNav/TopNavMenu.tsx +13 -3
- package/src/TreeList/TreeList.doc.mjs +1 -0
- package/src/TreeList/TreeList.test.tsx +327 -6
- package/src/TreeList/TreeList.tsx +5 -1
- package/src/TreeList/TreeListBranches.tsx +6 -0
- package/src/TreeList/TreeListItem.tsx +88 -13
- package/src/docPropLiterals.test.ts +36 -10
- package/src/hooks/useMenuHover.ts +18 -13
- package/src/postinstall.test.mjs +79 -0
- package/src/reset.a11y.chromium.spec.ts +52 -1
- package/src/reset.css +9 -29
- package/src/reset.test.ts +11 -0
- package/src/theme/derivedVarRegistry.test.ts +7 -0
- package/src/unicodePropertyEscapes.source-build.test.mjs +69 -0
- package/src/utils/plainDate.test.ts +37 -1
- package/src/utils/plainDate.ts +15 -5
|
@@ -1494,3 +1494,188 @@ describe('DropdownMenuSubMenu drill-in on a phone', () => {
|
|
|
1494
1494
|
screen.getAllByRole('menu', {name, ...h}).find(isShown);
|
|
1495
1495
|
});
|
|
1496
1496
|
});
|
|
1497
|
+
|
|
1498
|
+
describe('DropdownMenuSubMenu light dismiss of the root menu (#6893)', () => {
|
|
1499
|
+
// The browser closes the root `popover=\"auto\"` element itself on an outside
|
|
1500
|
+
// tap; that path never reaches the submenu, whose flyout is
|
|
1501
|
+
// `popover=\"manual\"`. Simulate it by hiding the root popover element
|
|
1502
|
+
// directly, exactly what light dismiss does to it.
|
|
1503
|
+
function lightDismissRootMenu() {
|
|
1504
|
+
const menu = screen.getByRole('menu', {name: /Actions/, hidden: true});
|
|
1505
|
+
const rootPopover = menu.closest<HTMLElement>('[popover]');
|
|
1506
|
+
expect(rootPopover).not.toBeNull();
|
|
1507
|
+
act(() => {
|
|
1508
|
+
rootPopover!.hidePopover();
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
function getFlyoutPopover(name: RegExp) {
|
|
1513
|
+
const flyout = screen.getByRole('menu', {name, hidden: true});
|
|
1514
|
+
return flyout.closest<HTMLElement>('[popover]');
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
it('closes an open flyout when the root menu is light-dismissed', async () => {
|
|
1518
|
+
const user = userEvent.setup();
|
|
1519
|
+
render(<MoveMenu />);
|
|
1520
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
1521
|
+
const trigger = screen.getByRole('menuitem', {
|
|
1522
|
+
name: /Move to/,
|
|
1523
|
+
hidden: true,
|
|
1524
|
+
});
|
|
1525
|
+
await user.click(trigger);
|
|
1526
|
+
await waitFor(() => {
|
|
1527
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
1528
|
+
});
|
|
1529
|
+
const flyoutPopover = getFlyoutPopover(/Move to/);
|
|
1530
|
+
expect(flyoutPopover).toHaveAttribute('popover-open', '');
|
|
1531
|
+
|
|
1532
|
+
lightDismissRootMenu();
|
|
1533
|
+
|
|
1534
|
+
await waitFor(() => {
|
|
1535
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
1536
|
+
});
|
|
1537
|
+
expect(flyoutPopover).not.toHaveAttribute('popover-open');
|
|
1538
|
+
});
|
|
1539
|
+
|
|
1540
|
+
it('leaves the submenu collapsed when the menu reopens after a light dismiss', async () => {
|
|
1541
|
+
const user = userEvent.setup();
|
|
1542
|
+
render(<MoveMenu />);
|
|
1543
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
1544
|
+
const trigger = screen.getByRole('menuitem', {
|
|
1545
|
+
name: /Move to/,
|
|
1546
|
+
hidden: true,
|
|
1547
|
+
});
|
|
1548
|
+
await user.click(trigger);
|
|
1549
|
+
await waitFor(() => {
|
|
1550
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
lightDismissRootMenu();
|
|
1554
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
1555
|
+
|
|
1556
|
+
await waitFor(() => {
|
|
1557
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
1558
|
+
});
|
|
1559
|
+
expect(getFlyoutPopover(/Move to/)).not.toHaveAttribute('popover-open');
|
|
1560
|
+
});
|
|
1561
|
+
|
|
1562
|
+
it('closes an open flyout when the root menu closes via controlled isMenuOpen', async () => {
|
|
1563
|
+
const user = userEvent.setup();
|
|
1564
|
+
function ControlledMenu() {
|
|
1565
|
+
const [open, setOpen] = useState(true);
|
|
1566
|
+
return (
|
|
1567
|
+
<>
|
|
1568
|
+
<DropdownMenu
|
|
1569
|
+
button={{label: 'Actions'}}
|
|
1570
|
+
isMenuOpen={open}
|
|
1571
|
+
onOpenChange={setOpen}>
|
|
1572
|
+
<DropdownMenuSubMenu label="Move to">
|
|
1573
|
+
<DropdownMenuItem label="Folder A" onClick={() => {}} />
|
|
1574
|
+
</DropdownMenuSubMenu>
|
|
1575
|
+
</DropdownMenu>
|
|
1576
|
+
<button type="button" onClick={() => setOpen(false)}>
|
|
1577
|
+
close it
|
|
1578
|
+
</button>
|
|
1579
|
+
</>
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1582
|
+
render(<ControlledMenu />);
|
|
1583
|
+
const trigger = screen.getByRole('menuitem', {
|
|
1584
|
+
name: /Move to/,
|
|
1585
|
+
hidden: true,
|
|
1586
|
+
});
|
|
1587
|
+
await user.click(trigger);
|
|
1588
|
+
await waitFor(() => {
|
|
1589
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
1590
|
+
});
|
|
1591
|
+
const flyoutPopover = getFlyoutPopover(/Move to/);
|
|
1592
|
+
|
|
1593
|
+
await user.click(screen.getByRole('button', {name: /close it/}));
|
|
1594
|
+
|
|
1595
|
+
await waitFor(() => {
|
|
1596
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
1597
|
+
});
|
|
1598
|
+
expect(flyoutPopover).not.toHaveAttribute('popover-open');
|
|
1599
|
+
});
|
|
1600
|
+
|
|
1601
|
+
it('closes flyouts nested two levels deep on light dismiss', async () => {
|
|
1602
|
+
const user = userEvent.setup();
|
|
1603
|
+
render(
|
|
1604
|
+
<DropdownMenu button={{label: 'Actions'}}>
|
|
1605
|
+
<DropdownMenuSubMenu label="Move to">
|
|
1606
|
+
<DropdownMenuSubMenu label="Deeper">
|
|
1607
|
+
<DropdownMenuItem label="Leaf" onClick={() => {}} />
|
|
1608
|
+
</DropdownMenuSubMenu>
|
|
1609
|
+
</DropdownMenuSubMenu>
|
|
1610
|
+
</DropdownMenu>,
|
|
1611
|
+
);
|
|
1612
|
+
await user.click(screen.getByRole('button', {name: /Actions/}));
|
|
1613
|
+
const first = screen.getByRole('menuitem', {
|
|
1614
|
+
name: /Move to/,
|
|
1615
|
+
hidden: true,
|
|
1616
|
+
});
|
|
1617
|
+
await user.click(first);
|
|
1618
|
+
await waitFor(() => {
|
|
1619
|
+
expect(first).toHaveAttribute('aria-expanded', 'true');
|
|
1620
|
+
});
|
|
1621
|
+
const deeper = screen.getByRole('menuitem', {
|
|
1622
|
+
name: /Deeper/,
|
|
1623
|
+
hidden: true,
|
|
1624
|
+
});
|
|
1625
|
+
await user.click(deeper);
|
|
1626
|
+
await waitFor(() => {
|
|
1627
|
+
expect(deeper).toHaveAttribute('aria-expanded', 'true');
|
|
1628
|
+
});
|
|
1629
|
+
const firstPopover = getFlyoutPopover(/Move to/);
|
|
1630
|
+
const deeperPopover = getFlyoutPopover(/Deeper/);
|
|
1631
|
+
|
|
1632
|
+
lightDismissRootMenu();
|
|
1633
|
+
|
|
1634
|
+
await waitFor(() => {
|
|
1635
|
+
expect(first).toHaveAttribute('aria-expanded', 'false');
|
|
1636
|
+
});
|
|
1637
|
+
await waitFor(() => {
|
|
1638
|
+
expect(deeper).toHaveAttribute('aria-expanded', 'false');
|
|
1639
|
+
});
|
|
1640
|
+
expect(firstPopover).not.toHaveAttribute('popover-open');
|
|
1641
|
+
expect(deeperPopover).not.toHaveAttribute('popover-open');
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
// Regression for the stale hover timer: a hover over the submenu trigger
|
|
1645
|
+
// schedules an open after the show delay. A press on the same trigger
|
|
1646
|
+
// cancels its own scheduled hover-open (that is the click guard), so the
|
|
1647
|
+
// way a timer is still pending at close time is a close that comes from
|
|
1648
|
+
// elsewhere — here the root menu's light dismiss, the #6893 case. The
|
|
1649
|
+
// close must cancel the scheduled hover-open: once the delay elapses the
|
|
1650
|
+
// flyout stays closed instead of reopening behind the dismissed menu.
|
|
1651
|
+
// Time is driven manually so the dismiss lands inside the show delay;
|
|
1652
|
+
// auto-advancing timers would let the hover-open fire before it.
|
|
1653
|
+
it('cancels a hover-open scheduled before the menu was closed from elsewhere', async () => {
|
|
1654
|
+
vi.useFakeTimers();
|
|
1655
|
+
try {
|
|
1656
|
+
render(<MoveMenu />);
|
|
1657
|
+
fireEvent.click(screen.getByRole('button', {name: /Actions/}));
|
|
1658
|
+
const trigger = screen.getByRole('menuitem', {
|
|
1659
|
+
name: /Move to/,
|
|
1660
|
+
hidden: true,
|
|
1661
|
+
});
|
|
1662
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
1663
|
+
|
|
1664
|
+
// Schedules the hover-open (default show delay 150ms).
|
|
1665
|
+
fireEvent.mouseEnter(trigger);
|
|
1666
|
+
|
|
1667
|
+
// Close from elsewhere while the hover-open is still pending.
|
|
1668
|
+
lightDismissRootMenu();
|
|
1669
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
1670
|
+
|
|
1671
|
+
// The scheduled delay passes; the flyout must stay closed.
|
|
1672
|
+
await act(async () => {
|
|
1673
|
+
vi.advanceTimersByTime(300);
|
|
1674
|
+
});
|
|
1675
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
1676
|
+
expect(getFlyoutPopover(/Move to/)).not.toHaveAttribute('popover-open');
|
|
1677
|
+
} finally {
|
|
1678
|
+
vi.useRealTimers();
|
|
1679
|
+
}
|
|
1680
|
+
});
|
|
1681
|
+
});
|
|
@@ -97,7 +97,9 @@ import {
|
|
|
97
97
|
} from './menuItemRoles';
|
|
98
98
|
import {
|
|
99
99
|
DropdownMenuContext,
|
|
100
|
+
DropdownMenuRootOpenContext,
|
|
100
101
|
useDropdownMenuContext,
|
|
102
|
+
useDropdownMenuRootOpen,
|
|
101
103
|
type DropdownMenuContextValue,
|
|
102
104
|
} from './DropdownMenuContext';
|
|
103
105
|
import {focusMenuItemOnHover} from './menuItemHover';
|
|
@@ -451,13 +453,17 @@ export function DropdownMenuSubMenu(
|
|
|
451
453
|
// Hover intent and the shared hover→click guard only: this level owns its own
|
|
452
454
|
// click handling, roving focus and typeahead. popover="manual", so the
|
|
453
455
|
// invoker wiring other consumers need does not apply. A drill-in row has no
|
|
454
|
-
// hover: a finger drives it, and a press opens it.
|
|
456
|
+
// hover: a finger drives it, and a press opens it. Hover is also gated on
|
|
457
|
+
// the root menu being open, so a hover-open scheduled before the menu
|
|
458
|
+
// closed from elsewhere is cancelled instead of firing into the hidden
|
|
459
|
+
// menu (#6893).
|
|
460
|
+
const isRootMenuOpen = useDropdownMenuRootOpen();
|
|
455
461
|
const {triggerProps, contentProps, confirmHoverOpen} =
|
|
456
462
|
useMenuHover<HTMLDivElement>({
|
|
457
463
|
show: showLayer,
|
|
458
464
|
hide: hideLayer,
|
|
459
465
|
isOpen: isFlyoutOpen,
|
|
460
|
-
isEnabled: canOpen && !isDrillIn,
|
|
466
|
+
isEnabled: canOpen && !isDrillIn && isRootMenuOpen,
|
|
461
467
|
// The safe triangle toward the flyout's near edge is built from the
|
|
462
468
|
// flyout this component renders, not the hook's own list ref.
|
|
463
469
|
flyoutRef: menuRef,
|
|
@@ -770,7 +776,7 @@ export function DropdownMenuSubMenu(
|
|
|
770
776
|
: flyoutStyles.popoverCustomWidth(resolvedMenuWidth.value)
|
|
771
777
|
: flyoutStyles.popover;
|
|
772
778
|
|
|
773
|
-
const
|
|
779
|
+
const nestedRows = (
|
|
774
780
|
<DropdownMenuContext value={nestedMenuContext}>
|
|
775
781
|
{isDrillIn && (
|
|
776
782
|
<DropdownMenuItem
|
|
@@ -790,6 +796,14 @@ export function DropdownMenuSubMenu(
|
|
|
790
796
|
{children}
|
|
791
797
|
</DropdownMenuContext>
|
|
792
798
|
);
|
|
799
|
+
// Nested rows live in this level's flyout, a layer of their own where the
|
|
800
|
+
// layer-scoped signal resets; re-provide it so their pending hover intent
|
|
801
|
+
// dies with the root menu too.
|
|
802
|
+
const nestedContent = (
|
|
803
|
+
<DropdownMenuRootOpenContext value={isRootMenuOpen}>
|
|
804
|
+
{nestedRows}
|
|
805
|
+
</DropdownMenuRootOpenContext>
|
|
806
|
+
);
|
|
793
807
|
|
|
794
808
|
return (
|
|
795
809
|
<>
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file DropdownMenuDividerAudit.a11y.chromium.spec.ts
|
|
5
|
+
* @input Exact-head DropdownMenuDivider story across themes, color modes, direction, and viewport widths
|
|
6
|
+
* @output Screenshots and fail-closed sensor receipts for the DropdownMenuDivider component audit
|
|
7
|
+
* @position Component-owned Night Watch browser evidence; CI runs it only for a DropdownMenuDivider audit pull request
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {createHash} from 'node:crypto';
|
|
11
|
+
import {execFileSync} from 'node:child_process';
|
|
12
|
+
import * as fs from 'node:fs';
|
|
13
|
+
import * as path from 'node:path';
|
|
14
|
+
import {expect, test, type Page} from '@playwright/test';
|
|
15
|
+
import {holdMotionStill} from '@astryxdesign/a11y-spec/chromium';
|
|
16
|
+
import {
|
|
17
|
+
DEFAULT_STORYBOOK_DIR,
|
|
18
|
+
serveStorybook,
|
|
19
|
+
type StaticServer,
|
|
20
|
+
} from '@astryxdesign/a11y-spec/storybook';
|
|
21
|
+
|
|
22
|
+
const OUTPUT = path.resolve('dropdown-menu-divider-audit-evidence');
|
|
23
|
+
const STORY_ID = 'core-dropdownmenudivider--menu-separator';
|
|
24
|
+
const WIDE = {width: 1024, height: 768};
|
|
25
|
+
const NARROW = {width: 320, height: 720};
|
|
26
|
+
|
|
27
|
+
type Mode = 'light' | 'dark';
|
|
28
|
+
type Direction = 'ltr' | 'rtl';
|
|
29
|
+
type Theme = 'neutral' | 'butter';
|
|
30
|
+
type AuditCase = {
|
|
31
|
+
key: string;
|
|
32
|
+
mode: Mode;
|
|
33
|
+
direction: Direction;
|
|
34
|
+
theme: Theme;
|
|
35
|
+
viewport: {width: number; height: number};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const cases: AuditCase[] = [
|
|
39
|
+
{
|
|
40
|
+
key: 'neutral-light',
|
|
41
|
+
mode: 'light',
|
|
42
|
+
direction: 'ltr',
|
|
43
|
+
theme: 'neutral',
|
|
44
|
+
viewport: WIDE,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'neutral-dark',
|
|
48
|
+
mode: 'dark',
|
|
49
|
+
direction: 'ltr',
|
|
50
|
+
theme: 'neutral',
|
|
51
|
+
viewport: WIDE,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
key: 'butter-light',
|
|
55
|
+
mode: 'light',
|
|
56
|
+
direction: 'ltr',
|
|
57
|
+
theme: 'butter',
|
|
58
|
+
viewport: WIDE,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: 'butter-dark',
|
|
62
|
+
mode: 'dark',
|
|
63
|
+
direction: 'ltr',
|
|
64
|
+
theme: 'butter',
|
|
65
|
+
viewport: WIDE,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'rtl-light',
|
|
69
|
+
mode: 'light',
|
|
70
|
+
direction: 'rtl',
|
|
71
|
+
theme: 'neutral',
|
|
72
|
+
viewport: WIDE,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
key: 'rtl-dark',
|
|
76
|
+
mode: 'dark',
|
|
77
|
+
direction: 'rtl',
|
|
78
|
+
theme: 'neutral',
|
|
79
|
+
viewport: WIDE,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
key: 'narrow-light',
|
|
83
|
+
mode: 'light',
|
|
84
|
+
direction: 'ltr',
|
|
85
|
+
theme: 'neutral',
|
|
86
|
+
viewport: NARROW,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
key: 'narrow-dark',
|
|
90
|
+
mode: 'dark',
|
|
91
|
+
direction: 'ltr',
|
|
92
|
+
theme: 'neutral',
|
|
93
|
+
viewport: NARROW,
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
test.describe.configure({mode: 'serial', retries: 0});
|
|
98
|
+
let server: StaticServer;
|
|
99
|
+
let checkoutSha: string;
|
|
100
|
+
let storybookSha: string;
|
|
101
|
+
|
|
102
|
+
function storyUrl(item: AuditCase) {
|
|
103
|
+
return `${server.origin}/iframe.html?id=${STORY_ID}&viewMode=story&globals=colorMode:${item.mode};astryxTheme:${item.theme};direction:${item.direction}`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function settle(page: Page) {
|
|
107
|
+
await holdMotionStill(page);
|
|
108
|
+
await page.evaluate(async () => document.fonts.ready);
|
|
109
|
+
await page.waitForTimeout(40);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
test.beforeAll(async () => {
|
|
113
|
+
fs.rmSync(OUTPUT, {recursive: true, force: true});
|
|
114
|
+
fs.mkdirSync(OUTPUT, {recursive: true});
|
|
115
|
+
checkoutSha = execFileSync('git', ['rev-parse', 'HEAD'], {
|
|
116
|
+
encoding: 'utf8',
|
|
117
|
+
}).trim();
|
|
118
|
+
const expected = process.env.ASTRYX_HEAD_SHA;
|
|
119
|
+
if (expected && expected !== checkoutSha) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`checkout ${checkoutSha} does not match expected head ${expected}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
server = await serveStorybook(
|
|
125
|
+
process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
|
|
126
|
+
);
|
|
127
|
+
const response = await fetch(`${server.origin}/astryx-build-sha.txt`);
|
|
128
|
+
if (!response.ok) {
|
|
129
|
+
throw new Error(`Storybook build has no SHA stamp (${response.status})`);
|
|
130
|
+
}
|
|
131
|
+
storybookSha = (await response.text()).trim();
|
|
132
|
+
if (storybookSha !== checkoutSha) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`Storybook ${storybookSha} does not match checkout ${checkoutSha}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test.afterAll(async () => {
|
|
140
|
+
await server?.close();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
for (const item of cases) {
|
|
144
|
+
test(item.key, async ({browser}) => {
|
|
145
|
+
const context = await browser.newContext({
|
|
146
|
+
viewport: item.viewport,
|
|
147
|
+
colorScheme: item.mode,
|
|
148
|
+
reducedMotion: 'reduce',
|
|
149
|
+
});
|
|
150
|
+
const page = await context.newPage();
|
|
151
|
+
const pageErrors: string[] = [];
|
|
152
|
+
page.on('pageerror', error => pageErrors.push(String(error)));
|
|
153
|
+
await page.goto(storyUrl(item), {waitUntil: 'load'});
|
|
154
|
+
await page.locator('#storybook-root').waitFor();
|
|
155
|
+
const menu = page.getByRole('menu').last();
|
|
156
|
+
await expect(menu).toBeVisible();
|
|
157
|
+
const separator = page.getByRole('separator');
|
|
158
|
+
await expect(separator).toBeVisible();
|
|
159
|
+
await expect(separator).toHaveAttribute('aria-orientation', 'horizontal');
|
|
160
|
+
await settle(page);
|
|
161
|
+
|
|
162
|
+
const menuItems = page.getByRole('menuitem');
|
|
163
|
+
await expect(menuItems).toHaveCount(2);
|
|
164
|
+
await menu.focus();
|
|
165
|
+
await page.keyboard.press('ArrowDown');
|
|
166
|
+
await expect(menuItems.first()).toBeFocused();
|
|
167
|
+
await page.keyboard.press('ArrowDown');
|
|
168
|
+
await expect(menuItems.last()).toBeFocused();
|
|
169
|
+
await expect(separator).not.toBeFocused();
|
|
170
|
+
|
|
171
|
+
const observed = await separator.evaluate(element => {
|
|
172
|
+
const rootBox = element.getBoundingClientRect();
|
|
173
|
+
const rule = element.firstElementChild;
|
|
174
|
+
const ruleBox = rule?.getBoundingClientRect() ?? null;
|
|
175
|
+
const rootStyle = getComputedStyle(element);
|
|
176
|
+
const ruleStyle = rule ? getComputedStyle(rule) : null;
|
|
177
|
+
return {
|
|
178
|
+
theme: document
|
|
179
|
+
.querySelector('[data-astryx-theme]')
|
|
180
|
+
?.getAttribute('data-astryx-theme'),
|
|
181
|
+
mode: document.documentElement.getAttribute('data-theme'),
|
|
182
|
+
direction: rootStyle.direction,
|
|
183
|
+
viewport: {width: innerWidth, height: innerHeight},
|
|
184
|
+
reducedMotion: matchMedia('(prefers-reduced-motion: reduce)').matches,
|
|
185
|
+
horizontalOverflow:
|
|
186
|
+
document.documentElement.scrollWidth > innerWidth + 1,
|
|
187
|
+
fonts: document.fonts.status,
|
|
188
|
+
role: element.getAttribute('role'),
|
|
189
|
+
orientation: element.getAttribute('aria-orientation'),
|
|
190
|
+
tabIndex: element.getAttribute('tabindex'),
|
|
191
|
+
targetClasses: {
|
|
192
|
+
menuDivider: element.classList.contains(
|
|
193
|
+
'astryx-dropdown-menu-divider',
|
|
194
|
+
),
|
|
195
|
+
divider: element.classList.contains('astryx-divider'),
|
|
196
|
+
},
|
|
197
|
+
geometry: {
|
|
198
|
+
root: {
|
|
199
|
+
x: rootBox.x,
|
|
200
|
+
y: rootBox.y,
|
|
201
|
+
width: rootBox.width,
|
|
202
|
+
height: rootBox.height,
|
|
203
|
+
},
|
|
204
|
+
rule:
|
|
205
|
+
ruleBox === null
|
|
206
|
+
? null
|
|
207
|
+
: {
|
|
208
|
+
x: ruleBox.x,
|
|
209
|
+
y: ruleBox.y,
|
|
210
|
+
width: ruleBox.width,
|
|
211
|
+
height: ruleBox.height,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
ruleBackground: ruleStyle?.backgroundColor ?? null,
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const geometryPass =
|
|
219
|
+
observed.geometry.root.width > 0 &&
|
|
220
|
+
observed.geometry.root.height > 0 &&
|
|
221
|
+
observed.geometry.rule !== null &&
|
|
222
|
+
observed.geometry.rule.width > 0 &&
|
|
223
|
+
observed.geometry.rule.height > 0;
|
|
224
|
+
const paintPass =
|
|
225
|
+
observed.ruleBackground !== null &&
|
|
226
|
+
observed.ruleBackground !== 'rgba(0, 0, 0, 0)' &&
|
|
227
|
+
observed.ruleBackground !== 'transparent';
|
|
228
|
+
const png = await page.screenshot({animations: 'disabled', fullPage: true});
|
|
229
|
+
const image = `${item.key}.png`;
|
|
230
|
+
const receipt = {
|
|
231
|
+
schemaVersion: 1,
|
|
232
|
+
expected: {
|
|
233
|
+
build: checkoutSha,
|
|
234
|
+
storyId: STORY_ID,
|
|
235
|
+
mode: item.mode,
|
|
236
|
+
direction: item.direction,
|
|
237
|
+
theme: item.theme,
|
|
238
|
+
viewport: item.viewport,
|
|
239
|
+
},
|
|
240
|
+
observed: {
|
|
241
|
+
build: storybookSha,
|
|
242
|
+
...observed,
|
|
243
|
+
menuItemCount: await menuItems.count(),
|
|
244
|
+
pageErrors,
|
|
245
|
+
},
|
|
246
|
+
image: {
|
|
247
|
+
file: image,
|
|
248
|
+
sha256: createHash('sha256').update(png).digest('hex'),
|
|
249
|
+
width: png.readUInt32BE(16),
|
|
250
|
+
height: png.readUInt32BE(20),
|
|
251
|
+
},
|
|
252
|
+
checks: {geometryPass, paintPass},
|
|
253
|
+
passed:
|
|
254
|
+
storybookSha === checkoutSha &&
|
|
255
|
+
pageErrors.length === 0 &&
|
|
256
|
+
observed.theme === item.theme &&
|
|
257
|
+
observed.mode === item.mode &&
|
|
258
|
+
observed.direction === item.direction &&
|
|
259
|
+
observed.viewport.width === item.viewport.width &&
|
|
260
|
+
observed.viewport.height === item.viewport.height &&
|
|
261
|
+
observed.reducedMotion &&
|
|
262
|
+
!observed.horizontalOverflow &&
|
|
263
|
+
observed.fonts === 'loaded' &&
|
|
264
|
+
observed.role === 'separator' &&
|
|
265
|
+
observed.orientation === 'horizontal' &&
|
|
266
|
+
observed.tabIndex === null &&
|
|
267
|
+
observed.targetClasses.menuDivider &&
|
|
268
|
+
observed.targetClasses.divider &&
|
|
269
|
+
geometryPass &&
|
|
270
|
+
paintPass,
|
|
271
|
+
};
|
|
272
|
+
fs.writeFileSync(path.join(OUTPUT, image), png);
|
|
273
|
+
fs.writeFileSync(
|
|
274
|
+
path.join(OUTPUT, `${item.key}.sensors.json`),
|
|
275
|
+
`${JSON.stringify(receipt, null, 2)}\n`,
|
|
276
|
+
);
|
|
277
|
+
expect(receipt.passed).toBe(true);
|
|
278
|
+
await context.close();
|
|
279
|
+
});
|
|
280
|
+
}
|