@astryxdesign/core 0.1.9-canary.eff3e5f → 0.1.9-canary.f7bce66

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 (91) hide show
  1. package/dist/Card/Card.js +1 -1
  2. package/dist/Divider/Divider.d.ts +2 -2
  3. package/dist/Divider/Divider.d.ts.map +1 -1
  4. package/dist/Divider/Divider.js +13 -0
  5. package/dist/FileInput/FileInput.d.ts.map +1 -1
  6. package/dist/FileInput/FileInput.js +64 -47
  7. package/dist/List/List.d.ts.map +1 -1
  8. package/dist/List/List.js +6 -3
  9. package/dist/Outline/Outline.js +2 -2
  10. package/dist/Slider/Slider.d.ts.map +1 -1
  11. package/dist/Slider/Slider.js +26 -1
  12. package/dist/Spinner/Spinner.d.ts +3 -2
  13. package/dist/Spinner/Spinner.d.ts.map +1 -1
  14. package/dist/Spinner/Spinner.js +11 -2
  15. package/dist/TabList/TabList.d.ts +2 -11
  16. package/dist/TabList/TabList.d.ts.map +1 -1
  17. package/dist/TabList/TabList.js +5 -9
  18. package/dist/TabList/TabListContext.d.ts +0 -5
  19. package/dist/TabList/TabListContext.d.ts.map +1 -1
  20. package/dist/TabList/TabListContext.js +0 -5
  21. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  22. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  23. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  24. package/dist/Tooltip/useTooltip.js +17 -1
  25. package/dist/TopNav/TopNavItem.d.ts +3 -1
  26. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  27. package/dist/TopNav/TopNavItem.js +30 -3
  28. package/dist/astryx.umd.js +42 -42
  29. package/dist/astryx.umd.js.map +3 -3
  30. package/dist/hooks/useAnnounce.d.ts +3 -0
  31. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  32. package/dist/hooks/useAnnounce.js +39 -1
  33. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  34. package/dist/hooks/useFocusTrap.js +52 -11
  35. package/dist/hooks/useHotkeys.d.ts +9 -0
  36. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  37. package/dist/hooks/useHotkeys.js +9 -0
  38. package/dist/utils/plainDate.d.ts.map +1 -1
  39. package/dist/utils/plainDate.js +12 -3
  40. package/package.json +1 -1
  41. package/src/Card/Card.tsx +1 -1
  42. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  43. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  44. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  45. package/src/DateInput/DateInput.doc.mjs +6 -0
  46. package/src/DateRangeInput/DateRangeInput.doc.mjs +6 -0
  47. package/src/DateTimeInput/DateTimeInput.doc.mjs +6 -0
  48. package/src/Divider/Divider.test.tsx +32 -8
  49. package/src/Divider/Divider.tsx +14 -1
  50. package/src/FileInput/FileInput.doc.mjs +7 -1
  51. package/src/FileInput/FileInput.test.tsx +24 -7
  52. package/src/FileInput/FileInput.tsx +67 -43
  53. package/src/List/List.test.tsx +17 -29
  54. package/src/List/List.tsx +6 -1
  55. package/src/MultiSelector/MultiSelector.doc.mjs +6 -0
  56. package/src/NumberInput/NumberInput.doc.mjs +6 -0
  57. package/src/Outline/Outline.test.tsx +12 -12
  58. package/src/Outline/Outline.tsx +2 -2
  59. package/src/RadioList/RadioList.doc.mjs +6 -0
  60. package/src/Selector/Selector.doc.mjs +6 -0
  61. package/src/Slider/Slider.doc.mjs +6 -0
  62. package/src/Slider/Slider.test.tsx +52 -0
  63. package/src/Slider/Slider.tsx +28 -1
  64. package/src/Spinner/Spinner.test.tsx +10 -8
  65. package/src/Spinner/Spinner.tsx +15 -5
  66. package/src/Switch/Switch.doc.mjs +6 -0
  67. package/src/TabList/TabList.doc.mjs +0 -6
  68. package/src/TabList/TabList.test.tsx +3 -15
  69. package/src/TabList/TabList.tsx +6 -17
  70. package/src/TabList/TabListContext.ts +0 -6
  71. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  72. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  73. package/src/TextArea/TextArea.doc.mjs +6 -0
  74. package/src/TextInput/TextInput.doc.mjs +6 -0
  75. package/src/TimeInput/TimeInput.doc.mjs +6 -0
  76. package/src/Tokenizer/Tokenizer.doc.mjs +8 -1
  77. package/src/Tooltip/Tooltip.test.tsx +46 -0
  78. package/src/Tooltip/useTooltip.tsx +20 -0
  79. package/src/TopNav/TopNav.test.tsx +93 -2
  80. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  81. package/src/TopNav/TopNavItem.tsx +35 -6
  82. package/src/Typeahead/Typeahead.doc.mjs +6 -0
  83. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  84. package/src/doc-mjs.d.ts +19 -0
  85. package/src/hooks/useAnnounce.test.tsx +75 -2
  86. package/src/hooks/useAnnounce.ts +47 -1
  87. package/src/hooks/useFocusTrap.test.tsx +104 -0
  88. package/src/hooks/useFocusTrap.ts +61 -12
  89. package/src/hooks/useHotkeys.ts +9 -0
  90. package/src/utils/plainDate.test.ts +24 -6
  91. package/src/utils/plainDate.ts +8 -3
