@astryxdesign/core 0.6.2 → 0.6.3-canary.039a67e

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 (621) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/Avatar/Avatar.d.ts.map +1 -1
  3. package/dist/Avatar/Avatar.js +33 -12
  4. package/dist/BottomSheet/BottomSheet.d.ts +1 -1
  5. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheet.js +3 -1
  7. package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
  8. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.js +56 -19
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +13 -28
  12. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  13. package/dist/Chat/ChatComposer.js +10 -5
  14. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  15. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  16. package/dist/Chat/ChatComposerDrawer.js +48 -23
  17. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  18. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  19. package/dist/Chat/ChatComposerInput.js +63 -16
  20. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  21. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  22. package/dist/Chat/ChatDictationButton.js +6 -4
  23. package/dist/Chat/ChatLayout.d.ts +19 -0
  24. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  25. package/dist/Chat/ChatLayout.js +19 -0
  26. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  27. package/dist/Chat/ChatLayoutScrollButton.js +44 -34
  28. package/dist/Chat/ChatMessageBubble.d.ts +2 -0
  29. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  30. package/dist/Chat/ChatMessageBubble.js +5 -3
  31. package/dist/Chat/ChatMessageList.d.ts +2 -1
  32. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  33. package/dist/Chat/ChatMessageList.js +4 -3
  34. package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
  35. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  36. package/dist/Chat/ChatMessageMetadata.js +12 -9
  37. package/dist/Chat/ChatSendButton.d.ts +2 -1
  38. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  39. package/dist/Chat/ChatSendButton.js +6 -4
  40. package/dist/Chat/ChatSystemMessage.d.ts +3 -3
  41. package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
  42. package/dist/Chat/ChatSystemMessage.js +2 -2
  43. package/dist/Chat/ChatTokenizedText.d.ts +6 -6
  44. package/dist/Chat/ChatTokenizedText.js +10 -6
  45. package/dist/Chat/ChatToolCalls.d.ts +7 -9
  46. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  47. package/dist/Chat/ChatToolCalls.js +43 -26
  48. package/dist/Chat/index.d.ts +1 -1
  49. package/dist/Chat/index.d.ts.map +1 -1
  50. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  51. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  52. package/dist/Citation/Citation.d.ts +1 -1
  53. package/dist/Citation/Citation.d.ts.map +1 -1
  54. package/dist/Citation/Citation.js +3 -2
  55. package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
  56. package/dist/CodeBlock/highlightRanges.js +14 -3
  57. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  58. package/dist/Collapsible/Collapsible.js +6 -1
  59. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  60. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  61. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  62. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  63. package/dist/DateInput/DateInput.d.ts +25 -5
  64. package/dist/DateInput/DateInput.d.ts.map +1 -1
  65. package/dist/DateInput/DateInput.js +29 -17
  66. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  67. package/dist/DateInput/NativeDateField.js +16 -16
  68. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  69. package/dist/DateInput/TouchDateField.js +2 -2
  70. package/dist/DateInput/index.d.ts +1 -1
  71. package/dist/DateInput/index.d.ts.map +1 -1
  72. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  73. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  74. package/dist/DateTimeInput/DateTimeInput.d.ts +32 -15
  75. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  76. package/dist/DateTimeInput/DateTimeInput.js +55 -30
  77. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  78. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  79. package/dist/DateTimeInput/index.d.ts +1 -1
  80. package/dist/DateTimeInput/index.d.ts.map +1 -1
  81. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  82. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  83. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  84. package/dist/Dialog/DialogHeader.d.ts +8 -1
  85. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  86. package/dist/Dialog/DialogHeader.js +13 -4
  87. package/dist/Field/InputClearButton.d.ts +4 -2
  88. package/dist/Field/InputClearButton.d.ts.map +1 -1
  89. package/dist/Field/InputClearButton.js +4 -2
  90. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  91. package/dist/Field/PanelSearchInput.js +1 -1
  92. package/dist/FileInput/FileInput.d.ts.map +1 -1
  93. package/dist/FileInput/FileInput.js +7 -7
  94. package/dist/Icon/Icon.d.ts +6 -31
  95. package/dist/Icon/Icon.d.ts.map +1 -1
  96. package/dist/Icon/Icon.js +8 -71
  97. package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
  98. package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
  99. package/dist/Icon/IconDefaultSizeContext.js +18 -0
  100. package/dist/Icon/IconSize.stylex.d.ts +65 -0
  101. package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
  102. package/dist/Icon/IconSize.stylex.js +75 -0
  103. package/dist/Item/Item.d.ts +1 -1
  104. package/dist/Item/Item.d.ts.map +1 -1
  105. package/dist/Item/Item.js +4 -3
  106. package/dist/Kbd/Kbd.d.ts +5 -3
  107. package/dist/Kbd/Kbd.d.ts.map +1 -1
  108. package/dist/Kbd/Kbd.js +36 -42
  109. package/dist/Link/Link.d.ts.map +1 -1
  110. package/dist/Link/Link.js +6 -2
  111. package/dist/Link/useLinkComponent.d.ts +5 -15
  112. package/dist/Link/useLinkComponent.d.ts.map +1 -1
  113. package/dist/Link/useLinkComponent.js +34 -51
  114. package/dist/List/List.d.ts +19 -1
  115. package/dist/List/List.d.ts.map +1 -1
  116. package/dist/List/List.js +9 -2
  117. package/dist/List/ListContext.d.ts +1 -0
  118. package/dist/List/ListContext.d.ts.map +1 -1
  119. package/dist/List/ListContext.js +2 -1
  120. package/dist/List/ListItem.d.ts +1 -1
  121. package/dist/List/ListItem.d.ts.map +1 -1
  122. package/dist/List/ListItem.js +9 -2
  123. package/dist/Markdown/Markdown.d.ts +8 -2
  124. package/dist/Markdown/Markdown.d.ts.map +1 -1
  125. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  126. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  127. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  128. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  129. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  130. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  131. package/dist/Markdown/Markdown.js +262 -109
  132. package/dist/Markdown/ast.d.ts +162 -0
  133. package/dist/Markdown/ast.d.ts.map +1 -0
  134. package/dist/Markdown/ast.js +74 -0
  135. package/dist/Markdown/index.d.ts +5 -3
  136. package/dist/Markdown/index.d.ts.map +1 -1
  137. package/dist/Markdown/index.js +3 -2
  138. package/dist/Markdown/parser/index.d.ts +10 -0
  139. package/dist/Markdown/parser/index.d.ts.map +1 -0
  140. package/dist/Markdown/parser/index.js +10 -0
  141. package/dist/Markdown/parser.d.ts +126 -58
  142. package/dist/Markdown/parser.d.ts.map +1 -1
  143. package/dist/Markdown/parser.js +726 -177
  144. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  145. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  146. package/dist/Markdown/plugins/frontmatter.js +132 -0
  147. package/dist/Markdown/plugins/index.d.ts +17 -0
  148. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  149. package/dist/Markdown/plugins/index.js +14 -0
  150. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  151. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  152. package/dist/Markdown/plugins/protocol.js +957 -0
  153. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  154. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  155. package/dist/Markdown/plugins/semanticFence.js +213 -0
  156. package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
  157. package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
  158. package/dist/Markdown/plugins/softBreaks.js +172 -0
  159. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  160. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  161. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  162. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  163. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  164. package/dist/Markdown/plugins/textTransform.js +374 -0
  165. package/dist/Markdown/remark.d.ts +196 -0
  166. package/dist/Markdown/remark.d.ts.map +1 -0
  167. package/dist/Markdown/remark.js +1062 -0
  168. package/dist/Markdown/url.d.ts +6 -0
  169. package/dist/Markdown/url.d.ts.map +1 -0
  170. package/dist/Markdown/url.js +31 -0
  171. package/dist/Markdown/utils.d.ts +4 -2
  172. package/dist/Markdown/utils.d.ts.map +1 -1
  173. package/dist/Markdown/utils.js +2 -1
  174. package/dist/MetadataList/MetadataList.js +3 -3
  175. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  176. package/dist/NumberInput/NumberInput.js +4 -4
  177. package/dist/Outline/index.d.ts +1 -0
  178. package/dist/Outline/index.d.ts.map +1 -1
  179. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  180. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  181. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  182. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  183. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  184. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  185. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  186. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  187. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  188. package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
  189. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  190. package/dist/ProgressBar/ProgressBar.js +36 -31
  191. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  192. package/dist/RadioList/RadioListItem.js +13 -1
  193. package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
  194. package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
  195. package/dist/ScrollableArea/ScrollableArea.js +1 -0
  196. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  197. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  198. package/dist/SegmentedControl/SegmentedControl.js +1 -0
  199. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  200. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  201. package/dist/Selector/Selector.d.ts +9 -7
  202. package/dist/Selector/Selector.d.ts.map +1 -1
  203. package/dist/Selector/Selector.js +16 -7
  204. package/dist/SideNav/SideNav.d.ts +2 -1
  205. package/dist/SideNav/SideNav.d.ts.map +1 -1
  206. package/dist/SideNav/SideNav.js +9 -3
  207. package/dist/Slider/Slider.d.ts.map +1 -1
  208. package/dist/Slider/Slider.js +28 -12
  209. package/dist/Spinner/Spinner.d.ts.map +1 -1
  210. package/dist/Spinner/Spinner.js +23 -7
  211. package/dist/Switch/Switch.d.ts.map +1 -1
  212. package/dist/Switch/Switch.js +11 -0
  213. package/dist/TabList/Tab.d.ts +1 -1
  214. package/dist/TabList/Tab.d.ts.map +1 -1
  215. package/dist/TabList/Tab.js +20 -7
  216. package/dist/Table/Table.d.ts +1 -0
  217. package/dist/Table/Table.d.ts.map +1 -1
  218. package/dist/Table/Table.js +29 -13
  219. package/dist/TextArea/TextArea.d.ts.map +1 -1
  220. package/dist/TextArea/TextArea.js +1 -1
  221. package/dist/TextInput/TextInput.d.ts.map +1 -1
  222. package/dist/TextInput/TextInput.js +2 -2
  223. package/dist/TimeInput/TimeInput.d.ts +30 -14
  224. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  225. package/dist/TimeInput/TimeInput.js +61 -13
  226. package/dist/TimeInput/TouchTimeField.d.ts +11 -0
  227. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -0
  228. package/dist/TimeInput/TouchTimeField.js +417 -0
  229. package/dist/TimeInput/index.d.ts +1 -1
  230. package/dist/TimeInput/index.d.ts.map +1 -1
  231. package/dist/Timer/Timer.d.ts +49 -0
  232. package/dist/Timer/Timer.d.ts.map +1 -0
  233. package/dist/Timer/Timer.js +158 -0
  234. package/dist/Timer/index.d.ts +9 -0
  235. package/dist/Timer/index.d.ts.map +1 -0
  236. package/dist/Timer/index.js +10 -0
  237. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  238. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  239. package/dist/ToggleButton/ToggleButton.js +15 -27
  240. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  241. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  242. package/dist/TopNav/TopNavMenu.js +3 -2
  243. package/dist/TreeList/TreeList.d.ts.map +1 -1
  244. package/dist/TreeList/TreeList.js +3 -0
  245. package/dist/TreeList/TreeListItem.d.ts +6 -1
  246. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  247. package/dist/TreeList/TreeListItem.js +12 -2
  248. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  249. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  250. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  251. package/dist/Typeahead/BaseTypeahead.js +16 -7
  252. package/dist/astryx.css +27 -11
  253. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  254. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  255. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  256. package/dist/hooks/useClickableContainer.d.ts +10 -1
  257. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  258. package/dist/hooks/useClickableContainer.js +15 -4
  259. package/dist/hooks/useScrollableArea.d.ts +6 -2
  260. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  261. package/dist/hooks/useScrollableArea.js +17 -5
  262. package/dist/index.d.ts +1 -0
  263. package/dist/index.d.ts.map +1 -1
  264. package/dist/index.js +3 -0
  265. package/dist/theme/declarationBoundary.d.ts +17 -0
  266. package/dist/theme/declarationBoundary.d.ts.map +1 -0
  267. package/dist/theme/declarationBoundary.js +343 -0
  268. package/dist/theme/defineTheme.d.ts +3 -0
  269. package/dist/theme/defineTheme.d.ts.map +1 -1
  270. package/dist/theme/defineTheme.js +4 -1
  271. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  272. package/dist/theme/derivedVarRegistry.js +4 -0
  273. package/dist/theme/generateThemeRules.d.ts +15 -7
  274. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  275. package/dist/theme/generateThemeRules.js +143 -35
  276. package/dist/theme/themeAdaptations.d.ts +5 -3
  277. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  278. package/dist/theme/themeAdaptations.js +33 -5
  279. package/dist/utils/inputPresentation.d.ts +55 -0
  280. package/dist/utils/inputPresentation.d.ts.map +1 -0
  281. package/dist/utils/inputPresentation.js +108 -0
  282. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  283. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  284. package/dist/utils/interactionOverlay.stylex.js +9 -0
  285. package/dist/utils/safeUrl.d.ts +11 -0
  286. package/dist/utils/safeUrl.d.ts.map +1 -0
  287. package/dist/utils/safeUrl.js +78 -0
  288. package/locales/af-ZA.json +530 -1
  289. package/locales/ar-SA.json +490 -1
  290. package/locales/ca-ES.json +514 -1
  291. package/locales/cs-CZ.json +498 -1
  292. package/locales/da-DK.json +522 -1
  293. package/locales/de-DE.json +522 -1
  294. package/locales/el-GR.json +498 -1
  295. package/locales/es-ES.json +510 -1
  296. package/locales/fi-FI.json +498 -1
  297. package/locales/fr-FR.json +534 -1
  298. package/locales/he-IL.json +498 -1
  299. package/locales/hu-HU.json +498 -1
  300. package/locales/it-IT.json +510 -1
  301. package/locales/ja-JP.json +490 -1
  302. package/locales/ko-KR.json +498 -1
  303. package/locales/nl-NL.json +534 -1
  304. package/locales/no-NO.json +510 -1
  305. package/locales/pl-PL.json +506 -1
  306. package/locales/pt-BR.json +506 -1
  307. package/locales/pt-PT.json +506 -1
  308. package/locales/ro-RO.json +506 -1
  309. package/locales/ru-RU.json +498 -1
  310. package/locales/sr-SP.json +498 -1
  311. package/locales/sv-SE.json +502 -1
  312. package/locales/tr-TR.json +498 -1
  313. package/locales/uk-UA.json +498 -1
  314. package/locales/vi-VN.json +502 -1
  315. package/locales/zh-CN.json +490 -1
  316. package/locales/zh-TW.json +490 -1
  317. package/package.json +24 -4
  318. package/src/Avatar/Avatar.doc.mjs +1 -1
  319. package/src/Avatar/Avatar.test.tsx +30 -0
  320. package/src/Avatar/Avatar.tsx +38 -14
  321. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  322. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  323. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  324. package/src/BottomSheet/BottomSheet.tsx +3 -1
  325. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  326. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  327. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  328. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  329. package/src/Button/Button.doc.mjs +5 -5
  330. package/src/Button/Button.tsx +15 -13
  331. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  332. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  333. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  334. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  335. package/src/Chat/ChatComposer.doc.mjs +14 -0
  336. package/src/Chat/ChatComposer.spec.md +230 -0
  337. package/src/Chat/ChatComposer.test.tsx +57 -0
  338. package/src/Chat/ChatComposer.tsx +21 -9
  339. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  340. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  341. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  342. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  343. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  344. package/src/Chat/ChatComposerInput.spec.md +185 -0
  345. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  346. package/src/Chat/ChatComposerInput.tsx +78 -13
  347. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  348. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  349. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  350. package/src/Chat/ChatDictationButton.spec.md +160 -0
  351. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  352. package/src/Chat/ChatDictationButton.tsx +8 -6
  353. package/src/Chat/ChatLayout.doc.mjs +12 -4
  354. package/src/Chat/ChatLayout.spec.md +271 -0
  355. package/src/Chat/ChatLayout.test.tsx +28 -0
  356. package/src/Chat/ChatLayout.tsx +19 -0
  357. package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
  358. package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
  359. package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
  360. package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
  361. package/src/Chat/ChatMessageBubble.spec.md +263 -0
  362. package/src/Chat/ChatMessageBubble.test.tsx +93 -0
  363. package/src/Chat/ChatMessageBubble.tsx +8 -3
  364. package/src/Chat/ChatMessageList.spec.md +222 -0
  365. package/src/Chat/ChatMessageList.test.tsx +64 -2
  366. package/src/Chat/ChatMessageList.tsx +4 -3
  367. package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
  368. package/src/Chat/ChatMessageMetadata.spec.md +220 -0
  369. package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
  370. package/src/Chat/ChatMessageMetadata.tsx +13 -13
  371. package/src/Chat/ChatSendButton.doc.mjs +32 -0
  372. package/src/Chat/ChatSendButton.spec.md +227 -0
  373. package/src/Chat/ChatSendButton.test.tsx +128 -8
  374. package/src/Chat/ChatSendButton.tsx +6 -4
  375. package/src/Chat/ChatSystemMessage.doc.mjs +115 -12
  376. package/src/Chat/ChatSystemMessage.spec.md +225 -0
  377. package/src/Chat/ChatSystemMessage.test.tsx +112 -20
  378. package/src/Chat/ChatSystemMessage.tsx +4 -6
  379. package/src/Chat/ChatTokenizedText.doc.mjs +96 -9
  380. package/src/Chat/ChatTokenizedText.spec.md +190 -0
  381. package/src/Chat/ChatTokenizedText.test.tsx +60 -1
  382. package/src/Chat/ChatTokenizedText.tsx +14 -8
  383. package/src/Chat/ChatToolCalls.doc.mjs +4 -1
  384. package/src/Chat/ChatToolCalls.spec.md +194 -0
  385. package/src/Chat/ChatToolCalls.test.tsx +83 -0
  386. package/src/Chat/ChatToolCalls.tsx +46 -21
  387. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
  388. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
  389. package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
  390. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
  391. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
  392. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
  393. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
  394. package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1522 -0
  395. package/src/Chat/__tests__/ChatSystemMessage.a11y.chromium.spec.ts +1004 -0
  396. package/src/Chat/__tests__/ChatTokenizedText.a11y.chromium.spec.ts +573 -0
  397. package/src/Chat/index.ts +1 -0
  398. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  399. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  400. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  401. package/src/Citation/Citation.doc.mjs +2 -2
  402. package/src/Citation/Citation.test.tsx +17 -0
  403. package/src/Citation/Citation.tsx +4 -2
  404. package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
  405. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  406. package/src/CodeBlock/highlightRanges.test.ts +143 -1
  407. package/src/CodeBlock/highlightRanges.ts +15 -5
  408. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  409. package/src/Collapsible/Collapsible.test.tsx +21 -0
  410. package/src/Collapsible/Collapsible.tsx +5 -0
  411. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  412. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  413. package/src/DateInput/DateInput.doc.mjs +38 -9
  414. package/src/DateInput/DateInput.tsx +59 -17
  415. package/src/DateInput/NativeDateField.tsx +24 -8
  416. package/src/DateInput/Presentation.test.tsx +121 -0
  417. package/src/DateInput/TouchDateField.tsx +6 -2
  418. package/src/DateInput/index.ts +1 -0
  419. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  420. package/src/DateTimeInput/DateTimeInput.doc.mjs +28 -12
  421. package/src/DateTimeInput/DateTimeInput.tsx +93 -37
  422. package/src/DateTimeInput/Presentation.test.tsx +89 -0
  423. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  424. package/src/DateTimeInput/index.ts +1 -0
  425. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  426. package/src/Dialog/Dialog.doc.mjs +2 -0
  427. package/src/Dialog/DialogHeader.doc.mjs +22 -0
  428. package/src/Dialog/DialogHeader.test.tsx +167 -3
  429. package/src/Dialog/DialogHeader.tsx +37 -6
  430. package/src/Dialog/modules/DialogHeader.spec.md +101 -42
  431. package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
  432. package/src/Field/InputClearButton.test.tsx +17 -3
  433. package/src/Field/InputClearButton.tsx +5 -2
  434. package/src/Field/PanelSearchInput.tsx +5 -2
  435. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  436. package/src/FileInput/FileInput.tsx +11 -2
  437. package/src/Icon/Icon.doc.mjs +7 -5
  438. package/src/Icon/Icon.spec.md +81 -40
  439. package/src/Icon/Icon.test.tsx +6 -3
  440. package/src/Icon/Icon.tsx +20 -68
  441. package/src/Icon/IconDefaultSizeContext.ts +23 -0
  442. package/src/Icon/IconSize.stylex.ts +70 -0
  443. package/src/IconButton/IconButton.doc.mjs +3 -3
  444. package/src/IconButton/IconButton.test.tsx +40 -0
  445. package/src/Item/Item.doc.mjs +6 -2
  446. package/src/Item/Item.tsx +9 -3
  447. package/src/Kbd/Kbd.doc.mjs +3 -3
  448. package/src/Kbd/Kbd.test.tsx +57 -1
  449. package/src/Kbd/Kbd.tsx +57 -37
  450. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  451. package/src/Link/Link.doc.mjs +17 -4
  452. package/src/Link/Link.test.tsx +24 -0
  453. package/src/Link/Link.tsx +5 -0
  454. package/src/Link/LinkProvider.doc.mjs +2 -2
  455. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
  456. package/src/Link/useLinkComponent.test.tsx +333 -0
  457. package/src/Link/useLinkComponent.ts +29 -57
  458. package/src/List/List.doc.mjs +6 -0
  459. package/src/List/List.spec.md +200 -0
  460. package/src/List/List.test.tsx +117 -1
  461. package/src/List/List.tsx +22 -2
  462. package/src/List/ListContext.tsx +3 -1
  463. package/src/List/ListItem.doc.mjs +2 -2
  464. package/src/List/ListItem.source-build.test.mjs +41 -0
  465. package/src/List/ListItem.tsx +26 -2
  466. package/src/Markdown/Markdown.doc.mjs +300 -2
  467. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  468. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  469. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  470. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  471. package/src/Markdown/Markdown.public.test.ts +130 -3
  472. package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
  473. package/src/Markdown/Markdown.spec.md +210 -45
  474. package/src/Markdown/Markdown.test.tsx +87 -3
  475. package/src/Markdown/Markdown.tsx +414 -135
  476. package/src/Markdown/ast.test.ts +307 -0
  477. package/src/Markdown/ast.ts +337 -0
  478. package/src/Markdown/incremental.test.ts +43 -0
  479. package/src/Markdown/index.ts +37 -1
  480. package/src/Markdown/modules/remark.spec.md +269 -0
  481. package/src/Markdown/modules/softBreaks.spec.md +137 -0
  482. package/src/Markdown/parser/index.ts +64 -0
  483. package/src/Markdown/parser.public.test.ts +103 -0
  484. package/src/Markdown/parser.test.ts +38 -6
  485. package/src/Markdown/parser.ts +1221 -242
  486. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  487. package/src/Markdown/plugins/frontmatter.ts +198 -0
  488. package/src/Markdown/plugins/index.ts +54 -0
  489. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  490. package/src/Markdown/plugins/protocol.ts +1618 -0
  491. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  492. package/src/Markdown/plugins/semanticFence.ts +424 -0
  493. package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
  494. package/src/Markdown/plugins/softBreaks.ts +169 -0
  495. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  496. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  497. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  498. package/src/Markdown/plugins/textTransform.ts +554 -0
  499. package/src/Markdown/remark.test.tsx +1877 -0
  500. package/src/Markdown/remark.ts +1574 -0
  501. package/src/Markdown/url.ts +36 -0
  502. package/src/Markdown/utils.ts +13 -1
  503. package/src/MetadataList/MetadataList.test.tsx +4 -2
  504. package/src/MetadataList/MetadataList.tsx +3 -3
  505. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  506. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  507. package/src/NumberInput/NumberInput.tsx +6 -1
  508. package/src/Outline/Outline.doc.mjs +7 -5
  509. package/src/Outline/Outline.spec.md +1 -1
  510. package/src/Outline/index.ts +1 -0
  511. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  512. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  513. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  514. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  515. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  516. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  517. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
  518. package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
  519. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  520. package/src/ProgressBar/ProgressBar.tsx +59 -72
  521. package/src/RadioList/RadioList.doc.mjs +11 -0
  522. package/src/RadioList/RadioList.test.tsx +32 -0
  523. package/src/RadioList/RadioListItem.tsx +25 -1
  524. package/src/ScrollableArea/ScrollableArea.tsx +1 -0
  525. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  526. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  527. package/src/SegmentedControl/SegmentedControl.test.tsx +61 -0
  528. package/src/SegmentedControl/SegmentedControl.tsx +2 -1
  529. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  530. package/src/Selector/Selector.doc.mjs +3 -3
  531. package/src/Selector/Selector.spec.md +51 -49
  532. package/src/Selector/Selector.test.tsx +61 -55
  533. package/src/Selector/Selector.tsx +34 -15
  534. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  535. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  536. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  537. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  538. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  539. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
  540. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  541. package/src/SideNav/SideNav.doc.mjs +1 -1
  542. package/src/SideNav/SideNav.test.tsx +10 -0
  543. package/src/SideNav/SideNav.tsx +14 -2
  544. package/src/Slider/Slider.doc.mjs +17 -3
  545. package/src/Slider/Slider.test.tsx +221 -0
  546. package/src/Slider/Slider.tsx +40 -9
  547. package/src/Spinner/Spinner.test.tsx +4 -0
  548. package/src/Spinner/Spinner.tsx +31 -18
  549. package/src/Switch/Switch.doc.mjs +11 -0
  550. package/src/Switch/Switch.test.tsx +16 -0
  551. package/src/Switch/Switch.tsx +28 -0
  552. package/src/TabList/Tab.tsx +35 -7
  553. package/src/TabList/TabList.doc.mjs +11 -0
  554. package/src/TabList/TabList.spec.md +204 -0
  555. package/src/TabList/TabList.test.tsx +66 -0
  556. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  557. package/src/Table/Table.doc.mjs +1 -1
  558. package/src/Table/Table.spec.md +54 -40
  559. package/src/Table/Table.test.tsx +83 -10
  560. package/src/Table/Table.tsx +30 -22
  561. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  562. package/src/TextArea/TextArea.tsx +6 -1
  563. package/src/TextInput/TextInput.test.tsx +20 -1
  564. package/src/TextInput/TextInput.tsx +6 -1
  565. package/src/TimeInput/NativeTimeInput.test.tsx +36 -3
  566. package/src/TimeInput/Presentation.test.tsx +148 -0
  567. package/src/TimeInput/TimeInput.doc.mjs +21 -5
  568. package/src/TimeInput/TimeInput.tsx +102 -11
  569. package/src/TimeInput/TouchTimeField.tsx +572 -0
  570. package/src/TimeInput/index.ts +1 -0
  571. package/src/Timer/Timer.doc.mjs +183 -0
  572. package/src/Timer/Timer.spec.md +215 -0
  573. package/src/Timer/Timer.test.tsx +302 -0
  574. package/src/Timer/Timer.tsx +258 -0
  575. package/src/Timer/index.ts +11 -0
  576. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  577. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  578. package/src/ToggleButton/ToggleButton.tsx +26 -33
  579. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  580. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  581. package/src/Token/Token.doc.mjs +2 -2
  582. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  583. package/src/TopNav/TopNavMenu.doc.mjs +2 -2
  584. package/src/TopNav/TopNavMenu.test.tsx +30 -0
  585. package/src/TopNav/TopNavMenu.tsx +7 -2
  586. package/src/TreeList/TreeList.doc.mjs +3 -3
  587. package/src/TreeList/TreeList.spec.md +123 -75
  588. package/src/TreeList/TreeList.test.tsx +29 -0
  589. package/src/TreeList/TreeList.tsx +3 -0
  590. package/src/TreeList/TreeListItem.tsx +15 -1
  591. package/src/TreeList/TreeListTypes.ts +11 -1
  592. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  593. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  594. package/src/Typeahead/Typeahead.test.tsx +53 -0
  595. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  596. package/src/__tests__/pressState.ts +93 -0
  597. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  598. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  599. package/src/hooks/useClickableContainer.test.tsx +236 -0
  600. package/src/hooks/useClickableContainer.ts +20 -4
  601. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  602. package/src/hooks/useScrollableArea.test.tsx +59 -1
  603. package/src/hooks/useScrollableArea.ts +34 -10
  604. package/src/index.ts +3 -0
  605. package/src/inputFontFloor.test.ts +106 -0
  606. package/src/tailwind-theme.css +0 -6
  607. package/src/theme/Theme.test.tsx +32 -0
  608. package/src/theme/declarationBoundary.test.ts +126 -0
  609. package/src/theme/declarationBoundary.ts +347 -0
  610. package/src/theme/defineTheme.ts +4 -0
  611. package/src/theme/derivedVarRegistry.test.ts +7 -0
  612. package/src/theme/derivedVarRegistry.ts +1 -0
  613. package/src/theme/generateThemeRules.test.ts +526 -1
  614. package/src/theme/generateThemeRules.ts +231 -50
  615. package/src/theme/themeAdaptations.test.ts +211 -1
  616. package/src/theme/themeAdaptations.ts +50 -4
  617. package/src/theme/tokenValueCompat.test.ts +4 -1
  618. package/src/utils/inputPresentation.ts +143 -0
  619. package/src/utils/interactionOverlay.stylex.ts +20 -0
  620. package/src/utils/safeUrl.test.ts +88 -0
  621. package/src/utils/safeUrl.ts +85 -0
