@astryxdesign/core 0.6.0 → 0.6.1
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 +41 -3
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts +12 -1
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +44 -15
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +3 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +3 -7
- package/dist/Center/Center.d.ts +23 -16
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +7 -5
- package/dist/CodeBlock/CodeBlock.js +2 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +12 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +12 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +1 -0
- package/dist/Field/InputClearButton.d.ts +2 -2
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +5 -1
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +16 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +12 -1
- package/dist/HoverCard/useHoverCard.js +2 -2
- package/dist/Indicator/CheckboxIndicator.js +2 -2
- package/dist/Indicator/RadioIndicator.js +2 -2
- package/dist/Layer/layerStack.d.ts +10 -0
- package/dist/Layer/layerStack.d.ts.map +1 -1
- package/dist/Layer/layerStack.js +21 -9
- package/dist/Layer/useLayerDismissal.d.ts +2 -3
- package/dist/Layer/useLayerDismissal.d.ts.map +1 -1
- package/dist/Layer/useLayerDismissal.js +2 -3
- package/dist/NavIcon/NavIcon.js +2 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +12 -2
- package/dist/Popover/usePopover.d.ts +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +4 -2
- package/dist/ProgressBar/ProgressBar.js +2 -2
- package/dist/ScrollableArea/ScrollableArea.d.ts +79 -0
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -0
- package/dist/ScrollableArea/ScrollableArea.js +144 -0
- package/dist/ScrollableArea/index.d.ts +11 -0
- package/dist/ScrollableArea/index.d.ts.map +1 -0
- package/dist/ScrollableArea/index.js +11 -0
- package/dist/StatusDot/StatusDot.js +2 -2
- package/dist/TextArea/TextArea.js +2 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +19 -4
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +12 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +21 -14
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +56 -20
- package/dist/astryx.css +15 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/scrollGeometry.d.ts +24 -0
- package/dist/hooks/scrollGeometry.d.ts.map +1 -0
- package/dist/hooks/scrollGeometry.js +86 -0
- package/dist/hooks/scrollOwnerRegistry.d.ts +15 -0
- package/dist/hooks/scrollOwnerRegistry.d.ts.map +1 -0
- package/dist/hooks/scrollOwnerRegistry.js +24 -0
- package/dist/hooks/useFocusTrap.d.ts +8 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +22 -11
- package/dist/hooks/useScrollableArea.d.ts +51 -0
- package/dist/hooks/useScrollableArea.d.ts.map +1 -0
- package/dist/hooks/useScrollableArea.js +287 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/defineTheme.d.ts +2 -6
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/derivedVarRegistry.js +1 -1
- package/dist/theme/localTokens.d.ts +8 -11
- package/dist/theme/localTokens.d.ts.map +1 -1
- package/dist/theme/localTokens.js +17 -71
- package/dist/theme/themeAdaptations.d.ts.map +1 -1
- package/dist/theme/themeAdaptations.js +4 -4
- package/dist/utils/themeProps.d.ts +10 -10
- package/dist/utils/themeProps.d.ts.map +1 -1
- package/dist/utils/themeProps.js +27 -10
- package/locales/en.json +16 -0
- package/locales/pseudo.json +12 -0
- package/package.json +7 -2
- package/src/AppShell/AppShell.test.tsx +36 -0
- package/src/AppShell/AppShell.tsx +4 -1
- package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
- package/src/Banner/Banner.test.tsx +3 -1
- package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +56 -1
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +211 -0
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +134 -2
- package/src/BottomSheet/BottomSheetSwitcher.tsx +43 -20
- package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +10 -5
- package/src/Breadcrumbs/BreadcrumbItem.spec.md +225 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +8 -13
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -2
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +49 -2
- package/src/Center/Center.doc.mjs +32 -28
- package/src/Center/Center.spec.md +225 -0
- package/src/Center/Center.test.tsx +42 -4
- package/src/Center/Center.tsx +24 -17
- package/src/Chat/ChatSystemMessage.test.tsx +2 -9
- package/src/CodeBlock/CodeBlock.doc.mjs +2 -2
- package/src/CodeBlock/CodeBlock.tsx +2 -2
- package/src/DateInput/DateInput.test.tsx +4 -4
- package/src/DateInput/DateInput.tsx +15 -4
- package/src/DateRangeInput/DateRangeInput.test.tsx +2 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +6 -4
- package/src/DateTimeInput/DateTimeInput.tsx +18 -7
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +4 -77
- package/src/Field/Field.test.tsx +42 -0
- package/src/Field/Field.tsx +6 -0
- package/src/Field/InputClearButton.test.tsx +35 -1
- package/src/Field/InputClearButton.tsx +7 -3
- package/src/Field/PanelSearchInput.tsx +21 -8
- package/src/FieldStatus/FieldStatus.spec.md +27 -17
- package/src/FieldStatus/FieldStatus.test.tsx +7 -5
- package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +198 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.known-failures.ts +13 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.renders.tsx +305 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +317 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.test.tsx +155 -0
- package/src/FileInput/FileInput.tsx +10 -1
- package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +3 -3
- package/src/HoverCard/HoverCard.doc.mjs +4 -4
- package/src/HoverCard/useHoverCard.tsx +2 -2
- package/src/Indicator/CheckboxIndicator.tsx +2 -2
- package/src/Indicator/Indicator.doc.mjs +2 -2
- package/src/Indicator/Indicator.test.tsx +1 -1
- package/src/Indicator/RadioIndicator.tsx +2 -2
- package/src/Layer/layerStack.ts +20 -9
- package/src/Layer/useLayerDismissal.ts +2 -3
- package/src/MultiSelector/MultiSelector.test.tsx +4 -4
- package/src/NavIcon/NavIcon.doc.mjs +4 -4
- package/src/NavIcon/NavIcon.tsx +2 -2
- package/src/NumberInput/NumberInput.tsx +18 -7
- package/src/Popover/Popover.doc.mjs +10 -10
- package/src/Popover/Popover.spec.md +55 -65
- package/src/Popover/Popover.test.tsx +29 -0
- package/src/Popover/usePopover.doc.mjs +4 -4
- package/src/Popover/usePopover.tsx +7 -4
- package/src/ProgressBar/ProgressBar.doc.mjs +4 -4
- package/src/ProgressBar/ProgressBar.test.tsx +1 -31
- package/src/ProgressBar/ProgressBar.tsx +2 -2
- package/src/RadioList/RadioList.test.tsx +5 -144
- package/src/RadioList/__tests__/RadioGroup.a11y.chromium.spec.ts +255 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.known-failures.ts +12 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.renders.tsx +232 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.states.ts +503 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.test.tsx +217 -0
- package/src/ScrollableArea/ScrollableArea.doc.mjs +100 -0
- package/src/ScrollableArea/ScrollableArea.spec.md +189 -0
- package/src/ScrollableArea/ScrollableArea.test.tsx +299 -0
- package/src/ScrollableArea/ScrollableArea.tsx +259 -0
- package/src/ScrollableArea/index.ts +26 -0
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +121 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +5 -172
- package/src/Selector/Selector.test.tsx +4 -4
- package/src/Spinner/Spinner.test.tsx +0 -18
- package/src/StatusDot/StatusDot.doc.mjs +4 -4
- package/src/StatusDot/StatusDot.tsx +2 -2
- package/src/TabList/TabList.test.tsx +5 -9
- package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +191 -0
- package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +45 -0
- package/src/TabList/__tests__/Tabs.a11y.renders.tsx +92 -0
- package/src/TabList/__tests__/Tabs.a11y.states.ts +247 -0
- package/src/TabList/__tests__/Tabs.a11y.test.tsx +153 -0
- package/src/Table/Table.doc.mjs +2 -2
- package/src/TextArea/TextArea.doc.mjs +4 -4
- package/src/TextArea/TextArea.tsx +2 -2
- package/src/TextInput/TextInput.doc.mjs +2 -1
- package/src/TextInput/TextInput.test.tsx +94 -0
- package/src/TextInput/TextInput.tsx +22 -6
- package/src/TimeInput/TimeInput.tsx +18 -7
- package/src/Toast/ToastViewport.test.tsx +1 -39
- package/src/Typeahead/BaseTypeahead.doc.mjs +229 -33
- package/src/Typeahead/BaseTypeahead.spec.md +269 -0
- package/src/Typeahead/BaseTypeahead.test.tsx +200 -0
- package/src/Typeahead/BaseTypeahead.tsx +99 -30
- package/src/hooks/index.ts +13 -0
- package/src/hooks/scrollGeometry.ts +155 -0
- package/src/hooks/scrollOwnerRegistry.ts +47 -0
- package/src/hooks/useFocusTrap.ts +22 -11
- package/src/hooks/useFocusTrapEscapeShim.test.tsx +4 -3
- package/src/hooks/useScrollableArea.doc.mjs +108 -0
- package/src/hooks/useScrollableArea.test.tsx +437 -0
- package/src/hooks/useScrollableArea.ts +469 -0
- package/src/index.ts +1 -0
- package/src/theme/defineTheme.test.ts +65 -105
- package/src/theme/defineTheme.ts +3 -9
- package/src/theme/derivedVarRegistry.ts +1 -1
- package/src/theme/localTokens.ts +25 -96
- package/src/theme/publicThemeHelperContract.test.ts +2 -2
- package/src/theme/themeAdaptations.test.ts +16 -42
- package/src/theme/themeAdaptations.ts +6 -9
- package/src/utils/themeProps.test.ts +29 -10
- package/src/utils/themeProps.ts +36 -17
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
/** @vitest-environment jsdom */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file StatusMessage.a11y.test.tsx
|
|
6
|
+
* @input Uses the shared status-message contract and current Core binding render map
|
|
7
|
+
* @output Component-facing jsdom evidence through expectAccessibilitySpec
|
|
8
|
+
* @position Fast migration lane; browser-owned outcomes remain explicitly unrun
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {afterEach, describe, expect, it} from 'vitest';
|
|
12
|
+
import {
|
|
13
|
+
act,
|
|
14
|
+
cleanup,
|
|
15
|
+
fireEvent,
|
|
16
|
+
render,
|
|
17
|
+
screen,
|
|
18
|
+
waitFor,
|
|
19
|
+
} from '@testing-library/react';
|
|
20
|
+
import {
|
|
21
|
+
STATUS_MESSAGE_PATTERN,
|
|
22
|
+
expectAccessibilitySpec,
|
|
23
|
+
} from '@astryxdesign/a11y-spec';
|
|
24
|
+
import {__resetLiveRegionsForTest} from '../../hooks/useAnnounce';
|
|
25
|
+
import {CORE_STATUS_MESSAGE_KNOWN_FAILURES} from './StatusMessage.a11y.known-failures';
|
|
26
|
+
import {
|
|
27
|
+
CORE_STATUS_MESSAGE_STATE_RENDERS,
|
|
28
|
+
transitionTestId,
|
|
29
|
+
} from './StatusMessage.a11y.renders';
|
|
30
|
+
import {
|
|
31
|
+
CORE_STATUS_MESSAGE_BINDING_STATES,
|
|
32
|
+
CORE_STATUS_MESSAGE_EXCLUSIONS,
|
|
33
|
+
type CoreStatusMessageBindingState,
|
|
34
|
+
} from './StatusMessage.a11y.states';
|
|
35
|
+
|
|
36
|
+
async function twoFrames(): Promise<void> {
|
|
37
|
+
await new Promise<void>(resolve => {
|
|
38
|
+
requestAnimationFrame(() => requestAnimationFrame(() => resolve()));
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function renderState(
|
|
43
|
+
state: CoreStatusMessageBindingState,
|
|
44
|
+
): Promise<void> {
|
|
45
|
+
render(CORE_STATUS_MESSAGE_STATE_RENDERS[state.id]());
|
|
46
|
+
await waitFor(() =>
|
|
47
|
+
expect(document.querySelector('[data-a11y-ready="true"]')).not.toBeNull(),
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function subjectFor(state: CoreStatusMessageBindingState): Element {
|
|
52
|
+
const facts = state.facts;
|
|
53
|
+
const role = facts.kind === 'progressbar' ? 'progressbar' : facts.role;
|
|
54
|
+
if (role == null) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`${state.id}: this component binding declares no public role`,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const matches =
|
|
60
|
+
facts.kind === 'progressbar'
|
|
61
|
+
? screen.getAllByRole(role, {hidden: true, name: facts.name})
|
|
62
|
+
: facts.messageSource === 'accessible-name'
|
|
63
|
+
? screen.getAllByRole(role, {
|
|
64
|
+
hidden: true,
|
|
65
|
+
name: facts.initialMessage,
|
|
66
|
+
})
|
|
67
|
+
: screen
|
|
68
|
+
.getAllByRole(role, {hidden: true})
|
|
69
|
+
.filter(
|
|
70
|
+
element =>
|
|
71
|
+
(element.textContent ?? '').replace(/\s+/g, ' ').trim() ===
|
|
72
|
+
facts.initialMessage,
|
|
73
|
+
);
|
|
74
|
+
if (matches.length !== 1) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`${state.id}: expected one ${role} subject in initial state, found ${matches.length}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return matches[0];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function transition(name: string): Promise<void> {
|
|
83
|
+
fireEvent.click(screen.getByTestId(transitionTestId(name)));
|
|
84
|
+
await act(twoFrames);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function reset(): void {
|
|
88
|
+
cleanup();
|
|
89
|
+
__resetLiveRegionsForTest();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
afterEach(reset);
|
|
93
|
+
|
|
94
|
+
describe('Core status-message bindings — jsdom lane', () => {
|
|
95
|
+
it.each(
|
|
96
|
+
CORE_STATUS_MESSAGE_BINDING_STATES.map(
|
|
97
|
+
state =>
|
|
98
|
+
[`${state.binding} [${state.id}]`, state.summary, state] as const,
|
|
99
|
+
),
|
|
100
|
+
)('%s — %s', async (_id, _summary, state) => {
|
|
101
|
+
await expectAccessibilitySpec({
|
|
102
|
+
spec: STATUS_MESSAGE_PATTERN,
|
|
103
|
+
binding: state.binding,
|
|
104
|
+
state: state.id,
|
|
105
|
+
facts: state.facts,
|
|
106
|
+
knownFailures: CORE_STATUS_MESSAGE_KNOWN_FAILURES,
|
|
107
|
+
render: async () => renderState(state),
|
|
108
|
+
subject: () => subjectFor(state),
|
|
109
|
+
transition,
|
|
110
|
+
cleanup: reset,
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('Core status-message binding inventory', () => {
|
|
116
|
+
it('names a distinct checked-in story for every bound state', () => {
|
|
117
|
+
const stories = CORE_STATUS_MESSAGE_BINDING_STATES.map(
|
|
118
|
+
state => state.storyId,
|
|
119
|
+
);
|
|
120
|
+
expect(new Set(stories).size).toBe(stories.length);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('binds every named Core status-message owner', () => {
|
|
124
|
+
expect(
|
|
125
|
+
[
|
|
126
|
+
...new Set(
|
|
127
|
+
CORE_STATUS_MESSAGE_BINDING_STATES.map(state => state.binding),
|
|
128
|
+
),
|
|
129
|
+
].sort(),
|
|
130
|
+
).toEqual([
|
|
131
|
+
'ChatSystemMessage',
|
|
132
|
+
'FieldStatus announcement channel',
|
|
133
|
+
'ProgressBar',
|
|
134
|
+
'Spinner',
|
|
135
|
+
'Toast announcement channel',
|
|
136
|
+
'Toast card',
|
|
137
|
+
]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('records every adjacent non-status or separately owned surface explicitly', () => {
|
|
141
|
+
expect(CORE_STATUS_MESSAGE_EXCLUSIONS.map(entry => entry.part)).toEqual([
|
|
142
|
+
'visible validation text',
|
|
143
|
+
'aria-hidden decorative spinner',
|
|
144
|
+
'date or section separator',
|
|
145
|
+
'role=log transcript updates',
|
|
146
|
+
'composer errors and tool-run states',
|
|
147
|
+
'busy announcement',
|
|
148
|
+
'focusable target-mark triggers and labels',
|
|
149
|
+
'visual fill, track, animation, and status cadence',
|
|
150
|
+
]);
|
|
151
|
+
expect(
|
|
152
|
+
CORE_STATUS_MESSAGE_EXCLUSIONS.every(entry => entry.reason.length > 0),
|
|
153
|
+
).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
@@ -589,7 +589,16 @@ export function FileInput({
|
|
|
589
589
|
onChange(null);
|
|
590
590
|
if (inputRef.current) {
|
|
591
591
|
inputRef.current.value = '';
|
|
592
|
-
inputRef.current
|
|
592
|
+
const targetInput = inputRef.current;
|
|
593
|
+
if (e.detail === 0) {
|
|
594
|
+
targetInput.focus();
|
|
595
|
+
} else {
|
|
596
|
+
// Defer focus restoration past the button's unmount task so iOS Safari
|
|
597
|
+
// and touch browsers don't jump the page scroll to 0 on tap.
|
|
598
|
+
requestAnimationFrame(() => {
|
|
599
|
+
targetInput.focus({preventScroll: true});
|
|
600
|
+
});
|
|
601
|
+
}
|
|
593
602
|
}
|
|
594
603
|
},
|
|
595
604
|
[onChange],
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`FormLayout > matches snapshot for horizontal direction 1`] = `
|
|
4
4
|
<div
|
|
5
|
-
class="astryx-form-layout FormLayout__styles.base xdt5ytf x18g69wz FormLayout__styles.horizontal xrvj5dj x1mt1orb xu6a5m6"
|
|
5
|
+
class="astryx-form-layout horizontal FormLayout__styles.base xdt5ytf x18g69wz FormLayout__styles.horizontal xrvj5dj x1mt1orb xu6a5m6"
|
|
6
6
|
data-direction="horizontal"
|
|
7
7
|
data-testid="layout"
|
|
8
8
|
>
|
|
@@ -17,7 +17,7 @@ exports[`FormLayout > matches snapshot for horizontal direction 1`] = `
|
|
|
17
17
|
|
|
18
18
|
exports[`FormLayout > matches snapshot for horizontal-labels direction 1`] = `
|
|
19
19
|
<div
|
|
20
|
-
class="astryx-form-layout FormLayout__styles.base xdt5ytf FormLayout__styles.horizontalLabels xrvj5dj x1pmbctz xlaq8a2 x7a106z xedohl4 x1rpgqan x1a1jff"
|
|
20
|
+
class="astryx-form-layout horizontal-labels FormLayout__styles.base xdt5ytf FormLayout__styles.horizontalLabels xrvj5dj x1pmbctz xlaq8a2 x7a106z xedohl4 x1rpgqan x1a1jff"
|
|
21
21
|
data-direction="horizontal-labels"
|
|
22
22
|
data-testid="layout"
|
|
23
23
|
>
|
|
@@ -32,7 +32,7 @@ exports[`FormLayout > matches snapshot for horizontal-labels direction 1`] = `
|
|
|
32
32
|
|
|
33
33
|
exports[`FormLayout > matches snapshot for vertical direction 1`] = `
|
|
34
34
|
<div
|
|
35
|
-
class="astryx-form-layout FormLayout__styles.base x78zum5 xdt5ytf x18g69wz"
|
|
35
|
+
class="astryx-form-layout vertical FormLayout__styles.base x78zum5 xdt5ytf x18g69wz"
|
|
36
36
|
data-direction="vertical"
|
|
37
37
|
data-testid="layout"
|
|
38
38
|
>
|
|
@@ -17,8 +17,8 @@ export const docs = {
|
|
|
17
17
|
theming: {
|
|
18
18
|
targets: [
|
|
19
19
|
{className: 'astryx-hover-card'},
|
|
20
|
-
//
|
|
21
|
-
//
|
|
20
|
+
// Retained beside the canonical names for backwards compatibility.
|
|
21
|
+
// New themes use the canonical targets above.
|
|
22
22
|
{className: 'astryx-hovercard', deprecatedFor: 'hover-card'},
|
|
23
23
|
],
|
|
24
24
|
vars: [
|
|
@@ -148,8 +148,8 @@ export const docsZh = {
|
|
|
148
148
|
theming: {
|
|
149
149
|
targets: [
|
|
150
150
|
{className: 'astryx-hover-card'},
|
|
151
|
-
//
|
|
152
|
-
//
|
|
151
|
+
// Retained beside the canonical names for backwards compatibility.
|
|
152
|
+
// New themes use the canonical targets above.
|
|
153
153
|
{className: 'astryx-hovercard', deprecatedFor: 'hover-card'},
|
|
154
154
|
],
|
|
155
155
|
vars: [
|
|
@@ -609,8 +609,8 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
609
609
|
): ReactNode => {
|
|
610
610
|
const renderPlacement = props?.placement ?? placement;
|
|
611
611
|
const themeClassName = themeProps('hover-card', undefined, {
|
|
612
|
-
// `hovercard` ran the compound name together;
|
|
613
|
-
//
|
|
612
|
+
// `hovercard` ran the compound name together; keep it emitted so
|
|
613
|
+
// existing themes continue to work.
|
|
614
614
|
legacyNames: ['hovercard'],
|
|
615
615
|
}).className;
|
|
616
616
|
const renderProps = {
|
|
@@ -206,8 +206,8 @@ export function CheckboxIndicator({
|
|
|
206
206
|
: null,
|
|
207
207
|
disabled: isDisabled ? 'disabled' : null,
|
|
208
208
|
},
|
|
209
|
-
// `checkbox` was the target before indicators existed;
|
|
210
|
-
//
|
|
209
|
+
// `checkbox` was the target before indicators existed; keep it
|
|
210
|
+
// emitted so existing themes continue to work.
|
|
211
211
|
{legacyNames: ['checkbox']},
|
|
212
212
|
),
|
|
213
213
|
stylex.props(
|
|
@@ -143,8 +143,8 @@ export const docs = {
|
|
|
143
143
|
states: ['checked', 'disabled'],
|
|
144
144
|
},
|
|
145
145
|
{className: 'astryx-radio-indicator-dot', visualProps: ['size']},
|
|
146
|
-
//
|
|
147
|
-
//
|
|
146
|
+
// Retained beside the canonical names for backwards compatibility.
|
|
147
|
+
// New themes use the canonical targets above.
|
|
148
148
|
{
|
|
149
149
|
className: 'astryx-checkbox',
|
|
150
150
|
visualProps: ['size'],
|
|
@@ -344,7 +344,7 @@ describe('useIndicator', () => {
|
|
|
344
344
|
* A theme target is public API. Renaming one to follow the
|
|
345
345
|
* `<component>-kebab` convention (`checkbox` → `checkbox-indicator`) would
|
|
346
346
|
* silently break every theme styling the old name — the CSS still compiles, it
|
|
347
|
-
* just stops matching. So both names
|
|
347
|
+
* just stops matching. So both names remain emitted for compatibility, and
|
|
348
348
|
* these tests pin that promise from both ends: the new name exists, and the
|
|
349
349
|
* old one has not quietly disappeared.
|
|
350
350
|
*/
|
|
@@ -170,8 +170,8 @@ export function RadioIndicator({
|
|
|
170
170
|
checked: isChecked ? 'checked' : null,
|
|
171
171
|
disabled: isDisabled ? 'disabled' : null,
|
|
172
172
|
},
|
|
173
|
-
// `radio` was the target before indicators existed;
|
|
174
|
-
//
|
|
173
|
+
// `radio` was the target before indicators existed; keep it emitted
|
|
174
|
+
// so existing themes continue to work.
|
|
175
175
|
{legacyNames: ['radio']},
|
|
176
176
|
),
|
|
177
177
|
stylex.props(
|
package/src/Layer/layerStack.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* @file layerStack.ts
|
|
7
7
|
* @input Uses the isImeKeyEvent predicate from utils/ime
|
|
8
8
|
* @output Exports the shared layer dismissal stack: registration, top-most
|
|
9
|
-
* ordering,
|
|
9
|
+
* ordering, the document-level Escape listener, and its internal local-event
|
|
10
|
+
* dispatcher
|
|
10
11
|
* @position Internal to the Layer system; consumed by useLayerDismissal, which
|
|
11
12
|
* is what overlays actually call. Not exported from the package root.
|
|
12
13
|
*
|
|
@@ -34,11 +35,12 @@
|
|
|
34
35
|
* ## Bubble phase, not capture
|
|
35
36
|
*
|
|
36
37
|
* The listener is on the BUBBLE phase so content inside a layer can claim the
|
|
37
|
-
* press first, either by `stopPropagation()` (the press never reaches
|
|
38
|
-
* `preventDefault()` (we see it and stand down).
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
38
|
+
* press first, either by `stopPropagation()` (the press never reaches the
|
|
39
|
+
* document listener) or by `preventDefault()` (we see it and stand down).
|
|
40
|
+
* A host whose public event prop can stop propagation may route the still-
|
|
41
|
+
* unprevented event through `dispatchLayerEscapeKeyDown` at its own boundary;
|
|
42
|
+
* the same stack still chooses the owner. Editors are why `preventDefault()`
|
|
43
|
+
* remains the explicit cancellation signal: their own Escape action must win.
|
|
42
44
|
*
|
|
43
45
|
* ## The stack, not the browser, decides
|
|
44
46
|
*
|
|
@@ -275,7 +277,16 @@ function dispatchEscape(): boolean {
|
|
|
275
277
|
return true;
|
|
276
278
|
}
|
|
277
279
|
|
|
278
|
-
|
|
280
|
+
/**
|
|
281
|
+
* Resolve a keydown through the shared stack immediately.
|
|
282
|
+
*
|
|
283
|
+
* The document listener is the normal path. A host may call this at its own
|
|
284
|
+
* element boundary after a consumer handler when that handler can stop
|
|
285
|
+
* propagation before the event reaches `document`. The same stack still picks
|
|
286
|
+
* the owner, and `preventDefault()` records the decision so a bubbling event is
|
|
287
|
+
* not handled twice.
|
|
288
|
+
*/
|
|
289
|
+
export function dispatchLayerEscapeKeyDown(event: KeyboardEvent): void {
|
|
279
290
|
if (event.key !== 'Escape') {
|
|
280
291
|
return;
|
|
281
292
|
}
|
|
@@ -309,7 +320,7 @@ function startListening(): void {
|
|
|
309
320
|
if (isListening || typeof document === 'undefined') {
|
|
310
321
|
return;
|
|
311
322
|
}
|
|
312
|
-
document.addEventListener('keydown',
|
|
323
|
+
document.addEventListener('keydown', dispatchLayerEscapeKeyDown);
|
|
313
324
|
document.addEventListener('compositionstart', handleCompositionStart, true);
|
|
314
325
|
document.addEventListener('compositionend', handleCompositionEnd, true);
|
|
315
326
|
document.addEventListener('blur', handleCompositionEnd, true);
|
|
@@ -320,7 +331,7 @@ function stopListening(): void {
|
|
|
320
331
|
if (!isListening || typeof document === 'undefined') {
|
|
321
332
|
return;
|
|
322
333
|
}
|
|
323
|
-
document.removeEventListener('keydown',
|
|
334
|
+
document.removeEventListener('keydown', dispatchLayerEscapeKeyDown);
|
|
324
335
|
document.removeEventListener(
|
|
325
336
|
'compositionstart',
|
|
326
337
|
handleCompositionStart,
|
|
@@ -97,9 +97,8 @@ export interface UseLayerDismissalReturn {
|
|
|
97
97
|
* The layer does NOT attach a key listener — the stack owns one listener and
|
|
98
98
|
* routes each Escape press to the top-most REGISTERED layer, so one press
|
|
99
99
|
* dismisses exactly one of them. Dialog (and what is built on it), Popover and
|
|
100
|
-
* the menus built on it, Tooltip, HoverCard, Lightbox
|
|
101
|
-
*
|
|
102
|
-
* still handles its own press when not.
|
|
100
|
+
* the menus built on it, Tooltip, HoverCard, Lightbox, MobileNav and
|
|
101
|
+
* BottomSheetSwitcher register today.
|
|
103
102
|
*
|
|
104
103
|
* `BottomSheet`, `CommandPalette`, `ContextMenu`, `DropdownMenuSubMenu`,
|
|
105
104
|
* `PowerSearchEditPopover` and lab's `Drawer` still run their own Escape
|
|
@@ -2433,8 +2433,8 @@ describe('MultiSelector clear icon theme target', () => {
|
|
|
2433
2433
|
// The canonical target lands on the icon element itself (not the button),
|
|
2434
2434
|
// so a theme can restyle just this glyph (color, size, hover) via
|
|
2435
2435
|
// `defineTheme` — a button-level target could not reach the icon's own
|
|
2436
|
-
// color/size. The original per-component name
|
|
2437
|
-
//
|
|
2436
|
+
// color/size. The original per-component name remains as a compatibility
|
|
2437
|
+
// alias.
|
|
2438
2438
|
const icon = getClearIcon();
|
|
2439
2439
|
expect(icon).toHaveClass('astryx-input-clear-icon');
|
|
2440
2440
|
expect(icon).toHaveClass('astryx-multi-selector-clear-icon');
|
|
@@ -2461,8 +2461,8 @@ describe('MultiSelector clear icon theme target', () => {
|
|
|
2461
2461
|
it('routes the clear glyph through the shared clear button, keeping the legacy target', () => {
|
|
2462
2462
|
// The clear affordance now composes the shared InputClearButton (a ghost
|
|
2463
2463
|
// Button with a secondary/sm glyph), so the icon carries the canonical
|
|
2464
|
-
// `astryx-input-clear-icon` target
|
|
2465
|
-
//
|
|
2464
|
+
// `astryx-input-clear-icon` target plus the supported compatibility alias
|
|
2465
|
+
// `astryx-multi-selector-clear-icon`. Aside from those target
|
|
2466
2466
|
// classes it matches the shared button's own `close`/`sm`/`secondary`
|
|
2467
2467
|
// glyph exactly, so the default look is defined in one place.
|
|
2468
2468
|
render(
|
|
@@ -37,8 +37,8 @@ export const docs = {
|
|
|
37
37
|
theming: {
|
|
38
38
|
targets: [
|
|
39
39
|
{className: 'astryx-nav-icon'},
|
|
40
|
-
//
|
|
41
|
-
//
|
|
40
|
+
// Retained beside the canonical names for backwards compatibility.
|
|
41
|
+
// New themes use the canonical targets above.
|
|
42
42
|
{className: 'astryx-navicon', deprecatedFor: 'nav-icon'},
|
|
43
43
|
],
|
|
44
44
|
},
|
|
@@ -70,8 +70,8 @@ export const docsZh = {
|
|
|
70
70
|
theming: {
|
|
71
71
|
targets: [
|
|
72
72
|
{className: 'astryx-nav-icon'},
|
|
73
|
-
//
|
|
74
|
-
//
|
|
73
|
+
// Retained beside the canonical names for backwards compatibility.
|
|
74
|
+
// New themes use the canonical targets above.
|
|
75
75
|
{className: 'astryx-navicon', deprecatedFor: 'nav-icon'},
|
|
76
76
|
],
|
|
77
77
|
},
|
package/src/NavIcon/NavIcon.tsx
CHANGED
|
@@ -80,8 +80,8 @@ export function NavIcon({
|
|
|
80
80
|
ref={ref}
|
|
81
81
|
{...mergeProps(
|
|
82
82
|
themeProps('nav-icon', undefined, {
|
|
83
|
-
// `navicon` ran the compound name together;
|
|
84
|
-
//
|
|
83
|
+
// `navicon` ran the compound name together; keep it emitted so
|
|
84
|
+
// existing themes continue to work.
|
|
85
85
|
legacyNames: ['navicon'],
|
|
86
86
|
}),
|
|
87
87
|
stylex.props(styles.base, xstyle),
|
|
@@ -829,13 +829,24 @@ export function NumberInput({
|
|
|
829
829
|
const canDecrement = getNextValue(-1) !== valueForStepping;
|
|
830
830
|
|
|
831
831
|
// Handle clear button click
|
|
832
|
-
const handleClear = useCallback(
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
832
|
+
const handleClear = useCallback(
|
|
833
|
+
(e?: React.MouseEvent<HTMLButtonElement>) => {
|
|
834
|
+
if (hasClear) {
|
|
835
|
+
onChange(null);
|
|
836
|
+
}
|
|
837
|
+
setPendingInput(null);
|
|
838
|
+
if (!e || e.detail === 0) {
|
|
839
|
+
inputRef.current?.focus();
|
|
840
|
+
} else {
|
|
841
|
+
// Defer focus restoration past the button's unmount task so iOS Safari
|
|
842
|
+
// and touch browsers don't jump the page scroll to 0 on tap.
|
|
843
|
+
requestAnimationFrame(() => {
|
|
844
|
+
inputRef.current?.focus({preventScroll: true});
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
},
|
|
848
|
+
[hasClear, onChange],
|
|
849
|
+
);
|
|
839
850
|
|
|
840
851
|
// Focus input when clicking anywhere on the wrapper (icons, padding, etc.)
|
|
841
852
|
const {onClick: handleWrapperClick, onMouseUp: handleWrapperMouseUp} =
|
|
@@ -168,8 +168,8 @@ export const docs = {
|
|
|
168
168
|
targets: [
|
|
169
169
|
// Canonical broad target for the painted Popover surface.
|
|
170
170
|
{className: 'astryx-popover'},
|
|
171
|
-
// Deprecated compatibility alias. Existing themes
|
|
172
|
-
//
|
|
171
|
+
// Deprecated compatibility alias. Existing themes remain supported;
|
|
172
|
+
// new themes target `popover`.
|
|
173
173
|
{
|
|
174
174
|
className: 'astryx-popover-surface',
|
|
175
175
|
deprecatedFor: 'popover',
|
|
@@ -202,7 +202,7 @@ export const docs = {
|
|
|
202
202
|
{
|
|
203
203
|
guidance: true,
|
|
204
204
|
description:
|
|
205
|
-
'Theme the painted surface through popover. Existing popover-surface overrides remain supported
|
|
205
|
+
'Theme the painted surface through popover. Existing popover-surface overrides remain supported for compatibility, while new themes use the canonical target.',
|
|
206
206
|
},
|
|
207
207
|
{
|
|
208
208
|
guidance: false,
|
|
@@ -231,7 +231,7 @@ export const docs = {
|
|
|
231
231
|
name: 'Popover surface',
|
|
232
232
|
required: true,
|
|
233
233
|
description:
|
|
234
|
-
'Painted surface owned by Popover. Theme it through the canonical popover target; popover-surface remains
|
|
234
|
+
'Painted surface owned by Popover. Theme it through the canonical popover target; popover-surface remains supported as a deprecated compatibility alias.',
|
|
235
235
|
},
|
|
236
236
|
{
|
|
237
237
|
name: 'Popover content',
|
|
@@ -371,8 +371,8 @@ export const docsZh = {
|
|
|
371
371
|
targets: [
|
|
372
372
|
// Canonical broad target for the painted Popover surface.
|
|
373
373
|
{className: 'astryx-popover'},
|
|
374
|
-
// Deprecated compatibility alias. Existing themes
|
|
375
|
-
//
|
|
374
|
+
// Deprecated compatibility alias. Existing themes remain supported;
|
|
375
|
+
// new themes target `popover`.
|
|
376
376
|
{
|
|
377
377
|
className: 'astryx-popover-surface',
|
|
378
378
|
deprecatedFor: 'popover',
|
|
@@ -405,7 +405,7 @@ export const docsZh = {
|
|
|
405
405
|
{
|
|
406
406
|
guidance: true,
|
|
407
407
|
description:
|
|
408
|
-
'Theme the painted surface through popover. Existing popover-surface overrides remain supported
|
|
408
|
+
'Theme the painted surface through popover. Existing popover-surface overrides remain supported for compatibility, while new themes use the canonical target.',
|
|
409
409
|
},
|
|
410
410
|
{
|
|
411
411
|
guidance: false,
|
|
@@ -434,7 +434,7 @@ export const docsZh = {
|
|
|
434
434
|
name: 'Popover surface',
|
|
435
435
|
required: true,
|
|
436
436
|
description:
|
|
437
|
-
'Painted surface owned by Popover. Theme it through the canonical popover target; popover-surface remains
|
|
437
|
+
'Painted surface owned by Popover. Theme it through the canonical popover target; popover-surface remains supported as a deprecated compatibility alias.',
|
|
438
438
|
},
|
|
439
439
|
{
|
|
440
440
|
name: 'Popover content',
|
|
@@ -472,7 +472,7 @@ export const docsDense = {
|
|
|
472
472
|
{
|
|
473
473
|
guidance: true,
|
|
474
474
|
description:
|
|
475
|
-
'Theme the painted surface through popover. Existing popover-surface overrides remain supported
|
|
475
|
+
'Theme the painted surface through popover. Existing popover-surface overrides remain supported for compatibility, while new themes use the canonical target.',
|
|
476
476
|
},
|
|
477
477
|
{
|
|
478
478
|
guidance: false,
|
|
@@ -501,7 +501,7 @@ export const docsDense = {
|
|
|
501
501
|
name: 'Popover surface',
|
|
502
502
|
required: true,
|
|
503
503
|
description:
|
|
504
|
-
'Painted surface owned by Popover. Theme it through the canonical popover target; popover-surface remains
|
|
504
|
+
'Painted surface owned by Popover. Theme it through the canonical popover target; popover-surface remains supported as a deprecated compatibility alias.',
|
|
505
505
|
},
|
|
506
506
|
{
|
|
507
507
|
name: 'Popover content',
|