@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
@@ -1 +1 @@
1
- {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/Chat/ChatMessage.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAQrD,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC9D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AAoFD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,MAAM,EACN,SAAS,EACT,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,GAAG,IAAI,EACR,EAAE,gBAAgB,+BA2FlB;yBAxGe,WAAW"}
1
+ {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/Chat/ChatMessage.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAiB,MAAM,OAAO,CAAC;AAQrD,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAI5C,MAAM,WAAW,gBAAiB,SAAQ,SAAS,CAAC,WAAW,CAAC;IAC9D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IAC7B,MAAM,EAAE,iBAAiB,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,EAAE,SAAS,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,CAAC,EAAE,WAAW,CAAC;CACvB;AA4FD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,EACR,MAAM,EACN,IAAI,EACJ,QAAQ,EACR,OAAO,EAAE,WAAW,EACpB,MAAM,EACN,SAAS,EACT,KAAK,EAAE,SAAS,EAChB,aAAa,EAAE,MAAM,EACrB,GAAG,EACH,GAAG,IAAI,EACR,EAAE,gBAAgB,+BA+FlB;yBA5Ge,WAAW"}
@@ -16,6 +16,7 @@
16
16
  * SYNC: When modified, update these files to stay in sync:
17
17
  * - /packages/core/src/Chat/index.ts (exports)
18
18
  * - /apps/storybook/stories/Chat.stories.tsx
19
+ * - /apps/storybook/stories/ChatMessage.stories.tsx
19
20
  * - /packages/cli/assets/templates/blocks/components/ChatMessage/ (block examples)
20
21
  */
21
22
  import { useMemo, useId } from 'react';
@@ -23,7 +24,7 @@ import * as stylex from '@stylexjs/stylex';
23
24
  import "../theme/tokens.stylex.js";
24
25
  import { colorVars, spacingVars, typeScaleVars, fontWeightVars } from "../theme/tokens.stylex.js";
25
26
  import { ChatMessageContext, useChatListContext } from "./ChatContext.js";
26
- import { mergeProps } from "../utils/index.js";
27
+ import { isRenderable, mergeProps } from "../utils/index.js";
27
28
  import { themeProps } from "../utils/themeProps.js";
28
29
  import { useTranslator } from "../i18n/index.js";
29
30
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -155,18 +156,23 @@ export function ChatMessage({
155
156
  const columnAlignment = sender === 'system' ? styles.contentColumnSystem : sender === 'user' ? styles.contentColumnUser : styles.contentColumnAssistant;
156
157
  const childrenAlignment = sender === 'system' ? styles.childrenSystem : sender === 'user' ? styles.childrenUser : styles.childrenAssistant;
157
158
  const isSystem = sender === 'system';
158
- const hasAvatar = avatar != null && !isSystem;
159
- const hasName = name != null && !isSystem;
159
+ const hasAvatar = !isSystem && isRenderable(avatar);
160
+ const hasName = !isSystem && isRenderable(name);
161
+ const hasMetadata = !isSystem && isRenderable(metadata);
160
162
  const nameId = useId();
161
163
  return /*#__PURE__*/_jsx(ChatMessageContext, {
162
164
  value: contextValue,
163
165
  children: /*#__PURE__*/_jsxs("article", {
164
166
  ...rest,
165
167
  ref: ref,
166
- "data-testid": testId,
167
- "aria-label": !hasName ? t('@astryx.chatMessage.messageFrom', {
168
+ "data-testid": testId
169
+ // The visible name labels the article. When it renders no text, the
170
+ // label reference resolves to nothing and the accessible name falls
171
+ // back to aria-label (accessible name computation 1.2, step 2B).
172
+ ,
173
+ "aria-label": t('@astryx.chatMessage.messageFrom', {
168
174
  sender
169
- }) : undefined,
175
+ }),
170
176
  "aria-labelledby": hasName ? nameId : undefined,
171
177
  ...mergeProps(themeProps('chat-message', {
172
178
  sender,
@@ -174,7 +180,7 @@ export function ChatMessage({
174
180
  }), stylex.props(styles.root, rootAlignment, hasAvatar && rootGap, xstyle), className, styleProp),
175
181
  children: [hasAvatar && /*#__PURE__*/_jsx("div", {
176
182
  ...{
177
- className: "x2lah0s x5du68j"
183
+ className: "xjl7jj x2lah0s x5du68j"
178
184
  },
179
185
  children: avatar
180
186
  }), /*#__PURE__*/_jsxs("div", {
@@ -182,13 +188,16 @@ export function ChatMessage({
182
188
  children: [hasName && /*#__PURE__*/_jsx("div", {
183
189
  id: nameId,
184
190
  ...{
185
- className: "x141an7d x2mo6ok xv1l7n4 x1ltkj2j x14cgwvg"
191
+ className: "xjl7jj x141an7d x2mo6ok xv1l7n4 x1ltkj2j x14cgwvg"
186
192
  },
187
193
  children: name
188
194
  }), /*#__PURE__*/_jsx("div", {
189
195
  ...stylex.props(styles.childrenWrap, childrenAlignment, childrenGap),
190
196
  children: children
191
- }), metadata != null && !isSystem && /*#__PURE__*/_jsx("div", {
197
+ }), hasMetadata && /*#__PURE__*/_jsx("div", {
198
+ ...{
199
+ className: "xjl7jj"
200
+ },
192
201
  children: metadata
193
202
  })]
194
203
  })]
@@ -6,7 +6,9 @@
6
6
  *
7
7
  * Detects trigger characters (@ / etc.) typed inside a contentEditable,
8
8
  * opens a popover at the cursor position with filtered items, handles
9
- * keyboard navigation, and inserts tokens or text on selection.
9
+ * keyboard navigation, and inserts tokens or text on selection. Triggers
10
+ * opt into multi-word queries with hasMultiWordQuery; results apply only
11
+ * while their query is current (component:ChatComposerInput FR10–FR16).
10
12
  *
11
13
  * Reuses SearchSource from Typeahead for async/sync search with
12
14
  * cancel() support and debounce.
@@ -25,6 +27,11 @@ export interface TriggerMenuState {
25
27
  items: SearchableItem[];
26
28
  highlightedIndex: number;
27
29
  isLoading: boolean;
30
+ /**
31
+ * The last settled results were an unmatched multi-word query, so the menu
32
+ * is closed. It stays closed while a newer search for the same query runs.
33
+ */
34
+ isHidden: boolean;
28
35
  }
29
36
  export interface UseTriggerMenuOptions {
30
37
  triggers?: ChatComposerTrigger[];
@@ -42,7 +49,7 @@ export interface UseTriggerMenuReturn {
42
49
  state: TriggerMenuState;
43
50
  /** Call on every input event to check for trigger activation */
44
51
  handleInput: () => void;
45
- /** Call on keydown \u2014 returns true if the event was consumed */
52
+ /** Call on keydown — returns true if the event was consumed */
46
53
  handleKeyDown: (e: React.KeyboardEvent) => boolean;
47
54
  /** Render the trigger menu popover */
48
55
  renderMenu: () => ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"useTriggerMenu.d.ts","sourceRoot":"","sources":["../../src/Chat/useTriggerMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGvD,OAAO,KAAK,EAAC,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,qBAAqB,CAAC;AAMhF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACpD,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,gBAAgB,CAAC;IACxB,gEAAgE;IAChE,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,oEAAoE;IACpE,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,OAAO,CAAC;IACnD,sCAAsC;IACtC,UAAU,EAAE,MAAM,SAAS,CAAC;IAC5B,mCAAmC;IACnC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;;;;OAKG;IACH,SAAS,EAAE;QACT,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;QAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC,eAAe,CAAC,EAAE,SAAS,CAAC;KAC7B,CAAC;CACH;AA+JD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CA0dtB"}
1
+ {"version":3,"file":"useTriggerMenu.d.ts","sourceRoot":"","sources":["../../src/Chat/useTriggerMenu.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGvD,OAAO,KAAK,EAAC,mBAAmB,EAAE,iBAAiB,EAAC,MAAM,qBAAqB,CAAC;AAMhF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IACpD,aAAa,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAClD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,gBAAgB,CAAC;IACxB,gEAAgE;IAChE,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,+DAA+D;IAC/D,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,OAAO,CAAC;IACnD,sCAAsC;IACtC,UAAU,EAAE,MAAM,SAAS,CAAC;IAC5B,mCAAmC;IACnC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB;;;;;OAKG;IACH,SAAS,EAAE;QACT,IAAI,EAAE,UAAU,GAAG,SAAS,CAAC;QAC7B,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,uBAAuB,CAAC,EAAE,MAAM,CAAC;QACjC,eAAe,CAAC,EAAE,SAAS,CAAC;KAC7B,CAAC;CACH;AAoOD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CAsnBtB"}
@@ -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.
@@ -25,7 +27,7 @@ import { usePopover } from "../Popover/usePopover.js";
25
27
  import { useHighlightedOptionScroll } from "../hooks/useHighlightedOptionScroll.js";
26
28
  import "../theme/tokens.stylex.js";
27
29
  import { colorVars, spacingVars, radiusVars, typeScaleVars, typographyVars } from "../theme/tokens.stylex.js";
28
- import { mergeProps, groupItems } from "../utils/index.js";
30
+ import { mergeProps, groupItems, isImeKeyEvent } from "../utils/index.js";
29
31
  import { themeProps } from "../utils/themeProps.js";
30
32
  import { useTranslator } from "../i18n/index.js";
31
33
 
@@ -48,6 +50,15 @@ const styles = {
48
50
  // Helpers
49
51
  // =============================================================================
50
52
 
53
+ /** The text node holding a collapsed caret inside `editable`, if any. */
54
+ function getCaretTextNode(editable) {
55
+ const selection = window.getSelection();
56
+ if (!selection || selection.rangeCount === 0) {
57
+ return null;
58
+ }
59
+ const node = selection.getRangeAt(0).startContainer;
60
+ return node.nodeType === Node.TEXT_NODE && editable.contains(node) ? node : null;
61
+ }
51
62
  function getTextBeforeCursor(editable) {
52
63
  const selection = window.getSelection();
53
64
  if (!selection || selection.rangeCount === 0) {
@@ -66,27 +77,73 @@ function getTextBeforeCursor(editable) {
66
77
  }
67
78
  return null;
68
79
  }
80
+ const MAX_MULTI_WORD_QUERY_LENGTH = 64;
81
+
82
+ /**
83
+ * An unmatched multi-word query hides the menu instead of covering prose with
84
+ * an empty panel, unless the trigger supplies its own empty message.
85
+ */
86
+ function isUnmatchedMultiWordQuery(trigger, items, isLoading) {
87
+ return trigger?.hasMultiWordQuery === true &&
88
+ // `null` means "not given", exactly as `undefined` does.
89
+ trigger.emptySearchText == null && items.length === 0 && !isLoading;
90
+ }
91
+ function isTriggerBoundary(char) {
92
+ return char === null || char === ' ' || char === '\t' || char === '\n';
93
+ }
94
+
95
+ /**
96
+ * Finds the trigger query the caret is in (component:ChatComposerInput FR10,
97
+ * FR11). A trigger character activates at the start of the text or after a
98
+ * space, tab, or line break. A single-token query ends at whitespace. A
99
+ * multi-word query ends at a line break, past the length bound, or where the
100
+ * same trigger's character starts a new query; another trigger's character
101
+ * inside it is ordinary text.
102
+ */
69
103
  function findActiveTrigger(textBeforeCursor, triggers) {
70
- for (let i = textBeforeCursor.length - 1; i >= 0; i--) {
104
+ let active = null;
105
+ for (let i = 0; i < textBeforeCursor.length; i++) {
71
106
  const char = textBeforeCursor[i];
72
- if (char === ' ' || char === '\n') {
73
- return null;
107
+ if (char === '\n') {
108
+ active = null;
109
+ continue;
74
110
  }
75
- for (const trigger of triggers) {
76
- if (char === trigger.character) {
77
- const prevChar = i > 0 ? textBeforeCursor[i - 1] : null;
78
- if (prevChar === null || prevChar === ' ' || prevChar === '\n') {
79
- const query = textBeforeCursor.slice(i + 1);
80
- return {
81
- trigger,
82
- query,
83
- triggerStart: i
84
- };
85
- }
111
+ if (active && !active.trigger.hasMultiWordQuery) {
112
+ if (char === ' ' || char === '\t') {
113
+ active = null;
86
114
  }
115
+ continue;
116
+ }
117
+ if (active && i - active.triggerStart > MAX_MULTI_WORD_QUERY_LENGTH) {
118
+ active = null;
119
+ }
120
+ if (!isTriggerBoundary(i > 0 ? textBeforeCursor[i - 1] : null)) {
121
+ continue;
122
+ }
123
+ const trigger = triggers.find(t => t.character === char);
124
+ if (!trigger) {
125
+ continue;
87
126
  }
127
+ if (active && trigger.character !== active.trigger.character) {
128
+ continue;
129
+ }
130
+ active = {
131
+ trigger,
132
+ triggerStart: i
133
+ };
88
134
  }
89
- return null;
135
+ if (!active) {
136
+ return null;
137
+ }
138
+ const query = textBeforeCursor.slice(active.triggerStart + 1);
139
+ if (active.trigger.hasMultiWordQuery && query.length > MAX_MULTI_WORD_QUERY_LENGTH) {
140
+ return null;
141
+ }
142
+ return {
143
+ trigger: active.trigger,
144
+ query,
145
+ triggerStart: active.triggerStart
146
+ };
90
147
  }
91
148
  function deleteTriggerText(editable, triggerStart) {
92
149
  const selection = window.getSelection();
@@ -131,11 +188,17 @@ export function useTriggerMenu(options) {
131
188
  query: '',
132
189
  items: [],
133
190
  highlightedIndex: 0,
134
- isLoading: false
191
+ isLoading: false,
192
+ isHidden: false
135
193
  });
136
194
  const triggerStartRef = useRef(-1);
137
195
  const searchTimeoutRef = useRef(null);
196
+ const searchRequestIdRef = useRef(0);
197
+ const dismissedRef = useRef(null);
138
198
  const anchorSpanRef = useRef(null);
199
+ // True while the popover is closed only because the query is unmatched; the
200
+ // trigger query itself is still active.
201
+ const isMenuSuppressedRef = useRef(false);
139
202
  const removeAnchorSpan = useCallback(() => {
140
203
  if (anchorSpanRef.current) {
141
204
  anchorSpanRef.current.remove();
@@ -144,6 +207,10 @@ export function useTriggerMenu(options) {
144
207
  }, []);
145
208
  const popover = usePopover({
146
209
  onHide: useCallback(() => {
210
+ if (isMenuSuppressedRef.current) {
211
+ return;
212
+ }
213
+ searchRequestIdRef.current++;
147
214
  removeAnchorSpan();
148
215
  setState(prev => ({
149
216
  ...prev,
@@ -152,7 +219,8 @@ export function useTriggerMenu(options) {
152
219
  query: '',
153
220
  items: [],
154
221
  highlightedIndex: 0,
155
- isLoading: false
222
+ isLoading: false,
223
+ isHidden: false
156
224
  }));
157
225
  }, [removeAnchorSpan]),
158
226
  hasLightDismiss: true,
@@ -162,6 +230,10 @@ export function useTriggerMenu(options) {
162
230
  // the contenteditable composer, so a modal dialog wrapper is incorrect.
163
231
  role: 'none'
164
232
  });
233
+ const {
234
+ show: showPopover,
235
+ hide: hidePopover
236
+ } = popover;
165
237
 
166
238
  // Cleanup on unmount
167
239
  useEffect(() => {
@@ -177,14 +249,29 @@ export function useTriggerMenu(options) {
177
249
  clearTimeout(searchTimeoutRef.current);
178
250
  searchTimeoutRef.current = null;
179
251
  }
252
+ searchRequestIdRef.current++;
180
253
  // Cancel any in-flight search on the active trigger's searchSource
181
254
  const trigger = state.activeTrigger;
182
255
  if (trigger?.searchSource) {
183
256
  trigger.searchSource.cancel?.();
184
257
  }
185
258
  removeAnchorSpan();
259
+ isMenuSuppressedRef.current = false;
260
+ // Ending the query also forgets an Escape on it; a send or clear must not
261
+ // leave the next message's mention at the same offset suppressed.
262
+ dismissedRef.current = null;
186
263
  popover.hide();
187
264
  triggerStartRef.current = -1;
265
+ setState(prev => ({
266
+ ...prev,
267
+ isActive: false,
268
+ activeTrigger: null,
269
+ query: '',
270
+ items: [],
271
+ highlightedIndex: 0,
272
+ isLoading: false,
273
+ isHidden: false
274
+ }));
188
275
  }, [popover, state.activeTrigger, removeAnchorSpan]);
189
276
 
190
277
  // Anchor the popover to the cursor position (not the entire input).
@@ -232,9 +319,46 @@ export function useTriggerMenu(options) {
232
319
  clearTimeout(searchTimeoutRef.current);
233
320
  searchTimeoutRef.current = null;
234
321
  }
322
+ const requestId = ++searchRequestIdRef.current;
323
+ // A result applies only while its request is the latest one and the
324
+ // caret is still inside the same trigger query. Submitting or clearing
325
+ // the editor ends the query without an input event, so check the DOM.
326
+ const isCurrent = () => {
327
+ if (requestId !== searchRequestIdRef.current) {
328
+ return false;
329
+ }
330
+ const editable = editableRef.current;
331
+ const textBefore = editable ? getTextBeforeCursor(editable) : null;
332
+ const found = textBefore === null || !triggers ? null : findActiveTrigger(textBefore, triggers);
333
+ if (found?.trigger.character !== trigger.character || found.triggerStart !== triggerStartRef.current) {
334
+ reset();
335
+ return false;
336
+ }
337
+ return true;
338
+ };
339
+ const applyResults = items => {
340
+ const isHidden = isUnmatchedMultiWordQuery(trigger, items, false);
341
+ setState(prev => ({
342
+ ...prev,
343
+ items,
344
+ highlightedIndex: items.length > 0 ? 0 : -1,
345
+ isLoading: false,
346
+ isHidden
347
+ }));
348
+ // A hidden menu closes its popover, which also releases the popover's
349
+ // Escape and light-dismiss handling; matches reopen it at the caret.
350
+ if (isHidden && !isMenuSuppressedRef.current) {
351
+ isMenuSuppressedRef.current = true;
352
+ hidePopover();
353
+ } else if (!isHidden && isMenuSuppressedRef.current) {
354
+ isMenuSuppressedRef.current = false;
355
+ setAnchor();
356
+ showPopover();
357
+ }
358
+ };
235
359
  const doSearch = () => {
236
360
  if (trigger.searchSource) {
237
- // Use SearchSource \u2014 cancel previous, then search
361
+ // Use SearchSource — cancel previous, then search
238
362
  trigger.searchSource.cancel?.();
239
363
  setState(prev => ({
240
364
  ...prev,
@@ -242,19 +366,15 @@ export function useTriggerMenu(options) {
242
366
  }));
243
367
  const result = trigger.searchSource.search(query);
244
368
  Promise.resolve(result).then(items => {
245
- setState(prev => ({
246
- ...prev,
247
- items,
248
- highlightedIndex: items.length > 0 ? 0 : -1,
249
- isLoading: false
250
- }));
369
+ if (!isCurrent()) {
370
+ return;
371
+ }
372
+ applyResults(items);
251
373
  }, () => {
252
- setState(prev => ({
253
- ...prev,
254
- items: [],
255
- highlightedIndex: -1,
256
- isLoading: false
257
- }));
374
+ if (!isCurrent()) {
375
+ return;
376
+ }
377
+ applyResults([]);
258
378
  });
259
379
  }
260
380
  };
@@ -274,7 +394,7 @@ export function useTriggerMenu(options) {
274
394
  doSearch();
275
395
  }
276
396
  }
277
- }, [debounceMs]);
397
+ }, [debounceMs, editableRef, triggers, reset, setAnchor, hidePopover, showPopover]);
278
398
  const selectItem = useCallback(item => {
279
399
  const trigger = state.activeTrigger;
280
400
  if (!trigger) {
@@ -309,6 +429,7 @@ export function useTriggerMenu(options) {
309
429
  }
310
430
  const textBefore = getTextBeforeCursor(editable);
311
431
  if (textBefore === null) {
432
+ dismissedRef.current = null;
312
433
  if (state.isActive) {
313
434
  reset();
314
435
  }
@@ -316,6 +437,7 @@ export function useTriggerMenu(options) {
316
437
  }
317
438
  const found = findActiveTrigger(textBefore, triggers);
318
439
  if (!found) {
440
+ dismissedRef.current = null;
319
441
  if (state.isActive) {
320
442
  reset();
321
443
  }
@@ -326,14 +448,27 @@ export function useTriggerMenu(options) {
326
448
  query,
327
449
  triggerStart
328
450
  } = found;
329
- if (!state.isActive || state.activeTrigger !== trigger) {
451
+
452
+ // After Escape, keep the menu hidden while that same query keeps growing
453
+ const dismissed = dismissedRef.current;
454
+ if (dismissed && dismissed.character === trigger.character && dismissed.triggerStart === triggerStart && dismissed.textNode !== null && dismissed.textNode.isConnected && dismissed.textNode === getCaretTextNode(editable)) {
455
+ if (query.startsWith(dismissed.dismissedQuery)) {
456
+ return;
457
+ }
458
+ dismissedRef.current = null;
459
+ } else {
460
+ dismissedRef.current = null;
461
+ }
462
+ if (!state.isActive || state.activeTrigger?.character !== trigger.character || triggerStartRef.current !== triggerStart) {
330
463
  triggerStartRef.current = triggerStart;
464
+ isMenuSuppressedRef.current = false;
331
465
  setState(prev => ({
332
466
  ...prev,
333
467
  isActive: true,
334
468
  activeTrigger: trigger,
335
469
  query,
336
- highlightedIndex: 0
470
+ highlightedIndex: 0,
471
+ isHidden: false
337
472
  }));
338
473
  setAnchor();
339
474
  searchItems(trigger, query);
@@ -341,13 +476,50 @@ export function useTriggerMenu(options) {
341
476
  } else if (state.query !== query) {
342
477
  setState(prev => ({
343
478
  ...prev,
344
- query
479
+ query,
480
+ activeTrigger: trigger
345
481
  }));
346
482
  searchItems(trigger, query);
347
483
  }
348
484
  }, [triggers, editableRef, state.isActive, state.activeTrigger, state.query, reset, setAnchor, searchItems, popover]);
485
+ const isMenuVisible = state.isActive && !state.isHidden;
349
486
  const handleKeyDown = useCallback(e => {
350
- if (!state.isActive || !popover.isOpen) {
487
+ // Never intercept IME composition keystrokes (e.g. Enter committing candidates)
488
+ if (isImeKeyEvent(e.nativeEvent)) {
489
+ return false;
490
+ }
491
+
492
+ // A hidden menu consumes nothing: arrows move the caret, Enter submits,
493
+ // and Escape reaches the surrounding surface.
494
+ if (!isMenuVisible) {
495
+ return false;
496
+ }
497
+ if (e.key === 'Escape') {
498
+ e.preventDefault();
499
+ const editable = editableRef.current;
500
+ const dismissed = state.activeTrigger ? {
501
+ character: state.activeTrigger.character,
502
+ triggerStart: triggerStartRef.current,
503
+ dismissedQuery: state.query,
504
+ textNode: editable ? getCaretTextNode(editable) : null
505
+ } : null;
506
+ reset();
507
+ // Remembered after reset, which clears it: the menu stays hidden while
508
+ // this same query keeps growing.
509
+ dismissedRef.current = dismissed;
510
+ return true;
511
+ }
512
+
513
+ // A visible menu keeps the arrows even when it has nothing to pick (rows
514
+ // still loading, or the empty message), so they never recall history
515
+ // under an open panel. Enter and Tab pick only a settled row; otherwise
516
+ // they keep their editor meaning, so Enter sends the message as typed.
517
+ const hasPickableRows = !state.isLoading && state.items.length > 0;
518
+ if (!hasPickableRows && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
519
+ e.preventDefault();
520
+ return true;
521
+ }
522
+ if (!hasPickableRows) {
351
523
  return false;
352
524
  }
353
525
  switch (e.key) {
@@ -379,16 +551,10 @@ export function useTriggerMenu(options) {
379
551
  }
380
552
  return false;
381
553
  }
382
- case 'Escape':
383
- {
384
- e.preventDefault();
385
- reset();
386
- return true;
387
- }
388
554
  default:
389
555
  return false;
390
556
  }
391
- }, [state.isActive, state.highlightedIndex, state.items, popover.isOpen, selectItem, reset]);
557
+ }, [isMenuVisible, editableRef, state.activeTrigger, state.query, state.isLoading, state.highlightedIndex, state.items, selectItem, reset]);
392
558
  const getItemId = useCallback(index => `${listboxId}-option-${index}`, [listboxId]);
393
559
 
394
560
  // Keep the highlighted option visible during keyboard navigation; hover
@@ -416,7 +582,7 @@ export function useTriggerMenu(options) {
416
582
  const ariaProps = !hasTriggers ? {
417
583
  role: 'textbox',
418
584
  'aria-multiline': 'true'
419
- } : state.isActive && popover.isOpen ? {
585
+ } : isMenuVisible ? {
420
586
  role: 'combobox',
421
587
  'aria-expanded': true,
422
588
  'aria-controls': listboxId,
@@ -428,9 +594,15 @@ export function useTriggerMenu(options) {
428
594
  'aria-haspopup': 'listbox'
429
595
  };
430
596
  const renderMenu = useCallback(() => {
431
- const trigger = state.activeTrigger;
432
- const emptyText = trigger?.emptySearchText ?? 'No results';
433
- const loadingText = trigger?.loadingText ?? 'Searching\u2026';
597
+ const activeTrigger = state.activeTrigger;
598
+ if (!activeTrigger) {
599
+ return null;
600
+ }
601
+ if (state.isHidden) {
602
+ return null;
603
+ }
604
+ const emptyText = activeTrigger.emptySearchText ?? 'No results';
605
+ const loadingText = activeTrigger.loadingText ?? 'Searching\u2026';
434
606
  let listContent;
435
607
  if (state.isLoading) {
436
608
  listContent = /*#__PURE__*/_jsx("div", {
@@ -471,7 +643,7 @@ export function useTriggerMenu(options) {
471
643
  className: "x9f619 x78zum5 x6s0dn4 xh8yej3 xlsj2fj xh6dtrn x1ypdohk x16khyan x1a2a7pz xc342km xng3xce x1yc453h x9ynric xjm74w1 xw6l6zx x1tgivj0 x1lmrjuc"
472
644
  }
473
645
  }[!!(idx === state.highlightedIndex) << 0],
474
- children: trigger?.renderItem ? trigger.renderItem(item) : /*#__PURE__*/_jsx("span", {
646
+ children: activeTrigger.renderItem ? activeTrigger.renderItem(item) : /*#__PURE__*/_jsx("span", {
475
647
  ...{
476
648
  className: "x98rzlu xeuugli xb3r6kr xlyipyv xuxw1ft"
477
649
  },
@@ -498,7 +670,7 @@ export function useTriggerMenu(options) {
498
670
  return popover.render(/*#__PURE__*/_jsx("div", {
499
671
  id: listboxId,
500
672
  role: "listbox",
501
- "aria-label": trigger?.menuLabel ?? t('@astryx.chatTriggerMenu.suggestions'),
673
+ "aria-label": activeTrigger.menuLabel ?? t('@astryx.chatTriggerMenu.suggestions'),
502
674
  ...mergeProps(themeProps('trigger-menu'), {
503
675
  className: "x9f619 x1xiyphd x1odjw0f x9epnlk xfb3i0g"
504
676
  }),
@@ -9,6 +9,15 @@ export interface CodeBlockProps extends BaseProps<HTMLPreElement> {
9
9
  hasLanguageLabel?: boolean;
10
10
  hasLineNumbers?: boolean;
11
11
  highlightLines?: number[];
12
+ /**
13
+ * Render the code as a unified diff over `language`: lines starting with
14
+ * `+` are added, `-` removed, `@@` is a hunk header (a `--- `/`+++ ` pair
15
+ * directly before one is a file header), anything else is context; the
16
+ * label reads `diff` or `<language> diff`. The glyph sits in its own column and the rest of every line
17
+ * keeps the language's syntax highlighting. Copy still returns the exact
18
+ * source, glyphs included.
19
+ */
20
+ isDiff?: boolean;
12
21
  hasCopyButton?: boolean;
13
22
  onCopy?: () => void;
14
23
  isWrapped?: boolean;
@@ -58,7 +67,7 @@ export interface CodeBlockProps extends BaseProps<HTMLPreElement> {
58
67
  * <CodeBlock code="const x = 42;" language="javascript" />
59
68
  * ```
60
69
  */
61
- export declare function CodeBlock({ code, language, title, hasLanguageLabel, hasLineNumbers, highlightLines, hasCopyButton, onCopy, isWrapped, maxHeight, isCollapsible, collapsibleThreshold, size, width: widthProp, container, tokenizer: customTokenizer, highlightMode, syntaxTheme, xstyle, className, style, ref, ...props }: CodeBlockProps): React.JSX.Element;
70
+ export declare function CodeBlock({ code, language, title, hasLanguageLabel, hasLineNumbers, highlightLines, isDiff, hasCopyButton, onCopy, isWrapped, maxHeight, isCollapsible, collapsibleThreshold, size, width: widthProp, container, tokenizer: customTokenizer, highlightMode, syntaxTheme, xstyle, className, style, ref, ...props }: CodeBlockProps): React.JSX.Element;
62
71
  export declare namespace CodeBlock {
63
72
  var displayName: string;
64
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/CodeBlock/CodeBlock.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AA6B5C,OAAO,EAAc,KAAK,qBAAqB,EAAC,MAAM,iBAAiB,CAAC;AA4WxE,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC/D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,KACb;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAqPD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAsB,EACtB,KAAK,EACL,gBAAuB,EACvB,cAAsB,EACtB,cAAc,EACd,aAAoB,EACpB,MAAM,EACN,SAAiB,EACjB,SAAS,EACT,aAAqB,EACrB,oBAAyB,EACzB,IAAW,EACX,KAAK,EAAE,SAAyB,EAChC,SAAkB,EAClB,SAAS,EAAE,eAAe,EAC1B,aAAsB,EACtB,WAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,cAAc,qBAmPhB;yBA3Qe,SAAS"}
1
+ {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/CodeBlock/CodeBlock.tsx"],"names":[],"mappings":"AAoBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,cAAc,CAAC;AAgC5C,OAAO,EAAc,KAAK,qBAAqB,EAAC,MAAM,iBAAiB,CAAC;AAwcxE,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,cAAc,CAAC;IAC/D,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,SAAS,CAAC,EAAE,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,KACb;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;IAClD,aAAa,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC5C;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAgSD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAsB,EACtB,KAAK,EACL,gBAAuB,EACvB,cAAsB,EACtB,cAAc,EACd,MAAc,EACd,aAAoB,EACpB,MAAM,EACN,SAAiB,EACjB,SAAS,EACT,aAAqB,EACrB,oBAAyB,EACzB,IAAW,EACX,KAAK,EAAE,SAAyB,EAChC,SAAkB,EAClB,SAAS,EAAE,eAAe,EAC1B,aAAsB,EACtB,WAAW,EACX,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,cAAc,qBAmRhB;yBA5Se,SAAS"}