@astryxdesign/core 0.7.4-canary.f32572e → 0.7.4

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  3. package/dist/Chat/ChatMessageList.js +8 -1
  4. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  5. package/dist/CheckboxInput/CheckboxInput.js +6 -0
  6. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  7. package/dist/CommandPalette/CommandPalette.js +6 -11
  8. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  9. package/dist/CommandPalette/CommandPaletteInput.js +7 -1
  10. package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -0
  11. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  12. package/dist/CommandPalette/CommandPaletteItem.js +5 -1
  13. package/dist/DateInput/DateInput.d.ts +6 -4
  14. package/dist/DateInput/DateInput.d.ts.map +1 -1
  15. package/dist/DateInput/DateInput.js +5 -1
  16. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  17. package/dist/DateInput/NativeDateField.js +5 -1
  18. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  19. package/dist/DateInput/TouchDateField.js +5 -1
  20. package/dist/DateInput/tokens.stylex.d.ts.map +1 -1
  21. package/dist/DateInput/tokens.stylex.js +3 -1
  22. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  23. package/dist/DropdownMenu/DropdownMenuSubMenu.js +7 -1
  24. package/dist/FileInput/FileInput.d.ts.map +1 -1
  25. package/dist/FileInput/FileInput.js +16 -2
  26. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  27. package/dist/Thumbnail/Thumbnail.js +9 -2
  28. package/package.json +4 -4
  29. package/src/BottomSheet/BottomSheet.spec.md +1 -0
  30. package/src/BottomSheet/BottomSheetEdgeTint.test.tsx +25 -2
  31. package/src/BottomSheet/BottomSheetSwitcher.spec.md +7 -6
  32. package/src/BottomSheet/BottomSheetSwitcher.test.tsx +221 -1
  33. package/src/BottomSheet/__tests__/BottomSheetNativeModal.a11y.browser.spec.ts +461 -0
  34. package/src/Chat/ChatMessageList.test.tsx +6 -2
  35. package/src/Chat/ChatMessageList.tsx +7 -1
  36. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +20 -12
  37. package/src/CheckboxInput/CheckboxInput.tsx +6 -0
  38. package/src/CommandPalette/CommandPalette.doc.mjs +4 -1
  39. package/src/CommandPalette/CommandPalette.test.tsx +4 -2
  40. package/src/CommandPalette/CommandPalette.tsx +6 -11
  41. package/src/CommandPalette/CommandPaletteInput.test.tsx +3 -1
  42. package/src/CommandPalette/CommandPaletteInput.tsx +10 -1
  43. package/src/CommandPalette/CommandPaletteItem.doc.mjs +17 -5
  44. package/src/CommandPalette/CommandPaletteItem.test.tsx +65 -12
  45. package/src/CommandPalette/CommandPaletteItem.tsx +6 -1
  46. package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +250 -20
  47. package/src/DateInput/DateInput.doc.mjs +23 -5
  48. package/src/DateInput/DateInput.spec.md +52 -45
  49. package/src/DateInput/DateInput.tsx +13 -7
  50. package/src/DateInput/NativeDateField.tsx +6 -2
  51. package/src/DateInput/TouchDateField.tsx +6 -2
  52. package/src/DateInput/__tests__/DateInputAudit.a11y.chromium.spec.ts +576 -0
  53. package/src/DateInput/tokens.stylex.ts +3 -1
  54. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +10 -1
  55. package/src/FileInput/FileInput.tsx +18 -2
  56. package/src/Overlay/Overlay.spec.md +304 -0
  57. package/src/Thumbnail/Thumbnail.test.tsx +6 -1
  58. package/src/Thumbnail/Thumbnail.tsx +12 -3
  59. package/src/__tests__/BusyOwnerAnnouncement.test.tsx +324 -2
@@ -79,7 +79,7 @@ export const docs = {
79
79
  name: 'isLoading',
80
80
  type: 'boolean',
81
81
  description:
82
- 'Whether the input is in a loading state. Disables interaction and shows a spinner.',
82
+ 'Whether the input is in a loading state. The field stays focusable and exposes `aria-busy` with a spinner; typing, picking, and clearing are blocked until loading ends.',
83
83
  default: 'false',
84
84
  },
