@astryxdesign/core 0.4.7 → 0.5.0-canary.32a62fd

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 (554) hide show
  1. package/CHANGELOG.md +161 -1
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +3 -2
  4. package/dist/AspectRatio/AspectRatio.d.ts +24 -0
  5. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  6. package/dist/AspectRatio/AspectRatio.js +23 -4
  7. package/dist/Avatar/Avatar.d.ts +25 -1
  8. package/dist/Avatar/Avatar.d.ts.map +1 -1
  9. package/dist/Avatar/Avatar.js +58 -19
  10. package/dist/Avatar/index.d.ts +2 -2
  11. package/dist/Avatar/index.d.ts.map +1 -1
  12. package/dist/Avatar/index.js +1 -1
  13. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  14. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  15. package/dist/AvatarGroup/AvatarGroup.js +8 -4
  16. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  17. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  19. package/dist/AvatarGroup/AvatarGroupOverflow.js +10 -6
  20. package/dist/Banner/Banner.d.ts +40 -15
  21. package/dist/Banner/Banner.d.ts.map +1 -1
  22. package/dist/Banner/Banner.js +51 -18
  23. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  24. package/dist/BottomSheet/BottomSheet.js +17 -4
  25. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  26. package/dist/BottomSheet/BottomSheetSwitcher.js +3 -2
  27. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  28. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -10
  29. package/dist/Button/Button.d.ts.map +1 -1
  30. package/dist/Button/Button.js +5 -4
  31. package/dist/ButtonGroup/ButtonGroup.d.ts +5 -1
  32. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  33. package/dist/ButtonGroup/ButtonGroup.js +26 -7
  34. package/dist/Calendar/Calendar.d.ts +3 -1
  35. package/dist/Calendar/Calendar.d.ts.map +1 -1
  36. package/dist/Calendar/Calendar.js +13 -14
  37. package/dist/Calendar/getInitialFocusDate.d.ts +46 -0
  38. package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -0
  39. package/dist/Calendar/getInitialFocusDate.js +62 -0
  40. package/dist/Carousel/Carousel.d.ts.map +1 -1
  41. package/dist/Carousel/Carousel.js +3 -3
  42. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposerInput.js +2 -3
  44. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  45. package/dist/Chat/ChatLayout.js +3 -3
  46. package/dist/Chat/ChatMessageList.d.ts +22 -3
  47. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  48. package/dist/Chat/ChatMessageList.js +6 -3
  49. package/dist/Chat/ChatTokenizedText.d.ts +2 -0
  50. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  51. package/dist/Chat/ChatTokenizedText.js +11 -6
  52. package/dist/Chat/useChatComposerTokens.js +1 -1
  53. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  54. package/dist/CheckboxInput/CheckboxInput.js +10 -3
  55. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  56. package/dist/ClickableCard/ClickableCard.js +3 -3
  57. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  58. package/dist/CodeBlock/CodeBlock.js +15 -4
  59. package/dist/CodeBlock/highlightRanges.js +1 -1
  60. package/dist/CodeBlock/highlightStyles.js +13 -13
  61. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  62. package/dist/CommandPalette/CommandPaletteInput.js +3 -2
  63. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  64. package/dist/CommandPalette/CommandPaletteItem.js +3 -2
  65. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  66. package/dist/ContextMenu/ContextMenu.js +4 -3
  67. package/dist/DateInput/DateInput.d.ts +43 -0
  68. package/dist/DateInput/DateInput.d.ts.map +1 -1
  69. package/dist/DateInput/DateInput.js +22 -2
  70. package/dist/DateInput/NativeDateField.d.ts +10 -0
  71. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  72. package/dist/DateInput/NativeDateField.js +477 -0
  73. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  74. package/dist/DateInput/TouchDateField.js +38 -4
  75. package/dist/DateInput/index.d.ts +1 -1
  76. package/dist/DateInput/index.d.ts.map +1 -1
  77. package/dist/DateTimeInput/DateTimeInput.d.ts +21 -1
  78. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  79. package/dist/DateTimeInput/DateTimeInput.js +406 -12
  80. package/dist/DateTimeInput/index.d.ts +1 -1
  81. package/dist/DateTimeInput/index.d.ts.map +1 -1
  82. package/dist/Dialog/Dialog.d.ts +7 -1
  83. package/dist/Dialog/Dialog.d.ts.map +1 -1
  84. package/dist/Dialog/Dialog.js +89 -58
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
  87. package/dist/Field/FieldLabel.d.ts.map +1 -1
  88. package/dist/Field/FieldLabel.js +9 -1
  89. package/dist/FileInput/FileInput.d.ts.map +1 -1
  90. package/dist/FileInput/FileInput.js +3 -2
  91. package/dist/Heading/Heading.d.ts.map +1 -1
  92. package/dist/Heading/Heading.js +6 -2
  93. package/dist/HoverCard/HoverCard.d.ts +6 -0
  94. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  95. package/dist/HoverCard/HoverCard.js +52 -3
  96. package/dist/HoverCard/useHoverCard.d.ts +16 -2
  97. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  98. package/dist/HoverCard/useHoverCard.js +74 -26
  99. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  100. package/dist/Indicator/CheckboxIndicator.js +6 -2
  101. package/dist/Item/Item.d.ts.map +1 -1
  102. package/dist/Item/Item.js +4 -2
  103. package/dist/Kbd/Kbd.d.ts.map +1 -1
  104. package/dist/Kbd/Kbd.js +2 -19
  105. package/dist/Layer/LayerDepthContext.d.ts +52 -0
  106. package/dist/Layer/LayerDepthContext.d.ts.map +1 -0
  107. package/dist/Layer/LayerDepthContext.js +66 -0
  108. package/dist/Layer/index.d.ts +3 -0
  109. package/dist/Layer/index.d.ts.map +1 -1
  110. package/dist/Layer/index.js +4 -0
  111. package/dist/Layer/layerStack.d.ts +98 -0
  112. package/dist/Layer/layerStack.d.ts.map +1 -0
  113. package/dist/Layer/layerStack.js +306 -0
  114. package/dist/Layer/useLayerDismissal.d.ts +93 -0
  115. package/dist/Layer/useLayerDismissal.d.ts.map +1 -0
  116. package/dist/Layer/useLayerDismissal.js +91 -0
  117. package/dist/Lightbox/Lightbox.d.ts +1 -0
  118. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  119. package/dist/Lightbox/Lightbox.js +103 -81
  120. package/dist/Markdown/index.d.ts +1 -1
  121. package/dist/Markdown/index.d.ts.map +1 -1
  122. package/dist/Markdown/parser.d.ts +38 -1
  123. package/dist/Markdown/parser.d.ts.map +1 -1
  124. package/dist/Markdown/parser.js +177 -29
  125. package/dist/MobileNav/MobileNav.d.ts +6 -1
  126. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  127. package/dist/MobileNav/MobileNav.js +61 -36
  128. package/dist/MultiSelector/MultiSelector.d.ts +15 -1
  129. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  130. package/dist/MultiSelector/MultiSelector.js +17 -6
  131. package/dist/MultiSelector/index.d.ts +1 -1
  132. package/dist/MultiSelector/index.d.ts.map +1 -1
  133. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  134. package/dist/NavIcon/NavIcon.js +5 -1
  135. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  136. package/dist/NavMenu/NavHeadingMenu.js +3 -2
  137. package/dist/NumberInput/NumberInput.d.ts +1 -0
  138. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  139. package/dist/NumberInput/NumberInput.js +27 -37
  140. package/dist/NumberInput/numberParser.d.ts +43 -0
  141. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  142. package/dist/NumberInput/numberParser.js +293 -0
  143. package/dist/Outline/Outline.d.ts.map +1 -1
  144. package/dist/Outline/Outline.js +3 -2
  145. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  146. package/dist/OverflowList/OverflowList.js +3 -2
  147. package/dist/Overlay/Overlay.d.ts.map +1 -1
  148. package/dist/Overlay/Overlay.js +3 -2
  149. package/dist/Popover/usePopover.d.ts.map +1 -1
  150. package/dist/Popover/usePopover.js +20 -17
  151. package/dist/PowerSearch/PowerSearch.d.ts +8 -2
  152. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearch.js +19 -6
  154. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +3 -1
  155. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  156. package/dist/PowerSearch/PowerSearchEditPopover.js +28 -6
  157. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -1
  158. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  159. package/dist/PowerSearch/PowerSearchValueEditor.js +19 -9
  160. package/dist/PowerSearch/types.d.ts +2 -0
  161. package/dist/PowerSearch/types.d.ts.map +1 -1
  162. package/dist/PowerSearch/usePowerSearchSource.d.ts +6 -1
  163. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  164. package/dist/PowerSearch/usePowerSearchSource.js +14 -5
  165. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  166. package/dist/ProgressBar/ProgressBar.js +18 -5
  167. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  168. package/dist/Resizable/ResizeHandle.js +3 -2
  169. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  170. package/dist/SegmentedControl/SegmentedControl.js +3 -2
  171. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  172. package/dist/SelectableCard/SelectableCard.js +3 -3
  173. package/dist/Selector/Selector.d.ts.map +1 -1
  174. package/dist/Selector/Selector.js +5 -0
  175. package/dist/SideNav/SideNav.d.ts.map +1 -1
  176. package/dist/SideNav/SideNav.js +4 -3
  177. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  178. package/dist/SideNav/SideNavHeading.js +8 -7
  179. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  180. package/dist/SideNav/SideNavItem.js +4 -3
  181. package/dist/Slider/Slider.d.ts.map +1 -1
  182. package/dist/Slider/Slider.js +3 -3
  183. package/dist/Spinner/Spinner.d.ts +3 -3
  184. package/dist/Spinner/Spinner.d.ts.map +1 -1
  185. package/dist/Spinner/Spinner.js +130 -78
  186. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  187. package/dist/StatusDot/StatusDot.js +6 -1
  188. package/dist/Stepper/Step.d.ts +140 -0
  189. package/dist/Stepper/Step.d.ts.map +1 -0
  190. package/dist/Stepper/Step.js +1045 -0
  191. package/dist/Stepper/StepStatus.d.ts +24 -0
  192. package/dist/Stepper/StepStatus.d.ts.map +1 -0
  193. package/dist/Stepper/StepStatus.js +1 -0
  194. package/dist/Stepper/Stepper.d.ts +93 -0
  195. package/dist/Stepper/Stepper.d.ts.map +1 -0
  196. package/dist/Stepper/Stepper.js +184 -0
  197. package/dist/Stepper/StepperContext.d.ts +41 -0
  198. package/dist/Stepper/StepperContext.d.ts.map +1 -0
  199. package/dist/Stepper/StepperContext.js +34 -0
  200. package/dist/Stepper/index.d.ts +8 -0
  201. package/dist/Stepper/index.d.ts.map +1 -0
  202. package/dist/Stepper/index.js +7 -0
  203. package/dist/Stepper/stepper.stylex.d.ts +15 -0
  204. package/dist/Stepper/stepper.stylex.d.ts.map +1 -0
  205. package/dist/Stepper/stepper.stylex.js +20 -0
  206. package/dist/Switch/Switch.d.ts.map +1 -1
  207. package/dist/Switch/Switch.js +8 -3
  208. package/dist/TabList/Tab.d.ts +15 -2
  209. package/dist/TabList/Tab.d.ts.map +1 -1
  210. package/dist/TabList/Tab.js +32 -7
  211. package/dist/TabList/TabList.d.ts +46 -7
  212. package/dist/TabList/TabList.d.ts.map +1 -1
  213. package/dist/TabList/TabList.js +353 -23
  214. package/dist/TabList/TabListContext.d.ts +11 -1
  215. package/dist/TabList/TabListContext.d.ts.map +1 -1
  216. package/dist/TabList/TabListContext.js +11 -2
  217. package/dist/TabList/TabMenu.d.ts.map +1 -1
  218. package/dist/TabList/TabMenu.js +3 -2
  219. package/dist/TabList/index.d.ts +2 -2
  220. package/dist/TabList/index.d.ts.map +1 -1
  221. package/dist/Table/BaseTable.d.ts.map +1 -1
  222. package/dist/Table/BaseTable.js +10 -2
  223. package/dist/Table/Table.d.ts.map +1 -1
  224. package/dist/Table/Table.js +3 -6
  225. package/dist/Table/TableRow.d.ts +16 -5
  226. package/dist/Table/TableRow.d.ts.map +1 -1
  227. package/dist/Table/TableRow.js +16 -5
  228. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  229. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +20 -8
  230. package/dist/Table/plugins/pagination/useTablePagination.d.ts +3 -0
  231. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  232. package/dist/Table/plugins/pagination/useTablePagination.js +21 -4
  233. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  234. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
  235. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
  236. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +10 -3
  237. package/dist/Table/plugins/selection/useTableSelection.d.ts +16 -0
  238. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  239. package/dist/Table/plugins/selection/useTableSelection.js +19 -5
  240. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  241. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  242. package/dist/Table/types.d.ts +22 -4
  243. package/dist/Table/types.d.ts.map +1 -1
  244. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  245. package/dist/Table/useBaseTablePlugins.js +5 -0
  246. package/dist/Text/Text.d.ts.map +1 -1
  247. package/dist/Text/Text.js +6 -2
  248. package/dist/TextArea/TextArea.d.ts.map +1 -1
  249. package/dist/TextArea/TextArea.js +9 -3
  250. package/dist/TextInput/TextInput.d.ts.map +1 -1
  251. package/dist/TextInput/TextInput.js +3 -2
  252. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  253. package/dist/TimeInput/TimeInput.js +3 -2
  254. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  255. package/dist/Timestamp/Timestamp.js +5 -3
  256. package/dist/Token/TokenLink.d.ts.map +1 -1
  257. package/dist/Token/TokenLink.js +2 -2
  258. package/dist/Tokenizer/Tokenizer.d.ts +3 -1
  259. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  260. package/dist/Tokenizer/Tokenizer.js +2 -0
  261. package/dist/Tooltip/Tooltip.d.ts +5 -0
  262. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  263. package/dist/Tooltip/useTooltip.d.ts +5 -0
  264. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  265. package/dist/Tooltip/useTooltip.js +39 -24
  266. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  267. package/dist/TopNav/TopNavHeading.js +5 -4
  268. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  269. package/dist/TopNav/TopNavMegaMenu.js +3 -3
  270. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  271. package/dist/TopNav/TopNavMenu.js +4 -3
  272. package/dist/Typeahead/BaseTypeahead.d.ts +2 -0
  273. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  274. package/dist/Typeahead/BaseTypeahead.js +68 -29
  275. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  276. package/dist/Typeahead/Typeahead.js +3 -2
  277. package/dist/astryx.css +94 -7
  278. package/dist/hooks/index.d.ts +1 -0
  279. package/dist/hooks/index.d.ts.map +1 -1
  280. package/dist/hooks/index.js +1 -0
  281. package/dist/hooks/useFocusTrap.d.ts +7 -4
  282. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  283. package/dist/hooks/useFocusTrap.js +60 -95
  284. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  285. package/dist/hooks/useHotkeys.js +3 -18
  286. package/dist/hooks/useMergedRefs.d.ts +18 -0
  287. package/dist/hooks/useMergedRefs.d.ts.map +1 -0
  288. package/dist/hooks/useMergedRefs.js +25 -0
  289. package/dist/index.d.ts +1 -0
  290. package/dist/index.d.ts.map +1 -1
  291. package/dist/index.js +1 -0
  292. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  293. package/dist/theme/derivedVarRegistry.js +24 -4
  294. package/dist/theme/syntax/tokens.d.ts +1 -1
  295. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  296. package/dist/theme/syntax/tokens.js +5 -2
  297. package/dist/utils/groupItems.d.ts +5 -1
  298. package/dist/utils/groupItems.d.ts.map +1 -1
  299. package/dist/utils/groupItems.js +9 -9
  300. package/dist/utils/index.d.ts +1 -1
  301. package/dist/utils/index.d.ts.map +1 -1
  302. package/dist/utils/isApplePlatform.d.ts +18 -0
  303. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  304. package/dist/utils/isApplePlatform.js +37 -0
  305. package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
  306. package/dist/utils/sharedResizeObserver.js +10 -1
  307. package/dist/utils/timeParser.d.ts +1 -1
  308. package/dist/utils/timeParser.d.ts.map +1 -1
  309. package/dist/utils/timeParser.js +26 -12
  310. package/locales/en.json +31 -7
  311. package/locales/pseudo.json +18 -0
  312. package/package.json +8 -3
  313. package/src/AppShell/AppShell.tsx +3 -2
  314. package/src/AspectRatio/AspectRatio.doc.mjs +6 -3
  315. package/src/AspectRatio/AspectRatio.test.tsx +57 -10
  316. package/src/AspectRatio/AspectRatio.tsx +40 -1
  317. package/src/Avatar/Avatar.doc.mjs +14 -3
  318. package/src/Avatar/Avatar.test.tsx +97 -0
  319. package/src/Avatar/Avatar.tsx +125 -52
  320. package/src/Avatar/index.ts +2 -2
  321. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  322. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  323. package/src/AvatarGroup/AvatarGroup.tsx +15 -6
  324. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  325. package/src/AvatarGroup/AvatarGroupOverflow.tsx +10 -4
  326. package/src/Banner/Banner.doc.mjs +13 -11
  327. package/src/Banner/Banner.test.tsx +102 -15
  328. package/src/Banner/Banner.tsx +72 -25
  329. package/src/BottomSheet/BottomSheet.test.tsx +123 -0
  330. package/src/BottomSheet/BottomSheet.tsx +17 -4
  331. package/src/BottomSheet/BottomSheetSwitcher.tsx +3 -2
  332. package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
  333. package/src/Button/Button.doc.mjs +22 -0
  334. package/src/Button/Button.test.tsx +13 -0
  335. package/src/Button/Button.tsx +5 -4
  336. package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
  337. package/src/ButtonGroup/ButtonGroup.test.tsx +391 -1
  338. package/src/ButtonGroup/ButtonGroup.tsx +23 -5
  339. package/src/Calendar/Calendar.doc.mjs +4 -3
  340. package/src/Calendar/Calendar.test.tsx +52 -0
  341. package/src/Calendar/Calendar.tsx +18 -15
  342. package/src/Calendar/getInitialFocusDate.test.ts +94 -0
  343. package/src/Calendar/getInitialFocusDate.ts +93 -0
  344. package/src/Carousel/Carousel.tsx +3 -2
  345. package/src/Chat/ChatComposerInput.tsx +5 -1
  346. package/src/Chat/ChatLayout.tsx +3 -2
  347. package/src/Chat/ChatMessageList.doc.mjs +9 -1
  348. package/src/Chat/ChatMessageList.test.tsx +46 -0
  349. package/src/Chat/ChatMessageList.tsx +28 -4
  350. package/src/Chat/ChatTokenizedText.tsx +17 -10
  351. package/src/Chat/useChatComposerTokens.ts +1 -1
  352. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  353. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  354. package/src/CheckboxInput/CheckboxInput.tsx +8 -2
  355. package/src/ClickableCard/ClickableCard.tsx +3 -2
  356. package/src/CodeBlock/CodeBlock.doc.mjs +16 -4
  357. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  358. package/src/CodeBlock/CodeBlock.tsx +20 -4
  359. package/src/CodeBlock/highlightRanges.ts +1 -1
  360. package/src/CodeBlock/highlightStyles.ts +13 -13
  361. package/src/CommandPalette/CommandPaletteInput.tsx +3 -2
  362. package/src/CommandPalette/CommandPaletteItem.tsx +3 -2
  363. package/src/ContextMenu/ContextMenu.doc.mjs +5 -0
  364. package/src/ContextMenu/ContextMenu.tsx +4 -3
  365. package/src/DateInput/DateInput.doc.mjs +16 -0
  366. package/src/DateInput/DateInput.tsx +55 -2
  367. package/src/DateInput/DateInputTouch.test.tsx +68 -9
  368. package/src/DateInput/NativeDateField.test.tsx +565 -0
  369. package/src/DateInput/NativeDateField.tsx +623 -0
  370. package/src/DateInput/TouchDateField.tsx +38 -4
  371. package/src/DateInput/index.ts +1 -0
  372. package/src/DateTimeInput/DateTimeInput.doc.mjs +18 -0
  373. package/src/DateTimeInput/DateTimeInput.test.tsx +1088 -0
  374. package/src/DateTimeInput/DateTimeInput.tsx +556 -24
  375. package/src/DateTimeInput/index.ts +1 -0
  376. package/src/Dialog/Dialog.doc.mjs +8 -3
  377. package/src/Dialog/Dialog.test.tsx +261 -1
  378. package/src/Dialog/Dialog.tsx +109 -58
  379. package/src/DropdownMenu/DropdownMenu.doc.mjs +6 -0
  380. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +8 -5
  381. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +8 -11
  382. package/src/Field/Field.doc.mjs +13 -2
  383. package/src/Field/FieldLabel.test.tsx +29 -0
  384. package/src/Field/FieldLabel.tsx +7 -0
  385. package/src/FileInput/FileInput.tsx +3 -2
  386. package/src/Heading/Heading.test.tsx +23 -1
  387. package/src/Heading/Heading.tsx +6 -2
  388. package/src/HoverCard/HoverCard.doc.mjs +13 -2
  389. package/src/HoverCard/HoverCard.test.tsx +101 -4
  390. package/src/HoverCard/HoverCard.tsx +71 -3
  391. package/src/HoverCard/useHoverCard.tsx +101 -33
  392. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  393. package/src/Indicator/Indicator.doc.mjs +2 -0
  394. package/src/Item/Item.tsx +5 -4
  395. package/src/Kbd/Kbd.tsx +2 -19
  396. package/src/Layer/LayerDepthContext.tsx +62 -0
  397. package/src/Layer/index.ts +9 -0
  398. package/src/Layer/layerDismissalFamilies.test.tsx +359 -0
  399. package/src/Layer/layerDismissalInvariants.test.tsx +417 -0
  400. package/src/Layer/layerStack.ts +362 -0
  401. package/src/Layer/useLayerDismissal.test.tsx +469 -0
  402. package/src/Layer/useLayerDismissal.ts +173 -0
  403. package/src/Layout/Layout.doc.mjs +2 -2
  404. package/src/Lightbox/Lightbox.doc.mjs +12 -0
  405. package/src/Lightbox/Lightbox.tsx +124 -102
  406. package/src/Link/Link.doc.mjs +39 -0
  407. package/src/Markdown/Markdown.doc.mjs +5 -0
  408. package/src/Markdown/incremental.test.ts +16 -2
  409. package/src/Markdown/index.ts +1 -0
  410. package/src/Markdown/parser.perf.test.ts +96 -1
  411. package/src/Markdown/parser.test.ts +145 -2
  412. package/src/Markdown/parser.ts +244 -29
  413. package/src/MobileNav/MobileNav.tsx +62 -36
  414. package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
  415. package/src/MultiSelector/MultiSelector.doc.mjs +27 -0
  416. package/src/MultiSelector/MultiSelector.test.tsx +106 -0
  417. package/src/MultiSelector/MultiSelector.tsx +50 -6
  418. package/src/MultiSelector/index.ts +1 -0
  419. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  420. package/src/NavIcon/NavIcon.test.tsx +9 -0
  421. package/src/NavIcon/NavIcon.tsx +5 -1
  422. package/src/NavMenu/NavHeadingMenu.tsx +3 -2
  423. package/src/NumberInput/NumberInput.doc.mjs +20 -0
  424. package/src/NumberInput/NumberInput.tsx +28 -29
  425. package/src/NumberInput/numberParser.test.ts +137 -0
  426. package/src/NumberInput/numberParser.ts +346 -0
  427. package/src/Outline/Outline.tsx +3 -2
  428. package/src/OverflowList/OverflowList.tsx +3 -2
  429. package/src/Overlay/Overlay.tsx +3 -2
  430. package/src/Popover/usePopover.tsx +31 -28
  431. package/src/PowerSearch/PowerSearch.doc.mjs +160 -28
  432. package/src/PowerSearch/PowerSearch.test.tsx +240 -1
  433. package/src/PowerSearch/PowerSearch.tsx +34 -5
  434. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +201 -0
  435. package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
  436. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +47 -1
  437. package/src/PowerSearch/PowerSearchValueEditor.tsx +15 -0
  438. package/src/PowerSearch/types.ts +2 -0
  439. package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
  440. package/src/PowerSearch/usePowerSearchSource.ts +13 -3
  441. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  442. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  443. package/src/ProgressBar/ProgressBar.tsx +28 -8
  444. package/src/Resizable/ResizeHandle.tsx +3 -2
  445. package/src/SegmentedControl/SegmentedControl.tsx +3 -2
  446. package/src/SelectableCard/SelectableCard.tsx +3 -2
  447. package/src/Selector/Selector.doc.mjs +12 -1
  448. package/src/Selector/Selector.test.tsx +45 -1
  449. package/src/Selector/Selector.tsx +11 -1
  450. package/src/SideNav/SideNav.doc.mjs +6 -6
  451. package/src/SideNav/SideNav.tsx +4 -2
  452. package/src/SideNav/SideNavHeading.tsx +12 -12
  453. package/src/SideNav/SideNavItem.tsx +4 -2
  454. package/src/Slider/Slider.tsx +3 -2
  455. package/src/Spinner/Spinner.test.tsx +147 -1
  456. package/src/Spinner/Spinner.tsx +120 -101
  457. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  458. package/src/StatusDot/StatusDot.test.tsx +9 -0
  459. package/src/StatusDot/StatusDot.tsx +7 -1
  460. package/src/Stepper/Step.doc.mjs +98 -0
  461. package/src/Stepper/Step.tsx +1638 -0
  462. package/src/Stepper/StepStatus.ts +26 -0
  463. package/src/Stepper/Stepper.doc.mjs +370 -0
  464. package/src/Stepper/Stepper.test.tsx +1024 -0
  465. package/src/Stepper/Stepper.tsx +258 -0
  466. package/src/Stepper/StepperContext.ts +71 -0
  467. package/src/Stepper/index.ts +18 -0
  468. package/src/Stepper/stepper.stylex.ts +19 -0
  469. package/src/Switch/Switch.doc.mjs +2 -0
  470. package/src/Switch/Switch.test.tsx +10 -0
  471. package/src/Switch/Switch.tsx +6 -2
  472. package/src/TabList/Tab.doc.mjs +13 -1
  473. package/src/TabList/Tab.tsx +67 -7
  474. package/src/TabList/TabList.doc.mjs +22 -6
  475. package/src/TabList/TabList.test.tsx +559 -0
  476. package/src/TabList/TabList.tsx +490 -22
  477. package/src/TabList/TabListContext.ts +13 -2
  478. package/src/TabList/TabMenu.tsx +3 -2
  479. package/src/TabList/index.ts +6 -2
  480. package/src/Table/BaseTable.tsx +12 -4
  481. package/src/Table/Table.doc.mjs +9 -2
  482. package/src/Table/Table.test.tsx +132 -14
  483. package/src/Table/Table.tsx +3 -8
  484. package/src/Table/TableBody.doc.mjs +40 -0
  485. package/src/Table/TableFooter.doc.mjs +40 -0
  486. package/src/Table/TableHeader.doc.mjs +40 -0
  487. package/src/Table/TableRow.tsx +16 -5
  488. package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +112 -0
  489. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +100 -0
  490. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +17 -8
  491. package/src/Table/plugins/pagination/useTablePagination.test.tsx +34 -4
  492. package/src/Table/plugins/pagination/useTablePagination.tsx +35 -3
  493. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -2
  494. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +13 -7
  495. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +12 -3
  496. package/src/Table/plugins/selection/useTableSelection.test.tsx +76 -0
  497. package/src/Table/plugins/selection/useTableSelection.tsx +40 -7
  498. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  499. package/src/Table/types.ts +22 -4
  500. package/src/Table/useBaseTablePlugins.ts +5 -0
  501. package/src/Table/useTableGroupedRows.doc.mjs +5 -4
  502. package/src/Table/useTablePagination.doc.mjs +7 -0
  503. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  504. package/src/Table/useTableSelection.doc.mjs +31 -0
  505. package/src/Text/Text.test.tsx +23 -1
  506. package/src/Text/Text.tsx +6 -2
  507. package/src/TextArea/TextArea.doc.mjs +8 -2
  508. package/src/TextArea/TextArea.test.tsx +11 -0
  509. package/src/TextArea/TextArea.tsx +15 -8
  510. package/src/TextInput/TextInput.doc.mjs +10 -0
  511. package/src/TextInput/TextInput.tsx +3 -2
  512. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  513. package/src/TimeInput/TimeInput.tsx +2 -2
  514. package/src/Timestamp/Timestamp.tsx +4 -2
  515. package/src/Toast/Toast.doc.mjs +6 -0
  516. package/src/Token/TokenLink.tsx +2 -2
  517. package/src/Tokenizer/Tokenizer.doc.mjs +27 -0
  518. package/src/Tokenizer/Tokenizer.tsx +4 -0
  519. package/src/Toolbar/Toolbar.doc.mjs +5 -0
  520. package/src/Tooltip/Tooltip.doc.mjs +5 -0
  521. package/src/Tooltip/Tooltip.test.tsx +32 -0
  522. package/src/Tooltip/Tooltip.tsx +5 -0
  523. package/src/Tooltip/useTooltip.tsx +47 -24
  524. package/src/TopNav/TopNavHeading.tsx +5 -4
  525. package/src/TopNav/TopNavMegaMenu.tsx +3 -2
  526. package/src/TopNav/TopNavMenu.tsx +4 -3
  527. package/src/Typeahead/BaseTypeahead.doc.mjs +11 -0
  528. package/src/Typeahead/BaseTypeahead.tsx +85 -33
  529. package/src/Typeahead/Typeahead.doc.mjs +5 -0
  530. package/src/Typeahead/Typeahead.test.tsx +49 -0
  531. package/src/Typeahead/Typeahead.tsx +3 -2
  532. package/src/hooks/index.ts +2 -0
  533. package/src/hooks/useContainerReveal.doc.mjs +2 -2
  534. package/src/hooks/useFocusTrap.test.tsx +14 -0
  535. package/src/hooks/useFocusTrap.ts +62 -111
  536. package/src/hooks/useFocusTrapEscapeShim.test.tsx +165 -0
  537. package/src/hooks/useHotkeys.ts +3 -18
  538. package/src/hooks/useMergedRefs.doc.mjs +79 -0
  539. package/src/hooks/useMergedRefs.test.tsx +62 -0
  540. package/src/hooks/useMergedRefs.ts +36 -0
  541. package/src/index.ts +1 -0
  542. package/src/theme/MediaTheme.doc.mjs +5 -5
  543. package/src/theme/derivedVarRegistry.test.ts +19 -3
  544. package/src/theme/derivedVarRegistry.ts +23 -4
  545. package/src/theme/generateThemeRules.test.ts +37 -0
  546. package/src/theme/syntax/tokens.ts +5 -2
  547. package/src/utils/groupItems.ts +12 -6
  548. package/src/utils/index.ts +1 -1
  549. package/src/utils/isApplePlatform.test.ts +61 -0
  550. package/src/utils/isApplePlatform.ts +37 -0
  551. package/src/utils/sharedResizeObserver.ts +10 -2
  552. package/src/utils/timeParser.test.ts +6 -1
  553. package/src/utils/timeParser.ts +35 -13
  554. package/src/__tests__/inputWidthContract.test.tsx +0 -69
