@astryxdesign/core 0.1.3 → 0.1.4-canary.01e5b29

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 (642) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +20 -18
  5. package/dist/AlertDialog/useImperativeAlertDialog.js +3 -3
  6. package/dist/AppShell/AppShell.d.ts +1 -1
  7. package/dist/AppShell/AppShell.d.ts.map +1 -1
  8. package/dist/AppShell/AppShell.js +55 -53
  9. package/dist/AspectRatio/AspectRatio.js +5 -5
  10. package/dist/Avatar/Avatar.d.ts.map +1 -1
  11. package/dist/Avatar/Avatar.js +27 -25
  12. package/dist/Avatar/AvatarStatusDot.js +5 -5
  13. package/dist/AvatarGroup/AvatarGroup.js +5 -5
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +5 -5
  15. package/dist/Badge/Badge.js +3 -3
  16. package/dist/Banner/Banner.d.ts.map +1 -1
  17. package/dist/Banner/Banner.js +32 -25
  18. package/dist/Blockquote/Blockquote.js +7 -7
  19. package/dist/Breadcrumbs/BreadcrumbItem.js +17 -17
  20. package/dist/Breadcrumbs/Breadcrumbs.js +7 -7
  21. package/dist/Button/Button.d.ts.map +1 -1
  22. package/dist/Button/Button.js +47 -26
  23. package/dist/ButtonGroup/ButtonGroup.js +7 -7
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +108 -64
  26. package/dist/Calendar/dayCellUtils.d.ts +67 -5
  27. package/dist/Calendar/dayCellUtils.d.ts.map +1 -1
  28. package/dist/Calendar/dayCellUtils.js +139 -18
  29. package/dist/Calendar/styles.d.ts +2 -2
  30. package/dist/Calendar/styles.d.ts.map +1 -1
  31. package/dist/Calendar/styles.js +2 -2
  32. package/dist/Card/Card.d.ts +4 -2
  33. package/dist/Card/Card.d.ts.map +1 -1
  34. package/dist/Card/Card.js +18 -10
  35. package/dist/Carousel/Carousel.d.ts.map +1 -1
  36. package/dist/Carousel/Carousel.js +20 -19
  37. package/dist/Center/Center.js +3 -3
  38. package/dist/Chat/ChatComposer.js +23 -23
  39. package/dist/Chat/ChatComposerDrawer.js +14 -14
  40. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  41. package/dist/Chat/ChatComposerInput.js +27 -15
  42. package/dist/Chat/ChatDictationButton.d.ts +1 -1
  43. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  44. package/dist/Chat/ChatDictationButton.js +13 -11
  45. package/dist/Chat/ChatLayout.js +17 -17
  46. package/dist/Chat/ChatLayoutScrollButton.d.ts +1 -1
  47. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  48. package/dist/Chat/ChatLayoutScrollButton.js +12 -10
  49. package/dist/Chat/ChatMessage.js +12 -12
  50. package/dist/Chat/ChatMessageBubble.js +7 -7
  51. package/dist/Chat/ChatMessageList.js +14 -14
  52. package/dist/Chat/ChatMessageMetadata.d.ts +1 -1
  53. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  54. package/dist/Chat/ChatMessageMetadata.js +14 -12
  55. package/dist/Chat/ChatPastedTextToken.js +13 -13
  56. package/dist/Chat/ChatSendButton.js +3 -3
  57. package/dist/Chat/ChatSystemMessage.d.ts +1 -1
  58. package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
  59. package/dist/Chat/ChatSystemMessage.js +17 -17
  60. package/dist/Chat/ChatTokenizedText.d.ts +1 -1
  61. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  62. package/dist/Chat/ChatTokenizedText.js +24 -15
  63. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  64. package/dist/Chat/ChatToolCalls.js +81 -74
  65. package/dist/Chat/index.d.ts +1 -1
  66. package/dist/Chat/index.d.ts.map +1 -1
  67. package/dist/Chat/useTriggerMenu.js +15 -15
  68. package/dist/CheckboxInput/CheckboxInput.d.ts +6 -1
  69. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  70. package/dist/CheckboxInput/CheckboxInput.js +32 -24
  71. package/dist/CheckboxList/CheckboxList.js +9 -9
  72. package/dist/CheckboxList/CheckboxListItem.d.ts +1 -1
  73. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  74. package/dist/CheckboxList/CheckboxListItem.js +8 -6
  75. package/dist/Citation/Citation.js +10 -10
  76. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  77. package/dist/ClickableCard/ClickableCard.js +32 -9
  78. package/dist/Code/Code.d.ts +15 -1
  79. package/dist/Code/Code.d.ts.map +1 -1
  80. package/dist/Code/Code.js +35 -5
  81. package/dist/Code/index.d.ts +1 -1
  82. package/dist/Code/index.d.ts.map +1 -1
  83. package/dist/CodeBlock/CodeBlock.d.ts +10 -1
  84. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  85. package/dist/CodeBlock/CodeBlock.js +88 -52
  86. package/dist/CodeBlock/index.d.ts +1 -1
  87. package/dist/CodeBlock/index.d.ts.map +1 -1
  88. package/dist/Collapsible/Collapsible.d.ts +9 -3
  89. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  90. package/dist/Collapsible/Collapsible.js +110 -22
  91. package/dist/Collapsible/CollapsibleGroup.d.ts +39 -7
  92. package/dist/Collapsible/CollapsibleGroup.d.ts.map +1 -1
  93. package/dist/Collapsible/CollapsibleGroup.js +73 -12
  94. package/dist/Collapsible/CollapsibleGroupContext.d.ts +31 -0
  95. package/dist/Collapsible/CollapsibleGroupContext.d.ts.map +1 -1
  96. package/dist/Collapsible/CollapsibleGroupContext.js +33 -3
  97. package/dist/Collapsible/index.d.ts +1 -0
  98. package/dist/Collapsible/index.d.ts.map +1 -1
  99. package/dist/Collapsible/useCollapsible.d.ts +4 -1
  100. package/dist/Collapsible/useCollapsible.d.ts.map +1 -1
  101. package/dist/Collapsible/useCollapsible.js +20 -6
  102. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  103. package/dist/CommandPalette/CommandPalette.js +36 -34
  104. package/dist/CommandPalette/CommandPaletteEmpty.d.ts +1 -1
  105. package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
  106. package/dist/CommandPalette/CommandPaletteEmpty.js +27 -7
  107. package/dist/CommandPalette/CommandPaletteFooter.js +16 -16
  108. package/dist/CommandPalette/CommandPaletteGroup.js +5 -5
  109. package/dist/CommandPalette/CommandPaletteInput.js +13 -13
  110. package/dist/CommandPalette/CommandPaletteItem.js +3 -3
  111. package/dist/CommandPalette/CommandPaletteList.js +3 -3
  112. package/dist/ContextMenu/ContextMenu.d.ts +9 -1
  113. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  114. package/dist/ContextMenu/ContextMenu.js +16 -11
  115. package/dist/DateInput/DateInput.js +18 -18
  116. package/dist/DateRangeInput/DateRangeInput.js +23 -23
  117. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -7
  118. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  119. package/dist/DateTimeInput/DateTimeInput.js +30 -26
  120. package/dist/DateTimeInput/index.d.ts +1 -1
  121. package/dist/DateTimeInput/index.d.ts.map +1 -1
  122. package/dist/Dialog/Dialog.js +9 -9
  123. package/dist/Dialog/DialogHeader.js +16 -16
  124. package/dist/Dialog/useImperativeDialog.js +3 -3
  125. package/dist/Divider/Divider.d.ts +0 -22
  126. package/dist/Divider/Divider.d.ts.map +1 -1
  127. package/dist/Divider/Divider.js +7 -7
  128. package/dist/DropdownMenu/DropdownMenu.js +10 -10
  129. package/dist/DropdownMenu/DropdownMenuItem.d.ts +2 -17
  130. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  131. package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
  132. package/dist/DropdownMenu/renderDropdownItems.js +10 -10
  133. package/dist/EmptyState/EmptyState.js +9 -9
  134. package/dist/Field/Field.js +17 -17
  135. package/dist/Field/FieldLabel.js +15 -15
  136. package/dist/Field/InputClearButton.js +5 -5
  137. package/dist/FieldStatus/FieldStatus.js +3 -3
  138. package/dist/FileInput/FileInput.js +29 -29
  139. package/dist/FormLayout/FormLayout.js +5 -5
  140. package/dist/Grid/Grid.d.ts +4 -3
  141. package/dist/Grid/Grid.d.ts.map +1 -1
  142. package/dist/Grid/Grid.js +29 -12
  143. package/dist/Grid/GridSpan.js +3 -3
  144. package/dist/HStack/HStack.js +3 -3
  145. package/dist/Heading/Heading.js +10 -10
  146. package/dist/HoverCard/HoverCard.js +9 -9
  147. package/dist/HoverCard/useHoverCard.js +3 -3
  148. package/dist/Icon/Icon.d.ts.map +1 -1
  149. package/dist/Icon/Icon.js +16 -12
  150. package/dist/Icon/defaultIcons.js +116 -116
  151. package/dist/IconButton/IconButton.js +3 -3
  152. package/dist/InputGroup/InputGroup.js +11 -11
  153. package/dist/InputGroup/InputGroupText.js +3 -3
  154. package/dist/Item/Item.js +18 -18
  155. package/dist/Kbd/Kbd.js +5 -5
  156. package/dist/Layer/LayerProvider.js +7 -7
  157. package/dist/Layer/useLayer.js +5 -5
  158. package/dist/Layout/Layout.js +21 -21
  159. package/dist/Layout/LayoutContent.js +3 -3
  160. package/dist/Layout/LayoutFooter.js +5 -5
  161. package/dist/Layout/LayoutHeader.js +5 -5
  162. package/dist/Layout/LayoutPanel.js +3 -3
  163. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  164. package/dist/Lightbox/Lightbox.js +55 -31
  165. package/dist/Lightbox/useLightbox.js +3 -3
  166. package/dist/Link/Link.js +15 -15
  167. package/dist/Link/LinkProvider.js +3 -3
  168. package/dist/Link/useLinkify.js +3 -3
  169. package/dist/List/List.js +11 -11
  170. package/dist/List/ListItem.js +11 -11
  171. package/dist/Markdown/Markdown.d.ts.map +1 -1
  172. package/dist/Markdown/Markdown.js +102 -102
  173. package/dist/Markdown/parser.d.ts +7 -0
  174. package/dist/Markdown/parser.d.ts.map +1 -1
  175. package/dist/Markdown/parser.js +300 -6
  176. package/dist/MetadataList/MetadataList.js +10 -10
  177. package/dist/MetadataList/MetadataListItem.js +15 -15
  178. package/dist/MobileNav/MobileNav.js +15 -15
  179. package/dist/MobileNav/MobileNavToggle.js +5 -5
  180. package/dist/MoreMenu/MoreMenu.js +3 -3
  181. package/dist/MultiSelector/MultiSelector.d.ts +7 -1
  182. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  183. package/dist/MultiSelector/MultiSelector.js +64 -55
  184. package/dist/NavIcon/NavIcon.js +3 -3
  185. package/dist/NavMenu/NavHeadingMenu.js +5 -5
  186. package/dist/NavMenu/NavHeadingMenuItem.js +8 -8
  187. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  188. package/dist/NumberInput/NumberInput.js +48 -32
  189. package/dist/Outline/Outline.js +15 -15
  190. package/dist/OverflowList/OverflowList.js +8 -8
  191. package/dist/Overlay/Overlay.js +3 -3
  192. package/dist/Overlay/OverlayScrim.js +5 -5
  193. package/dist/Overlay/useOverlay.js +3 -3
  194. package/dist/Pagination/Pagination.d.ts +1 -1
  195. package/dist/Pagination/Pagination.d.ts.map +1 -1
  196. package/dist/Pagination/Pagination.js +125 -72
  197. package/dist/Popover/Popover.js +16 -16
  198. package/dist/Popover/usePopover.js +7 -7
  199. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  200. package/dist/PowerSearch/PowerSearch.js +110 -92
  201. package/dist/PowerSearch/PowerSearchEditPopover.js +84 -84
  202. package/dist/PowerSearch/PowerSearchFilterEditor.js +3 -3
  203. package/dist/PowerSearch/PowerSearchToken.js +5 -5
  204. package/dist/PowerSearch/PowerSearchValueEditor.js +54 -54
  205. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  206. package/dist/ProgressBar/ProgressBar.js +25 -18
  207. package/dist/RadioList/RadioList.d.ts +7 -1
  208. package/dist/RadioList/RadioList.d.ts.map +1 -1
  209. package/dist/RadioList/RadioList.js +10 -8
  210. package/dist/RadioList/RadioListItem.d.ts +1 -1
  211. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  212. package/dist/RadioList/RadioListItem.js +30 -22
  213. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  214. package/dist/Resizable/ResizeHandle.js +28 -10
  215. package/dist/Section/Section.js +5 -5
  216. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  217. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  218. package/dist/SegmentedControl/SegmentedControl.js +32 -10
  219. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  220. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  221. package/dist/SegmentedControl/SegmentedControlItem.js +18 -12
  222. package/dist/SelectableCard/SelectableCard.js +5 -5
  223. package/dist/Selector/Selector.d.ts +6 -0
  224. package/dist/Selector/Selector.d.ts.map +1 -1
  225. package/dist/Selector/Selector.js +54 -45
  226. package/dist/Selector/SelectorOption.js +3 -3
  227. package/dist/SideNav/SideNav.d.ts.map +1 -1
  228. package/dist/SideNav/SideNav.js +38 -34
  229. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  230. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  231. package/dist/SideNav/SideNavCollapseButton.js +8 -6
  232. package/dist/SideNav/SideNavHeading.js +87 -87
  233. package/dist/SideNav/SideNavItem.js +42 -42
  234. package/dist/SideNav/SideNavSection.d.ts +1 -1
  235. package/dist/SideNav/SideNavSection.d.ts.map +1 -1
  236. package/dist/SideNav/SideNavSection.js +18 -16
  237. package/dist/Skeleton/Skeleton.js +3 -3
  238. package/dist/Slider/Slider.d.ts +6 -0
  239. package/dist/Slider/Slider.d.ts.map +1 -1
  240. package/dist/Slider/Slider.js +31 -22
  241. package/dist/Spinner/Spinner.d.ts.map +1 -1
  242. package/dist/Spinner/Spinner.js +10 -10
  243. package/dist/StatusDot/StatusDot.js +5 -5
  244. package/dist/Switch/Switch.d.ts +13 -4
  245. package/dist/Switch/Switch.d.ts.map +1 -1
  246. package/dist/Switch/Switch.js +41 -30
  247. package/dist/TabList/Tab.js +18 -18
  248. package/dist/TabList/TabList.js +5 -5
  249. package/dist/TabList/TabMenu.d.ts.map +1 -1
  250. package/dist/TabList/TabMenu.js +57 -30
  251. package/dist/TabList/tab.markers.stylex.d.ts +1 -1
  252. package/dist/Table/BaseTable.d.ts.map +1 -1
  253. package/dist/Table/BaseTable.js +51 -39
  254. package/dist/Table/Table.js +7 -7
  255. package/dist/Table/TableBody.d.ts +1 -1
  256. package/dist/Table/TableBody.d.ts.map +1 -1
  257. package/dist/Table/TableBody.js +9 -5
  258. package/dist/Table/TableCell.d.ts.map +1 -1
  259. package/dist/Table/TableCell.js +76 -7
  260. package/dist/Table/TableFooter.d.ts +1 -1
  261. package/dist/Table/TableFooter.d.ts.map +1 -1
  262. package/dist/Table/TableFooter.js +9 -5
  263. package/dist/Table/TableHeader.d.ts +1 -1
  264. package/dist/Table/TableHeader.d.ts.map +1 -1
  265. package/dist/Table/TableHeader.js +9 -5
  266. package/dist/Table/TableHeaderCell.js +3 -3
  267. package/dist/Table/TableRow.js +5 -5
  268. package/dist/Table/index.d.ts +2 -0
  269. package/dist/Table/index.d.ts.map +1 -1
  270. package/dist/Table/index.js +1 -0
  271. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  272. package/dist/Table/plugins/columnResize/useTableColumnResize.js +14 -11
  273. package/dist/Table/plugins/filtering/useTableFiltering.js +71 -71
  274. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  275. package/dist/Table/plugins/pagination/paginateData.js +5 -1
  276. package/dist/Table/plugins/pagination/useTablePagination.js +7 -7
  277. package/dist/Table/plugins/rowExpansion/index.d.ts +3 -0
  278. package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -0
  279. package/dist/Table/plugins/rowExpansion/index.js +3 -0
  280. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +90 -0
  281. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -0
  282. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +398 -0
  283. package/dist/Table/plugins/selection/useTableSelection.js +18 -18
  284. package/dist/Table/plugins/selection/useTableSelectionState.d.ts.map +1 -1
  285. package/dist/Table/plugins/selection/useTableSelectionState.js +11 -1
  286. package/dist/Table/plugins/sortable/useTableSortable.js +17 -17
  287. package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
  288. package/dist/Table/plugins/sortable/useTableSortableState.js +8 -4
  289. package/dist/Table/tableContextMenu.d.ts +5 -1
  290. package/dist/Table/tableContextMenu.d.ts.map +1 -1
  291. package/dist/Table/tableContextMenu.js +19 -12
  292. package/dist/Text/Text.d.ts +1 -1
  293. package/dist/Text/Text.d.ts.map +1 -1
  294. package/dist/Text/Text.js +14 -13
  295. package/dist/Text/text.stylex.d.ts +35 -0
  296. package/dist/Text/text.stylex.d.ts.map +1 -1
  297. package/dist/Text/text.stylex.js +52 -1
  298. package/dist/TextArea/TextArea.js +14 -14
  299. package/dist/TextInput/TextInput.js +15 -15
  300. package/dist/Thumbnail/Thumbnail.d.ts +3 -2
  301. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  302. package/dist/Thumbnail/Thumbnail.js +30 -29
  303. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  304. package/dist/TimeInput/TimeInput.js +26 -21
  305. package/dist/Timestamp/Timestamp.d.ts +1 -1
  306. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  307. package/dist/Timestamp/Timestamp.js +37 -26
  308. package/dist/Toast/Toast.d.ts.map +1 -1
  309. package/dist/Toast/Toast.js +25 -17
  310. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  311. package/dist/Toast/ToastViewport.js +23 -11
  312. package/dist/Toast/useToast.js +4 -4
  313. package/dist/ToggleButton/ToggleButton.js +12 -12
  314. package/dist/ToggleButton/ToggleButtonGroup.js +5 -5
  315. package/dist/Token/Token.js +21 -21
  316. package/dist/Tokenizer/Tokenizer.d.ts +6 -1
  317. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  318. package/dist/Tokenizer/Tokenizer.js +38 -29
  319. package/dist/Toolbar/Toolbar.js +18 -18
  320. package/dist/Tooltip/Tooltip.js +11 -11
  321. package/dist/Tooltip/useTooltip.js +3 -3
  322. package/dist/TopNav/TopNav.js +32 -32
  323. package/dist/TopNav/TopNavHeading.js +67 -67
  324. package/dist/TopNav/TopNavItem.js +5 -5
  325. package/dist/TopNav/TopNavMegaMenu.js +30 -30
  326. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +1 -1
  327. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  328. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +25 -14
  329. package/dist/TopNav/TopNavMegaMenuItem.js +16 -16
  330. package/dist/TopNav/TopNavMenu.js +32 -32
  331. package/dist/TreeList/TreeList.js +8 -8
  332. package/dist/TreeList/TreeListBranches.js +11 -11
  333. package/dist/TreeList/TreeListItem.js +30 -30
  334. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  335. package/dist/Typeahead/BaseTypeahead.js +23 -20
  336. package/dist/Typeahead/Typeahead.js +12 -12
  337. package/dist/Typeahead/TypeaheadItem.js +10 -10
  338. package/dist/VStack/VStack.js +3 -3
  339. package/dist/astryx.css +23 -0
  340. package/dist/astryx.umd.js +60 -58
  341. package/dist/astryx.umd.js.map +4 -4
  342. package/dist/docs-types.d.ts +13 -1
  343. package/dist/docs-types.d.ts.map +1 -1
  344. package/dist/hooks/focusableSelector.d.ts +1 -1
  345. package/dist/hooks/focusableSelector.d.ts.map +1 -1
  346. package/dist/hooks/focusableSelector.js +1 -1
  347. package/dist/hooks/index.d.ts +2 -0
  348. package/dist/hooks/index.d.ts.map +1 -1
  349. package/dist/hooks/index.js +1 -0
  350. package/dist/hooks/useFocusTrap.d.ts +3 -0
  351. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  352. package/dist/hooks/useFocusTrap.js +38 -1
  353. package/dist/hooks/useHotkeys.d.ts +51 -0
  354. package/dist/hooks/useHotkeys.d.ts.map +1 -0
  355. package/dist/hooks/useHotkeys.js +160 -0
  356. package/dist/hooks/useInteractiveRole.d.ts +6 -2
  357. package/dist/hooks/useInteractiveRole.d.ts.map +1 -1
  358. package/dist/hooks/useInteractiveRole.js +6 -2
  359. package/dist/hooks/useKeyboardHint.js +9 -9
  360. package/dist/hooks/useStreamingText.d.ts +3 -1
  361. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  362. package/dist/hooks/useStreamingText.js +14 -5
  363. package/dist/theme/MediaTheme.js +3 -3
  364. package/dist/theme/Theme.js +7 -7
  365. package/dist/theme/defineTheme.d.ts +1 -1
  366. package/dist/theme/defineTheme.d.ts.map +1 -1
  367. package/dist/theme/expandColorScale.d.ts.map +1 -1
  368. package/dist/theme/expandColorScale.js +10 -3
  369. package/dist/theme/hct.d.ts +0 -15
  370. package/dist/theme/hct.d.ts.map +1 -1
  371. package/dist/theme/hct.js +9 -9
  372. package/dist/theme/syntax/SyntaxTheme.js +5 -5
  373. package/dist/theme/tokens.d.ts +10 -2
  374. package/dist/theme/tokens.d.ts.map +1 -1
  375. package/dist/theme/tokens.js +220 -4
  376. package/dist/utils/color.d.ts +42 -0
  377. package/dist/utils/color.d.ts.map +1 -0
  378. package/dist/utils/color.js +150 -0
  379. package/dist/utils/composeEventHandlers.d.ts +30 -0
  380. package/dist/utils/composeEventHandlers.d.ts.map +1 -0
  381. package/dist/utils/composeEventHandlers.js +40 -0
  382. package/dist/utils/index.d.ts +3 -0
  383. package/dist/utils/index.d.ts.map +1 -1
  384. package/dist/utils/index.js +3 -1
  385. package/dist/utils/timeParser.d.ts.map +1 -1
  386. package/dist/utils/timeParser.js +8 -5
  387. package/package.json +3 -3
  388. package/src/AlertDialog/AlertDialog.tsx +2 -0
  389. package/src/AppShell/AppShell.tsx +2 -0
  390. package/src/AspectRatio/AspectRatio.doc.mjs +1 -1
  391. package/src/Avatar/Avatar.doc.mjs +13 -2
  392. package/src/Avatar/Avatar.test.tsx +32 -1
  393. package/src/Avatar/Avatar.tsx +12 -20
  394. package/src/Banner/Banner.doc.mjs +8 -0
  395. package/src/Banner/Banner.test.tsx +38 -0
  396. package/src/Banner/Banner.tsx +8 -1
  397. package/src/Button/Button.tsx +39 -6
  398. package/src/ButtonGroup/ButtonGroup.doc.mjs +1 -1
  399. package/src/Calendar/Calendar.doc.mjs +1 -1
  400. package/src/Calendar/Calendar.test.tsx +201 -17
  401. package/src/Calendar/Calendar.tsx +79 -26
  402. package/src/Calendar/dayCellUtils.test.ts +306 -1
  403. package/src/Calendar/dayCellUtils.ts +206 -13
  404. package/src/Calendar/styles.ts +12 -2
  405. package/src/Card/Card.doc.mjs +1 -1
  406. package/src/Card/Card.tsx +16 -6
  407. package/src/Carousel/Carousel.doc.mjs +12 -12
  408. package/src/Carousel/Carousel.test.tsx +13 -0
  409. package/src/Carousel/Carousel.tsx +1 -0
  410. package/src/Chat/Chat.doc.mjs +1 -1
  411. package/src/Chat/ChatComposerInput.test.tsx +24 -0
  412. package/src/Chat/ChatComposerInput.tsx +17 -1
  413. package/src/Chat/ChatDictationButton.test.tsx +43 -0
  414. package/src/Chat/ChatDictationButton.tsx +4 -4
  415. package/src/Chat/ChatLayoutScrollButton.test.tsx +33 -0
  416. package/src/Chat/ChatLayoutScrollButton.tsx +3 -1
  417. package/src/Chat/ChatMessageMetadata.test.tsx +32 -0
  418. package/src/Chat/ChatMessageMetadata.tsx +4 -6
  419. package/src/Chat/ChatSystemMessage.test.tsx +26 -11
  420. package/src/Chat/ChatSystemMessage.tsx +7 -7
  421. package/src/Chat/ChatTokenizedText.test.tsx +29 -16
  422. package/src/Chat/ChatTokenizedText.tsx +15 -8
  423. package/src/Chat/ChatToolCalls.test.tsx +55 -0
  424. package/src/Chat/ChatToolCalls.tsx +10 -12
  425. package/src/Chat/index.ts +1 -4
  426. package/src/Chat/useChatNewMessages.test.tsx +4 -4
  427. package/src/CheckboxInput/CheckboxInput.doc.mjs +12 -4
  428. package/src/CheckboxInput/CheckboxInput.test.tsx +103 -0
  429. package/src/CheckboxInput/CheckboxInput.tsx +13 -0
  430. package/src/CheckboxList/CheckboxList.doc.mjs +1 -1
  431. package/src/CheckboxList/CheckboxList.test.tsx +19 -0
  432. package/src/CheckboxList/CheckboxListItem.tsx +11 -2
  433. package/src/Citation/Citation.doc.mjs +5 -0
  434. package/src/ClickableCard/ClickableCard.tsx +45 -2
  435. package/src/Code/Code.test.tsx +54 -0
  436. package/src/Code/Code.tsx +48 -4
  437. package/src/Code/index.ts +1 -1
  438. package/src/CodeBlock/CodeBlock.doc.mjs +7 -2
  439. package/src/CodeBlock/CodeBlock.test.tsx +122 -3
  440. package/src/CodeBlock/CodeBlock.tsx +62 -4
  441. package/src/CodeBlock/index.ts +1 -1
  442. package/src/Collapsible/Collapsible.doc.mjs +8 -4
  443. package/src/Collapsible/Collapsible.test.tsx +405 -0
  444. package/src/Collapsible/Collapsible.tsx +86 -10
  445. package/src/Collapsible/CollapsibleGroup.doc.mjs +27 -3
  446. package/src/Collapsible/CollapsibleGroup.test.tsx +318 -0
  447. package/src/Collapsible/CollapsibleGroup.tsx +107 -9
  448. package/src/Collapsible/CollapsibleGroupContext.tsx +42 -2
  449. package/src/Collapsible/index.ts +4 -0
  450. package/src/Collapsible/useCollapsible.ts +20 -6
  451. package/src/CommandPalette/CommandPalette.tsx +5 -3
  452. package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +5 -0
  453. package/src/CommandPalette/CommandPaletteEmpty.tsx +15 -1
  454. package/src/CommandPalette/CommandPaletteGroup.doc.mjs +10 -0
  455. package/src/CommandPalette/CommandPaletteInput.doc.mjs +6 -0
  456. package/src/CommandPalette/CommandPaletteItem.doc.mjs +6 -0
  457. package/src/CommandPalette/CommandPaletteList.doc.mjs +9 -0
  458. package/src/ContextMenu/ContextMenu.doc.mjs +15 -0
  459. package/src/ContextMenu/ContextMenu.test.tsx +15 -0
  460. package/src/ContextMenu/ContextMenu.tsx +19 -1
  461. package/src/ContextMenu/ContextMenuItem.doc.mjs +6 -0
  462. package/src/DateInput/DateInput.doc.mjs +6 -1
  463. package/src/DateInput/DateInput.test.tsx +11 -20
  464. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  465. package/src/DateRangeInput/DateRangeInput.test.tsx +31 -44
  466. package/src/DateRangeInput/DateRangeInput.tsx +2 -2
  467. package/src/DateTimeInput/DateTimeInput.doc.mjs +4 -3
  468. package/src/DateTimeInput/DateTimeInput.test.tsx +118 -16
  469. package/src/DateTimeInput/DateTimeInput.tsx +9 -8
  470. package/src/DateTimeInput/index.ts +1 -0
  471. package/src/Dialog/DialogHeader.doc.mjs +45 -0
  472. package/src/Divider/Divider.tsx +1 -23
  473. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -1
  474. package/src/DropdownMenu/DropdownMenu.test.tsx +5 -3
  475. package/src/DropdownMenu/DropdownMenuItem.tsx +5 -17
  476. package/src/EmptyState/EmptyState.doc.mjs +1 -1
  477. package/src/Field/Field.doc.mjs +1 -1
  478. package/src/Field/FieldLabel.test.tsx +2 -2
  479. package/src/FieldStatus/FieldStatus.test.tsx +282 -0
  480. package/src/FileInput/FileInput.doc.mjs +1 -1
  481. package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +0 -3
  482. package/src/Grid/Grid.doc.mjs +3 -3
  483. package/src/Grid/Grid.test.tsx +43 -18
  484. package/src/Grid/Grid.tsx +26 -9
  485. package/src/Icon/Icon.test.tsx +41 -29
  486. package/src/Icon/Icon.tsx +6 -2
  487. package/src/InputGroup/InputGroup.tsx +2 -2
  488. package/src/InteractiveRoleContext/InteractiveRoleContext.test.tsx +185 -0
  489. package/src/Item/Item.tsx +1 -1
  490. package/src/Layout/Layout.test.tsx +285 -0
  491. package/src/Layout/LayoutContent.doc.mjs +12 -0
  492. package/src/Layout/LayoutPanel.doc.mjs +40 -0
  493. package/src/Layout/LayoutSlots.test.tsx +364 -0
  494. package/src/Layout/__tests__/edgeCompensation.test.tsx +72 -0
  495. package/src/Lightbox/Lightbox.doc.mjs +5 -0
  496. package/src/Lightbox/Lightbox.test.tsx +123 -2
  497. package/src/Lightbox/Lightbox.tsx +29 -1
  498. package/src/Markdown/Markdown.test.tsx +23 -0
  499. package/src/Markdown/Markdown.tsx +9 -7
  500. package/src/Markdown/incremental.test.ts +36 -0
  501. package/src/Markdown/parser.perf.test.ts +34 -12
  502. package/src/Markdown/parser.test.ts +210 -0
  503. package/src/Markdown/parser.ts +301 -6
  504. package/src/MobileNav/MobileNav.doc.mjs +20 -0
  505. package/src/MultiSelector/MultiSelector.doc.mjs +14 -1
  506. package/src/MultiSelector/MultiSelector.test.tsx +33 -0
  507. package/src/MultiSelector/MultiSelector.tsx +20 -0
  508. package/src/NavMenu/NavMenu.doc.mjs +15 -0
  509. package/src/NumberInput/NumberInput.test.tsx +48 -3
  510. package/src/NumberInput/NumberInput.tsx +32 -15
  511. package/src/Outline/parseOutlineFromMarkdown.test.ts +80 -0
  512. package/src/OverflowList/OverflowList.test.tsx +416 -0
  513. package/src/Overlay/Overlay.doc.mjs +6 -0
  514. package/src/Overlay/Overlay.test.tsx +356 -0
  515. package/src/Pagination/Pagination.test.tsx +162 -0
  516. package/src/Pagination/Pagination.tsx +80 -26
  517. package/src/Popover/Popover.test.tsx +65 -0
  518. package/src/PowerSearch/PowerSearch.doc.mjs +4 -4
  519. package/src/PowerSearch/PowerSearch.test.tsx +109 -1
  520. package/src/PowerSearch/PowerSearch.tsx +37 -16
  521. package/src/ProgressBar/ProgressBar.test.tsx +30 -0
  522. package/src/ProgressBar/ProgressBar.tsx +12 -5
  523. package/src/RadioList/RadioList.doc.mjs +7 -1
  524. package/src/RadioList/RadioList.test.tsx +65 -0
  525. package/src/RadioList/RadioList.tsx +10 -1
  526. package/src/RadioList/RadioListItem.tsx +13 -4
  527. package/src/Resizable/ResizeHandle.test.tsx +218 -0
  528. package/src/Resizable/ResizeHandle.tsx +22 -4
  529. package/src/Section/Section.test.tsx +4 -10
  530. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  531. package/src/SegmentedControl/SegmentedControl.test.tsx +192 -0
  532. package/src/SegmentedControl/SegmentedControl.tsx +27 -5
  533. package/src/SegmentedControl/SegmentedControlItem.tsx +9 -4
  534. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  535. package/src/Selector/Selector.doc.mjs +12 -1
  536. package/src/Selector/Selector.test.tsx +30 -0
  537. package/src/Selector/Selector.tsx +18 -0
  538. package/src/SideNav/SideNav.doc.mjs +7 -1
  539. package/src/SideNav/SideNav.test.tsx +66 -0
  540. package/src/SideNav/SideNav.tsx +6 -2
  541. package/src/SideNav/SideNavCollapseButton.tsx +4 -3
  542. package/src/SideNav/SideNavSection.tsx +6 -4
  543. package/src/SizeContext/SizeContext.test.tsx +226 -0
  544. package/src/Slider/Slider.doc.mjs +14 -2
  545. package/src/Slider/Slider.test.tsx +30 -0
  546. package/src/Slider/Slider.tsx +20 -0
  547. package/src/Spinner/Spinner.tsx +1 -0
  548. package/src/Switch/Switch.doc.mjs +21 -9
  549. package/src/Switch/Switch.test.tsx +137 -0
  550. package/src/Switch/Switch.tsx +32 -7
  551. package/src/TabList/TabList.doc.mjs +3 -3
  552. package/src/TabList/TabList.test.tsx +185 -1
  553. package/src/TabList/TabMenu.tsx +45 -9
  554. package/src/Table/BaseTable.tsx +16 -3
  555. package/src/Table/Table.test.tsx +87 -0
  556. package/src/Table/TableBody.tsx +15 -2
  557. package/src/Table/TableCell.tsx +87 -8
  558. package/src/Table/TableFooter.tsx +15 -2
  559. package/src/Table/TableHeader.tsx +15 -2
  560. package/src/Table/index.ts +5 -0
  561. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +13 -0
  562. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +3 -1
  563. package/src/Table/plugins/pagination/paginateData.ts +5 -1
  564. package/src/Table/plugins/pagination/useTablePagination.test.tsx +13 -0
  565. package/src/Table/plugins/rowExpansion/index.ts +7 -0
  566. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +155 -0
  567. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +590 -0
  568. package/src/Table/plugins/selection/useTableSelectionState.test.tsx +23 -0
  569. package/src/Table/plugins/selection/useTableSelectionState.tsx +11 -6
  570. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +35 -1
  571. package/src/Table/plugins/sortable/useTableSortableState.tsx +8 -4
  572. package/src/Table/tableContextMenu.test.tsx +27 -3
  573. package/src/Table/tableContextMenu.tsx +20 -2
  574. package/src/Table/useTablePagination.doc.mjs +4 -1
  575. package/src/Table/useTableRowExpansion.doc.mjs +80 -0
  576. package/src/Table/useTableSortable.doc.mjs +4 -1
  577. package/src/Text/Text.doc.mjs +2 -2
  578. package/src/Text/Text.test.tsx +11 -0
  579. package/src/Text/Text.tsx +4 -2
  580. package/src/Text/text.stylex.ts +41 -0
  581. package/src/TextArea/TextArea.doc.mjs +1 -1
  582. package/src/TextArea/TextArea.test.tsx +3 -3
  583. package/src/TextInput/TextInput.doc.mjs +1 -1
  584. package/src/TextInput/TextInput.test.tsx +3 -3
  585. package/src/Thumbnail/Thumbnail.test.tsx +36 -2
  586. package/src/Thumbnail/Thumbnail.tsx +4 -2
  587. package/src/TimeInput/TimeInput.doc.mjs +11 -6
  588. package/src/TimeInput/TimeInput.test.tsx +37 -0
  589. package/src/TimeInput/TimeInput.tsx +11 -1
  590. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  591. package/src/Timestamp/Timestamp.test.tsx +52 -0
  592. package/src/Timestamp/Timestamp.tsx +30 -16
  593. package/src/Toast/Toast.tsx +11 -3
  594. package/src/Toast/ToastViewport.test.tsx +64 -0
  595. package/src/Toast/ToastViewport.tsx +12 -0
  596. package/src/ToggleButton/ToggleButton.doc.mjs +1 -0
  597. package/src/Tokenizer/Tokenizer.doc.mjs +16 -4
  598. package/src/Tokenizer/Tokenizer.test.tsx +33 -0
  599. package/src/Tokenizer/Tokenizer.tsx +19 -0
  600. package/src/Toolbar/Toolbar.test.tsx +1 -1
  601. package/src/TopNav/TopNav.doc.mjs +1 -1
  602. package/src/TopNav/TopNav.test.tsx +18 -0
  603. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +9 -2
  604. package/src/TreeList/TreeList.doc.mjs +2 -2
  605. package/src/Typeahead/BaseTypeahead.doc.mjs +19 -0
  606. package/src/Typeahead/BaseTypeahead.tsx +5 -2
  607. package/src/Typeahead/Typeahead.doc.mjs +7 -2
  608. package/src/Typeahead/Typeahead.test.tsx +45 -1
  609. package/src/__tests__/TestIcon.tsx +26 -0
  610. package/src/__tests__/fastRoleQueries.ts +66 -0
  611. package/src/docPropReferences.test.ts +178 -0
  612. package/src/docs-types.ts +14 -0
  613. package/src/hooks/focusableSelector.ts +1 -1
  614. package/src/hooks/index.ts +3 -0
  615. package/src/hooks/useFocusTrap.doc.mjs +4 -2
  616. package/src/hooks/useFocusTrap.test.tsx +149 -1
  617. package/src/hooks/useFocusTrap.ts +50 -1
  618. package/src/hooks/useHotkeys.doc.mjs +52 -0
  619. package/src/hooks/useHotkeys.test.ts +245 -0
  620. package/src/hooks/useHotkeys.ts +203 -0
  621. package/src/hooks/useInteractiveRole.ts +12 -4
  622. package/src/hooks/useKeyboardHint.doc.mjs +6 -6
  623. package/src/hooks/useStreamingText.test.ts +54 -19
  624. package/src/hooks/useStreamingText.ts +16 -5
  625. package/src/theme/SyntaxTheme.doc.mjs +4 -4
  626. package/src/theme/defineTheme.ts +4 -13
  627. package/src/theme/derivedVarRegistry.test.ts +2 -2
  628. package/src/theme/expandColorScale.test.ts +29 -0
  629. package/src/theme/expandColorScale.ts +11 -6
  630. package/src/theme/hct.ts +9 -17
  631. package/src/theme/tokens.test.ts +182 -9
  632. package/src/theme/tokens.ts +239 -4
  633. package/src/theme/useTheme.test.tsx +20 -0
  634. package/src/utils/color.test.ts +133 -0
  635. package/src/utils/color.ts +148 -0
  636. package/src/utils/composeEventHandlers.test.ts +71 -0
  637. package/src/utils/composeEventHandlers.ts +44 -0
  638. package/src/utils/index.ts +4 -0
  639. package/src/utils/mergeProps.test.ts +166 -0
  640. package/src/utils/sharedResizeObserver.test.ts +2 -2
  641. package/src/utils/timeParser.test.ts +13 -0
  642. package/src/utils/timeParser.ts +8 -5