85
85
  {
@@ -253,6 +253,11 @@ export const docs = {
253
253
  description:
254
254
  'Show a loading state with changeAction when the date triggers a server-side save.',
255
255
  },
256
+ {
257
+ guidance: true,
258
+ description:
259
+ 'On a fine pointer the field follows the WAI-ARIA combobox pattern with a dialog popup, as in the APG date picker combobox: ArrowDown or Alt+ArrowDown opens the calendar, and Escape closes it and returns focus to the field.',
260
+ },
256
261
  {
257
262
  guidance: true,
258
263
  description:
@@ -301,7 +306,7 @@ export const docs = {
301
306
  name: 'Calendar popover',
302
307
  required: false,
303
308
  description:
304
- 'A month grid that appears when the icon is clicked or the input is focused.',
309
+ 'A month grid that appears when the icon or the input is clicked, or when ArrowDown is pressed in the input.',
305
310
  },
306
311
  {
307
312
  name: 'Clear button',
@@ -351,6 +356,11 @@ export const docsZh = {
351
356
  description:
352
357
  'Show a loading state with changeAction when the date triggers a server-side save.',
353
358
  },
359
+ {
360
+ guidance: true,
361
+ description:
362
+ 'On a fine pointer the field follows the WAI-ARIA combobox pattern with a dialog popup, as in the APG date picker combobox: ArrowDown or Alt+ArrowDown opens the calendar, and Escape closes it and returns focus to the field.',
363
+ },
354
364
  {
355
365
  guidance: false,
356
366
  description:
@@ -401,7 +411,8 @@ export const docsZh = {
401
411
  {
402
412
  name: 'isDisabled',
403
413
  type: 'boolean',
404
- description: '禁用输入框和日历。输入框仍可聚焦并暴露 `aria-disabled`,但不能输入或打开日历。',
414
+ description:
415
+ '禁用输入框和日历。输入框仍可聚焦并暴露 `aria-disabled`,但不能输入或打开日历。',
405
416
  default: 'false',
406
417
  },
407
418
  {
@@ -429,7 +440,8 @@ export const docsZh = {
429
440
  {
430
441
  name: 'isLoading',
431
442
  type: 'boolean',
432
- description: '输入框是否处于加载状态。禁用交互并显示加载指示器。',
443
+ description:
444
+ '输入框是否处于加载状态。字段仍可聚焦,并通过 `aria-busy` 和加载指示器表示忙碌;加载结束前不能输入、选择或清除日期。',
433
445
  default: 'false',
434
446
  },
435
447
  {
@@ -599,6 +611,11 @@ export const docsDense = {
599
611
  description:
600
612
  'Show a loading state with changeAction when the date triggers a server-side save.',
601
613
  },
614
+ {
615
+ guidance: true,
616
+ description:
617
+ 'On a fine pointer the field follows the WAI-ARIA combobox pattern with a dialog popup, as in the APG date picker combobox: ArrowDown or Alt+ArrowDown opens the calendar, and Escape closes it and returns focus to the field.',
618
+ },
602
619
  {
603
620
  guidance: true,
604
621
  description:
@@ -638,7 +655,8 @@ export const docsDense = {
638
655
  value: 'selected date YYYY-MM-DD',
639
656
  onChange: 'callback on date change',
640
657
  changeAction: 'async action after onChange; drives optimistic UI',
641
- isLoading: 'loading state; disables interaction, shows spinner',
658
+ isLoading:
659
+ 'loading state; stays focusable w/ aria-busy + spinner; blocks typing, picking, clearing',
642
660
  min: 'min selectable date (YYYY-MM-DD)',
643
661
  max: 'max selectable date (YYYY-MM-DD)',
644
662
  dateConstraints: 'custom constraint fns to disable specific dates',
@@ -17,6 +17,7 @@ verified_by:
17
17
  packages/core/src/DateInput/DateInputTouch.test.tsx,
18
18
  packages/core/src/DateInput/NativeDateField.test.tsx,
19
19
  packages/core/src/DateInput/Presentation.test.tsx,
20
+ packages/core/src/__tests__/BusyOwnerAnnouncement.test.tsx,
20
21
  packages/core/src/theme/themingTargets.test.ts,
21
22
  scripts/check-knowledge.mjs,
22
23
  ]
@@ -30,26 +31,25 @@ architecture:
30
31
  architecture:public-component-api,
31
32
  ]
32
33
  contributing: []
33
- system_specs: [spec:AST-043]
34
+ system_specs: [spec:AST-043, spec:AST-085, spec:AST-086]
34
35
  ---
35
36
 
36
37
  # DateInput component contract
37
38
 
38
- This draft records shipped behavior plus one objective conformance fix already settled
39
- by `family:input-fields/FR6`. It does not approve a new public API, default,
39
+ This draft records shipped behavior. It does not approve a new public API, default,
40
40
  compatibility promise, ownership boundary, or visual direction.
41
41
 
42
42
  ## Contract at a glance
43
43
 
44
- | Area | Contract |
45
- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
46
- | Public contract | API shape and defaults remain unchanged. The native-picker surface now follows the existing `changeAction` order, optimistic-value, and busy-feedback contract. |
47
- | Behavior | `presentation` selects the picker surface; an omitted value remains `adaptive-native`; `presentation` wins over deprecated `nativePicker`; every committed path emits the same controlled ISO-date value and action feedback. |
48
- | End-user impact | People can type or pick one date using a surface suited to the primary pointer; native-picker saves now run instead of being silently dropped. |
49
- | Builder impact | Existing native DateInput `changeAction` handlers now run after `onChange` and receive optimistic busy feedback. No API or migration work is required. |
50
- | Compatibility/readiness | Compatible patch correction under the current input-field family rule. Released defaults and controlled ownership are preserved; exact-head browser evidence remains audit evidence rather than product authority. |
51
- | Review checks | Reject a surface-mapping change, lost constraint, callback-order change, unlabeled field, unreachable disabled reason, changed close behavior, or a theming target placed on the wrong owner. |
52
- | Governing rules | `spec:AST-043/FR1–FR5`; `family:input-fields/FR1–FR6, FR8–FR10`; `family:overlay-dismissal/FR1–FR7`, including its recorded BottomSheet adoption gap; the three architecture records linked above. |
44
+ | Area | Contract |
45
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
46
+ | Public contract | None. API shape and defaults are as shipped; every surface follows the input-field `changeAction`, disabled, and busy contracts. |
47
+ | Behavior | `presentation` selects the picker surface; an omitted value is `adaptive-native`; `presentation` wins over deprecated `nativePicker`; every committed path emits the same controlled ISO-date value and action feedback. |
48
+ | End-user impact | People type or pick one date using a surface suited to the primary pointer. Disabled and busy fields stay focusable; a busy field keeps its ordinary paint with a Spinner while new commits are blocked. |
49
+ | Builder impact | None. `changeAction` runs after `onChange` with optimistic busy feedback on every surface. |
50
+ | Compatibility/readiness | Draft observational record of shipped behavior. Released defaults and controlled ownership are preserved; browser evidence remains audit evidence rather than product authority. |
51
+ | Review checks | Reject a surface-mapping change, lost constraint, callback-order change, unlabeled field, native `disabled`, disabled paint on a busy-only field, unreachable disabled reason, changed close behavior, or a theming target placed on the wrong owner. |
52
+ | Governing rules | `spec:AST-043/FR1–FR5`; `spec:AST-085/FR1–FR6`; `spec:AST-086/FR3, FR4, FR6, FR8`; `family:input-fields/FR1–FR6, FR8–FR11`; `family:overlay-dismissal/FR1–FR7`, including its recorded BottomSheet adoption gap; the three architecture records linked above. |
53
53
 
54
54
  This table is a review projection; the body below is authoritative only after this
55
55
  record becomes `current`.
@@ -63,8 +63,8 @@ browser/OS date picker selected by the public presentation contract.
63
63
  ## Compatibility and migration
64
64
 
65
65
  - Released default preserved: `yes`
66
- - Compatibility class: compatible patch; no API shape or default changes, and the native
67
- surface now adopts the existing `changeAction` contract instead of dropping it
66
+ - Compatibility class: no API shape or default changes; every surface follows the
67
+ input-field `changeAction`, disabled, and busy contracts
68
68
  - Controlled/uncontrolled behavior: unchanged; DateInput remains controlled by
69
69
  `value`, with `undefined` representing no selected date
70
70
  - Migration decision: `spec:AST-043/DEC-1` and `spec:AST-043/DEC-2` own the
@@ -121,20 +121,20 @@ Consumer migration instructions belong in consumer docs and release notes.
121
121
  Draft requirements identify their evidence basis; they do not turn observation into
122
122
  approved policy.
123
123
 
124
- | ID | Candidate invariant | Basis | Draft review state |
125
- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- | ----------------------------------------- |
126
- | FR1 | DateInput MUST present the controlled ISO `value` and emit `onChange` with the next ISO date or `undefined` without maintaining a competing committed value. | Current source, docs, and focused tests | Verified shipped behavior |
127
- | FR2 | The five `presentation` values MUST resolve to the fine/coarse surfaces in `spec:AST-043/FR1`; omitting both presentation props MUST preserve `adaptive-native`. | `spec:AST-043/FR1–FR3`; Presentation tests | Settled by current system authority |
128
- | FR3 | Explicit `presentation` MUST outrank deprecated `nativePicker`; the legacy values MUST retain their mappings and development-only warning from `spec:AST-043/FR3–FR4`. | Current source, docs, and Presentation tests | Settled by current system authority |
129
- | FR4 | Adaptive resolution MUST use the primary pointer rather than viewport width or any-pointer availability, so tablets receive a touch surface and touchscreen laptops retain the typable field. | Current source, consumer docs, and surface-selection tests | Verified shipped behavior |
130
- | FR5 | Text, Calendar, bottom-sheet, and native commit paths MUST enforce `min`, `max`, and `dateConstraints`; a rejected value MUST NOT replace the controlled value. | Current source and all four focused suites | Verified shipped behavior |
131
- | FR6 | Named committed formats MUST follow the InternationalizationProvider locale and shared Timestamp vocabulary; formatting MUST NOT rewrite in-progress typed text. | Current source, docs, locale tests, `spec:AST-043/FR5` | Verified shipped behavior |
132
- | FR7 | Every value-change path MUST call `onChange` before `changeAction`, present the proposed value optimistically, and expose one busy state while the Action is pending. | `family:input-fields/FR6`; current source and focused tests | Settled shared rule and verified adoption |
133
- | FR8 | The pointer field MUST open its Calendar from the input, calendar toggle, ArrowDown, or Alt+ArrowDown; Popover dismissal and focus return MUST remain owned by the shared Popover path. | Current source, Popover composition, keyboard/focus tests | Verified shipped behavior |
134
- | FR9 | A pointer-surface Calendar selection MUST commit and close its Popover; a bottom-sheet Calendar selection MUST remain editable in the open sheet until Save closes the surface. | Current source and pointer/touch tests | Verified shipped behavior |
135
- | FR10 | Standalone mode MUST compose Field; admitted InputGroup mode MUST remove competing Field chrome while preserving name, description, value, keyboard, focus, and editing semantics. | `family:input-fields/FR3`; current source and InputGroup tests | Settled shared rule and verified adoption |
136
- | FR11 | Clear MUST emit `undefined` through the ordinary change pipeline. The pointer and bottom-sheet surfaces restore field focus using their shipped timing; the native surface MUST NOT reclaim focus because doing so reopens the OS picker. | Current source and focused clear tests | Verified shipped behavior |
137
- | FR12 | Disabled-with-reason MUST remain focusable enough to expose its explanation while blocking mutation. Ordinary disabled and explicit-loading states remain inactive. During a pending Action, pointer and bottom-sheet surfaces remain inactive; the native surface stays focusable so the OS picker remains attached but rejects additional commits until the Action settles. | `family:input-fields/FR4–FR6`; current source and focused tests | Settled shared rule and verified adoption |
124
+ | ID | Candidate invariant | Basis | Draft review state |
125
+ | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------- |
126
+ | FR1 | DateInput MUST present the controlled ISO `value` and emit `onChange` with the next ISO date or `undefined` without maintaining a competing committed value. | Current source, docs, and focused tests | Verified shipped behavior |
127
+ | FR2 | The five `presentation` values MUST resolve to the fine/coarse surfaces in `spec:AST-043/FR1`; omitting both presentation props MUST preserve `adaptive-native`. | `spec:AST-043/FR1–FR3`; Presentation tests | Settled by current system authority |
128
+ | FR3 | Explicit `presentation` MUST outrank deprecated `nativePicker`; the legacy values MUST retain their mappings and development-only warning from `spec:AST-043/FR3–FR4`. | Current source, docs, and Presentation tests | Settled by current system authority |
129
+ | FR4 | Adaptive resolution MUST use the primary pointer rather than viewport width or any-pointer availability, so tablets receive a touch surface and touchscreen laptops retain the typable field. | Current source, consumer docs, and surface-selection tests | Verified shipped behavior |
130
+ | FR5 | Text, Calendar, bottom-sheet, and native commit paths MUST enforce `min`, `max`, and `dateConstraints`; a rejected value MUST NOT replace the controlled value. | Current source and all four focused suites | Verified shipped behavior |
131
+ | FR6 | Named committed formats MUST follow the InternationalizationProvider locale and shared Timestamp vocabulary; formatting MUST NOT rewrite in-progress typed text. | Current source, docs, locale tests, `spec:AST-043/FR5` | Verified shipped behavior |
132
+ | FR7 | Every value-change path MUST call `onChange` before `changeAction`, present the proposed value optimistically, and expose one busy state while the Action is pending. | `family:input-fields/FR6`; current source and focused tests | Settled shared rule and verified adoption |
133
+ | FR8 | The pointer field MUST open its Calendar from the input, calendar toggle, ArrowDown, or Alt+ArrowDown; Popover dismissal and focus return MUST remain owned by the shared Popover path. | Current source, Popover composition, keyboard/focus tests | Verified shipped behavior |
134
+ | FR9 | A pointer-surface Calendar selection MUST commit and close its Popover; a bottom-sheet Calendar selection MUST remain editable in the open sheet until Save closes the surface. | Current source and pointer/touch tests | Verified shipped behavior |
135
+ | FR10 | Standalone mode MUST compose Field; admitted InputGroup mode MUST remove competing Field chrome while preserving name, description, value, keyboard, focus, and editing semantics. | `family:input-fields/FR3`; current source and InputGroup tests | Settled shared rule and verified adoption |
136
+ | FR11 | Clear MUST emit `undefined` through the ordinary change pipeline. The pointer and bottom-sheet surfaces restore field focus using their shipped timing; the native surface MUST NOT reclaim focus because doing so reopens the OS picker. Implementation gap: when the field becomes disabled or busy while its clear control holds focus, the control unmounts and focus falls to the document body; `spec:AST-085/FR4` requires focus to stay or move to a destination this record names. | Current source and focused clear tests; `spec:AST-085/FR4` | Verified shipped behavior |
137
+ | FR12 | No surface renders native `disabled`. A disabled field MUST stay focusable with `aria-disabled`, block typing, picking, clearing, and opening, describe its disabled reason when one is given, and take disabled paint. While busy (`isLoading` or a pending Action) the pointer and bottom-sheet surfaces expose `aria-disabled` and `aria-busy`, stay focusable, and block new commits; the native surface does the same for `isLoading`, and during a pending Action stays editable so the OS picker remains attached but rejects additional commits until the Action settles. A busy field that is not disabled keeps its ordinary paint and Spinner, shows no hover ring while commits are blocked, and keeps its keyboard focus ring. | `spec:AST-085/FR1–FR6`; `family:input-fields/FR4–FR6`; `family:buttons/FR4`; current source and focused tests | Settled shared rule and verified adoption |
138
138
 
139
139
  ### Allowed variation
140
140
 
@@ -152,21 +152,21 @@ approved policy.
152
152
 
153
153
  ### Representative states
154
154
 
155
- | State | Required invariant | Allowed variation |
156
- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
157
- | empty rest | Labelled field shows the placeholder and calendar affordance without a committed value. | Label, placeholder, size, width |
158
- | committed rest | Field displays the controlled value in the selected committed format. | Format and locale |
159
- | typing | Raw typed text remains visible until commit or reversion. | Parseable text form and locale |
160
- | invalid typed text | Field reflects invalid state, announces the error, and preserves the prior committed value. | Invalid text |
161
- | constrained date | Unreachable dates cannot commit on any surface. | Bound or predicate source |
162
- | popover open | Input reflects expanded dialog state and the Calendar is reachable by pointer and keyboard. | Month count and week start |
163
- | bottom sheet open | Touch calendar remains open across date corrections until Save. | Visible month and wheel state |
164
- | native open/closed | Real date input retains its labelled controlled value while the browser/OS owns picker chrome. | Engine-provided picker |
165
- | disabled | Mutation and activation are blocked. | With or without a reason |
166
- | busy | `aria-busy` and one Spinner expose the save. New commits are blocked; the native picker stays focusable and may move its transient OS highlight without emitting another change. | Explicit loading or pending Action |
167
- | clearable | A committed value has one labelled clear action that emits `undefined`. | Surface and value |
168
- | status | Error, warning, or success remains named and uses shared status presentation. | Status type, message, placement |
169
- | InputGroup | Group owns outer field chrome while DateInput preserves its field semantics. | Group prefix or suffix content |
155
+ | State | Required invariant | Allowed variation |
156
+ | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
157
+ | empty rest | Labelled field shows the placeholder and calendar affordance without a committed value. | Label, placeholder, size, width |
158
+ | committed rest | Field displays the controlled value in the selected committed format. | Format and locale |
159
+ | typing | Raw typed text remains visible until commit or reversion. | Parseable text form and locale |
160
+ | invalid typed text | Field reflects invalid state, announces the error, and preserves the prior committed value. | Invalid text |
161
+ | constrained date | Unreachable dates cannot commit on any surface. | Bound or predicate source |
162
+ | popover open | Input reflects expanded dialog state and the Calendar is reachable by pointer and keyboard. | Month count and week start |
163
+ | bottom sheet open | Touch calendar remains open across date corrections until Save. | Visible month and wheel state |
164
+ | native open/closed | Real date input retains its labelled controlled value while the browser/OS owns picker chrome. | Engine-provided picker |
165
+ | disabled | Focusable with `aria-disabled` and disabled paint; mutation and activation are blocked. | With or without a reason |
166
+ | busy | `aria-busy` on the control; the composed Spinner is silent and the field announces its busy start once (`spec:AST-086/FR8`). The field keeps its ordinary paint, new commits are blocked, and the native picker stays focusable during a pending Action and may move its transient OS highlight without emitting another change. | Explicit loading or pending Action |
167
+ | clearable | A committed value has one labelled clear action that emits `undefined`. | Surface and value |
168
+ | status | Error, warning, or success remains named and uses shared status presentation. | Status type, message, placement |
169
+ | InputGroup | Group owns outer field chrome while DateInput preserves its field semantics. | Group prefix or suffix content |
170
170
 
171
171
  ### Transformation and precedence order
172
172
 
@@ -201,8 +201,10 @@ approved policy.
201
201
  - **AR3 — Validation.** Invalid typed or native selections are exposed without color
202
202
  alone; rejected typed input uses an assertive alert and native rejection remains
203
203
  described to assistive technology.
204
- - **AR4 — Disabled reason.** A disabled field with a reason remains focusable and
205
- described while all value mutation and picker activation stay blocked.
204
+ - **AR4 — Disabled and busy focus.** A disabled or busy field remains focusable and
205
+ exposes its state on the focused control (`spec:AST-085/FR1, FR5`); a disabled
206
+ reason, when given, describes the field's focusable controls while all value
207
+ mutation and picker activation stay blocked.
206
208
  - **AR5 — Native control.** The browser/OS date input remains the labelled value owner;
207
209
  the painted committed-value overlay is excluded from the accessibility tree.
208
210
  - **AR6 — Touch calendar.** The bottom-sheet Calendar preserves one reachable day per
@@ -274,6 +276,11 @@ clear-glyph target of its own.
274
276
  policy.
275
277
  - `spec:AST-043` owns the picker presentation vocabulary, default, native fallback,
276
278
  deprecated mapping, and precedence.
279
+ - `spec:AST-085` owns focusable disabled and busy controls: no native `disabled`,
280
+ blocked change paths, distinct disabled and busy paint, and focus kept when a
281
+ control becomes inactive.
282
+ - `spec:AST-086` owns busy announcements: the composed Spinner is silent and the
283
+ field announces each busy start once.
277
284
  - `architecture:component-theming-surface` owns target admission, painting-element
278
285
  placement, state reflection, and anatomy mapping.
279
286
  - `architecture:interaction-modality` owns input-modality principles; DateInput uses
@@ -80,8 +80,9 @@ import {
80
80
  import {useDevWarning} from '../hooks/useDevWarning';
81
81
 
82
82
  const styles = stylex.create({
83
- // The shared disabled style drops the focus ring; restore it while this
84
- // field's own input holds focus (spec:AST-085 FR6). Defaults repeat it.
83
+ // While disabled or busy the field takes no hover ring, but the focus ring
84
+ // returns while this field's own input holds focus (spec:AST-085 FR6).
85
+ // Defaults repeat the shared border and shadow.
85
86
  disabledFocusRing: {
86
87
  borderColor: {
87
88
  default: colorVars['--color-border-emphasized'],
@@ -292,7 +293,9 @@ export interface DateInputProps extends Omit<
292
293
  changeAction?: (value: ISODateString | undefined) => void | Promise<void>;
293
294
 
294
295
  /**
295
- * Whether the input is in a loading state.
296
+ * Whether the input is in a loading state. The field stays focusable and
297
+ * exposes `aria-busy` with a Spinner; typing, picking, and clearing are
298
+ * blocked until loading ends.
296
299
  * @default false
297
300
  */
298
301
  isLoading?: boolean;
@@ -319,9 +322,9 @@ export interface DateInputProps extends Omit<
319
322
  placeholder?: string;
320
323
 
321
324
  /**
322
- * The size of the input.
323
- * - 'sm': Compact size (18px height)
324
- * - 'md': Default size (26px height)
325
+ * The size of the input. The field height follows the theme's element-size
326
+ * token for the chosen size (`--size-element-sm`, `--size-element-md`, or
327
+ * `--size-element-lg`).
325
328
  * @default 'md'
326
329
  */
327
330
  size?: DateInputSize;
@@ -835,7 +838,10 @@ function PointerDateField({
835
838
  stylex.props(
836
839
  inputWrapperStyles.base,
837
840
  sizeStyles[size],
838
- isEffectivelyDisabled && inputWrapperStyles.disabled,
841
+ // Disabled paint belongs to the disabled state only; a busy field
842
+ // keeps its ordinary paint and shows the Spinner (spec:AST-085
843
+ // FR6, family:buttons FR4).
844
+ isDisabled && inputWrapperStyles.disabled,
839
845
  isEffectivelyDisabled && styles.disabledFocusRing,
840
846
  status && inputStatusBorderStyles[status.type],
841
847
  status &&
@@ -83,7 +83,8 @@ import {
83
83
  import {chainEventHandlers} from '../utils/chainEventHandlers';
84
84
 
85
85
  const styles = stylex.create({
86
- // Same as DateInput's: the focus ring for a focused disabled field.
86
+ // Same as DateInput's: no hover ring while disabled or busy, and the
87
+ // focus ring while the field's input holds focus.
87
88
  disabledFocusRing: {
88
89
  borderColor: {
89
90
  default: colorVars['--color-border-emphasized'],
@@ -597,7 +598,10 @@ export function NativeDateField({
597
598
  inputWrapperStyles.base,
598
599
  sizeStyles[size],
599
600
  styles.wrapper,
600
- isEffectivelyDisabled && inputWrapperStyles.disabled,
601
+ // Disabled paint belongs to the disabled state only; a busy field
602
+ // keeps its ordinary paint and shows the Spinner (spec:AST-085
603
+ // FR6, family:buttons FR4).
604
+ isDisabled && inputWrapperStyles.disabled,
601
605
  isEffectivelyDisabled && styles.disabledFocusRing,
602
606
  status && inputStatusBorderStyles[status.type],
603
607
  status &&
@@ -167,7 +167,8 @@ const sizeStyles = stylex.create({
167
167
  });
168
168
 
169
169
  const styles = stylex.create({
170
- // Same as DateInput's: the focus ring for a focused disabled field.
170
+ // Same as DateInput's: no hover ring while disabled or busy, and the
171
+ // focus ring while the field's input holds focus.
171
172
  disabledFocusRing: {
172
173
  borderColor: {
173
174
  default: colorVars['--color-border-emphasized'],
@@ -1233,7 +1234,10 @@ export function TouchDateField({
1233
1234
  inputWrapperStyles.base,
1234
1235
  sizeStyles[size],
1235
1236
  styles.wrapper,
1236
- isEffectivelyDisabled && inputWrapperStyles.disabled,
1237
+ // Disabled paint belongs to the disabled state only; a busy field
1238
+ // keeps its ordinary paint and shows the Spinner (spec:AST-085
1239
+ // FR6, family:buttons FR4).
1240
+ isDisabled && inputWrapperStyles.disabled,
1237
1241
  isEffectivelyDisabled && styles.disabledFocusRing,
1238
1242
  status && inputStatusBorderStyles[status.type],
1239
1243
  status &&