@astryxdesign/core 0.6.2-canary.bfee8a4 → 0.6.2-canary.c8d5849

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 (261) hide show
  1. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  2. package/dist/Chat/ChatComposerInput.js +2 -2
  3. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  4. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  5. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  6. package/dist/Collapsible/Collapsible.js +6 -1
  7. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  8. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  9. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  10. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  11. package/dist/DateInput/DateInput.d.ts.map +1 -1
  12. package/dist/DateInput/DateInput.js +4 -4
  13. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  14. package/dist/DateInput/NativeDateField.js +16 -16
  15. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  16. package/dist/DateInput/TouchDateField.js +2 -2
  17. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  18. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  19. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  20. package/dist/DateTimeInput/DateTimeInput.js +8 -8
  21. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  22. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  23. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  24. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  25. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  26. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  27. package/dist/Field/PanelSearchInput.js +1 -1
  28. package/dist/FileInput/FileInput.d.ts.map +1 -1
  29. package/dist/FileInput/FileInput.js +7 -7
  30. package/dist/Kbd/Kbd.d.ts +5 -3
  31. package/dist/Kbd/Kbd.d.ts.map +1 -1
  32. package/dist/Kbd/Kbd.js +36 -42
  33. package/dist/Link/Link.d.ts.map +1 -1
  34. package/dist/Link/Link.js +6 -2
  35. package/dist/Markdown/Markdown.d.ts +8 -2
  36. package/dist/Markdown/Markdown.d.ts.map +1 -1
  37. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  38. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  39. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  40. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  41. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  42. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  43. package/dist/Markdown/Markdown.js +262 -109
  44. package/dist/Markdown/ast.d.ts +162 -0
  45. package/dist/Markdown/ast.d.ts.map +1 -0
  46. package/dist/Markdown/ast.js +74 -0
  47. package/dist/Markdown/index.d.ts +5 -3
  48. package/dist/Markdown/index.d.ts.map +1 -1
  49. package/dist/Markdown/index.js +3 -2
  50. package/dist/Markdown/parser/index.d.ts +10 -0
  51. package/dist/Markdown/parser/index.d.ts.map +1 -0
  52. package/dist/Markdown/parser/index.js +10 -0
  53. package/dist/Markdown/parser.d.ts +126 -58
  54. package/dist/Markdown/parser.d.ts.map +1 -1
  55. package/dist/Markdown/parser.js +716 -167
  56. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  57. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  58. package/dist/Markdown/plugins/frontmatter.js +132 -0
  59. package/dist/Markdown/plugins/index.d.ts +16 -0
  60. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  61. package/dist/Markdown/plugins/index.js +13 -0
  62. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  63. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  64. package/dist/Markdown/plugins/protocol.js +957 -0
  65. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  66. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  67. package/dist/Markdown/plugins/semanticFence.js +213 -0
  68. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  69. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  70. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  71. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  72. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  73. package/dist/Markdown/plugins/textTransform.js +374 -0
  74. package/dist/Markdown/remark.d.ts +196 -0
  75. package/dist/Markdown/remark.d.ts.map +1 -0
  76. package/dist/Markdown/remark.js +1062 -0
  77. package/dist/Markdown/url.d.ts +4 -0
  78. package/dist/Markdown/url.d.ts.map +1 -0
  79. package/dist/Markdown/url.js +25 -0
  80. package/dist/Markdown/utils.d.ts +4 -2
  81. package/dist/Markdown/utils.d.ts.map +1 -1
  82. package/dist/Markdown/utils.js +2 -1
  83. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  84. package/dist/NumberInput/NumberInput.js +4 -4
  85. package/dist/Outline/index.d.ts +1 -0
  86. package/dist/Outline/index.d.ts.map +1 -1
  87. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  88. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  89. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  90. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  91. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  92. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  93. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  94. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  95. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  96. package/dist/ProgressBar/ProgressBar.js +36 -31
  97. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  98. package/dist/RadioList/RadioListItem.js +13 -1
  99. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  100. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  101. package/dist/Selector/Selector.d.ts.map +1 -1
  102. package/dist/Selector/Selector.js +1 -1
  103. package/dist/SideNav/SideNav.d.ts +2 -1
  104. package/dist/SideNav/SideNav.d.ts.map +1 -1
  105. package/dist/SideNav/SideNav.js +9 -3
  106. package/dist/Slider/Slider.d.ts.map +1 -1
  107. package/dist/Slider/Slider.js +14 -8
  108. package/dist/Spinner/Spinner.d.ts.map +1 -1
  109. package/dist/Spinner/Spinner.js +23 -7
  110. package/dist/Switch/Switch.d.ts.map +1 -1
  111. package/dist/Switch/Switch.js +11 -0
  112. package/dist/TabList/Tab.d.ts +1 -1
  113. package/dist/TabList/Tab.d.ts.map +1 -1
  114. package/dist/TabList/Tab.js +20 -7
  115. package/dist/Table/Table.d.ts +1 -0
  116. package/dist/Table/Table.d.ts.map +1 -1
  117. package/dist/Table/Table.js +29 -13
  118. package/dist/TextArea/TextArea.d.ts.map +1 -1
  119. package/dist/TextArea/TextArea.js +1 -1
  120. package/dist/TextInput/TextInput.d.ts.map +1 -1
  121. package/dist/TextInput/TextInput.js +2 -2
  122. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  123. package/dist/TimeInput/TimeInput.js +4 -4
  124. package/dist/ToggleButton/ToggleButton.d.ts +2 -1
  125. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  126. package/dist/ToggleButton/ToggleButton.js +7 -1
  127. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  128. package/dist/Typeahead/BaseTypeahead.js +16 -7
  129. package/dist/astryx.css +14 -6
  130. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  131. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  132. package/dist/utils/interactionOverlay.stylex.js +9 -0
  133. package/package.json +18 -3
  134. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  135. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  136. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  137. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  138. package/src/Chat/ChatComposerInput.doc.mjs +3 -3
  139. package/src/Chat/ChatComposerInput.tsx +10 -2
  140. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  141. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  142. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  143. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  144. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  145. package/src/Collapsible/Collapsible.test.tsx +21 -0
  146. package/src/Collapsible/Collapsible.tsx +5 -0
  147. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  148. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  149. package/src/DateInput/DateInput.tsx +6 -1
  150. package/src/DateInput/NativeDateField.tsx +24 -8
  151. package/src/DateInput/TouchDateField.tsx +6 -2
  152. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  153. package/src/DateTimeInput/DateTimeInput.tsx +6 -1
  154. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  155. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  156. package/src/Field/PanelSearchInput.tsx +5 -2
  157. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  158. package/src/FileInput/FileInput.tsx +11 -2
  159. package/src/Kbd/Kbd.doc.mjs +3 -3
  160. package/src/Kbd/Kbd.test.tsx +57 -1
  161. package/src/Kbd/Kbd.tsx +57 -37
  162. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  163. package/src/Link/Link.doc.mjs +11 -0
  164. package/src/Link/Link.test.tsx +24 -0
  165. package/src/Link/Link.tsx +5 -0
  166. package/src/Markdown/Markdown.doc.mjs +272 -0
  167. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  168. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  169. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  170. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  171. package/src/Markdown/Markdown.public.test.ts +126 -3
  172. package/src/Markdown/Markdown.spec.md +197 -44
  173. package/src/Markdown/Markdown.test.tsx +11 -0
  174. package/src/Markdown/Markdown.tsx +414 -135
  175. package/src/Markdown/ast.test.ts +307 -0
  176. package/src/Markdown/ast.ts +337 -0
  177. package/src/Markdown/incremental.test.ts +12 -0
  178. package/src/Markdown/index.ts +37 -1
  179. package/src/Markdown/modules/remark.spec.md +269 -0
  180. package/src/Markdown/parser/index.ts +64 -0
  181. package/src/Markdown/parser.public.test.ts +103 -0
  182. package/src/Markdown/parser.ts +1180 -235
  183. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  184. package/src/Markdown/plugins/frontmatter.ts +198 -0
  185. package/src/Markdown/plugins/index.ts +53 -0
  186. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  187. package/src/Markdown/plugins/protocol.ts +1618 -0
  188. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  189. package/src/Markdown/plugins/semanticFence.ts +424 -0
  190. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  191. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  192. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  193. package/src/Markdown/plugins/textTransform.ts +554 -0
  194. package/src/Markdown/remark.test.tsx +1877 -0
  195. package/src/Markdown/remark.ts +1574 -0
  196. package/src/Markdown/url.ts +30 -0
  197. package/src/Markdown/utils.ts +13 -1
  198. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  199. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  200. package/src/NumberInput/NumberInput.tsx +6 -1
  201. package/src/Outline/Outline.doc.mjs +7 -5
  202. package/src/Outline/Outline.spec.md +1 -1
  203. package/src/Outline/index.ts +1 -0
  204. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  205. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  206. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  207. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  208. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  209. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  210. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  211. package/src/ProgressBar/ProgressBar.tsx +59 -72
  212. package/src/RadioList/RadioList.doc.mjs +11 -0
  213. package/src/RadioList/RadioList.test.tsx +32 -0
  214. package/src/RadioList/RadioListItem.tsx +25 -1
  215. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  216. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  217. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  218. package/src/Selector/Selector.spec.md +12 -9
  219. package/src/Selector/Selector.tsx +6 -1
  220. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  221. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  222. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  223. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  224. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  225. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  226. package/src/SideNav/SideNav.doc.mjs +1 -1
  227. package/src/SideNav/SideNav.test.tsx +10 -0
  228. package/src/SideNav/SideNav.tsx +14 -2
  229. package/src/Slider/Slider.doc.mjs +11 -0
  230. package/src/Slider/Slider.test.tsx +128 -0
  231. package/src/Slider/Slider.tsx +25 -7
  232. package/src/Spinner/Spinner.test.tsx +4 -0
  233. package/src/Spinner/Spinner.tsx +31 -18
  234. package/src/Switch/Switch.doc.mjs +11 -0
  235. package/src/Switch/Switch.test.tsx +16 -0
  236. package/src/Switch/Switch.tsx +28 -0
  237. package/src/TabList/Tab.tsx +35 -7
  238. package/src/TabList/TabList.doc.mjs +11 -0
  239. package/src/TabList/TabList.test.tsx +66 -0
  240. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  241. package/src/Table/Table.doc.mjs +1 -1
  242. package/src/Table/Table.spec.md +54 -40
  243. package/src/Table/Table.test.tsx +83 -10
  244. package/src/Table/Table.tsx +30 -22
  245. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  246. package/src/TextArea/TextArea.tsx +6 -1
  247. package/src/TextInput/TextInput.test.tsx +20 -1
  248. package/src/TextInput/TextInput.tsx +6 -1
  249. package/src/TimeInput/TimeInput.tsx +6 -1
  250. package/src/ToggleButton/ToggleButton.test.tsx +133 -0
  251. package/src/ToggleButton/ToggleButton.tsx +9 -2
  252. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  253. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  254. package/src/TreeList/TreeList.spec.md +123 -75
  255. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  256. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  257. package/src/Typeahead/Typeahead.test.tsx +53 -0
  258. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  259. package/src/__tests__/pressState.ts +93 -0
  260. package/src/inputFontFloor.test.ts +106 -0
  261. package/src/utils/interactionOverlay.stylex.ts +20 -0