@@ -1,8 +1,9 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
- import {describe, it, expect, vi, beforeEach} from 'vitest';
4
- import {render, screen, fireEvent} from '@testing-library/react';
3
+ import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
4
+ import {render, screen, fireEvent, waitFor} from '@testing-library/react';
5
5
  import {Lightbox} from './Lightbox';
6
+ import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
6
7
 
7
8
  // Mock showModal/close for jsdom
8
9
  beforeEach(() => {
@@ -16,6 +17,16 @@ beforeEach(() => {
16
17
  });
17
18
  });
18
19
 
20
+ // useAnnounce mounts singleton live regions on <body>; reset between tests so
21
+ // stale announcements from one test don't leak into the next.
22
+ afterEach(() => {
23
+ __resetLiveRegionsForTest();
24
+ });
25
+
26
+ function politeRegion(): HTMLElement | null {
27
+ return document.querySelector('[data-astryx-live-region="polite"]');
28
+ }
29
+
19
30
  describe('Lightbox', () => {
20
31
  it('renders as a dialog element', () => {
21
32
  render(
@@ -300,6 +311,116 @@ describe('Lightbox', () => {
300
311
  });
301
312
  });
302
313
 
314
+ describe('screen-reader announcements', () => {
315
+ const media = [
316
+ {src: '/a.jpg', alt: 'Image A', caption: 'First'},
317
+ {src: '/b.jpg', alt: 'Image B', caption: 'Second'},
318
+ {src: '/c.jpg', alt: 'Image C'},
319
+ ];
320
+
321
+ it('announces the new image and position when navigating next via button', async () => {
322
+ render(
323
+ <Lightbox
324
+ isOpen={true}
325
+ onOpenChange={() => {}}
326
+ media={media}
327
+ defaultIndex={0}
328
+ />,
329
+ );
330
+ fireEvent.click(screen.getByLabelText('Next'));
331
+ await waitFor(() => {
332
+ expect(politeRegion()).toHaveTextContent('Image B, 2 of 3');
333
+ });
334
+ });
335
+
336
+ it('announces the new image and position when navigating via arrow keys', async () => {
337
+ render(
338
+ <Lightbox
339
+ isOpen={true}
340
+ onOpenChange={() => {}}
341
+ media={media}
342
+ defaultIndex={1}
343
+ />,
344
+ );
345
+ const dialog = document.querySelector('dialog')!;
346
+ fireEvent.keyDown(dialog, {key: 'ArrowRight'});
347
+ await waitFor(() => {
348
+ expect(politeRegion()).toHaveTextContent('Image C, 3 of 3');
349
+ });
350
+ });
351
+
352
+ it('announces the new image and position when navigating prev', async () => {
353
+ render(
354
+ <Lightbox
355
+ isOpen={true}
356
+ onOpenChange={() => {}}
357
+ media={media}
358
+ defaultIndex={2}
359
+ />,
360
+ );
361
+ fireEvent.click(screen.getByLabelText('Previous'));
362
+ await waitFor(() => {
363
+ expect(politeRegion()).toHaveTextContent('Image B, 2 of 3');
364
+ });
365
+ });
366
+
367
+ it('falls back to a positional label when the image has no alt', async () => {
368
+ const unlabeled = [
369
+ {src: '/a.jpg', alt: 'Image A'},
370
+ {src: '/b.jpg', alt: ''},
371
+ ];
372
+ render(
373
+ <Lightbox
374
+ isOpen={true}
375
+ onOpenChange={() => {}}
376
+ media={unlabeled}
377
+ defaultIndex={0}
378
+ />,
379
+ );
380
+ fireEvent.click(screen.getByLabelText('Next'));
381
+ await waitFor(() => {
382
+ expect(politeRegion()).toHaveTextContent('Image 2 of 2');
383
+ });
384
+ });
385
+
386
+ it('does not announce on initial open', async () => {
387
+ render(
388
+ <Lightbox
389
+ isOpen={true}
390
+ onOpenChange={() => {}}
391
+ media={media}
392
+ defaultIndex={1}
393
+ />,
394
+ );
395
+ // Allow any scheduled rAF to flush; nothing should have been announced.
396
+ await new Promise(resolve => requestAnimationFrame(() => resolve(null)));
397
+ // The dialog's aria-label already names the current image on open, so no
398
+ // live region is created (announce is never called).
399
+ expect(politeRegion()).toBeNull();
400
+ });
401
+
402
+ it('does not announce when the lightbox opens at a new index', async () => {
403
+ const {rerender} = render(
404
+ <Lightbox
405
+ isOpen={false}
406
+ onOpenChange={() => {}}
407
+ media={media}
408
+ index={0}
409
+ />,
410
+ );
411
+ rerender(
412
+ <Lightbox
413
+ isOpen={true}
414
+ onOpenChange={() => {}}
415
+ media={media}
416
+ index={2}
417
+ />,
418
+ );
419
+ await new Promise(resolve => requestAnimationFrame(() => resolve(null)));
420
+ expect(politeRegion()).toBeNull();
421
+ });
422
+ });
423
+
303
424
  describe('video support', () => {
304
425
  it('renders a video element when type is video', () => {
305
426
  const {container} = render(
@@ -19,6 +19,7 @@
19
19
  import {
20
20
  useCallback,
21
21
  useEffect,
22
+ useMemo,
22
23
  useRef,
23
24
  useState,
24
25
  type MouseEvent as ReactMouseEvent,
@@ -28,6 +29,7 @@ import * as stylex from '@stylexjs/stylex';
28
29
  import {colorVars, spacingVars, typeScaleVars} from '../theme/tokens.stylex';
29
30
  import {Icon} from '../Icon';
30
31
  import {IconButton} from '../IconButton';
32
+ import {useAnnounce} from '../hooks/useAnnounce';
31
33
  import {useScrollLock} from '../hooks/useScrollLock';
32
34
  import {useIsomorphicLayoutEffect} from '../hooks/useIsomorphicLayoutEffect';
33
35
  import {mergeProps, mergeRefs} from '../utils';
@@ -306,7 +308,10 @@ export function Lightbox({
306
308
  const dragStartRef = useRef({x: 0, y: 0, panX: 0, panY: 0});
307
309
 
308
310
  // Resolve current media item
309
- const mediaArray = Array.isArray(media) ? media : [media];
311
+ const mediaArray = useMemo(
312
+ () => (Array.isArray(media) ? media : [media]),
313
+ [media],
314
+ );
310
315
  const isGallery = mediaArray.length > 1;
311
316
  const currentItem =
312
317
  mediaArray.length > 0
@@ -329,6 +334,29 @@ export function Lightbox({
329
334
  setPan({x: 0, y: 0});
330
335
  }, [index, currentItem?.src]);
331
336
 
337
+ // Announce gallery navigation to screen readers. Moving between images only
338
+ // updates the visual counter, which is silent to assistive tech, so mirror
339
+ // each change in a polite live region ("<alt>, 3 of 12", or "Image 3 of 12"
340
+ // when the image has no alt). Announce only when the image changes during an
341
+ // already-open session — not on mount, not when opening (even at a new
342
+ // index, since the dialog's aria-label already names the current image), and
343
+ // not on close.
344
+ const announce = useAnnounce();
345
+ const prevIndexRef = useRef(index);
346
+ const wasOpenRef = useRef(isOpen);
347
+ useEffect(() => {
348
+ const indexChanged = prevIndexRef.current !== index;
349
+ const wasOpen = wasOpenRef.current;
350
+ prevIndexRef.current = index;
351
+ wasOpenRef.current = isOpen;
352
+ if (!indexChanged || !isOpen || !wasOpen) {
353
+ return;
354
+ }
355
+ const item = mediaArray[Math.min(index, mediaArray.length - 1)];
356
+ const position = `${index + 1} of ${mediaArray.length}`;
357
+ announce(item?.alt ? `${item.alt}, ${position}` : `Image ${position}`);
358
+ }, [index, isOpen, announce, mediaArray]);
359
+
332
360
  // Open/close dialog
333
361
  useIsomorphicLayoutEffect(() => {
334
362
  const dialog = dialogRef.current;
@@ -95,6 +95,29 @@ describe('Markdown', () => {
95
95
  expect(link.getAttribute('rel')).toBe('noopener noreferrer');
96
96
  });
97
97
 
98
+ it('renders a footer reference-style link as an anchor', () => {
99
+ // The XDS parser previously had no reference-definition support, so this
100
+ // rendered as literal `[the docs][docs]` text with the definition leaking
101
+ // as a paragraph. It now resolves to a real anchor.
102
+ render(
103
+ <Markdown>
104
+ {'See [the docs][docs] here.\n\n[docs]: https://example.com/docs\n'}
105
+ </Markdown>,
106
+ );
107
+ const link = screen.getByText('the docs');
108
+ expect(link.tagName).toBe('A');
109
+ expect(link.getAttribute('href')).toBe('https://example.com/docs');
110
+ // The definition line must not leak into the rendered output.
111
+ expect(screen.queryByText(/\[docs\]:/)).toBeNull();
112
+ });
113
+
114
+ it('renders a shortcut reference-style link as an anchor', () => {
115
+ render(<Markdown>{'See [the docs].\n\n[the docs]: /docs'}</Markdown>);
116
+ const link = screen.getByText('the docs');
117
+ expect(link.tagName).toBe('A');
118
+ expect(link.getAttribute('href')).toBe('/docs');
119
+ });
120
+
98
121
  it('does not add target="_blank" to relative links', () => {
99
122
  render(<Markdown>{'[internal](/page)'}</Markdown>);
100
123
  const link = screen.getByText('internal');
@@ -425,7 +425,14 @@ const streamingStyles = stylex.create({
425
425
  fadeIn: {
426
426
  opacity: 1,
427
427
  transitionProperty: 'opacity',
428
- transitionDuration: durationVars['--duration-medium'],
428
+ // Collapse the entry fade to an instant swap under reduced motion. The
429
+ // 0s duration makes the @starting-style opacity jump non-animated (the
430
+ // media query can't nest inside @starting-style), mirroring the
431
+ // conditional-duration form in Spinner (Spinner.tsx).
432
+ transitionDuration: {
433
+ default: durationVars['--duration-medium'],
434
+ '@media (prefers-reduced-motion: reduce)': '0s',
435
+ },
429
436
  transitionTimingFunction: easeVars['--ease-standard'],
430
437
  '@starting-style': {
431
438
  opacity: 0,
@@ -1049,12 +1056,7 @@ function renderBlock(
1049
1056
  switch (node.type) {
1050
1057
  case 'heading': {
1051
1058
  const level = Math.min(node.level + headingLevelStart - 1, 6) as
1052
- | 1
1053
- | 2
1054
- | 3
1055
- | 4
1056
- | 5
1057
- | 6;
1059
+ 1 | 2 | 3 | 4 | 5 | 6;
1058
1060
  const headingChildren = node.children.map((c, i) =>
1059
1061
  renderInline(
1060
1062
  c,
@@ -650,3 +650,39 @@ describe('streaming end-to-end: no raw syntax visible', () => {
650
650
  });
651
651
  });
652
652
  });
653
+
654
+ describe('parseMarkdownIncremental link reference definitions', () => {
655
+ function firstLinkHref(blocks: BlockNode[]): string | undefined {
656
+ for (const block of blocks) {
657
+ if (block.type === 'paragraph') {
658
+ for (const node of block.children) {
659
+ if (node.type === 'link') {
660
+ return node.href;
661
+ }
662
+ }
663
+ }
664
+ }
665
+ return undefined;
666
+ }
667
+
668
+ it('resolves a footer reference streamed across chunks (matches full parse)', () => {
669
+ const text = 'See [the docs][d] here.\n\n[d]: https://example.com/d\n';
670
+ const {final} = simulateStreaming(text, 5);
671
+ expect(final).toEqual(parseMarkdown(text));
672
+ expect(firstLinkHref(final)).toBe('https://example.com/d');
673
+ });
674
+
675
+ it('re-resolves an already-settled reference once its definition arrives', () => {
676
+ const state = createIncrementalState();
677
+ // The reference paragraph settles (blank line) before the definition.
678
+ parseMarkdownIncremental('See [d] here.\n\n', state);
679
+ const before = parseMarkdownIncremental('See [d] here.\n\n[d', state);
680
+ expect(firstLinkHref(before)).toBeUndefined();
681
+ // Definition completes — the settled paragraph must pick up the link.
682
+ const after = parseMarkdownIncremental(
683
+ 'See [d] here.\n\n[d]: /docs\n',
684
+ state,
685
+ );
686
+ expect(firstLinkHref(after)).toBe('/docs');
687
+ });
688
+ });
@@ -69,6 +69,31 @@ function simulateStreamingIncremental(
69
69
  return parseMarkdownIncremental(fullText, state);
70
70
  }
71
71
 
72
+ // A single wall-clock measurement is flaky when the whole suite runs in
73
+ // parallel forks: scheduler contention can inflate a millisecond-scale
74
+ // sample well past a tight budget (observed 30.9ms against the 20ms Small
75
+ // budget). The fastest of a few runs approximates the un-contended cost —
76
+ // a real regression raises the minimum too — so budgets stay tight without
77
+ // flapping. The streaming budget tests below keep a single run: their
78
+ // budgets carry 10x+ headroom, which contention cannot realistically eat.
79
+ function measureBest<T>(
80
+ runs: number,
81
+ fn: () => T,
82
+ ): {elapsed: number; result: T} {
83
+ let elapsed = Infinity;
84
+ let result!: T;
85
+ for (let i = 0; i < runs; i++) {
86
+ const start = performance.now();
87
+ const r = fn();
88
+ const t = performance.now() - start;
89
+ if (t < elapsed) {
90
+ elapsed = t;
91
+ result = r;
92
+ }
93
+ }
94
+ return {elapsed, result};
95
+ }
96
+
72
97
  describe('parseMarkdown performance', () => {
73
98
  const sizes = [
74
99
  {name: 'Small', paragraphs: 10, maxMs: 20},
@@ -93,9 +118,7 @@ describe('parseMarkdown performance', () => {
93
118
  for (const size of sizes) {
94
119
  it(`full re-parse ${size.name} (${size.paragraphs} paragraphs) under ${size.maxMs}ms`, () => {
95
120
  const text = generateAIResponse(size.paragraphs);
96
- const start = performance.now();
97
- const result = parseMarkdown(text);
98
- const elapsed = performance.now() - start;
121
+ const {elapsed, result} = measureBest(3, () => parseMarkdown(text));
99
122
  console.log(
100
123
  ` ${size.name} full parse: ${elapsed.toFixed(2)}ms → ${result.length} blocks`,
101
124
  );
@@ -149,15 +172,14 @@ describe('parseMarkdown performance', () => {
149
172
  const text = generateAIResponse(200);
150
173
  const chunkSize = 50;
151
174
 
152
- // Full re-parse timing
153
- const fullStart = performance.now();
154
- simulateStreamingFullReparse(text, chunkSize);
155
- const fullElapsed = performance.now() - fullStart;
156
-
157
- // Incremental timing
158
- const incrStart = performance.now();
159
- simulateStreamingIncremental(text, chunkSize);
160
- const incrElapsed = performance.now() - incrStart;
175
+ // The assertion below compares a ratio of two measurements, so noise on
176
+ // either side can flip it — measure both as best-of-3.
177
+ const {elapsed: fullElapsed} = measureBest(3, () =>
178
+ simulateStreamingFullReparse(text, chunkSize),
179
+ );
180
+ const {elapsed: incrElapsed} = measureBest(3, () =>
181
+ simulateStreamingIncremental(text, chunkSize),
182
+ );
161
183
 
162
184
  const speedup = fullElapsed / incrElapsed;
163
185
  console.log(`\n === Incremental vs Full Re-parse Speedup ===`);
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {describe, it, expect} from 'vitest';
4
4
  import {parseMarkdown, parseInline} from './parser';
5
+ import type {InlineNode} from './parser';
5
6
 
6
7
  describe('parseInline', () => {
7
8
  it('parses plain text', () => {
@@ -946,3 +947,212 @@ describe('citation parsing', () => {
946
947
  });
947
948
  });
948
949
  });
950
+
951
+ // ---------------------------------------------------------------------------
952
+ // Link reference definitions
953
+ // ---------------------------------------------------------------------------
954
+
955
+ describe('link reference definitions', () => {
956
+ // Collect every link/image node across a block tree for concise assertions.
957
+ function collectLinks(
958
+ nodes: InlineNode[],
959
+ ): {type: string; href?: string; src?: string; text: string}[] {
960
+ const out: {type: string; href?: string; src?: string; text: string}[] = [];
961
+ const textOf = (inlineNodes: InlineNode[]): string =>
962
+ inlineNodes
963
+ .map(inline =>
964
+ inline.type === 'text'
965
+ ? inline.content
966
+ : 'children' in inline
967
+ ? textOf(inline.children)
968
+ : '',
969
+ )
970
+ .join('');
971
+ for (const node of nodes) {
972
+ if (node.type === 'link') {
973
+ out.push({type: 'link', href: node.href, text: textOf(node.children)});
974
+ } else if (node.type === 'image') {
975
+ out.push({type: 'image', src: node.src, text: node.alt});
976
+ } else if ('children' in node) {
977
+ out.push(...collectLinks(node.children));
978
+ }
979
+ }
980
+ return out;
981
+ }
982
+
983
+ function paragraphLinks(input: string) {
984
+ const blocks = parseMarkdown(input);
985
+ const links = blocks.flatMap(block =>
986
+ block.type === 'paragraph' ? collectLinks(block.children) : [],
987
+ );
988
+ return {blocks, links};
989
+ }
990
+
991
+ it('resolves a full reference `[text][label]` and drops the definition', () => {
992
+ const {blocks, links} = paragraphLinks(
993
+ 'See [the docs][docs] here.\n\n[docs]: https://example.com/docs\n',
994
+ );
995
+ // Only the paragraph survives; the definition line produces no block.
996
+ expect(blocks).toHaveLength(1);
997
+ expect(blocks[0].type).toBe('paragraph');
998
+ expect(links).toEqual([
999
+ {type: 'link', href: 'https://example.com/docs', text: 'the docs'},
1000
+ ]);
1001
+ });
1002
+
1003
+ it('resolves a collapsed reference `[text][]`', () => {
1004
+ const {links} = paragraphLinks(
1005
+ 'See [the docs][].\n\n[the docs]: https://example.com/docs',
1006
+ );
1007
+ expect(links).toEqual([
1008
+ {type: 'link', href: 'https://example.com/docs', text: 'the docs'},
1009
+ ]);
1010
+ });
1011
+
1012
+ it('resolves a shortcut reference `[text]`', () => {
1013
+ const {links} = paragraphLinks(
1014
+ 'See [the docs].\n\n[the docs]: https://example.com/docs',
1015
+ );
1016
+ expect(links).toEqual([
1017
+ {type: 'link', href: 'https://example.com/docs', text: 'the docs'},
1018
+ ]);
1019
+ });
1020
+
1021
+ it('resolves a reference that appears before its definition', () => {
1022
+ const {links} = paragraphLinks('[foo]\n\n[foo]: /bar');
1023
+ expect(links).toEqual([{type: 'link', href: '/bar', text: 'foo'}]);
1024
+ });
1025
+
1026
+ it('matches labels case-insensitively with collapsed whitespace', () => {
1027
+ const {links} = paragraphLinks(
1028
+ 'See [The Docs][DOCS].\n\n[docs]: https://example.com/d',
1029
+ );
1030
+ expect(links).toEqual([
1031
+ {type: 'link', href: 'https://example.com/d', text: 'The Docs'},
1032
+ ]);
1033
+ });
1034
+
1035
+ it('supports an angle-bracket destination and a title', () => {
1036
+ const {links} = paragraphLinks(
1037
+ 'See [x].\n\n[x]: <https://example.com/x> "the title"',
1038
+ );
1039
+ expect(links).toEqual([
1040
+ {type: 'link', href: 'https://example.com/x', text: 'x'},
1041
+ ]);
1042
+ });
1043
+
1044
+ it('absorbs a title on the line after a title-less definition', () => {
1045
+ const {blocks, links} = paragraphLinks(
1046
+ 'See [x].\n\n[x]: https://example.com/x\n "the title"\n',
1047
+ );
1048
+ // The continuation title line must not leak as its own paragraph.
1049
+ expect(blocks).toHaveLength(1);
1050
+ expect(links).toEqual([
1051
+ {type: 'link', href: 'https://example.com/x', text: 'x'},
1052
+ ]);
1053
+ });
1054
+
1055
+ it('resolves an empty angle-bracket destination to an empty href', () => {
1056
+ const {blocks, links} = paragraphLinks('[foo]\n\n[foo]: <>');
1057
+ expect(blocks).toHaveLength(1);
1058
+ expect(links).toEqual([{type: 'link', href: '', text: 'foo'}]);
1059
+ });
1060
+
1061
+ it('recognizes a definition immediately after a heading (no blank line)', () => {
1062
+ const {blocks, links} = paragraphLinks('# Title\n[x]: /url\n\n[x]');
1063
+ expect(blocks.map(block => block.type)).toEqual(['heading', 'paragraph']);
1064
+ expect(links).toEqual([{type: 'link', href: '/url', text: 'x'}]);
1065
+ });
1066
+
1067
+ it('recognizes a definition immediately after a closed code fence', () => {
1068
+ const {blocks, links} = paragraphLinks('```\ncode\n```\n[x]: /url\n\n[x]');
1069
+ expect(blocks.map(block => block.type)).toEqual(['codeblock', 'paragraph']);
1070
+ expect(links).toEqual([{type: 'link', href: '/url', text: 'x'}]);
1071
+ });
1072
+
1073
+ it('uses the first definition when a label is defined twice', () => {
1074
+ const {links} = paragraphLinks('[a]\n\n[a]: /first\n[a]: /second');
1075
+ expect(links).toEqual([{type: 'link', href: '/first', text: 'a'}]);
1076
+ });
1077
+
1078
+ it('resolves a blockquote-nested definition even with a top-level definition present', () => {
1079
+ const blocks = parseMarkdown('[outer]: /o\n\n> [inner]\n>\n> [inner]: /i');
1080
+ const quote = blocks.find(block => block.type === 'blockquote');
1081
+ expect(quote?.type).toBe('blockquote');
1082
+ if (quote != null && quote.type === 'blockquote') {
1083
+ const links = quote.children.flatMap(block =>
1084
+ block.type === 'paragraph' ? collectLinks(block.children) : [],
1085
+ );
1086
+ expect(links).toEqual([{type: 'link', href: '/i', text: 'inner'}]);
1087
+ }
1088
+ });
1089
+
1090
+ it('resolves a reference image `![alt][label]`', () => {
1091
+ const {links} = paragraphLinks('![logo][l]\n\n[l]: /logo.png');
1092
+ expect(links).toEqual([{type: 'image', src: '/logo.png', text: 'logo'}]);
1093
+ });
1094
+
1095
+ it('does not treat a whitespace-only second label as collapsed', () => {
1096
+ // `[foo][ ]` is a full reference to the empty (normalized) label and matches
1097
+ // nothing; `[foo]` still resolves as a shortcut and `[ ]` stays literal.
1098
+ const blocks = parseMarkdown('[foo][ ]\n\n[foo]: /f');
1099
+ expect(blocks[0].type).toBe('paragraph');
1100
+ if (blocks[0].type === 'paragraph') {
1101
+ expect(collectLinks(blocks[0].children)).toEqual([
1102
+ {type: 'link', href: '/f', text: 'foo'},
1103
+ ]);
1104
+ const literal = blocks[0].children
1105
+ .map(node => (node.type === 'text' ? node.content : ''))
1106
+ .join('');
1107
+ expect(literal).toContain('[ ]');
1108
+ }
1109
+ });
1110
+
1111
+ it('leaves an unresolved reference as literal text', () => {
1112
+ const {blocks, links} = paragraphLinks('See [the docs][missing].');
1113
+ expect(links).toEqual([]);
1114
+ expect(blocks[0].type).toBe('paragraph');
1115
+ if (blocks[0].type === 'paragraph') {
1116
+ expect(blocks[0].children).toContainEqual({
1117
+ type: 'text',
1118
+ content: 'See [the docs][missing].',
1119
+ });
1120
+ }
1121
+ });
1122
+
1123
+ it('does not resolve a definition or reference inside a code fence', () => {
1124
+ const blocks = parseMarkdown('```\n[x]\n[x]: /should-not-resolve\n```');
1125
+ expect(blocks).toHaveLength(1);
1126
+ expect(blocks[0].type).toBe('codeblock');
1127
+ if (blocks[0].type === 'codeblock') {
1128
+ expect(blocks[0].content).toBe('[x]\n[x]: /should-not-resolve');
1129
+ }
1130
+ });
1131
+
1132
+ it('does not treat a definition-shaped line as a definition mid-paragraph', () => {
1133
+ // CommonMark: a definition cannot interrupt a paragraph.
1134
+ const {blocks, links} = paragraphLinks('Foo\n[bar]: /baz');
1135
+ expect(links).toEqual([]);
1136
+ expect(blocks).toHaveLength(1);
1137
+ expect(blocks[0].type).toBe('paragraph');
1138
+ });
1139
+
1140
+ it('leaves footnote markers and definitions untouched', () => {
1141
+ const blocks = parseMarkdown(
1142
+ 'A claim.[^1]\n\n[^1]: https://example.com/note',
1143
+ );
1144
+ // No link nodes; the `[^1]` marker stays literal and `[^1]:` is not
1145
+ // treated as a link reference definition (footnotes are out of scope).
1146
+ const links = blocks.flatMap(block =>
1147
+ block.type === 'paragraph' ? collectLinks(block.children) : [],
1148
+ );
1149
+ expect(links).toEqual([]);
1150
+ expect(blocks).toHaveLength(2);
1151
+ });
1152
+
1153
+ it('leaves ordinary bracketed text with no definition alone', () => {
1154
+ const {links, blocks} = paragraphLinks('an array like [1, 2, 3] here');
1155
+ expect(links).toEqual([]);
1156
+ expect(blocks[0].type).toBe('paragraph');
1157
+ });
1158
+ });