@astryxdesign/core 0.7.3-canary.2468b8a → 0.7.3-canary.296edaf

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 (46) hide show
  1. package/dist/Calendar/Calendar.js +3 -2
  2. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -5
  3. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  4. package/dist/DateTimeInput/DateTimeInput.js +25 -27
  5. package/dist/DateTimeInput/NativeDateSegment.d.ts +3 -2
  6. package/dist/DateTimeInput/NativeDateSegment.d.ts.map +1 -1
  7. package/dist/DateTimeInput/NativeDateSegment.js +5 -5
  8. package/dist/DateTimeInput/NativeTimeSegment.d.ts +3 -2
  9. package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -1
  10. package/dist/DateTimeInput/NativeTimeSegment.js +5 -5
  11. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  12. package/dist/DateTimeInput/TouchDateTimeField.js +12 -9
  13. package/dist/Pagination/Pagination.d.ts.map +1 -1
  14. package/dist/Pagination/Pagination.js +5 -2
  15. package/dist/TimeInput/TimeInput.js +1 -1
  16. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  17. package/dist/Timestamp/Timestamp.js +41 -8
  18. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  19. package/dist/TreeList/TreeListItem.js +8 -3
  20. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  21. package/dist/hooks/useGridFocus.js +10 -1
  22. package/package.json +3 -3
  23. package/scripts/agent-doc-state.mjs +24 -2
  24. package/src/BottomSheet/BottomSheet.spec.md +26 -53
  25. package/src/BottomSheet/BottomSheetSwitcher.spec.md +45 -48
  26. package/src/Calendar/Calendar.test.tsx +68 -24
  27. package/src/Calendar/Calendar.tsx +2 -1
  28. package/src/DateRangeInput/DateRangeInput.test.tsx +9 -3
  29. package/src/DateTimeInput/DateTimeInput.doc.mjs +9 -8
  30. package/src/DateTimeInput/DateTimeInput.test.tsx +126 -11
  31. package/src/DateTimeInput/DateTimeInput.tsx +42 -26
  32. package/src/DateTimeInput/DateTimeInputTouch.test.tsx +24 -0
  33. package/src/DateTimeInput/NativeDateSegment.tsx +9 -6
  34. package/src/DateTimeInput/NativePickerSegments.test.tsx +31 -0
  35. package/src/DateTimeInput/NativeTimeSegment.tsx +9 -6
  36. package/src/DateTimeInput/TouchDateTimeField.tsx +22 -7
  37. package/src/Pagination/Pagination.test.tsx +5 -1
  38. package/src/Pagination/Pagination.tsx +3 -1
  39. package/src/TimeInput/NativeTimeInput.test.tsx +3 -1
  40. package/src/TimeInput/TimeInput.tsx +1 -1
  41. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  42. package/src/Timestamp/Timestamp.test.tsx +168 -0
  43. package/src/Timestamp/Timestamp.tsx +62 -11
  44. package/src/TreeList/TreeList.test.tsx +28 -0
  45. package/src/TreeList/TreeListItem.tsx +6 -2
  46. package/src/hooks/useGridFocus.ts +16 -1
