@astryxdesign/core 0.7.1-canary.ff40b78 → 0.7.1

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 (348) hide show
  1. package/CHANGELOG.md +116 -0
  2. package/dist/Button/Button.d.ts +1 -1
  3. package/dist/Button/Button.d.ts.map +1 -1
  4. package/dist/Button/Button.js +5 -2
  5. package/dist/Calendar/Calendar.d.ts.map +1 -1
  6. package/dist/Calendar/Calendar.js +191 -32
  7. package/dist/Chat/ChatComposerInput.d.ts +9 -0
  8. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  9. package/dist/Chat/ChatComposerInput.js +5 -0
  10. package/dist/Chat/ChatMessage.d.ts +11 -0
  11. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  12. package/dist/Chat/ChatMessage.js +18 -9
  13. package/dist/Chat/useTriggerMenu.d.ts +9 -2
  14. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  15. package/dist/Chat/useTriggerMenu.js +222 -50
  16. package/dist/CodeBlock/CodeBlock.d.ts +10 -1
  17. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  18. package/dist/CodeBlock/CodeBlock.js +158 -38
  19. package/dist/CodeBlock/tokenizer.d.ts +39 -0
  20. package/dist/CodeBlock/tokenizer.d.ts.map +1 -1
  21. package/dist/CodeBlock/tokenizer.js +108 -0
  22. package/dist/CommandPalette/CommandPalette.d.ts +9 -5
  23. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  24. package/dist/CommandPalette/CommandPalette.js +38 -20
  25. package/dist/CommandPalette/CommandPaletteEmpty.d.ts +4 -3
  26. package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
  27. package/dist/CommandPalette/CommandPaletteEmpty.js +4 -3
  28. package/dist/CommandPalette/CommandPaletteInput.d.ts +5 -4
  29. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  30. package/dist/CommandPalette/CommandPaletteInput.js +35 -18
  31. package/dist/CommandPalette/CommandPaletteItem.d.ts +11 -6
  32. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  33. package/dist/CommandPalette/CommandPaletteItem.js +8 -9
  34. package/dist/CommandPalette/CommandPaletteList.d.ts +4 -2
  35. package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
  36. package/dist/CommandPalette/CommandPaletteList.js +10 -5
  37. package/dist/ComplexSelector/ComplexSelector.d.ts +8 -5
  38. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  39. package/dist/ComplexSelector/ComplexSelector.js +12 -3
  40. package/dist/ContextMenu/ContextMenu.d.ts +3 -3
  41. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  42. package/dist/ContextMenu/ContextMenu.js +62 -48
  43. package/dist/DateInput/DateInput.js +1 -1
  44. package/dist/DateInput/MonthScroller.d.ts.map +1 -1
  45. package/dist/DateInput/MonthScroller.js +12 -4
  46. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  47. package/dist/DateRangeInput/DateRangeInput.js +12 -2
  48. package/dist/Dialog/Dialog.d.ts +1 -1
  49. package/dist/Dialog/Dialog.d.ts.map +1 -1
  50. package/dist/Dialog/Dialog.js +16 -5
  51. package/dist/Dialog/DialogHeader.d.ts +1 -1
  52. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  53. package/dist/Dialog/DialogHeader.js +7 -7
  54. package/dist/Divider/Divider.d.ts +1 -0
  55. package/dist/Divider/Divider.d.ts.map +1 -1
  56. package/dist/Divider/Divider.js +5 -4
  57. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  58. package/dist/DropdownMenu/DropdownMenu.js +161 -65
  59. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +7 -5
  60. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  61. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +12 -5
  62. package/dist/Field/InputClearButton.d.ts +8 -4
  63. package/dist/Field/InputClearButton.d.ts.map +1 -1
  64. package/dist/Field/InputClearButton.js +23 -7
  65. package/dist/FormLayout/FormLayout.d.ts.map +1 -1
  66. package/dist/FormLayout/FormLayout.js +1 -0
  67. package/dist/Grid/Grid.d.ts +13 -4
  68. package/dist/Grid/Grid.d.ts.map +1 -1
  69. package/dist/Grid/Grid.js +7 -1
  70. package/dist/HoverCard/useHoverCard.d.ts +1 -1
  71. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  72. package/dist/HoverCard/useHoverCard.js +67 -49
  73. package/dist/InputGroup/InputGroup.d.ts +2 -4
  74. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  75. package/dist/InputGroup/InputGroup.js +2 -4
  76. package/dist/InputGroup/groupStyles.d.ts +10 -2
  77. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  78. package/dist/InputGroup/groupStyles.js +19 -2
  79. package/dist/Layer/useLayerDismissal.d.ts +9 -9
  80. package/dist/Layer/useLayerDismissal.js +9 -9
  81. package/dist/Markdown/Markdown.d.ts.map +1 -1
  82. package/dist/Markdown/Markdown.js +25 -4
  83. package/dist/MobileNav/MobileNav.d.ts +7 -0
  84. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  85. package/dist/MobileNav/MobileNav.js +45 -2
  86. package/dist/MultiSelector/MultiSelector.d.ts +7 -4
  87. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  88. package/dist/MultiSelector/MultiSelector.js +24 -3
  89. package/dist/NumberInput/NumberInput.js +1 -1
  90. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  91. package/dist/PowerSearch/PowerSearchEditPopover.js +6 -0
  92. package/dist/Resizable/ResizeHandle.d.ts +1 -1
  93. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  94. package/dist/Resizable/ResizeHandle.js +83 -15
  95. package/dist/Resizable/useResizable.d.ts +23 -0
  96. package/dist/Resizable/useResizable.d.ts.map +1 -1
  97. package/dist/Resizable/useResizable.js +78 -0
  98. package/dist/Selector/Selector.d.ts +6 -3
  99. package/dist/Selector/Selector.d.ts.map +1 -1
  100. package/dist/Selector/Selector.js +28 -6
  101. package/dist/SideNav/SideNav.d.ts.map +1 -1
  102. package/dist/SideNav/SideNav.js +10 -2
  103. package/dist/Slider/Slider.d.ts.map +1 -1
  104. package/dist/Slider/Slider.js +18 -7
  105. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  106. package/dist/Tokenizer/Tokenizer.js +16 -4
  107. package/dist/Toolbar/Toolbar.d.ts +2 -1
  108. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  109. package/dist/Toolbar/Toolbar.js +3 -1
  110. package/dist/TreeList/TreeList.d.ts.map +1 -1
  111. package/dist/TreeList/TreeList.js +6 -3
  112. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  113. package/dist/TreeList/TreeListItem.js +7 -1
  114. package/dist/astryx.css +22 -0
  115. package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
  116. package/dist/hooks/useScrollOverflow.js +55 -12
  117. package/dist/hooks/useTreeFocus.d.ts +21 -0
  118. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  119. package/dist/hooks/useTreeFocus.js +40 -2
  120. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  121. package/dist/i18n/generated-locales/en.generated.js +3 -0
  122. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  123. package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
  124. package/dist/reset.a11y.chromium.spec.js +6 -1
  125. package/dist/reset.until-found.a11y.browser.spec.d.ts +2 -0
  126. package/dist/reset.until-found.a11y.browser.spec.d.ts.map +1 -0
  127. package/dist/reset.until-found.a11y.browser.spec.js +71 -0
  128. package/dist/theme/syntax/SyntaxTheme.d.ts.map +1 -1
  129. package/dist/theme/syntax/SyntaxTheme.js +43 -2
  130. package/dist/theme/syntax/defineSyntaxTheme.d.ts +18 -5
  131. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  132. package/dist/theme/syntax/defineSyntaxTheme.js +38 -9
  133. package/dist/theme/syntax/index.d.ts +1 -1
  134. package/dist/theme/syntax/index.d.ts.map +1 -1
  135. package/dist/theme/syntax/tokens.d.ts +12 -2
  136. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  137. package/dist/theme/syntax/tokens.js +25 -4
  138. package/dist/utils/plainDate.d.ts +12 -0
  139. package/dist/utils/plainDate.d.ts.map +1 -1
  140. package/dist/utils/plainDate.js +63 -10
  141. package/locales/en.json +13 -1
  142. package/locales/pseudo.json +9 -0
  143. package/package.json +4 -4
  144. package/src/AlertDialog/AlertDialog.doc.mjs +6 -0
  145. package/src/AlertDialog/AlertDialog.spec.md +205 -0
  146. package/src/AlertDialog/AlertDialog.test.tsx +3 -14
  147. package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +115 -0
  148. package/src/AlertDialog/__tests__/AlertDialog.a11y.renders.tsx +52 -0
  149. package/src/AlertDialog/__tests__/AlertDialog.a11y.states.ts +68 -0
  150. package/src/AlertDialog/__tests__/AlertDialog.a11y.test.tsx +144 -0
  151. package/src/Button/Button.test.tsx +37 -0
  152. package/src/Button/Button.tsx +5 -1
  153. package/src/Calendar/Calendar.doc.mjs +234 -60
  154. package/src/Calendar/Calendar.spec.md +209 -0
  155. package/src/Calendar/Calendar.test.tsx +559 -20
  156. package/src/Calendar/Calendar.tsx +258 -41
  157. package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +126 -0
  158. package/src/Calendar/__tests__/Calendar.a11y.known-failures.ts +12 -0
  159. package/src/Calendar/__tests__/Calendar.a11y.renders.tsx +57 -0
  160. package/src/Calendar/__tests__/Calendar.a11y.states.ts +139 -0
  161. package/src/Calendar/__tests__/Calendar.a11y.test.tsx +137 -0
  162. package/src/Carousel/Carousel.test.tsx +54 -71
  163. package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +192 -0
  164. package/src/Carousel/__tests__/Carousel.a11y.known-failures.ts +27 -0
  165. package/src/Carousel/__tests__/Carousel.a11y.renders.tsx +39 -0
  166. package/src/Carousel/__tests__/Carousel.a11y.states.ts +139 -0
  167. package/src/Carousel/__tests__/Carousel.a11y.test.tsx +127 -0
  168. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  169. package/src/Chat/ChatComposerInput.spec.md +94 -55
  170. package/src/Chat/ChatComposerInput.test.tsx +202 -1
  171. package/src/Chat/ChatComposerInput.tsx +13 -0
  172. package/src/Chat/ChatMessage.doc.mjs +31 -16
  173. package/src/Chat/ChatMessage.spec.md +265 -0
  174. package/src/Chat/ChatMessage.test.tsx +246 -0
  175. package/src/Chat/ChatMessage.tsx +30 -7
  176. package/src/Chat/ChatSystemMessage.spec.md +36 -37
  177. package/src/Chat/ChatSystemMessage.test.tsx +4 -4
  178. package/src/Chat/useTriggerMenu.test.tsx +994 -0
  179. package/src/Chat/useTriggerMenu.tsx +278 -46
  180. package/src/CodeBlock/CodeBlock.doc.mjs +7 -0
  181. package/src/CodeBlock/CodeBlock.spec.md +40 -41
  182. package/src/CodeBlock/CodeBlock.test.tsx +89 -9
  183. package/src/CodeBlock/CodeBlock.tsx +205 -25
  184. package/src/CodeBlock/__tests__/CodeBlockOverflowStop.a11y.chromium.spec.ts +125 -0
  185. package/src/CodeBlock/__tests__/DiffRowPaint.a11y.chromium.spec.ts +93 -0
  186. package/src/CodeBlock/tokenizer.test.ts +112 -0
  187. package/src/CodeBlock/tokenizer.ts +106 -0
  188. package/src/Collapsible/CollapsibleGroup.spec.md +17 -8
  189. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.renders.tsx +45 -0
  190. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.states.ts +139 -0
  191. package/src/Collapsible/__tests__/CollapsibleGroup.a11y.test.tsx +135 -0
  192. package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +128 -0
  193. package/src/CommandPalette/CommandPalette.doc.mjs +126 -23
  194. package/src/CommandPalette/CommandPalette.spec.md +100 -49
  195. package/src/CommandPalette/CommandPalette.test.tsx +241 -2
  196. package/src/CommandPalette/CommandPalette.tsx +47 -21
  197. package/src/CommandPalette/CommandPaletteEmpty.tsx +4 -3
  198. package/src/CommandPalette/CommandPaletteInput.doc.mjs +61 -4
  199. package/src/CommandPalette/CommandPaletteInput.spec.md +215 -0
  200. package/src/CommandPalette/CommandPaletteInput.test.tsx +375 -51
  201. package/src/CommandPalette/CommandPaletteInput.tsx +74 -21
  202. package/src/CommandPalette/CommandPaletteItem.doc.mjs +73 -22
  203. package/src/CommandPalette/CommandPaletteItem.spec.md +223 -0
  204. package/src/CommandPalette/CommandPaletteItem.test.tsx +200 -5
  205. package/src/CommandPalette/CommandPaletteItem.tsx +16 -11
  206. package/src/CommandPalette/CommandPaletteList.doc.mjs +3 -3
  207. package/src/CommandPalette/CommandPaletteList.spec.md +41 -36
  208. package/src/CommandPalette/CommandPaletteList.test.tsx +80 -0
  209. package/src/CommandPalette/CommandPaletteList.tsx +10 -5
  210. package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +599 -0
  211. package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -8
  212. package/src/ComplexSelector/ComplexSelector.spec.md +14 -9
  213. package/src/ComplexSelector/ComplexSelector.test.tsx +64 -16
  214. package/src/ComplexSelector/ComplexSelector.tsx +37 -8
  215. package/src/ContextMenu/ContextMenu.doc.mjs +6 -0
  216. package/src/ContextMenu/ContextMenu.spec.md +51 -53
  217. package/src/ContextMenu/ContextMenu.test.tsx +132 -1
  218. package/src/ContextMenu/ContextMenu.tsx +78 -48
  219. package/src/DateInput/DateInput.doc.mjs +52 -0
  220. package/src/DateInput/DateInput.spec.md +27 -15
  221. package/src/DateInput/DateInput.test.tsx +38 -0
  222. package/src/DateInput/DateInput.tsx +1 -1
  223. package/src/DateInput/DateInputTouch.test.tsx +22 -0
  224. package/src/DateInput/MonthScroller.tsx +12 -4
  225. package/src/DateRangeInput/DateRangeInput.test.tsx +49 -0
  226. package/src/DateRangeInput/DateRangeInput.tsx +20 -2
  227. package/src/Dialog/Dialog.test.tsx +27 -1
  228. package/src/Dialog/Dialog.tsx +16 -5
  229. package/src/Dialog/DialogHeader.test.tsx +27 -2
  230. package/src/Dialog/DialogHeader.tsx +7 -8
  231. package/src/Dialog/__tests__/Dialog.a11y.chromium.spec.ts +21 -14
  232. package/src/Divider/Divider.doc.mjs +5 -3
  233. package/src/Divider/Divider.spec.md +140 -54
  234. package/src/Divider/Divider.test.tsx +15 -0
  235. package/src/Divider/Divider.tsx +6 -4
  236. package/src/DropdownMenu/DropdownMenu.doc.mjs +2 -2
  237. package/src/DropdownMenu/DropdownMenu.spec.md +121 -45
  238. package/src/DropdownMenu/DropdownMenu.test.tsx +288 -23
  239. package/src/DropdownMenu/DropdownMenu.tsx +212 -81
  240. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +38 -2
  241. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +32 -18
  242. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +146 -1
  243. package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +136 -0
  244. package/src/DropdownMenu/__tests__/MenuButton.a11y.known-failures.ts +12 -0
  245. package/src/DropdownMenu/__tests__/MenuButton.a11y.renders.tsx +67 -0
  246. package/src/DropdownMenu/__tests__/MenuButton.a11y.states.ts +141 -0
  247. package/src/DropdownMenu/__tests__/MenuButton.a11y.test.tsx +138 -0
  248. package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +40 -5
  249. package/src/Field/InputClearButton.test.tsx +29 -4
  250. package/src/Field/InputClearButton.tsx +26 -8
  251. package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +21 -14
  252. package/src/FormLayout/FormLayout.tsx +1 -0
  253. package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +1 -1
  254. package/src/Grid/Grid.doc.mjs +14 -11
  255. package/src/Grid/Grid.spec.md +50 -32
  256. package/src/Grid/Grid.tsx +13 -4
  257. package/src/HoverCard/HoverCard.test.tsx +46 -1
  258. package/src/HoverCard/useHoverCard.tsx +68 -48
  259. package/src/InputGroup/InputGroup.doc.mjs +11 -1
  260. package/src/InputGroup/InputGroup.tsx +2 -4
  261. package/src/InputGroup/groupStyles.ts +40 -2
  262. package/src/Layer/useLayerDismissal.ts +9 -9
  263. package/src/Link/__tests__/Link.a11y.chromium.spec.ts +142 -0
  264. package/src/Link/__tests__/Link.a11y.renders.tsx +97 -0
  265. package/src/Link/__tests__/Link.a11y.states.ts +104 -0
  266. package/src/Link/__tests__/Link.a11y.test.tsx +127 -0
  267. package/src/Markdown/Markdown.doc.mjs +1 -1
  268. package/src/Markdown/Markdown.fr23.perf.test.ts +161 -40
  269. package/src/Markdown/Markdown.spec.md +45 -23
  270. package/src/Markdown/Markdown.test.tsx +38 -0
  271. package/src/Markdown/Markdown.tsx +24 -2
  272. package/src/Markdown/plugins/semanticFence.test.tsx +3 -2
  273. package/src/MobileNav/MobileNav.tsx +50 -2
  274. package/src/MobileNav/MobileNavFocus.test.tsx +553 -0
  275. package/src/MoreMenu/MoreMenu.spec.md +18 -7
  276. package/src/MoreMenu/MoreMenu.test.tsx +38 -0
  277. package/src/MultiSelector/MultiSelector.doc.mjs +8 -8
  278. package/src/MultiSelector/MultiSelector.spec.md +1 -1
  279. package/src/MultiSelector/MultiSelector.test.tsx +188 -21
  280. package/src/MultiSelector/MultiSelector.tsx +50 -11
  281. package/src/NumberInput/NumberInput.test.tsx +24 -0
  282. package/src/NumberInput/NumberInput.tsx +1 -1
  283. package/src/NumberInput/__tests__/NumberInput.a11y.chromium.spec.ts +22 -15
  284. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +78 -0
  285. package/src/PowerSearch/PowerSearchEditPopover.tsx +6 -0
  286. package/src/Resizable/Resizable.spec.md +41 -9
  287. package/src/Resizable/ResizeHandle.test.tsx +565 -2
  288. package/src/Resizable/ResizeHandle.tsx +126 -21
  289. package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +119 -0
  290. package/src/Resizable/__tests__/ResizeHandle.a11y.known-failures.ts +39 -0
  291. package/src/Resizable/__tests__/ResizeHandle.a11y.renders.tsx +80 -0
  292. package/src/Resizable/__tests__/ResizeHandle.a11y.states.ts +197 -0
  293. package/src/Resizable/__tests__/ResizeHandle.a11y.test.tsx +123 -0
  294. package/src/Resizable/useResizable.ts +95 -0
  295. package/src/Selector/Selector.doc.mjs +7 -6
  296. package/src/Selector/Selector.spec.md +37 -24
  297. package/src/Selector/Selector.test.tsx +176 -10
  298. package/src/Selector/Selector.tsx +59 -14
  299. package/src/Selector/__tests__/Combobox.a11y.known-failures.ts +27 -0
  300. package/src/Selector/__tests__/Combobox.a11y.states.ts +145 -0
  301. package/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts +108 -0
  302. package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +126 -0
  303. package/src/SideNav/SideNav.test.tsx +35 -0
  304. package/src/SideNav/SideNav.tsx +16 -2
  305. package/src/Slider/Slider.spec.md +43 -17
  306. package/src/Slider/Slider.test.tsx +134 -0
  307. package/src/Slider/Slider.tsx +29 -6
  308. package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +112 -0
  309. package/src/Slider/__tests__/Slider.a11y.known-failures.ts +12 -0
  310. package/src/Slider/__tests__/Slider.a11y.renders.tsx +42 -0
  311. package/src/Slider/__tests__/Slider.a11y.states.ts +106 -0
  312. package/src/Slider/__tests__/Slider.a11y.test.tsx +105 -0
  313. package/src/Switch/__tests__/Switch.a11y.chromium.spec.ts +25 -18
  314. package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +19 -12
  315. package/src/TextInput/__tests__/TextInput.a11y.chromium.spec.ts +21 -14
  316. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +18 -11
  317. package/src/Tokenizer/Tokenizer.test.tsx +87 -0
  318. package/src/Tokenizer/Tokenizer.tsx +31 -3
  319. package/src/Toolbar/Toolbar.test.tsx +131 -4
  320. package/src/Toolbar/Toolbar.tsx +3 -1
  321. package/src/TreeList/TreeList.spec.md +33 -8
  322. package/src/TreeList/TreeList.test.tsx +72 -0
  323. package/src/TreeList/TreeList.tsx +10 -6
  324. package/src/TreeList/TreeListItem.tsx +5 -0
  325. package/src/TreeList/__tests__/TreeList.a11y.chromium.spec.ts +125 -0
  326. package/src/TreeList/__tests__/TreeList.a11y.renders.tsx +44 -0
  327. package/src/TreeList/__tests__/TreeList.a11y.states.ts +164 -0
  328. package/src/TreeList/__tests__/TreeList.a11y.test.tsx +138 -0
  329. package/src/TreeList/__tests__/TreeListRowNames.a11y.chromium.spec.ts +82 -0
  330. package/src/hooks/useScrollOverflow.test.tsx +222 -0
  331. package/src/hooks/useScrollOverflow.ts +55 -13
  332. package/src/hooks/useTreeFocus.test.tsx +37 -0
  333. package/src/hooks/useTreeFocus.ts +55 -2
  334. package/src/i18n/generated-locales/en.generated.ts +3 -0
  335. package/src/i18n/generated-locales/pseudo.generated.ts +3 -0
  336. package/src/reset.a11y.chromium.spec.ts +9 -1
  337. package/src/reset.css +8 -3
  338. package/src/reset.until-found.a11y.browser.spec.ts +75 -0
  339. package/src/reset.until-found.test.ts +32 -0
  340. package/src/stylexValidation.source-build.test.mjs +42 -0
  341. package/src/theme/syntax/SyntaxTheme.tsx +46 -5
  342. package/src/theme/syntax/defineSyntaxTheme.diff.test.ts +91 -0
  343. package/src/theme/syntax/defineSyntaxTheme.ts +75 -15
  344. package/src/theme/syntax/index.ts +5 -1
  345. package/src/theme/syntax/tokens.ts +32 -2
  346. package/src/theme/syntax/useSyntaxTheme.diff.test.tsx +40 -0
  347. package/src/utils/plainDate.test.ts +147 -0
  348. package/src/utils/plainDate.ts +75 -10