@@ -24,7 +24,15 @@ export type InlineNode =
24
24
  | {type: 'citation'; sourceId: string}
25
25
  | {type: 'break'};
26
26
 
27
- export type BlockNode =
27
+ export type BlockNode = BlockNodeKind & {
28
+ /**
29
+ * Where this block came from in the source, when parsed with the
30
+ * `sourceRanges` option. Top-level blocks only.
31
+ */
32
+ range?: SourceRange;
33
+ };
34
+
35
+ type BlockNodeKind =
28
36
  | {type: 'heading'; level: 1 | 2 | 3 | 4 | 5 | 6; children: InlineNode[]}
29
37
  | {type: 'paragraph'; children: InlineNode[]}
30
38
  | {type: 'codeblock'; language: string; content: string}
@@ -47,6 +55,17 @@ export type BlockNode =
47
55
  | {type: 'hr'}
48
56
  | {type: 'image'; src: string; alt: string};
49
57
 
58
+ /**
59
+ * Where a block sits in the source string handed to `parseMarkdown`:
60
+ * `source.slice(start, end)` is the block, and `end` excludes the block's
61
+ * trailing blank lines.
62
+ *
63
+ * An object rather than a `[start, end]` tuple so a second way of addressing
64
+ * the same block — line numbers, once a consumer needs them — can be added as
65
+ * optional fields without breaking anyone.
66
+ */
67
+ export type SourceRange = {readonly start: number; readonly end: number};
68
+
50
69
  export type ListItemNode = {checked?: boolean; children: BlockNode[]};