package/dist/astryx.css CHANGED
@@ -65,7 +65,7 @@
65
65
  @keyframes xv1hr86-B{from{opacity:0;transform:translateY(calc(-1 * var(--spacing-2))) scale(.95);}to{opacity:1;transform:translateY(0) scale(1);}}
66
66
  @keyframes x1b6yrix-B{from{opacity:0;transform:translateY(var(--spacing-2));}to{opacity:1;transform:translateY(0);}}
67
67
  @keyframes xiylxmw-B{from{opacity:0;transform:translateY(calc(-1 * var(--spacing-2)));}to{opacity:1;transform:translateY(0);}}
68
- @keyframes xqng64z-B{0%{transform:rotate(0deg);}100%{transform:rotate(360deg);}}
68
+ @keyframes x1wbvqyn-B{0%{stroke-dashoffset:0;}100%{stroke-dashoffset:calc(var(--_spinner-ring-diameter) * -3.141592653589793);}}
69
69
  @keyframes x1c2q33o-B{0%{transform:translateX(100%);}100%{transform:translateX(-250%);}}
70
70
  @keyframes xr3m334-B{0%{transform:translateX(-100%);}100%{transform:translateX(250%);}}
71
71
  @keyframes x1xhkexc-B{from{width:0;margin-inline-end:0;opacity:0;}to{width:14px;margin-inline-end:var(--spacing-1);opacity:1;}}
