@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
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * @file BottomSheetPanel.test.tsx
5
5
  * @input Uses vitest, Testing Library, BottomSheetPanel
6
- * @output Tests the shared sheet surface motion contract
6
+ * @output Tests the shared sheet surface motion and keyboard scroll contracts
7
7
  * @position Internal presentation tests shared by standalone and switcher modes
8
8
  */
9
9
 
@@ -50,6 +50,7 @@ function renderPanel(
50
50
  ) {
51
51
  return render(
52
52
  <BottomSheetPanel
53
+ label="Sheet details"
53
54
  state={state}
54
55
  height="hug"
55
56
  style={panelTransitionStyle}
@@ -92,6 +93,7 @@ describe('BottomSheetPanel', () => {
92
93
  const onMotionComplete = vi.fn();
93
94
  const {rerender} = render(
94
95
  <BottomSheetPanel
96
+ label="Sheet details"
95
97
  state={{kind: 'retained', motion: 'covered', alignmentOffset: 0}}
96
98
  height="hug"
97
99
  style={panelTransitionStyle}
@@ -104,6 +106,7 @@ describe('BottomSheetPanel', () => {
104
106
 
105
107
  rerender(
106
108
  <BottomSheetPanel
109
+ label="Sheet details"
107
110
  state={{kind: 'open', entering: true}}
108
111
  height="hug"
109
112
  style={panelTransitionStyle}
@@ -139,6 +142,7 @@ describe('BottomSheetPanel', () => {
139
142
 
140
143
  rerender(
141
144
  <BottomSheetPanel
145
+ label="Sheet details"
142
146
  state={{kind: 'exiting'}}
143
147
  height="hug"
144
148
  style={panelTransitionStyle}
@@ -166,6 +170,7 @@ describe('BottomSheetPanel', () => {
166
170
  const onMotionComplete = vi.fn();
167
171
  render(
168
172
  <BottomSheetPanel
173
+ label="Sheet details"
169
174
  state={{kind: 'open', entering: true}}
170
175
  height="hug"
171
176
  onDismiss={() => {}}
@@ -184,6 +189,7 @@ describe('BottomSheetPanel', () => {
184
189
  const onMotionComplete = vi.fn();
185
190
  render(
186
191
  <BottomSheetPanel
192
+ label="Sheet details"
187
193
  state={{kind: 'open', entering: true}}
188
194
  height="hug"
189
195
  style={{
@@ -211,6 +217,7 @@ describe('BottomSheetPanel', () => {
211
217
  const panelRef = vi.fn();
212
218
  const {rerender, unmount} = render(
213
219
  <BottomSheetPanel
220
+ label="Sheet details"
214
221
  ref={panelRef}
215
222
  state={{kind: 'open', entering: false}}
216
223
  height="hug"
@@ -223,6 +230,7 @@ describe('BottomSheetPanel', () => {
223
230
  expect(panelRef).toHaveBeenCalledTimes(1);
224
231
  rerender(
225
232
  <BottomSheetPanel
233
+ label="Sheet details"
226
234
  ref={panelRef}
227
235
  state={{kind: 'open', entering: false}}
228
236
  height="hug"
@@ -361,6 +369,7 @@ describe('BottomSheetPanel', () => {
361
369
 
362
370
  const {container: closing} = render(
363
371
  <BottomSheetPanel
372
+ label="Sheet details"
364
373
  state={{kind: 'exiting'}}
365
374
  height="hug"
366
375
  onDismiss={() => {}}
@@ -379,6 +388,7 @@ describe('BottomSheetPanel', () => {
379
388
 
380
389
  const {container: resting} = render(
381
390
  <BottomSheetPanel
391
+ label="Sheet details"
382
392
  state={{kind: 'open', entering: false}}
383
393
  height="hug"
384
394
  onDismiss={() => {}}
@@ -4,14 +4,14 @@
4
4
 
5
5
  /**
6
6
  * @file BottomSheetPanel.tsx
7
- * @input Uses React, StyleX, theme tokens, useSheetGestures
8
- * @output Internal BottomSheetPanel surface and motion-state types
7
+ * @input Uses React, StyleX, theme tokens, sheet gestures, shared scroll behavior, and the host label
8
+ * @output Internal BottomSheetPanel with a keyboard-reachable scrolling body and motion-state types
9
9
  * @position Shared presentation layer for standalone and switcher BottomSheets
10
10
  *
11
11
  * This component owns everything intrinsic to a sheet surface: height budgets,
12
12
  * drag and snap gestures, the handle and scrolling body, motion styles, and
13
- * transition completion. It deliberately does not own a dialog, focus, inert
14
- * state, or switcher registration; those belong to the hosting controller.
13
+ * transition completion. It owns the body's keyboard access; dialog focus
14
+ * entry/return, inert state, and switcher registration belong to the host.
15
15
  *
16
16
  * SYNC: When modified, update these files to stay in sync:
17
17
  * - /packages/core/src/BottomSheet/BottomSheet.tsx
@@ -33,17 +33,20 @@ import {
33
33
  import * as stylex from '@stylexjs/stylex';
34
34
  import type {BaseProps} from '../BaseProps';
35
35
  import {useDevWarning} from '../hooks';
36
+ import {useScrollableArea} from '../hooks/useScrollableArea';
36
37
  import {
37
38
  borderVars,
38
39
  colorVars,
39
40
  durationVars,
40
41
  easeVars,
42
+ focusVars,
41
43
  radiusVars,
42
44
  shadowVars,
43
45
  sizeVars,
44
46
  spacingVars,
45
47
  } from '../theme/tokens.stylex';
46
48
  import {mergeProps, themeProps} from '../utils';
49
+ import {focusOutlineStyles} from '../utils/focusOutline.stylex';
47
50
  import {overlayPaddingReset} from '../Layout/padding.stylex';
48
51
  import {
49
52
  isValidSnapPoint,
@@ -211,9 +214,11 @@ const styles = stylex.create({
211
214
  flexGrow: 1,
212
215
  minHeight: 0,
213
216
  boxSizing: 'border-box',
214
- overflowY: 'auto',
215
- overscrollBehavior: 'none',
216
217
  touchAction: 'pan-y',
218
+ outlineOffset: {
219
+ default: 0,
220
+ ':focus-visible': `calc(-1 * ${focusVars['--focus-outline-width']})`,
221
+ },
217
222
  // The scrolling area paints the surface itself, covering the sheet's whole
218
223
  // inner box. Without it the sheet's edge is not uniform: a theme that packs
219
224
  // an inset ring into --shadow-high (the bundled themes all add one in dark
@@ -229,6 +234,15 @@ const styles = stylex.create({
229
234
  // space a content wrapper's own top padding already provides.
230
235
  paddingBlockEnd: 0,
231
236
  },
237
+ content: {
238
+ // Preserve the body's block formatting (including margin/float isolation)
239
+ // and its definite percentage-height basis. min-content lets this real
240
+ // observed box grow with async content beyond a fixed-height viewport.
241
+ display: 'flow-root',
242
+ boxSizing: 'border-box',
243
+ height: '100%',
244
+ minHeight: 'min-content',
245
+ },
232
246
  tallKeyboardBody: {
233
247
  scrollPaddingBlockEnd: MOBILE_KEYBOARD_BOTTOM_CLEARANCE,
234
248
  '::after': {
@@ -265,6 +279,8 @@ interface BottomSheetPanelProps extends BaseProps<HTMLDivElement> {
265
279
  ref?: React.Ref<HTMLDivElement>;
266
280
  state: BottomSheetPanelState;
267
281
  height: BottomSheetHeight | number | string;
282
+ /** Existing host name, reused for the keyboard scrolling group. */
283
+ label: string;
268
284
  children: ReactNode;
269
285
  snapPoints?: ReadonlyArray<BottomSheetSnapPoint>;
270
286
  isSwipeDismissAllowed?: boolean;
@@ -391,6 +407,7 @@ export function BottomSheetPanel({
391
407
  ref,
392
408
  state,
393
409
  height,
410
+ label,
394
411
  children,
395
412
  snapPoints,
396
413
  className,
@@ -490,6 +507,17 @@ export function BottomSheetPanel({
490
507
  onScrimOpacity,
491
508
  });
492
509
 
510
+ const {getViewportProps, getContentProps} = useScrollableArea({
511
+ // The previous overflow-y:auto also computed overflow-x:auto. Keep wide
512
+ // content reachable instead of clipping that existing inline scroll path.
513
+ axis: 'both',
514
+ keyboardAccess: {owner: 'contentOrViewport', label},
515
+ overscroll: 'contain',
516
+ // The sheet body deliberately remains the boundary for sheet-local sticky
517
+ // content while fitting, as it was before shared scroll adoption.
518
+ stickyContainment: 'always',
519
+ });
520
+
493
521
  const setElement = useCallback(
494
522
  (element: HTMLDivElement | null) => {
495
523
  sheetRef(element);
@@ -656,17 +684,22 @@ export function BottomSheetPanel({
656
684
  <div {...stylex.props(styles.handlePill)} />
657
685
  </div>
658
686
  <div
659
- {...mergeProps(
660
- stylex.props(
661
- styles.body,
662
- height === 'tall' && styles.tallKeyboardBody,
687
+ {...getViewportProps<HTMLDivElement>({
688
+ ...bodyProps,
689
+ ...mergeProps(
690
+ stylex.props(
691
+ focusOutlineStyles.focusVisible,
692
+ styles.body,
693
+ height === 'tall' && styles.tallKeyboardBody,
694
+ ),
695
+ scrollPreservationInset > 0
696
+ ? {style: {paddingBlockEnd: `${scrollPreservationInset}px`}}
697
+ : {},
663
698
  ),
664
- scrollPreservationInset > 0
665
- ? {style: {paddingBlockEnd: `${scrollPreservationInset}px`}}
666
- : {},
667
- )}
668
- {...bodyProps}>
669
- {children}
699
+ })}>
700
+ <div {...getContentProps<HTMLDivElement>(stylex.props(styles.content))}>
701
+ {children}
702
+ </div>
670
703
  </div>
671
704
  </div>
672
705
  );
@@ -0,0 +1,344 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file BottomSheetKeyboard.a11y.browser.spec.ts
5
+ * @input Built BottomSheet stories and real Chromium/WebKit keyboard input
6
+ * @output Browser evidence for shared focus delegation, traversal, and native scrolling
7
+ * @position Cross-browser proof for useScrollableArea's contentOrViewport policy
8
+ */
9
+
10
+ import {expect, test, type Page, type Locator} from '@playwright/test';
11
+ import {
12
+ DEFAULT_STORYBOOK_DIR,
13
+ serveStorybook,
14
+ type StaticServer,
15
+ } from '@astryxdesign/a11y-spec/storybook';
16
+
17
+ let storybook: StaticServer;
18
+ test.beforeAll(async () => {
19
+ storybook = await serveStorybook(
20
+ process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
21
+ );
22
+ });
23
+ test.afterAll(async () => {
24
+ await storybook?.close();
25
+ });
26
+
27
+ // macOS WebKit defaults to text-field traversal. Option+Tab selects its native
28
+ // all-controls traversal, equivalent to enabling Safari's keyboard preference.
29
+ function tabKey(browserName: string, reverse = false): string {
30
+ return `${browserName === 'webkit' && process.platform === 'darwin' ? 'Alt+' : ''}${reverse ? 'Shift+' : ''}Tab`;
31
+ }
32
+
33
+ async function mount(page: Page, browserName: string, variant = 'button') {
34
+ await page.goto(
35
+ `${storybook.origin}/iframe.html?id=core-bottomsheet--keyboard-delegation&viewMode=story`,
36
+ );
37
+ const viewport = page.getByRole('group', {
38
+ name: 'Keyboard reading',
39
+ exact: true,
40
+ });
41
+ await expect(viewport).toHaveAttribute('data-scrollable-block', 'true');
42
+ await page.getByLabel('Content case').selectOption(variant);
43
+ await expect(viewport).toHaveAttribute('tabindex', '0');
44
+ // WebKit includes the non-modal dialog host in sequential navigation;
45
+ // Chromium enters its descendants directly. Start immediately before the body.
46
+ const before =
47
+ browserName === 'webkit'
48
+ ? page.getByRole('dialog', {name: 'Keyboard reading', exact: true})
49
+ : page.getByRole('button', {name: 'Toggle modal', exact: true});
50
+ await before.focus();
51
+ return {viewport, before};
52
+ }
53
+
54
+ for (const variant of ['button', 'link']) {
55
+ test(`${variant}: forward entry delegates once and reverse traversal exits`, async ({
56
+ page,
57
+ browserName,
58
+ }) => {
59
+ const {viewport, before} = await mount(page, browserName, variant);
60
+ const first = page.getByRole(variant === 'button' ? 'button' : 'link', {
61
+ name: variant === 'button' ? 'First action' : 'First link',
62
+ exact: true,
63
+ });
64
+ await page.keyboard.press(tabKey(browserName));
65
+ await expect(first).toBeFocused();
66
+ await expect(viewport).toHaveAttribute('tabindex', '0');
67
+ await expect(viewport).toHaveAccessibleName('Keyboard reading');
68
+ await expect(first).toHaveAccessibleName(
69
+ variant === 'button' ? 'First action' : 'First link',
70
+ );
71
+ await page.keyboard.press(tabKey(browserName));
72
+ await expect(page.getByRole('button', {name: 'Last action'})).toBeFocused();
73
+ await page.keyboard.press(tabKey(browserName, true));
74
+ await expect(first).toBeFocused();
75
+ await page.keyboard.press(tabKey(browserName, true));
76
+ await expect(before).toBeFocused();
77
+ await expect(viewport).toHaveAttribute('tabindex', '0');
78
+ await page.keyboard.press(tabKey(browserName));
79
+ await expect(first).toBeFocused();
80
+ });
81
+ }
82
+
83
+ for (const variant of [
84
+ 'text',
85
+ 'input',
86
+ 'disabled',
87
+ 'nested',
88
+ 'native-scroll',
89
+ 'radiogroup',
90
+ 'slider',
91
+ 'combobox',
92
+ 'listbox',
93
+ 'menu',
94
+ 'grid',
95
+ 'tree',
96
+ 'tablist',
97
+ 'toolbar',
98
+ ]) {
99
+ test(`${variant}: retains a named viewport stop`, async ({
100
+ page,
101
+ browserName,
102
+ }) => {
103
+ const {viewport, before} = await mount(page, browserName, variant);
104
+ await page.keyboard.press(tabKey(browserName));
105
+ await expect(viewport).toBeFocused();
106
+ await expect(viewport).toHaveAccessibleName('Keyboard reading');
107
+ await page.keyboard.press(tabKey(browserName, true));
108
+ await expect(before).toBeFocused();
109
+ });
110
+ }
111
+
112
+ async function scrollRange(viewport: Locator) {
113
+ return viewport.evaluate(element => ({
114
+ position: element.scrollTop,
115
+ max: element.scrollHeight - element.clientHeight,
116
+ }));
117
+ }
118
+
119
+ for (const key of ['PageDown', 'ArrowDown']) {
120
+ test(`${key}: reaches both scroll edges after delegation`, async ({
121
+ page,
122
+ browserName,
123
+ }) => {
124
+ const {viewport} = await mount(page, browserName);
125
+ await page.keyboard.press(tabKey(browserName));
126
+ const first = page.getByRole('button', {name: 'First action', exact: true});
127
+ await expect(first).toBeFocused();
128
+ for (let count = 0; count < 300; count++) {
129
+ const {position, max} = await scrollRange(viewport);
130
+ if (position >= max - 1) {
131
+ break;
132
+ }
133
+ await page.keyboard.press(key, {delay: key === 'ArrowDown' ? 50 : 25});
134
+ }
135
+ await expect
136
+ .poll(async () => {
137
+ const {position, max} = await scrollRange(viewport);
138
+ // WebKit can overshoot a native edge while showing rubber-band feedback.
139
+ return max - position;
140
+ })
141
+ .toBeLessThanOrEqual(1);
142
+ for (let count = 0; count < 300; count++) {
143
+ if ((await scrollRange(viewport)).position <= 1) {
144
+ break;
145
+ }
146
+ await page.keyboard.press(key === 'PageDown' ? 'PageUp' : 'ArrowUp', {
147
+ delay: key === 'ArrowDown' ? 50 : 25,
148
+ });
149
+ }
150
+ await expect
151
+ .poll(async () => (await scrollRange(viewport)).position)
152
+ .toBeLessThanOrEqual(1);
153
+ await expect(first).toBeFocused();
154
+ });
155
+ }
156
+
157
+ test('pointer and programmatic focus stay on the viewport, including during keydown', async ({
158
+ page,
159
+ browserName,
160
+ }) => {
161
+ const {viewport, before} = await mount(page, browserName);
162
+ await viewport.focus();
163
+ await expect(viewport).toBeFocused();
164
+ await before.focus();
165
+ await viewport.click({position: {x: 4, y: 40}});
166
+ await expect(viewport).toBeFocused();
167
+ await before.focus();
168
+ await before.evaluate(element => {
169
+ element.addEventListener('keydown', event => {
170
+ if (event instanceof KeyboardEvent && event.key === 'Tab') {
171
+ event.preventDefault();
172
+ document
173
+ .querySelector<HTMLElement>(
174
+ '[role="group"][aria-label="Keyboard reading"]',
175
+ )
176
+ ?.focus();
177
+ }
178
+ });
179
+ });
180
+ await page.keyboard.press(tabKey(browserName));
181
+ await expect(viewport).toBeFocused();
182
+ });
183
+
184
+ test('dynamic eligibility is checked at the next entry without mutation observation', async ({
185
+ page,
186
+ browserName,
187
+ }) => {
188
+ await page.addInitScript(() => {
189
+ const Original = window.MutationObserver;
190
+ const observers: MutationObserver[] = [];
191
+ window.MutationObserver = class extends Original {
192
+ constructor(callback: MutationCallback) {
193
+ super(callback);
194
+ observers.push(this);
195
+ }
196
+ };
197
+ Object.assign(window, {
198
+ stopMutationObservers: () =>
199
+ observers.forEach(observer => observer.disconnect()),
200
+ });
201
+ });
202
+ const {viewport, before} = await mount(page, browserName);
203
+ await page.evaluate(() => {
204
+ (
205
+ window as unknown as {stopMutationObservers: () => void}
206
+ ).stopMutationObservers();
207
+ });
208
+ await viewport.focus();
209
+ const first = page.getByRole('button', {name: 'First action', exact: true});
210
+ await first.evaluate(element => element.setAttribute('disabled', ''));
211
+ await expect(viewport).toBeFocused();
212
+ await before.focus();
213
+ await page.keyboard.press(tabKey(browserName));
214
+ await expect(page.getByRole('button', {name: 'Last action'})).toBeFocused();
215
+ await before.focus();
216
+ await first.evaluate(element => element.removeAttribute('disabled'));
217
+ await page.keyboard.press(tabKey(browserName));
218
+ await expect(first).toBeFocused();
219
+ await before.focus();
220
+ await viewport.locator('[data-scroll-content]').evaluate(element => {
221
+ const input = document.createElement('input');
222
+ input.setAttribute('aria-label', 'Inserted input');
223
+ element.prepend(input);
224
+ });
225
+ await page.keyboard.press(tabKey(browserName));
226
+ await expect(viewport).toBeFocused();
227
+ await page.getByLabel('Inserted input').evaluate(element => element.remove());
228
+ await expect(viewport).toBeFocused();
229
+ await before.focus();
230
+ await page.keyboard.press(tabKey(browserName));
231
+ await expect(first).toBeFocused();
232
+ await before.focus();
233
+ await first.evaluate(element => element.setAttribute('role', 'combobox'));
234
+ await page.keyboard.press(tabKey(browserName));
235
+ await expect(viewport).toBeFocused();
236
+ });
237
+
238
+ test('modal BottomSheet keeps native focus containment without cycling through the viewport', async ({
239
+ page,
240
+ browserName,
241
+ }) => {
242
+ await mount(page, browserName);
243
+ await page.getByRole('button', {name: 'Toggle modal', exact: true}).click();
244
+ const dialog = page.getByRole('dialog', {
245
+ name: 'Keyboard reading',
246
+ exact: true,
247
+ });
248
+ await expect
249
+ .poll(async () => dialog.evaluate(element => element.matches(':modal')))
250
+ .toBe(true);
251
+ const viewport = page.getByRole('group', {
252
+ name: 'Keyboard reading',
253
+ exact: true,
254
+ });
255
+ await expect(viewport).toHaveAttribute('data-scrollable-block', 'true');
256
+ const panel = dialog.locator('.astryx-bottom-sheet');
257
+ await panel.focus();
258
+ await page.keyboard.press(tabKey(browserName));
259
+ const first = page.getByRole('button', {name: 'First action', exact: true});
260
+ await expect(first).toBeFocused();
261
+ await page.keyboard.press(tabKey(browserName, true));
262
+ await expect(viewport).not.toBeFocused();
263
+ await expect(first).not.toBeFocused();
264
+ // Native dialog traversal may wrap to another sheet target or browser chrome;
265
+ // it must never focus the inert background or create a viewport/child loop.
266
+ await expect(
267
+ page.getByRole('button', {name: 'Before sheet', includeHidden: true}),
268
+ ).not.toBeFocused();
269
+ await expect(viewport).toHaveAttribute('tabindex', '0');
270
+ });
271
+
272
+ test('fitting text removes the viewport stop while preserving current focus', async ({
273
+ page,
274
+ browserName,
275
+ }) => {
276
+ const {viewport} = await mount(page, browserName, 'text');
277
+ await viewport.focus();
278
+ await viewport.locator('[data-scroll-content]').evaluate(element => {
279
+ element.textContent = 'Short reading content';
280
+ });
281
+ await expect(viewport).not.toHaveAttribute('data-scrollable-block', 'true');
282
+ await expect(viewport).toHaveAttribute('tabindex', '-1');
283
+ await expect(viewport).toBeFocused();
284
+ });
285
+
286
+ test('horizontal overflow remains keyboard scrollable after delegation', async ({
287
+ page,
288
+ browserName,
289
+ }) => {
290
+ const {viewport, before} = await mount(page, browserName);
291
+ await viewport.evaluate(element => {
292
+ const content = element.querySelector<HTMLElement>('[data-scroll-content]');
293
+ if (content != null) {
294
+ content.style.width = `${element.clientWidth + 320}px`;
295
+ }
296
+ });
297
+ await expect(viewport).toHaveAttribute('data-scrollable-inline', 'true');
298
+ await before.focus();
299
+ await page.keyboard.press(tabKey(browserName));
300
+ await expect(
301
+ page.getByRole('button', {name: 'First action', exact: true}),
302
+ ).toBeFocused();
303
+ for (const key of ['ArrowRight', 'ArrowLeft']) {
304
+ for (let count = 0; count < 100; count++) {
305
+ const atEdge = await viewport.evaluate(
306
+ (element, forward) =>
307
+ forward
308
+ ? element.scrollLeft >=
309
+ element.scrollWidth - element.clientWidth - 1
310
+ : element.scrollLeft <= 1,
311
+ key === 'ArrowRight',
312
+ );
313
+ if (atEdge) {
314
+ break;
315
+ }
316
+ await page.keyboard.press(key, {delay: 50});
317
+ }
318
+ await expect
319
+ .poll(async () =>
320
+ viewport.evaluate(
321
+ (element, forward) =>
322
+ forward
323
+ ? element.scrollWidth - element.clientWidth - element.scrollLeft
324
+ : element.scrollLeft,
325
+ key === 'ArrowRight',
326
+ ),
327
+ )
328
+ .toBeLessThanOrEqual(1);
329
+ }
330
+ });
331
+
332
+ test('does not skip an aria-hidden first tab stop to delegate to a later action', async ({
333
+ page,
334
+ browserName,
335
+ }) => {
336
+ const {viewport} = await mount(page, browserName);
337
+ await page
338
+ .getByRole('button', {name: 'First action', exact: true})
339
+ .evaluate(element => {
340
+ element.setAttribute('aria-hidden', 'true');
341
+ });
342
+ await page.keyboard.press(tabKey(browserName));
343
+ await expect(viewport).toBeFocused();
344
+ });
@@ -157,8 +157,8 @@ export const docs = {
157
157
  name: 'icon',
158
158
  type: 'ReactNode',
159
159
  description:
160
- 'Icon element rendered before the label text.',
161
- slotElements: [{__element: 'Icon', props: {icon: 'check', size: 'sm'}}],
160
+ 'Icon element rendered before the label text. An Astryx Icon with no explicit size defaults to sm for sm/md buttons and md for lg buttons.',
161
+ slotElements: [{__element: 'Icon', props: {icon: 'check'}}],
162
162
  },
163
163
  {
164
164
  name: 'isIconOnly',
@@ -210,7 +210,7 @@ export const docs = {
210
210
  name: 'href',
211
211
  type: 'string',
212
212
  description:
213
- 'When provided, renders the button as a link element (<a> or custom link component).',
213
+ 'When provided, renders the button as a link element (<a> or custom link component). The destination follows the shared navigation rule described on the Link `href` prop.',
214
214
  },
215
215
  {
216
216
  name: 'as',
@@ -294,7 +294,7 @@ export const docsZh = {
294
294
  description: '禁用按钮。存在工具提示时,使用 aria-disabled 代替原生 disabled 以保持可聚焦。',
295
295
  default: 'false',
296
296
  },
297
- {name: 'icon', type: 'ReactNode', description: '图标元素。仅提供 icon 而不提供 children 时,按钮渲染为正方形的纯图标按钮。'},
297
+ {name: 'icon', type: 'ReactNode', description: '图标元素。未显式指定尺寸的 Astryx Icon 在 sm/md 按钮中默认为 sm,在 lg 按钮中默认为 md。仅提供 icon 而不提供 children 时,按钮渲染为正方形的纯图标按钮。'},
298
298
  {name: 'width', type: 'SizeValue', description: "按钮宽度。数字按像素处理,字符串按原样使用(如 '100%' 表示全宽按钮)。默认按内容自适应宽度。"},
299
299
  {name: 'children', type: 'ReactNode', description: '可选的可见内容覆盖;label 仍然是必需的(用于无障碍名称)。大多数情况使用 <Button label="Save" />。'},
300
300
  {
@@ -361,7 +361,7 @@ export const docsDense = {
361
361
  value: 'HTML value for form submission',
362
362
  form: 'associates button with form element by ID',
363
363
  isLoading: 'shows spinner+disables interaction; announces via live region',
364
- icon: 'icon element rendered before label text',
364
+ icon: 'icon element rendered before label text; unsized Astryx Icon defaults to sm for sm/md buttons and md for lg',
365
365
  isIconOnly: 'when true, renders square icon-only button; label becomes aria-label',
366
366
  width: "Width of button. Numbers=pixels, strings=as-is (e.g. '100%' for full-width).",
367
367
  children: 'optional visible override; label is still required for a11y. Prefer <Button label="Save" /> over using children',
@@ -38,6 +38,8 @@ import {
38
38
  } from '../theme/tokens.stylex';
39
39
  import {Spinner} from '../Spinner';
40
40
  import {VisuallyHidden} from '../VisuallyHidden';
41
+ import {IconDefaultSizeProvider} from '../Icon/IconDefaultSizeContext';
42
+ import {iconBoxSizeStyles, type IconSize} from '../Icon/IconSize.stylex';
41
43
 
42
44
  import {EDGE_COMP_ATTR} from '../Layout/edgeCompensation.stylex';
43
45
  import {useSize} from '../SizeContext/SizeContext';
@@ -170,17 +172,6 @@ const sizeStyles = stylex.create({
170
172
  },
171
173
  });
172
174
 
173
- /**
174
- * Icon size per button size.
175
- * Matches Icon sizing: sm/md=16px, lg=20px.
176
- * fontSize is set so emoji and text-based icons scale correctly.
177
- */
178
- const iconSizeStyles = stylex.create({
179
- sm: {width: 16, height: 16, fontSize: 16},
180
- md: {width: 16, height: 16, fontSize: 16},
181
- lg: {width: 20, height: 20, fontSize: 20},
182
- });
183
-
184
175
  /**
185
176
  * Resting elevation for floating buttons (e.g. a FAB). `none` is the default
186
177
  * flat button; `low`/`med`/`high` map to the shadow token scale. 'none' stays
@@ -233,6 +224,12 @@ export type ButtonVariant = keyof ButtonVariantMap;
233
224
  */
234
225
  export type ButtonSize = keyof typeof sizeStyles;
235
226
 
227
+ const iconSizeByButtonSize = {
228
+ sm: 'sm',
229
+ md: 'sm',
230
+ lg: 'md',
231
+ } satisfies Record<ButtonSize, IconSize>;
232
+
236
233
  export interface ButtonProps extends BaseProps<HTMLButtonElement> {
237
234
  /** Ref forwarded to the root element */
238
235
  ref?: React.Ref<HTMLButtonElement>;
@@ -683,6 +680,8 @@ export function Button({
683
680
  style,
684
681
  );
685
682
 
683
+ const iconSize = iconSizeByButtonSize[size];
684
+
686
685
  const buttonContent = (
687
686
  <>
688
687
  {isLoadingState && (
@@ -705,8 +704,11 @@ export function Button({
705
704
  )}
706
705
  aria-hidden={isLoadingState || undefined}>
707
706
  {icon && (
708
- <span {...stylex.props(styles.iconWrapper, iconSizeStyles[size])}>
709
- {icon}
707
+ <span
708
+ {...stylex.props(styles.iconWrapper, iconBoxSizeStyles[iconSize])}>
709
+ <IconDefaultSizeProvider value={iconSize}>
710
+ {icon}
711
+ </IconDefaultSizeProvider>
710
712
  </span>
711
713
  )}
712
714
  {isIconOnly ? null : (