@@ -36,6 +36,23 @@ function atomicClasses(style: (typeof probe)[keyof typeof probe]): string[] {
36
36
  describe('Citation', () => {
37
37
  const source = {title: 'Example Source', url: 'https://example.com'};
38
38
 
39
+ it.each([
40
+ 'javascript:alert(1)',
41
+ 'vbscript:MsgBox(1)',
42
+ 'data:text/html,<b>x</b>',
43
+ 'java\nscript:alert(1)',
44
+ ])('renders rejected citation URL %s without navigation', url => {
45
+ const {container} = render(
46
+ <>
47
+ <Citation source={{title: 'Source', url}} number={1} />
48
+ <Citation source={{title: 'Source', url}} number={1} variant="number" />
49
+ </>,
50
+ );
51
+ expect(container.querySelector('a')).toBeNull();
52
+ expect(container.querySelector('[href]')).toBeNull();
53
+ expect(container.textContent).toBe('Source1');
54
+ });
55
+
39
56
  it('renders the source title as a link in the label variant', () => {
40
57
  render(<Citation source={source} number={1} data-testid="citation" />);
41
58
  const el = screen.getByTestId('citation');
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file Citation.tsx
7
- * @input Uses React, StyleX, theme tokens
7
+ * @input Uses React, StyleX, theme tokens, and the shared navigation policy
8
8
  * @output Exports Citation component for inline citation references
9
9
  * @position Core implementation; consumed by index.ts
10
10
  *
@@ -30,6 +30,7 @@ import {
30
30
  easeVars,
31
31
  } from '../theme/tokens.stylex';
32
32
  import {mergeProps} from '../utils';
33
+ import {isSafeUrl} from '../utils/safeUrl';
33
34
  import type {BaseProps} from '../BaseProps';
34
35
  import {themeProps} from '../utils/themeProps';
35
36
  import {useTranslator} from '../i18n';
@@ -189,7 +190,8 @@ export function Citation({
189
190
  }: CitationProps): React.ReactElement {
190
191
  const t = useTranslator();
191
192
  const title = source.title ?? String(number);
192
- const href = source.url;
193
+ const href =
194
+ source.url != null && isSafeUrl(source.url) ? source.url : undefined;
193
195
 
194
196
  // Resolve the source icon. A non-string `icon` node renders as-is (an Astryx
195
197
  // <Icon>, SVG, avatar, etc.). Otherwise fall back to an image URL: `src`, or
@@ -22,7 +22,7 @@ export const docs = {
22
22
  props: [
23
23
  {name: 'label', type: 'string', description: 'Accessibility label.', required: true},
24
24
  {name: 'onClick', type: '(event: MouseEvent) => void', description: 'Click handler: fires on card surface only.'},
25
- {name: 'href', type: 'string', description: 'Navigation URL.'},
25
+ {name: 'href', type: 'string', description: 'Navigation URL. Plain, new-tab, Cmd/Ctrl-click, and middle-click activation all follow the shared navigation rule described on the Link `href` prop.'},
26
26
  {name: 'target', type: 'string', description: 'Link target.', default: "'_self'"},
27
27
  {name: 'isDisabled', type: 'boolean', description: 'Disables the card.', default: 'false'},
28
28
  {name: 'children', type: 'ReactNode', description: 'Card content.'},
@@ -69,7 +69,7 @@ export const docsDense = {
69
69
  propDescriptions: {
70
70
  label: 'accessibility label',
71
71
  onClick: 'click handler: fires on card surface only',
72
- href: 'navigation URL',
72
+ href: 'navigation URL; every activation follows the shared navigation rule (see Link href)',
73
73
  target: 'link target',
74
74
  isDisabled: 'disables card',
75
75
  padding: 'inner padding',
@@ -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', () => {
@@ -4,14 +4,18 @@ import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
4
4
  import {applyHighlightRangesChunked} from './highlightRanges';
5
5
  import type {TokenLine} from './tokenizer';
6
6
 
7
- // Mock CSS Highlight API
7
+ // Mock CSS Highlight API. `escape` is real behavior, not a mock: the code
8
+ // under test escapes generated names with it, so jsdom's implementation is
9
+ // carried over when the CSS global is replaced.
8
10
  class MockHighlight extends Set<Range> {}
9
11
  const mockHighlightsMap = new Map<string, MockHighlight>();
12
+ const realCssEscape = globalThis.CSS.escape;
10
13
 
11
14
  beforeEach(() => {
12
15
  mockHighlightsMap.clear();
13
16
 
14
17
  globalThis.CSS = {
18
+ escape: realCssEscape,
15
19
  highlights: {
16
20
  get: (name: string) => mockHighlightsMap.get(name),
17
21
  set: (name: string, h: MockHighlight) => mockHighlightsMap.set(name, h),
@@ -44,6 +48,30 @@ function createCodeElement(lines: string[]): HTMLElement {
44
48
  return code;
45
49
  }
46
50
 
51
+ /**
52
+ * The dynamic stylesheet is module-level state shared by every test in this
53
+ * file, so each test drives unique token types and looks its rules up by the
54
+ * escaped name rather than by position.
55
+ */
56
+ function dynamicRules(): CSSStyleRule[] {
57
+ const dynamicSheet = document.querySelector<HTMLStyleElement>(
58
+ 'style[data-astryx-highlight-dynamic]',
59
+ );
60
+ return Array.from(dynamicSheet?.sheet?.cssRules ?? []) as CSSStyleRule[];
61
+ }
62
+
63
+ /**
64
+ * Exactly the two highlight selectors and nothing else: an escaped ident may
65
+ * contain any character, but only behind a backslash, so an unescaped `)`
66
+ * that closed the function early (and the `, body` after it) cannot match.
67
+ */
68
+ const HIGHLIGHT_ONLY_SELECTOR =
69
+ /^\.astryx-code-block code::highlight\((?:[^()\\]|\\.)+\), \.astryx-codeeditor code::highlight\((?:[^()\\]|\\.)+\)$/;
70
+
71
+ function highlightRule(name: string): string {
72
+ return `.astryx-code-block code::highlight(${name}), .astryx-codeeditor code::highlight(${name})`;
73
+ }
74
+
47
75
  describe('applyHighlightRangesChunked', () => {
48
76
  it('creates ranges for tokens on each line', () => {
49
77
  const codeEl = createCodeElement(['const x = 1;', 'let y = 2;']);
@@ -67,6 +95,120 @@ describe('applyHighlightRangesChunked', () => {
67
95
  expect(kwHighlight!.size).toBe(0);
68
96
  });
69
97
 
98
+ it('keeps every parser-accepted tokenizer type coloured under its raw name', () => {
99
+ // The dotted type that crashed the block, plus names a narrow allowlist
100
+ // would wrongly reject even though the CSS parser accepts them all.
101
+ const types = ['keyword.control.sql', '_private', 'キーワード', '9start'];
102
+ const codeEl = createCodeElement(types.map(() => 'line'));
103
+ const tokenLines: TokenLine[] = types.map(type => [
104
+ {type, start: 0, end: 4},
105
+ ]);
106
+
107
+ const mockStyle = document.createElement('style');
108
+ mockStyle.setAttribute('data-astryx-highlight-styles', '');
109
+ document.head.appendChild(mockStyle);
110
+ const insertRule = vi.spyOn(CSSStyleSheet.prototype, 'insertRule');
111
+
112
+ const cleanup = applyHighlightRangesChunked(codeEl, tokenLines);
113
+
114
+ // Ranges register under the RAW names: a ::highlight() selector matches
115
+ // by ident value, so the escaped rule below still paints them.
116
+ for (const type of types) {
117
+ expect(mockHighlightsMap.get(`astryx-${type}`)?.size).toBe(1);
118
+ }
119
+
120
+ // One rule per type, with only the characters that need it escaped.
121
+ expect(insertRule.mock.calls.map(([rule]) => rule)).toEqual([
122
+ `${highlightRule('astryx-keyword\\.control\\.sql')} { color: var(--color-syntax-keyword\\.control\\.sql, currentColor); }`,
123
+ `${highlightRule('astryx-_private')} { color: var(--color-syntax-_private, currentColor); }`,
124
+ `${highlightRule('astryx-キーワード')} { color: var(--color-syntax-キーワード, currentColor); }`,
125
+ `${highlightRule('astryx-9start')} { color: var(--color-syntax-9start, currentColor); }`,
126
+ ]);
127
+
128
+ cleanup();
129
+ });
130
+
131
+ it('escapes the highlight name so a token type cannot leave its ::highlight() selector', () => {
132
+ // Unescaped, this type closes ::highlight() early and the CSS parser
133
+ // accepts what follows as a valid second selector plus a declaration
134
+ // block, with the trailing comment opener swallowing the rest of the
135
+ // generated rule text. The result is a rule that styles <body>.
136
+ const type = 'sel), body { background: red } /*';
137
+ const escapedName =
138
+ 'astryx-sel\\)\\,\\ body\\ \\{\\ background\\:\\ red\\ \\}\\ \\/\\*';
139
+ const codeEl = createCodeElement(['line']);
140
+ const tokenLines: TokenLine[] = [[{type, start: 0, end: 4}]];
141
+
142
+ const mockStyle = document.createElement('style');
143
+ mockStyle.setAttribute('data-astryx-highlight-styles', '');
144
+ document.head.appendChild(mockStyle);
145
+ const insertRule = vi.spyOn(CSSStyleSheet.prototype, 'insertRule');
146
+
147
+ const cleanup = applyHighlightRangesChunked(codeEl, tokenLines);
148
+
149
+ expect(mockHighlightsMap.get(`astryx-${type}`)?.size).toBe(1);
150
+
151
+ // The exact rule text handed to the engine: both generated names fully
152
+ // escaped, one colour declaration, nothing of the payload's making.
153
+ expect(insertRule).toHaveBeenCalledTimes(1);
154
+ expect(insertRule).toHaveBeenCalledWith(
155
+ `${highlightRule(escapedName)} { color: var(--color-syntax-sel\\)\\,\\ body\\ \\{\\ background\\:\\ red\\ \\}\\ \\/\\*, currentColor); }`,
156
+ );
157
+
158
+ // And as parsed: the rule for this type keeps the payload inside the
159
+ // ident, and no rule in the sheet has any selector beyond the two
160
+ // highlight selectors.
161
+ const rules = dynamicRules();
162
+ const rule = rules.find(r => r.selectorText.includes('astryx-sel'));
163
+ expect(rule?.selectorText).toBe(highlightRule(escapedName));
164
+ for (const r of rules) {
165
+ expect(r.selectorText).toMatch(HIGHLIGHT_ONLY_SELECTOR);
166
+ }
167
+
168
+ cleanup();
169
+ });
170
+
171
+ it('escapes the custom property so a token type cannot add declarations', () => {
172
+ // Unescaped, this type closes var() early and the CSS parser accepts
173
+ // what follows as two more valid declarations.
174
+ const type = 'p); background: red; --x: var(--y';
175
+ const escapedName =
176
+ 'astryx-p\\)\\;\\ background\\:\\ red\\;\\ --x\\:\\ var\\(--y';
177
+ const escapedColor =
178
+ 'var(--color-syntax-p\\)\\;\\ background\\:\\ red\\;\\ --x\\:\\ var\\(--y, currentColor)';
179
+ const codeEl = createCodeElement(['line']);
180
+ const tokenLines: TokenLine[] = [[{type, start: 0, end: 4}]];
181
+
182
+ const mockStyle = document.createElement('style');
183
+ mockStyle.setAttribute('data-astryx-highlight-styles', '');
184
+ document.head.appendChild(mockStyle);
185
+ const insertRule = vi.spyOn(CSSStyleSheet.prototype, 'insertRule');
186
+
187
+ const cleanup = applyHighlightRangesChunked(codeEl, tokenLines);
188
+
189
+ expect(mockHighlightsMap.get(`astryx-${type}`)?.size).toBe(1);
190
+
191
+ expect(insertRule).toHaveBeenCalledTimes(1);
192
+ expect(insertRule).toHaveBeenCalledWith(
193
+ `${highlightRule(escapedName)} { color: ${escapedColor}; }`,
194
+ );
195
+
196
+ // As parsed: exactly one declaration, `color`, whose value is the
197
+ // escaped custom property with its fallback.
198
+ const rule = dynamicRules().find(r => r.selectorText.includes('astryx-p'));
199
+ expect(rule).toBeDefined();
200
+ expect(rule!.selectorText).toBe(highlightRule(escapedName));
201
+ const declared = Array.from({length: rule!.style.length}, (_, i) =>
202
+ rule!.style.item(i),
203
+ );
204
+ expect(declared).toEqual(['color']);
205
+ expect(rule!.style.getPropertyValue('color')).toBe(escapedColor);
206
+ expect(rule!.style.getPropertyValue('background')).toBe('');
207
+ expect(rule!.style.getPropertyValue('--x')).toBe('');
208
+
209
+ cleanup();
210
+ });
211
+
70
212
  it('handles empty token lines', () => {
71
213
  const codeEl = createCodeElement(['', 'const x = 1;']);
72
214
  const tokenLines: TokenLine[] = [[], [{type: 'keyword', start: 0, end: 5}]];
@@ -64,11 +64,21 @@ function ensureDynamicHighlightType(tokenType: string): void {
64
64
  }
65
65
  }
66
66
 
67
- const name = `astryx-${tokenType}`;
68
- const colorVar = `var(--color-syntax-${tokenType}, currentColor)`;
69
- dynamicStyleSheet.insertRule(
70
- `.astryx-code-block code::highlight(${name}), .astryx-codeeditor code::highlight(${name}) { color: ${colorVar}; }`,
71
- );
67
+ // CSS.escape both generated names before they land in rule text: the
68
+ // registry key stays the raw string (a ::highlight() selector matches by
69
+ // ident VALUE, escapes and all), so dotted, non-ASCII, `_private`, and
70
+ // digit-led token types keep their colours — while nothing a token stream
71
+ // carries can step outside its ident and shape the rule.
72
+ const name = CSS.escape(`astryx-${tokenType}`);
73
+ const colorVar = `var(${CSS.escape(`--color-syntax-${tokenType}`)}, currentColor)`;
74
+ try {
75
+ dynamicStyleSheet.insertRule(
76
+ `.astryx-code-block code::highlight(${name}), .astryx-codeeditor code::highlight(${name}) { color: ${colorVar}; }`,
77
+ );
78
+ } catch {
79
+ // An engine that still refuses the rule costs that type its colour
80
+ // (ranges paint with currentColor) — never the whole code block.
81
+ }
72
82
  }
73
83
 
74
84
  // ---------------------------------------------------------------------------
@@ -82,6 +82,17 @@ export const docs = {
82
82
  {name: 'CollapsibleGroup'},
83
83
  ],
84
84
  usage: {
85
+ accessibility: [
86
+ {
87
+ name: 'Trigger label',
88
+ category: 'Color contrast',
89
+ criterion: '1.4.3 Contrast (Minimum)',
90
+ requirement: '4.5:1',
91
+ states: ['Rest', 'Pointer down'],
92
+ description:
93
+ 'The trigger text must have at least 4.5:1 contrast with the surface behind it. For Pointer down, measure against the pressed overlay the trigger row paints while it is pressed.',
94
+ },
95
+ ],
85
96
  description: 'Collapsible hides and reveals content behind a trigger button. Use it in settings panels, FAQ pages, or detail views to keep the page scannable while letting users drill into sections they care about. Wrap multiple collapsibles in CollapsibleGroup for accordion behavior. For custom collapsible components, use the `useCollapsible` hook directly (`astryx hook useCollapsible`).',
86
97
  bestPractices: [
87
98
  { guidance: true, description: 'Use hasDividers on CollapsibleGroup for FAQ-style lists: built-in row hairlines with themed border tokens, no hand-rolled borders.' },
@@ -12,6 +12,7 @@
12
12
  import {describe, it, expect, vi} from 'vitest';
13
13
  import {render, screen, within} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
+ import {hasPressedArm} from '../__tests__/pressState';
15
16
  import {Collapsible} from './Collapsible';
16
17
  import {CollapsibleGroup} from './CollapsibleGroup';
17
18
 
@@ -615,3 +616,23 @@ describe('Collapsible', () => {
615
616
  });
616
617
  });
617
618
  });
619
+
620
+ describe('pressed state', () => {
621
+ it('paints the pressed overlay on the trigger row while it is pressed', () => {
622
+ render(
623
+ <Collapsible trigger="Details">
624
+ <p>Body</p>
625
+ </Collapsible>,
626
+ );
627
+ expect(hasPressedArm(screen.getByRole('button'))).toBe(true);
628
+ });
629
+
630
+ it('does not press a disabled trigger', () => {
631
+ render(
632
+ <Collapsible trigger="Details" isDisabled>
633
+ <p>Body</p>
634
+ </Collapsible>,
635
+ );
636
+ expect(hasPressedArm(screen.getByRole('button'))).toBe(false);
637
+ });
638
+ });
@@ -48,6 +48,7 @@ import {mergeProps} from '../utils';
48
48
  import type {BaseProps} from '../BaseProps';
49
49
  import {themeProps} from '../utils/themeProps';
50
50
  import {focusOutlineProps} from '../utils/focusOutline.stylex';
51
+ import {interactionOverlayStyles} from '../utils/interactionOverlay.stylex';
51
52
 
52
53
  const styles = stylex.create({
53
54
  root: {
@@ -411,6 +412,10 @@ export function Collapsible({
411
412
  focusOutlineProps.focusVisible(
412
413
  styles.trigger,
413
414
  density != null && triggerDensity[density],
415
+ // The system's pressed overlay on the disclosure row. The trigger
416
+ // has no hover surface of its own, so this is the one background
417
+ // it paints, and only while it is pressed.
418
+ !isDisabled && interactionOverlayStyles.pressedBackgroundColor,
414
419
  isDisabled && styles.triggerDisabled,
415
420
  ),
416
421
  )}>
@@ -73,9 +73,14 @@ const styles = stylex.create({
73
73
  backgroundColor: 'transparent',
74
74
  color: colorVars['--color-text-primary'],
75
75
  fontFamily: typographyVars['--font-family-body'],
76
+ // The 16px floor is iOS-only: iOS Safari zooms the page when a focused
77
+ // control sits under 16px, and only iOS WebKit implements
78
+ // -webkit-touch-callout to key the coarse-pointer floor to it.
76
79
  fontSize: {
77
80
  default: typeScaleVars['--text-body-size'],
78
- '@media (pointer: coarse)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
81
+ '@media (pointer: coarse)': {
82
+ '@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
83
+ },
79
84
  },
80
85
  lineHeight: typeScaleVars['--text-body-leading'],
81
86
  padding: 0,
@@ -65,9 +65,14 @@ const styles = stylex.create({
65
65
  paddingBlock: spacingVars['--spacing-2'],
66
66
  paddingInline: spacingVars['--spacing-3'],
67
67
  fontFamily: typographyVars['--font-family-body'],
68
+ // The 16px floor is iOS-only: iOS Safari zooms the page when a focused
69
+ // control sits under 16px, and only iOS WebKit implements
70
+ // -webkit-touch-callout to key the coarse-pointer floor to it.
68
71
  fontSize: {
69
72
  default: typeScaleVars['--text-label-size'],
70
- '@media (pointer: coarse)': `max(1rem, ${typeScaleVars['--text-label-size']})`,
73
+ '@media (pointer: coarse)': {
74
+ '@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-label-size']})`,
75
+ },
71
76
  },
72
77
  lineHeight: typeScaleVars['--text-label-leading'],
73
78
  color: colorVars['--color-text-primary'],
@@ -156,11 +156,18 @@ export const docs = {
156
156
  "How the committed date value is displayed. Named values are reused from Timestamp's format vocabulary: 'date' shows 'Mar 21, 2026', 'date_long' shows 'March 21, 2026', 'date_weekday' shows 'Wed, Mar 21, 2026', 'system_date' shows '2026-03-21'. A function receives the ISO value and returns a custom string. Applies only to the committed value, never to text being typed.",
157
157
  default: "'date_long'",
158
158
  },
159
+ {
160
+ name: 'presentation',
161
+ type: "'popover' | 'bottom-sheet' | 'native' | 'adaptive-bottom-sheet' | 'adaptive-native'",
162
+ description:
163
+ "Which surface draws the date picker. 'adaptive-native' (the default) uses Astryx's calendar popover on a fine pointer and the browser/OS picker (input type=date) on a coarse pointer, keeping Astryx fallbacks where a native control cannot express the value; 'native' always uses the browser/OS picker with no fallback; 'adaptive-bottom-sheet' uses the popover on a fine pointer and Astryx's bottom-sheet picker on a coarse pointer; 'popover' and 'bottom-sheet' force that Astryx surface on every pointer. Every value opens a picker; a typed-only field is TimeInput's alone. Use a non-native presentation for a field that needs weekStartsOn, numberOfMonths or dateConstraints, none of which a native picker can express.",
164
+ default: "'adaptive-native'",
165
+ },
159
166
  {
160
167
  name: 'nativePicker',
161
168
  type: "'touch' | 'always' | 'never'",
162
169
  description:
163
- "Which surface draws the date picker. 'touch' (the default) hands a touch device to the browser/OS: the field becomes an input type=date and the platform draws the picker (the iOS wheel, the Android calendar dialog); 'always' does that wherever the browser supports input type=date; 'never' keeps Astryx's own pickers everywhere (the bottom-sheet picker on a finger, the calendar popover on a mouse). Use 'never' for a field that needs weekStartsOn, numberOfMonths or dateConstraints, none of which a native picker can express. format and placeholder still apply in native mode; min and max are forwarded, but a native picker may not show them (on iOS an out-of-range date can be selected and is refused on commit rather than greyed out).",
170
+ "Deprecated: use presentation ('touch' = 'adaptive-native', 'always' = 'native', 'never' = 'adaptive-bottom-sheet'). Still works exactly as released; presentation wins when both are set.",
164
171
  default: "'touch'",
165
172
  },
166
173
  {
@@ -178,9 +185,16 @@ export const docs = {
178
185
  ],
179
186
  theming: {
180
187
  targets: [
181
- {className: 'astryx-date-input', visualProps: ['size', 'status'], states: ['disabled']},
188
+ {
189
+ className: 'astryx-date-input',
190
+ visualProps: ['size', 'status'],
191
+ states: ['disabled'],
192
+ },
182
193
  {className: 'astryx-date-input-toggle-icon', states: ['state']},
183
- {className: 'astryx-date-input-clear-icon', deprecatedFor: 'input-clear-icon'},
194
+ {
195
+ className: 'astryx-date-input-clear-icon',
196
+ deprecatedFor: 'input-clear-icon',
197
+ },
184
198
  ],
185
199
  },
186
200
  usage: {
@@ -434,7 +448,8 @@ export const docsZh = {
434
448
  {
435
449
  name: 'weekStartsOn',
436
450
  type: "0 | 1 | 2 | 3 | 4 | 5 | 6 | 'sun' | 'mon' | 'tue' | 'wed' | 'thu' | 'fri' | 'sat'",
437
- description: '日历弹出层中每周的起始日。可为数字(0=周日……6=周六)或三字母星期缩写。',
451
+ description:
452
+ '日历弹出层中每周的起始日。可为数字(0=周日……6=周六)或三字母星期缩写。',
438
453
  default: '0',
439
454
  },
440
455
  {
@@ -444,11 +459,18 @@ export const docsZh = {
444
459
  "已选日期的显示格式。命名值复用 Timestamp 的格式词汇:'date' 显示 'Mar 21, 2026','date_long' 显示 'March 21, 2026','date_weekday' 显示 'Wed, Mar 21, 2026','system_date' 显示 '2026-03-21'。函数接收 ISO 值并返回自定义字符串。仅作用于已提交的值,不影响正在输入的文本。",
445
460
  default: "'date_long'",
446
461
  },
462
+ {
463
+ name: 'presentation',
464
+ type: "'popover' | 'bottom-sheet' | 'native' | 'adaptive-bottom-sheet' | 'adaptive-native'",
465
+ description:
466
+ "由哪个界面绘制日期选择器。'adaptive-native'(默认)在精细指针上使用 Astryx 日历弹出层、在粗指针上使用浏览器/操作系统选择器(input type=date),且原生控件无法表达值时保留 Astryx 回退;'native' 始终使用浏览器/操作系统选择器且不回退;'adaptive-bottom-sheet' 在精细指针上用弹出层、在粗指针上用 Astryx 底部选择器;'popover' 与 'bottom-sheet' 在任何指针上强制使用对应 Astryx 界面。每个值都会打开选择器;仅输入字段的呈现只属于 TimeInput。需要 weekStartsOn、numberOfMonths 或 dateConstraints 的字段应使用非原生呈现,原生选择器无法表达这些。",
467
+ default: "'adaptive-native'",
468
+ },
447
469
  {
448
470
  name: 'nativePicker',
449
471
  type: "'touch' | 'always' | 'never'",
450
472
  description:
451
- "由哪个界面绘制日期选择器。'touch'(默认)在触摸设备上交给浏览器/操作系统:字段变为 input type=date,由平台绘制选择器(iOS 滚轮、Android 日历对话框);'always' 在所有支持 input type=date 的浏览器上都这样做;'never' 始终使用 Astryx 自带的选择器(触摸设备用底部弹出选择器,鼠标设备用日历弹出层)。需要 weekStartsOn、numberOfMonths 或 dateConstraints 的字段应使用 'never',原生选择器无法表达这些。原生模式下 format 和 placeholder 仍然生效;min 和 max 会传递给原生控件,但原生选择器可能不会显示这些限制(在 iOS 上仍可选中超出范围的日期,会在提交时被拒绝,而不是变灰)。",
473
+ "已弃用:请使用 presentation('touch'='adaptive-native'、'always'='native'、'never'='adaptive-bottom-sheet')。仍按已发布行为工作;同时设置时以 presentation 为准。",
452
474
  default: "'touch'",
453
475
  },
454
476
  {
@@ -466,7 +488,10 @@ export const docsZh = {
466
488
  states: ['disabled'],
467
489
  },
468
490
  {className: 'astryx-date-input-toggle-icon', states: ['state']},
469
- {className: 'astryx-date-input-clear-icon', deprecatedFor: 'input-clear-icon'},
491
+ {
492
+ className: 'astryx-date-input-clear-icon',
493
+ deprecatedFor: 'input-clear-icon',
494
+ },
470
495
  ],
471
496
  },
472
497
  };
@@ -544,15 +569,19 @@ export const docsDense = {
544
569
  placeholder: 'placeholder text in input',
545
570
  size: 'input control size',
546
571
  status: 'error/warning/success status w/ message',
547
- statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing; tooltip hides the box and shows it on the status icon.',
572
+ statusVariant:
573
+ 'How status message is placed: attached overlaps below input; detached floats below w/ spacing; tooltip hides the box and shows it on the status icon.',
548
574
  labelTooltip: 'tooltip text via info icon at label end',
549
575
  hasClear: 'Shows clear button when date is set. Clears value on click.',
550
576
  numberOfMonths: 'months shown simultaneously in calendar popover',
551
- weekStartsOn: 'first day of week in calendar (0=Sunday, or name e.g. "mon")',
577
+ weekStartsOn:
578
+ 'first day of week in calendar (0=Sunday, or name e.g. "mon")',
552
579
  format:
553
580
  "committed-value display: 'date_long' (default, March 21, 2026), 'date' (Mar 21, 2026), 'date_weekday' (Wed, Mar 21, 2026), 'system_date' (2026-03-21), or (iso)=>string; reuses Timestamp vocabulary. Committed value only, not while typing.",
581
+ presentation:
582
+ "which surface draws the picker: 'adaptive-native' (default) = Astryx popover on fine, browser/OS on coarse w/ Astryx fallbacks; 'native' = browser/OS always, no fallback; 'adaptive-bottom-sheet' = popover fine / Astryx sheet coarse; 'popover'/'bottom-sheet' force Astryx. every value opens a picker (no text-only value; that is TimeInput's). use non-native for weekStartsOn/numberOfMonths/dateConstraints.",
554
583
  nativePicker:
555
- "which surface draws the picker: 'touch' (default) = browser/OS on a coarse pointer, 'always', 'never' = Astryx's own everywhere. use 'never' for weekStartsOn/numberOfMonths/dateConstraints. format+placeholder still apply; min/max forwarded but not necessarily shown by the OS picker, refused on commit instead.",
584
+ "deprecated, use presentation: 'touch'='adaptive-native', 'always'='native', 'never'='adaptive-bottom-sheet'. still works as released; presentation wins if both set.",
556
585
  xstyle: 'StyleX styles for layout; must be stylex.create() value',
557
586
  },
558
587
  };