@@ -939,8 +939,9 @@ function DayCell({
939
939
  // Mark today's cell programmatically (APG date-picker pattern), not just
940
940
  // visually, so screen-reader users can identify the current date.
941
941
  ,
942
- "aria-current": state.isToday ? 'date' : undefined,
943
- disabled: isDisabled
942
+ "aria-current": state.isToday ? 'date' : undefined
943
+ // A disabled day stays focusable through aria-disabled (spec:AST-085
944
+ // FR1); arrows still skip it and its click and hover are guarded.
944
945
  // Initial roving tab-stop seed; useGridFocus owns it after mount.
945
946
  ,
946
947
  tabIndex: isTabbableDay ? 0 : -1,
@@ -54,12 +54,12 @@ export interface DateTimeInputProps extends Omit<FieldInputBaseProps<HTMLInputEl
54
54
  /**
55
55
  * Explains why the input is disabled. When set together with
56
56
  * `isDisabled`, the input shows a tooltip with this text on hover and
57
- * keyboard focus, and the date and time fields stay focusable (via
58
- * `aria-disabled`) so the reason is discoverable by keyboard and assistive
59
- * technology. Typing and calendar activation stay blocked.
57
+ * keyboard focus, and the date and time fields are described by it, so the
58
+ * reason is discoverable by keyboard and assistive technology. Typing and
59
+ * calendar activation stay blocked.
60
60
  *
61
- * Use this instead of wrapping a disabled input in `Tooltip` — disabled
62
- * controls don't emit the pointer events an external tooltip needs.
61
+ * Use this instead of wrapping a disabled input in `Tooltip`, so the
62
+ * reason is tied to the field.
63
63
  *
64
64
  * @example
65
65
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"DateTimeInput.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/DateTimeInput.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"DateTimeInput.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/DateTimeInput.tsx"],"names":[],"mappings":"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"}
@@ -68,6 +68,11 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
68
68
  // flex wrapping moves each growing segment onto its own full-width row.
69
69
  const HORIZONTAL_SEGMENT_BASIS = 196;
70
70
  const styles = {
71
+ disabledFocusRing: {
72
+ kVAM5u: "xvy26l8 x6q1khz",
73
+ kGVxlE: "x1gnnqk1 xuihb5h",
74
+ $$css: true
75
+ },
71
76
  row: {
72
77
  k1xSpc: "x78zum5",
73
78
  kwnvtZ: "x1a02dak",
@@ -565,7 +570,7 @@ function PointerDateTimeField({
565
570
  setNativeTimeDraft(newTime);
566
571
  }, [fireChange, optimisticValue, valueParts.date]);
567
572
  const handleDateInputChange = useCallback(e => {
568
- // With a disabledMessage the input drops `disabled` for focusability, so
573
+ // The input is never natively disabled (AST-085 FR1), so
569
574
  // guard value mutation explicitly (readOnly also blocks typing).
570
575
  if (isEffectivelyDisabled) {
571
576
  return;
@@ -801,7 +806,7 @@ function PointerDateTimeField({
801
806
 
802
807
  // --- Time handlers ---
803
808
  const handleTimeInputChange = useCallback(e => {
804
- // With a disabledMessage the input drops `disabled` for focusability, so
809
+ // The input is never natively disabled (AST-085 FR1), so
805
810
  // guard value mutation explicitly (readOnly also blocks typing).
806
811
  if (isEffectivelyDisabled) {
807
812
  return;
@@ -873,7 +878,8 @@ function PointerDateTimeField({
873
878
  // window uses those same arrows to navigate candidates, so guard the
874
879
  // composing keydown (fires before compositionend) to avoid stealing them
875
880
  // mid-composition. See utils/ime.ts.
876
- if (isImeKeyEvent(e.nativeEvent)) {
881
+ // A disabled or busy field steps nothing, so it announces nothing (FR2).
882
+ if (isImeKeyEvent(e.nativeEvent) || isEffectivelyDisabled) {
877
883
  return;
878
884
  }
879
885
 
@@ -1026,7 +1032,7 @@ function PointerDateTimeField({
1026
1032
  ...mergeProps(themeProps('date-time-input-date-segment', {
1027
1033
  size,
1028
1034
  status: status?.type ?? null
1029
- }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.dateWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
1035
+ }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.dateWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, isEffectivelyDisabled && styles.disabledFocusRing, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
1030
1036
  children: [usesNativePicker ? /*#__PURE__*/_jsx(NativeDateSegment, {
1031
1037
  id: dateInputId,
1032
1038
  inputRef: mergedDateInputRef,
@@ -1037,7 +1043,7 @@ function PointerDateTimeField({
1037
1043
  max: calendarMax,
1038
1044
  isDateDisabled: isDateDisabled,
1039
1045
  isEffectivelyDisabled: isEffectivelyDisabled,
1040
- hasDisabledMessage: showsDisabledMessage,
1046
+ isFocusableDisabled: true,
1041
1047
  isEffectivelyRequired: isEffectivelyRequired,
1042
1048
  isBusy: isBusy,
1043
1049
  statusType: status?.type,
@@ -1046,14 +1052,17 @@ function PointerDateTimeField({
1046
1052
  ...controlProps,
1047
1053
  'aria-labelledby': controlLabelledBy,
1048
1054
  onBlur: onBlurProp,
1049
- onClick: onClickProp,
1055
+ onClick: isEffectivelyDisabled ? undefined : onClickProp,
1050
1056
  onKeyDown: onKeyDownProp
1051
1057
  }
1052
1058
  }) : /*#__PURE__*/_jsxs(_Fragment, {
1053
1059
  children: [/*#__PURE__*/_jsx("button", {
1054
1060
  type: "button",
1055
1061
  onClick: handleCalendarToggle,
1056
- disabled: isEffectivelyDisabled,
1062
+ "aria-disabled": isEffectivelyDisabled || undefined
1063
+ // A tab stop while disabled too, so it carries the reason (FR5).
1064
+ ,
1065
+ "aria-describedby": showsDisabledMessage ? disabledMessageTooltip.describedBy : undefined,
1057
1066
  "aria-label": popover.isOpen ? t('@astryx.dateInput.toggleCalendarClose') : t('@astryx.dateInput.openCalendar'),
1058
1067
  ...stylex.props(focusOutlineStyles.focusVisible, styles.iconButton, isEffectivelyDisabled && styles.iconButtonDisabled),
1059
1068
  children: /*#__PURE__*/_jsx(Icon, {
@@ -1080,18 +1089,12 @@ function PointerDateTimeField({
1080
1089
  value: dateDisplayValue,
1081
1090
  onChange: handleDateInputChange,
1082
1091
  onBlur: chainEventHandlers(handleDateBlur, onBlurProp),
1083
- onClick: chainEventHandlers(handleDateInputClick, onClickProp),
1092
+ onClick: isEffectivelyDisabled ? undefined : chainEventHandlers(handleDateInputClick, onClickProp),
1084
1093
  onKeyDown: chainEventHandlers(handleDateKeyDown, onKeyDownProp),
1085
1094
  "aria-labelledby": controlLabelledBy,
1086
- placeholder: placeholder
1087
- // With a disabledMessage the input keeps focusability via
1088
- // aria-disabled so the reason is focus-discoverable; typing is
1089
- // blocked with readOnly and the mutation guards, and calendar
1090
- // activation is blocked by the isEffectivelyDisabled guards.
1091
- ,
1092
- disabled: isEffectivelyDisabled && !showsDisabledMessage,
1093
- "aria-disabled": showsDisabledMessage ? 'true' : undefined,
1094
- readOnly: showsDisabledMessage || undefined,
1095
+ placeholder: placeholder,
1096
+ "aria-disabled": isEffectivelyDisabled ? 'true' : undefined,
1097
+ readOnly: isEffectivelyDisabled || undefined,
1095
1098
  "aria-describedby": ariaDescribedBy,
1096
1099
  "aria-required": isEffectivelyRequired ? 'true' : undefined,
1097
1100
  "aria-invalid": status?.type === 'error' || !isDateInputValid ? 'true' : undefined,
@@ -1141,7 +1144,7 @@ function PointerDateTimeField({
1141
1144
  ...mergeProps(themeProps('date-time-input-time-segment', {
1142
1145
  size,
1143
1146
  status: status?.type ?? null
1144
- }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.timeWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
1147
+ }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.timeWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, isEffectivelyDisabled && styles.disabledFocusRing, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
1145
1148
  children: usesNativeTimePicker ? /*#__PURE__*/_jsx(NativeTimeSegment, {
1146
1149
  id: timeInputId,
1147
1150
  inputRef: timeInputRef,
@@ -1157,7 +1160,7 @@ function PointerDateTimeField({
1157
1160
  max: timeMax,
1158
1161
  hourFormat: hourFormat,
1159
1162
  isEffectivelyDisabled: isEffectivelyDisabled,
1160
- hasDisabledMessage: showsDisabledMessage,
1163
+ isFocusableDisabled: true,
1161
1164
  isEffectivelyRequired: isEffectivelyRequired,
1162
1165
  isBusy: isBusy,
1163
1166
  statusType: status?.type,
@@ -1197,14 +1200,9 @@ function PointerDateTimeField({
1197
1200
  "aria-expanded": hasTimeOptions ? timePopover.isOpen : undefined,
1198
1201
  "aria-controls": hasTimeOptions && timePopover.isOpen ? timeListboxId : undefined,
1199
1202
  "aria-autocomplete": hasTimeOptions ? 'list' : undefined,
1200
- "aria-activedescendant": hasTimeOptions && timePopover.isOpen && activeTimeIndex >= 0 && activeTimeIndex < timeOptions.length ? timeOptionId(activeTimeIndex) : undefined
1201
- // With a disabledMessage the input keeps focusability via
1202
- // aria-disabled so the reason is focus-discoverable; typing is
1203
- // blocked with readOnly and the mutation guards.
1204
- ,
1205
- disabled: isEffectivelyDisabled && !showsDisabledMessage,
1206
- "aria-disabled": showsDisabledMessage ? 'true' : undefined,
1207
- readOnly: showsDisabledMessage || undefined,
1203
+ "aria-activedescendant": hasTimeOptions && timePopover.isOpen && activeTimeIndex >= 0 && activeTimeIndex < timeOptions.length ? timeOptionId(activeTimeIndex) : undefined,
1204
+ "aria-disabled": isEffectivelyDisabled ? 'true' : undefined,
1205
+ readOnly: isEffectivelyDisabled || undefined,
1208
1206
  "aria-label": resolvedTimeLabel,
1209
1207
  "aria-describedby": ariaDescribedBy,
1210
1208
  "aria-required": isEffectivelyRequired ? 'true' : undefined,
@@ -11,7 +11,8 @@ export type NativeDateSegmentProps = {
11
11
  max?: ISODateString;
12
12
  isDateDisabled: (date: ReturnType<typeof plainDateFromISO>) => boolean;
13
13
  isEffectivelyDisabled: boolean;
14
- hasDisabledMessage: boolean;
14
+ /** While disabled, stay focusable: aria-disabled and readOnly, not `disabled`. */
15
+ isFocusableDisabled: boolean;
15
16
  isEffectivelyRequired: boolean;
16
17
  isBusy: boolean;
17
18
  statusType?: InputStatusType;
@@ -24,7 +25,7 @@ export type NativeDateSegmentProps = {
24
25
  controlProps?: Omit<FieldInputBaseProps<HTMLInputElement>, keyof FieldPartStyleProps | 'onChange' | 'defaultValue'>;
25
26
  };
26
27
  /** The native date half rendered inside DateTimeInput's date wrapper. */
27
- export declare function NativeDateSegment({ id, inputRef, value, onChange, placeholder, min, max, isDateDisabled, isEffectivelyDisabled, hasDisabledMessage, isEffectivelyRequired, isBusy, statusType, ariaDescribedBy, controlProps, }: NativeDateSegmentProps): import("react").JSX.Element;
28
+ export declare function NativeDateSegment({ id, inputRef, value, onChange, placeholder, min, max, isDateDisabled, isEffectivelyDisabled, isFocusableDisabled, isEffectivelyRequired, isBusy, statusType, ariaDescribedBy, controlProps, }: NativeDateSegmentProps): import("react").JSX.Element;
28
29
  export declare namespace NativeDateSegment {
29
30
  var displayName: string;
30
31
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NativeDateSegment.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/NativeDateSegment.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EAIL,gBAAgB,EAGhB,KAAK,aAAa,EACnB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,UAAU,CAAC;AAK9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,cAAc,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,KAAK,OAAO,CAAC;IACvE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,IAAI,CACjB,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,mBAAmB,GAAG,UAAU,GAAG,cAAc,CACxD,CAAC;CACH,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,EACX,GAAG,EACH,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,MAAM,EACN,UAAU,EACV,eAAe,EACf,YAAY,GACb,EAAE,sBAAsB,+BAuOxB;yBAvPe,iBAAiB"}
1
+ {"version":3,"file":"NativeDateSegment.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/NativeDateSegment.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAO7B,OAAO,EAIL,gBAAgB,EAGhB,KAAK,aAAa,EACnB,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,UAAU,CAAC;AAK9C,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,cAAc,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,KAAK,OAAO,CAAC;IACvE,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kFAAkF;IAClF,mBAAmB,EAAE,OAAO,CAAC;IAC7B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,IAAI,CACjB,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,mBAAmB,GAAG,UAAU,GAAG,cAAc,CACxD,CAAC;CACH,CAAC;AAEF,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,EACX,GAAG,EACH,GAAG,EACH,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,MAAM,EACN,UAAU,EACV,eAAe,EACf,YAAY,GACb,EAAE,sBAAsB,+BAyOxB;yBAzPe,iBAAiB"}
@@ -46,7 +46,7 @@ export function NativeDateSegment({
46
46
  max,
47
47
  isDateDisabled,
48
48
  isEffectivelyDisabled,
49
- hasDisabledMessage,
49
+ isFocusableDisabled,
50
50
  isEffectivelyRequired,
51
51
  isBusy,
52
52
  statusType,
@@ -192,7 +192,7 @@ export function NativeDateSegment({
192
192
  children: [/*#__PURE__*/_jsx("button", {
193
193
  type: "button",
194
194
  onClick: openPicker,
195
- disabled: isEffectivelyDisabled,
195
+ "aria-disabled": isEffectivelyDisabled || undefined,
196
196
  "aria-label": t('@astryx.dateInput.openCalendar'),
197
197
  tabIndex: -1,
198
198
  ...stylex.props(focusOutlineStyles.focusVisible, styles.iconButton, isEffectivelyDisabled && styles.iconButtonDisabled),
@@ -219,9 +219,9 @@ export function NativeDateSegment({
219
219
  onBlur: chainEventHandlers(handleBlur, onBlurProp),
220
220
  min: min,
221
221
  max: max,
222
- disabled: isEffectivelyDisabled && !hasDisabledMessage,
223
- "aria-disabled": hasDisabledMessage ? 'true' : undefined,
224
- readOnly: hasDisabledMessage || undefined,
222
+ disabled: isEffectivelyDisabled && !isFocusableDisabled,
223
+ "aria-disabled": isEffectivelyDisabled && isFocusableDisabled ? 'true' : undefined,
224
+ readOnly: isEffectivelyDisabled && isFocusableDisabled || undefined,
225
225
  "aria-describedby": ariaDescribedBy,
226
226
  "aria-required": isEffectivelyRequired ? 'true' : undefined,
227
227
  "aria-invalid": statusType === 'error' || !isInputValid ? 'true' : undefined,
@@ -17,7 +17,8 @@ export type NativeTimeSegmentProps = {
17
17
  max?: ISOTimeString;
18
18
  hourFormat: '12h' | '24h';
19
19
  isEffectivelyDisabled: boolean;
20
- hasDisabledMessage: boolean;
20
+ /** While disabled, stay focusable: aria-disabled and readOnly, not `disabled`. */
21
+ isFocusableDisabled: boolean;
21
22
  isEffectivelyRequired: boolean;
22
23
  isBusy: boolean;
23
24
  statusType?: InputStatusType;
@@ -30,7 +31,7 @@ export type NativeTimeSegmentProps = {
30
31
  controlProps?: Omit<FieldInputBaseProps<HTMLInputElement>, keyof FieldPartStyleProps | 'onChange' | 'defaultValue'>;
31
32
  };
32
33
  /** The shared native time control rendered inside Astryx field chrome. */
33
- export declare function NativeTimeSegment({ id, inputRef, value, onChange, placeholder, inputLabel, openPickerLabel, ariaLabelledBy, iconThemeProps, hasAutoFocus, min, max, hourFormat, isEffectivelyDisabled, hasDisabledMessage, isEffectivelyRequired, isBusy, statusType, ariaDescribedBy, controlProps, }: NativeTimeSegmentProps): import("react").JSX.Element;
34
+ export declare function NativeTimeSegment({ id, inputRef, value, onChange, placeholder, inputLabel, openPickerLabel, ariaLabelledBy, iconThemeProps, hasAutoFocus, min, max, hourFormat, isEffectivelyDisabled, isFocusableDisabled, isEffectivelyRequired, isBusy, statusType, ariaDescribedBy, controlProps, }: NativeTimeSegmentProps): import("react").JSX.Element;
34
35
  export declare namespace NativeTimeSegment {
35
36
  var displayName: string;
36
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"NativeTimeSegment.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/NativeTimeSegment.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,UAAU,CAAC;AAK9C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,UAAU,CAAC;AAoBlB,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,IAAI,CACjB,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,mBAAmB,GAAG,UAAU,GAAG,cAAc,CACxD,CAAC;CACH,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAoB,EACpB,GAAG,EACH,GAAG,EACH,UAAU,EACV,qBAAqB,EACrB,kBAAkB,EAClB,qBAAqB,EACrB,MAAM,EACN,UAAU,EACV,eAAe,EACf,YAAY,GACb,EAAE,sBAAsB,+BA2OxB;yBAhQe,iBAAiB"}
1
+ {"version":3,"file":"NativeTimeSegment.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/NativeTimeSegment.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,UAAU,CAAC;AAK9C,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,UAAU,CAAC;AAoBlB,MAAM,MAAM,sBAAsB,GAAG;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,GAAG,SAAS,KAAK,IAAI,CAAC;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,GAAG,CAAC,EAAE,aAAa,CAAC;IACpB,UAAU,EAAE,KAAK,GAAG,KAAK,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kFAAkF;IAClF,mBAAmB,EAAE,OAAO,CAAC;IAC7B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,YAAY,CAAC,EAAE,IAAI,CACjB,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,MAAM,mBAAmB,GAAG,UAAU,GAAG,cAAc,CACxD,CAAC;CACH,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,EAChC,EAAE,EACF,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,WAAW,EACX,UAAU,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAoB,EACpB,GAAG,EACH,GAAG,EACH,UAAU,EACV,qBAAqB,EACrB,mBAAmB,EACnB,qBAAqB,EACrB,MAAM,EACN,UAAU,EACV,eAAe,EACf,YAAY,GACb,EAAE,sBAAsB,+BA6OxB;yBAlQe,iBAAiB"}
@@ -59,7 +59,7 @@ export function NativeTimeSegment({
59
59
  max,
60
60
  hourFormat,
61
61
  isEffectivelyDisabled,
62
- hasDisabledMessage,
62
+ isFocusableDisabled,
63
63
  isEffectivelyRequired,
64
64
  isBusy,
65
65
  statusType,
@@ -202,7 +202,7 @@ export function NativeTimeSegment({
202
202
  children: [/*#__PURE__*/_jsx("button", {
203
203
  type: "button",
204
204
  onClick: openPicker,
205
- disabled: isEffectivelyDisabled,
205
+ "aria-disabled": isEffectivelyDisabled || undefined,
206
206
  "aria-label": openPickerLabel,
207
207
  tabIndex: -1,
208
208
  ...stylex.props(focusOutlineStyles.focusVisible, styles.iconButton, isEffectivelyDisabled && styles.iconButtonDisabled),
@@ -228,9 +228,9 @@ export function NativeTimeSegment({
228
228
  min: min,
229
229
  max: max,
230
230
  step: 60,
231
- disabled: isEffectivelyDisabled && !hasDisabledMessage,
232
- "aria-disabled": hasDisabledMessage ? 'true' : undefined,
233
- readOnly: hasDisabledMessage || undefined
231
+ disabled: isEffectivelyDisabled && !isFocusableDisabled,
232
+ "aria-disabled": isEffectivelyDisabled && isFocusableDisabled ? 'true' : undefined,
233
+ readOnly: isEffectivelyDisabled && isFocusableDisabled || undefined
234
234
  // The segment's own label applies only when nothing else names it;
235
235
  // otherwise a caller aria-label from the spread above stays.
236
236
  ,
@@ -1 +1 @@
1
- {"version":3,"file":"TouchDateTimeField.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/TouchDateTimeField.tsx"],"names":[],"mappings":"AA6GA,OAAO,KAAK,EAAC,kBAAkB,EAAoB,MAAM,iBAAiB,CAAC;AA4U3E,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,eAAe,EACf,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,SAAiB,EACjB,GAAG,EACH,GAAG,EACH,eAAe,EACf,UAAkB,EAClB,UAAkB,EAElB,aAAa,EAAE,cAAc,EAC7B,kBAAkB,EAAE,mBAAmB,EACvC,QAAgB,EAChB,WAAW,EAAE,oBAAoB,EACjC,eAAe,EAAE,wBAAwB,EACzC,SAAS,EACT,IAAI,EAAE,QAAQ,EACd,MAAM,EACN,YAAY,EAEZ,cAAc,EAAE,eAAe,EAC/B,YAAY,EAAE,gBAAoB,EAClC,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,GAAG,EACH,GAAG,SAAS,EACb,EAAE,kBAAkB,+BAm/BpB;yBA1hCe,kBAAkB"}
1
+ {"version":3,"file":"TouchDateTimeField.d.ts","sourceRoot":"","sources":["../../src/DateTimeInput/TouchDateTimeField.tsx"],"names":[],"mappings":"AA6GA,OAAO,KAAK,EAAC,kBAAkB,EAAoB,MAAM,iBAAiB,CAAC;AAuV3E,wBAAgB,kBAAkB,CAAC,EACjC,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,eAAe,EACf,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,SAAiB,EACjB,GAAG,EACH,GAAG,EACH,eAAe,EACf,UAAkB,EAClB,UAAkB,EAElB,aAAa,EAAE,cAAc,EAC7B,kBAAkB,EAAE,mBAAmB,EACvC,QAAgB,EAChB,WAAW,EAAE,oBAAoB,EACjC,eAAe,EAAE,wBAAwB,EACzC,SAAS,EACT,IAAI,EAAE,QAAQ,EACd,MAAM,EACN,YAAY,EAEZ,cAAc,EAAE,eAAe,EAC/B,YAAY,EAAE,gBAAoB,EAClC,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,GAAG,EACH,GAAG,SAAS,EACb,EAAE,kBAAkB,+BAu/BpB;yBA9hCe,kBAAkB"}
@@ -103,6 +103,11 @@ const sizeStyles = {
103
103
  };
104
104
  const HORIZONTAL_SEGMENT_BASIS = 196;
105
105
  const styles = {
106
+ disabledFocusRing: {
107
+ kVAM5u: "xvy26l8 x6q1khz",
108
+ kGVxlE: "x1gnnqk1 xuihb5h",
109
+ $$css: true
110
+ },
106
111
  iconButton: {
107
112
  k1xSpc: "x78zum5",
108
113
  kGNEyG: "x6s0dn4",
@@ -932,11 +937,11 @@ export function TouchDateTimeField({
932
937
  ...mergeProps(themeProps('date-time-input-date-segment', {
933
938
  size,
934
939
  status: status?.type ?? null
935
- }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.touchDateWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
940
+ }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.touchDateWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, isEffectivelyDisabled && styles.disabledFocusRing, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
936
941
  children: [/*#__PURE__*/_jsx("button", {
937
942
  type: "button",
938
943
  onClick: () => openSheet('date'),
939
- disabled: isEffectivelyDisabled,
944
+ "aria-disabled": isEffectivelyDisabled || undefined,
940
945
  "aria-label": t('@astryx.dateInput.openCalendar'),
941
946
  tabIndex: -1,
942
947
  ...stylex.props(focusOutlineStyles.focusVisible, styles.iconButton, isEffectivelyDisabled && styles.iconButtonDisabled),
@@ -958,12 +963,11 @@ export function TouchDateTimeField({
958
963
  readOnly: true,
959
964
  inputMode: "none",
960
965
  onChange: () => {},
961
- onClick: chainEventHandlers(() => openSheet('date'), onClickProp),
966
+ onClick: isEffectivelyDisabled ? undefined : chainEventHandlers(() => openSheet('date'), onClickProp),
962
967
  onKeyDown: chainEventHandlers(event => handleInputKeyDown(event, 'date'), onKeyDownProp),
963
968
  "aria-labelledby": controlLabelledBy,
964
969
  placeholder: placeholder,
965
- disabled: isEffectivelyDisabled && !showsDisabledMessage,
966
- "aria-disabled": showsDisabledMessage ? 'true' : undefined,
970
+ "aria-disabled": isEffectivelyDisabled ? 'true' : undefined,
967
971
  "aria-describedby": ariaDescribedBy,
968
972
  "aria-required": isEffectivelyRequired ? 'true' : undefined,
969
973
  "aria-invalid": status?.type === 'error' ? 'true' : undefined,
@@ -997,11 +1001,11 @@ export function TouchDateTimeField({
997
1001
  ...mergeProps(themeProps('date-time-input-time-segment', {
998
1002
  size,
999
1003
  status: status?.type ?? null
1000
- }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.touchTimeWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
1004
+ }), stylex.props(inputWrapperStyles.base, sizeStyles[size], styles.touchTimeWrapper, isEffectivelyDisabled && inputWrapperStyles.disabled, isEffectivelyDisabled && styles.disabledFocusRing, status && inputStatusBorderStyles[status.type], status && !isEffectivelyDisabled && inputStatusHoverShadowStyles[status.type], status && inputStatusFocusWithinStyles[status.type])),
1001
1005
  children: [/*#__PURE__*/_jsx("button", {
1002
1006
  type: "button",
1003
1007
  onClick: () => openSheet('time'),
1004
- disabled: isEffectivelyDisabled,
1008
+ "aria-disabled": isEffectivelyDisabled || undefined,
1005
1009
  "aria-label": t('@astryx.dateTimeInput.openTimePicker', {
1006
1010
  label: resolvedTimeLabel
1007
1011
  }),
@@ -1025,8 +1029,7 @@ export function TouchDateTimeField({
1025
1029
  onClick: () => openSheet('time'),
1026
1030
  onKeyDown: event => handleInputKeyDown(event, 'time'),
1027
1031
  placeholder: timePlaceholder,
1028
- disabled: isEffectivelyDisabled && !showsDisabledMessage,
1029
- "aria-disabled": showsDisabledMessage ? 'true' : undefined,
1032
+ "aria-disabled": isEffectivelyDisabled ? 'true' : undefined,
1030
1033
  "aria-label": resolvedTimeLabel,
1031
1034
  "aria-describedby": ariaDescribedBy,
1032
1035
  "aria-required": isEffectivelyRequired ? 'true' : undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/Pagination/Pagination.tsx"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAMlD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,oBAAoB,CAAC;AAE3D,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE7B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGtD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IAGtB,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwHD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CA6CpB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,OAAO,EACP,QAAQ,EAAE,YAAiB,EAC3B,eAAe,EACf,gBAAgB,EAChB,OAAiB,EACjB,SAAS,EACT,YAAY,EAAE,gBAAgB,EAC9B,IAAI,EAAE,QAAY,EAClB,YAAgB,EAChB,IAAW,EACX,UAAkB,EAClB,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,MAAM,EACrB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,sCAwfjB;yBAhhBe,UAAU"}
1
+ {"version":3,"file":"Pagination.d.ts","sourceRoot":"","sources":["../../src/Pagination/Pagination.tsx"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,SAAS,CAAC;AAMlD;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,oBAAoB,CAAC;AAE3D,uCAAuC;AACvC,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,WAAW,CAAC,EACtB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAE7B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAGtD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAGlB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,yCAAyC;IACzC,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAG9C;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;IAGtB,wDAAwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAC;IAGrB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAGf,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwHD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,GACnB,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CA6CpB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,UAAU,EAAE,cAAc,EAC1B,OAAO,EACP,QAAQ,EAAE,YAAiB,EAC3B,eAAe,EACf,gBAAgB,EAChB,OAAiB,EACjB,SAAS,EACT,YAAY,EAAE,gBAAgB,EAC9B,IAAI,EAAE,QAAY,EAClB,YAAgB,EAChB,IAAW,EACX,UAAkB,EAClB,KAAK,EAAE,cAAc,EACrB,aAAa,EAAE,MAAM,EACrB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,eAAe,sCA0fjB;yBAlhBe,UAAU"}
@@ -496,8 +496,11 @@ export function Pagination({
496
496
  // needs to focus the dot, which some browsers (Safari) skip for
497
497
  // buttons, so focus it explicitly.
498
498
  ,
499
- onClick: e => e.currentTarget.focus(),
500
- disabled: isDisabled,
499
+ onClick: e => e.currentTarget.focus()
500
+ // Disabled dots stay focusable (spec:AST-085 FR1); the page
501
+ // only follows focus while enabled (handleDotsFocus).
502
+ ,
503
+ "aria-disabled": isDisabled || undefined,
501
504
  ...mergeProps(themeProps('pagination-dot', {
502
505
  active: isActive ? 'active' : null,
503
506
  size
@@ -420,7 +420,7 @@ function TimeField({
420
420
  max: max,
421
421
  hourFormat: hourFormat,
422
422
  isEffectivelyDisabled: isDisabled,
423
- hasDisabledMessage: showsDisabledMessage,
423
+ isFocusableDisabled: showsDisabledMessage,
424
424
  isEffectivelyRequired: isEffectivelyRequired,
425
425
  isBusy: isBusy,
426
426
  statusType: status?.type,
@@ -1 +1 @@
1
- {"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../src/Timestamp/Timestamp.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAK9E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAK5C,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,kBAAkB,CAAC;AAY1B,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,gBAAgB,GAChB,MAAM,GACN,MAAM,GACN,WAAW,GACX,cAAc,GACd,WAAW,GACX,MAAM,GACN,aAAa,GACb,kBAAkB,GAClB,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,eAAe,CAAC;IAChE,kDAAkD;IAClD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC,uFAAuF;IACvF,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACtD;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AA+ED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,MAAe,EACf,aAAsC,EACtC,UAAiB,EACjB,cAAc,EACd,eAAuB,EACvB,MAAc,EACd,IAAmB,EACnB,IAAI,EACJ,KAAmB,EACnB,MAAM,EACN,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,GAAG,IAAI,EACR,EAAE,cAAc,sCA+JhB;yBAjLe,SAAS"}
1
+ {"version":3,"file":"Timestamp.d.ts","sourceRoot":"","sources":["../../src/Timestamp/Timestamp.tsx"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAC,MAAM,gBAAgB,CAAC;AAK9E,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAK5C,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,kBAAkB,CAAC;AAY1B,MAAM,MAAM,eAAe,GACvB,UAAU,GACV,gBAAgB,GAChB,MAAM,GACN,MAAM,GACN,WAAW,GACX,cAAc,GACd,WAAW,GACX,MAAM,GACN,aAAa,GACb,kBAAkB,GAClB,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,eAAe,CAAC;IAChE,kDAAkD;IAClD,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC,uFAAuF;IACvF,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;;OAkBG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACtD;;;;;;;;OAQG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;;OAGG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;OAEG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,sCAAsC;IACtC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAsFD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,MAAe,EACf,aAAsC,EACtC,UAAiB,EACjB,cAAc,EACd,eAAuB,EACvB,MAAc,EACd,IAAmB,EACnB,IAAI,EACJ,KAAmB,EACnB,MAAM,EACN,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,aAAa,EAAE,MAAM,EACrB,GAAG,IAAI,EACR,EAAE,cAAc,sCAoMhB;yBAtNe,SAAS"}
@@ -16,7 +16,7 @@
16
16
  * - /apps/storybook/stories/Timestamp.stories.tsx
17
17
  * - /packages/cli/assets/templates/blocks/components/Timestamp/ (showcase blocks)
18
18
  */
19
- import { lazy, Suspense, useEffect, useRef, useState } from 'react';
19
+ import { lazy, Suspense, useEffect, useRef, useState, useSyncExternalStore } from 'react';
20
20
  import * as stylex from '@stylexjs/stylex';
21
21
  import { Text } from "../Text/index.js";
22
22
  import { mergeProps } from "../utils/index.js";
@@ -76,6 +76,13 @@ function getLiveInterval(diffSeconds) {
76
76
  return 300_000; // every 5 minutes
77
77
  }
78
78
 
79
+ // Whether this render may read the current time. Server renders (including
80
+ // static prerenders) and the hydration pass read `false`, so the markup never
81
+ // depends on when it was rendered; client renders read `true`.
82
+ const subscribeToNothing = () => () => {};
83
+ const canReadClockOnClient = () => true;
84
+ const canReadClockOnServer = () => false;
85
+
79
86
  /** Whether a format is non-relative (i.e. shows a fixed date/time). */
80
87
  function isAbsoluteFormat(format) {
81
88
  return format !== 'relative' && format !== 'relative_short' && format !== 'auto';
@@ -134,7 +141,23 @@ export function Timestamp({
134
141
  const locale = useLocale();
135
142
  const timeRef = useRef(null);
136
143
  const mergedTimeRef = useMergedRefs(ref, timeRef);
137
- const [now, setNow] = useState(() => new Date());
144
+ // Only relative and auto formats depend on the current time. Absolute
145
+ // formats never read the clock, so they render identically on the server,
146
+ // in a static prerender, and on the client. A clock-dependent format reads
147
+ // it on the client only: server renders and the hydration pass show the
148
+ // full date and time in UTC, and the client switches to the relative phrase
149
+ // right after hydration.
150
+ const needsClock = !isAbsoluteFormat(format);
151
+ const canReadClock = useSyncExternalStore(subscribeToNothing, canReadClockOnClient, canReadClockOnServer);
152
+ const [now, setNow] = useState(() => needsClock && canReadClock ? new Date() : null);
153
+ // Read the clock during render once it may be read: after hydration (the
154
+ // store re-renders with its client value) and when `format` switches from
155
+ // an absolute value to a clock-dependent one, so the placeholder never
156
+ // commits on the client.
157
+ if (needsClock && canReadClock && now === null) {
158
+ // eslint-disable-next-line @eslint-react/purity -- seeds clock state once, like the initializer; never runs on the server or while hydrating
159
+ setNow(new Date());
160
+ }
138
161
  const date = parseValue(value);
139
162
  // An unparseable value (a malformed date string, or a NaN timestamp from
140
163
  // missing data) yields an Invalid Date, and formatting one throws "Invalid
@@ -143,13 +166,23 @@ export function Timestamp({
143
166
  const isValidDate = !Number.isNaN(date.getTime());
144
167
  const isoString = isValidDate ? date.toISOString() : '';
145
168
 
146
- // Determine effective format
147
- const diffSeconds = Math.round((now.getTime() - date.getTime()) / 1000);
148
- const effectiveFormat = format === 'auto' ? Math.abs(diffSeconds) <= autoThreshold ? 'relative' : 'date_time' : format;
169
+ // Determine effective format. Until the clock is read, a clock-dependent
170
+ // format renders as the full date and time.
171
+ const isClockPending = needsClock && now === null;
172
+ const diffSeconds = now === null ? 0 : Math.round((now.getTime() - date.getTime()) / 1000);
173
+ const effectiveFormat = isClockPending ? 'date_time' : format === 'auto' ? Math.abs(diffSeconds) <= autoThreshold ? 'relative' : 'date_time' : format;
149
174
 
150
- // Format the display text. No time zone is passed: the visible text always
151
- // reads in the viewer's own zone, and only the tooltip names others.
152
- const displayText = !isValidDate ? '' : effectiveFormat === 'relative' ? formatRelativeTime(date, now, locale, 'long') : effectiveFormat === 'relative_short' ? formatRelativeTime(date, now, locale, 'narrow') : isAbsoluteFormat(effectiveFormat) ? formatInstant(date, effectiveFormat, locale, {
175
+ // Format the display text in the viewer's own zone; only the tooltip names
176
+ // others. The one exception is the pre-hydration placeholder, written in
177
+ // UTC with its label so every zone produces the same markup.
178
+ const displayText = !isValidDate ? '' : effectiveFormat === 'relative' ? formatRelativeTime(date, now ?? date, locale, 'long') : effectiveFormat === 'relative_short' ? formatRelativeTime(date, now ?? date, locale, 'narrow') : isAbsoluteFormat(effectiveFormat) ? formatInstant(date, effectiveFormat, locale,
179
+ // The pre-hydration placeholder is written in UTC, labelled, so
180
+ // the server and the hydrating client produce the same text in
181
+ // every time zone.
182
+ isClockPending ? {
183
+ timeZone: 'UTC',
184
+ isTimezoneShown: true
185
+ } : {
153
186
  isTimezoneShown
154
187
  }) : '';
155
188
 
@@ -1 +1 @@
1
- {"version":3,"file":"TreeListItem.d.ts","sourceRoot":"","sources":["../../src/TreeList/TreeListItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAyB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAoB3C,OAAO,KAAK,EAAC,eAAe,EAAE,eAAe,EAAC,MAAM,iBAAiB,CAAC;AA6RtE,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB;;;;OAIG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAMD,wBAAgB,YAAY,CAAC,EAC3B,EAAE,EACF,KAAK,EACL,WAAW,EACX,YAAY,EACZ,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAkB,EAClB,UAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,MAAM,EACN,eAAe,EACf,UAAU,EACV,QAAQ,EACR,OAAO,EACP,OAAO,EACP,gBAAgB,EAChB,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,yBAAyB,+BA+S3B;yBA1Ue,YAAY"}
1
+ {"version":3,"file":"TreeListItem.d.ts","sourceRoot":"","sources":["../../src/TreeList/TreeListItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,EAAyB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAoB3C,OAAO,KAAK,EAAC,eAAe,EAAE,eAAe,EAAC,MAAM,iBAAiB,CAAC;AA8RtE,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,OAAO,EAAE,eAAe,CAAC;IACzB;;;;OAIG;IACH,OAAO,EAAE,eAAe,CAAC;IACzB,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;CACrB;AAMD,wBAAgB,YAAY,CAAC,EAC3B,EAAE,EACF,KAAK,EACL,WAAW,EACX,YAAY,EACZ,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,OAAO,EACP,IAAI,EACJ,MAAM,EACN,UAAkB,EAClB,UAAkB,EAClB,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,MAAM,EACN,eAAe,EACf,UAAU,EACV,QAAQ,EACR,OAAO,EACP,OAAO,EACP,gBAAgB,EAChB,QAAQ,EACR,OAAO,EACP,UAAU,GACX,EAAE,yBAAyB,+BAkT3B;yBA7Ue,YAAY"}
@@ -27,6 +27,7 @@ import { useLinkComponent } from "../Link/useLinkComponent.js";
27
27
  import { TreeListBranches } from "./TreeListBranches.js";
28
28
  import { themeProps } from "../utils/themeProps.js";
29
29
  import { useTranslator } from "../i18n/index.js";
30
+ import { disabledInteractionProps } from "../utils/disabledInteraction.js";
30
31
 
31
32
  // =============================================================================
32
33
  // Styles
@@ -311,13 +312,16 @@ export function TreeListItem({
311
312
  // Stable identity for TreeList's activateItem selector — do not
312
313
  // remove without also updating TreeList.tsx.
313
314
  ,
314
- "data-tree-toggle": "",
315
- disabled: isDisabled
315
+ "data-tree-toggle": ""
316
+ // Disabled stays focusable (spec:AST-085 FR1) but inert (FR2).
317
+ ,
318
+ "aria-disabled": isDisabled || undefined
316
319
  // Roving tabindex lives on the treeitem row; the chevron toggle is not
317
320
  // a separate tab stop. Row-level Enter/Space forwards to this button.
318
321
  ,
319
322
  tabIndex: -1,
320
323
  onClick: handleToggle,
324
+ ...(isDisabled ? disabledInteractionProps() : null),
321
325
  ...mergeProps(
322
326
  // Stable theme target for the expand/collapse control. `data-tree-toggle`
323
327
  // stays as the functional activation hook; this adds a themeable
@@ -365,7 +369,8 @@ export function TreeListItem({
365
369
  }) : onClick != null ? /*#__PURE__*/_jsx("button", {
366
370
  type: "button",
367
371
  onClick: onClick,
368
- disabled: isDisabled,
372
+ "aria-disabled": isDisabled || undefined,
373
+ ...(isDisabled ? disabledInteractionProps() : null),
369
374
  "aria-labelledby": labelId,
370
375
  "aria-describedby": description != null ? descriptionId : undefined
371
376
  // Roving tabindex lives on the treeitem row; inner action is not a
@@ -1 +1 @@
1
- {"version":3,"file":"useGridFocus.d.ts","sourceRoot":"","sources":["../../src/hooks/useGridFocus.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;IAEjD;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5D;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE3D;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IAExB;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEnC;;OAEG;IACH,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAEhD;;;;OAIG;IACH,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CAuYvB"}
1
+ {"version":3,"file":"useGridFocus.d.ts","sourceRoot":"","sources":["../../src/hooks/useGridFocus.ts"],"names":[],"mappings":"AAsBA;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC;IAEjD;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,WAAW,GAAG,IAAI,CAAC;IAE3D;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5D;;;;;OAKG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAE3D;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IAExB;;;;;;;;;;;;;;;;;;OAkBG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IACrE;;OAEG;IACH,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAEnC;;OAEG;IACH,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAEhD;;;;OAIG;IACH,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEnC;;OAEG;IACH,UAAU,EAAE,MAAM,IAAI,CAAC;IAEvB;;OAEG;IACH,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,EAC9D,OAAO,EAAE,mBAAmB,GAC3B,kBAAkB,CAAC,CAAC,CAAC,CAsZvB"}
@@ -163,7 +163,16 @@ export function useGridFocus(options) {
163
163
  for (const el of targets) {
164
164
  setTabIndex(el, el === tabbable ? 0 : -1);
165
165
  }
166
- }, [getFocusTargets, setTabIndex]);
166
+ // A cell that stopped being focusable (an aria-disabled day, for example,
167
+ // which stays reachable by focus) can still hold the stop from earlier
168
+ // navigation; it never stays tabbable, so the grid keeps one Tab stop.
169
+ for (const cell of getCells()) {
170
+ const el = cellFocusable(cell) ? null : resolveFocusTarget(cell);
171
+ if (el != null) {
172
+ setTabIndex(el, -1);
173
+ }
174
+ }
175
+ }, [getFocusTargets, getCells, cellFocusable, resolveFocusTarget, setTabIndex]);
167
176
 
168
177
  // Keep the tab stop valid across renders (cells added/removed, focusability
169
178
  // toggled). Runs after every commit but only when roving tabindex is on.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.7.3-canary.2468b8a",
3
+ "version": "0.7.3-canary.296edaf",
4
4
  "displayName": "Astryx Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -792,8 +792,8 @@
792
792
  "react-dom": ">=19.0.0"
793
793
  },
794
794
  "devDependencies": {
795
- "@astryxdesign/a11y-spec": "0.7.3-canary.2468b8a",
796
- "@astryxdesign/cli": "0.7.3-canary.2468b8a",
795
+ "@astryxdesign/a11y-spec": "0.7.3-canary.296edaf",
796
+ "@astryxdesign/cli": "0.7.3-canary.296edaf",
797
797
  "@babel/cli": "^7.29.7",
798
798
  "@babel/core": "^7.29.7",
799
799
  "@babel/preset-react": "^7.29.7",