package/dist/Card/Card.js CHANGED
@@ -55,7 +55,7 @@ const styles = {
55
55
  withBorder: {
56
56
  kMzoRj: "x1litavf",
57
57
  ksu8eU: "x1y0btm7",
58
- kVAM5u: "xvy26l8",
58
+ kVAM5u: "x14i3s5s",
59
59
  kZCmMZ: "xs19ii7",
60
60
  kwRFfy: "x12frdag",
61
61
  kLKAdn: "x1nex4ik",
@@ -10,7 +10,7 @@
10
10
  * - /apps/storybook/stories/Divider.stories.tsx
11
11
  * - /packages/cli/templates/blocks/components/Divider/ (showcase blocks)
12
12
  */
13
- import type { ReactNode } from 'react';
13
+ import { type ReactNode } from 'react';
14
14
  import type { BaseProps } from '../BaseProps';
15
15
  /**
16
16
  * Extensible variant map for Divider.
@@ -71,7 +71,7 @@ export interface DividerProps extends BaseProps<HTMLDivElement> {
71
71
  * <Divider label="or" />
72
72
  * ```
73
73
  */
74
- export declare function Divider({ orientation, label, variant, isFullBleed, xstyle, className, style, ref, ...props }: DividerProps): import("react").JSX.Element;
74
+ export declare function Divider({ orientation, label, variant, isFullBleed, xstyle, className, style, ref, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }: DividerProps): import("react").JSX.Element;
75
75
  export declare namespace Divider {
76
76
  var displayName: string;
77
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Divider.d.ts","sourceRoot":"","sources":["../../src/Divider/Divider.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AACrC,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAY5C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC7D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IAExC;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAiED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,EACtB,WAA0B,EAC1B,KAAK,EACL,OAAkB,EAClB,WAAmB,EACnB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,YAAY,+BA+Cd;yBAzDe,OAAO"}
1
+ {"version":3,"file":"Divider.d.ts","sourceRoot":"","sources":["../../src/Divider/Divider.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAQ,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAY5C;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;CACd;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC7D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC;;;OAGG;IACH,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IAExC;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAiED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,EACtB,WAA0B,EAC1B,KAAK,EACL,OAAkB,EAClB,WAAmB,EACnB,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,GAAG,KAAK,EACT,EAAE,YAAY,+BA0Dd;yBAtEe,OAAO"}
@@ -14,6 +14,7 @@
14
14
  * - /apps/storybook/stories/Divider.stories.tsx
15
15
  * - /packages/cli/templates/blocks/components/Divider/ (showcase blocks)
16
16
  */
17
+ import { useId } from 'react';
17
18
  import * as stylex from '@stylexjs/stylex';
18
19
  import "../theme/tokens.stylex.js";
19
20
  import { colorVars, spacingVars, typeScaleVars, borderVars } from "../theme/tokens.stylex.js";
@@ -110,14 +111,25 @@ export function Divider({
110
111
  className,
111
112
  style,
112
113
  ref,
114
+ 'aria-label': ariaLabel,
115
+ 'aria-labelledby': ariaLabelledBy,
113
116
  ...props
114
117
  }) {
115
118
  const isHorizontal = orientation === 'horizontal';
119
+ const labelId = useId();
120
+
121
+ // A separator does not derive its accessible name from its content, so the
122
+ // rendered label must be referenced explicitly via aria-labelledby to be
123
+ // exposed as the separator's name (WCAG 1.3.1). An explicit aria-label or
124
+ // aria-labelledby from the consumer takes precedence.
125
+ const resolvedLabelledBy = ariaLabelledBy ?? (label && ariaLabel == null ? labelId : undefined);
116
126
  return /*#__PURE__*/_jsxs("div", {
117
127
  ref: ref,
118
128
  ...props,
119
129
  role: "separator",
120
130
  "aria-orientation": orientation,
131
+ "aria-label": ariaLabel,
132
+ "aria-labelledby": resolvedLabelledBy,
121
133
  ...mergeProps(themeProps('divider', {
122
134
  variant,
123
135
  orientation
@@ -125,6 +137,7 @@ export function Divider({
125
137
  children: [/*#__PURE__*/_jsx("div", {
126
138
  ...stylex.props(isHorizontal ? lineStyles.horizontalLine : lineStyles.verticalLine, lineStyles[variant])
127
139
  }), label && /*#__PURE__*/_jsx("div", {
140
+ id: labelId,
128
141
  ...{
129
142
  0: {
130
143
  className: "x2lah0s xrrkdod x141an7d x1ltkj2j xv1l7n4"
@@ -1 +1 @@
1
- {"version":3,"file":"FileInput.d.ts","sourceRoot":"","sources":["../../src/FileInput/FileInput.tsx"],"names":[],"mappings":"AAsCA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AAQlB,YAAY,EACV,WAAW,IAAI,eAAe,EAC9B,eAAe,IAAI,mBAAmB,GACvC,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AA+M9C,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,SAAS,EACT,UAAU,GAAG,cAAc,GAAG,OAAO,CACtC;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC5B;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAqB,EACrB,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,UAAkB,EAClB,OAAO,EACP,QAAQ,EACR,UAAkB,EAClB,eAAe,EACf,UAAkB,EAClB,SAAiB,EACjB,MAAM,EAAE,UAAU,EAClB,aAA0B,EAC1B,WAAW,EACX,WAAW,EACX,IAAc,EACd,UAAkB,EAClB,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,cAAc,+BAoYhB;yBA/Ze,SAAS"}
1
+ {"version":3,"file":"FileInput.d.ts","sourceRoot":"","sources":["../../src/FileInput/FileInput.tsx"],"names":[],"mappings":"AAsCA,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACxB,MAAM,UAAU,CAAC;AASlB,YAAY,EACV,WAAW,IAAI,eAAe,EAC9B,eAAe,IAAI,mBAAmB,GACvC,MAAM,UAAU,CAAC;AAElB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AA+M9C,MAAM,WAAW,cAAe,SAAQ,IAAI,CAC1C,SAAS,EACT,UAAU,GAAG,cAAc,GAAG,OAAO,CACtC;IACC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClC;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;OAEG;IACH,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;IAC5B;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,GAAG,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAC5B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,aAAqB,EACrB,KAAK,EACL,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,UAAkB,EAClB,OAAO,EACP,QAAQ,EACR,UAAkB,EAClB,eAAe,EACf,UAAkB,EAClB,SAAiB,EACjB,MAAM,EAAE,UAAU,EAClB,aAA0B,EAC1B,WAAW,EACX,WAAW,EACX,IAAc,EACd,UAAkB,EAClB,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,cAAc,+BA2ZhB;yBAtbe,SAAS"}
@@ -25,6 +25,7 @@ import { Spinner } from "../Spinner/index.js";
25
25
  import { VisuallyHidden } from "../VisuallyHidden/index.js";
26
26
  import { useAnnounce } from "../hooks/useAnnounce.js";
27
27
  import { useInputStatusIcon } from "../hooks/useInputStatusIcon.js";
28
+ import { useClickableContainer } from "../hooks/useClickableContainer.js";
28
29
  import { useTooltip } from "../Tooltip/index.js";
29
30
  import { mergeProps, mergeRefs } from "../utils/index.js";
30
31
  import { themeProps } from "../utils/themeProps.js";
@@ -203,6 +204,7 @@ export function FileInput({
203
204
  const statusMessageID = useId();
204
205
  const requiredID = useId();
205
206
  const inputRef = useRef(null);
207
+ const containerRef = useRef(null);
206
208
  const [isDragOver, setIsDragOver] = useState(false);
207
209
  const [validationError, setValidationError] = useState(null);
208
210
  const [, startTransition] = useTransition();
@@ -214,10 +216,10 @@ export function FileInput({
214
216
  const announce = useAnnounce();
215
217
 
216
218
  // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
217
- // tooltip listeners attach to the role="button" trigger (which already
218
- // exists) and the trigger stays perceivable via aria-disabled instead of the
219
- // native disabled attribute. Opening the picker is blocked by the isDisabled
220
- // guards in handleClick / handleKeyDown / handleFiles.
219
+ // tooltip listeners attach to the visible container (which stays hoverable)
220
+ // and the trigger stays perceivable via aria-disabled instead of the native
221
+ // disabled attribute. Opening the picker is blocked by the isDisabled guards
222
+ // in the handlers.
221
223
  const showsDisabledMessage = isDisabled && !!disabledMessage;
222
224
  const disabledMessageTooltip = useTooltip({
223
225
  placement: 'above',
@@ -236,11 +238,11 @@ export function FileInput({
236
238
  statusVariant
237
239
  });
238
240
 
239
- // Required state. `aria-required` is not a supported property of
240
- // role="button" in WAI-ARIA 1.2 (AT does not announce it there), so the
241
- // trigger instead points its aria-describedby at a visually hidden
242
- // "Required" span — mirroring the Field label's visible indicator (where
243
- // isOptional takes precedence) and the pattern Slider uses for its thumbs.
241
+ // Required state. The trigger is a real button, but AT does not reliably
242
+ // announce aria-required, so the trigger instead points its aria-describedby
243
+ // at a visually hidden "Required" span — mirroring the Field label's visible
244
+ // indicator (where isOptional takes precedence) and the pattern Slider uses
245
+ // for its thumbs.
244
246
  const conveysRequired = isRequired && !isOptional;
245
247
  const ariaDescribedBy = [description ? descriptionID : null, statusVariant !== 'tooltip' && status?.message ? statusMessageID : null,
246
248
  // The tooltip variant renders no message box; describe the input by the
@@ -302,12 +304,28 @@ export function FileInput({
302
304
  inputRef.current?.click();
303
305
  }
304
306
  }, [isDisabled]);
307
+
308
+ // Explicit keyboard activation so Enter/Space open the picker even where a
309
+ // synthetic keydown does not raise a native click. The isDisabled guard
310
+ // blocks activation while focusable-disabled.
305
311
  const handleKeyDown = useCallback(e => {
306
312
  if ((e.key === 'Enter' || e.key === ' ') && !isDisabled) {
307
313
  e.preventDefault();
308
314
  inputRef.current?.click();
309
315
  }
310
316
  }, [isDisabled]);
317
+
318
+ // Make the surface clickable without giving it an interactive role. Clicks on
319
+ // the nested clear/status controls are ignored by the hook, so those buttons
320
+ // are plain siblings — no nested-interactive violation.
321
+ const {
322
+ onClick: onContainerClick,
323
+ onMouseUp: onContainerMouseUp
324
+ } = useClickableContainer({
325
+ containerRef,
326
+ onClick: handleClick,
327
+ disabled: isDisabled
328
+ });
311
329
  const handleDragEnter = useCallback(e => {
312
330
  e.preventDefault();
313
331
  e.stopPropagation();
@@ -437,50 +455,49 @@ export function FileInput({
437
455
  width: width,
438
456
  children: [/*#__PURE__*/_jsxs("div", {
439
457
  ref: el => {
440
- // Anchor + hover/focus listeners for the disabled-message tooltip.
441
- // Handlers are gated internally by isEnabled, and anchor names
442
- // compose, so attaching unconditionally is safe.
458
+ containerRef.current = el;
459
+ // Anchor + hover/focus listeners for the disabled-message tooltip on
460
+ // the visible container (the focusable trigger is visually hidden, so
461
+ // anchoring there would place the tooltip at a 1px box). focusin
462
+ // bubbles from the trigger button, so the tooltip still opens on
463
+ // keyboard focus. Handlers are gated internally by isEnabled.
443
464
  disabledMessageTooltip.ref(el);
444
465
  },
445
- role: "button"
446
- // With a disabledMessage the trigger keeps focusability via
447
- // aria-disabled so the reason is focus-discoverable; opening the picker
448
- // is still blocked by the isDisabled guards in the handlers.
449
- ,
450
- tabIndex: isDisabled && !showsDisabledMessage ? -1 : 0,
451
- "aria-disabled": showsDisabledMessage ? 'true' : undefined,
452
- onClick: handleClick,
453
- onKeyDown: handleKeyDown
454
- // aria-label suppresses child content from the accessible name, so
455
- // compose the selected filenames into it — otherwise a screen-reader
456
- // user refocusing the control hears only the field label and cannot
457
- // tell what (if anything) is attached.
458
- ,
459
- "aria-label": hasFiles && fileNames ? t('@astryx.fileInput.triggerWithFiles', {
460
- label,
461
- fileNames
462
- }) : label,
463
- "aria-busy": isLoading || undefined
464
- // These describe the operable control, so they belong on the focusable
465
- // role="button" wrapper — not the hidden tabIndex={-1} file input the
466
- // user never focuses (forms-6). Required state is conveyed through
467
- // the visually hidden "Required" node in aria-describedby, not
468
- // aria-required, which role="button" does not support in ARIA 1.2.
469
- ,
470
- "aria-describedby": ariaDescribedBy
471
- // aria-invalid is likewise unsupported on role="button", but it stays:
472
- // a message-less error status (`status={{type: 'error'}}`) has no
473
- // described-by replacement, and some AT still honor the attribute, so
474
- // removing it would not be strictly better. Errors *with* a message
475
- // are described via statusMessageID above.
476
- ,
477
- "aria-invalid": status?.type === 'error' ? 'true' : undefined,
466
+ onClick: !isDisabled ? onContainerClick : undefined,
467
+ onMouseUp: !isDisabled ? onContainerMouseUp : undefined,
478
468
  ...dragDropProps,
479
469
  ...mergeProps(themeProps('file-input', {
480
470
  mode,
481
471
  status: status?.type ?? null
482
472
  }), stylex.props(isDropzone ? styles.dropzone : styles.compact, isDropzone && !isDisabled && styles.dropzoneHover, isDropzone && isDragOver && styles.dropzoneActive, isDropzone && isDisabled && styles.dropzoneDisabled, !isDropzone && isDisabled && styles.compactDisabled, status && statusBorderStyles[status.type], xstyle), className, style),
483
- children: [/*#__PURE__*/_jsx("input", {
473
+ children: [/*#__PURE__*/_jsx(VisuallyHidden, {
474
+ children: /*#__PURE__*/_jsx("button", {
475
+ type: "button"
476
+ // With a disabledMessage the trigger keeps focusability via
477
+ // aria-disabled so the reason is focus-discoverable; opening the
478
+ // picker is still blocked by the isDisabled guards in the handlers.
479
+ // Otherwise the native disabled attribute removes it from the tab
480
+ // order.
481
+ ,
482
+ disabled: isDisabled && !showsDisabledMessage,
483
+ tabIndex: isDisabled && !showsDisabledMessage ? -1 : 0,
484
+ "aria-disabled": showsDisabledMessage ? 'true' : undefined,
485
+ onClick: handleClick,
486
+ onKeyDown: handleKeyDown
487
+ // aria-label suppresses child content from the accessible name, so
488
+ // compose the selected filenames into it — otherwise a
489
+ // screen-reader user refocusing the control hears only the field
490
+ // label and cannot tell what (if anything) is attached.
491
+ ,
492
+ "aria-label": hasFiles && fileNames ? t('@astryx.fileInput.triggerWithFiles', {
493
+ label,
494
+ fileNames
495
+ }) : label,
496
+ "aria-busy": isLoading || undefined,
497
+ "aria-describedby": ariaDescribedBy,
498
+ "aria-invalid": status?.type === 'error' ? 'true' : undefined
499
+ })
500
+ }), /*#__PURE__*/_jsx("input", {
484
501
  ...rest,
485
502
  ref: mergeRefs(ref, inputRef),
486
503
  id: id,
@@ -490,7 +507,7 @@ export function FileInput({
490
507
  disabled: isDisabled,
491
508
  onChange: handleInputChange
492
509
  // The visually-hidden native input is never focused (tabIndex={-1});
493
- // its describedby/required/invalid live on the role="button" wrapper.
510
+ // its describedby/required/invalid live on the trigger button.
494
511
  ,
495
512
  "aria-hidden": "true",
496
513
  tabIndex: -1,
@@ -1 +1 @@
1
- {"version":3,"file":"List.d.ts","sourceRoot":"","sources":["../../src/List/List.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAiB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAIvB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,IAAI,SAAS,GAClC,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,SAAU,SAAQ,SAAS,CAC1C,gBAAgB,GAAG,gBAAgB,CACpC;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;IACrD;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,OAAoB,EACpB,WAAmB,EACnB,MAAM,EACN,SAAkB,EAClB,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,GACJ,EAAE,SAAS,+BAiDX;yBA7De,IAAI"}
1
+ {"version":3,"file":"List.d.ts","sourceRoot":"","sources":["../../src/List/List.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAiB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AAIvB,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,eAAe,IAAI,SAAS,GAClC,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,SAAU,SAAQ,SAAS,CAC1C,gBAAgB,GAAG,gBAAgB,CACpC;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,GAAG,gBAAgB,CAAC,CAAC;IACrD;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,WAAW,CAAC;IAEtB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;;;OAIG;IACH,SAAS,CAAC,EAAE,eAAe,CAAC;IAE5B;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,IAAI,CAAC,EACnB,QAAQ,EACR,OAAoB,EACpB,WAAmB,EACnB,MAAM,EACN,SAAkB,EAClB,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,GACJ,EAAE,SAAS,+BAsDX;yBAlEe,IAAI"}
package/dist/List/List.js CHANGED
@@ -106,9 +106,12 @@ export function List({
106
106
  ...(isOrdered && start != null && start !== 1 ? {
107
107
  start
108
108
  } : {}),
109
- ...(listStyle === 'none' && !isOrdered ? {
110
- role: 'list'
111
- } : {}),
109
+ // The base list style always sets list-style-type: none (markers are
110
+ // custom-rendered by ListItem), and Safari/VoiceOver drops implicit
111
+ // list semantics for lists styled with list-style: none. The explicit
112
+ // role restores "list, N items" announcements for every listStyle
113
+ // variant.
114
+ role: "list",
112
115
  ...mergeProps(themeProps('list', {
113
116
  density,
114
117
  listStyle
@@ -241,7 +241,7 @@ export function Outline({
241
241
  return;
242
242
  }
243
243
  const links = Array.from(list.querySelectorAll('a[href]'));
244
- const active = links.find(link => link.getAttribute('aria-current') === 'true');
244
+ const active = links.find(link => link.getAttribute('aria-current') === 'location');
245
245
  if (active == null) {
246
246
  return;
247
247
  }
@@ -326,7 +326,7 @@ export function Outline({
326
326
  role: "listitem",
327
327
  children: /*#__PURE__*/_jsx(LinkComponent, {
328
328
  href: `#${item.id}`,
329
- "aria-current": isActive ? 'true' : undefined,
329
+ "aria-current": isActive ? 'location' : undefined,
330
330
  onClick: handleClick(item.id),
331
331
  onKeyDown: handleKeyDown(item.id),
332
332
  ...mergeProps(themeProps('outline-item', {
@@ -1 +1 @@
1
- {"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../src/Slider/Slider.tsx"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAGhD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAO9C,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IAC3C,8DAA8D;IAC9D,KAAK,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,iEAAiE;IACjE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,8CAA8C;IAC9C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7C,iEAAiE;IACjE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAChD,8CAA8C;IAC9C,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAyN/D;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,EAAC,GAAG,EAAE,GAAG,KAAK,EAAC,EAAE,WAAW,+BA0mBlD;yBA1mBe,MAAM"}
1
+ {"version":3,"file":"Slider.d.ts","sourceRoot":"","sources":["../../src/Slider/Slider.tsx"],"names":[],"mappings":"AAyCA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AAGhD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAO9C,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,8FAA8F;IAC9F,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uCAAuC;IACvC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,uEAAuE;IACvE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gCAAgC;IAChC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uDAAuD;IACvD,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,uEAAuE;IACvE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACxC,6DAA6D;IAC7D,YAAY,CAAC,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;IAC3C,8DAA8D;IAC9D,KAAK,CAAC,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,yCAAyC;IACzC,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,iEAAiE;IACjE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,8CAA8C;IAC9C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAC7C,iEAAiE;IACjE,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;IAChD,8CAA8C;IAC9C,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAoP/D;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CAAC,EAAC,GAAG,EAAE,GAAG,KAAK,EAAC,EAAE,WAAW,+BA0mBlD;yBA1mBe,MAAM"}
@@ -49,12 +49,37 @@ const THUMB_SIZE = 20;
49
49
  function clamp(val, min, max) {
50
50
  return Math.min(Math.max(val, min), max);
51
51
  }
52
+
53
+ /**
54
+ * Number of decimal places a value carries, including values in exponent
55
+ * notation (e.g. 1e-7 → 7). Used to round away binary floating-point error
56
+ * after step arithmetic.
57
+ */
58
+ function getDecimalPrecision(num) {
59
+ if (Math.abs(num) < 1) {
60
+ const parts = num.toExponential().split('e-');
61
+ if (parts.length === 2) {
62
+ const mantissaDecimals = parts[0].split('.')[1]?.length ?? 0;
63
+ return mantissaDecimals + parseInt(parts[1], 10);
64
+ }
65
+ }
66
+ const decimalPart = String(num).split('.')[1];
67
+ return decimalPart ? decimalPart.length : 0;
68
+ }
52
69
  function snapToStep(val, min, step) {
53
70
  if (step <= 0) {
54
71
  return val;
55
72
  }
56
73
  const steps = Math.round((val - min) / step);
57
- return min + steps * step;
74
+ const snapped = min + steps * step;
75
+ // `min + steps * step` accumulates binary floating-point error with
76
+ // fractional steps (0 + 3 * 0.1 → 0.30000000000000004), which leaks into
77
+ // onChange/onChangeEnd payloads, aria-valuenow, and the value tooltip.
78
+ // Snapped values can never carry more decimals than min/step combined, so
79
+ // rounding to that precision removes only the error.
80
+ const precision = Math.min(Math.max(getDecimalPrecision(min), getDecimalPrecision(step)), 20 // toFixed() throws past 20 digits
81
+ );
82
+ return Number(snapped.toFixed(precision));
58
83
  }
59
84
  function getPercent(val, min, max) {
60
85
  if (max === min) {
@@ -60,8 +60,9 @@ export interface SpinnerProps extends BaseProps<HTMLSpanElement> {
60
60
  * Visible content displayed below the spinner.
61
61
  * Accepts a string or ReactNode for rich content.
62
62
  *
63
- * When `label` is a string, it is also used as the accessible name
64
- * (aria-label) unless `aria-label` is explicitly set.
63
+ * When `label` is a string, the visible text also provides the accessible
64
+ * name of the status element (via aria-labelledby, avoiding a duplicate
65
+ * announcement) unless `aria-label` is explicitly set.
65
66
  *
66
67
  * @example
67
68
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/Spinner/Spinner.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAoB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAIxD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAc5C,QAAA,MAAM,KAAK;;;;;;;;;;;;;;;;;CAKV,CAAC;AAiDF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,KAAK,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExE,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC9D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,EACtB,IAAW,EACX,KAAiB,EACjB,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,GAAG,SAAS,EACb,EAAE,YAAY,+BA4Id;yBAvJe,OAAO"}
1
+ {"version":3,"file":"Spinner.d.ts","sourceRoot":"","sources":["../../src/Spinner/Spinner.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAA2B,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAI/D,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAc5C,QAAA,MAAM,KAAK;;;;;;;;;;;;;;;;;CAKV,CAAC;AAiDF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,KAAK,CAAC;AAE7C,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExE,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,eAAe,CAAC;IAC9D,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACjC;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,EACtB,IAAW,EACX,KAAiB,EACjB,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,YAAY,EAAE,SAAS,EACvB,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,GAAG,SAAS,EACb,EAAE,YAAY,+BAqJd;yBAhKe,OAAO"}
@@ -15,7 +15,7 @@
15
15
  * - /apps/storybook/stories/Spinner.stories.tsx
16
16
  * - /packages/cli/templates/blocks/components/Spinner/ (showcase blocks)
17
17
  */
18
- import { useEffect, useRef } from 'react';
18
+ import { useEffect, useId, useRef } from 'react';
19
19
  import * as stylex from '@stylexjs/stylex';
20
20
  import "../theme/tokens.stylex.js";
21
21
  import { durationVars, spacingVars } from "../theme/tokens.stylex.js";
@@ -183,13 +183,21 @@ export function Spinner({
183
183
  } = SIZES[size];
184
184
  const frameSize = diameter + border * 2;
185
185
  const hasLabel = label != null;
186
+ const labelId = useId();
187
+
188
+ // When a visible string label renders (and no explicit aria-label is set),
189
+ // name the status element from the visible Text via aria-labelledby instead
190
+ // of duplicating the same string as aria-label — the duplicate would be
191
+ // announced twice by screen readers (WCAG 4.1.2).
192
+ const namedByVisibleLabel = hasLabel && typeof label === 'string' && ariaLabel == null;
186
193
 
187
194
  // Resolve accessible name: explicit aria-label > string label > "Loading"
188
195
  const resolvedAriaLabel = ariaLabel ?? (typeof label === 'string' ? label : undefined) ?? 'Loading';
189
196
  const spinner = /*#__PURE__*/_jsx("span", {
190
197
  ref: hasLabel ? undefined : ref,
191
198
  role: "status",
192
- "aria-label": resolvedAriaLabel,
199
+ "aria-label": namedByVisibleLabel ? undefined : resolvedAriaLabel,
200
+ "aria-labelledby": namedByVisibleLabel ? labelId : undefined,
193
201
  "data-testid": hasLabel ? undefined : testId,
194
202
  ...(hasLabel ? {} : restProps),
195
203
  ...mergeProps(hasLabel ? '' : themeProps('spinner', {
@@ -219,6 +227,7 @@ export function Spinner({
219
227
  shade
220
228
  }), stylex.props(styles.wrapper, xstyle), className, style),
221
229
  children: [spinner, typeof label === 'string' ? /*#__PURE__*/_jsx(Text, {
230
+ id: labelId,
222
231
  type: "body",
223
232
  weight: "bold",
224
233
  children: label
@@ -14,7 +14,7 @@
14
14
  */
15
15
  import React, { type ReactNode } from 'react';
16
16
  import type { BaseProps } from '../BaseProps';
17
- import type { TabListOrientation, TabListSize } from './TabListContext';
17
+ import type { TabListSize } from './TabListContext';
18
18
  import { EDGE_COMP_ATTR } from '../Layout/edgeCompensation.stylex';
19
19
  export interface TabListProps extends Omit<BaseProps<HTMLElement>, 'onChange'> {
20
20
  ref?: React.Ref<HTMLElement>;
@@ -44,15 +44,6 @@ export interface TabListProps extends Omit<BaseProps<HTMLElement>, 'onChange'> {
44
44
  * @default false
45
45
  */
46
46
  hasDivider?: boolean;
47
- /**
48
- * Orientation of the tab strip, controlling which arrow keys move
49
- * focus between tabs.
50
- * - `'horizontal'` (default): ArrowLeft / ArrowRight (ArrowUp / ArrowDown
51
- * also work per the WAI-ARIA APG).
52
- * - `'vertical'`: ArrowUp / ArrowDown (ArrowLeft / ArrowRight also work).
53
- * @default 'horizontal'
54
- */
55
- orientation?: TabListOrientation;
56
47
  /**
57
48
  * Tab and TabMenu children.
58
49
  */
@@ -74,7 +65,7 @@ export interface TabListProps extends Omit<BaseProps<HTMLElement>, 'onChange'> {
74
65
  * </TabList>
75
66
  * ```
76
67
  */
77
- export declare function TabList({ ref, value, onChange, size: sizeProp, layout, hasDivider, orientation, xstyle, className, style, children, onKeyDown: onKeyDownProp, onFocus: onFocusProp, onBlur: onBlurProp, 'aria-label': ariaLabelFromProps, 'aria-orientation': _ariaOrientation, [EDGE_COMP_ATTR]: _edgeCompAttr, ...restProps }: TabListProps): React.JSX.Element;
68
+ export declare function TabList({ ref, value, onChange, size: sizeProp, layout, hasDivider, xstyle, className, style, children, onKeyDown: onKeyDownProp, onFocus: onFocusProp, onBlur: onBlurProp, 'aria-label': ariaLabelFromProps, 'aria-orientation': _ariaOrientation, [EDGE_COMP_ATTR]: _edgeCompAttr, ...restProps }: TabListProps): React.JSX.Element;
78
69
  export declare namespace TabList {
79
70
  var displayName: string;
80
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TabList.d.ts","sourceRoot":"","sources":["../../src/TabList/TabList.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,EAAuB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGlE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAC,kBAAkB,EAAE,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAKtE,OAAO,EAAC,cAAc,EAAC,MAAM,mCAAmC,CAAC;AAWjE,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAC5E,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AA4BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,EACtB,GAAG,EACH,KAAK,EACL,QAAQ,EACR,IAAI,EAAE,QAAQ,EACd,MAAc,EACd,UAAkB,EAClB,WAA0B,EAC1B,MAAM,EACN,SAAS,EACT,KAAK,EACL,QAAQ,EACR,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,kBAAkB,EAChC,kBAAkB,EAAE,gBAAgB,EACpC,CAAC,cAAc,CAAC,EAAE,aAAa,EAC/B,GAAG,SAAS,EACb,EAAE,YAAY,qBAmGd;yBAtHe,OAAO"}
1
+ {"version":3,"file":"TabList.d.ts","sourceRoot":"","sources":["../../src/TabList/TabList.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,EAAuB,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAGlE,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAE5C,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAKlD,OAAO,EAAC,cAAc,EAAC,MAAM,mCAAmC,CAAC;AAWjE,MAAM,WAAW,YAAa,SAAQ,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,UAAU,CAAC;IAC5E,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACxB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AA4BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,OAAO,CAAC,EACtB,GAAG,EACH,KAAK,EACL,QAAQ,EACR,IAAI,EAAE,QAAQ,EACd,MAAc,EACd,UAAkB,EAClB,MAAM,EACN,SAAS,EACT,KAAK,EACL,QAAQ,EACR,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,kBAAkB,EAChC,kBAAkB,EAAE,gBAAgB,EACpC,CAAC,cAAc,CAAC,EAAE,aAAa,EAC/B,GAAG,SAAS,EACb,EAAE,YAAY,qBAkGd;yBApHe,OAAO"}
@@ -82,7 +82,6 @@ export function TabList({
82
82
  size: sizeProp,
83
83
  layout = 'hug',
84
84
  hasDivider = false,
85
- orientation = 'horizontal',
86
85
  xstyle,
87
86
  className,
88
87
  style,
@@ -102,14 +101,13 @@ export function TabList({
102
101
  // Roving-tabindex keyboard navigation across the tab strip via the shared
103
102
  // hook. `orientation: 'both'` accepts both arrow axes per the WAI-ARIA APG
104
103
  // allowance for tab strips (ArrowRight/ArrowDown advance, ArrowLeft/ArrowUp
105
- // retreat) regardless of the component's `orientation` prop, which only
106
- // drives the keyboard hint badge (see useKeyboardHint below). We do not set
107
- // `aria-orientation` on the `<nav>`: that attribute is invalid on the
108
- // navigation role and triggers an axe `aria-allowed-attr` violation.
104
+ // retreat). We do not set `aria-orientation` on the `<nav>`: that attribute
105
+ // is invalid on the navigation role and triggers an axe `aria-allowed-attr`
106
+ // violation.
109
107
  //
110
108
  // `hasRovingTabIndex` makes the hook own the single tab stop: it stamps
111
109
  // tabindex 0/-1, repairs the stop on mount and as stops mount/unmount or
112
- // toggle disabled, and — via `handleFocus` on the nav — keeps the stop in
110
+ // toggle disabled, and -- via `handleFocus` on the nav -- keeps the stop in
113
111
  // sync after clicks or programmatic focus. Individual Tabs still render
114
112
  // `tabIndex={isSelected ? 0 : -1}` (see Tab.tsx) as the initial source of
115
113
  // truth; the hook's repair preserves an existing tab stop and only promotes
@@ -128,9 +126,7 @@ export function TabList({
128
126
  onKeyDown: onHintKeyDown,
129
127
  onFocus: onHintFocus,
130
128
  onBlur: onHintBlur
131
- } = useKeyboardHint({
132
- orientation
133
- });
129
+ } = useKeyboardHint();
134
130
  const contextValue = useMemo(() => ({
135
131
  value,
136
132
  onChange,
@@ -9,11 +9,6 @@ export type TabListSize = 'sm' | 'md' | 'lg';
9
9
  * - `'fill'`: tabs stretch equally to fill the container width.
10
10
  */
11
11
  export type TabListLayout = 'hug' | 'fill';
12
- /**
13
- * Orientation of the tab strip. Controls which arrow keys move focus
14
- * between tabs and the reported `aria-orientation`.
15
- */
16
- export type TabListOrientation = 'horizontal' | 'vertical';
17
12
  /**
18
13
  * Context for communicating value/onChange/size/layout from TabList to children.
19
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"TabListContext.d.ts","sourceRoot":"","sources":["../../src/TabList/TabListContext.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;AAE3C;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG,UAAU,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,eAAO,MAAM,cAAc,qDAAkD,CAAC;AAG9E;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CASvD"}
1
+ {"version":3,"file":"TabListContext.d.ts","sourceRoot":"","sources":["../../src/TabList/TabListContext.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAC;AAE3C;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED,eAAO,MAAM,cAAc,qDAAkD,CAAC;AAG9E;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,mBAAmB,CASvD"}
@@ -23,11 +23,6 @@ import { createContext, use } from 'react';
23
23
  * - `'fill'`: tabs stretch equally to fill the container width.
24
24
  */
25
25
 
26
- /**
27
- * Orientation of the tab strip. Controls which arrow keys move focus
28
- * between tabs and the reported `aria-orientation`.
29
- */
30
-
31
26
  /**
32
27
  * Context for communicating value/onChange/size/layout from TabList to children.
33
28
  */
@@ -1 +1 @@
1
- {"version":3,"file":"useTableSelection.d.ts","sourceRoot":"","sources":["../../../../src/Table/plugins/selection/useTableSelection.tsx"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAC,WAAW,EAAkC,MAAM,aAAa,CAAC;AAQ9E,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxE,uCAAuC;IACvC,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACxC,6EAA6E;IAC7E,YAAY,EAAE,CAAC,KAAK,EAAE;QAAC,IAAI,EAAE,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAC,KAAK,IAAI,CAAC;IAC9D,kDAAkD;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE;QAAC,aAAa,EAAE,OAAO,CAAA;KAAC,KAAK,IAAI,CAAC;IACvD,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAC3C,oGAAoG;IACpG,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACxC;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;CACnC;AAuND,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,WAAW,CAAC,CAAC,CAAC,CAmFhB"}
1
+ {"version":3,"file":"useTableSelection.d.ts","sourceRoot":"","sources":["../../../../src/Table/plugins/selection/useTableSelection.tsx"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAC,WAAW,EAAkC,MAAM,aAAa,CAAC;AAQ9E,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACxE,uCAAuC;IACvC,iBAAiB,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACxC,6EAA6E;IAC7E,YAAY,EAAE,CAAC,KAAK,EAAE;QAAC,IAAI,EAAE,CAAC,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAC,KAAK,IAAI,CAAC;IAC9D,kDAAkD;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE;QAAC,aAAa,EAAE,OAAO,CAAA;KAAC,KAAK,IAAI,CAAC;IACvD,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,OAAO,CAAC;IAChC,iFAAiF;IACjF,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC;IACnC,+FAA+F;IAC/F,mBAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IAC3C,oGAAoG;IACpG,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;IACxC;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;CACnC;AAuND,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,MAAM,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACjC,WAAW,CAAC,CAAC,CAAC,CAsFhB"}
@@ -279,6 +279,9 @@ export function useTableSelection(config) {
279
279
  }
280
280
  applyRowSelectionStyle(el, store.getConfig().getIsItemSelected(item));
281
281
  });
282
+ return () => {
283
+ unsub();
284
+ };
282
285
  };
283
286
  return {
284
287
  ...props,
@@ -1 +1 @@
1
- {"version":3,"file":"useTooltip.d.ts","sourceRoot":"","sources":["../../src/Tooltip/useTooltip.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAsD3B;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEtC;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;IACH,aAAa,EAAE,CACb,QAAQ,EAAE,SAAS,EACnB,KAAK,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,KAC5C,SAAS,CAAC;CAChB;AAyBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CAkQtE"}
1
+ {"version":3,"file":"useTooltip.d.ts","sourceRoot":"","sources":["../../src/Tooltip/useTooltip.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAKL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAEf,OAAO,EAEL,KAAK,kBAAkB,EACvB,KAAK,cAAc,EACnB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAsD3B;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,SAAS,CAAC,EAAE,cAAc,CAAC;IAE3B;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IAEpB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,GAAG,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAE9B;;;OAGG;IACH,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEtC;;;;OAIG;IACH,cAAc,EAAE,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzC;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;;;;OAOG;IACH,aAAa,EAAE,CACb,QAAQ,EAAE,SAAS,EACnB,KAAK,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,KAC5C,SAAS,CAAC;CAChB;AAyBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,aAAa,CAsRtE"}
@@ -201,6 +201,19 @@ export function useTooltip(options = {}) {
201
201
  scheduleHide();
202
202
  }, [scheduleHide]);
203
203
 
204
+ // Pressing the trigger hides its own tooltip: once the control is activated
205
+ // the hint has served its purpose, and a tooltip lingering over a
206
+ // just-pressed control reads as stale. Fires on pointerdown so it feels
207
+ // immediate. Uncontrolled tooltips only — a controlled tooltip's visibility
208
+ // is owned by the consumer. `layer.hide()` self-guards when already closed.
209
+ const handlePointerDown = useCallback(() => {
210
+ if (isOpen !== undefined) {
211
+ return;
212
+ }
213
+ clearTimeouts();
214
+ layer.hide();
215
+ }, [isOpen, clearTimeouts, layer]);
216
+
204
217
  // Interaction ref that handles event listeners only
205
218
  const interactionRef = useCallback(el => {
206
219
  // Cleanup previous element
@@ -209,11 +222,14 @@ export function useTooltip(options = {}) {
209
222
  triggerRef.current.removeEventListener('mouseleave', handleMouseLeave);
210
223
  triggerRef.current.removeEventListener('focusin', handleFocusIn);
211
224
  triggerRef.current.removeEventListener('focusout', handleFocusOut);
225
+ triggerRef.current.removeEventListener('pointerdown', handlePointerDown);
212
226
  }
213
227
  if (el) {
214
228
  // Attach hover listeners
215
229
  el.addEventListener('mouseenter', handleMouseEnter);
216
230
  el.addEventListener('mouseleave', handleMouseLeave);
231
+ // Press-to-dismiss: activating the trigger hides its own tooltip.
232
+ el.addEventListener('pointerdown', handlePointerDown);
217
233
 
218
234
  // Attach focus listeners based on focusTrigger option
219
235
  const shouldAttachFocus = focusTrigger === 'always' || focusTrigger === 'auto' && isFocusable(el);
@@ -223,7 +239,7 @@ export function useTooltip(options = {}) {
223
239
  }
224
240
  }
225
241
  triggerRef.current = el;
226
- }, [focusTrigger, handleMouseEnter, handleMouseLeave, handleFocusIn, handleFocusOut]);
242
+ }, [focusTrigger, handleMouseEnter, handleMouseLeave, handleFocusIn, handleFocusOut, handlePointerDown]);
227
243
 
228
244
  // Combined ref - shorthand for calling both positionRef and interactionRef
229
245
  const ref = useCallback(el => {
@@ -47,6 +47,8 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
47
47
  isSelected?: boolean;
48
48
  /**
49
49
  * Whether the nav item is disabled.
50
+ * A disabled item renders as a plain anchor without an href (and without
51
+ * target), so it cannot navigate and is removed from the tab order.
50
52
  * @default false
51
53
  */
52
54
  isDisabled?: boolean;
@@ -91,7 +93,7 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
91
93
  * />
92
94
  * ```
93
95
  */
94
- export declare function TopNavItem({ as, label, isSelected, isDisabled, isIconOnly, icon, children, size, xstyle, className, style, ref, ...props }: TopNavItemProps): import("react").JSX.Element;
96
+ export declare function TopNavItem({ as, href, target, onClick, label, isSelected, isDisabled, isIconOnly, icon, children, size, xstyle, className, style, ref, ...props }: TopNavItemProps): import("react").JSX.Element;
95
97
  export declare namespace TopNavItem {
96
98
  var displayName: string;
97
99
  }