@@ -10,7 +10,9 @@
10
10
  *
11
11
  * Detects trigger characters (@ / etc.) typed inside a contentEditable,
12
12
  * opens a popover at the cursor position with filtered items, handles
13
- * keyboard navigation, and inserts tokens or text on selection.
13
+ * keyboard navigation, and inserts tokens or text on selection. Triggers
14
+ * opt into multi-word queries with hasMultiWordQuery; results apply only
15
+ * while their query is current (component:ChatComposerInput FR10–FR16).
14
16
  *
15
17
  * Reuses SearchSource from Typeahead for async/sync search with
16
18
  * cancel() support and debounce.
@@ -38,7 +40,7 @@ import {
38
40
  typeScaleVars,
39
41
  typographyVars,
40
42
  } from '../theme/tokens.stylex';
41
- import {mergeProps, groupItems} from '../utils';
43
+ import {mergeProps, groupItems, isImeKeyEvent} from '../utils';
42
44
  import type {SearchableItem} from '../Typeahead/types';
43
45
  import {themeProps} from '../utils/themeProps';
44
46
  import {useTranslator} from '../i18n';
@@ -55,6 +57,11 @@ export interface TriggerMenuState {
55
57
  items: SearchableItem[];
56
58
  highlightedIndex: number;
57
59
  isLoading: boolean;
60
+ /**
61
+ * The last settled results were an unmatched multi-word query, so the menu
62
+ * is closed. It stays closed while a newer search for the same query runs.
63
+ */
64
+ isHidden: boolean;
58
65
  }
