@astryxdesign/core 0.7.2 → 0.7.3-canary.04c7468
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +8 -4
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +7 -0
- package/dist/Calendar/Calendar.js +3 -2
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +19 -24
- package/dist/ClickableCard/ClickableCard.d.ts +2 -2
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +11 -9
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +11 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +23 -5
- package/dist/DateInput/DateInput.d.ts +4 -4
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +27 -20
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +14 -8
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +14 -10
- package/dist/DateRangeInput/DateRangeInput.d.ts +5 -5
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +27 -18
- package/dist/DateTimeInput/DateTimeInput.d.ts +5 -5
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +25 -27
- package/dist/DateTimeInput/NativeDateSegment.d.ts +3 -2
- package/dist/DateTimeInput/NativeDateSegment.d.ts.map +1 -1
- package/dist/DateTimeInput/NativeDateSegment.js +5 -5
- package/dist/DateTimeInput/NativeTimeSegment.d.ts +3 -2
- package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
- package/dist/DateTimeInput/NativeTimeSegment.js +5 -5
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +12 -9
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +9 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +52 -10
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +34 -1
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +15 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +21 -2
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +375 -42
- package/dist/DropdownMenu/menuRegionStops.d.ts +2 -2
- package/dist/DropdownMenu/menuRegionStops.js +2 -2
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +14 -12
- package/dist/Link/Link.d.ts +2 -3
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +11 -19
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +48 -15
- package/dist/MultiSelector/MultiSelector.d.ts +4 -4
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts +2 -0
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.d.ts.map +1 -0
- package/dist/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.js +48 -0
- package/dist/MultiSelector/MultiSelector.js +25 -18
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +5 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +8 -4
- package/dist/Selector/Selector.d.ts +4 -4
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +23 -14
- package/dist/Selector/SelectorOption.d.ts.map +1 -1
- package/dist/Selector/SelectorOption.js +1 -0
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +7 -14
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +25 -17
- package/dist/Switch/switch.markers.stylex.d.ts +2 -0
- package/dist/Switch/switch.markers.stylex.d.ts.map +1 -1
- package/dist/Switch/switch.markers.stylex.js +6 -0
- package/dist/TimeInput/TimeInput.d.ts +7 -6
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +37 -20
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -1
- package/dist/TimeInput/TouchTimeField.js +17 -6
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +41 -8
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +8 -3
- package/dist/Tooltip/Tooltip.d.ts.map +1 -1
- package/dist/Tooltip/Tooltip.js +36 -14
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +11 -2
- package/dist/TopNav/TopNav.d.ts.map +1 -1
- package/dist/TopNav/TopNav.js +2 -2
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +1 -0
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +8 -3
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +14 -2
- package/dist/astryx.css +8 -2
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +10 -1
- package/dist/hooks/useMenuPress.d.ts +11 -1
- package/dist/hooks/useMenuPress.d.ts.map +1 -1
- package/dist/hooks/useMenuPress.js +43 -5
- package/dist/utils/disabledInteraction.d.ts +21 -0
- package/dist/utils/disabledInteraction.d.ts.map +1 -0
- package/dist/utils/disabledInteraction.js +33 -0
- package/dist/utils/timeParser.d.ts +4 -0
- package/dist/utils/timeParser.d.ts.map +1 -1
- package/dist/utils/timeParser.js +9 -2
- package/package.json +4 -4
- package/scripts/agent-doc-state.mjs +58 -9
- package/src/Banner/Banner.spec.md +37 -32
- package/src/BottomSheet/BottomSheet.spec.md +34 -54
- package/src/BottomSheet/BottomSheet.test.tsx +29 -0
- package/src/BottomSheet/BottomSheet.tsx +8 -4
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +125 -58
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +26 -0
- package/src/BottomSheet/BottomSheetSwitcher.tsx +6 -0
- package/src/Calendar/Calendar.test.tsx +68 -24
- package/src/Calendar/Calendar.tsx +2 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +44 -5
- package/src/CheckboxInput/CheckboxInput.tsx +16 -26
- package/src/CheckboxInput/__tests__/Checkbox.a11y.states.ts +3 -3
- package/src/CheckboxList/CheckboxList.test.tsx +9 -6
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
- package/src/ClickableCard/ClickableCard.test.tsx +5 -4
- package/src/ClickableCard/ClickableCard.tsx +9 -9
- package/src/CodeBlock/CodeBlock.highlightStyles.test.tsx +87 -0
- package/src/CodeBlock/CodeBlock.tsx +11 -1
- package/src/ComplexSelector/ComplexSelector.focusableDisabled.test.tsx +76 -0
- package/src/ComplexSelector/ComplexSelector.tsx +21 -4
- package/src/ContextMenu/ContextMenu.test.tsx +41 -0
- package/src/DateInput/DateInput.doc.mjs +9 -8
- package/src/DateInput/DateInput.test.tsx +88 -13
- package/src/DateInput/DateInput.tsx +49 -21
- package/src/DateInput/DateInputTouch.test.tsx +22 -1
- package/src/DateInput/NativeDateField.test.tsx +29 -3
- package/src/DateInput/NativeDateField.tsx +20 -7
- package/src/DateInput/TouchDateField.tsx +24 -9
- package/src/DateRangeInput/DateRangeInput.doc.mjs +6 -5
- package/src/DateRangeInput/DateRangeInput.spec.md +13 -13
- package/src/DateRangeInput/DateRangeInput.test.tsx +82 -16
- package/src/DateRangeInput/DateRangeInput.tsx +40 -20
- package/src/DateTimeInput/DateTimeInput.doc.mjs +9 -8
- package/src/DateTimeInput/DateTimeInput.test.tsx +126 -11
- package/src/DateTimeInput/DateTimeInput.tsx +42 -26
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +24 -0
- package/src/DateTimeInput/NativeDateSegment.tsx +9 -6
- package/src/DateTimeInput/NativePickerSegments.test.tsx +31 -0
- package/src/DateTimeInput/NativeTimeSegment.tsx +9 -6
- package/src/DateTimeInput/TouchDateTimeField.tsx +22 -7
- package/src/Dialog/Dialog.test.tsx +39 -0
- package/src/Dialog/Dialog.tsx +9 -4
- package/src/DropdownMenu/DropdownMenu.spec.md +33 -2
- package/src/DropdownMenu/DropdownMenu.tsx +79 -8
- package/src/DropdownMenu/DropdownMenuContext.public.test.ts +22 -0
- package/src/DropdownMenu/DropdownMenuContext.tsx +39 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +16 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +623 -1
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +556 -99
- package/src/DropdownMenu/__tests__/SubMenuHeaderFooter.a11y.chromium.spec.ts +267 -0
- package/src/DropdownMenu/menuRegionStops.ts +2 -2
- package/src/DropdownMenu/modules/useMenuPress.spec.md +9 -0
- package/src/FieldStatus/FieldStatus.spec.md +3 -2
- package/src/FileInput/FileInput.test.tsx +30 -7
- package/src/FileInput/FileInput.tsx +21 -11
- package/src/Link/Link.test.tsx +21 -7
- package/src/Link/Link.tsx +16 -24
- package/src/Link/__tests__/Link.a11y.states.ts +1 -1
- package/src/Markdown/Markdown.rerender.test.tsx +143 -0
- package/src/Markdown/Markdown.tsx +89 -35
- package/src/MultiSelector/MultiSelector.disabledFocus.a11y.chromium.spec.ts +71 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +5 -5
- package/src/MultiSelector/MultiSelector.focusableDisabled.test.tsx +121 -0
- package/src/MultiSelector/MultiSelector.test.tsx +49 -7
- package/src/MultiSelector/MultiSelector.tsx +53 -29
- package/src/Pagination/Pagination.test.tsx +5 -1
- package/src/Pagination/Pagination.tsx +3 -1
- package/src/Popover/Popover.test.tsx +15 -0
- package/src/Popover/Popover.tsx +19 -8
- package/src/PowerSearch/PowerSearchFilterEditor.test.tsx +3 -2
- package/src/PowerSearch/PowerSearchToken.test.tsx +7 -5
- package/src/Selector/Selector.doc.mjs +4 -4
- package/src/Selector/Selector.focusableDisabled.test.tsx +127 -0
- package/src/Selector/Selector.spec.md +11 -11
- package/src/Selector/Selector.test.tsx +64 -6
- package/src/Selector/Selector.tsx +51 -21
- package/src/Selector/SelectorOption.tsx +4 -0
- package/src/SideNav/SideNav.test.tsx +35 -0
- package/src/Slider/Slider.spec.md +11 -11
- package/src/Slider/Slider.test.tsx +3 -3
- package/src/Slider/Slider.tsx +8 -15
- package/src/Switch/Switch.test.tsx +85 -8
- package/src/Switch/Switch.tsx +26 -16
- package/src/Switch/__tests__/Switch.a11y.states.ts +2 -2
- package/src/Switch/switch.markers.stylex.ts +4 -0
- package/src/Table/Table.spec.md +2 -0
- package/src/Table/plugins/infiniteScroll/useTableInfiniteScroll.spec.md +244 -0
- package/src/Table/plugins/selection/useTableSelection.test.tsx +5 -3
- package/src/Table/plugins/virtualization/useTableVirtualization.spec.md +266 -0
- package/src/TimeInput/NativeTimeInput.test.tsx +25 -1
- package/src/TimeInput/Presentation.test.tsx +23 -0
- package/src/TimeInput/TimeInput.doc.mjs +13 -10
- package/src/TimeInput/TimeInput.test.tsx +139 -7
- package/src/TimeInput/TimeInput.tsx +53 -24
- package/src/TimeInput/TouchTimeField.tsx +27 -5
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/Timestamp/Timestamp.test.tsx +168 -0
- package/src/Timestamp/Timestamp.tsx +62 -11
- package/src/Token/Token.test.tsx +26 -4
- package/src/Token/Token.tsx +6 -2
- package/src/Tokenizer/Tokenizer.spec.md +28 -28
- package/src/Tooltip/Tooltip.test.tsx +51 -6
- package/src/Tooltip/Tooltip.tsx +41 -18
- package/src/Tooltip/__tests__/Tooltip.a11y.chromium.spec.ts +129 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.renders.tsx +86 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.states.ts +132 -0
- package/src/Tooltip/__tests__/Tooltip.a11y.test.tsx +126 -0
- package/src/Tooltip/__tests__/TooltipHoverBridge.a11y.chromium.spec.ts +74 -0
- package/src/Tooltip/useTooltip.test.tsx +23 -0
- package/src/Tooltip/useTooltip.tsx +22 -9
- package/src/TopNav/TopNav.tsx +11 -1
- package/src/TopNav/TopNavHeading.tsx +1 -0
- package/src/TopNav/__tests__/TopNavMobileLongHeading.a11y.chromium.spec.ts +74 -0
- package/src/TreeList/TreeList.test.tsx +28 -0
- package/src/TreeList/TreeListItem.tsx +6 -2
- package/src/Typeahead/Typeahead.test.tsx +89 -0
- package/src/Typeahead/Typeahead.tsx +15 -2
- package/src/__tests__/DisabledTriggerFocus.a11y.chromium.spec.ts +86 -0
- package/src/hooks/useGridFocus.ts +16 -1
- package/src/hooks/useMenuPress.ts +45 -7
- package/src/utils/disabledInteraction.ts +40 -0
- package/src/utils/timeParser.test.ts +11 -0
- package/src/utils/timeParser.ts +9 -2
|
@@ -231,14 +231,38 @@ describe('TimeInput nativePicker', () => {
|
|
|
231
231
|
expect(input).not.toBeDisabled();
|
|
232
232
|
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
233
233
|
expect(input).toHaveAttribute('readonly');
|
|
234
|
+
// The shared native time segment's picker button is focusable-disabled
|
|
235
|
+
// (spec:AST-085 FR1) and still blocks opening.
|
|
234
236
|
expect(
|
|
235
237
|
screen.getByRole('button', {name: 'Open Start time'}),
|
|
236
|
-
).
|
|
238
|
+
).toHaveAttribute('aria-disabled', 'true');
|
|
237
239
|
const tooltip = document.querySelector<HTMLElement>('[role="tooltip"]');
|
|
238
240
|
expect(tooltip).not.toBeNull();
|
|
239
241
|
expect(input.getAttribute('aria-describedby')).toContain(tooltip?.id);
|
|
240
242
|
});
|
|
241
243
|
|
|
244
|
+
it('keeps a disabled native field focusable without native disabled (AST-085 FR1, FR2)', () => {
|
|
245
|
+
stubPointer(true);
|
|
246
|
+
const onClick = vi.fn();
|
|
247
|
+
render(
|
|
248
|
+
<TimeInput
|
|
249
|
+
label="Start time"
|
|
250
|
+
nativePicker="always"
|
|
251
|
+
isDisabled
|
|
252
|
+
onClick={onClick}
|
|
253
|
+
onChange={() => {}}
|
|
254
|
+
/>,
|
|
255
|
+
);
|
|
256
|
+
const input = getNativeTimeInput();
|
|
257
|
+
expect(input).not.toHaveAttribute('disabled');
|
|
258
|
+
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
259
|
+
expect(input).toHaveAttribute('readonly');
|
|
260
|
+
input.focus();
|
|
261
|
+
expect(input).toHaveFocus();
|
|
262
|
+
fireEvent.click(input);
|
|
263
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
264
|
+
});
|
|
265
|
+
|
|
242
266
|
it('forwards refs and autofocus to the native input', () => {
|
|
243
267
|
stubPointer(true);
|
|
244
268
|
const ref = vi.fn();
|
|
@@ -96,6 +96,29 @@ describe('TimeInput presentation', () => {
|
|
|
96
96
|
expect(screen.getByRole('listbox', {name: 'Minute'})).toBeInTheDocument();
|
|
97
97
|
});
|
|
98
98
|
|
|
99
|
+
it('bottom-sheet: a disabled field stays focusable and inert (AST-085 FR1, FR2)', () => {
|
|
100
|
+
stubPointer(false);
|
|
101
|
+
const onClick = vi.fn();
|
|
102
|
+
render(
|
|
103
|
+
<TimeInput
|
|
104
|
+
label="Start"
|
|
105
|
+
presentation="bottom-sheet"
|
|
106
|
+
isDisabled
|
|
107
|
+
onClick={onClick}
|
|
108
|
+
onChange={() => {}}
|
|
109
|
+
/>,
|
|
110
|
+
);
|
|
111
|
+
const input = screen.getByRole('combobox', {name: 'Start'});
|
|
112
|
+
expect(input).not.toHaveAttribute('disabled');
|
|
113
|
+
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
114
|
+
input.focus();
|
|
115
|
+
expect(input).toHaveFocus();
|
|
116
|
+
fireEvent.click(input);
|
|
117
|
+
expect(input).toHaveAttribute('aria-expanded', 'false');
|
|
118
|
+
expect(screen.queryByRole('listbox', {name: 'Hour'})).toBeNull();
|
|
119
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
120
|
+
});
|
|
121
|
+
|
|
99
122
|
it('adaptive-bottom-sheet: typed on fine, sheet on coarse', () => {
|
|
100
123
|
stubPointer(false);
|
|
101
124
|
const {unmount} = render(
|
|
@@ -71,7 +71,7 @@ export const docs = {
|
|
|
71
71
|
{
|
|
72
72
|
guidance: false,
|
|
73
73
|
description:
|
|
74
|
-
'Wrap a disabled TimeInput in Tooltip to explain why it is disabled
|
|
74
|
+
'Wrap a disabled TimeInput in Tooltip to explain why it is disabled. Use the disabledMessage prop instead, which ties the reason to the field.',
|
|
75
75
|
},
|
|
76
76
|
],
|
|
77
77
|
anatomy: [
|
|
@@ -144,14 +144,15 @@ export const docs = {
|
|
|
144
144
|
{
|
|
145
145
|
name: 'isDisabled',
|
|
146
146
|
type: 'boolean',
|
|
147
|
-
description:
|
|
147
|
+
description:
|
|
148
|
+
'Disables the input and suppresses interactions. The input stays focusable and exposes `aria-disabled`.',
|
|
148
149
|
default: 'false',
|
|
149
150
|
},
|
|
150
151
|
{
|
|
151
152
|
name: 'disabledMessage',
|
|
152
153
|
type: 'string',
|
|
153
154
|
description:
|
|
154
|
-
'Explains why the input is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and
|
|
155
|
+
'Explains why the input is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and describes the input (activation stays blocked). Use this instead of wrapping a disabled TimeInput in Tooltip.',
|
|
155
156
|
},
|
|
156
157
|
{
|
|
157
158
|
name: 'value',
|
|
@@ -212,7 +213,7 @@ export const docs = {
|
|
|
212
213
|
name: 'increment',
|
|
213
214
|
type: 'number',
|
|
214
215
|
description:
|
|
215
|
-
'Number of minutes to add or subtract when the user presses the up or down arrow key.',
|
|
216
|
+
'Number of minutes to add or subtract when the user presses the up or down arrow key. Steps are whole minutes; a fractional value leaves the time unchanged.',
|
|
216
217
|
default: '1',
|
|
217
218
|
},
|
|
218
219
|
{
|
|
@@ -329,14 +330,14 @@ export const docsZh = {
|
|
|
329
330
|
{
|
|
330
331
|
name: 'isDisabled',
|
|
331
332
|
type: 'boolean',
|
|
332
|
-
description: '
|
|
333
|
+
description: '禁用输入框并抑制交互。输入框仍可聚焦并暴露 `aria-disabled`。',
|
|
333
334
|
default: 'false',
|
|
334
335
|
},
|
|
335
336
|
{
|
|
336
337
|
name: 'disabledMessage',
|
|
337
338
|
type: 'string',
|
|
338
339
|
description:
|
|
339
|
-
'说明输入框为何被禁用。与 isDisabled
|
|
340
|
+
'说明输入框为何被禁用。与 isDisabled 一起使用时,在悬停/键盘聚焦时显示提示,并描述输入框(仍阻止输入和调整)。请使用此属性,而不是用 Tooltip 包裹已禁用的 TimeInput。',
|
|
340
341
|
},
|
|
341
342
|
{
|
|
342
343
|
name: 'value',
|
|
@@ -392,7 +393,8 @@ export const docsZh = {
|
|
|
392
393
|
{
|
|
393
394
|
name: 'increment',
|
|
394
395
|
type: 'number',
|
|
395
|
-
description:
|
|
396
|
+
description:
|
|
397
|
+
'用户按上或下方向键时增加或减少的分钟数。步长为整分钟;传入小数时时间保持不变。',
|
|
396
398
|
default: '1',
|
|
397
399
|
},
|
|
398
400
|
{
|
|
@@ -509,7 +511,7 @@ export const docsZh = {
|
|
|
509
511
|
{
|
|
510
512
|
guidance: false,
|
|
511
513
|
description:
|
|
512
|
-
'Wrap a disabled TimeInput in Tooltip to explain why it is disabled
|
|
514
|
+
'Wrap a disabled TimeInput in Tooltip to explain why it is disabled. Use the disabledMessage prop instead, which ties the reason to the field.',
|
|
513
515
|
},
|
|
514
516
|
],
|
|
515
517
|
anatomy: [
|
|
@@ -611,7 +613,7 @@ export const docsDense = {
|
|
|
611
613
|
'Marks required+sets aria-required. Mutually exclusive w/ isOptional.',
|
|
612
614
|
isDisabled: 'Disables input, suppresses interactions.',
|
|
613
615
|
disabledMessage:
|
|
614
|
-
'Reason shown in a tooltip on hover/focus when disabled;
|
|
616
|
+
'Reason shown in a tooltip on hover/focus when disabled; describes the input.',
|
|
615
617
|
value: 'Controlled time in ISO format (HH:MM or HH:MM:SS).',
|
|
616
618
|
onChange: 'Fired on time change. Receives undefined when cleared.',
|
|
617
619
|
changeAction:
|
|
@@ -623,7 +625,8 @@ export const docsDense = {
|
|
|
623
625
|
hasClear: 'Shows clear button when value set+not disabled.',
|
|
624
626
|
hourFormat:
|
|
625
627
|
"Display format. '12h' shows AM/PM; '24h' uses 24-hour notation.",
|
|
626
|
-
increment:
|
|
628
|
+
increment:
|
|
629
|
+
'Minutes to add/subtract on arrow up/down. Whole minutes only; a fractional value leaves the time unchanged.',
|
|
627
630
|
presentation:
|
|
628
631
|
"picker surface: 'adaptive-native' (default) = typed field fine / browser/OS coarse (hasSeconds or increment!=1 retains typed); 'native' = browser/OS always, no fallback; 'adaptive-bottom-sheet' = typed fine / Astryx wheel sheet coarse; 'bottom-sheet' = sheet always; 'text-input'/'popover' = typed field only.",
|
|
629
632
|
nativePicker:
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
|
|
13
|
-
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
13
|
+
import {act, render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
|
+
import * as stylex from '@stylexjs/stylex';
|
|
16
|
+
import {colorVars} from '../theme/tokens.stylex';
|
|
15
17
|
import {TimeInput} from './TimeInput';
|
|
16
18
|
import {InputGroup, InputGroupText} from '../InputGroup';
|
|
17
19
|
import {InternationalizationProvider} from '../i18n';
|
|
@@ -65,6 +67,26 @@ describe('TimeInput', () => {
|
|
|
65
67
|
expect(onChange).toHaveBeenCalledWith('14:31');
|
|
66
68
|
});
|
|
67
69
|
|
|
70
|
+
it('does not step into a fractional minute when increment is fractional', () => {
|
|
71
|
+
const onChange = vi.fn();
|
|
72
|
+
render(
|
|
73
|
+
<TimeInput
|
|
74
|
+
label="Time"
|
|
75
|
+
value={'14:30' as ISOTimeString}
|
|
76
|
+
increment={0.5}
|
|
77
|
+
onChange={onChange}
|
|
78
|
+
/>,
|
|
79
|
+
);
|
|
80
|
+
const input = screen.getByLabelText('Time');
|
|
81
|
+
|
|
82
|
+
// `increment` is documented as minutes and typed `number`. A fractional one
|
|
83
|
+
// used to reach formatISOTime unrounded, which pads "30.5" to two
|
|
84
|
+
// characters and leaves it, so the arrow key handed the consumer a value
|
|
85
|
+
// that is no longer a time at all.
|
|
86
|
+
fireEvent.keyDown(input, {key: 'ArrowUp'});
|
|
87
|
+
expect(onChange).toHaveBeenCalledWith('14:30');
|
|
88
|
+
});
|
|
89
|
+
|
|
68
90
|
it('displays formatted time in 12h format', () => {
|
|
69
91
|
render(
|
|
70
92
|
<TimeInput
|
|
@@ -121,9 +143,41 @@ describe('TimeInput', () => {
|
|
|
121
143
|
);
|
|
122
144
|
});
|
|
123
145
|
|
|
124
|
-
it('
|
|
146
|
+
it('keeps a disabled input focusable without native disabled (AST-085 FR1)', () => {
|
|
147
|
+
render(<TimeInput label="Time" isDisabled onChange={() => {}} />);
|
|
148
|
+
const input = screen.getByRole('textbox');
|
|
149
|
+
expect(input).not.toHaveAttribute('disabled');
|
|
150
|
+
expect(input).toHaveAttribute('aria-disabled', 'true');
|
|
151
|
+
expect(input).toHaveAttribute('readonly');
|
|
152
|
+
input.focus();
|
|
153
|
+
expect(input).toHaveFocus();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('restores the focus ring on a focused disabled field (AST-085 FR6)', () => {
|
|
157
|
+
// The same declarations as the field's ring style compile to the same
|
|
158
|
+
// atomic classes; the shared disabled style alone drops them.
|
|
159
|
+
const ringClasses = stylex
|
|
160
|
+
.props(
|
|
161
|
+
stylex.create({
|
|
162
|
+
ring: {
|
|
163
|
+
borderColor: {
|
|
164
|
+
default: colorVars['--color-border-emphasized'],
|
|
165
|
+
':focus-within': colorVars['--color-accent'],
|
|
166
|
+
},
|
|
167
|
+
boxShadow: {
|
|
168
|
+
default: 'none',
|
|
169
|
+
':focus-within': `inset 0px 0px 0px 2px ${colorVars['--color-accent-muted']}`,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
}).ring,
|
|
173
|
+
)
|
|
174
|
+
.className!.split(' ')
|
|
175
|
+
.filter(name => !name.includes('__'));
|
|
125
176
|
render(<TimeInput label="Time" isDisabled onChange={() => {}} />);
|
|
126
|
-
|
|
177
|
+
const wrapper = screen.getByRole('textbox').closest('.astryx-time-input')!;
|
|
178
|
+
for (const name of ringClasses) {
|
|
179
|
+
expect(wrapper).toHaveClass(name);
|
|
180
|
+
}
|
|
127
181
|
});
|
|
128
182
|
|
|
129
183
|
it('shows clear button when hasClear is true and value exists', () => {
|
|
@@ -625,11 +679,89 @@ describe('TimeInput', () => {
|
|
|
625
679
|
expect(onChange).not.toHaveBeenCalled();
|
|
626
680
|
});
|
|
627
681
|
|
|
628
|
-
it('
|
|
629
|
-
|
|
682
|
+
it('blocks typing, arrows and a caller onClick when disabled without a reason (AST-085 FR2)', async () => {
|
|
683
|
+
const user = userEvent.setup();
|
|
684
|
+
const onChange = vi.fn();
|
|
685
|
+
const onClick = vi.fn();
|
|
686
|
+
render(
|
|
687
|
+
<TimeInput
|
|
688
|
+
label="Time"
|
|
689
|
+
value={'09:00' as ISOTimeString}
|
|
690
|
+
onChange={onChange}
|
|
691
|
+
onClick={onClick}
|
|
692
|
+
isDisabled
|
|
693
|
+
/>,
|
|
694
|
+
);
|
|
695
|
+
const input = screen.getByLabelText('Time');
|
|
696
|
+
await user.click(input);
|
|
697
|
+
await user.type(input, '1');
|
|
698
|
+
await user.keyboard('{ArrowUp}');
|
|
699
|
+
await user.tab();
|
|
700
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
701
|
+
expect(onClick).not.toHaveBeenCalled();
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
it.each([
|
|
705
|
+
['text-input', false, {isDisabled: true}],
|
|
706
|
+
['native', true, {isDisabled: true}],
|
|
707
|
+
['bottom-sheet', true, {isDisabled: true}],
|
|
708
|
+
['bottom-sheet', true, {isLoading: true}],
|
|
709
|
+
] as const)(
|
|
710
|
+
'does not submit a surrounding form on Enter: %s (coarse %s) %o (AST-085 FR2)',
|
|
711
|
+
async (presentation, isCoarse, state) => {
|
|
712
|
+
vi.stubGlobal('matchMedia', (query: string) => ({
|
|
713
|
+
matches: /pointer:\s*coarse/.test(query)
|
|
714
|
+
? isCoarse
|
|
715
|
+
: /pointer:\s*fine/.test(query) && !isCoarse,
|
|
716
|
+
media: query,
|
|
717
|
+
addEventListener: () => {},
|
|
718
|
+
removeEventListener: () => {},
|
|
719
|
+
addListener: () => {},
|
|
720
|
+
removeListener: () => {},
|
|
721
|
+
}));
|
|
722
|
+
const user = userEvent.setup();
|
|
723
|
+
const onSubmit = vi.fn((e: React.FormEvent) => e.preventDefault());
|
|
724
|
+
render(
|
|
725
|
+
<form onSubmit={onSubmit}>
|
|
726
|
+
<TimeInput
|
|
727
|
+
label="Time"
|
|
728
|
+
presentation={presentation}
|
|
729
|
+
value={'09:00' as ISOTimeString}
|
|
730
|
+
onChange={() => {}}
|
|
731
|
+
{...state}
|
|
732
|
+
/>
|
|
733
|
+
<button type="submit">Save</button>
|
|
734
|
+
</form>,
|
|
735
|
+
);
|
|
736
|
+
try {
|
|
737
|
+
const input = document.querySelector<HTMLInputElement>(
|
|
738
|
+
'.astryx-time-input input:not([type=hidden])',
|
|
739
|
+
)!;
|
|
740
|
+
act(() => input.focus());
|
|
741
|
+
await user.keyboard('{Enter}');
|
|
742
|
+
expect(onSubmit).not.toHaveBeenCalled();
|
|
743
|
+
} finally {
|
|
744
|
+
vi.unstubAllGlobals();
|
|
745
|
+
}
|
|
746
|
+
},
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
it('drops a draft instead of committing it when the field becomes disabled (AST-085 FR2)', async () => {
|
|
750
|
+
const user = userEvent.setup();
|
|
751
|
+
const onChange = vi.fn();
|
|
752
|
+
const value = '09:00' as ISOTimeString;
|
|
753
|
+
const {rerender} = render(
|
|
754
|
+
<TimeInput label="Time" value={value} onChange={onChange} />,
|
|
755
|
+
);
|
|
630
756
|
const input = screen.getByLabelText('Time');
|
|
631
|
-
|
|
632
|
-
|
|
757
|
+
await user.click(input);
|
|
758
|
+
await user.clear(input);
|
|
759
|
+
onChange.mockClear();
|
|
760
|
+
rerender(
|
|
761
|
+
<TimeInput label="Time" value={value} onChange={onChange} isDisabled />,
|
|
762
|
+
);
|
|
763
|
+
await user.tab();
|
|
764
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
633
765
|
});
|
|
634
766
|
|
|
635
767
|
it('does not swap in the format-hint placeholder on focus while disabled', () => {
|
|
@@ -93,6 +93,18 @@ import {useDevWarning} from '../hooks/useDevWarning';
|
|
|
93
93
|
const TOUCH_POINTER_QUERY = '(pointer: coarse)';
|
|
94
94
|
|
|
95
95
|
const styles = stylex.create({
|
|
96
|
+
// The shared disabled style drops the focus ring; restore it while a
|
|
97
|
+
// control inside the field holds focus (spec:AST-085 FR6). Defaults repeat it.
|
|
98
|
+
disabledFocusRing: {
|
|
99
|
+
borderColor: {
|
|
100
|
+
default: colorVars['--color-border-emphasized'],
|
|
101
|
+
':focus-within': colorVars['--color-accent'],
|
|
102
|
+
},
|
|
103
|
+
boxShadow: {
|
|
104
|
+
default: 'none',
|
|
105
|
+
':focus-within': `inset 0px 0px 0px 2px ${colorVars['--color-accent-muted']}`,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
96
108
|
icon: {
|
|
97
109
|
display: 'flex',
|
|
98
110
|
alignItems: 'center',
|
|
@@ -207,12 +219,12 @@ export interface TimeInputProps extends Omit<
|
|
|
207
219
|
/**
|
|
208
220
|
* Explains why the input is disabled. When set together with
|
|
209
221
|
* `isDisabled`, the input shows a tooltip with this text on hover and
|
|
210
|
-
* keyboard focus, and the
|
|
211
|
-
*
|
|
212
|
-
*
|
|
222
|
+
* keyboard focus, and the input is described by it, so the reason is
|
|
223
|
+
* discoverable by keyboard and assistive technology. Typing and arrow-key
|
|
224
|
+
* adjustment stay blocked.
|
|
213
225
|
*
|
|
214
|
-
* Use this instead of wrapping a disabled input in `Tooltip
|
|
215
|
-
*
|
|
226
|
+
* Use this instead of wrapping a disabled input in `Tooltip`, so the
|
|
227
|
+
* reason is tied to the field.
|
|
216
228
|
*
|
|
217
229
|
* @example
|
|
218
230
|
* ```
|
|
@@ -286,7 +298,8 @@ export interface TimeInputProps extends Omit<
|
|
|
286
298
|
hourFormat?: TimeInputHourFormat;
|
|
287
299
|
|
|
288
300
|
/**
|
|
289
|
-
* Increment in minutes when using arrow keys.
|
|
301
|
+
* Increment in minutes when using arrow keys. Steps are whole minutes: a
|
|
302
|
+
* fractional value leaves the time unchanged.
|
|
290
303
|
* @default 1
|
|
291
304
|
*/
|
|
292
305
|
increment?: number;
|
|
@@ -478,10 +491,10 @@ function TimeField({
|
|
|
478
491
|
}
|
|
479
492
|
}, [announce, inputGroup, status?.message, status?.type]);
|
|
480
493
|
|
|
481
|
-
//
|
|
482
|
-
//
|
|
483
|
-
//
|
|
484
|
-
//
|
|
494
|
+
// A disabled field never renders native `disabled` (spec:AST-085 FR1): the
|
|
495
|
+
// input stays focusable via aria-disabled, and readOnly plus the value
|
|
496
|
+
// mutation guards block typing. The disabled-reason tooltip's listeners
|
|
497
|
+
// attach to the input container.
|
|
485
498
|
const showsDisabledMessage = isDisabled && !!disabledMessage;
|
|
486
499
|
const disabledMessageTooltip = useTooltip({
|
|
487
500
|
placement: 'above',
|
|
@@ -576,8 +589,8 @@ function TimeField({
|
|
|
576
589
|
// Handle input text change - update immediately if valid
|
|
577
590
|
const handleInputChange = useCallback(
|
|
578
591
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
579
|
-
//
|
|
580
|
-
//
|
|
592
|
+
// The input is never natively disabled (spec:AST-085 FR1), so guard
|
|
593
|
+
// value mutation explicitly (readOnly also blocks typing).
|
|
581
594
|
if (isDisabled) {
|
|
582
595
|
return;
|
|
583
596
|
}
|
|
@@ -612,6 +625,11 @@ function TimeField({
|
|
|
612
625
|
if (pendingInput === null) {
|
|
613
626
|
return;
|
|
614
627
|
}
|
|
628
|
+
// Disabled: keep the value, drop the draft (spec:AST-085 FR2).
|
|
629
|
+
if (isDisabled) {
|
|
630
|
+
setPendingInput(null);
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
615
633
|
|
|
616
634
|
if (!pendingInput.trim()) {
|
|
617
635
|
// Empty input clears the value
|
|
@@ -632,10 +650,17 @@ function TimeField({
|
|
|
632
650
|
// Clear pending input - display will revert to formatted value
|
|
633
651
|
setPendingInput(null);
|
|
634
652
|
},
|
|
635
|
-
[pendingInput, value, fireChange, hasSeconds, min, max],
|
|
653
|
+
[pendingInput, isDisabled, value, fireChange, hasSeconds, min, max],
|
|
636
654
|
);
|
|
637
655
|
|
|
638
656
|
// Handle keyboard navigation on input
|
|
657
|
+
// Enter in a focused disabled field would submit a surrounding form (FR2).
|
|
658
|
+
const preventDisabledEnter = (e: KeyboardEvent<HTMLInputElement>) => {
|
|
659
|
+
if (isDisabled && e.key === 'Enter') {
|
|
660
|
+
e.preventDefault();
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
|
|
639
664
|
const handleInputKeyDown = useCallback(
|
|
640
665
|
(e: KeyboardEvent<HTMLInputElement>) => {
|
|
641
666
|
// ArrowUp/ArrowDown step the time and preventDefault; an IME candidate
|
|
@@ -645,8 +670,7 @@ function TimeField({
|
|
|
645
670
|
if (isImeKeyEvent(e.nativeEvent)) {
|
|
646
671
|
return;
|
|
647
672
|
}
|
|
648
|
-
// Arrow-key adjustment mutates the value; block it while
|
|
649
|
-
// disabled reason (the input keeps focusability via aria-disabled).
|
|
673
|
+
// Arrow-key adjustment mutates the value; block it while disabled.
|
|
650
674
|
if (isDisabled) {
|
|
651
675
|
return;
|
|
652
676
|
}
|
|
@@ -743,6 +767,7 @@ function TimeField({
|
|
|
743
767
|
inputWrapperStyles.base,
|
|
744
768
|
sizeStyles[size],
|
|
745
769
|
isDisabled && inputWrapperStyles.disabled,
|
|
770
|
+
isDisabled && styles.disabledFocusRing,
|
|
746
771
|
status && inputStatusBorderStyles[status.type],
|
|
747
772
|
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
748
773
|
status && inputStatusFocusWithinStyles[status.type],
|
|
@@ -777,7 +802,7 @@ function TimeField({
|
|
|
777
802
|
max={max}
|
|
778
803
|
hourFormat={hourFormat}
|
|
779
804
|
isEffectivelyDisabled={isDisabled}
|
|
780
|
-
|
|
805
|
+
isFocusableDisabled
|
|
781
806
|
isEffectivelyRequired={isEffectivelyRequired}
|
|
782
807
|
isBusy={isBusy}
|
|
783
808
|
statusType={status?.type}
|
|
@@ -786,7 +811,8 @@ function TimeField({
|
|
|
786
811
|
...controlProps,
|
|
787
812
|
onFocus: onFocusProp,
|
|
788
813
|
onBlur: onBlurProp,
|
|
789
|
-
onKeyDown: onKeyDownProp,
|
|
814
|
+
onKeyDown: chainEventHandlers(preventDisabledEnter, onKeyDownProp),
|
|
815
|
+
onClick: isDisabled ? undefined : controlProps.onClick,
|
|
790
816
|
}}
|
|
791
817
|
/>
|
|
792
818
|
) : (
|
|
@@ -803,14 +829,17 @@ function TimeField({
|
|
|
803
829
|
onChange={handleInputChange}
|
|
804
830
|
onFocus={chainEventHandlers(handleFocus, onFocusProp)}
|
|
805
831
|
onBlur={chainEventHandlers(handleBlur, onBlurProp)}
|
|
806
|
-
onKeyDown={chainEventHandlers(
|
|
832
|
+
onKeyDown={chainEventHandlers(
|
|
833
|
+
preventDisabledEnter,
|
|
834
|
+
handleInputKeyDown,
|
|
835
|
+
onKeyDownProp,
|
|
836
|
+
)}
|
|
807
837
|
placeholder={displayPlaceholder}
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
//
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
readOnly={showsDisabledMessage || undefined}
|
|
838
|
+
aria-disabled={isDisabled ? 'true' : undefined}
|
|
839
|
+
readOnly={isDisabled || undefined}
|
|
840
|
+
// The browser still dispatches a click on an aria-disabled input,
|
|
841
|
+
// so a caller's onClick is skipped too (spec:AST-085 FR2).
|
|
842
|
+
onClick={isDisabled ? undefined : controlProps.onClick}
|
|
814
843
|
autoFocus={hasAutoFocus}
|
|
815
844
|
data-autofocus={hasAutoFocus || undefined}
|
|
816
845
|
aria-describedby={ariaDescribedBy}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
useRef,
|
|
25
25
|
useState,
|
|
26
26
|
useTransition,
|
|
27
|
+
type KeyboardEvent,
|
|
27
28
|
} from 'react';
|
|
28
29
|
import * as stylex from '@stylexjs/stylex';
|
|
29
30
|
import {BottomSheet} from '../BottomSheet';
|
|
@@ -45,7 +46,7 @@ import {useMergedRefs} from '../hooks/useMergedRefs';
|
|
|
45
46
|
import {useResolvedRequired} from '../hooks/useResolvedRequired';
|
|
46
47
|
import {Icon} from '../Icon';
|
|
47
48
|
import {useTranslator} from '../i18n';
|
|
48
|
-
import {sizeVars, spacingVars} from '../theme/tokens.stylex';
|
|
49
|
+
import {colorVars, sizeVars, spacingVars} from '../theme/tokens.stylex';
|
|
49
50
|
import {useSize} from '../SizeContext/SizeContext';
|
|
50
51
|
import {Spinner} from '../Spinner';
|
|
51
52
|
import {useTooltip} from '../Tooltip';
|
|
@@ -74,6 +75,17 @@ const sizeStyles = stylex.create({
|
|
|
74
75
|
});
|
|
75
76
|
|
|
76
77
|
const styles = stylex.create({
|
|
78
|
+
// Same as TimeInput's: the focus ring for a focused disabled field.
|
|
79
|
+
disabledFocusRing: {
|
|
80
|
+
borderColor: {
|
|
81
|
+
default: colorVars['--color-border-emphasized'],
|
|
82
|
+
':focus-within': colorVars['--color-accent'],
|
|
83
|
+
},
|
|
84
|
+
boxShadow: {
|
|
85
|
+
default: 'none',
|
|
86
|
+
':focus-within': `inset 0px 0px 0px 2px ${colorVars['--color-accent-muted']}`,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
77
89
|
iconButton: {
|
|
78
90
|
display: 'flex',
|
|
79
91
|
alignItems: 'center',
|
|
@@ -447,6 +459,7 @@ export function TouchTimeField({
|
|
|
447
459
|
inputWrapperStyles.base,
|
|
448
460
|
sizeStyles[size],
|
|
449
461
|
isDisabled && inputWrapperStyles.disabled,
|
|
462
|
+
isDisabled && styles.disabledFocusRing,
|
|
450
463
|
status && inputStatusBorderStyles[status.type],
|
|
451
464
|
status && !isDisabled && inputStatusHoverShadowStyles[status.type],
|
|
452
465
|
status && inputStatusFocusWithinStyles[status.type],
|
|
@@ -459,7 +472,7 @@ export function TouchTimeField({
|
|
|
459
472
|
<button
|
|
460
473
|
type="button"
|
|
461
474
|
onClick={openSheet}
|
|
462
|
-
disabled={isEffectivelyDisabled}
|
|
475
|
+
aria-disabled={isEffectivelyDisabled || undefined}
|
|
463
476
|
aria-label={t('@astryx.timeInput.openPicker', {label})}
|
|
464
477
|
tabIndex={-1}
|
|
465
478
|
{...stylex.props(focusOutlineStyles.focusVisible, styles.iconButton)}>
|
|
@@ -475,10 +488,19 @@ export function TouchTimeField({
|
|
|
475
488
|
readOnly
|
|
476
489
|
inputMode="none"
|
|
477
490
|
onChange={() => {}}
|
|
478
|
-
onClick={
|
|
491
|
+
onClick={
|
|
492
|
+
isEffectivelyDisabled
|
|
493
|
+
? undefined
|
|
494
|
+
: chainEventHandlers(openSheet, onClickProp)
|
|
495
|
+
}
|
|
496
|
+
// Enter would submit a surrounding form while disabled (FR2).
|
|
497
|
+
onKeyDown={chainEventHandlers((e: KeyboardEvent<HTMLInputElement>) => {
|
|
498
|
+
if (isEffectivelyDisabled && e.key === 'Enter') {
|
|
499
|
+
e.preventDefault();
|
|
500
|
+
}
|
|
501
|
+
}, controlProps.onKeyDown)}
|
|
479
502
|
placeholder={placeholder}
|
|
480
|
-
disabled={isEffectivelyDisabled
|
|
481
|
-
aria-disabled={showsDisabledMessage ? 'true' : undefined}
|
|
503
|
+
aria-disabled={isEffectivelyDisabled ? 'true' : undefined}
|
|
482
504
|
aria-describedby={ariaDescribedBy}
|
|
483
505
|
aria-required={isEffectivelyRequired ? 'true' : undefined}
|
|
484
506
|
aria-invalid={status?.type === 'error' ? 'true' : undefined}
|
|
@@ -28,7 +28,7 @@ export const docs = {
|
|
|
28
28
|
name: 'format',
|
|
29
29
|
type: "'relative' | 'relative_short' | 'auto' | 'date' | 'date_long' | 'date_weekday' | 'date_time' | 'time' | 'system_date' | 'system_date_time' | 'system_time' | 'unix_seconds'",
|
|
30
30
|
description:
|
|
31
|
-
"Display format. 'relative' uses the locale's native long relative-time wording ('2 hours ago' in English), 'relative_short' uses its narrow pattern ('2h ago' in English) for compact surfaces, 'date' shows 'Mar 21, 2025', 'date_long' shows 'March 21, 2025', 'date_weekday' shows 'Wed, Mar 21, 2025', 'date_time' shows 'Mar 21, 2025, 2:51 PM', 'time' shows '2:51 PM', 'system_*' variants use ISO-style formatting, 'unix_seconds' shows the Unix time in whole seconds since the epoch (an absolute, zone-independent value), 'auto' switches from relative to date_time based on recency.",
|
|
31
|
+
"Display format. 'relative' uses the locale's native long relative-time wording ('2 hours ago' in English), 'relative_short' uses its narrow pattern ('2h ago' in English) for compact surfaces, 'date' shows 'Mar 21, 2025', 'date_long' shows 'March 21, 2025', 'date_weekday' shows 'Wed, Mar 21, 2025', 'date_time' shows 'Mar 21, 2025, 2:51 PM', 'time' shows '2:51 PM', 'system_*' variants use ISO-style formatting, 'unix_seconds' shows the Unix time in whole seconds since the epoch (an absolute, zone-independent value), 'auto' switches from relative to date_time based on recency. Absolute formats never read the current time. 'relative', 'relative_short' and 'auto' read it on the client only: a server render or static prerender shows the full date and time in UTC, labelled, and the client switches to the format's normal output after hydration.",
|
|
32
32
|
default: "'auto'",
|
|
33
33
|
},
|
|
34
34
|
{
|