51
70
  export type TableCellNode = {children: InlineNode[]};
52
71
  export type TableAlignment = 'left' | 'center' | 'right' | null;
@@ -78,11 +97,28 @@ export type ParseOptions = {
78
97
  * suffix is not rejected (Astryx accepts any plausible TLD shape).
79
98
  */
80
99
  autolink?: 'gfm';
100
+ /**
101
+ * When true, every top-level block carries a `range` — the offsets it
102
+ * occupies in the string passed in. Lets a consumer that still holds the
103
+ * source slice the original markdown for a block instead of reconstructing
104
+ * it from the parsed node (or from the rendered DOM). Off by default: the
105
+ * field is absent unless asked for, so nothing that compares nodes changes.
106
+ *
107
+ * Blocks nested inside a list item or a blockquote do not carry one.
108
+ */
109
+ sourceRanges?: boolean;
81
110
  };
82
111
 
83
112
  type ResolvedOptions = {
84
113
  readonly sourceIds: ReadonlySet<string> | undefined;
85
114
  readonly autolink: 'gfm' | undefined;
115
+ readonly sourceRanges?: boolean;
116
+ /**
117
+ * Offset of this parse's input within the document the ranges are reported
118
+ * against. Internal only — the incremental parser parses slices and needs
119
+ * their blocks' ranges to come out absolute.
120
+ */
121
+ readonly baseOffset?: number;
86
122
  /**
87
123
  * Link reference definitions (`[label]: url`) collected from the whole
88
124
  * document, keyed by normalized label. Internal only — populated by the
@@ -109,7 +145,11 @@ function resolveOptions(
109
145
  return {sourceIds: arg as ReadonlySet<string>, autolink: undefined};
110
146
  }
111
147
  const opts = arg as ParseOptions;
112
- return {sourceIds: opts.sourceIds, autolink: opts.autolink};
148
+ return {
149
+ sourceIds: opts.sourceIds,
150
+ autolink: opts.autolink,
151
+ sourceRanges: opts.sourceRanges,
152
+ };
113
153
  }
114
154
 
115
155
  // ---------------------------------------------------------------------------
@@ -174,6 +214,11 @@ function matchLinkDefinition(
174
214
  function extractLinkDefinitions(input: string): {
175
215
  defs: ReadonlyMap<string, string>;
176
216
  cleaned: string;
217
+ /**
218
+ * For each line of `cleaned`, the line of `input` it came from. Undefined
219
+ * when nothing was stripped and the two are the same text.
220
+ */
221
+ lineMap?: number[];
177
222
  } {
178
223
  const lines = input.split('\n');
179
224
  const defs = new Map<string, string>();
@@ -235,8 +280,14 @@ function extractLinkDefinitions(input: string): {
235
280
  if (defs.size === 0) {
236
281
  return {defs, cleaned: input};
237
282
  }
238
- const cleaned = lines.filter((_, index) => keep[index]).join('\n');
239
- return {defs, cleaned};
283
+ const lineMap: number[] = [];
284
+ for (let index = 0; index < lines.length; index++) {
285
+ if (keep[index]) {
286
+ lineMap.push(index);
287
+ }
288
+ }
289
+ const cleaned = lineMap.map(index => lines[index]).join('\n');
290
+ return {defs, cleaned, lineMap};
240
291
  }
241
292
 
242
293
  /** Order-independent signature of a link-definition set, for cache checks. */
@@ -1042,6 +1093,16 @@ function isTableSeparator(line: string): boolean {
1042
1093
  return nonEmpty.length > 0 && nonEmpty.every(cell => /^:?-+:?$/.test(cell));
1043
1094
  }
1044
1095
 
1096
+ /**
1097
+ * The same options for content parsed out of an enclosing block. Ranges are a
1098
+ * top-level contract: a list item's or a blockquote's children are parsed from
1099
+ * text the caller reassembled (markers and `>` prefixes stripped), so an
1100
+ * offset into it would not address the document.
1101
+ */
1102
+ function nested(opts: ResolvedOptions): ResolvedOptions {
1103
+ return opts.sourceRanges ? {...opts, sourceRanges: false} : opts;
1104
+ }
1105
+
1045
1106
  /**
1046
1107
  * Returns true when a line could start a new block — used to stop paragraph
1047
1108
  * continuation. Every regex here uses bounded or single-class quantifiers
@@ -1213,7 +1274,7 @@ function parseList(
1213
1274
  itemText += '\n' + deindented.join('\n');
1214
1275
  }
1215
1276
 
1216
- items.push({checked, children: parseMarkdownImpl(itemText, opts)});
1277
+ items.push({checked, children: parseMarkdownImpl(itemText, nested(opts))});
1217
1278
 
1218
1279
  // CommonMark loose list: blank line(s) between items of the same style
1219
1280
  // and indent still form one list. Skip the blanks and continue if the
@@ -1274,7 +1335,7 @@ function parseMarkdownImpl(
1274
1335
  // definitions win on conflict, matching CommonMark's first-definition-wins
1275
1336
  // in document order; locally-nested definitions still resolve within this
1276
1337
  // parse.
1277
- const {defs, cleaned} = extractLinkDefinitions(input);
1338
+ const {defs, cleaned, lineMap} = extractLinkDefinitions(input);
1278
1339
  const inherited = baseOpts.linkDefs;
1279
1340
  let linkDefs: ReadonlyMap<string, string> | undefined;
1280
1341
  if (defs.size === 0) {
@@ -1288,9 +1349,25 @@ function parseMarkdownImpl(
1288
1349
  linkDefs != null ? {...baseOpts, linkDefs} : baseOpts;
1289
1350
  const lines = cleaned.split('\n');
1290
1351
  const blocks: BlockNode[] = [];
1352
+ // The line each block started on, parallel to `blocks`. Only collected when
1353
+ // ranges were asked for; a block's end is resolved after the loop, since the
1354
+ // branch that produced it has already moved `index` past whatever it read.
1355
+ const blockStartLines: number[] | null = opts.sourceRanges ? [] : null;
1356
+ // Set only by a block that consumes blank lines as content, where the
1357
+ // positional end derivation would trim them away.
1358
+ const blockEndLines: (number | undefined)[] | null = opts.sourceRanges
1359
+ ? []
1360
+ : null;
1361
+ let blockStartLine = 0;
1362
+ const pushBlock = (node: BlockNode, endLine?: number) => {
1363
+ blocks.push(node);
1364
+ blockStartLines?.push(blockStartLine);
1365
+ blockEndLines?.push(endLine);
1366
+ };
1291
1367
  let index = 0;
1292
1368
 
1293
1369
  while (index < lines.length) {
1370
+ blockStartLine = index;
1294
1371
  const line = lines[index];
1295
1372
  if (line.trim() === '') {
1296
1373
  index++;
@@ -1309,14 +1386,20 @@ function parseMarkdownImpl(
1309
1386
  index++;
1310
1387
  }
1311
1388
  index++; // skip closing fence
1312
- blocks.push({type: 'codeblock', language, content: codeLines.join('\n')});
1389
+ // A fence owns its blank lines, and an unterminated one (mid-stream)
1390
+ // can end on them, so it states its own end rather than letting the
1391
+ // positional derivation trim them off.
1392
+ pushBlock(
1393
+ {type: 'codeblock', language, content: codeLines.join('\n')},
1394
+ Math.min(index, lines.length) - 1,
1395
+ );
1313
1396
  continue;
1314
1397
  }
1315
1398
 
1316
1399
  // --- Heading ---
1317
1400
  const headingMatch = line.match(/^(#{1,6}) +(.*)/);
1318
1401
  if (headingMatch) {
1319
- blocks.push({
1402
+ pushBlock({
1320
1403
  type: 'heading',
1321
1404
  level: headingMatch[1].length as 1 | 2 | 3 | 4 | 5 | 6,
1322
1405
  children: parseInlineEntry(headingMatch[2], opts),
@@ -1327,7 +1410,7 @@ function parseMarkdownImpl(
1327
1410
 
1328
1411
  // --- HR (must precede list check to handle `- - -`, `* * *`, `_ _ _`) ---
1329
1412
  if (isHorizontalRule(line)) {
1330
- blocks.push({type: 'hr'});
1413
+ pushBlock({type: 'hr'});
1331
1414
  index++;
1332
1415
  continue;
1333
1416
  }
@@ -1335,7 +1418,7 @@ function parseMarkdownImpl(
1335
1418
  // --- Standalone image ---
1336
1419
  const imageMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)/);
1337
1420
  if (imageMatch && line.trim() === imageMatch[0]) {
1338
- blocks.push({type: 'image', alt: imageMatch[1], src: imageMatch[2]});
1421
+ pushBlock({type: 'image', alt: imageMatch[1], src: imageMatch[2]});
1339
1422
  index++;
1340
1423
  continue;
1341
1424
  }
@@ -1347,7 +1430,7 @@ function parseMarkdownImpl(
1347
1430
  isTableSeparator(lines[index + 1])
1348
1431
  ) {
1349
1432
  const tableResult = parseTable(lines, index, opts);
1350
- blocks.push(tableResult.node);
1433
+ pushBlock(tableResult.node);
1351
1434
  index = tableResult.nextIndex;
1352
1435
  continue;
1353
1436
  }
@@ -1362,9 +1445,9 @@ function parseMarkdownImpl(
1362
1445
  quoteLines.push(lines[index].replace(/^> ?/, ''));
1363
1446
  index++;
1364
1447
  }
1365
- blocks.push({
1448
+ pushBlock({
1366
1449
  type: 'blockquote',
1367
- children: parseMarkdownImpl(quoteLines.join('\n'), opts),
1450
+ children: parseMarkdownImpl(quoteLines.join('\n'), nested(opts)),
1368
1451
  });
1369
1452
  continue;
1370
1453
  }
@@ -1372,7 +1455,7 @@ function parseMarkdownImpl(
1372
1455
  // --- Unordered list ---
1373
1456
  if (/^ {0,9}[-*+] /.test(line)) {
1374
1457
  const listResult = parseList(lines, index, false, opts);
1375
- blocks.push(listResult.node);
1458
+ pushBlock(listResult.node);
1376
1459
  index = listResult.nextIndex;
1377
1460
  continue;
1378
1461
  }
@@ -1380,7 +1463,7 @@ function parseMarkdownImpl(
1380
1463
  // --- Ordered list ---
1381
1464
  if (/^ {0,9}\d+[.)] /.test(line)) {
1382
1465
  const listResult = parseList(lines, index, true, opts);
1383
- blocks.push(listResult.node);
1466
+ pushBlock(listResult.node);
1384
1467
  index = listResult.nextIndex;
1385
1468
  continue;
1386
1469
  }
@@ -1396,14 +1479,76 @@ function parseMarkdownImpl(
1396
1479
  paraLines.push(lines[index]);
1397
1480
  index++;
1398
1481
  }
1399
- blocks.push({
1482
+ pushBlock({
1400
1483
  type: 'paragraph',
1401
1484
  children: parseInlineEntry(paraLines.join('\n'), opts),
1402
1485
  });
1403
1486
  }
1487
+ if (blockStartLines != null) {
1488
+ stampSourceRanges(
1489
+ blocks,
1490
+ blockStartLines,
1491
+ blockEndLines ?? [],
1492
+ lines,
1493
+ lineMap,
1494
+ input,
1495
+ opts,
1496
+ );
1497
+ }
1404
1498
  return blocks;
1405
1499
  }
1406
1500
 
1501
+ /**
1502
+ * Give each block the offsets it occupies in the original input.
1503
+ *
1504
+ * Blocks are contiguous and in source order, so a block runs from its own
1505
+ * first line to the line before the next block starts, minus the blank lines
1506
+ * between them. Offsets are computed against the *input*, not the text the
1507
+ * block loop saw: link reference definitions are stripped before parsing, and
1508
+ * `lineMap` says which input line each surviving line came from.
1509
+ */
1510
+ function stampSourceRanges(
1511
+ blocks: BlockNode[],
1512
+ blockStartLines: number[],
1513
+ blockEndLines: (number | undefined)[],
1514
+ lines: string[],
1515
+ lineMap: number[] | undefined,
1516
+ input: string,
1517
+ opts: ResolvedOptions,
1518
+ ): void {
1519
+ const base = opts.baseOffset ?? 0;
1520
+ // Offset of the first character of every line of the input.
1521
+ const inputLineStarts = [0];
1522
+ for (let i = 0; i < input.length; i++) {
1523
+ if (input[i] === '\n') {
1524
+ inputLineStarts.push(i + 1);
1525
+ }
1526
+ }
1527
+ // Stripping removes whole lines and never edits one, so a parsed line's
1528
+ // length is its input line's length.
1529
+ const lineStart = (line: number): number =>
1530
+ base + inputLineStarts[lineMap != null ? lineMap[line] : line];
1531
+
1532
+ for (let i = 0; i < blocks.length; i++) {
1533
+ const startLine = blockStartLines[i];
1534
+ let endLine = blockEndLines[i];
1535
+ if (endLine == null) {
1536
+ const nextStart =
1537
+ i + 1 < blocks.length ? blockStartLines[i + 1] : lines.length;
1538
+ endLine = nextStart - 1;
1539
+ while (endLine > startLine && lines[endLine].trim() === '') {
1540
+ endLine--;
1541
+ }
1542
+ }
1543
+ // Exactly the block's own lines, verbatim — a CRLF document's trailing
1544
+ // `\r` included, since the parser reads it as part of the line too and a
1545
+ // range that dropped it would slice to something that re-parses
1546
+ // differently.
1547
+ const end = lineStart(endLine) + lines[endLine].length;
1548
+ blocks[i] = {...blocks[i], range: {start: lineStart(startLine), end}};
1549
+ }
1550
+ }
1551
+
1407
1552
  // ---------------------------------------------------------------------------
1408
1553
  // Incremental parsing
1409
1554
  // ---------------------------------------------------------------------------
@@ -1420,6 +1565,12 @@ export interface IncrementalState {
1420
1565
  * with newly-arriving content.
1421
1566
  */
1422
1567
  autolink?: 'gfm';
1568
+ /**
1569
+ * The `sourceRanges` option the cached `settledBlocks` were parsed with.
1570
+ * Flipping it invalidates them the same way `autolink` does: they either
1571
+ * lack the ranges the caller now asks for, or carry ones it did not.
1572
+ */
1573
+ sourceRanges?: boolean;
1423
1574
  /**
1424
1575
  * Signature of the link reference definitions the cached `settledBlocks`
1425
1576
  * were parsed with. Definitions are document-global and typically arrive
@@ -1435,12 +1586,26 @@ export function createIncrementalState(): IncrementalState {
1435
1586
 
1436
1587
  /**
1437
1588
  * Find the line-index of the last blank line that is NOT inside a fenced code
1438
- * block. Returns -1 when nothing is settled (unclosed fence or no blank line).
1589
+ * block, and report whether a fence is still open at the end of the input.
1590
+ * Returns -1 when nothing is settled.
1591
+ *
1592
+ * This index must never move backwards as more of the document arrives. The
1593
+ * caller's cache is keyed on the settled text staying a prefix of what it was,
1594
+ * so a boundary that retracts by one line costs a re-parse of every block in
1595
+ * the document. Two things used to retract it: a blank last line, which is
1596
+ * just the newline the stream has written so far and stops being blank as soon
1597
+ * as the next chunk appends to it; and an open fence, which used to collapse
1598
+ * the boundary to -1 even though the content before the fence opened cannot be
1599
+ * changed by anything typed inside it.
1439
1600
  */
1440
- function findSettledBoundary(lines: string[]): number {
1601
+ function findSettledBoundary(lines: string[]): {
1602
+ boundary: number;
1603
+ openFence: boolean;
1604
+ } {
1441
1605
  let inFence = false;
1442
1606
  let fenceMarker = '';
1443
1607
  let lastBoundary = -1;
1608
+ let boundaryBeforeFence = -1;
1444
1609
 
1445
1610
  for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
1446
1611
  const line = lines[lineIndex];
@@ -1451,6 +1616,7 @@ function findSettledBoundary(lines: string[]): number {
1451
1616
  if (!inFence) {
1452
1617
  inFence = true;
1453
1618
  fenceMarker = fenceMatch[1];
1619
+ boundaryBeforeFence = lastBoundary;
1454
1620
  } else if (
1455
1621
  fenceMatch[1].startsWith(fenceMarker[0]) &&
1456
1622
  fenceMatch[1].length >= fenceMarker.length
@@ -1460,12 +1626,20 @@ function findSettledBoundary(lines: string[]): number {
1460
1626
  }
1461
1627
  }
1462
1628
 
1463
- if (!inFence && line.trim() === '' && lineIndex > 0) {
1629
+ if (
1630
+ !inFence &&
1631
+ line.trim() === '' &&
1632
+ lineIndex > 0 &&
1633
+ lineIndex < lines.length - 1
1634
+ ) {
1464
1635
  lastBoundary = lineIndex;
1465
1636
  }
1466
1637
  }
1467
1638
 
1468
- return inFence ? -1 : lastBoundary;
1639
+ return {
1640
+ boundary: inFence ? boundaryBeforeFence : lastBoundary,
1641
+ openFence: inFence,
1642
+ };
1469
1643
  }
1470
1644
 
1471
1645
  /**
@@ -1689,6 +1863,15 @@ function trimUnsettledStructural(text: string): string {
1689
1863
  return lines.join('\n');
1690
1864
  }
1691
1865
 
1866
+ /**
1867
+ * The same options, for parsing a slice that starts at `offset` of the
1868
+ * document — so the slice's blocks report ranges into the whole document
1869
+ * rather than into the slice.
1870
+ */
1871
+ function atOffset(opts: ResolvedOptions, offset: number): ResolvedOptions {
1872
+ return opts.sourceRanges ? {...opts, baseOffset: offset} : opts;
1873
+ }
1874
+
1692
1875
  /**
1693
1876
  * Concatenate freshly-parsed delta blocks with previously-settled blocks,
1694
1877
  * merging adjacent same-style lists into a single loose list. The boundary
@@ -1718,6 +1901,11 @@ function mergeSettledBlocks(
1718
1901
  delimiter: prevLast.delimiter,
1719
1902
  loose: true,
1720
1903
  items: [...prevLast.items, ...deltaFirst.items],
1904
+ // One list now, so one range: from where the first half started to
1905
+ // where the second half ended.
1906
+ ...(prevLast.range != null && deltaFirst.range != null
1907
+ ? {range: {start: prevLast.range.start, end: deltaFirst.range.end}}
1908
+ : null),
1721
1909
  };
1722
1910
  return [...prev.slice(0, -1), merged, ...delta.slice(1)];
1723
1911
  }
@@ -1740,15 +1928,19 @@ export function parseMarkdownIncremental(
1740
1928
  arg?: ReadonlySet<string> | ParseOptions,
1741
1929
  ): BlockNode[] {
1742
1930
  const opts = resolveOptions(arg);
1743
- // Invalidate cache when the autolink option flips — cached settled blocks
1744
- // were parsed with the previous setting and would otherwise be reused
1745
- // unchanged.
1746
- if (state.autolink !== opts.autolink) {
1931
+ // Invalidate cache when the autolink or sourceRanges option flips — cached
1932
+ // settled blocks were parsed with the previous setting and would otherwise
1933
+ // be reused unchanged.
1934
+ if (
1935
+ state.autolink !== opts.autolink ||
1936
+ Boolean(state.sourceRanges) !== Boolean(opts.sourceRanges)
1937
+ ) {
1747
1938
  state.prevInput = '';
1748
1939
  state.settledText = '';
1749
1940
  state.settledBlocks = [];
1750
1941
  state.settledUpTo = 0;
1751
1942
  state.autolink = opts.autolink;
1943
+ state.sourceRanges = opts.sourceRanges;
1752
1944
  }
1753
1945
  if (input === '') {
1754
1946
  state.prevInput = '';
@@ -1776,17 +1968,23 @@ export function parseMarkdownIncremental(
1776
1968
  linkDefs.size > 0 ? {...opts, linkDefs} : opts;
1777
1969
 
1778
1970
  const lines = input.split('\n');
1779
- const boundary = findSettledBoundary(lines);
1971
+ const {boundary, openFence} = findSettledBoundary(lines);
1780
1972
 
1781
1973
  if (boundary < 0) {
1782
- // Inside an unclosed fence or no blank-line boundary — full re-parse
1974
+ // Nothing settled yet — no blank line, or a fence opened before the first
1975
+ // one — so there is no prefix to keep and the whole input is re-parsed.
1783
1976
  state.prevInput = input;
1784
1977
  return parseMarkdownImpl(input, parseOpts);
1785
1978
  }
1786
1979
 
1787
1980
  const settledText = lines.slice(0, boundary).join('\n');
1788
1981
  const unsettledRaw = lines.slice(boundary).join('\n').trim();
1789
- const unsettledText = trimUnsettledStructural(unsettledRaw);
1982
+ // Structural trimming holds back lines that look like an incomplete list or
1983
+ // table, which inside a fence is ordinary code: a TypeScript union or a `- `
1984
+ // would disappear from the code block as it streams.
1985
+ const unsettledText = openFence
1986
+ ? unsettledRaw
1987
+ : trimUnsettledStructural(unsettledRaw);
1790
1988
 
1791
1989
  let settledBlocks: BlockNode[];
1792
1990
 
@@ -1799,15 +1997,32 @@ export function parseMarkdownIncremental(
1799
1997
  ) {
1800
1998
  // Settled portion grew — parse only the new delta
1801
1999
  const delta = settledText.slice(state.settledText.length);
1802
- const deltaBlocks = parseMarkdownImpl(delta, parseOpts);
2000
+ const deltaBlocks = parseMarkdownImpl(
2001
+ delta,
2002
+ atOffset(parseOpts, state.settledText.length),
2003
+ );
1803
2004
  settledBlocks = mergeSettledBlocks(state.settledBlocks, deltaBlocks);
1804
2005
  } else {
1805
2006
  // Content before the boundary changed — full re-parse of settled portion
1806
2007
  settledBlocks = parseMarkdownImpl(settledText, parseOpts);
1807
2008
  }
1808
2009
 
2010
+ // The unsettled tail is trimmed before parsing, so its offset in the
2011
+ // document is where that trimmed text actually starts — not the boundary,
2012
+ // which is a line index. If it somehow can't be located, parse it without
2013
+ // ranges rather than report wrong ones. Only worth searching for when
2014
+ // ranges were asked for: this runs on every streamed chunk.
2015
+ const unsettledStart =
2016
+ unsettledText && opts.sourceRanges
2017
+ ? input.indexOf(unsettledText, settledText.length)
2018
+ : -1;
1809
2019
  const unsettledBlocks = unsettledText
1810
- ? parseMarkdownImpl(unsettledText, parseOpts)
2020
+ ? parseMarkdownImpl(
2021
+ unsettledText,
2022
+ unsettledStart >= 0
2023
+ ? atOffset(parseOpts, unsettledStart)
2024
+ : nested(parseOpts),
2025
+ )
1811
2026
  : [];
1812
2027
 
1813
2028
  state.settledText = settledText;
@@ -19,10 +19,15 @@
19
19
  * - `::backdrop` pseudo-element
20
20
  * - Body scroll lock
21
21
  * - Focus trapping
22
- * - Escape key handling via `cancel` event
22
+ *
23
+ * Escape is owned by the shared dismissal stack (`useLayerDismissal`), so a
24
+ * drawer opened over another layer takes the press and nothing behind it
25
+ * closes. The native `cancel` event still handles the dismissals the browser
26
+ * starts itself, such as the Android back gesture.
23
27
  *
24
28
  * SYNC: When modified, update these files to stay in sync:
25
29
  * - /packages/core/src/MobileNav/index.ts (exports if types change)
30
+ * - /packages/core/src/Layer/useLayerDismissal.ts (dismissal stack)
26
31
  * - /packages/core/src/hooks/scrollbarGutter.ts (shared scroll-lock gutter)
27
32
  * - /packages/cli/assets/templates/blocks/components/MobileNav/ (showcase blocks)
28
33
  */
@@ -52,12 +57,15 @@ import {
52
57
  holdScrollbarGutter,
53
58
  type ScrollbarGutterHold,
54
59
  } from '../hooks/scrollbarGutter';
55
- import {mergeProps, mergeRefs, composeEventHandlers} from '../utils';
60
+ import {mergeProps, composeEventHandlers} from '../utils';
56
61
  import {overlayPaddingReset} from '../Layout/padding.stylex';
62
+ import {LayerDepthProvider} from '../Layer/LayerDepthContext';
63
+ import {useLayerDismissal} from '../Layer/useLayerDismissal';
57
64
  import type {BaseProps} from '../BaseProps';
58
65
  import {themeProps} from '../utils/themeProps';
59
66
  import {useTranslator} from '../i18n';
60
67
 
68
+ import {useMergedRefs} from '../hooks/useMergedRefs';
61
69
  // =============================================================================
62
70
  // Styles
63
71
  // =============================================================================
@@ -536,13 +544,28 @@ export function MobileNav({
536
544
  };
537
545
  }, []);
538
546
 
539
- // Handle native cancel event (Escape key) — prevent default and route through onOpenChange
547
+ const {shouldDismissOnCloseRequest} = useLayerDismissal({
548
+ isActive: isOpen,
549
+ onDismiss: () => onOpenChange(false),
550
+ });
551
+
552
+ // The native `cancel` event is the browser's own close-watcher firing: an
553
+ // Android back gesture, or a close request the stack never saw a press for.
554
+ // Escape presses the stack owns never arrive here — it preventDefault()s
555
+ // those, which suppresses the close watcher.
556
+ //
557
+ // Always preventDefault so the browser cannot close a controlled <dialog>
558
+ // behind React's back, then answer with the stack's own rules: top-most
559
+ // only, and never while an IME composition is in progress.
540
560
  const handleCancel = useCallback(
541
561
  (event: React.SyntheticEvent<HTMLDialogElement>) => {
542
562
  event.preventDefault();
563
+ if (!shouldDismissOnCloseRequest()) {
564
+ return;
565
+ }
543
566
  onOpenChange(false);
544
567
  },
545
- [onOpenChange],
568
+ [onOpenChange, shouldDismissOnCloseRequest],
546
569
  );
547
570
 
548
571
  // Handle clicks on the dialog backdrop area (outside the drawer)
@@ -561,7 +584,7 @@ export function MobileNav({
561
584
 
562
585
  return (
563
586
  <dialog
564
- ref={mergeRefs(ref, dialogRef)}
587
+ ref={useMergedRefs(ref, dialogRef)}
565
588
  id={dialogId}
566
589
  {...mergeProps(
567
590
  themeProps('mobile-nav', {side: resolvedSide}),
@@ -586,38 +609,41 @@ export function MobileNav({
586
609
  }
587
610
  onClick={composeEventHandlers(onClickProp, handleDialogClick)}
588
611
  onCancel={handleCancel}>
589
- {/* Drawer panel — tabIndex so showModal() focuses the drawer, not the close button */}
590
- <div
591
- tabIndex={-1}
592
- {...stylex.props(
593
- styles.drawer,
594
- dynamicStyles.width(width),
595
- isStart && styles.drawerStart,
596
- isStart && isOpen && styles.drawerStartOpen,
597
- !isStart && styles.drawerEnd,
598
- !isStart && isOpen && styles.drawerEndOpen,
599
- )}>
600
- {/* Header — content + close button */}
601
- <div {...stylex.props(styles.header, !header && styles.headerNoTitle)}>
602
- {typeof header === 'string' ? (
603
- <Heading level={2} xstyle={styles.headerText}>
604
- {header}
605
- </Heading>
606
- ) : (
607
- (header ?? null)
608
- )}
609
- <Button
610
- variant="ghost"
611
- label={t('@astryx.mobileNav.closeNavigation')}
612
- icon={<Icon icon="close" color="inherit" />}
613
- onClick={() => onOpenChange(false)}
614
- isIconOnly
615
- />
612
+ <LayerDepthProvider>
613
+ {/* Drawer panel — tabIndex so showModal() focuses the drawer, not the close button */}
614
+ <div
615
+ tabIndex={-1}
616
+ {...stylex.props(
617
+ styles.drawer,
618
+ dynamicStyles.width(width),
619
+ isStart && styles.drawerStart,
620
+ isStart && isOpen && styles.drawerStartOpen,
621
+ !isStart && styles.drawerEnd,
622
+ !isStart && isOpen && styles.drawerEndOpen,
623
+ )}>
624
+ {/* Header — content + close button */}
625
+ <div
626
+ {...stylex.props(styles.header, !header && styles.headerNoTitle)}>
627
+ {typeof header === 'string' ? (
628
+ <Heading level={2} xstyle={styles.headerText}>
629
+ {header}
630
+ </Heading>
631
+ ) : (
632
+ (header ?? null)
633
+ )}
634
+ <Button
635
+ variant="ghost"
636
+ label={t('@astryx.mobileNav.closeNavigation')}
637
+ icon={<Icon icon="close" color="inherit" />}
638
+ onClick={() => onOpenChange(false)}
639
+ isIconOnly
640
+ />
641
+ </div>
642
+
643
+ {/* Scrollable content */}
644
+ <div {...stylex.props(styles.content)}>{children}</div>
616
645
  </div>
617
-
618
- {/* Scrollable content */}
619
- <div {...stylex.props(styles.content)}>{children}</div>
620
- </div>
646
+ </LayerDepthProvider>
621
647
  </dialog>
622
648
  );
623
649
  }
@@ -46,7 +46,8 @@ export const docs = {
46
46
  type: 'boolean',
47
47
  description: 'Whether the menu trigger is disabled.',
48
48
  default: 'false',
49
- }, {
49
+ },
50
+ {
50
51
  name: 'placement',
51
52
  type: "'above' | 'below' | 'start' | 'end'",
52
53
  description:
@@ -60,6 +61,11 @@ export const docs = {
60
61
  "Alignment along the placement axis. Use 'end' to align the menu with the trigger's trailing edge, which is usually what an overflow menu wants.",
61
62
  default: "'start'",
62
63
  },
64
+ {
65
+ name: 'onOpenChange',
66
+ type: '(isOpen: boolean) => void',
67
+ description: 'Callback fired when the menu opens or closes.',
68
+ },
63
69
  {
64
70
  name: 'xstyle',
65
71
  type: 'StyleXStyles',