@astryxdesign/core 0.3.0-canary.ccb5ca9 → 0.3.0-canary.cd0b9f6

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 (122) hide show
  1. package/dist/AlertDialog/AlertDialog.d.ts +10 -2
  2. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/dist/AlertDialog/AlertDialog.js +22 -3
  4. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  5. package/dist/CheckboxInput/CheckboxInput.js +35 -125
  6. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  7. package/dist/CodeBlock/CodeBlock.js +40 -47
  8. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
  9. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  10. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
  11. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
  12. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  13. package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
  14. package/dist/Indicator/CheckIndicator.d.ts +26 -0
  15. package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
  16. package/dist/Indicator/CheckIndicator.js +151 -0
  17. package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
  18. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
  19. package/dist/Indicator/CheckboxIndicator.js +173 -0
  20. package/dist/Indicator/RadioIndicator.d.ts +23 -0
  21. package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
  22. package/dist/Indicator/RadioIndicator.js +137 -0
  23. package/dist/Indicator/index.d.ts +24 -0
  24. package/dist/Indicator/index.d.ts.map +1 -0
  25. package/dist/Indicator/index.js +26 -0
  26. package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
  27. package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
  28. package/dist/Indicator/indicator.markers.stylex.js +21 -0
  29. package/dist/Indicator/indicatorRegistry.d.ts +71 -0
  30. package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
  31. package/dist/Indicator/indicatorRegistry.js +93 -0
  32. package/dist/Indicator/types.d.ts +147 -0
  33. package/dist/Indicator/types.d.ts.map +1 -0
  34. package/dist/Indicator/types.js +1 -0
  35. package/dist/Indicator/useIndicator.d.ts +18 -0
  36. package/dist/Indicator/useIndicator.d.ts.map +1 -0
  37. package/dist/Indicator/useIndicator.js +30 -0
  38. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  39. package/dist/RadioList/RadioListItem.js +29 -84
  40. package/dist/Selector/Selector.d.ts.map +1 -1
  41. package/dist/Selector/Selector.js +10 -8
  42. package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
  43. package/dist/Timestamp/TimestampHoverCard.js +16 -34
  44. package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
  45. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  46. package/dist/TopNav/TopNavMegaMenu.js +67 -20
  47. package/dist/astryx.css +7 -15
  48. package/dist/astryx.umd.js +49 -49
  49. package/dist/astryx.umd.js.map +4 -4
  50. package/dist/hooks/index.d.ts +3 -0
  51. package/dist/hooks/index.d.ts.map +1 -1
  52. package/dist/hooks/index.js +2 -0
  53. package/dist/hooks/useClipboard.d.ts +59 -0
  54. package/dist/hooks/useClipboard.d.ts.map +1 -0
  55. package/dist/hooks/useClipboard.js +106 -0
  56. package/dist/hooks/useIndicatorFocusRing.d.ts +29 -0
  57. package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
  58. package/dist/hooks/useIndicatorFocusRing.js +97 -0
  59. package/dist/index.d.ts +1 -0
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +1 -0
  62. package/dist/theme/defineTheme.d.ts +16 -0
  63. package/dist/theme/defineTheme.d.ts.map +1 -1
  64. package/dist/theme/defineTheme.js +8 -0
  65. package/dist/theme/index.d.ts +1 -0
  66. package/dist/theme/index.d.ts.map +1 -1
  67. package/dist/utils/focusOutline.stylex.d.ts +33 -0
  68. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  69. package/dist/utils/focusOutline.stylex.js +35 -0
  70. package/dist/utils/themeProps.d.ts +20 -1
  71. package/dist/utils/themeProps.d.ts.map +1 -1
  72. package/dist/utils/themeProps.js +8 -2
  73. package/package.json +7 -2
  74. package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
  75. package/src/AlertDialog/AlertDialog.test.tsx +208 -1
  76. package/src/AlertDialog/AlertDialog.tsx +21 -3
  77. package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
  78. package/src/CheckboxInput/CheckboxInput.test.tsx +83 -0
  79. package/src/CheckboxInput/CheckboxInput.tsx +44 -202
  80. package/src/CodeBlock/CodeBlock.doc.mjs +1 -0
  81. package/src/CodeBlock/CodeBlock.test.tsx +24 -0
  82. package/src/CodeBlock/CodeBlock.tsx +30 -61
  83. package/src/DropdownMenu/DropdownMenu.doc.mjs +0 -5
  84. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
  85. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
  86. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
  87. package/src/Indicator/CheckIndicator.tsx +168 -0
  88. package/src/Indicator/CheckboxIndicator.tsx +253 -0
  89. package/src/Indicator/Indicator.doc.mjs +279 -0
  90. package/src/Indicator/Indicator.test.tsx +284 -0
  91. package/src/Indicator/RadioIndicator.tsx +202 -0
  92. package/src/Indicator/index.ts +45 -0
  93. package/src/Indicator/indicator.markers.stylex.ts +19 -0
  94. package/src/Indicator/indicatorRegistry.test.tsx +106 -0
  95. package/src/Indicator/indicatorRegistry.ts +120 -0
  96. package/src/Indicator/types.ts +163 -0
  97. package/src/Indicator/useIndicator.ts +39 -0
  98. package/src/RadioList/RadioList.doc.mjs +4 -2
  99. package/src/RadioList/RadioListItem.tsx +31 -130
  100. package/src/Selector/Selector.test.tsx +59 -1
  101. package/src/Selector/Selector.tsx +57 -46
  102. package/src/Timestamp/TimestampHoverCard.tsx +13 -35
  103. package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
  104. package/src/TopNav/TopNavMegaMenu.tsx +83 -24
  105. package/src/hooks/index.ts +4 -0
  106. package/src/hooks/useClipboard.doc.mjs +86 -0
  107. package/src/hooks/useClipboard.test.tsx +151 -0
  108. package/src/hooks/useClipboard.ts +135 -0
  109. package/src/hooks/useIndicatorFocusRing.tsx +121 -0
  110. package/src/index.ts +1 -0
  111. package/src/theme/defineTheme.ts +24 -0
  112. package/src/theme/index.ts +13 -0
  113. package/src/utils/focusOutline.stylex.ts +35 -0
  114. package/src/utils/themeProps.ts +26 -4
  115. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
  116. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
  117. package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
  118. package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
  119. package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
  120. package/dist/RadioList/radio.markers.stylex.js +0 -12
  121. package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
  122. package/src/RadioList/radio.markers.stylex.ts +0 -10
