@astryxdesign/core 0.7.1 → 0.7.2-canary.151434a
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/AspectRatio/AspectRatio.d.ts +6 -8
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +44 -3
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +38 -14
- 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/CheckboxListItem.d.ts +9 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +4 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +20 -8
- package/dist/Drawer/Drawer.d.ts +191 -0
- package/dist/Drawer/Drawer.d.ts.map +1 -0
- package/dist/Drawer/Drawer.js +382 -0
- package/dist/Drawer/DrawerHeader.d.ts +85 -0
- package/dist/Drawer/DrawerHeader.d.ts.map +1 -0
- package/dist/Drawer/DrawerHeader.js +134 -0
- package/dist/Drawer/index.d.ts +11 -0
- package/dist/Drawer/index.d.ts.map +1 -0
- package/dist/Drawer/index.js +11 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts +42 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -0
- package/dist/Drawer/useDrawerDialogPresence.js +236 -0
- package/dist/DropdownMenu/DropdownMenu.js +1 -1
- 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/DropdownMenuSubMenu.js +4 -4
- 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/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -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/Layer/layerViewportInset.stylex.d.ts +6 -2
- package/dist/Layer/layerViewportInset.stylex.d.ts.map +1 -1
- package/dist/Layer/layerViewportInset.stylex.js +6 -2
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +13 -7
- package/dist/Layer/useLayerDismissal.d.ts +1 -1
- package/dist/Layer/useLayerDismissal.js +1 -1
- package/dist/Layout/container.stylex.d.ts +5 -5
- package/dist/Layout/container.stylex.js +4 -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/plugins/frontmatter.d.ts.map +1 -1
- package/dist/Markdown/plugins/frontmatter.js +7 -3
- 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/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +22 -8
- package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +100 -2
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -1
- package/dist/Pagination/Pagination.d.ts +8 -5
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +21 -8
- package/dist/Popover/Popover.js +2 -2
- package/dist/PowerSearch/PowerSearch.js +1 -1
- 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/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +6 -2
- package/dist/Switch/Switch.d.ts +1 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +13 -1
- package/dist/TabList/TabMenu.d.ts +2 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -3
- package/dist/Text/useTruncation.d.ts +7 -5
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +16 -5
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +11 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +26 -0
- package/dist/astryx.css +35 -12
- package/dist/hooks/useEntryAnimation.d.ts +2 -1
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +14 -12
- package/dist/hooks/useIsHydrating.d.ts +6 -0
- package/dist/hooks/useIsHydrating.d.ts.map +1 -0
- package/dist/hooks/useIsHydrating.js +30 -0
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +112 -1
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +112 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +0 -3
- package/dist/utils/focusOutline.stylex.d.ts +4 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +4 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +15 -9
- package/dist/utils/sharedMutationObserver.d.ts +21 -0
- package/dist/utils/sharedMutationObserver.d.ts.map +1 -0
- package/dist/utils/sharedMutationObserver.js +69 -0
- package/locales/en.json +444 -0
- package/locales/pseudo.json +333 -0
- package/package.json +9 -4
- 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/Button/Button.doc.mjs +2 -2
- package/src/Button/Button.test.tsx +155 -9
- package/src/Button/Button.tsx +39 -16
- package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
- package/src/Button/__tests__/Button.a11y.states.ts +0 -10
- package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
- package/src/CheckboxInput/CheckboxInput.tsx +3 -1
- package/src/CheckboxList/CheckboxList.test.tsx +22 -0
- package/src/CheckboxList/CheckboxListItem.doc.mjs +16 -0
- package/src/CheckboxList/CheckboxListItem.tsx +10 -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 +472 -0
- package/src/Drawer/Drawer.spec.md +357 -0
- package/src/Drawer/Drawer.test.tsx +1300 -0
- package/src/Drawer/Drawer.tsx +613 -0
- package/src/Drawer/DrawerDirection.test.tsx +127 -0
- package/src/Drawer/DrawerHeader.doc.mjs +293 -0
- package/src/Drawer/DrawerHeader.test.tsx +102 -0
- package/src/Drawer/DrawerHeader.tsx +235 -0
- package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +401 -0
- package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +297 -0
- package/src/Drawer/index.ts +13 -0
- package/src/Drawer/useDrawerDialogPresence.ts +284 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +21 -12
- package/src/DropdownMenu/DropdownMenu.tsx +2 -2
- package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +2 -2
- package/src/DropdownMenu/DropdownMenuDivider.tsx +9 -5
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +2 -2
- package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +145 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.known-failures.ts +26 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.renders.tsx +65 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.states.ts +138 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.test.tsx +136 -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/HoverCard/HoverCard.test.tsx +58 -0
- package/src/HoverCard/useHoverCard.tsx +10 -2
- package/src/IconButton/IconButton.doc.mjs +2 -2
- package/src/IconButton/IconButton.test.tsx +3 -1
- package/src/Item/Item.doc.mjs +12 -8
- package/src/Item/Item.spec.md +226 -0
- package/src/Item/Item.test.tsx +61 -0
- package/src/Item/Item.tsx +40 -4
- package/src/Layer/layerViewportInset.source-build.test.mjs +90 -0
- package/src/Layer/layerViewportInset.stylex.ts +6 -2
- package/src/Layer/layerViewportInset.test.ts +1 -0
- package/src/Layer/useLayer.tsx +24 -13
- package/src/Layer/useLayerDismissal.ts +1 -1
- package/src/Layout/container.stylex.ts +6 -6
- 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 +24 -5
- package/src/List/ListItem.tsx +56 -27
- package/src/List/index.ts +1 -1
- package/src/Markdown/Markdown.tsx +14 -1
- package/src/Markdown/plugins/frontmatter.test.tsx +25 -0
- package/src/Markdown/plugins/frontmatter.ts +7 -3
- package/src/MetadataList/MetadataList.doc.mjs +2 -2
- package/src/MetadataList/MetadataList.test.tsx +38 -0
- package/src/MetadataList/MetadataList.tsx +8 -1
- package/src/MetadataList/MetadataListContext.tsx +1 -1
- package/src/MultiSelector/MultiSelector.test.tsx +159 -0
- package/src/MultiSelector/MultiSelector.tsx +40 -7
- package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +112 -2
- package/src/MultiSelector/hooks.ts +3 -1
- package/src/MultiSelector/useMultiCombobox.doc.mjs +267 -0
- package/src/Pagination/Pagination.doc.mjs +7 -7
- package/src/Pagination/Pagination.spec.md +9 -9
- package/src/Pagination/Pagination.test.tsx +242 -0
- package/src/Pagination/Pagination.tsx +27 -11
- package/src/Popover/Popover.test.tsx +2 -2
- package/src/Popover/Popover.tsx +4 -4
- package/src/PowerSearch/PowerSearch.test.tsx +85 -0
- package/src/PowerSearch/PowerSearch.tsx +2 -2
- package/src/RadioList/RadioList.test.tsx +22 -0
- package/src/RadioList/RadioListItem.doc.mjs +16 -0
- package/src/RadioList/RadioListItem.tsx +10 -1
- package/src/Selector/hooks.ts +6 -2
- package/src/Selector/useCombobox.doc.mjs +237 -0
- package/src/Switch/Switch.test.tsx +49 -0
- package/src/Switch/Switch.tsx +11 -0
- package/src/TabList/TabList.spec.md +57 -44
- package/src/TabList/TabList.test.tsx +67 -0
- package/src/TabList/TabMenu.doc.mjs +4 -3
- package/src/TabList/TabMenu.tsx +7 -4
- package/src/Text/useTruncation.test.tsx +69 -0
- package/src/Text/useTruncation.ts +16 -5
- package/src/Tokenizer/Tokenizer.test.tsx +54 -1
- package/src/Tooltip/Tooltip.test.tsx +31 -0
- package/src/Tooltip/useTooltip.test.tsx +13 -0
- package/src/Tooltip/useTooltip.tsx +11 -0
- package/src/TreeList/TreeList.spec.md +29 -17
- package/src/Typeahead/BaseTypeahead.tsx +26 -0
- package/src/Typeahead/Typeahead.test.tsx +260 -2
- package/src/hooks/useEntryAnimation.doc.mjs +4 -4
- package/src/hooks/useEntryAnimation.ssr.test.tsx +143 -0
- package/src/hooks/useEntryAnimation.ts +15 -16
- package/src/hooks/useIsHydrating.test.tsx +70 -0
- package/src/hooks/useIsHydrating.ts +31 -0
- package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
- package/src/i18n/InternationalizationProvider.spec.md +252 -0
- package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
- package/src/i18n/generated-locales/en.generated.ts +121 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +121 -0
- package/src/i18n/useTranslator.test.tsx +37 -0
- package/src/index.ts +1 -0
- package/src/reset.css +0 -29
- package/src/theme/derivedVarRegistry.test.ts +3 -3
- package/src/theme/derivedVarRegistry.ts +0 -3
- package/src/utils/focusOutline.stylex.ts +4 -0
- package/src/utils/plainDate.test.ts +37 -1
- package/src/utils/plainDate.ts +15 -5
- package/src/utils/sharedMutationObserver.test.ts +53 -0
- package/src/utils/sharedMutationObserver.ts +78 -0
|
@@ -59,6 +59,28 @@ beforeEach(() => {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
describe('CheckboxList', () => {
|
|
62
|
+
it('forwards CheckboxListItem align to its Item row unchanged', () => {
|
|
63
|
+
render(
|
|
64
|
+
<CheckboxList label="Toppings" value={[]} onChange={() => {}}>
|
|
65
|
+
<CheckboxListItem label="Cheese" value="cheese" data-testid="cheese" />
|
|
66
|
+
<CheckboxListItem
|
|
67
|
+
label="Olives"
|
|
68
|
+
value="olives"
|
|
69
|
+
align="first-line"
|
|
70
|
+
data-testid="olives"
|
|
71
|
+
/>
|
|
72
|
+
</CheckboxList>,
|
|
73
|
+
);
|
|
74
|
+
expect(screen.getByTestId('cheese')).toHaveAttribute(
|
|
75
|
+
'data-align',
|
|
76
|
+
'center',
|
|
77
|
+
);
|
|
78
|
+
expect(screen.getByTestId('olives')).toHaveAttribute(
|
|
79
|
+
'data-align',
|
|
80
|
+
'first-line',
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
62
84
|
it('renders with label', () => {
|
|
63
85
|
render(
|
|
64
86
|
<CheckboxList label="Preferences" value={[]} onChange={() => {}}>
|
|
@@ -55,6 +55,13 @@ export const docs = {
|
|
|
55
55
|
},
|
|
56
56
|
],
|
|
57
57
|
},
|
|
58
|
+
{
|
|
59
|
+
name: 'align',
|
|
60
|
+
type: "'center' | 'start' | 'first-line'",
|
|
61
|
+
description:
|
|
62
|
+
'Vertical alignment of the start and end content against the label, passed through to Item unchanged. `first-line` keeps a small mark (a checkbox) level with the first line of a wrapped label. See Item.align.',
|
|
63
|
+
default: "'center'",
|
|
64
|
+
},
|
|
58
65
|
{
|
|
59
66
|
name: 'isDisabled',
|
|
60
67
|
type: 'boolean',
|
|
@@ -130,6 +137,13 @@ export const docsZh = {
|
|
|
130
137
|
type: 'ReactNode',
|
|
131
138
|
description: '在标签区域后渲染的内容。',
|
|
132
139
|
},
|
|
140
|
+
{
|
|
141
|
+
name: 'align',
|
|
142
|
+
type: "'center' | 'start' | 'first-line'",
|
|
143
|
+
description:
|
|
144
|
+
'起始和结束内容相对于标签的垂直对齐方式,原样传递给 Item。`first-line` 让小标记(复选框)与换行标签的第一行保持水平。参见 Item.align。',
|
|
145
|
+
default: "'center'",
|
|
146
|
+
},
|
|
133
147
|
{
|
|
134
148
|
name: 'isDisabled',
|
|
135
149
|
type: 'boolean',
|
|
@@ -165,6 +179,8 @@ export const docsDense = {
|
|
|
165
179
|
description:
|
|
166
180
|
'Individual checkbox item w/ label, description, end content slot. Collection mode inside CheckboxList with value; standalone inside List or CheckboxList without value.',
|
|
167
181
|
propDescriptions: {
|
|
182
|
+
align:
|
|
183
|
+
"Start/end content alignment, passed to Item: 'center' (default), 'start', or 'first-line' (centered on the label's first line).",
|
|
168
184
|
label:
|
|
169
185
|
'Primary label. String or ReactNode; nested controls keep their behavior. A ReactNode names the checkbox from its visible text.',
|
|
170
186
|
'aria-label':
|
|
@@ -29,6 +29,7 @@ import {ListContext} from '../List/ListContext';
|
|
|
29
29
|
import {CheckboxListContext} from './CheckboxListContext';
|
|
30
30
|
import {useTranslator} from '../i18n';
|
|
31
31
|
import {ItemDescriptionContext} from '../Item/ItemDescriptionContext';
|
|
32
|
+
import type {ItemAlign} from '../Item';
|
|
32
33
|
|
|
33
34
|
// =============================================================================
|
|
34
35
|
// Styles
|
|
@@ -45,6 +46,13 @@ const styles = stylex.create({
|
|
|
45
46
|
// =============================================================================
|
|
46
47
|
|
|
47
48
|
export interface CheckboxListItemProps extends BaseProps<HTMLLIElement> {
|
|
49
|
+
/**
|
|
50
|
+
* Vertical alignment of the start and end content against the label,
|
|
51
|
+
* forwarded to Item. Use `first-line` to keep the checkbox level with the
|
|
52
|
+
* first line of a wrapped label.
|
|
53
|
+
* @default 'center'
|
|
54
|
+
*/
|
|
55
|
+
align?: ItemAlign;
|
|
48
56
|
/**
|
|
49
57
|
* Primary text label for the item.
|
|
50
58
|
*
|
|
@@ -192,6 +200,7 @@ export function CheckboxListItem({
|
|
|
192
200
|
className,
|
|
193
201
|
style,
|
|
194
202
|
onClick: onClickProp,
|
|
203
|
+
align,
|
|
195
204
|
...restProps
|
|
196
205
|
}: CheckboxListItemProps) {
|
|
197
206
|
const t = useTranslator();
|
|
@@ -297,6 +306,7 @@ export function CheckboxListItem({
|
|
|
297
306
|
label={namesFromVisibleLabel ? <span id={labelID}>{label}</span> : label}
|
|
298
307
|
description={description}
|
|
299
308
|
endContent={endContent}
|
|
309
|
+
align={align}
|
|
300
310
|
isDisabled={effectiveDisabled}
|
|
301
311
|
// Delegate row clicks to the checkbox instead of wiring onClick (which
|
|
302
312
|
// would add an invisible row button = a second tab stop). The checkbox
|
|
@@ -110,6 +110,52 @@ beforeEach(() => {
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
describe('Dialog', () => {
|
|
113
|
+
it('restores focus to the opener when content mounts in the open commit', () => {
|
|
114
|
+
function Harness({
|
|
115
|
+
open,
|
|
116
|
+
onOpenChange,
|
|
117
|
+
}: {
|
|
118
|
+
open: boolean;
|
|
119
|
+
onOpenChange: (v: boolean) => void;
|
|
120
|
+
}) {
|
|
121
|
+
return (
|
|
122
|
+
<>
|
|
123
|
+
<button type="button" onClick={() => onOpenChange(true)}>
|
|
124
|
+
Open
|
|
125
|
+
</button>
|
|
126
|
+
<Dialog isOpen={open} onOpenChange={onOpenChange}>
|
|
127
|
+
{open ? (
|
|
128
|
+
<div>
|
|
129
|
+
<DialogHeader title="Review" />
|
|
130
|
+
<p>Body</p>
|
|
131
|
+
</div>
|
|
132
|
+
) : null}
|
|
133
|
+
</Dialog>
|
|
134
|
+
</>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let open = false;
|
|
139
|
+
const setOpen = (v: boolean) => {
|
|
140
|
+
open = v;
|
|
141
|
+
};
|
|
142
|
+
const harness = render(<Harness open={open} onOpenChange={setOpen} />);
|
|
143
|
+
const opener = screen.getByRole('button', {name: 'Open'});
|
|
144
|
+
opener.focus();
|
|
145
|
+
|
|
146
|
+
fireEvent.click(opener);
|
|
147
|
+
harness.rerender(<Harness open={open} onOpenChange={setOpen} />);
|
|
148
|
+
|
|
149
|
+
// The freshly mounted header title is the focused screen reader anchor
|
|
150
|
+
// while the dialog is open...
|
|
151
|
+
expect(document.activeElement).toBe(screen.getByText('Review'));
|
|
152
|
+
|
|
153
|
+
// ...but closing restores the element that opened the dialog, not the
|
|
154
|
+
// (now unmounted) title.
|
|
155
|
+
harness.rerender(<Harness open={false} onOpenChange={setOpen} />);
|
|
156
|
+
expect(document.activeElement).toBe(opener);
|
|
157
|
+
});
|
|
158
|
+
|
|
113
159
|
it('renders when isOpen is true', () => {
|
|
114
160
|
render(
|
|
115
161
|
<Dialog isOpen={true} onOpenChange={() => {}}>
|
package/src/Dialog/Dialog.tsx
CHANGED
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
useCallback,
|
|
33
33
|
useEffect,
|
|
34
34
|
useId,
|
|
35
|
+
useLayoutEffect,
|
|
35
36
|
useMemo,
|
|
36
37
|
useRef,
|
|
37
38
|
type ReactNode,
|
|
@@ -505,12 +506,26 @@ export function Dialog({
|
|
|
505
506
|
|
|
506
507
|
const mergedDialogRef = useMergedRefs(ref, attachDialog);
|
|
507
508
|
|
|
508
|
-
// Capture the element that was focused when the dialog opened,
|
|
509
|
-
//
|
|
509
|
+
// Capture the element that was focused when the dialog opened, for
|
|
510
|
+
// directional animation origin and focus restoration on close.
|
|
510
511
|
const triggerElementRef = useRef<HTMLElement | null>(null);
|
|
511
512
|
|
|
512
513
|
useInteractionModalityTracking();
|
|
513
514
|
|
|
515
|
+
// This runs in a layout effect so the capture lands before any descendant's
|
|
516
|
+
// passive mount effect: all layout effects run before any passive effect,
|
|
517
|
+
// while a child's passive effect runs before this parent's passive effect.
|
|
518
|
+
// Content that mounts in the open commit — e.g. a DialogHeader focusing its
|
|
519
|
+
// own title on mount — would otherwise move document.activeElement inside
|
|
520
|
+
// the dialog before the capture ran, and closing would then restore focus
|
|
521
|
+
// to a detached node, stranding the user's focus on <body>.
|
|
522
|
+
useLayoutEffect(() => {
|
|
523
|
+
if (isInline || !isOpen) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
triggerElementRef.current = document.activeElement as HTMLElement | null;
|
|
527
|
+
}, [isOpen, isInline]);
|
|
528
|
+
|
|
514
529
|
// Derive dismissal behavior from purpose
|
|
515
530
|
const allowEscape = purpose !== 'required';
|
|
516
531
|
const allowBackdropClick = purpose === 'info';
|
|
@@ -526,11 +541,9 @@ export function Dialog({
|
|
|
526
541
|
}
|
|
527
542
|
|
|
528
543
|
if (isOpen) {
|
|
529
|
-
//
|
|
530
|
-
//
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
// Set directional CSS custom properties before opening
|
|
544
|
+
// Set directional CSS custom properties before opening. The trigger was
|
|
545
|
+
// captured by the layout effect above, before any descendant effect
|
|
546
|
+
// could move focus.
|
|
534
547
|
const trigger = triggerElementRef.current;
|
|
535
548
|
if (trigger && trigger !== document.body) {
|
|
536
549
|
const dir = getDialogDirection(trigger);
|
|
@@ -25,18 +25,4 @@ export const DIALOG_MODAL_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
|
|
|
25
25
|
reason:
|
|
26
26
|
'This migration records the existing focus-order violation without changing the overlapping Dialog implementation path.',
|
|
27
27
|
},
|
|
28
|
-
{
|
|
29
|
-
expectation: 'modal-dialog.focus.restored',
|
|
30
|
-
binding: 'Dialog',
|
|
31
|
-
state: 'conditional-content-focus-restoration',
|
|
32
|
-
evidenceLayer: 'real-browser',
|
|
33
|
-
failureEquals:
|
|
34
|
-
'closing the modal dialog did not return focus to its still-available invoker',
|
|
35
|
-
standardsReference:
|
|
36
|
-
'Astryx component:Dialog FR4 — closing a native Dialog must return focus to its still-connected invoker when it can receive focus.',
|
|
37
|
-
userImpact:
|
|
38
|
-
'When focus-moving content mounts only while the dialog is open, closing can leave the user at the document body instead of the control that opened the task.',
|
|
39
|
-
reason:
|
|
40
|
-
'This migration records the existing restoration violation without changing the overlapping Dialog implementation path.',
|
|
41
|
-
},
|
|
42
28
|
];
|