59
66
 
60
67
  export interface UseTriggerMenuOptions {
@@ -74,7 +81,7 @@ export interface UseTriggerMenuReturn {
74
81
  state: TriggerMenuState;
75
82
  /** Call on every input event to check for trigger activation */
76
83
  handleInput: () => void;
77
- /** Call on keydown \u2014 returns true if the event was consumed */
84
+ /** Call on keydown — returns true if the event was consumed */
78
85
  handleKeyDown: (e: React.KeyboardEvent) => boolean;
79
86
  /** Render the trigger menu popover */
80
87
  renderMenu: () => ReactNode;
@@ -169,6 +176,18 @@ const styles = stylex.create({
169
176
  // Helpers
170
177
  // =============================================================================
171
178
 
179
+ /** The text node holding a collapsed caret inside `editable`, if any. */
180
+ function getCaretTextNode(editable: HTMLDivElement): Node | null {
181
+ const selection = window.getSelection();
182
+ if (!selection || selection.rangeCount === 0) {
183
+ return null;
184
+ }
185
+ const node = selection.getRangeAt(0).startContainer;
186
+ return node.nodeType === Node.TEXT_NODE && editable.contains(node)
187
+ ? node
188
+ : null;
189
+ }
190
+
172
191
  function getTextBeforeCursor(editable: HTMLDivElement): string | null {
173
192
  const selection = window.getSelection();
174
193
  if (!selection || selection.rangeCount === 0) {
@@ -191,6 +210,38 @@ function getTextBeforeCursor(editable: HTMLDivElement): string | null {
191
210
  return null;
192
211
  }
193
212
 
213
+ const MAX_MULTI_WORD_QUERY_LENGTH = 64;
214
+
215
+ /**
216
+ * An unmatched multi-word query hides the menu instead of covering prose with
217
+ * an empty panel, unless the trigger supplies its own empty message.
218
+ */
219
+ function isUnmatchedMultiWordQuery(
220
+ trigger: ChatComposerTrigger | null,
221
+ items: SearchableItem[],
222
+ isLoading: boolean,
223
+ ): boolean {
224
+ return (
225
+ trigger?.hasMultiWordQuery === true &&
226
+ // `null` means "not given", exactly as `undefined` does.
227
+ trigger.emptySearchText == null &&
228
+ items.length === 0 &&
229
+ !isLoading
230
+ );
231
+ }
232
+
233
+ function isTriggerBoundary(char: string | null): boolean {
234
+ return char === null || char === ' ' || char === '\t' || char === '\n';
235
+ }
236
+
237
+ /**
238
+ * Finds the trigger query the caret is in (component:ChatComposerInput FR10,
239
+ * FR11). A trigger character activates at the start of the text or after a
240
+ * space, tab, or line break. A single-token query ends at whitespace. A
241
+ * multi-word query ends at a line break, past the length bound, or where the
242
+ * same trigger's character starts a new query; another trigger's character
243
+ * inside it is ordinary text.
244
+ */
194
245
  function findActiveTrigger(
195
246
  textBeforeCursor: string,
196
247
  triggers: ChatComposerTrigger[],
@@ -199,25 +250,50 @@ function findActiveTrigger(
199
250
  query: string;
200
251
  triggerStart: number;
201
252
  } | null {
202
- for (let i = textBeforeCursor.length - 1; i >= 0; i--) {
253
+ let active: {trigger: ChatComposerTrigger; triggerStart: number} | null =
254
+ null;
255
+
256
+ for (let i = 0; i < textBeforeCursor.length; i++) {
203
257
  const char = textBeforeCursor[i];
204
258
 
205
- if (char === ' ' || char === '\n') {
206
- return null;
259
+ if (char === '\n') {
260
+ active = null;
261
+ continue;
207
262
  }
208
-
209
- for (const trigger of triggers) {
210
- if (char === trigger.character) {
211
- const prevChar = i > 0 ? textBeforeCursor[i - 1] : null;
212
- if (prevChar === null || prevChar === ' ' || prevChar === '\n') {
213
- const query = textBeforeCursor.slice(i + 1);
214
- return {trigger, query, triggerStart: i};
215
- }
263
+ if (active && !active.trigger.hasMultiWordQuery) {
264
+ if (char === ' ' || char === '\t') {
265
+ active = null;
216
266
  }
267
+ continue;
268
+ }
269
+ if (active && i - active.triggerStart > MAX_MULTI_WORD_QUERY_LENGTH) {
270
+ active = null;
271
+ }
272
+
273
+ if (!isTriggerBoundary(i > 0 ? textBeforeCursor[i - 1] : null)) {
274
+ continue;
275
+ }
276
+ const trigger = triggers.find(t => t.character === char);
277
+ if (!trigger) {
278
+ continue;
217
279
  }
280
+ if (active && trigger.character !== active.trigger.character) {
281
+ continue;
282
+ }
283
+ active = {trigger, triggerStart: i};
218
284
  }
219
285
 
220
- return null;
286
+ if (!active) {
287
+ return null;
288
+ }
289
+ const query = textBeforeCursor.slice(active.triggerStart + 1);
290
+ if (
291
+ active.trigger.hasMultiWordQuery &&
292
+ query.length > MAX_MULTI_WORD_QUERY_LENGTH
293
+ ) {
294
+ return null;
295
+ }
296
+ return {trigger: active.trigger, query, triggerStart: active.triggerStart};
221
297
  }
222
298
 
223
299
  function deleteTriggerText(
@@ -274,11 +350,25 @@ export function useTriggerMenu(
274
350
  items: [],
275
351
  highlightedIndex: 0,
276
352
  isLoading: false,
353
+ isHidden: false,
277
354
  });
278
355
 
279
356
  const triggerStartRef = useRef<number>(-1);
280
357
  const searchTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
358
+ const searchRequestIdRef = useRef<number>(0);
359
+ const dismissedRef = useRef<{
360
+ character: string;
361
+ triggerStart: number;
362
+ dismissedQuery: string;
363
+ // The text the Escape dismissed. Replacing the draft from outside typing
364
+ // (a send button, a cleared value) replaces this node, which ends the
365
+ // dismissal without any extra bookkeeping.
366
+ textNode: Node | null;
367
+ } | null>(null);
281
368
  const anchorSpanRef = useRef<HTMLSpanElement | null>(null);
369
+ // True while the popover is closed only because the query is unmatched; the
370
+ // trigger query itself is still active.
371
+ const isMenuSuppressedRef = useRef(false);
282
372
 
283
373
  const removeAnchorSpan = useCallback(() => {
284
374
  if (anchorSpanRef.current) {
@@ -289,6 +379,10 @@ export function useTriggerMenu(
289
379
 
290
380
  const popover = usePopover({
291
381
  onHide: useCallback(() => {
382
+ if (isMenuSuppressedRef.current) {
383
+ return;
384
+ }
385
+ searchRequestIdRef.current++;
292
386
  removeAnchorSpan();
293
387
  setState(prev => ({
294
388
  ...prev,
@@ -298,6 +392,7 @@ export function useTriggerMenu(
298
392
  items: [],
299
393
  highlightedIndex: 0,
300
394
  isLoading: false,
395
+ isHidden: false,
301
396
  }));
302
397
  }, [removeAnchorSpan]),
303
398
  hasLightDismiss: true,
@@ -307,6 +402,7 @@ export function useTriggerMenu(
307
402
  // the contenteditable composer, so a modal dialog wrapper is incorrect.
308
403
  role: 'none',
309
404
  });
405
+ const {show: showPopover, hide: hidePopover} = popover;
310
406
 
311
407
  // Cleanup on unmount
312
408
  useEffect(() => {
@@ -323,14 +419,29 @@ export function useTriggerMenu(
323
419
  clearTimeout(searchTimeoutRef.current);
324
420
  searchTimeoutRef.current = null;
325
421
  }
422
+ searchRequestIdRef.current++;
326
423
  // Cancel any in-flight search on the active trigger's searchSource
327
424
  const trigger = state.activeTrigger;
328
425
  if (trigger?.searchSource) {
329
426
  trigger.searchSource.cancel?.();
330
427
  }
331
428
  removeAnchorSpan();
429
+ isMenuSuppressedRef.current = false;
430
+ // Ending the query also forgets an Escape on it; a send or clear must not
431
+ // leave the next message's mention at the same offset suppressed.
432
+ dismissedRef.current = null;
332
433
  popover.hide();
333
434
  triggerStartRef.current = -1;
435
+ setState(prev => ({
436
+ ...prev,
437
+ isActive: false,
438
+ activeTrigger: null,
439
+ query: '',
440
+ items: [],
441
+ highlightedIndex: 0,
442
+ isLoading: false,
443
+ isHidden: false,
444
+ }));
334
445
  }, [popover, state.activeTrigger, removeAnchorSpan]);
335
446
 
336
447
  // Anchor the popover to the cursor position (not the entire input).
@@ -395,28 +506,69 @@ export function useTriggerMenu(
395
506
  searchTimeoutRef.current = null;
396
507
  }
397
508
 
509
+ const requestId = ++searchRequestIdRef.current;
510
+ // A result applies only while its request is the latest one and the
511
+ // caret is still inside the same trigger query. Submitting or clearing
512
+ // the editor ends the query without an input event, so check the DOM.
513
+ const isCurrent = () => {
514
+ if (requestId !== searchRequestIdRef.current) {
515
+ return false;
516
+ }
517
+ const editable = editableRef.current;
518
+ const textBefore = editable ? getTextBeforeCursor(editable) : null;
519
+ const found =
520
+ textBefore === null || !triggers
521
+ ? null
522
+ : findActiveTrigger(textBefore, triggers);
523
+ if (
524
+ found?.trigger.character !== trigger.character ||
525
+ found.triggerStart !== triggerStartRef.current
526
+ ) {
527
+ reset();
528
+ return false;
529
+ }
530
+ return true;
531
+ };
532
+
533
+ const applyResults = (items: SearchableItem[]) => {
534
+ const isHidden = isUnmatchedMultiWordQuery(trigger, items, false);
535
+ setState(prev => ({
536
+ ...prev,
537
+ items,
538
+ highlightedIndex: items.length > 0 ? 0 : -1,
539
+ isLoading: false,
540
+ isHidden,
541
+ }));
542
+ // A hidden menu closes its popover, which also releases the popover's
543
+ // Escape and light-dismiss handling; matches reopen it at the caret.
544
+ if (isHidden && !isMenuSuppressedRef.current) {
545
+ isMenuSuppressedRef.current = true;
546
+ hidePopover();
547
+ } else if (!isHidden && isMenuSuppressedRef.current) {
548
+ isMenuSuppressedRef.current = false;
549
+ setAnchor();
550
+ showPopover();
551
+ }
552
+ };
553
+
398
554
  const doSearch = () => {
399
555
  if (trigger.searchSource) {
400
- // Use SearchSource \u2014 cancel previous, then search
556
+ // Use SearchSource — cancel previous, then search
401
557
  trigger.searchSource.cancel?.();
402
558
  setState(prev => ({...prev, isLoading: true}));
403
559
  const result = trigger.searchSource.search(query);
404
560
  Promise.resolve(result).then(
405
561
  items => {
406
- setState(prev => ({
407
- ...prev,
408
- items,
409
- highlightedIndex: items.length > 0 ? 0 : -1,
410
- isLoading: false,
411
- }));
562
+ if (!isCurrent()) {
563
+ return;
564
+ }
565
+ applyResults(items);
412
566
  },
413
567
  () => {
414
- setState(prev => ({
415
- ...prev,
416
- items: [],
417
- highlightedIndex: -1,
418
- isLoading: false,
419
- }));
568
+ if (!isCurrent()) {
569
+ return;
570
+ }
571
+ applyResults([]);
420
572
  },
421
573
  );
422
574
  }
@@ -435,7 +587,15 @@ export function useTriggerMenu(
435
587
  }
436
588
  }
437
589
  },
438
- [debounceMs],
590
+ [
591
+ debounceMs,
592
+ editableRef,
593
+ triggers,
594
+ reset,
595
+ setAnchor,
596
+ hidePopover,
597
+ showPopover,
598
+ ],
439
599
  );
440
600
 
441
601
  const selectItem = useCallback(
@@ -490,6 +650,7 @@ export function useTriggerMenu(
490
650
 
491
651
  const textBefore = getTextBeforeCursor(editable);
492
652
  if (textBefore === null) {
653
+ dismissedRef.current = null;
493
654
  if (state.isActive) {
494
655
  reset();
495
656
  }
@@ -498,6 +659,7 @@ export function useTriggerMenu(
498
659
 
499
660
  const found = findActiveTrigger(textBefore, triggers);
500
661
  if (!found) {
662
+ dismissedRef.current = null;
501
663
  if (state.isActive) {
502
664
  reset();
503
665
  }
@@ -506,20 +668,44 @@ export function useTriggerMenu(
506
668
 
507
669
  const {trigger, query, triggerStart} = found;
508
670
 
509
- if (!state.isActive || state.activeTrigger !== trigger) {
671
+ // After Escape, keep the menu hidden while that same query keeps growing
672
+ const dismissed = dismissedRef.current;
673
+ if (
674
+ dismissed &&
675
+ dismissed.character === trigger.character &&
676
+ dismissed.triggerStart === triggerStart &&
677
+ dismissed.textNode !== null &&
678
+ dismissed.textNode.isConnected &&
679
+ dismissed.textNode === getCaretTextNode(editable)
680
+ ) {
681
+ if (query.startsWith(dismissed.dismissedQuery)) {
682
+ return;
683
+ }
684
+ dismissedRef.current = null;
685
+ } else {
686
+ dismissedRef.current = null;
687
+ }
688
+
689
+ if (
690
+ !state.isActive ||
691
+ state.activeTrigger?.character !== trigger.character ||
692
+ triggerStartRef.current !== triggerStart
693
+ ) {
510
694
  triggerStartRef.current = triggerStart;
695
+ isMenuSuppressedRef.current = false;
511
696
  setState(prev => ({
512
697
  ...prev,
513
698
  isActive: true,
514
699
  activeTrigger: trigger,
515
700
  query,
516
701
  highlightedIndex: 0,
702
+ isHidden: false,
517
703
  }));
518
704
  setAnchor();
519
705
  searchItems(trigger, query);
520
706
  popover.show();
521
707
  } else if (state.query !== query) {
522
- setState(prev => ({...prev, query}));
708
+ setState(prev => ({...prev, query, activeTrigger: trigger}));
523
709
  searchItems(trigger, query);
524
710
  }
525
711
  }, [
@@ -534,9 +720,49 @@ export function useTriggerMenu(
534
720
  popover,
535
721
  ]);
536
722
 
723
+ const isMenuVisible = state.isActive && !state.isHidden;
724
+
537
725
  const handleKeyDown = useCallback(
538
726
  (e: React.KeyboardEvent): boolean => {
539
- if (!state.isActive || !popover.isOpen) {
727
+ // Never intercept IME composition keystrokes (e.g. Enter committing candidates)
728
+ if (isImeKeyEvent(e.nativeEvent)) {
729
+ return false;
730
+ }
731
+
732
+ // A hidden menu consumes nothing: arrows move the caret, Enter submits,
733
+ // and Escape reaches the surrounding surface.
734
+ if (!isMenuVisible) {
735
+ return false;
736
+ }
737
+
738
+ if (e.key === 'Escape') {
739
+ e.preventDefault();
740
+ const editable = editableRef.current;
741
+ const dismissed = state.activeTrigger
742
+ ? {
743
+ character: state.activeTrigger.character,
744
+ triggerStart: triggerStartRef.current,
745
+ dismissedQuery: state.query,
746
+ textNode: editable ? getCaretTextNode(editable) : null,
747
+ }
748
+ : null;
749
+ reset();
750
+ // Remembered after reset, which clears it: the menu stays hidden while
751
+ // this same query keeps growing.
752
+ dismissedRef.current = dismissed;
753
+ return true;
754
+ }
755
+
756
+ // A visible menu keeps the arrows even when it has nothing to pick (rows
757
+ // still loading, or the empty message), so they never recall history
758
+ // under an open panel. Enter and Tab pick only a settled row; otherwise
759
+ // they keep their editor meaning, so Enter sends the message as typed.
760
+ const hasPickableRows = !state.isLoading && state.items.length > 0;
761
+ if (!hasPickableRows && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
762
+ e.preventDefault();
763
+ return true;
764
+ }
765
+ if (!hasPickableRows) {
540
766
  return false;
541
767
  }
542
768
 
@@ -575,20 +801,18 @@ export function useTriggerMenu(
575
801
  }
576
802
  return false;
577
803
  }
578
- case 'Escape': {
579
- e.preventDefault();
580
- reset();
581
- return true;
582
- }
583
804
  default:
584
805
  return false;
585
806
  }
586
807
  },
587
808
  [
588
- state.isActive,
809
+ isMenuVisible,
810
+ editableRef,
811
+ state.activeTrigger,
812
+ state.query,
813
+ state.isLoading,
589
814
  state.highlightedIndex,
590
815
  state.items,
591
- popover.isOpen,
592
816
  selectItem,
593
817
  reset,
594
818
  ],
@@ -621,7 +845,7 @@ export function useTriggerMenu(
621
845
  const hasTriggers = (triggers?.length ?? 0) > 0;
622
846
  const ariaProps: UseTriggerMenuReturn['ariaProps'] = !hasTriggers
623
847
  ? {role: 'textbox', 'aria-multiline': 'true'}
624
- : state.isActive && popover.isOpen
848
+ : isMenuVisible
625
849
  ? {
626
850
  role: 'combobox',
627
851
  'aria-expanded': true as const,
@@ -639,9 +863,17 @@ export function useTriggerMenu(
639
863
  };
640
864
 
641
865
  const renderMenu = useCallback((): ReactNode => {
642
- const trigger = state.activeTrigger;
643
- const emptyText = trigger?.emptySearchText ?? 'No results';
644
- const loadingText = trigger?.loadingText ?? 'Searching\u2026';
866
+ const activeTrigger = state.activeTrigger;
867
+ if (!activeTrigger) {
868
+ return null;
869
+ }
870
+
871
+ if (state.isHidden) {
872
+ return null;
873
+ }
874
+
875
+ const emptyText = activeTrigger.emptySearchText ?? 'No results';
876
+ const loadingText = activeTrigger.loadingText ?? 'Searching\u2026';
645
877
 
646
878
  let listContent: ReactNode;
647
879
  if (state.isLoading) {
@@ -674,8 +906,8 @@ export function useTriggerMenu(
674
906
  styles.item,
675
907
  idx === state.highlightedIndex && styles.itemHighlighted,
676
908
  )}>
677
- {trigger?.renderItem ? (
678
- trigger.renderItem(item)
909
+ {activeTrigger.renderItem ? (
910
+ activeTrigger.renderItem(item)
679
911
  ) : (
680
912
  <span {...stylex.props(styles.itemLabel)}>{item.label}</span>
681
913
  )}
@@ -704,7 +936,7 @@ export function useTriggerMenu(
704
936
  id={listboxId}
705
937
  role="listbox"
706
938
  aria-label={
707
- trigger?.menuLabel ?? t('@astryx.chatTriggerMenu.suggestions')
939
+ activeTrigger.menuLabel ?? t('@astryx.chatTriggerMenu.suggestions')
708
940
  }
709
941
  {...mergeProps(
710
942
  themeProps('trigger-menu'),
@@ -56,6 +56,13 @@ export const docs = {
56
56
  type: 'number[]',
57
57
  description: '1-indexed line numbers to highlight.',
58
58
  },
59
+ {
60
+ name: 'isDiff',
61
+ type: 'boolean',
62
+ default: 'false',
63
+ description:
64
+ 'Render the code as a unified diff over `language`: lines starting with + are added, - removed, @@ is a hunk header (a `--- `/`+++ ` file-header pair directly before one is a header too), anything else is context. The language label reads `diff` or `<language> diff`. The glyph sits in its own column and the rest of each line keeps syntax highlighting; copy returns the exact source. Markdown ```diff and ```diff-<lang> fences set this.',
65
+ },
59
66
  {
60
67
  name: 'hasCopyButton',
61
68
  type: 'boolean',