@@ -22,7 +22,8 @@ export interface AlertDialogProps extends BaseProps<HTMLDialogElement> {
22
22
  isOpen: boolean;
23
23
  /**
24
24
  * Renders alert dialog content inline without modal behavior.
25
- * For documentation previews and showcases only.
25
+ * For documentation previews and showcases only. The inline path is not a
26
+ * modal, so it renders `role="group"` rather than `role="alertdialog"`.
26
27
  * @default false
27
28
  */
28
29
  isInline?: boolean;
@@ -73,9 +74,16 @@ export interface AlertDialogProps extends BaseProps<HTMLDialogElement> {
73
74
  /**
74
75
  * A confirmation dialog for destructive or irreversible actions.
75
76
  *
77
+ * Implements the WAI-ARIA APG Alert Dialog pattern:
78
+ * https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/
79
+ *
76
80
  * Uses `role="alertdialog"` and requires explicit user action to dismiss.
77
81
  * Cannot be dismissed by clicking outside. Escape key triggers cancel.
78
- * Initial focus goes to the cancel button (least destructive action).
82
+ * Initial focus goes to the cancel button (least destructive action), pinned
83
+ * with `data-autofocus` so it survives any change to the footer's order.
84
+ *
85
+ * The `isInline` preview path is not modal, so it renders `role="group"`
86
+ * instead — the alertdialog role would promise modality it does not have.
79
87
  *
80
88
  * @example
81
89
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"AlertDialog.d.ts","sourceRoot":"","sources":["../../src/AlertDialog/AlertDialog.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA2B,MAAM,OAAO,CAAC;AAQhD,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAK5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACpE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAE3C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAE9B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC;IAExB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,WAAW,EACX,WAAW,EAAE,oBAAoB,EACjC,WAAW,EACX,aAA6B,EAC7B,eAAe,EACf,QAAQ,EACR,KAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,IAAI,EACR,EAAE,gBAAgB,qBAwDlB;yBA1Ee,WAAW"}
1
+ {"version":3,"file":"AlertDialog.d.ts","sourceRoot":"","sources":["../../src/AlertDialog/AlertDialog.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAA2B,MAAM,OAAO,CAAC;AAQhD,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAK5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,iBAAiB,CAAC;IACpE,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC;IAE3C;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAE9B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,QAAQ,EAAE,MAAM,OAAO,CAAC;IAExB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,GAAG,EACH,MAAM,EACN,QAAQ,EACR,YAAY,EACZ,KAAK,EACL,WAAW,EACX,WAAW,EAAE,oBAAoB,EACjC,WAAW,EACX,aAA6B,EAC7B,eAAe,EACf,QAAQ,EACR,KAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,aAAa,EAAE,MAAM,EACrB,GAAG,IAAI,EACR,EAAE,gBAAgB,qBAkElB;yBApFe,WAAW"}
@@ -31,9 +31,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
31
31
  /**
32
32
  * A confirmation dialog for destructive or irreversible actions.
33
33
  *
34
+ * Implements the WAI-ARIA APG Alert Dialog pattern:
35
+ * https://www.w3.org/WAI/ARIA/apg/patterns/alertdialog/
36
+ *
34
37
  * Uses `role="alertdialog"` and requires explicit user action to dismiss.
35
38
  * Cannot be dismissed by clicking outside. Escape key triggers cancel.
36
- * Initial focus goes to the cancel button (least destructive action).
39
+ * Initial focus goes to the cancel button (least destructive action), pinned
40
+ * with `data-autofocus` so it survives any change to the footer's order.
41
+ *
42
+ * The `isInline` preview path is not modal, so it renders `role="group"`
43
+ * instead — the alertdialog role would promise modality it does not have.
37
44
  *
38
45
  * @example
39
46
  * ```
@@ -80,8 +87,14 @@ export function AlertDialog({
80
87
  isInline: isInline,
81
88
  onOpenChange: onOpenChange,
82
89
  width: width,
83
- purpose: "form",
84
- role: "alertdialog",
90
+ purpose: "form"
91
+ // `alertdialog` is a modal role: it promises an interruption the user
92
+ // has to deal with, a focus trap, and an inert page behind it. The
93
+ // inline path renders a plain always-present div with none of that, so
94
+ // the role would misdescribe it. `group` keeps the title and
95
+ // description associated with a container without claiming a dialog.
96
+ ,
97
+ role: isInline ? 'group' : 'alertdialog',
85
98
  "aria-labelledby": titleId,
86
99
  "aria-describedby": descriptionId,
87
100
  ...mergeProps(themeProps('alert-dialog'), {
@@ -111,6 +124,12 @@ export function AlertDialog({
111
124
  variant: "ghost",
112
125
  label: cancelLabel,
113
126
  onClick: handleCancel
127
+ // Dialog focuses [data-autofocus] itself after showModal(),
128
+ // because React's autoFocus runs during commit while the
129
+ // dialog is still invisible. Cancel is the least destructive
130
+ // choice, so it is the one that should be preselected.
131
+ ,
132
+ "data-autofocus": true
114
133
  }), /*#__PURE__*/_jsx(Button, {
115
134
  variant: actionVariant,
116
135
  label: actionLabel,
@@ -1 +1 @@
1
- {"version":3,"file":"CheckboxInput.d.ts","sourceRoot":"","sources":["../../src/CheckboxInput/CheckboxInput.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAML,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAY3C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AA6JhD,QAAA,MAAM,iBAAiB;;;;;;;;;EASrB,CAAC;AAmCH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAE/D,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IACrE,wDAAwD;IACxD,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,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACxE;;OAEG;IACH,YAAY,CAAC,EAAE,CACb,OAAO,EAAE,OAAO,EAChB,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAC7B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,OAAO,GAAG,eAAe,CAAC;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACpD;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAiB,EACjB,KAAK,EACL,UAAkB,EAClB,QAAQ,EACR,eAAe,EACf,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,IAAW,EACX,OAAO,EACP,MAAM,EACN,SAAS,EACT,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,kBAAkB,+BA0NpB;yBAnPe,aAAa"}
1
+ {"version":3,"file":"CheckboxInput.d.ts","sourceRoot":"","sources":["../../src/CheckboxInput/CheckboxInput.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAOL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAS3C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,gBAAgB,CAAC;AAG9C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,gBAAgB,CAAC;AA0DhD,QAAA,MAAM,iBAAiB;;;;;;;;;EASrB,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,iBAAiB,CAAC;AAE/D,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC;IACrE,wDAAwD;IACxD,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,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACxE;;OAEG;IACH,YAAY,CAAC,EAAE,CACb,OAAO,EAAE,OAAO,EAChB,CAAC,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAC7B,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;OAEG;IACH,KAAK,EAAE,OAAO,GAAG,eAAe,CAAC;IACjC;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACpD;;OAEG;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IACnD;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjC;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAOD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,aAAqB,EACrB,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,SAAiB,EACjB,KAAK,EACL,UAAkB,EAClB,QAAQ,EACR,eAAe,EACf,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,IAAW,EACX,OAAO,EACP,MAAM,EACN,SAAS,EACT,MAAM,EACN,KAAK,EACL,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,IAAI,EACR,EAAE,kBAAkB,+BAkMpB;yBA3Ne,aAAa"}
@@ -15,20 +15,21 @@
15
15
  * - /apps/storybook/stories/CheckboxInput.stories.tsx (storybook stories)
16
16
  * - /packages/cli/assets/templates/blocks/components/CheckboxInput/ (showcase blocks)
17
17
  */
18
- import { useId, useCallback, use, useOptimistic, useTransition } from 'react';
18
+ import { useId, useCallback, use, useOptimistic, useRef, useTransition } from 'react';
19
19
  import * as stylex from '@stylexjs/stylex';
20
20
  import "../theme/tokens.stylex.js";
21
- import { colorVars, spacingVars, radiusVars, durationVars, easeVars, typographyVars, typeScaleVars, fontWeightVars, borderVars } from "../theme/tokens.stylex.js";
21
+ import { colorVars, spacingVars, typographyVars, typeScaleVars, fontWeightVars } from "../theme/tokens.stylex.js";
22
22
  import { FieldLabel } from "../Field/FieldLabel.js";
23
23
  import { FieldStatus } from "../FieldStatus/FieldStatus.js";
24
24
  import { Spinner } from "../Spinner/index.js";
25
25
  import { useTooltip } from "../Tooltip/index.js";
26
26
  import { mergeProps, mergeRefs } from "../utils/index.js";
27
- import "./checkbox.markers.stylex.js";
28
- import { checkboxScope } from "./checkbox.markers.stylex.js";
27
+ import { indicatorScope } from "../Indicator/indicator.markers.stylex.js";
28
+ import { useIndicatorFocusRing } from "../hooks/useIndicatorFocusRing.js";
29
+ import { useIndicator } from "../Indicator/index.js";
29
30
  import { themeProps } from "../utils/themeProps.js";
30
31
  import { CheckboxListContext } from "../CheckboxList/CheckboxListContext.js";
31
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
32
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
32
33
  const styles = {
33
34
  container: {
34
35
  k1xSpc: "x78zum5",
@@ -61,63 +62,6 @@ const styles = {
61
62
  inputDisabled: {
62
63
  kkrTdU: "x1h6gzvc",
63
64
  $$css: true
64
- },
65
- checkbox: {
66
- k1xSpc: "x78zum5",
67
- kGNEyG: "x6s0dn4",
68
- kjj79g: "xl56j7k",
69
- kMzoRj: "x1litavf",
70
- ksu8eU: "x1y0btm7",
71
- kaIpWk: "xx3sua9",
72
- k1ekBW: "xts7igz",
73
- kIyJzY: "xuedmi6 x12w9bfk",
74
- kAMwcw: "xlr8y92",
75
- $$css: true
76
- },
77
- checkboxFocus: {
78
- kI3sdo: "x1a2a7pz xkri23q",
79
- kInvED: "x81n7kt",
80
- $$css: true
81
- },
82
- checkboxUnchecked: {
83
- kMwMTN: "xqwr325",
84
- kVAM5u: "xvy26l8 x1jtjlen",
85
- kWkggS: "x10xzikg xrsv7h",
86
- $$css: true
87
- },
88
- checkboxChecked: {
89
- kMwMTN: "x17wrial",
90
- kVAM5u: "xad5do x1od6ugu",
91
- kWkggS: "x1ewilqj x6aeo4j",
92
- $$css: true
93
- },
94
- checkboxDisabled: {
95
- kSiTet: "xbyyjgo",
96
- kVAM5u: "x14i3s5s xmt8yqp",
97
- $$css: true
98
- },
99
- checkboxDisabledUnchecked: {
100
- kWkggS: "xwmxj5m x1cjfj8k",
101
- $$css: true
102
- },
103
- checkmark: {
104
- k1xSpc: "x1s85apg",
105
- kMwMTN: "x17wrial xs5hli",
106
- $$css: true
107
- },
108
- checkmarkVisible: {
109
- k1xSpc: "x1lliihq",
110
- $$css: true
111
- },
112
- indeterminateMark: {
113
- k1xSpc: "x1s85apg",
114
- kWkggS: "x1azo05 xwvh9j7",
115
- kaIpWk: "xjspbzw",
116
- $$css: true
117
- },
118
- indeterminateMarkVisible: {
119
- k1xSpc: "x1lliihq",
120
- $$css: true
121
65
  }
122
66
  };
123
67
  const wrapperSizeStyles = {
@@ -132,42 +76,6 @@ const wrapperSizeStyles = {
132
76
  $$css: true
133
77
  }
134
78
  };
135
- const checkboxSizeStyles = {
136
- sm: {
137
- kzqmXN: "xw4jnvo",
138
- kZKoxP: "x1qx5ct2",
139
- $$css: true
140
- },
141
- md: {
142
- kzqmXN: "xvy4d1p",
143
- kZKoxP: "xxk0z11",
144
- $$css: true
145
- }
146
- };
147
- const checkmarkSizeStyles = {
148
- sm: {
149
- kzqmXN: "xsmyaan",
150
- kZKoxP: "x1kpxq89",
151
- $$css: true
152
- },
153
- md: {
154
- kzqmXN: "x6jxa94",
155
- kZKoxP: "x1v9usgg",
156
- $$css: true
157
- }
158
- };
159
- const indeterminateSizeStyles = {
160
- sm: {
161
- kzqmXN: "x1fsd2vl",
162
- kZKoxP: "x36qwtl",
163
- $$css: true
164
- },
165
- md: {
166
- kzqmXN: "xsmyaan",
167
- kZKoxP: "x36qwtl",
168
- $$css: true
169
- }
170
- };
171
79
  // Dynamic field width (number -> px, string used as-is).
172
80
  const dynamicWidthStyles = {
173
81
  width: width => [{
@@ -248,9 +156,19 @@ export function CheckboxInput({
248
156
  focusTrigger: 'always',
249
157
  isEnabled: showsDisabledMessage
250
158
  });
159
+
160
+ // The checkbox visual is an indicator: a theme can restyle it through the
161
+ // `checkbox` target or replace the component outright.
162
+ const CheckboxControl = useIndicator('checkbox');
163
+ // The ring is drawn on the indicator itself: the native input is
164
+ // `opacity: 0`, and only the indicator's own element can shape the outline
165
+ // to match it. See useIndicatorFocusRing.
166
+ const indicatorRef = useRef(null);
167
+ const {
168
+ focusProps
169
+ } = useIndicatorFocusRing(indicatorRef, isDisabled);
251
170
  const isIndeterminate = optimisticValue === 'indeterminate';
252
171
  const isChecked = optimisticValue === true;
253
- const isCheckedOrIndeterminate = isChecked || isIndeterminate;
254
172
 
255
173
  // Sync the native indeterminate DOM property (can't be set via JSX
256
174
  // attribute). On a native checkbox this is the authoritative way to expose
@@ -291,9 +209,13 @@ export function CheckboxInput({
291
209
  // unconditionally is safe.
292
210
  disabledMessageTooltip.interactionRef(el);
293
211
  },
294
- ...stylex.props(styles.container, isLabelHidden && styles.containerLabelHidden, !isDisabled && checkboxScope),
212
+ ...stylex.props(styles.container, isLabelHidden && styles.containerLabelHidden,
213
+ // Hover and focus reach the checkbox visual through this ancestor
214
+ // marker rather than props, so the whole row drives it.
215
+ !isDisabled && indicatorScope),
295
216
  children: [/*#__PURE__*/_jsxs("div", {
296
217
  ...stylex.props(styles.checkboxWrapper, wrapperSizeStyles[size]),
218
+ ...focusProps,
297
219
  children: [/*#__PURE__*/_jsx("input", {
298
220
  ...rest,
299
221
  ref: mergeRefs(ref, indeterminateRef, disabledMessageTooltip.positionRef),
@@ -333,31 +255,19 @@ export function CheckboxInput({
333
255
  "aria-invalid": status?.type === 'error' ? true : undefined,
334
256
  "aria-busy": isBusy || undefined,
335
257
  ...stylex.props(styles.input, wrapperSizeStyles[size], isDisabled && styles.inputDisabled)
336
- }), /*#__PURE__*/_jsx("div", {
337
- "aria-hidden": "true",
338
- ...mergeProps(themeProps('checkbox', {
339
- size,
340
- checked: isChecked ? 'checked' : isIndeterminate ? 'indeterminate' : null,
341
- disabled: isDisabled ? 'disabled' : null
342
- }), stylex.props(styles.checkbox, checkboxSizeStyles[size], !isDisabled && styles.checkboxFocus, isCheckedOrIndeterminate ? styles.checkboxChecked : styles.checkboxUnchecked, isDisabled && styles.checkboxDisabled, isDisabled && !isCheckedOrIndeterminate && styles.checkboxDisabledUnchecked)),
343
- children: isBusy ? /*#__PURE__*/_jsx(Spinner, {
344
- size: "sm",
345
- shade: "inherit"
346
- }) : /*#__PURE__*/_jsxs(_Fragment, {
347
- children: [/*#__PURE__*/_jsx("svg", {
348
- viewBox: "0 0 10 10",
349
- ...stylex.props(styles.checkmark, checkmarkSizeStyles[size], isChecked && styles.checkmarkVisible),
350
- children: /*#__PURE__*/_jsx("path", {
351
- d: "M8.5 2.5L4 7.5L1.5 5",
352
- stroke: "currentColor",
353
- strokeWidth: "1.5",
354
- fill: "none",
355
- strokeLinecap: "round",
356
- strokeLinejoin: "round"
357
- })
358
- }), /*#__PURE__*/_jsx("div", {
359
- ...stylex.props(styles.indeterminateMark, indeterminateSizeStyles[size], isIndeterminate && styles.indeterminateMarkVisible)
360
- })]
258
+ }), /*#__PURE__*/_jsx("span", {
259
+ ref: indicatorRef,
260
+ ...{
261
+ className: "xjp7ctv"
262
+ },
263
+ children: /*#__PURE__*/_jsx(CheckboxControl, {
264
+ state: isIndeterminate ? 'indeterminate' : isChecked ? 'checked' : 'unchecked',
265
+ size: size,
266
+ isDisabled: isDisabled,
267
+ children: isBusy ? /*#__PURE__*/_jsx(Spinner, {
268
+ size: "sm",
269
+ shade: "inherit"
270
+ }) : null
361
271
  })
362
272
  })]
363
273
  }), /*#__PURE__*/_jsx("div", {
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/CodeBlock/CodeBlock.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA4B5C,OAAO,EAAc,KAAK,qBAAqB,EAAC,MAAM,iBAAiB,CAAC;AAmXxE,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC/D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,KACb;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAqPD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAsB,EACtB,KAAK,EACL,gBAAuB,EACvB,cAAsB,EACtB,cAAc,EACd,aAAoB,EACpB,MAAM,EACN,SAAiB,EACjB,SAAS,EACT,aAAqB,EACrB,oBAAyB,EACzB,IAAW,EACX,KAAK,EAAE,SAAyB,EAChC,SAAkB,EAClB,SAAS,EAAE,eAAe,EAC1B,aAAsB,EACtB,WAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,cAAc,qBA2OhB;yBAnQe,SAAS"}
1
+ {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/CodeBlock/CodeBlock.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA6B5C,OAAO,EAAc,KAAK,qBAAqB,EAAC,MAAM,iBAAiB,CAAC;AAwWxE,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC/D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,KACb;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAqPD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAsB,EACtB,KAAK,EACL,gBAAuB,EACvB,cAAsB,EACtB,cAAc,EACd,aAAoB,EACpB,MAAM,EACN,SAAiB,EACjB,SAAS,EACT,aAAqB,EACrB,oBAAyB,EACzB,IAAW,EACX,KAAK,EAAE,SAAyB,EAChC,SAAkB,EAClB,SAAS,EAAE,eAAe,EAC1B,aAAsB,EACtB,WAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,cAAc,qBAsNhB;yBA9Oe,SAAS"}
@@ -14,8 +14,9 @@ import * as stylex from '@stylexjs/stylex';
14
14
  import "../theme/tokens.stylex.js";
15
15
  import { colorVars, spacingVars, radiusVars, typographyVars, fontWeightVars, typeScaleVars, borderVars, durationVars, easeVars } from "../theme/tokens.stylex.js";
16
16
  import { mergeProps } from "../utils/index.js";
17
- import { useAnnounce } from "../hooks/useAnnounce.js";
17
+ import { useClipboard } from "../hooks/useClipboard.js";
18
18
  import { Icon } from "../Icon/index.js";
19
+ import { IconButton } from "../IconButton/index.js";
19
20
  import { tokenize, tokenizeAsync, flatTokensToLines, SYNC_TOKENIZE_THRESHOLD } from "./tokenizer.js";
20
21
  import { ensureHighlightStyles } from "./highlightStyles.js";
21
22
  import { applyHighlightRangesChunked } from "./highlightRanges.js";
@@ -148,6 +149,16 @@ const styles = {
148
149
  sizeMd: {
149
150
  kGuDYH: "xp03k98",
150
151
  $$css: true
152
+ },
153
+ copyButton: {
154
+ kMwMTN: "x1mjzq1q",
155
+ $$css: true
156
+ },
157
+ copyButtonAbsolute: {
158
+ kVAEAm: "x10l6tqk",
159
+ k87sOh: "xctzyg",
160
+ kt4wiu: "x72tfeb",
161
+ $$css: true
151
162
  }
152
163
  };
153
164
 
@@ -437,18 +448,15 @@ export function CodeBlock({
437
448
  ...props
438
449
  }) {
439
450
  const t = useTranslator();
440
- const [copied, setCopied] = useState(false);
441
- const copyResetTimerRef = useRef(null);
442
- const announce = useAnnounce();
443
-
444
- // Clear a pending "copied" reset when the block unmounts.
445
- useEffect(() => {
446
- return () => {
447
- if (copyResetTimerRef.current != null) {
448
- clearTimeout(copyResetTimerRef.current);
449
- }
450
- };
451
- }, []);
451
+ // Owns the clipboard write, the transient copied flag, its reset timer, and
452
+ // the polite copy announcement (a swapped aria-label alone is not reliably
453
+ // announced) — shared with Timestamp via the same hook.
454
+ const {
455
+ copy,
456
+ isCopied: copied
457
+ } = useClipboard({
458
+ announce: t('@astryx.codeBlock.copied')
459
+ });
452
460
  const useSpans = highlightMode === 'spans' || highlightMode === 'auto' && !hasHighlightAPI() || highlightMode === 'auto' && isSafari();
453
461
  const lines = useMemo(() => {
454
462
  const l = code.split('\n');
@@ -460,26 +468,11 @@ export function CodeBlock({
460
468
  const tokenLines = useTokenLines(code, language, customTokenizer);
461
469
  const highlightSet = useMemo(() => highlightLines ? new Set(highlightLines) : null, [highlightLines]);
462
470
  const handleCopy = useCallback(async () => {
463
- try {
464
- await navigator.clipboard.writeText(code);
465
- setCopied(true);
466
- // Swapping the button's aria-label alone isn't reliably announced by
467
- // screen readers, so confirm the copy via a polite live region.
468
- announce(t('@astryx.codeBlock.copied'));
471
+ const didCopy = await copy(code);
472
+ if (didCopy) {
469
473
  onCopy?.();
470
- // Restart the reset timer on every copy — otherwise a rapid re-copy
471
- // is reverted early by the previous click's timer.
472
- if (copyResetTimerRef.current != null) {
473
- clearTimeout(copyResetTimerRef.current);
474
- }
475
- copyResetTimerRef.current = setTimeout(() => {
476
- copyResetTimerRef.current = null;
477
- setCopied(false);
478
- }, 2000);
479
- } catch {
480
- // Clipboard failures leave the copied state unchanged.
481
474
  }
482
- }, [code, onCopy, announce, t]);
475
+ }, [code, copy, onCopy]);
483
476
  const sizeStyle = size === 'sm' ? styles.sizeSm : styles.sizeMd;
484
477
  // Digits in the largest line number — sizes the gutter column width.
485
478
  const maxLineDigits = String(lines.length).length;
@@ -496,28 +489,28 @@ export function CodeBlock({
496
489
  const scrollStyle = maxHeight ? {
497
490
  maxHeight: typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight
498
491
  } : undefined;
499
- const copyIcon = /*#__PURE__*/_jsx(Icon, {
500
- icon: copied ? 'check' : 'copy',
492
+ const copyButtonEl = hasCopyButton ? /*#__PURE__*/_jsx(IconButton, {
493
+ variant: "ghost",
501
494
  size: "sm",
502
- color: "inherit"
503
- });
504
- const copyButtonEl = hasCopyButton ? /*#__PURE__*/_jsx("button", {
505
- type: "button",
495
+ icon: /*#__PURE__*/_jsx(Icon, {
496
+ icon: copied ? 'check' : 'copy',
497
+ size: "sm",
498
+ color: "inherit"
499
+ })
500
+ // A visible "Copy" hover/focus hint via Button's built-in tooltip. It
501
+ // stays "Copy" after copying — the copy → check icon flip is the
502
+ // confirmation, not a tooltip change. The aria-label still swaps to the
503
+ // localized "Copied" for assistive tech, backed by the announcement.
504
+ ,
505
+ tooltip: t('@astryx.codeBlock.copyCode'),
506
+ label: copied ? t('@astryx.codeBlock.copied') : t('@astryx.codeBlock.copyCode'),
506
507
  onClick: e => {
507
508
  // Stop propagation so copying does not toggle the collapsible header.
508
509
  e.stopPropagation();
509
510
  void handleCopy();
510
511
  },
511
- "aria-label": copied ? t('@astryx.codeBlock.copied') : t('@astryx.codeBlock.copyCode'),
512
- ...{
513
- 0: {
514
- className: "x3nfvp2 x6s0dn4 xl56j7k x9epnlk x3kzqx6 xx3sua9 xjbqb8w xe9uy6x x1mjzq1q x1ypdohk x14ju556"
515
- },
516
- 1: {
517
- className: "x3nfvp2 x6s0dn4 xl56j7k x9epnlk x3kzqx6 xx3sua9 xjbqb8w xe9uy6x x1mjzq1q x1ypdohk x14ju556 x10l6tqk xctzyg x72tfeb"
518
- }
519
- }[!!!showHeader << 0],
520
- children: copyIcon
512
+ xstyle: [styles.copyButton, !showHeader && styles.copyButtonAbsolute],
513
+ ...themeProps('codeblock-copy-button')
521
514
  }) : null;
522
515
  const headerEl = showHeader ? /*#__PURE__*/_jsxs("div", {
523
516
  ...{
@@ -11,17 +11,14 @@
11
11
  * Enter/Space activation come from the parent DropdownMenu's useListFocus +
12
12
  * activation path, which matches menuitemcheckbox alongside plain menuitem rows.
13
13
  *
14
- * The checkbox visual composes the real CheckboxInput primitive so its checkmark
15
- * matches CheckboxListItem and picks up the standard `checkbox` theming slots.
16
- * It is purely decorative: the composed control is wrapped in an element that is
17
- * both `aria-hidden` and `inert`, so it contributes nothing to the row's
18
- * accessible name, and its native <input> and sr-only label stay out of the tab
19
- * order and the accessibility tree while pointer clicks fall through to the row
20
- * — the same shim MultiSelector uses. The row owns the checked state and
21
- * accessible name. The control size is derived from the menu's item size (a
22
- * `sm` menu gets the compact control; `md`/`lg` get the standard one) and it
23
- * swaps to the inline-end of the row on coarse-pointer (touch) devices via CSS
24
- * `order`, so it lands where selection toggles are conventionally placed on
14
+ * The checkbox visual is the shared checkbox indicator, decorative
15
+ * (aria-hidden) — the row owns the role, checked state, and accessible name, so
16
+ * there is no nested native <input> to shim out of the accessibility tree. It
17
+ * picks up the same `checkbox` theming (and any theme replacement) as
18
+ * CheckboxInput. The control size is derived from the menu's item size (a `sm`
19
+ * menu gets the compact control; `md`/`lg` get the standard one) and the marker
20
+ * box swaps to the inline-end of the row on coarse-pointer (touch) devices via
21
+ * CSS `order`, so it lands where selection toggles are conventionally placed on
25
22
  * mobile.
26
23
  */
27
24
  import { type ReactNode } from 'react';
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenuCheckboxItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuCheckboxItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAOtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAsC5C,MAAM,WAAW,6BAA8B,SAAQ,IAAI,CACzD,SAAS,EACT,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAClD;IACC;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,WAAW,EACX,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,UAAkB,EAClB,gBAAwB,EACxB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,6BAA6B,+BA6D/B;yBA1Ee,wBAAwB"}
1
+ {"version":3,"file":"DropdownMenuCheckboxItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuCheckboxItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAOtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAyC5C,MAAM,WAAW,6BAA8B,SAAQ,IAAI,CACzD,SAAS,EACT,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,UAAU,CAClD;IACC;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IACf;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CAAC,EACvC,KAAK,EACL,WAAW,EACX,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,UAAkB,EAClB,gBAAwB,EACxB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,6BAA6B,+BA0D/B;yBAvEe,wBAAwB"}
@@ -15,23 +15,20 @@
15
15
  * Enter/Space activation come from the parent DropdownMenu's useListFocus +
16
16
  * activation path, which matches menuitemcheckbox alongside plain menuitem rows.
17
17
  *
18
- * The checkbox visual composes the real CheckboxInput primitive so its checkmark
19
- * matches CheckboxListItem and picks up the standard `checkbox` theming slots.
20
- * It is purely decorative: the composed control is wrapped in an element that is
21
- * both `aria-hidden` and `inert`, so it contributes nothing to the row's
22
- * accessible name, and its native <input> and sr-only label stay out of the tab
23
- * order and the accessibility tree while pointer clicks fall through to the row
24
- * — the same shim MultiSelector uses. The row owns the checked state and
25
- * accessible name. The control size is derived from the menu's item size (a
26
- * `sm` menu gets the compact control; `md`/`lg` get the standard one) and it
27
- * swaps to the inline-end of the row on coarse-pointer (touch) devices via CSS
28
- * `order`, so it lands where selection toggles are conventionally placed on
18
+ * The checkbox visual is the shared checkbox indicator, decorative
19
+ * (aria-hidden) — the row owns the role, checked state, and accessible name, so
20
+ * there is no nested native <input> to shim out of the accessibility tree. It
21
+ * picks up the same `checkbox` theming (and any theme replacement) as
22
+ * CheckboxInput. The control size is derived from the menu's item size (a `sm`
23
+ * menu gets the compact control; `md`/`lg` get the standard one) and the marker
24
+ * box swaps to the inline-end of the row on coarse-pointer (touch) devices via
25
+ * CSS `order`, so it lands where selection toggles are conventionally placed on
29
26
  * mobile.
30
27
  */
31
28
  import { useCallback } from 'react';
32
29
  import * as stylex from '@stylexjs/stylex';
33
30
  import { renderIconSlot } from "../Icon/index.js";
34
- import { CheckboxInput } from "../CheckboxInput/CheckboxInput.js";
31
+ import { useIndicator } from "../Indicator/index.js";
35
32
  import { Item } from "../Item/index.js";
36
33
  import { useDropdownMenuContext } from "./DropdownMenuContext.js";
37
34
  import { focusMenuItemOnHover } from "./menuItemHover.js";
@@ -53,8 +50,18 @@ const styles = {
53
50
  kSiTet: "xbyyjgo",
54
51
  kkrTdU: "x1h6gzvc",
55
52
  $$css: true
53
+ },
54
+ marker: {
55
+ kfzvcC: "x47corl",
56
+ kayTVb: "x1g77sc7 xozvky",
57
+ keTefX: "x1lziwak x1jymrmb",
58
+ $$css: true
56
59
  }
57
60
  };
61
+
62
+ // Matches the control sizes CheckboxInput uses, so a checkbox reads the same in
63
+ // a menu row as it does in a form.
64
+
58
65
  /**
59
66
  * A checkable dropdown menu item (role="menuitemcheckbox").
60
67
  *
@@ -90,12 +97,7 @@ export function DropdownMenuCheckboxItem({
90
97
  const ctx = useDropdownMenuContext();
91
98
  const menuSize = ctx?.menuSize ?? 'md';
92
99
  const controlSize = menuSize === 'sm' ? 'sm' : 'md';
93
-
94
- // The composed checkbox is decorative and inert, so its label never reaches
95
- // the accessibility tree — the row's `label` prop provides the announced
96
- // name. CheckboxInput still requires a string label, so pass one through when
97
- // the row label is a plain string.
98
- const checkboxLabel = typeof label === 'string' ? label : '';
100
+ const CheckboxControl = useIndicator('checkbox');
99
101
  const handleClick = useCallback(() => {
100
102
  if (isDisabled) {
101
103
  return;
@@ -112,19 +114,18 @@ export function DropdownMenuCheckboxItem({
112
114
  "aria-checked": value,
113
115
  tabIndex: isDisabled ? undefined : -1,
114
116
  onPointerMove: handlePointerMove,
115
- marker: /*#__PURE__*/_jsx("div", {
116
- "aria-hidden": "true",
117
- inert: true,
118
- ...{
119
- className: "x78zum5 x2lah0s x47corl x1g77sc7 xozvky x1lziwak x1jymrmb"
120
- },
121
- children: /*#__PURE__*/_jsx(CheckboxInput, {
122
- label: checkboxLabel,
123
- isLabelHidden: true,
124
- value: value,
125
- isDisabled: isDisabled,
126
- size: controlSize
127
- })
117
+ marker:
118
+ /*#__PURE__*/
119
+ // No wrapper, and no menu-specific theme target: the shared
120
+ // `astryx-checkbox` target is already on this element (main reached
121
+ // the menu checkbox through it too), so the menu adds only its own
122
+ // placement rules. A wrapper here would have duplicated the
123
+ // indicator's control size and moved nothing themeable.
124
+ _jsx(CheckboxControl, {
125
+ state: value ? 'checked' : 'unchecked',
126
+ size: controlSize,
127
+ isDisabled: isDisabled,
128
+ xstyle: styles.marker
128
129
  }),
129
130
  startContent: icon ? renderIconSlot(icon, {
130
131
  size: 'sm',
@@ -10,11 +10,11 @@
10
10
  * state + onChange come from DropdownMenuRadioGroupContext. Keyboard nav +
11
11
  * Enter/Space activation come from the parent DropdownMenu.
12
12
  *
13
- * The round radio visual (circle + center dot) is decorative (aria-hidden) —
14
- * the row owns the checked state. Its size is derived from the menu's item size
15
- * and it swaps to the inline-end of the row on coarse-pointer (touch) devices
16
- * via CSS `order`. The dot is a shaped element, not an icon (a filled circle
17
- * has no registry glyph).
13
+ * The round radio visual is the shared radio indicator, decorative
14
+ * (aria-hidden) — the row owns the checked state, and menu radios pick up the
15
+ * same `radio` theming (and any theme replacement) as RadioList. This row keeps
16
+ * the marker box: its size is derived from the menu's item size and it swaps to
17
+ * the inline-end of the row on coarse-pointer (touch) devices via CSS `order`.
18
18
  */
19
19
  import { type ReactNode } from 'react';
20
20
  import { type IconType } from '../Icon';
@@ -1 +1 @@
1
- {"version":3,"file":"DropdownMenuRadioItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuRadioItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAYtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAqE5C,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CACtD,SAAS,EACT,MAAM,GAAG,cAAc,GAAG,UAAU,CACrC;IACC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,KAAK,EACL,WAAW,EACX,IAAI,EACJ,UAAkB,EAClB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,0BAA0B,+BAgF5B;yBA3Fe,qBAAqB"}
1
+ {"version":3,"file":"DropdownMenuRadioItem.d.ts","sourceRoot":"","sources":["../../src/DropdownMenu/DropdownMenuRadioItem.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAiC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAErE,OAAO,EAAiB,KAAK,QAAQ,EAAC,MAAM,SAAS,CAAC;AAOtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAyC5C,MAAM,WAAW,0BAA2B,SAAQ,IAAI,CACtD,SAAS,EACT,MAAM,GAAG,cAAc,GAAG,UAAU,CACrC;IACC;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,KAAK,EAAE,SAAS,CAAC;IACjB;;OAEG;IACH,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,KAAK,EACL,KAAK,EACL,WAAW,EACX,IAAI,EACJ,UAAkB,EAClB,UAAU,EACV,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,IAAI,EACR,EAAE,0BAA0B,+BAmE5B;yBA9Ee,qBAAqB"}