@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
|
@@ -552,6 +552,68 @@ describe('PowerSearch', () => {
|
|
|
552
552
|
});
|
|
553
553
|
});
|
|
554
554
|
|
|
555
|
+
describe('filter token focus', () => {
|
|
556
|
+
it('opens the editor with the mouse without opening search suggestions', async () => {
|
|
557
|
+
const user = userEvent.setup();
|
|
558
|
+
render(
|
|
559
|
+
<PowerSearch
|
|
560
|
+
config={config}
|
|
561
|
+
filters={[
|
|
562
|
+
{
|
|
563
|
+
field: 'status',
|
|
564
|
+
operator: 'is',
|
|
565
|
+
value: {type: 'enum', value: 'open'},
|
|
566
|
+
},
|
|
567
|
+
]}
|
|
568
|
+
onChange={() => {}}
|
|
569
|
+
/>,
|
|
570
|
+
);
|
|
571
|
+
const input = screen.getByRole('combobox', {name: 'Search'});
|
|
572
|
+
|
|
573
|
+
await user.pointer({
|
|
574
|
+
target: screen.getByText('Status: is'),
|
|
575
|
+
keys: '[MouseLeft>]',
|
|
576
|
+
});
|
|
577
|
+
expect(input).not.toHaveFocus();
|
|
578
|
+
expect(input).toHaveAttribute('aria-expanded', 'false');
|
|
579
|
+
expect(
|
|
580
|
+
screen.queryByRole('button', {name: 'Apply', hidden: true}),
|
|
581
|
+
).toBeNull();
|
|
582
|
+
|
|
583
|
+
await user.pointer({keys: '[/MouseLeft]'});
|
|
584
|
+
expect(
|
|
585
|
+
await screen.findByRole('button', {name: 'Apply', hidden: true}),
|
|
586
|
+
).toBeInTheDocument();
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it('preserves search entry and token editing with the keyboard', async () => {
|
|
590
|
+
const user = userEvent.setup();
|
|
591
|
+
render(
|
|
592
|
+
<PowerSearch
|
|
593
|
+
config={config}
|
|
594
|
+
filters={[
|
|
595
|
+
{
|
|
596
|
+
field: 'status',
|
|
597
|
+
operator: 'is',
|
|
598
|
+
value: {type: 'enum', value: 'open'},
|
|
599
|
+
},
|
|
600
|
+
]}
|
|
601
|
+
onChange={() => {}}
|
|
602
|
+
/>,
|
|
603
|
+
);
|
|
604
|
+
await user.tab();
|
|
605
|
+
expect(screen.getByRole('combobox', {name: 'Search'})).toHaveFocus();
|
|
606
|
+
|
|
607
|
+
await user.tab({shift: true}); // Remove button
|
|
608
|
+
await user.tab({shift: true}); // Token label
|
|
609
|
+
expect(screen.getByRole('button', {name: 'Status: is'})).toHaveFocus();
|
|
610
|
+
await user.keyboard('{Enter}');
|
|
611
|
+
expect(
|
|
612
|
+
await screen.findByRole('button', {name: 'Apply', hidden: true}),
|
|
613
|
+
).toBeInTheDocument();
|
|
614
|
+
});
|
|
615
|
+
});
|
|
616
|
+
|
|
555
617
|
describe('PowerSearch statusVariant forwarding', () => {
|
|
556
618
|
it('defaults to attached (status renders with data-variant="attached")', () => {
|
|
557
619
|
const {container} = render(
|
|
@@ -900,6 +900,15 @@ export function PowerSearch({
|
|
|
900
900
|
size={size}
|
|
901
901
|
icon={tokenIcon}
|
|
902
902
|
endContent={valueContent}
|
|
903
|
+
onMouseDown={
|
|
904
|
+
handleClick
|
|
905
|
+
? e => {
|
|
906
|
+
// Keep a token press from entering Tokenizer's input-focus
|
|
907
|
+
// redirect. Click still edits/removes; Tab entry is unchanged.
|
|
908
|
+
e.preventDefault();
|
|
909
|
+
}
|
|
910
|
+
: undefined
|
|
911
|
+
}
|
|
903
912
|
onClick={
|
|
904
913
|
handleClick
|
|
905
914
|
? (e: React.MouseEvent) => {
|
|
@@ -80,6 +80,77 @@ function createSearchSource(
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
describe('isDisabled reaches every built-in value editor', () => {
|
|
84
|
+
const items = [
|
|
85
|
+
{id: 'a', label: 'Alpha'},
|
|
86
|
+
{id: 'b', label: 'Beta'},
|
|
87
|
+
];
|
|
88
|
+
const enumValues = [
|
|
89
|
+
{value: 'a', label: 'Alpha'},
|
|
90
|
+
{value: 'b', label: 'Beta'},
|
|
91
|
+
];
|
|
92
|
+
const cases: ReadonlyArray<[string, OperatorValue]> = [
|
|
93
|
+
['string', {type: 'string'}],
|
|
94
|
+
[
|
|
95
|
+
'string with a search source',
|
|
96
|
+
{type: 'string', searchSource: createSearchSource(items)},
|
|
97
|
+
],
|
|
98
|
+
[
|
|
99
|
+
'string_list',
|
|
100
|
+
{type: 'string_list', searchSource: createSearchSource(items)},
|
|
101
|
+
],
|
|
102
|
+
['integer', {type: 'integer'}],
|
|
103
|
+
['float', {type: 'float'}],
|
|
104
|
+
['time', {type: 'time'}],
|
|
105
|
+
['date_absolute', {type: 'date_absolute'}],
|
|
106
|
+
['date_relative', {type: 'date_relative'}],
|
|
107
|
+
['date_range', {type: 'date_range'}],
|
|
108
|
+
['enum', {type: 'enum', values: enumValues}],
|
|
109
|
+
['enum_list', {type: 'enum_list', values: enumValues}],
|
|
110
|
+
[
|
|
111
|
+
'entity_list',
|
|
112
|
+
{type: 'entity_list', searchSource: createSearchSource(items)},
|
|
113
|
+
],
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
// Every form control the editor renders outside a closed popover (a date
|
|
117
|
+
// input's calendar stays mounted while closed, and its disabled trigger
|
|
118
|
+
// cannot open it), so a disabled built-in editor leaves nothing a person
|
|
119
|
+
// can type into, press, or open.
|
|
120
|
+
function controlsOf(container: HTMLElement): HTMLElement[] {
|
|
121
|
+
return Array.from(
|
|
122
|
+
container.querySelectorAll<HTMLElement>(
|
|
123
|
+
'input, textarea, button, select, [role="combobox"], [contenteditable="true"]',
|
|
124
|
+
),
|
|
125
|
+
).filter(element => {
|
|
126
|
+
const popover = element.closest<HTMLElement>('[popover]');
|
|
127
|
+
return (
|
|
128
|
+
element.getAttribute('aria-hidden') !== 'true' &&
|
|
129
|
+
(popover == null || popover.matches(':popover-open'))
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const isUnavailable = (element: HTMLElement) =>
|
|
135
|
+
(element as HTMLInputElement).disabled === true ||
|
|
136
|
+
element.getAttribute('aria-disabled') === 'true';
|
|
137
|
+
|
|
138
|
+
it.each(cases)('%s', (_name, operatorValue) => {
|
|
139
|
+
const {container} = render(
|
|
140
|
+
<PowerSearchValueEditor
|
|
141
|
+
operatorValue={operatorValue}
|
|
142
|
+
filterValue={undefined}
|
|
143
|
+
onChange={() => {}}
|
|
144
|
+
config={stubConfig}
|
|
145
|
+
isDisabled
|
|
146
|
+
/>,
|
|
147
|
+
);
|
|
148
|
+
const controls = controlsOf(container);
|
|
149
|
+
expect(controls.length).toBeGreaterThan(0);
|
|
150
|
+
expect(controls.filter(element => !isUnavailable(element))).toEqual([]);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
83
154
|
// =============================================================================
|
|
84
155
|
// #1103 — StringEditor ignores searchSource
|
|
85
156
|
// =============================================================================
|
|
@@ -105,12 +105,14 @@ function StringEditor({
|
|
|
105
105
|
onChange,
|
|
106
106
|
onEnter: _onEnter,
|
|
107
107
|
maxMenuItems,
|
|
108
|
+
isDisabled,
|
|
108
109
|
}: {
|
|
109
110
|
operatorValue: OperatorValue & {type: 'string'};
|
|
110
111
|
filterValue: FilterValue | undefined;
|
|
111
112
|
onChange: (value: FilterValue, shouldSave?: boolean) => void;
|
|
112
113
|
onEnter?: () => void;
|
|
113
114
|
maxMenuItems?: number;
|
|
115
|
+
isDisabled?: boolean;
|
|
114
116
|
}) {
|
|
115
117
|
const t = useTranslator();
|
|
116
118
|
const currentValue = filterValue?.type === 'string' ? filterValue.value : '';
|
|
@@ -126,6 +128,7 @@ function StringEditor({
|
|
|
126
128
|
<Typeahead
|
|
127
129
|
label={t('@astryx.powersearch.valueEditor.value')}
|
|
128
130
|
isLabelHidden
|
|
131
|
+
isDisabled={isDisabled}
|
|
129
132
|
searchSource={operatorValue.searchSource}
|
|
130
133
|
value={selectedItem}
|
|
131
134
|
onChange={item => {
|
|
@@ -146,6 +149,7 @@ function StringEditor({
|
|
|
146
149
|
<TextInput
|
|
147
150
|
label={t('@astryx.powersearch.valueEditor.value')}
|
|
148
151
|
isLabelHidden
|
|
152
|
+
isDisabled={isDisabled}
|
|
149
153
|
value={currentValue}
|
|
150
154
|
placeholder={t('@astryx.powersearch.valueEditor.enterValuePlaceholder')}
|
|
151
155
|
onChange={(value: string) => {
|
|
@@ -160,11 +164,13 @@ function StringListEditor({
|
|
|
160
164
|
filterValue,
|
|
161
165
|
onChange,
|
|
162
166
|
maxMenuItems,
|
|
167
|
+
isDisabled,
|
|
163
168
|
}: {
|
|
164
169
|
operatorValue: OperatorValue & {type: 'string_list'};
|
|
165
170
|
filterValue: FilterValue | undefined;
|
|
166
171
|
onChange: (value: FilterValue) => void;
|
|
167
172
|
maxMenuItems?: number;
|
|
173
|
+
isDisabled?: boolean;
|
|
168
174
|
}) {
|
|
169
175
|
const t = useTranslator();
|
|
170
176
|
const currentValue: SearchableItem[] = useMemo(() => {
|
|
@@ -194,6 +200,7 @@ function StringListEditor({
|
|
|
194
200
|
<Tokenizer
|
|
195
201
|
label={t('@astryx.powersearch.valueEditor.values')}
|
|
196
202
|
isLabelHidden
|
|
203
|
+
isDisabled={isDisabled}
|
|
197
204
|
searchSource={source}
|
|
198
205
|
value={currentValue}
|
|
199
206
|
onChange={items => {
|
|
@@ -278,11 +285,13 @@ function IntegerEditor({
|
|
|
278
285
|
filterValue,
|
|
279
286
|
onChange,
|
|
280
287
|
onEnter,
|
|
288
|
+
isDisabled,
|
|
281
289
|
}: {
|
|
282
290
|
operatorValue: OperatorValue & {type: 'integer'};
|
|
283
291
|
filterValue: FilterValue | undefined;
|
|
284
292
|
onChange: (value: FilterValue, shouldSave?: boolean) => void;
|
|
285
293
|
onEnter?: () => void;
|
|
294
|
+
isDisabled?: boolean;
|
|
286
295
|
}) {
|
|
287
296
|
const t = useTranslator();
|
|
288
297
|
const currentValue =
|
|
@@ -300,6 +309,7 @@ function IntegerEditor({
|
|
|
300
309
|
<NumberInput
|
|
301
310
|
label={t('@astryx.powersearch.valueEditor.value')}
|
|
302
311
|
isLabelHidden
|
|
312
|
+
isDisabled={isDisabled}
|
|
303
313
|
value={currentValue ?? null}
|
|
304
314
|
onChange={handlers.handleChange}
|
|
305
315
|
onFocus={handlers.handleFocus}
|
|
@@ -320,11 +330,13 @@ function FloatEditor({
|
|
|
320
330
|
filterValue,
|
|
321
331
|
onChange,
|
|
322
332
|
onEnter,
|
|
333
|
+
isDisabled,
|
|
323
334
|
}: {
|
|
324
335
|
operatorValue: OperatorValue & {type: 'float'};
|
|
325
336
|
filterValue: FilterValue | undefined;
|
|
326
337
|
onChange: (value: FilterValue, shouldSave?: boolean) => void;
|
|
327
338
|
onEnter?: () => void;
|
|
339
|
+
isDisabled?: boolean;
|
|
328
340
|
}) {
|
|
329
341
|
const t = useTranslator();
|
|
330
342
|
const currentValue =
|
|
@@ -342,6 +354,7 @@ function FloatEditor({
|
|
|
342
354
|
<NumberInput
|
|
343
355
|
label={t('@astryx.powersearch.valueEditor.value')}
|
|
344
356
|
isLabelHidden
|
|
357
|
+
isDisabled={isDisabled}
|
|
345
358
|
value={currentValue ?? null}
|
|
346
359
|
onChange={handlers.handleChange}
|
|
347
360
|
onFocus={handlers.handleFocus}
|
|
@@ -360,10 +373,12 @@ function TimeEditor({
|
|
|
360
373
|
operatorValue,
|
|
361
374
|
filterValue,
|
|
362
375
|
onChange,
|
|
376
|
+
isDisabled,
|
|
363
377
|
}: {
|
|
364
378
|
operatorValue: OperatorValue & {type: 'time'};
|
|
365
379
|
filterValue: FilterValue | undefined;
|
|
366
380
|
onChange: (value: FilterValue) => void;
|
|
381
|
+
isDisabled?: boolean;
|
|
367
382
|
}) {
|
|
368
383
|
const t = useTranslator();
|
|
369
384
|
const currentValue =
|
|
@@ -375,6 +390,7 @@ function TimeEditor({
|
|
|
375
390
|
<TimeInput
|
|
376
391
|
label={t('@astryx.powersearch.valueEditor.time')}
|
|
377
392
|
isLabelHidden
|
|
393
|
+
isDisabled={isDisabled}
|
|
378
394
|
value={currentValue}
|
|
379
395
|
onChange={value => {
|
|
380
396
|
if (value != null) {
|
|
@@ -390,10 +406,12 @@ function TimeEditor({
|
|
|
390
406
|
function DateAbsoluteEditor({
|
|
391
407
|
filterValue,
|
|
392
408
|
onChange,
|
|
409
|
+
isDisabled,
|
|
393
410
|
}: {
|
|
394
411
|
operatorValue: OperatorValue & {type: 'date_absolute'};
|
|
395
412
|
filterValue: FilterValue | undefined;
|
|
396
413
|
onChange: (value: FilterValue) => void;
|
|
414
|
+
isDisabled?: boolean;
|
|
397
415
|
}) {
|
|
398
416
|
const t = useTranslator();
|
|
399
417
|
// Convert unixSeconds to ISO date string for the date input
|
|
@@ -409,6 +427,7 @@ function DateAbsoluteEditor({
|
|
|
409
427
|
<DateInput
|
|
410
428
|
label={t('@astryx.powersearch.valueEditor.date')}
|
|
411
429
|
isLabelHidden
|
|
430
|
+
isDisabled={isDisabled}
|
|
412
431
|
value={currentValue}
|
|
413
432
|
onChange={value => {
|
|
414
433
|
if (value != null) {
|
|
@@ -424,10 +443,12 @@ function DateRelativeEditor({
|
|
|
424
443
|
operatorValue,
|
|
425
444
|
filterValue,
|
|
426
445
|
onChange,
|
|
446
|
+
isDisabled,
|
|
427
447
|
}: {
|
|
428
448
|
operatorValue: OperatorValue & {type: 'date_relative'};
|
|
429
449
|
filterValue: FilterValue | undefined;
|
|
430
450
|
onChange: (value: FilterValue, shouldSave?: boolean) => void;
|
|
451
|
+
isDisabled?: boolean;
|
|
431
452
|
}) {
|
|
432
453
|
const t = useTranslator();
|
|
433
454
|
const currentValue =
|
|
@@ -469,6 +490,7 @@ function DateRelativeEditor({
|
|
|
469
490
|
<Selector
|
|
470
491
|
label={t('@astryx.powersearch.valueEditor.relativeDate')}
|
|
471
492
|
isLabelHidden
|
|
493
|
+
isDisabled={isDisabled}
|
|
472
494
|
options={options}
|
|
473
495
|
value={currentValue}
|
|
474
496
|
onChange={value => {
|
|
@@ -481,10 +503,12 @@ function DateRelativeEditor({
|
|
|
481
503
|
function DateRangeEditor({
|
|
482
504
|
filterValue,
|
|
483
505
|
onChange,
|
|
506
|
+
isDisabled,
|
|
484
507
|
}: {
|
|
485
508
|
operatorValue: OperatorValue & {type: 'date_range'};
|
|
486
509
|
filterValue: FilterValue | undefined;
|
|
487
510
|
onChange: (value: FilterValue) => void;
|
|
511
|
+
isDisabled?: boolean;
|
|
488
512
|
}) {
|
|
489
513
|
const t = useTranslator();
|
|
490
514
|
const currentValue = useMemo<DateRange | null>(() => {
|
|
@@ -534,6 +558,7 @@ function DateRangeEditor({
|
|
|
534
558
|
<DateRangeInput
|
|
535
559
|
label={t('@astryx.powersearch.valueEditor.dateRange')}
|
|
536
560
|
isLabelHidden
|
|
561
|
+
isDisabled={isDisabled}
|
|
537
562
|
value={currentValue}
|
|
538
563
|
onChange={handleChange}
|
|
539
564
|
hasClear={false}
|
|
@@ -546,10 +571,12 @@ function EnumEditor({
|
|
|
546
571
|
operatorValue,
|
|
547
572
|
filterValue,
|
|
548
573
|
onChange,
|
|
574
|
+
isDisabled,
|
|
549
575
|
}: {
|
|
550
576
|
operatorValue: OperatorValue & {type: 'enum'};
|
|
551
577
|
filterValue: FilterValue | undefined;
|
|
552
578
|
onChange: (value: FilterValue, shouldSave?: boolean) => void;
|
|
579
|
+
isDisabled?: boolean;
|
|
553
580
|
}) {
|
|
554
581
|
const t = useTranslator();
|
|
555
582
|
const currentValue =
|
|
@@ -568,6 +595,7 @@ function EnumEditor({
|
|
|
568
595
|
<Selector
|
|
569
596
|
label={t('@astryx.powersearch.valueEditor.value')}
|
|
570
597
|
isLabelHidden
|
|
598
|
+
isDisabled={isDisabled}
|
|
571
599
|
options={options}
|
|
572
600
|
value={currentValue}
|
|
573
601
|
onChange={value => {
|
|
@@ -581,10 +609,12 @@ function EnumListEditor({
|
|
|
581
609
|
operatorValue,
|
|
582
610
|
filterValue,
|
|
583
611
|
onChange,
|
|
612
|
+
isDisabled,
|
|
584
613
|
}: {
|
|
585
614
|
operatorValue: OperatorValue & {type: 'enum_list'};
|
|
586
615
|
filterValue: FilterValue | undefined;
|
|
587
616
|
onChange: (value: FilterValue) => void;
|
|
617
|
+
isDisabled?: boolean;
|
|
588
618
|
}) {
|
|
589
619
|
const t = useTranslator();
|
|
590
620
|
const items = useMemo(
|
|
@@ -608,6 +638,7 @@ function EnumListEditor({
|
|
|
608
638
|
<Tokenizer
|
|
609
639
|
label={t('@astryx.powersearch.valueEditor.values')}
|
|
610
640
|
isLabelHidden
|
|
641
|
+
isDisabled={isDisabled}
|
|
611
642
|
searchSource={source}
|
|
612
643
|
value={currentValue}
|
|
613
644
|
onChange={selectedItems => {
|
|
@@ -632,11 +663,13 @@ function EntityListEditor({
|
|
|
632
663
|
filterValue,
|
|
633
664
|
onChange,
|
|
634
665
|
maxMenuItems,
|
|
666
|
+
isDisabled,
|
|
635
667
|
}: {
|
|
636
668
|
operatorValue: OperatorValue & {type: 'entity_list'};
|
|
637
669
|
filterValue: FilterValue | undefined;
|
|
638
670
|
onChange: (value: FilterValue) => void;
|
|
639
671
|
maxMenuItems?: number;
|
|
672
|
+
isDisabled?: boolean;
|
|
640
673
|
}) {
|
|
641
674
|
const t = useTranslator();
|
|
642
675
|
const source = useMemo<SearchSource<SearchableItem>>(() => {
|
|
@@ -665,6 +698,7 @@ function EntityListEditor({
|
|
|
665
698
|
<Tokenizer
|
|
666
699
|
label={t('@astryx.powersearch.valueEditor.entities')}
|
|
667
700
|
isLabelHidden
|
|
701
|
+
isDisabled={isDisabled}
|
|
668
702
|
searchSource={source}
|
|
669
703
|
value={currentValue}
|
|
670
704
|
onChange={items => {
|
|
@@ -738,6 +772,7 @@ export function PowerSearchValueEditor({
|
|
|
738
772
|
case 'string':
|
|
739
773
|
return (
|
|
740
774
|
<StringEditor
|
|
775
|
+
isDisabled={isDisabled}
|
|
741
776
|
operatorValue={operatorValue}
|
|
742
777
|
filterValue={filterValue}
|
|
743
778
|
onChange={onChange}
|
|
@@ -749,6 +784,7 @@ export function PowerSearchValueEditor({
|
|
|
749
784
|
case 'string_list':
|
|
750
785
|
return (
|
|
751
786
|
<StringListEditor
|
|
787
|
+
isDisabled={isDisabled}
|
|
752
788
|
operatorValue={operatorValue}
|
|
753
789
|
filterValue={filterValue}
|
|
754
790
|
onChange={onChange}
|
|
@@ -759,6 +795,7 @@ export function PowerSearchValueEditor({
|
|
|
759
795
|
case 'integer':
|
|
760
796
|
return (
|
|
761
797
|
<IntegerEditor
|
|
798
|
+
isDisabled={isDisabled}
|
|
762
799
|
operatorValue={operatorValue}
|
|
763
800
|
filterValue={filterValue}
|
|
764
801
|
onChange={onChange}
|
|
@@ -769,6 +806,7 @@ export function PowerSearchValueEditor({
|
|
|
769
806
|
case 'float':
|
|
770
807
|
return (
|
|
771
808
|
<FloatEditor
|
|
809
|
+
isDisabled={isDisabled}
|
|
772
810
|
operatorValue={operatorValue}
|
|
773
811
|
filterValue={filterValue}
|
|
774
812
|
onChange={onChange}
|
|
@@ -779,6 +817,7 @@ export function PowerSearchValueEditor({
|
|
|
779
817
|
case 'time':
|
|
780
818
|
return (
|
|
781
819
|
<TimeEditor
|
|
820
|
+
isDisabled={isDisabled}
|
|
782
821
|
operatorValue={operatorValue}
|
|
783
822
|
filterValue={filterValue}
|
|
784
823
|
onChange={onChange}
|
|
@@ -788,6 +827,7 @@ export function PowerSearchValueEditor({
|
|
|
788
827
|
case 'date_absolute':
|
|
789
828
|
return (
|
|
790
829
|
<DateAbsoluteEditor
|
|
830
|
+
isDisabled={isDisabled}
|
|
791
831
|
operatorValue={operatorValue}
|
|
792
832
|
filterValue={filterValue}
|
|
793
833
|
onChange={onChange}
|
|
@@ -797,6 +837,7 @@ export function PowerSearchValueEditor({
|
|
|
797
837
|
case 'date_relative':
|
|
798
838
|
return (
|
|
799
839
|
<DateRelativeEditor
|
|
840
|
+
isDisabled={isDisabled}
|
|
800
841
|
operatorValue={operatorValue}
|
|
801
842
|
filterValue={filterValue}
|
|
802
843
|
onChange={onChange}
|
|
@@ -806,6 +847,7 @@ export function PowerSearchValueEditor({
|
|
|
806
847
|
case 'date_range':
|
|
807
848
|
return (
|
|
808
849
|
<DateRangeEditor
|
|
850
|
+
isDisabled={isDisabled}
|
|
809
851
|
operatorValue={operatorValue}
|
|
810
852
|
filterValue={filterValue}
|
|
811
853
|
onChange={onChange}
|
|
@@ -815,6 +857,7 @@ export function PowerSearchValueEditor({
|
|
|
815
857
|
case 'enum':
|
|
816
858
|
return (
|
|
817
859
|
<EnumEditor
|
|
860
|
+
isDisabled={isDisabled}
|
|
818
861
|
operatorValue={operatorValue}
|
|
819
862
|
filterValue={filterValue}
|
|
820
863
|
onChange={onChange}
|
|
@@ -824,6 +867,7 @@ export function PowerSearchValueEditor({
|
|
|
824
867
|
case 'enum_list':
|
|
825
868
|
return (
|
|
826
869
|
<EnumListEditor
|
|
870
|
+
isDisabled={isDisabled}
|
|
827
871
|
operatorValue={operatorValue}
|
|
828
872
|
filterValue={filterValue}
|
|
829
873
|
onChange={onChange}
|
|
@@ -833,6 +877,7 @@ export function PowerSearchValueEditor({
|
|
|
833
877
|
case 'entity_list':
|
|
834
878
|
return (
|
|
835
879
|
<EntityListEditor
|
|
880
|
+
isDisabled={isDisabled}
|
|
836
881
|
operatorValue={operatorValue}
|
|
837
882
|
filterValue={filterValue}
|
|
838
883
|
onChange={onChange}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
-
import {describe, it} from 'vitest';
|
|
4
|
-
import {screen} from '@testing-library/react';
|
|
3
|
+
import {describe, it, expect} from 'vitest';
|
|
4
|
+
import {render, screen} from '@testing-library/react';
|
|
5
5
|
import {expectFieldInputProps} from '../Field/fieldInputFamily.testing';
|
|
6
6
|
import {describeFieldInputParts} from '../Field/fieldInputFamily.render-testing';
|
|
7
7
|
import {RadioList, type RadioListProps} from './RadioList';
|
|
@@ -22,3 +22,46 @@ describeFieldInputParts('RadioList', {
|
|
|
22
22
|
getControl: () => screen.getByRole('radiogroup'),
|
|
23
23
|
inGroup: false,
|
|
24
24
|
});
|
|
25
|
+
|
|
26
|
+
describe('RadioList FR10 details', () => {
|
|
27
|
+
it("names the radiogroup by its label and then a caller's aria-labelledby", () => {
|
|
28
|
+
render(
|
|
29
|
+
<>
|
|
30
|
+
<span id="caller-name">Billing</span>
|
|
31
|
+
<RadioList
|
|
32
|
+
label="Plan"
|
|
33
|
+
value="a"
|
|
34
|
+
onChange={() => {}}
|
|
35
|
+
aria-labelledby="caller-name">
|
|
36
|
+
<RadioListItem label="A" value="a" />
|
|
37
|
+
</RadioList>
|
|
38
|
+
</>,
|
|
39
|
+
);
|
|
40
|
+
const group = screen.getByRole('radiogroup');
|
|
41
|
+
const ids = group.getAttribute('aria-labelledby')?.split(' ');
|
|
42
|
+
expect(ids).toHaveLength(2);
|
|
43
|
+
expect(document.getElementById(ids?.[0] ?? '')?.textContent).toContain(
|
|
44
|
+
'Plan',
|
|
45
|
+
);
|
|
46
|
+
expect(ids?.[1]).toBe('caller-name');
|
|
47
|
+
expect(screen.getByRole('radiogroup', {name: 'Plan Billing'})).toBe(group);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('puts hidden, inert, and dir on the radiogroup', () => {
|
|
51
|
+
render(
|
|
52
|
+
<RadioList
|
|
53
|
+
label="Plan"
|
|
54
|
+
value="a"
|
|
55
|
+
onChange={() => {}}
|
|
56
|
+
hidden
|
|
57
|
+
inert
|
|
58
|
+
dir="rtl">
|
|
59
|
+
<RadioListItem label="A" value="a" />
|
|
60
|
+
</RadioList>,
|
|
61
|
+
);
|
|
62
|
+
const group = document.querySelector<HTMLElement>('[role="radiogroup"]');
|
|
63
|
+
expect(group).toHaveAttribute('hidden');
|
|
64
|
+
expect(group).toHaveAttribute('inert');
|
|
65
|
+
expect(group).toHaveAttribute('dir', 'rtl');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -524,6 +524,28 @@ describe('RadioList', () => {
|
|
|
524
524
|
});
|
|
525
525
|
|
|
526
526
|
describe('RadioListItem rest forwarding', () => {
|
|
527
|
+
it('forwards align to its Item row unchanged', () => {
|
|
528
|
+
render(
|
|
529
|
+
<RadioList label="Preference" value="" onChange={() => {}}>
|
|
530
|
+
<RadioListItem label="Option A" value="a" data-testid="item-a" />
|
|
531
|
+
<RadioListItem
|
|
532
|
+
label="Option B"
|
|
533
|
+
value="b"
|
|
534
|
+
align="first-line"
|
|
535
|
+
data-testid="item-b"
|
|
536
|
+
/>
|
|
537
|
+
</RadioList>,
|
|
538
|
+
);
|
|
539
|
+
expect(screen.getByTestId('item-a')).toHaveAttribute(
|
|
540
|
+
'data-align',
|
|
541
|
+
'center',
|
|
542
|
+
);
|
|
543
|
+
expect(screen.getByTestId('item-b')).toHaveAttribute(
|
|
544
|
+
'data-align',
|
|
545
|
+
'first-line',
|
|
546
|
+
);
|
|
547
|
+
});
|
|
548
|
+
|
|
527
549
|
it('forwards data-testid, id, and aria-* to the item root element', () => {
|
|
528
550
|
render(
|
|
529
551
|
<RadioList label="Preference" value="" onChange={() => {}}>
|
|
@@ -31,6 +31,7 @@ import type {InputStatus} from '../Field/types';
|
|
|
31
31
|
import {useTooltip} from '../Tooltip';
|
|
32
32
|
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
33
33
|
import {composeEventHandlers, mergeProps} from '../utils';
|
|
34
|
+
import {joinAriaIDs} from '../utils/inputAria';
|
|
34
35
|
import {
|
|
35
36
|
type FieldInputBaseProps,
|
|
36
37
|
useFieldInputStyling,
|
|
@@ -216,6 +217,7 @@ export function RadioList({
|
|
|
216
217
|
htmlName,
|
|
217
218
|
children,
|
|
218
219
|
onFocus,
|
|
220
|
+
'aria-labelledby': ariaLabelledByProp,
|
|
219
221
|
'aria-describedby': ariaDescribedByProp,
|
|
220
222
|
...restProps
|
|
221
223
|
}: RadioListProps) {
|
|
@@ -399,7 +401,8 @@ export function RadioList({
|
|
|
399
401
|
disabledMessageTooltip.ref(el);
|
|
400
402
|
}}
|
|
401
403
|
role="radiogroup"
|
|
402
|
-
aria-labelledby
|
|
404
|
+
// A caller aria-labelledby names the group together with its label.
|
|
405
|
+
aria-labelledby={joinAriaIDs(labelID, ariaLabelledByProp)}
|
|
403
406
|
onFocus={composeEventHandlers(handleFocus, onFocus)}
|
|
404
407
|
aria-describedby={
|
|
405
408
|
[
|
|
@@ -43,6 +43,13 @@ export const docs = {
|
|
|
43
43
|
description:
|
|
44
44
|
'Secondary content displayed below the label. Links and buttons keep their own click behaviour — the row only delegates clicks from its non-interactive surface to the radio.',
|
|
45
45
|
},
|
|
46
|
+
{
|
|
47
|
+
name: 'align',
|
|
48
|
+
type: "'center' | 'start' | 'first-line'",
|
|
49
|
+
description:
|
|
50
|
+
'Vertical alignment of the start and end content against the label, passed through to Item unchanged. `first-line` keeps a small mark (a radio) level with the first line of a wrapped label. See Item.align.',
|
|
51
|
+
default: "'center'",
|
|
52
|
+
},
|
|
46
53
|
{
|
|
47
54
|
name: 'isDisabled',
|
|
48
55
|
type: 'boolean',
|
|
@@ -117,6 +124,13 @@ export const docsZh = {
|
|
|
117
124
|
description:
|
|
118
125
|
'显示在标签下方的次要内容。链接和按钮保留自身的点击行为——整行仅将非交互区域的点击委派给单选框。',
|
|
119
126
|
},
|
|
127
|
+
{
|
|
128
|
+
name: 'align',
|
|
129
|
+
type: "'center' | 'start' | 'first-line'",
|
|
130
|
+
description:
|
|
131
|
+
'起始和结束内容相对于标签的垂直对齐方式,原样传递给 Item。`first-line` 让小标记(单选按钮)与换行标签的第一行保持水平。参见 Item.align。',
|
|
132
|
+
default: "'center'",
|
|
133
|
+
},
|
|
120
134
|
{
|
|
121
135
|
name: 'isDisabled',
|
|
122
136
|
type: 'boolean',
|
|
@@ -142,6 +156,8 @@ export const docsDense = {
|
|
|
142
156
|
displayName: 'Radio List Item',
|
|
143
157
|
description: 'Individual radio item w/ label, description, content slots.',
|
|
144
158
|
propDescriptions: {
|
|
159
|
+
align:
|
|
160
|
+
"Start/end content alignment, passed to Item: 'center' (default), 'start', or 'first-line' (centered on the label's first line).",
|
|
145
161
|
label:
|
|
146
162
|
'Primary label. String or ReactNode; nested controls keep their behavior.',
|
|
147
163
|
'aria-label':
|
|
@@ -29,7 +29,7 @@ import {indicatorScope} from '../Indicator/indicator.markers.stylex';
|
|
|
29
29
|
import {useIndicatorFocusRing} from '../hooks/useIndicatorFocusRing';
|
|
30
30
|
import {usePressFeedback} from '../hooks/usePressFeedback';
|
|
31
31
|
import {useIndicator} from '../Indicator';
|
|
32
|
-
import {Item} from '../Item';
|
|
32
|
+
import {Item, type ItemAlign} from '../Item';
|
|
33
33
|
import {themeProps} from '../utils/themeProps';
|
|
34
34
|
|
|
35
35
|
// The touch press's paint, declared by the shared overlay styles on the
|
|
@@ -156,6 +156,13 @@ const rowStyles = stylex.create({
|
|
|
156
156
|
|
|
157
157
|
export interface RadioListItemProps extends BaseProps<HTMLDivElement> {
|
|
158
158
|
ref?: React.Ref<HTMLDivElement>;
|
|
159
|
+
/**
|
|
160
|
+
* Vertical alignment of the start and end content against the label,
|
|
161
|
+
* forwarded to Item. Use `first-line` to keep the radio level with the
|
|
162
|
+
* first line of a wrapped label.
|
|
163
|
+
* @default 'center'
|
|
164
|
+
*/
|
|
165
|
+
align?: ItemAlign;
|
|
159
166
|
/**
|
|
160
167
|
* Primary label for the radio item.
|
|
161
168
|
*
|
|
@@ -232,6 +239,7 @@ export function RadioListItem({
|
|
|
232
239
|
isDisabled: isItemDisabled = false,
|
|
233
240
|
startContent,
|
|
234
241
|
endContent,
|
|
242
|
+
align,
|
|
235
243
|
xstyle,
|
|
236
244
|
className,
|
|
237
245
|
style,
|
|
@@ -366,6 +374,7 @@ export function RadioListItem({
|
|
|
366
374
|
) : undefined
|
|
367
375
|
}
|
|
368
376
|
endContent={endContent}
|
|
377
|
+
align={align}
|
|
369
378
|
xstyle={
|
|
370
379
|
[
|
|
371
380
|
// Hover reaches the radio visual through this ancestor marker rather
|