@@ -650,10 +650,10 @@
650
650
  .x3psbcj:not(#\#):not(#\#):not(#\#){animation-name:x1ahk7ht-B}
651
651
  .x1dvww92:not(#\#):not(#\#):not(#\#){animation-name:x1b6yrix-B}
652
652
  .x97zbip:not(#\#):not(#\#):not(#\#){animation-name:x1k48ry3-B}
653
+ .x1nlxm0d:not(#\#):not(#\#):not(#\#){animation-name:x1wbvqyn-B}
653
654
  .x1gbn2au:not(#\#):not(#\#):not(#\#){animation-name:x1xhkexc-B}
654
655
  .xeuoslp:not(#\#):not(#\#):not(#\#){animation-name:xgnty7z-B}
655
656
  .x1srr2gu:not(#\#):not(#\#):not(#\#){animation-name:xiylxmw-B}
656
- .x1ka1v4i:not(#\#):not(#\#):not(#\#){animation-name:xqng64z-B}
657
657
  .xozk8ic:not(#\#):not(#\#):not(#\#){animation-name:xr3m334-B}
658
658
  .x1mta51n:not(#\#):not(#\#):not(#\#){animation-name:xtut5q7-B}
659
659
  .xck01x9:not(#\#):not(#\#):not(#\#){animation-name:xu7jd1z-B}
@@ -1313,7 +1313,6 @@
1313
1313
  .x126k92a:not(#\#):not(#\#):not(#\#){white-space:pre-wrap}
1314
1314
  .x1sdyfia:not(#\#):not(#\#):not(#\#){white-space:pre}
1315
1315
  .x1q1rmc8:not(#\#):not(#\#):not(#\#){will-change:transform,opacity}
1316
- .x1so62im:not(#\#):not(#\#):not(#\#){will-change:transform}
1317
1316
  .x1yn0g08:not(#\#):not(#\#):not(#\#){word-break:break-all}
1318
1317
  .x13faqbe:not(#\#):not(#\#):not(#\#){word-break:break-word}
1319
1318
  .x1lldw8n:not(#\#):not(#\#):not(#\#){word-break:normal}
@@ -1331,6 +1330,7 @@
1331
1330
  .x7v6acp.x7v6acp:where(.x84s7jz:focus-within *):not(#\#):not(#\#):not(#\#){visibility:visible}
1332
1331
  .x5um2zc.x5um2zc:where(.x1twag4g:first-child *):not(#\#):not(#\#):not(#\#){visibility:hidden}
1333
1332
  .x1se5z8o.x1se5z8o:where(.x1twag4g:last-child *):not(#\#):not(#\#):not(#\#){visibility:hidden}
1333
+ .x6ipy2d.x6ipy2d:where(.x1u3b27q:active *):not(#\#):not(#\#):not(#\#){background-color:var(--color-overlay-pressed)}
1334
1334
  @supports (animation-timeline: view()){.x1iu2jvn.x1iu2jvn:not(#\#):not(#\#):not(#\#){animation-name:x1tut0r7-B}}
1335
1335
  @supports (container-type: scroll-state){.xafyuhj.xafyuhj:not(#\#):not(#\#):not(#\#){container-type:scroll-state}}
1336
1336
  .xfd3fxj:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){animation-name:x1c2q33o-B}
@@ -1364,6 +1364,7 @@
1364
1364
  .xx47ajj:focus-visible:not(#\#):not(#\#):not(#\#){outline-color:var(--focus-outline-color)}
1365
1365
  .x7s97pk:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:2px}
1366
1366
  .x1nw7mhf:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:calc(-1 * var(--focus-outline-width))}
1367
+ .x1l5jwag:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:calc(0px - var(--focus-outline-width))}
1367
1368
  .x13aywxo:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:var(--button-focus-offset)}
1368
1369
  .x1vwwbsn:focus-visible:not(#\#):not(#\#):not(#\#){outline-offset:var(--focus-outline-offset)}
1369
1370
  .xwz5zln.xwz5zln:where(.x1iwu4tg:has(:focus-visible) *):not(#\#):not(#\#):not(#\#){outline-offset:var(--focus-outline-offset)}
@@ -1449,8 +1450,6 @@
1449
1450
  @media (max-width: 480px){.xedohl4.xedohl4:not(#\#):not(#\#):not(#\#){display:flex}}
1450
1451
  @media (pointer: coarse){.xhj50sb.xhj50sb:not(#\#):not(#\#):not(#\#){display:none}}
1451
1452
  @media (max-width: 480px){.x1rpgqan.x1rpgqan:not(#\#):not(#\#):not(#\#){flex-direction:column}}
1452
- @media (pointer: coarse){.x6pjikd.x6pjikd:not(#\#):not(#\#):not(#\#){font-size:max(1rem,var(--text-body-size))}}
1453
- @media (pointer: coarse){.xdk3u5w.xdk3u5w:not(#\#):not(#\#):not(#\#){font-size:max(1rem,var(--text-label-size))}}
1454
1453
  @media (pointer: coarse){.x1jymrmb.x1jymrmb:not(#\#):not(#\#):not(#\#){margin-inline-start:auto}}
1455
1454
  @media (forced-colors: active){.x1tbh5bv.x1tbh5bv:not(#\#):not(#\#):not(#\#){opacity:1}}
1456
1455
  @media (pointer: coarse){.xozvky.xozvky:not(#\#):not(#\#):not(#\#){order:1}}
@@ -1479,7 +1478,11 @@
1479
1478
  @media (hover: hover){.x8ydxbz.x8ydxbz.x8ydxbz:where(.x84s7jz:hover *):not(#\#):not(#\#):not(#\#){pointer-events:auto}}
1480
1479
  @media (hover: hover){.x17hxqr7.x17hxqr7.x17hxqr7:where(.x84s7jz:hover *):not(#\#):not(#\#):not(#\#){transform:translateY(0)}}
1481
1480
  @media (hover: hover){.xneequu.xneequu.xneequu:where(.x84s7jz:hover *):not(#\#):not(#\#):not(#\#){visibility:visible}}
1481
+ @media (hover: hover){.x74x3iv.x74x3iv.x74x3iv:where(.x1u3b27q:active *):not(#\#):not(#\#):not(#\#){background-color:var(--color-overlay-pressed)}}
1482
+ @media (forced-colors: none){.x1xm682w.x1xm682w.x1xm682w:where(.x1iwu4tg:active *):not(#\#):not(#\#):not(#\#){background-image:linear-gradient(var(--color-overlay-pressed),var(--color-overlay-pressed))}}
1482
1483
  @supports (animation-timeline: view()){@media (prefers-reduced-motion: reduce){.xk3h8ob.xk3h8ob.xk3h8ob:not(#\#):not(#\#):not(#\#){animation-name:xuvekqa-B}}}
1484
+ @supports (-webkit-touch-callout: none){@media (pointer: coarse){.xf9zqsd.xf9zqsd.xf9zqsd:not(#\#):not(#\#):not(#\#){font-size:max(1rem,var(--text-body-size))}}}
1485
+ @supports (-webkit-touch-callout: none){@media (pointer: coarse){.x1w61h2b.x1w61h2b.x1w61h2b:not(#\#):not(#\#):not(#\#){font-size:max(1rem,var(--text-label-size))}}}
1483
1486
  @media (hover: hover){.xvxo0qp.xvxo0qp.xvxo0qp:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:color-mix(in srgb,var(--color-accent),var(--color-tint-hover) 15%)}}
1484
1487
  @media (hover: hover){.x1pfkqlk.x1pfkqlk.x1pfkqlk:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:transparent}}
1485
1488
  @media (hover: hover){.xcu6dpe.xcu6dpe.xcu6dpe:hover:where(:not(:disabled,[aria-disabled="true"])):not(#\#):not(#\#):not(#\#){background-color:var(--color-neutral)}}
@@ -1560,7 +1563,6 @@
1560
1563
  .xs02d24:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(100% + 1px)}
1561
1564
  .x12qplqi:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(100% + var(--container-padding-block-start,0px) + var(--container-padding-block-end,0px))}
1562
1565
  .xpa73km:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(100dvh - var(--_app-shell-header-height,0px))}
1563
- .x1oglpa6:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(max(1rem,var(--text-body-size)) * var(--text-body-leading));height:1lh}
1564
1566
  .x1tpcejd:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--_sheet-budget) + 48px)}
1565
1567
  .x1uiybsj:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-lg) - 4px)}
1566
1568
  .x102lyln:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-lg) - 8px)}
@@ -1569,6 +1571,7 @@
1569
1571
  .x1u5rhrp:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-md) + var(--spacing-1))}
1570
1572
  .xzj98nu:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-sm) - 4px)}
1571
1573
  .xzydfjl:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--size-element-sm) - 8px)}
1574
+ .x1mutkkf:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--text-body-size) * var(--text-body-leading));height:1lh}
1572
1575
  .x1q370uo:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--text-body-size) * var(--text-body-leading))}
1573
1576
  .x14o5nre:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(var(--text-supporting-size) * var(--text-supporting-leading))}
1574
1577
  .xw1wawg:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(44px - 8px)}
@@ -1868,6 +1871,7 @@
1868
1871
  @media (pointer: coarse){.xkagaj0.xkagaj0:not(#\#):not(#\#):not(#\#):not(#\#){min-width:24px}}
1869
1872
  @media (pointer: coarse){.x1xrq5m.x1xrq5m:not(#\#):not(#\#):not(#\#):not(#\#){min-width:44px}}
1870
1873
  @media (pointer: coarse){.xngvp7v.xngvp7v:not(#\#):not(#\#):not(#\#):not(#\#){min-width:44px}}
1874
+ @supports (-webkit-touch-callout: none){@media (pointer: coarse){.x9w4715.x9w4715.x9w4715:not(#\#):not(#\#):not(#\#):not(#\#){height:calc(max(1rem,var(--text-body-size)) * var(--text-body-leading));height:1lh}}}
1871
1875
  @starting-style{.x1sopeo2.x1sopeo2:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){grid-template-rows:0fr}}
1872
1876
  .x1xsm0q9:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset:-14px}
1873
1877
  .xarstr8:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset:0}
@@ -1885,6 +1889,8 @@
1885
1889
  @starting-style{.x14gflnl.x14gflnl:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#){transform:translateX(100%)}}
1886
1890
  .x1k48kgn:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{border-radius:inherit}
1887
1891
  .xxyica1:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{border-radius:inherit}
1892
+ .xq94oqs:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{border-radius:var(--radius-full)}
1893
+ .xtb6wbx:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{border-radius:var(--radius-inner)}
1888
1894
  .x17gn2l9:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{grid-column:1}
1889
1895
  .xd54j2p:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{inset-block:0}
1890
1896
  .xpsyfx0:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::-webkit-date-and-time-value{margin-block:0}
@@ -1964,6 +1970,8 @@
1964
1970
  .xa5v58t:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transition-timing-function:var(--ease-standard)}
1965
1971
  .x1rbqspl:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{user-select:none}
1966
1972
  .xy5mcqj:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{z-index:-1}
1973
+ .xzywxsk.xzywxsk:where(.x1odsvnm:active *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-color:var(--color-overlay-pressed)}
1974
+ .x2kv6q6.x2kv6q6:where(.x1odsvnm:active:not(:has(a:active,button:active,[role="button"]:active,[role="link"]:active)) *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-color:var(--color-overlay-pressed)}
1967
1975
  .xk7vujl:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-image:linear-gradient(to left,var(--color-shadow),transparent)}
1968
1976
  .xlptwl5:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::after{background-image:linear-gradient(to right,var(--color-shadow),transparent)}
1969
1977
  .xdq8fwl:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#):not(#\#)::before{transform-origin:right center}
@@ -4,6 +4,11 @@
4
4
  * @output Exports reusable background-color and background-image state styles
5
5
  * @position Internal styling utility for interactive core surfaces
6
6
  *
7
+ * Every surface that paints a press composes one of these (or carries its own
8
+ * `:active` rule), so a change to how the system answers a press is made here
9
+ * once. `pressedBackgroundColor` is the press without the hover, for controls
10
+ * whose hover is a colour or nothing.
11
+ *
7
12
  * Keep the enabled guard outside the individual states. StyleX assigns an
8
13
  * extra priority bucket (and generated selector specificity) to media-nested
9
14
  * rules. Repeating `:active` inside the hover-capable branch gives hover and
@@ -22,5 +27,8 @@ export declare const interactionOverlayStyles: Readonly<{
22
27
  readonly backgroundImageOnNeutral: Readonly<{
23
28
  readonly backgroundImage: stylex.StyleXClassNameFor<"backgroundImage", string | null>;
24
29
  }>;
30
+ readonly pressedBackgroundColor: Readonly<{
31
+ readonly backgroundColor: stylex.StyleXClassNameFor<"backgroundColor", "light-dark(#05365919, #FFFFFF19)" | null>;
32
+ }>;
25
33
  }>;
26
34
  //# sourceMappingURL=interactionOverlay.stylex.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"interactionOverlay.stylex.d.ts","sourceRoot":"","sources":["../../src/utils/interactionOverlay.stylex.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAU3C,eAAO,MAAM,wBAAwB;;;;;;;;;;EA2CnC,CAAC"}
1
+ {"version":3,"file":"interactionOverlay.stylex.d.ts","sourceRoot":"","sources":["../../src/utils/interactionOverlay.stylex.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,MAAM,MAAM,kBAAkB,CAAC;AAU3C,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;EA0DnC,CAAC"}
@@ -10,6 +10,11 @@
10
10
  * @output Exports reusable background-color and background-image state styles
11
11
  * @position Internal styling utility for interactive core surfaces
12
12
  *
13
+ * Every surface that paints a press composes one of these (or carries its own
14
+ * `:active` rule), so a change to how the system answers a press is made here
15
+ * once. `pressedBackgroundColor` is the press without the hover, for controls
16
+ * whose hover is a colour or nothing.
17
+ *
13
18
  * Keep the enabled guard outside the individual states. StyleX assigns an
14
19
  * extra priority bucket (and generated selector specificity) to media-nested
15
20
  * rules. Repeating `:active` inside the hover-capable branch gives hover and
@@ -38,5 +43,9 @@ export const interactionOverlayStyles = {
38
43
  backgroundImageOnNeutral: {
39
44
  kKwaWg: "x14bno8m xzmimnh x1otsd3y xo3fi6e",
40
45
  $$css: true
46
+ },
47
+ pressedBackgroundColor: {
48
+ kWkggS: "x1anq1lc",
49
+ $$css: true
41
50
  }
42
51
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/core",
3
- "version": "0.6.2-canary.bfee8a4",
3
+ "version": "0.6.2-canary.c8d5849",
4
4
  "displayName": "Astryx Core",
5
5
  "description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
6
6
  "author": "Meta Open Source",
@@ -619,6 +619,16 @@
619
619
  "types": "./dist/utils/index.d.ts",
620
620
  "default": "./dist/utils/index.js"
621
621
  },
622
+ "./Markdown/plugins": {
623
+ "source": "./src/Markdown/plugins/index.ts",
624
+ "types": "./dist/Markdown/plugins/index.d.ts",
625
+ "default": "./dist/Markdown/plugins/index.js"
626
+ },
627
+ "./Markdown/parser": {
628
+ "source": "./src/Markdown/parser/index.ts",
629
+ "types": "./dist/Markdown/parser/index.d.ts",
630
+ "default": "./dist/Markdown/parser/index.js"
631
+ },
622
632
  "./Calendar/utils": {
623
633
  "source": "./src/Calendar/utils.ts",
624
634
  "types": "./dist/Calendar/utils.d.ts",
@@ -653,6 +663,11 @@
653
663
  "source": "./src/Typeahead/utils.ts",
654
664
  "types": "./dist/Typeahead/utils.d.ts",
655
665
  "default": "./dist/Typeahead/utils.js"
666
+ },
667
+ "./Markdown/remark": {
668
+ "source": "./src/Markdown/remark.ts",
669
+ "types": "./dist/Markdown/remark.d.ts",
670
+ "default": "./dist/Markdown/remark.js"
656
671
  }
657
672
  },
658
673
  "files": [
@@ -672,8 +687,8 @@
672
687
  "react-dom": ">=19.0.0"
673
688
  },
674
689
  "devDependencies": {
675
- "@astryxdesign/a11y-spec": "0.6.2-canary.bfee8a4",
676
- "@astryxdesign/cli": "0.6.2-canary.bfee8a4",
690
+ "@astryxdesign/a11y-spec": "0.6.2-canary.c8d5849",
691
+ "@astryxdesign/cli": "0.6.2-canary.c8d5849",
677
692
  "@babel/cli": "^7.29.7",
678
693
  "@babel/core": "^7.29.7",
679
694
  "@babel/preset-react": "^7.29.7",
@@ -21,7 +21,13 @@
21
21
  * ./Button.a11y.known-failures.ts, both shared with the jsdom lane.
22
22
  */
23
23
 
24
- import {expect, test, type CDPSession, type Page} from '@playwright/test';
24
+ import {
25
+ expect,
26
+ test,
27
+ type CDPSession,
28
+ type Locator,
29
+ type Page,
30
+ } from '@playwright/test';
25
31
  import {
26
32
  BUTTON_PATTERN,
27
33
  blockingResults,
@@ -93,6 +99,14 @@ async function activationsOn(page: Page): Promise<number> {
93
99
  return Number(raw ?? '0');
94
100
  }
95
101
 
102
+ function pointerTargetFor(
103
+ page: Page,
104
+ state: ButtonBindingRow,
105
+ ): Locator | undefined {
106
+ const selector = (state as ButtonBindingState).pointerTargetSelector;
107
+ return selector == null ? undefined : page.locator(selector).first();
108
+ }
109
+
96
110
  async function runState(
97
111
  page: Page,
98
112
  cdp: CDPSession,
@@ -111,6 +125,7 @@ async function runState(
111
125
  return createChromiumHarness({
112
126
  page,
113
127
  subject: page.locator('#storybook-root').getByRole('button').first(),
128
+ pointerTarget: pointerTargetFor(page, state),
114
129
  cdp,
115
130
  });
116
131
  },
@@ -306,6 +321,7 @@ test('every expectation is exercised by at least one bound state', async ({
306
321
  .locator('#storybook-root')
307
322
  .getByRole('button')
308
323
  .first(),
324
+ pointerTarget: pointerTargetFor(page, state),
309
325
  cdp,
310
326
  });
311
327
  },
@@ -83,33 +83,4 @@ export const BUTTON_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
83
83
  userImpact: 'The same, from an icon button.',
84
84
  reason: 'Inherited from Button, as above.',
85
85
  },
86
-
87
- // ---- ClickableCard's role-bearing element cannot be clicked -------------
88
- {
89
- expectation: 'button.action.survives-an-aborted-press',
90
- binding: 'ClickableCard',
91
- state: 'clickable-card',
92
- evidenceLayer: 'real-browser',
93
- failureEquals:
94
- 'a pointer press cannot land on this control: something else is on top of it at its own centre, so there is no press here to abort',
95
- standardsReference: 'WCAG 2.2 2.5.2 Pointer Cancellation (Level A)',
96
- userImpact:
97
- 'The same defect seen from the other side: pointer cancellation cannot be demonstrated on a control no pointer press can land on. Recorded rather than reported green — a serene pass here would claim an outcome nobody observed.',
98
- reason:
99
- 'Same cause as the record above. It is a second record rather than a wider one because a known failure names exactly one outcome, and these two would be fixed and verified separately.',
100
- },
101
- {
102
- expectation: 'button.action.runs-on-pointer',
103
- binding: 'ClickableCard',
104
- state: 'clickable-card',
105
- evidenceLayer: 'real-browser',
106
- failureEquals:
107
- 'a pointer could not reach this control within 2000ms: the browser never found it visible, stable, and able to receive a pointer event. Something is covering it, or it is clipped to nothing.',
108
- standardsReference:
109
- 'Current Astryx buttons family FR2 and WAI-ARIA APG Button operability requirement; supports WCAG 2.2 4.1.2 Name, Role, Value (Level A)',
110
- userImpact:
111
- "Anyone whose tooling acts on the accessible object rather than on pixels — a speech-input user saying the card's name, or assistive technology dispatching a click at the element it is told is the button — aims at a 1×1 control the card's own content paints over. A sighted mouse user is unaffected: they click the card surface, which handles it.",
112
- reason:
113
- 'ClickableCard deliberately splits the surface that takes the click from the hidden button that carries the role and name. Reconciling the two is a design-system decision, not a change this contract should make.',
114
- },
115
86
  ];
@@ -88,12 +88,19 @@ export const BUTTON_STATE_RENDERS: Record<ButtonStateId, StateRender> = {
88
88
  ),
89
89
 
90
90
  'clickable-card': activate => (
91
- <ClickableCard label="Open billing settings" onClick={activate}>
91
+ <ClickableCard
92
+ data-a11y-pointer-target
93
+ label="Open billing settings"
94
+ onClick={activate}>
92
95
  <div>Billing</div>
93
96
  </ClickableCard>
94
97
  ),
95
98
  'clickable-card-disabled': activate => (
96
- <ClickableCard label="Open billing settings" isDisabled onClick={activate}>
99
+ <ClickableCard
100
+ data-a11y-pointer-target
101
+ label="Open billing settings"
102
+ isDisabled
103
+ onClick={activate}>
97
104
  <div>Billing</div>
98
105
  </ClickableCard>
99
106
  ),
@@ -92,6 +92,13 @@ export interface ButtonBindingState {
92
92
  * typo here is reported as a stale inventory, not as a standards failure.
93
93
  */
94
94
  readonly visibleLabel: string | null;
95
+ /**
96
+ * The surface that receives pointer input when it is not the role-bearing
97
+ * element. ClickableCard keeps its button/link hidden for role, name, and
98
+ * keyboard focus, and takes the pointer on the card surface; a binding that
99
+ * aimed the pointer at the hidden control would be testing the wrong surface.
100
+ */
101
+ readonly pointerTargetSelector?: string;
95
102
  /** The checked-in Storybook story the Chromium lane drives. */
96
103
  readonly storyId: string;
97
104
  /**
@@ -220,6 +227,7 @@ export const BUTTON_BINDING_STATES = [
220
227
  "a card whose whole surface performs an action, through the hidden button that carries the card's role and name",
221
228
  facts: facts(),
222
229
  visibleLabel: null,
230
+ pointerTargetSelector: '[data-a11y-pointer-target]',
223
231
  storyId: 'a11y-button-pattern--clickable-card-default',
224
232
  },
225
233
  {
@@ -228,6 +236,7 @@ export const BUTTON_BINDING_STATES = [
228
236
  summary: 'a disabled action card',
229
237
  facts: facts({operable: false, focusable: false, unavailable: true}),
230
238
  visibleLabel: null,
239
+ pointerTargetSelector: '[data-a11y-pointer-target]',
231
240
  storyId: 'a11y-button-pattern--clickable-card-disabled',
232
241
  },
233
242
 
@@ -7,7 +7,7 @@ export const docs = {
7
7
  subComponentOf: 'Chat',
8
8
  displayName: 'Chat Composer Input',
9
9
  isHiddenFromOverview: true,
10
- description: "Rich text input for the chat composer. Supports trigger menus (type @ or / to open a typeahead), inline tokens rendered as badges, message history recall with ArrowUp/Down, paste/drop file handling, and a 16px touch-device font-size floor to prevent iOS input zoom. Pass it to ChatComposer's input slot when you need more than a plain textarea.",
10
+ description: "Rich text input for the chat composer. Supports trigger menus (type @ or / to open a typeahead), inline tokens rendered as badges, message history recall with ArrowUp/Down, paste/drop file handling, and a 16px iOS font-size floor to prevent input zoom. Pass it to ChatComposer's input slot when you need more than a plain textarea.",
11
11
  props: [
12
12
  {
13
13
  name: 'handleRef',
@@ -92,7 +92,7 @@ export const docsZh = {
92
92
  name: 'ChatComposerInput',
93
93
  isHiddenFromOverview: true,
94
94
  displayName: 'Chat Composer Input',
95
- description: '聊天编写器的富文本输入。支持触发菜单(输入 @ 或 / 打开 typeahead)、内联标记徽章、ArrowUp/Down 消息历史回溯、粘贴/拖放文件处理,并在触控设备上将字体大小保持至少 16px 以避免 iOS 输入缩放。当需要普通文本区域以外的功能时,传入 ChatComposer 的 input 插槽。',
95
+ description: '聊天编写器的富文本输入。支持触发菜单(输入 @ 或 / 打开 typeahead)、内联标记徽章、ArrowUp/Down 消息历史回溯、粘贴/拖放文件处理,并在 iOS 上将字体大小保持至少 16px 以避免输入缩放。当需要普通文本区域以外的功能时,传入 ChatComposer 的 input 插槽。',
96
96
  propDescriptions: {
97
97
  handleRef: '命令式句柄,用于编程式控制:insertToken、insertText、focus 和 getValue。',
98
98
  value: '受控输入值。与 onChange 配对实现双向绑定。',
@@ -115,7 +115,7 @@ export const docsDense = {
115
115
  name: 'ChatComposerInput',
116
116
  isHiddenFromOverview: true,
117
117
  displayName: 'Chat Composer Input',
118
- description: 'rich input for composer; trigger menus (@/commands), inline tokens, msg history, paste/drop files, 16px touch font-size floor to prevent iOS zoom. Use in ChatComposer input slot when you need more than plain textarea.',
118
+ description: 'rich input for composer; trigger menus (@/commands), inline tokens, msg history, paste/drop files, 16px iOS font-size floor to prevent zoom. Use in ChatComposer input slot when you need more than plain textarea.',
119
119
  propDescriptions: {
120
120
  handleRef: 'imperative handle (insertToken/insertText/focus/getValue)',
121
121
  value: 'controlled value; pair w/ onChange for two-way binding',
@@ -233,9 +233,14 @@ const styles = stylex.create({
233
233
  whiteSpace: 'pre-wrap',
234
234
  wordBreak: 'break-word',
235
235
  overflowY: 'auto',
236
+ // The 16px floor is iOS-only: iOS Safari zooms the page when a focused
237
+ // control sits under 16px, and only iOS WebKit implements
238
+ // -webkit-touch-callout to key the coarse-pointer floor to it.
236
239
  fontSize: {
237
240
  default: typeScaleVars['--text-body-size'],
238
- '@media (pointer: coarse)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
241
+ '@media (pointer: coarse)': {
242
+ '@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
243
+ },
239
244
  },
240
245
  lineHeight: `${LINE_HEIGHT_PX}px`,
241
246
  fontFamily: typographyVars['--font-family-body'],
@@ -250,9 +255,12 @@ const styles = stylex.create({
250
255
  insetInlineEnd: 0,
251
256
  pointerEvents: 'none',
252
257
  color: colorVars['--color-text-secondary'],
258
+ // Same iOS-only floor as the editable region it stands in for.
253
259
  fontSize: {
254
260
  default: typeScaleVars['--text-body-size'],
255
- '@media (pointer: coarse)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
261
+ '@media (pointer: coarse)': {
262
+ '@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
263
+ },
256
264
  },
257
265
  lineHeight: `${LINE_HEIGHT_PX}px`,
258
266
  fontFamily: typographyVars['--font-family-body'],
@@ -137,6 +137,17 @@ export const docs = {
137
137
  ],
138
138
  },
139
139
  usage: {
140
+ accessibility: [
141
+ {
142
+ name: 'Checkbox box',
143
+ category: 'Color contrast',
144
+ criterion: '1.4.11 Non-text Contrast',
145
+ requirement: '3:1',
146
+ states: ['Rest', 'Hover', 'Pointer down', 'Checked'],
147
+ description:
148
+ 'The box edge (unchecked) and fill (checked) must have at least 3:1 contrast with the surface behind them. For Hover and Pointer down, measure the final colors after the tint and the pressed overlay are applied.',
149
+ },
150
+ ],
140
151
  description: 'CheckboxInput toggles a single on/off value. Use it for settings like "Enable notifications", terms acceptance, or opt-in choices. For multiple checkboxes in a group, use CheckboxList instead.',
141
152
  bestPractices: [
142
153
  { guidance: true, description: 'Always provide a visible label so the user knows what they are toggling. Use isLabelHidden only when surrounding context makes it obvious.' },
@@ -15,6 +15,7 @@
15
15
  import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
16
16
  import {render, screen, fireEvent, waitFor} from '@testing-library/react';
17
17
  import userEvent from '@testing-library/user-event';
18
+ import {hasPressedArm} from '../__tests__/pressState';
18
19
  import {CheckboxInput} from './CheckboxInput';
19
20
  import {Theme} from '../theme/Theme';
20
21
  import {defineTheme} from '../theme/defineTheme';
@@ -763,3 +764,36 @@ describe('label theme target', () => {
763
764
  expect(label).toHaveClass('astryx-checkbox-label');
764
765
  });
765
766
  });
767
+
768
+ describe('pressed state', () => {
769
+ it('paints the pressed overlay over the indicator while the row is pressed', () => {
770
+ const {container} = render(
771
+ <CheckboxInput label="Accept terms" value={false} onChange={() => {}} />,
772
+ );
773
+ const box = container.querySelector('.astryx-checkbox-indicator');
774
+ const wrapper = box?.parentElement?.parentElement;
775
+ if (wrapper == null) {
776
+ throw new Error('the checkbox has no indicator wrapper to press');
777
+ }
778
+ // The owner paints over the resolved indicator, so the treatment survives a
779
+ // theme replacement that does not forward style props.
780
+ expect(hasPressedArm(wrapper)).toBe(true);
781
+ });
782
+
783
+ it('does not expose a pressed arm on a disabled checkbox', () => {
784
+ const {container} = render(
785
+ <CheckboxInput
786
+ label="Unavailable"
787
+ value={false}
788
+ onChange={() => {}}
789
+ isDisabled
790
+ />,
791
+ );
792
+ const box = container.querySelector('.astryx-checkbox-indicator');
793
+ const wrapper = box?.parentElement?.parentElement;
794
+ if (wrapper == null) {
795
+ throw new Error('the checkbox has no indicator wrapper');
796
+ }
797
+ expect(hasPressedArm(wrapper)).toBe(false);
798
+ });
799
+ });
@@ -70,6 +70,22 @@ const styles = stylex.create({
70
70
  flexShrink: 0,
71
71
  isolation: 'isolate',
72
72
  },
73
+ // The owner paints this layer over the resolved indicator, so a theme
74
+ // replacement cannot accidentally drop the component's pressed contract.
75
+ indicatorPressOverlay: {
76
+ '::after': {
77
+ content: '""',
78
+ position: 'absolute',
79
+ inset: 0,
80
+ borderRadius: radiusVars['--radius-inner'],
81
+ pointerEvents: 'none',
82
+ backgroundColor: {
83
+ default: 'transparent',
84
+ [stylex.when.ancestor(':active', indicatorScope)]:
85
+ colorVars['--color-overlay-pressed'],
86
+ },
87
+ },
88
+ },
73
89
  // Holds only the indicator, so the focus ring has one unambiguous target.
74
90
  // `display: contents` adds no box of its own — the indicator keeps whatever
75
91
  // layout relationship it already had with the wrapper.
@@ -399,7 +415,11 @@ export function CheckboxInput({
399
415
  !isDisabled && indicatorScope,
400
416
  )}>
401
417
  <div
402
- {...stylex.props(styles.checkboxWrapper, wrapperSizeStyles[size])}
418
+ {...stylex.props(
419
+ styles.checkboxWrapper,
420
+ wrapperSizeStyles[size],
421
+ !isDisabled && styles.indicatorPressOverlay,
422
+ )}
403
423
  {...focusProps}>
404
424
  <input
405
425
  {...rest}
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {describe, it, expect, vi} from 'vitest';
4
4
  import {render, screen, fireEvent} from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
5
6
  import {ClickableCard} from './ClickableCard';
6
7
 
7
8
  describe('ClickableCard', () => {
@@ -47,6 +48,47 @@ describe('ClickableCard', () => {
47
48
  expect(handleClick).toHaveBeenCalledTimes(1);
48
49
  });
49
50
 
51
+ it('calls onClick once when the accessible control itself is clicked', () => {
52
+ const handleClick = vi.fn();
53
+ render(
54
+ <ClickableCard label="Test card" onClick={handleClick}>
55
+ <span>Content</span>
56
+ </ClickableCard>,
57
+ );
58
+ // Pointer activation aimed at the element carrying the role — what
59
+ // speech input, assistive technology, and automation dispatch.
60
+ fireEvent.click(screen.getByRole('button', {name: 'Test card'}));
61
+ expect(handleClick).toHaveBeenCalledTimes(1);
62
+ });
63
+
64
+ it('passes the card surface as currentTarget for surface clicks', () => {
65
+ const seen: EventTarget[] = [];
66
+ render(
67
+ <ClickableCard
68
+ label="Test card"
69
+ onClick={e => seen.push(e.currentTarget)}>
70
+ <span>Content</span>
71
+ </ClickableCard>,
72
+ );
73
+ fireEvent.click(screen.getByText('Content'));
74
+ expect(seen).toHaveLength(1);
75
+ expect(seen[0]).toBe(screen.getByText('Content').parentElement);
76
+ });
77
+
78
+ it('calls onClick exactly once when the surface of an href card is clicked without preventDefault', () => {
79
+ const handleClick = vi.fn();
80
+ render(
81
+ <ClickableCard label="Nav card" href="/settings" onClick={handleClick}>
82
+ <span>Content</span>
83
+ </ClickableCard>,
84
+ );
85
+ // The container hook proxies the surface click to the link with
86
+ // `link.click()`; that synthetic click bubbles back through the card and
87
+ // must not run the consumer callback a second time.
88
+ fireEvent.click(screen.getByText('Content'));
89
+ expect(handleClick).toHaveBeenCalledTimes(1);
90
+ });
91
+
50
92
  it('does NOT call onClick when a nested button is clicked', () => {
51
93
  const handleCardClick = vi.fn();
52
94
  const handleButtonClick = vi.fn();
@@ -86,25 +128,80 @@ describe('ClickableCard', () => {
86
128
  expect(link).toHaveAttribute('target', '_blank');
87
129
  });
88
130
 
89
- it('disabled button is disabled', () => {
131
+ it('disabled button is disabled and the surface runs nothing', () => {
90
132
  const handleClick = vi.fn();
91
133
  render(
92
134
  <ClickableCard label="Disabled" onClick={handleClick} isDisabled>
93
- Content
135
+ <span>Content</span>
94
136
  </ClickableCard>,
95
137
  );
96
138
  const button = screen.getByRole('button', {name: 'Disabled'});
97
139
  expect(button).toBeDisabled();
140
+ fireEvent.click(screen.getByText('Content'));
141
+ fireEvent.click(button);
142
+ expect(handleClick).not.toHaveBeenCalled();
98
143
  });
99
144
 
100
- it('disabled link has aria-disabled', () => {
145
+ it('disabled link has aria-disabled, leaves the tab order, and the surface runs nothing', () => {
146
+ const handleClick = vi.fn();
101
147
  render(
102
- <ClickableCard label="Disabled link" href="/settings" isDisabled>
103
- Content
148
+ <ClickableCard
149
+ label="Disabled link"
150
+ href="/settings"
151
+ onClick={handleClick}
152
+ isDisabled>
153
+ <span>Content</span>
104
154
  </ClickableCard>,
105
155
  );
106
156
  const link = screen.getByRole('link', {name: 'Disabled link'});
107
157
  expect(link).toHaveAttribute('aria-disabled', 'true');
158
+ expect(link).toHaveAttribute('tabindex', '-1');
159
+ fireEvent.click(screen.getByText('Content'));
160
+ expect(handleClick).not.toHaveBeenCalled();
161
+ });
162
+
163
+ it('runs onClick once from the keyboard via the hidden button', async () => {
164
+ const user = userEvent.setup();
165
+ const handleClick = vi.fn();
166
+ render(
167
+ <ClickableCard label="Test card" onClick={handleClick}>
168
+ <span>Content</span>
169
+ </ClickableCard>,
170
+ );
171
+ await user.tab();
172
+ expect(screen.getByRole('button', {name: 'Test card'})).toHaveFocus();
173
+ await user.keyboard('{Enter}');
174
+ await user.keyboard(' ');
175
+ expect(handleClick).toHaveBeenCalledTimes(2);
176
+ });
177
+
178
+ it('does NOT call onClick when a nested input is clicked', () => {
179
+ const handleCardClick = vi.fn();
180
+ render(
181
+ <ClickableCard label="Test card" onClick={handleCardClick}>
182
+ <input aria-label="Quantity" readOnly value="1" />
183
+ </ClickableCard>,
184
+ );
185
+ fireEvent.click(screen.getByRole('textbox', {name: 'Quantity'}));
186
+ expect(handleCardClick).not.toHaveBeenCalled();
187
+ });
188
+
189
+ it('does NOT call onClick when text inside the card is selected', () => {
190
+ const handleClick = vi.fn();
191
+ render(
192
+ <ClickableCard label="Test card" onClick={handleClick}>
193
+ <span>Selectable body text</span>
194
+ </ClickableCard>,
195
+ );
196
+ const text = screen.getByText('Selectable body text');
197
+ const range = document.createRange();
198
+ range.selectNodeContents(text);
199
+ const selection = document.getSelection()!;
200
+ selection.removeAllRanges();
201
+ selection.addRange(range);
202
+ fireEvent.click(text);
203
+ expect(handleClick).not.toHaveBeenCalled();
204
+ selection.removeAllRanges();
108
205
  });
109
206
 
110
207
  describe('elevation', () => {