@astryxdesign/core 0.6.2 → 0.6.3-canary.0899f21

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 (549) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/BottomSheet/BottomSheet.d.ts +1 -1
  3. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  4. package/dist/BottomSheet/BottomSheet.js +3 -1
  5. package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
  6. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  7. package/dist/BottomSheet/BottomSheetPanel.js +56 -19
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +13 -28
  10. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  11. package/dist/Chat/ChatComposer.js +10 -5
  12. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  13. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  14. package/dist/Chat/ChatComposerDrawer.js +48 -23
  15. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  16. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  17. package/dist/Chat/ChatComposerInput.js +63 -16
  18. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  19. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  20. package/dist/Chat/ChatDictationButton.js +6 -4
  21. package/dist/Chat/ChatLayout.d.ts +19 -0
  22. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  23. package/dist/Chat/ChatLayout.js +19 -0
  24. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  25. package/dist/Chat/ChatLayoutScrollButton.js +44 -34
  26. package/dist/Chat/ChatMessageBubble.d.ts +2 -0
  27. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  28. package/dist/Chat/ChatMessageBubble.js +5 -3
  29. package/dist/Chat/ChatMessageList.d.ts +2 -1
  30. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  31. package/dist/Chat/ChatMessageList.js +4 -3
  32. package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
  33. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  34. package/dist/Chat/ChatMessageMetadata.js +12 -9
  35. package/dist/Chat/ChatSendButton.js +1 -1
  36. package/dist/Chat/index.d.ts +1 -1
  37. package/dist/Chat/index.d.ts.map +1 -1
  38. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  39. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  40. package/dist/Citation/Citation.d.ts +1 -1
  41. package/dist/Citation/Citation.d.ts.map +1 -1
  42. package/dist/Citation/Citation.js +3 -2
  43. package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
  44. package/dist/CodeBlock/highlightRanges.js +14 -3
  45. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  46. package/dist/Collapsible/Collapsible.js +6 -1
  47. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  48. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  49. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  50. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  51. package/dist/DateInput/DateInput.d.ts.map +1 -1
  52. package/dist/DateInput/DateInput.js +4 -4
  53. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  54. package/dist/DateInput/NativeDateField.js +16 -16
  55. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  56. package/dist/DateInput/TouchDateField.js +2 -2
  57. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  58. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  59. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  60. package/dist/DateTimeInput/DateTimeInput.js +8 -8
  61. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  62. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  63. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  64. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  65. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  66. package/dist/Dialog/DialogHeader.d.ts +8 -1
  67. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  68. package/dist/Dialog/DialogHeader.js +13 -4
  69. package/dist/Field/InputClearButton.d.ts +4 -2
  70. package/dist/Field/InputClearButton.d.ts.map +1 -1
  71. package/dist/Field/InputClearButton.js +4 -2
  72. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  73. package/dist/Field/PanelSearchInput.js +1 -1
  74. package/dist/FileInput/FileInput.d.ts.map +1 -1
  75. package/dist/FileInput/FileInput.js +7 -7
  76. package/dist/Icon/Icon.d.ts +6 -31
  77. package/dist/Icon/Icon.d.ts.map +1 -1
  78. package/dist/Icon/Icon.js +8 -71
  79. package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
  80. package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
  81. package/dist/Icon/IconDefaultSizeContext.js +18 -0
  82. package/dist/Icon/IconSize.stylex.d.ts +65 -0
  83. package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
  84. package/dist/Icon/IconSize.stylex.js +75 -0
  85. package/dist/Item/Item.d.ts +1 -1
  86. package/dist/Item/Item.d.ts.map +1 -1
  87. package/dist/Item/Item.js +4 -3
  88. package/dist/Kbd/Kbd.d.ts +5 -3
  89. package/dist/Kbd/Kbd.d.ts.map +1 -1
  90. package/dist/Kbd/Kbd.js +36 -42
  91. package/dist/Link/Link.d.ts.map +1 -1
  92. package/dist/Link/Link.js +6 -2
  93. package/dist/Link/useLinkComponent.d.ts +5 -15
  94. package/dist/Link/useLinkComponent.d.ts.map +1 -1
  95. package/dist/Link/useLinkComponent.js +34 -51
  96. package/dist/List/List.d.ts +19 -1
  97. package/dist/List/List.d.ts.map +1 -1
  98. package/dist/List/List.js +9 -2
  99. package/dist/List/ListContext.d.ts +1 -0
  100. package/dist/List/ListContext.d.ts.map +1 -1
  101. package/dist/List/ListContext.js +2 -1
  102. package/dist/List/ListItem.d.ts +1 -1
  103. package/dist/List/ListItem.d.ts.map +1 -1
  104. package/dist/List/ListItem.js +9 -2
  105. package/dist/Markdown/Markdown.d.ts +8 -2
  106. package/dist/Markdown/Markdown.d.ts.map +1 -1
  107. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  108. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  109. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  110. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  111. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  112. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  113. package/dist/Markdown/Markdown.js +262 -109
  114. package/dist/Markdown/ast.d.ts +162 -0
  115. package/dist/Markdown/ast.d.ts.map +1 -0
  116. package/dist/Markdown/ast.js +74 -0
  117. package/dist/Markdown/index.d.ts +5 -3
  118. package/dist/Markdown/index.d.ts.map +1 -1
  119. package/dist/Markdown/index.js +3 -2
  120. package/dist/Markdown/parser/index.d.ts +10 -0
  121. package/dist/Markdown/parser/index.d.ts.map +1 -0
  122. package/dist/Markdown/parser/index.js +10 -0
  123. package/dist/Markdown/parser.d.ts +126 -58
  124. package/dist/Markdown/parser.d.ts.map +1 -1
  125. package/dist/Markdown/parser.js +716 -167
  126. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  127. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  128. package/dist/Markdown/plugins/frontmatter.js +132 -0
  129. package/dist/Markdown/plugins/index.d.ts +17 -0
  130. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  131. package/dist/Markdown/plugins/index.js +14 -0
  132. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  133. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  134. package/dist/Markdown/plugins/protocol.js +957 -0
  135. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  136. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  137. package/dist/Markdown/plugins/semanticFence.js +213 -0
  138. package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
  139. package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
  140. package/dist/Markdown/plugins/softBreaks.js +172 -0
  141. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  142. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  143. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  144. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  145. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  146. package/dist/Markdown/plugins/textTransform.js +374 -0
  147. package/dist/Markdown/remark.d.ts +196 -0
  148. package/dist/Markdown/remark.d.ts.map +1 -0
  149. package/dist/Markdown/remark.js +1062 -0
  150. package/dist/Markdown/url.d.ts +6 -0
  151. package/dist/Markdown/url.d.ts.map +1 -0
  152. package/dist/Markdown/url.js +31 -0
  153. package/dist/Markdown/utils.d.ts +4 -2
  154. package/dist/Markdown/utils.d.ts.map +1 -1
  155. package/dist/Markdown/utils.js +2 -1
  156. package/dist/MetadataList/MetadataList.js +3 -3
  157. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  158. package/dist/NumberInput/NumberInput.js +4 -4
  159. package/dist/Outline/index.d.ts +1 -0
  160. package/dist/Outline/index.d.ts.map +1 -1
  161. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  162. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  163. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  164. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  165. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  166. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  167. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  168. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  169. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  170. package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
  171. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  172. package/dist/ProgressBar/ProgressBar.js +36 -31
  173. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  174. package/dist/RadioList/RadioListItem.js +13 -1
  175. package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
  176. package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
  177. package/dist/ScrollableArea/ScrollableArea.js +1 -0
  178. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  179. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  180. package/dist/Selector/Selector.d.ts +9 -7
  181. package/dist/Selector/Selector.d.ts.map +1 -1
  182. package/dist/Selector/Selector.js +16 -7
  183. package/dist/SideNav/SideNav.d.ts +2 -1
  184. package/dist/SideNav/SideNav.d.ts.map +1 -1
  185. package/dist/SideNav/SideNav.js +9 -3
  186. package/dist/Slider/Slider.d.ts.map +1 -1
  187. package/dist/Slider/Slider.js +28 -12
  188. package/dist/Spinner/Spinner.d.ts.map +1 -1
  189. package/dist/Spinner/Spinner.js +23 -7
  190. package/dist/Switch/Switch.d.ts.map +1 -1
  191. package/dist/Switch/Switch.js +11 -0
  192. package/dist/TabList/Tab.d.ts +1 -1
  193. package/dist/TabList/Tab.d.ts.map +1 -1
  194. package/dist/TabList/Tab.js +20 -7
  195. package/dist/Table/Table.d.ts +1 -0
  196. package/dist/Table/Table.d.ts.map +1 -1
  197. package/dist/Table/Table.js +29 -13
  198. package/dist/TextArea/TextArea.d.ts.map +1 -1
  199. package/dist/TextArea/TextArea.js +1 -1
  200. package/dist/TextInput/TextInput.d.ts.map +1 -1
  201. package/dist/TextInput/TextInput.js +2 -2
  202. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  203. package/dist/TimeInput/TimeInput.js +4 -4
  204. package/dist/Timer/Timer.d.ts +49 -0
  205. package/dist/Timer/Timer.d.ts.map +1 -0
  206. package/dist/Timer/Timer.js +158 -0
  207. package/dist/Timer/index.d.ts +9 -0
  208. package/dist/Timer/index.d.ts.map +1 -0
  209. package/dist/Timer/index.js +10 -0
  210. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  211. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  212. package/dist/ToggleButton/ToggleButton.js +15 -27
  213. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  214. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  215. package/dist/TopNav/TopNavMenu.js +3 -2
  216. package/dist/TreeList/TreeList.d.ts.map +1 -1
  217. package/dist/TreeList/TreeList.js +3 -0
  218. package/dist/TreeList/TreeListItem.d.ts +6 -1
  219. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  220. package/dist/TreeList/TreeListItem.js +12 -2
  221. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  222. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  223. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  224. package/dist/Typeahead/BaseTypeahead.js +16 -7
  225. package/dist/astryx.css +27 -11
  226. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  227. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  228. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  229. package/dist/hooks/useClickableContainer.d.ts +10 -1
  230. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  231. package/dist/hooks/useClickableContainer.js +15 -4
  232. package/dist/hooks/useScrollableArea.d.ts +6 -2
  233. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  234. package/dist/hooks/useScrollableArea.js +17 -5
  235. package/dist/index.d.ts +1 -0
  236. package/dist/index.d.ts.map +1 -1
  237. package/dist/index.js +3 -0
  238. package/dist/theme/declarationBoundary.d.ts +17 -0
  239. package/dist/theme/declarationBoundary.d.ts.map +1 -0
  240. package/dist/theme/declarationBoundary.js +343 -0
  241. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  242. package/dist/theme/derivedVarRegistry.js +4 -0
  243. package/dist/theme/generateThemeRules.d.ts +13 -7
  244. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  245. package/dist/theme/generateThemeRules.js +140 -34
  246. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  247. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  248. package/dist/utils/interactionOverlay.stylex.js +9 -0
  249. package/dist/utils/safeUrl.d.ts +11 -0
  250. package/dist/utils/safeUrl.d.ts.map +1 -0
  251. package/dist/utils/safeUrl.js +78 -0
  252. package/locales/af-ZA.json +530 -1
  253. package/locales/ar-SA.json +490 -1
  254. package/locales/ca-ES.json +514 -1
  255. package/locales/cs-CZ.json +498 -1
  256. package/locales/da-DK.json +522 -1
  257. package/locales/de-DE.json +522 -1
  258. package/locales/el-GR.json +498 -1
  259. package/locales/es-ES.json +510 -1
  260. package/locales/fi-FI.json +498 -1
  261. package/locales/fr-FR.json +534 -1
  262. package/locales/he-IL.json +498 -1
  263. package/locales/hu-HU.json +498 -1
  264. package/locales/it-IT.json +510 -1
  265. package/locales/ja-JP.json +490 -1
  266. package/locales/ko-KR.json +498 -1
  267. package/locales/nl-NL.json +534 -1
  268. package/locales/no-NO.json +510 -1
  269. package/locales/pl-PL.json +506 -1
  270. package/locales/pt-BR.json +506 -1
  271. package/locales/pt-PT.json +506 -1
  272. package/locales/ro-RO.json +506 -1
  273. package/locales/ru-RU.json +498 -1
  274. package/locales/sr-SP.json +498 -1
  275. package/locales/sv-SE.json +502 -1
  276. package/locales/tr-TR.json +498 -1
  277. package/locales/uk-UA.json +498 -1
  278. package/locales/vi-VN.json +502 -1
  279. package/locales/zh-CN.json +490 -1
  280. package/locales/zh-TW.json +490 -1
  281. package/package.json +24 -4
  282. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  283. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  284. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  285. package/src/BottomSheet/BottomSheet.tsx +3 -1
  286. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  287. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  288. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  289. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  290. package/src/Button/Button.doc.mjs +5 -5
  291. package/src/Button/Button.tsx +15 -13
  292. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  293. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  294. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  295. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  296. package/src/Chat/ChatComposer.doc.mjs +14 -0
  297. package/src/Chat/ChatComposer.spec.md +230 -0
  298. package/src/Chat/ChatComposer.test.tsx +57 -0
  299. package/src/Chat/ChatComposer.tsx +21 -9
  300. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  301. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  302. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  303. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  304. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  305. package/src/Chat/ChatComposerInput.spec.md +185 -0
  306. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  307. package/src/Chat/ChatComposerInput.tsx +78 -13
  308. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  309. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  310. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  311. package/src/Chat/ChatDictationButton.spec.md +160 -0
  312. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  313. package/src/Chat/ChatDictationButton.tsx +8 -6
  314. package/src/Chat/ChatLayout.doc.mjs +12 -4
  315. package/src/Chat/ChatLayout.spec.md +271 -0
  316. package/src/Chat/ChatLayout.test.tsx +28 -0
  317. package/src/Chat/ChatLayout.tsx +19 -0
  318. package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
  319. package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
  320. package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
  321. package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
  322. package/src/Chat/ChatMessageBubble.spec.md +263 -0
  323. package/src/Chat/ChatMessageBubble.test.tsx +93 -0
  324. package/src/Chat/ChatMessageBubble.tsx +8 -3
  325. package/src/Chat/ChatMessageList.spec.md +222 -0
  326. package/src/Chat/ChatMessageList.test.tsx +64 -2
  327. package/src/Chat/ChatMessageList.tsx +4 -3
  328. package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
  329. package/src/Chat/ChatMessageMetadata.spec.md +220 -0
  330. package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
  331. package/src/Chat/ChatMessageMetadata.tsx +13 -13
  332. package/src/Chat/ChatSendButton.test.tsx +1 -4
  333. package/src/Chat/ChatSendButton.tsx +1 -1
  334. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
  335. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
  336. package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
  337. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
  338. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
  339. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
  340. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
  341. package/src/Chat/index.ts +1 -0
  342. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  343. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  344. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  345. package/src/Citation/Citation.doc.mjs +2 -2
  346. package/src/Citation/Citation.test.tsx +17 -0
  347. package/src/Citation/Citation.tsx +4 -2
  348. package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
  349. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  350. package/src/CodeBlock/highlightRanges.test.ts +143 -1
  351. package/src/CodeBlock/highlightRanges.ts +15 -5
  352. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  353. package/src/Collapsible/Collapsible.test.tsx +21 -0
  354. package/src/Collapsible/Collapsible.tsx +5 -0
  355. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  356. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  357. package/src/DateInput/DateInput.tsx +6 -1
  358. package/src/DateInput/NativeDateField.tsx +24 -8
  359. package/src/DateInput/TouchDateField.tsx +6 -2
  360. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  361. package/src/DateTimeInput/DateTimeInput.tsx +6 -1
  362. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  363. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  364. package/src/Dialog/Dialog.doc.mjs +2 -0
  365. package/src/Dialog/DialogHeader.doc.mjs +22 -0
  366. package/src/Dialog/DialogHeader.test.tsx +167 -3
  367. package/src/Dialog/DialogHeader.tsx +37 -6
  368. package/src/Dialog/modules/DialogHeader.spec.md +101 -42
  369. package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
  370. package/src/Field/InputClearButton.test.tsx +17 -3
  371. package/src/Field/InputClearButton.tsx +5 -2
  372. package/src/Field/PanelSearchInput.tsx +5 -2
  373. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  374. package/src/FileInput/FileInput.tsx +11 -2
  375. package/src/Icon/Icon.doc.mjs +7 -5
  376. package/src/Icon/Icon.spec.md +81 -40
  377. package/src/Icon/Icon.test.tsx +6 -3
  378. package/src/Icon/Icon.tsx +20 -68
  379. package/src/Icon/IconDefaultSizeContext.ts +23 -0
  380. package/src/Icon/IconSize.stylex.ts +70 -0
  381. package/src/IconButton/IconButton.doc.mjs +3 -3
  382. package/src/IconButton/IconButton.test.tsx +40 -0
  383. package/src/Item/Item.doc.mjs +6 -2
  384. package/src/Item/Item.tsx +9 -3
  385. package/src/Kbd/Kbd.doc.mjs +3 -3
  386. package/src/Kbd/Kbd.test.tsx +57 -1
  387. package/src/Kbd/Kbd.tsx +57 -37
  388. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  389. package/src/Link/Link.doc.mjs +17 -4
  390. package/src/Link/Link.test.tsx +24 -0
  391. package/src/Link/Link.tsx +5 -0
  392. package/src/Link/LinkProvider.doc.mjs +2 -2
  393. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
  394. package/src/Link/useLinkComponent.test.tsx +333 -0
  395. package/src/Link/useLinkComponent.ts +29 -57
  396. package/src/List/List.doc.mjs +6 -0
  397. package/src/List/List.spec.md +200 -0
  398. package/src/List/List.test.tsx +117 -1
  399. package/src/List/List.tsx +22 -2
  400. package/src/List/ListContext.tsx +3 -1
  401. package/src/List/ListItem.doc.mjs +2 -2
  402. package/src/List/ListItem.source-build.test.mjs +41 -0
  403. package/src/List/ListItem.tsx +26 -2
  404. package/src/Markdown/Markdown.doc.mjs +300 -2
  405. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  406. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  407. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  408. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  409. package/src/Markdown/Markdown.public.test.ts +130 -3
  410. package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
  411. package/src/Markdown/Markdown.spec.md +203 -45
  412. package/src/Markdown/Markdown.test.tsx +63 -0
  413. package/src/Markdown/Markdown.tsx +414 -135
  414. package/src/Markdown/ast.test.ts +307 -0
  415. package/src/Markdown/ast.ts +337 -0
  416. package/src/Markdown/incremental.test.ts +12 -0
  417. package/src/Markdown/index.ts +37 -1
  418. package/src/Markdown/modules/remark.spec.md +269 -0
  419. package/src/Markdown/modules/softBreaks.spec.md +137 -0
  420. package/src/Markdown/parser/index.ts +64 -0
  421. package/src/Markdown/parser.public.test.ts +103 -0
  422. package/src/Markdown/parser.test.ts +20 -0
  423. package/src/Markdown/parser.ts +1180 -235
  424. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  425. package/src/Markdown/plugins/frontmatter.ts +198 -0
  426. package/src/Markdown/plugins/index.ts +54 -0
  427. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  428. package/src/Markdown/plugins/protocol.ts +1618 -0
  429. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  430. package/src/Markdown/plugins/semanticFence.ts +424 -0
  431. package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
  432. package/src/Markdown/plugins/softBreaks.ts +169 -0
  433. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  434. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  435. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  436. package/src/Markdown/plugins/textTransform.ts +554 -0
  437. package/src/Markdown/remark.test.tsx +1877 -0
  438. package/src/Markdown/remark.ts +1574 -0
  439. package/src/Markdown/url.ts +36 -0
  440. package/src/Markdown/utils.ts +13 -1
  441. package/src/MetadataList/MetadataList.test.tsx +4 -2
  442. package/src/MetadataList/MetadataList.tsx +3 -3
  443. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  444. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  445. package/src/NumberInput/NumberInput.tsx +6 -1
  446. package/src/Outline/Outline.doc.mjs +7 -5
  447. package/src/Outline/Outline.spec.md +1 -1
  448. package/src/Outline/index.ts +1 -0
  449. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  450. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  451. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  452. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  453. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  454. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  455. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
  456. package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
  457. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  458. package/src/ProgressBar/ProgressBar.tsx +59 -72
  459. package/src/RadioList/RadioList.doc.mjs +11 -0
  460. package/src/RadioList/RadioList.test.tsx +32 -0
  461. package/src/RadioList/RadioListItem.tsx +25 -1
  462. package/src/ScrollableArea/ScrollableArea.tsx +1 -0
  463. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  464. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  465. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  466. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  467. package/src/Selector/Selector.doc.mjs +2 -2
  468. package/src/Selector/Selector.spec.md +51 -49
  469. package/src/Selector/Selector.test.tsx +61 -55
  470. package/src/Selector/Selector.tsx +34 -15
  471. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  472. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  473. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  474. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  475. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  476. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
  477. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  478. package/src/SideNav/SideNav.doc.mjs +1 -1
  479. package/src/SideNav/SideNav.test.tsx +10 -0
  480. package/src/SideNav/SideNav.tsx +14 -2
  481. package/src/Slider/Slider.doc.mjs +17 -3
  482. package/src/Slider/Slider.test.tsx +221 -0
  483. package/src/Slider/Slider.tsx +40 -9
  484. package/src/Spinner/Spinner.test.tsx +4 -0
  485. package/src/Spinner/Spinner.tsx +31 -18
  486. package/src/Switch/Switch.doc.mjs +11 -0
  487. package/src/Switch/Switch.test.tsx +16 -0
  488. package/src/Switch/Switch.tsx +28 -0
  489. package/src/TabList/Tab.tsx +35 -7
  490. package/src/TabList/TabList.doc.mjs +11 -0
  491. package/src/TabList/TabList.spec.md +204 -0
  492. package/src/TabList/TabList.test.tsx +66 -0
  493. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  494. package/src/Table/Table.doc.mjs +1 -1
  495. package/src/Table/Table.spec.md +54 -40
  496. package/src/Table/Table.test.tsx +83 -10
  497. package/src/Table/Table.tsx +30 -22
  498. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  499. package/src/TextArea/TextArea.tsx +6 -1
  500. package/src/TextInput/TextInput.test.tsx +20 -1
  501. package/src/TextInput/TextInput.tsx +6 -1
  502. package/src/TimeInput/TimeInput.tsx +6 -1
  503. package/src/Timer/Timer.doc.mjs +183 -0
  504. package/src/Timer/Timer.spec.md +215 -0
  505. package/src/Timer/Timer.test.tsx +302 -0
  506. package/src/Timer/Timer.tsx +258 -0
  507. package/src/Timer/index.ts +11 -0
  508. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  509. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  510. package/src/ToggleButton/ToggleButton.tsx +26 -33
  511. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  512. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  513. package/src/Token/Token.doc.mjs +2 -2
  514. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  515. package/src/TopNav/TopNavMenu.doc.mjs +2 -2
  516. package/src/TopNav/TopNavMenu.test.tsx +30 -0
  517. package/src/TopNav/TopNavMenu.tsx +7 -2
  518. package/src/TreeList/TreeList.doc.mjs +3 -3
  519. package/src/TreeList/TreeList.spec.md +123 -75
  520. package/src/TreeList/TreeList.test.tsx +29 -0
  521. package/src/TreeList/TreeList.tsx +3 -0
  522. package/src/TreeList/TreeListItem.tsx +15 -1
  523. package/src/TreeList/TreeListTypes.ts +11 -1
  524. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  525. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  526. package/src/Typeahead/Typeahead.test.tsx +53 -0
  527. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  528. package/src/__tests__/pressState.ts +93 -0
  529. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  530. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  531. package/src/hooks/useClickableContainer.test.tsx +236 -0
  532. package/src/hooks/useClickableContainer.ts +20 -4
  533. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  534. package/src/hooks/useScrollableArea.test.tsx +59 -1
  535. package/src/hooks/useScrollableArea.ts +34 -10
  536. package/src/index.ts +3 -0
  537. package/src/inputFontFloor.test.ts +106 -0
  538. package/src/tailwind-theme.css +0 -6
  539. package/src/theme/Theme.test.tsx +32 -0
  540. package/src/theme/declarationBoundary.test.ts +126 -0
  541. package/src/theme/declarationBoundary.ts +347 -0
  542. package/src/theme/derivedVarRegistry.test.ts +7 -0
  543. package/src/theme/derivedVarRegistry.ts +1 -0
  544. package/src/theme/generateThemeRules.test.ts +526 -1
  545. package/src/theme/generateThemeRules.ts +228 -50
  546. package/src/theme/tokenValueCompat.test.ts +4 -1
  547. package/src/utils/interactionOverlay.stylex.ts +20 -0
  548. package/src/utils/safeUrl.test.ts +88 -0
  549. package/src/utils/safeUrl.ts +85 -0
@@ -1,7 +1,14 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
- import {describe, it, expect} from 'vitest';
4
- import {render, screen} from '@testing-library/react';
3
+ /**
4
+ * @file ChatMessageList.test.tsx
5
+ * @input React Testing Library, Vitest, and the public ChatMessageList surface
6
+ * @output Observable log, empty-state, alignment, and async-loading regressions
7
+ * @position Colocated component behavior tests
8
+ */
9
+
10
+ import {describe, it, expect, vi} from 'vitest';
11
+ import {act, render, screen} from '@testing-library/react';
5
12
  import {ChatMessageList} from './ChatMessageList';
6
13
  import {ChatMessage} from './ChatMessage';
7
14
  import {ChatMessageBubble} from './ChatMessageBubble';
@@ -55,6 +62,11 @@ describe('ChatMessageList', () => {
55
62
  expect(screen.getByText('No messages yet')).toBeTruthy();
56
63
  });
57
64
 
65
+ it('renders an accepted numeric empty state', () => {
66
+ render(<ChatMessageList emptyState={0}>{[]}</ChatMessageList>);
67
+ expect(screen.getByRole('log')).toHaveTextContent('0');
68
+ });
69
+
58
70
  it('applies density class', () => {
59
71
  render(
60
72
  <ChatMessageList density="compact" data-testid="list">
@@ -129,4 +141,54 @@ describe('ChatMessageList', () => {
129
141
  );
130
142
  expect(screen.getByText('Hello')).toBeTruthy();
131
143
  });
144
+
145
+ it('loads older messages through the top sentinel and exposes pending status', async () => {
146
+ let notify!: IntersectionObserverCallback;
147
+ let complete!: () => void;
148
+ const observeSentinel = vi.fn();
149
+ const disconnect = vi.fn();
150
+ const action = vi.fn(
151
+ async () =>
152
+ new Promise<void>(resolve => {
153
+ complete = resolve;
154
+ }),
155
+ );
156
+ class Observer {
157
+ constructor(callback: IntersectionObserverCallback) {
158
+ notify = callback;
159
+ }
160
+ observe = observeSentinel;
161
+ disconnect = disconnect;
162
+ }
163
+ vi.stubGlobal('IntersectionObserver', Observer);
164
+ try {
165
+ const {unmount} = render(
166
+ <ChatMessageList scrollToTopAction={action}>
167
+ <div>Earlier message</div>
168
+ </ChatMessageList>,
169
+ );
170
+ expect(observeSentinel).toHaveBeenCalledTimes(1);
171
+ act(() => {
172
+ notify(
173
+ [{isIntersecting: false} as IntersectionObserverEntry],
174
+ {} as IntersectionObserver,
175
+ );
176
+ });
177
+ expect(action).not.toHaveBeenCalled();
178
+ act(() => {
179
+ notify(
180
+ [{isIntersecting: true} as IntersectionObserverEntry],
181
+ {} as IntersectionObserver,
182
+ );
183
+ });
184
+ expect(action).toHaveBeenCalledTimes(1);
185
+ expect(screen.getByRole('status', {name: 'Loading'})).toBeTruthy();
186
+ await act(async () => complete());
187
+ expect(screen.queryByRole('status', {name: 'Loading'})).toBeNull();
188
+ unmount();
189
+ expect(disconnect).toHaveBeenCalledTimes(1);
190
+ } finally {
191
+ vi.unstubAllGlobals();
192
+ }
193
+ });
132
194
  });
@@ -4,7 +4,8 @@
4
4
 
5
5
  /**
6
6
  * @file ChatMessageList.tsx
7
- * @input Uses React, StyleX, ChatListContext, theme tokens, spacing step utilities
7
+ * @input Uses React, StyleX, ChatListContext, theme tokens, spacing step utilities,
8
+ * and isRenderable to preserve accepted empty-state content
8
9
  * @output Exports ChatMessageList component and ChatMessageListProps
9
10
  * @position Presentational message container — holds ChatMessage children
10
11
  *
@@ -31,7 +32,7 @@ import {
31
32
  type ChatDensity,
32
33
  useChatLayoutContext,
33
34
  } from './ChatContext';
34
- import {mergeProps} from '../utils';
35
+ import {isRenderable, mergeProps} from '../utils';
35
36
  import {Spinner} from '../Spinner';
36
37
  import type {BaseProps} from '../BaseProps';
37
38
  import type {SpacingStep} from '../utils/types';
@@ -321,7 +322,7 @@ export function ChatMessageList({
321
322
  {/* Messages or empty state */}
322
323
  {hasChildren ? (
323
324
  children
324
- ) : emptyState ? (
325
+ ) : isRenderable(emptyState) ? (
325
326
  <div {...stylex.props(styles.emptyState)}>{emptyState}</div>
326
327
  ) : null}
327
328
  </div>
@@ -6,7 +6,8 @@ export const docs = {
6
6
  name: 'ChatMessageMetadata',
7
7
  subComponentOf: 'Chat',
8
8
  displayName: 'Chat Message Metadata',
9
- description: 'Composable metadata row for chat messages. Renders timestamp, footer content, and delivery status in a single row. Direction reverses for user sender. Renders nothing if all props are empty.',
9
+ description:
10
+ 'Composable metadata row for chat messages. Renders timestamp, footer content, and delivery status in a single row. Direction reverses for user sender. Omits the row when both slots are omitted or non-rendering scalars and status is omitted.',
10
11
  props: [
11
12
  {
12
13
  name: 'timestamp',
@@ -42,12 +43,64 @@ export const docs = {
42
43
  description: 'Message delivery status. Shows icon + label.',
43
44
  },
44
45
  ],
46
+ usage: {
47
+ description:
48
+ 'Place ChatMessageMetadata below a message or in the last ChatMessageBubble metadata slot to show a timestamp, footer content, and optional delivery status. Non-rendering scalar slots (booleans and empty strings) create no separator; numeric zero remains visible. Composite React content remains caller-owned.',
49
+ bestPractices: [
50
+ {
51
+ guidance: true,
52
+ description:
53
+ 'Put metadata in the last bubble metadata slot when the message uses bubbles, so it follows the bubble content.',
54
+ },
55
+ {
56
+ guidance: true,
57
+ description:
58
+ 'Pass timestamp and footer content independently; separators are omitted for non-rendering scalar slots. Composite React nodes are used as supplied.',
59
+ },
60
+ {
61
+ guidance: false,
62
+ description:
63
+ 'Do not supply footer actions without their own accessible names and interaction behavior; the metadata row does not own those controls.',
64
+ },
65
+ {
66
+ guidance: false,
67
+ description:
68
+ 'Do not put the same metadata on both a bubble and its enclosing message.',
69
+ },
70
+ ],
71
+ anatomy: [
72
+ {
73
+ name: 'Metadata row',
74
+ required: true,
75
+ description: 'Sender-aware line containing the visible metadata items.',
76
+ },
77
+ {
78
+ name: 'Timestamp',
79
+ required: false,
80
+ description:
81
+ 'Caller-supplied time content at the start of the logical sequence.',
82
+ },
83
+ {
84
+ name: 'Footer',
85
+ required: false,
86
+ description:
87
+ 'Caller-supplied information or actions between time and status.',
88
+ },
89
+ {
90
+ name: 'Status',
91
+ required: false,
92
+ description:
93
+ 'Localized delivery icon and text when a status is supplied.',
94
+ },
95
+ ],
96
+ },
45
97
  };
46
98
 
47
99
  export const docsZh = {
48
100
  name: 'ChatMessageMetadata',
49
101
  displayName: 'Chat Message Metadata',
50
- description: '可组合的消息元数据行。渲染时间戳、页脚内容和发送状态。用户消息方向反转。',
102
+ description:
103
+ '可组合的消息元数据行。渲染时间戳、页脚内容和发送状态。用户消息方向反转。',
51
104
  propDescriptions: {
52
105
  timestamp: '时间戳内容,字符串或 Timestamp 组件。',
53
106
  footer: '页脚内容:模型信息、反应按钮、复制按钮。',
@@ -58,7 +111,8 @@ export const docsZh = {
58
111
  export const docsDense = {
59
112
  name: 'ChatMessageMetadata',
60
113
  displayName: 'Chat Message Metadata',
61
- description: 'composable metadata row; renders timestamp · footer · status; reverses for user sender',
114
+ description:
115
+ 'composable metadata row; renders timestamp · footer · status; reverses for user sender',
62
116
  propDescriptions: {
63
117
  timestamp: 'timestamp content; string or Timestamp',
64
118
  footer: 'footer content; model info, reaction btns, copy btn',
@@ -0,0 +1,220 @@
1
+ ---
2
+ schema_version: 3
3
+ template_version: 6
4
+ kind: component
5
+ id: component:ChatMessageMetadata
6
+ authority: draft
7
+ archive_reason: null
8
+ superseded_by: null
9
+ approved_by: null
10
+ approved_at: null
11
+ owners: [cixzhang]
12
+ review_triggers: [public-api, behavior, layout, accessibility, theming, testing]
13
+ verified_by:
14
+ [
15
+ packages/core/src/Chat/ChatMessageMetadata.test.tsx,
16
+ packages/core/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts,
17
+ apps/storybook/stories/ChatMessageMetadata.stories.tsx,
18
+ packages/core/src/theme/themingTargets.test.ts,
19
+ ]
20
+ modules: []
21
+ families: []
22
+ design_specs: []
23
+ architecture:
24
+ [
25
+ architecture:public-component-api,
26
+ architecture:component-test-sufficiency,
27
+ architecture:component-theming-surface,
28
+ architecture:component-style-authoring,
29
+ architecture:react-component-runtime,
30
+ architecture:knowledge-contracts,
31
+ ]
32
+ contributing: []
33
+ system_specs: [spec:AST-029]
34
+ ---
35
+
36
+ # ChatMessageMetadata component contract
37
+
38
+ This is an observational draft of the existing Core chat metadata surface and
39
+ its tested empty-scalar correction. It creates no new prop, status meaning,
40
+ announcement guarantee, or visual policy. Current shared records govern their
41
+ own scopes independently of this draft.
42
+
43
+ ## Contract at a glance
44
+
45
+ | Area | Contract |
46
+ | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
47
+ | Public contract | Optional `timestamp` and `footer` ReactNode slots, optional closed `status` union, root `BaseProps<HTMLDivElement>` and `ref`, exported through `./Chat`. |
48
+ | Behavior | The row renders its present slots in timestamp, footer, status order, with a separator only between present slots; user sender reverses the flex row. Five delivery statuses have localized icon-and-text displays. |
49
+ | End-user impact | Non-rendering scalar slot values no longer leave a standalone dot, a blank metadata row, or a separator without adjacent content. Visible numeric zero remains. |
50
+ | Builder impact | No new inputs, defaults, or migration. Caller-supplied footer controls remain caller-owned. |
51
+ | Compatibility/readiness | Patch-compatible scalar correction to a released `./Chat` subpath; draft pending exact-head observational verification and owner review. |
52
+ | Review checks | Reject a lost visible zero, stranded separator, omitted translated status label, dropped root passthrough, or claim that a static DOM attribute proves an AT announcement. |
53
+ | Governing rules | `architecture:public-component-api/INV1, INV3, INV5–INV9`; `architecture:component-test-sufficiency/INV1–INV7`; `spec:AST-029/FR2–FR5`. |
54
+
55
+ The table is a review projection. Consumer syntax belongs in
56
+ `ChatMessageMetadata.doc.mjs` and the Chat family consumer documentation.
57
+
58
+ ## Intent
59
+
60
+ ChatMessageMetadata is the optional compact line below a chat message. It
61
+ projects caller-owned timestamp/footer content and an optional delivery status
62
+ inside the sender-aware Chat composition. It is not the message article, the
63
+ bubble surface, the transcript, or the footer control owner.
64
+
65
+ ## Compatibility and migration
66
+
67
+ - Released default preserved: yes. Core `0.6.3` exports `./Chat` with this
68
+ component, props, and status type.
69
+ - Compatibility class: patch correction for non-rendering scalar ReactNode
70
+ values, preserving numeric `0` and the published props.
71
+ - Controlled/uncontrolled behavior: not applicable; the component stores no
72
+ delivery state.
73
+ - Migration decision: none. Existing callers need no new option.
74
+
75
+ Consumer migration instructions, when needed, belong in release notes rather
76
+ than this record.
77
+
78
+ ## Ownership boundary
79
+
80
+ **Owns**
81
+
82
+ - The optional metadata root, its `chat-message-metadata` painting target,
83
+ ref, neutral DOM passthrough, and composed styling inputs.
84
+ - Presence checks and separators among timestamp, footer, and status.
85
+ - Sender-relative row order from the nearest Chat message context, with an
86
+ assistant fallback outside that context.
87
+ - Status-to-glyph and translated-caption selection and the local sending/error
88
+ paint path.
89
+
90
+ **Does not own / non-goals**
91
+
92
+ - Sender identity, article semantics, avatar, name, and body alignment:
93
+ `ChatMessage` owns these.
94
+ - Bubble inset and placement: `ChatMessageBubble` owns these.
95
+ - Footer action semantics, button focus, and callback behavior: the caller's
96
+ supplied content owns them.
97
+ - Transcript scrolling, loading, or delivery-state transitions: the surrounding
98
+ composition owns these.
99
+ - A new public rule for inspecting composite, lazy, or asynchronous ReactNode
100
+ values, or a screen-reader announcement-timing guarantee.
101
+
102
+ ## Public concepts
103
+
104
+ | Concept | Closed values or states | Observed meaning | Availability | Default | Owner | Stability | Invalid-value behavior |
105
+ | -------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------- | ----------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------- |
106
+ | `timestamp` | Omitted or caller ReactNode | Optional first item, normally a time | Any composition | Omitted | Caller | Released | Null, booleans, and empty string do not render a scalar slot; `0` renders; non-scalars remain opaque |
107
+ | `footer` | Omitted or caller ReactNode | Optional middle item such as model information or caller controls | Any composition | Omitted | Caller | Released | Same scalar treatment as timestamp |
108
+ | `status` | `sending`, `sent`, `delivered`, `read`, `error`, omitted | Optional delivery caption and glyph | Any composition | Omitted | Component/caller input | Released | Closed type union; omitted contributes no item |
109
+ | Sender context | `user`, `assistant`, `system`, absent | Selects user-reversed or other forward row order | Within `ChatMessage` or standalone | Assistant when absent | `ChatMessage` / local fallback | Observational | Non-user values share the forward path |
110
+ | Root surface | `BaseProps<HTMLDivElement>`, `ref`, `xstyle`, `className`, `style` | Extends the metadata row when it exists | Slot passes scalar-presence check or status present | Absent for empty scalar slots and no status | `architecture:public-component-api` | Released | Non-scalar values remain opaque; target and consumer styles combine |
111
+
112
+ ## Behavioral and layout contract
113
+
114
+ The following candidate invariants name their evidence. They are observations
115
+ for review, not current product policy created by this draft.
116
+
117
+ | ID | Candidate invariant | Basis | Draft review state |
118
+ | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------ |
119
+ | FR1 | The root appears when at least one slot passes the shared scalar-presence predicate or `status` is present. Non-scalar values are treated as present without inspecting their inner content. | Public ReactNode seam, shared `isRenderable` scalar utility, focused red/green and browser evidence | Verify correction |
120
+ | FR2 | Accepted slot values render in timestamp, footer, status order with dots between values considered present; numeric `0` is visible in either slot, and non-scalar nodes remain opaque. | Shipped ordering, shared scalar utility, focused tests, light/dark browser cases | Verify correction |
121
+ | FR3 | A `user` message reverses row direction; `assistant`, `system`, and absent context use the forward path. | Source, Chat context, sender and RTL browser fixtures | Verify observation |
122
+ | FR4 | Status selects one of five registry icons and localized labels; failure uses the error text token, and sending has a CSS pulse suppressed under reduced motion. | Source, locale catalog, owned browser status matrix | Verify observation |
123
+ | FR5 | The root merges the target, default StyleX output, and consumer `xstyle`, `className`, and `style`; accepted neutral DOM/ARIA inputs and `ref` reach that root. | Source, public API authority, existing passthrough test | Verify observation |
124
+ | FR6 | A status item has a translated title and author-supplied `aria-label`, an icon and visible localized text. The row declares no live-region role or imperative announcement. | Source, DOM tests and axe fixtures; no real-AT timing claim | Verify observation |
125
+
126
+ ### Allowed variation
127
+
128
+ - **AV1 - Slot content.** The caller decides the structure and semantics inside
129
+ timestamp and footer slots. This component does not inspect non-scalar nodes.
130
+ - **AV2 - Theme.** Semantic colors, typography, and spacing resolve through the
131
+ active Theme; the root remains the public metadata painting target.
132
+ - **AV3 - Context.** Standalone use takes the assistant ordering fallback.
133
+
134
+ ### Representative states
135
+
136
+ | State | Observed result | Allowed variation |
137
+ | --------------------------- | --------------------------------------------------------------------------- | -------------------------------------- |
138
+ | Standalone timestamp | One root and one visible item | Caller content |
139
+ | User or assistant message | Sender-relative row order | Text direction inherited from the page |
140
+ | Timestamp + footer + status | Items separated according to scalar presence; composite nodes remain opaque | Caller footer content |
141
+ | Each delivery status | Distinct localized caption and mapped icon | Active translation and theme tokens |
142
+ | Non-rendering scalar slots | No stranded dot; no row when all items are empty | Composite nodes remain opaque |
143
+ | Numeric `0` | Visible content, not an empty marker | Either slot |
144
+ | Long footer at narrow width | Content reflows within its container | Caller text may wrap |
145
+
146
+ ### Transformation and precedence order
147
+
148
+ - **ORD1 - Presence before separators.** Decide scalar presence with the shared
149
+ predicate while treating non-scalar caller nodes as opaque, then place
150
+ punctuation between values considered present. The status check remains
151
+ independent of the slot checks.
152
+ - **ORD2 - Composition.** Resolve sender context, select flex order, and compose
153
+ component StyleX and theme target with consumer styling inputs on one root.
154
+
155
+ ### Performance and resources
156
+
157
+ - **PR1 - Render derivation.** The component creates no local React state,
158
+ Effects, timers, observer, or event listeners. Its local animation is CSS and
159
+ suppressed for reduced motion.
160
+
161
+ ## Accessibility contract
162
+
163
+ - **AR1 - Display semantics.** The metadata line does not add a button, focus
164
+ target, list role, or live region of its own. Interactive footer content retains
165
+ its own semantics and keyboard behavior.
166
+ - **AR2 - Visible delivery state.** The status caption accompanies the glyph so
167
+ state identification does not rely on color or the icon alone.
168
+ - **AR3 - Evidence boundary.** Browser-exposed markup and axe coverage do not
169
+ establish spoken output or announcement timing; any such future claim follows
170
+ `spec:AST-009` and its named AT evidence rule.
171
+
172
+ ## Design relationships
173
+
174
+ | Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
175
+ | ---------------- | ---------------------------------------------------------------- | -------------------------------------------- | -------------- | ------------------ |
176
+ | Metadata row | Semantic supporting typography and sender-relative reading order | Local representation unsettled | Supporting | FR2–FR3 |
177
+ | Delivery status | Registry glyph, caption, and semantic error token | Local prominence and motion choice unsettled | Supporting | FR4, AR2 |
178
+
179
+ No current component-local ChatMessageMetadata design decision is introduced.
180
+ The draft `design:motion` and `design:system-states` records are not adopted as
181
+ current authority by this record.
182
+
183
+ ## Family and system relationships
184
+
185
+ - There is no current `family:chat` product-authority record. `Chat.doc.mjs` is
186
+ consumer composition guidance, not a family contract.
187
+ - `architecture:public-component-api` owns root export and passthrough;
188
+ `architecture:component-theming-surface` owns the public painting target;
189
+ `architecture:component-test-sufficiency` owns bounded evidence coverage.
190
+ - `spec:AST-029` keeps the closed audit inventory and score outside this
191
+ component draft.
192
+
193
+ ## Verification map
194
+
195
+ | Contract | Evidence | Representative states | Mutation or failure expectation | Audit section |
196
+ | ------------ | ------------------------------------------------------ | ------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------- |
197
+ | FR1–FR2 | `ChatMessageMetadata.test.tsx`; Chromium receipts | empty scalar, zero, timestamp/footer/status | A nullish-only guard reintroduces a stray separator or blank row | `audit:ChatMessageMetadata/behavior` |
198
+ | FR3 | Storybook sender fixtures and Chromium RTL frames | user, assistant, standalone in LTR/RTL | Wrong relative ordering becomes visible | `audit:ChatMessageMetadata/rtl` |
199
+ | FR4, AR2 | Status fixtures, locale catalog, Chromium/axe receipts | five statuses, light/dark, reduced motion | A dropped status label or failed theme paint is visible | `audit:ChatMessageMetadata/accessibility` |
200
+ | FR5 | Existing passthrough test and theming-target guard | DOM/data/ARIA and styling | Root drops accepted caller inputs or target | `audit:ChatMessageMetadata/public-api` |
201
+ | FR6, AR1–AR3 | Axe and browser semantic receipts | static status and caller button | Missing text/icon or falsely claimed AT timing remains detectable | `audit:ChatMessageMetadata/testing` |
202
+
203
+ ## Decision log
204
+
205
+ None. This draft makes no new component-local product decision.
206
+
207
+ ## Open questions
208
+
209
+ - **OQ1 - Should non-scalar ReactNode slots ever be normalized for emptiness?**
210
+ (`human-api`) Arrays, Fragments, lazy content, and promises remain opaque under
211
+ the existing scalar predicate; this audit does not consume or inspect them.
212
+ - **OQ2 - Should standalone delivery-status changes be announced, and if so by
213
+ which owner?** (`human-api`) The current row is display-only. No spoken-timing
214
+ claim is made without a current owner and applicable AT evidence.
215
+
216
+ ## Content boundary
217
+
218
+ This record does not store an audit score, screenshot manifest, CI transcript,
219
+ consumer prop example, new public API, or shared visual policy. Those remain in
220
+ the audit PR evidence, consumer docs, and their canonical owners.
@@ -29,4 +29,38 @@ describe('ChatMessageMetadata', () => {
29
29
  expect(root).toHaveAttribute('data-custom', 'x');
30
30
  expect(root).toHaveAttribute('id', 'meta-1');
31
31
  });
32
+
33
+ it('omits separators when a footer slot has no rendered content', () => {
34
+ render(
35
+ <ChatMessageMetadata
36
+ timestamp="10:32"
37
+ footer={false}
38
+ data-testid="meta"
39
+ />,
40
+ );
41
+ expect(screen.getByTestId('meta')).toHaveTextContent('10:32');
42
+ expect(screen.getByTestId('meta')).not.toHaveTextContent('·');
43
+ });
44
+
45
+ it('omits an empty timestamp and the row when both slots are empty', () => {
46
+ const {rerender} = render(
47
+ <ChatMessageMetadata
48
+ timestamp={false}
49
+ footer="Model info"
50
+ data-testid="meta"
51
+ />,
52
+ );
53
+ expect(screen.getByTestId('meta')).toHaveTextContent('Model info');
54
+ expect(screen.getByTestId('meta')).not.toHaveTextContent('·');
55
+
56
+ rerender(
57
+ <ChatMessageMetadata timestamp="" footer={false} data-testid="meta" />,
58
+ );
59
+ expect(screen.queryByTestId('meta')).not.toBeInTheDocument();
60
+ });
61
+
62
+ it('keeps numeric zero in both visible slots', () => {
63
+ render(<ChatMessageMetadata timestamp={0} footer={0} data-testid="meta" />);
64
+ expect(screen.getByTestId('meta')).toHaveTextContent('0·0');
65
+ });
32
66
  });
@@ -4,12 +4,12 @@
4
4
 
5
5
  /**
6
6
  * @file ChatMessageMetadata.tsx
7
- * @input Uses React, StyleX, ChatContext, Icon, theme tokens
7
+ * @input Uses React, StyleX, ChatContext, Icon, theme tokens, and isRenderable
8
8
  * @output Exports ChatMessageMetadata component
9
9
  * @position Shared metadata row used by composing inside ChatMessage
10
10
  *
11
- * Renders: <timestamp> · <footer> · <status>
12
- * Direction reverses for user sender.
11
+ * Renders timestamp, footer, and status values with separators determined by
12
+ * scalar presence. Direction reverses for user sender.
13
13
  */
14
14
 
15
15
  import React, {type ReactNode} from 'react';
@@ -23,7 +23,7 @@ import {
23
23
  import {useChatMessageContext} from './ChatContext';
24
24
  import {Icon} from '../Icon';
25
25
  import type {IconName} from '../Icon/globalIconRegistry';
26
- import {mergeProps} from '../utils';
26
+ import {isRenderable, mergeProps} from '../utils';
27
27
  import type {BaseProps} from '../BaseProps';
28
28
  import {themeProps} from '../utils/themeProps';
29
29
  import {useTranslator} from '../i18n';
@@ -97,7 +97,8 @@ export interface ChatMessageMetadataProps extends BaseProps<HTMLDivElement> {
97
97
  * Composable metadata row for chat messages.
98
98
  *
99
99
  * Renders: timestamp · footer · status
100
- * Renders nothing if all props are null/undefined.
100
+ * Renders nothing when neither slot passes the scalar-presence check and no
101
+ * status is set. Composite React nodes remain caller-owned.
101
102
  *
102
103
  * @example
103
104
  * ```
@@ -124,8 +125,9 @@ export function ChatMessageMetadata({
124
125
  const statusConfig = status != null ? STATUS_CONFIG[status] : null;
125
126
  const statusLabel = statusConfig != null ? t(statusConfig.i18nKey) : '';
126
127
 
127
- const hasContent =
128
- timestamp != null || footer != null || statusConfig != null;
128
+ const hasTimestamp = isRenderable(timestamp);
129
+ const hasFooter = isRenderable(footer);
130
+ const hasContent = hasTimestamp || hasFooter || statusConfig != null;
129
131
  if (!hasContent) {
130
132
  return null;
131
133
  }
@@ -144,12 +146,10 @@ export function ChatMessageMetadata({
144
146
  style,
145
147
  )}
146
148
  {...rest}>
147
- {timestamp != null && <span>{timestamp}</span>}
148
- {timestamp != null && (footer != null || statusConfig != null) && (
149
- <span>·</span>
150
- )}
151
- {footer != null && footer}
152
- {footer != null && statusConfig != null && <span>·</span>}
149
+ {hasTimestamp && <span>{timestamp}</span>}
150
+ {hasTimestamp && (hasFooter || statusConfig != null) && <span>·</span>}
151
+ {hasFooter && footer}
152
+ {hasFooter && statusConfig != null && <span>·</span>}
153
153
  {statusConfig != null && (
154
154
  <span
155
155
  title={statusLabel}
@@ -180,10 +180,7 @@ describe('ChatSendButton', () => {
180
180
  expect(send).toBeEnabled();
181
181
 
182
182
  fireEvent.click(send);
183
- // Only that the click reaches the composer's submit path is this
184
- // button's behavior. The submitted value comes from the composer's own
185
- // state, not from here, so asserting it would pin ChatComposer instead.
186
- expect(onSubmit).toHaveBeenCalledTimes(1);
183
+ expect(onSubmit).toHaveBeenCalledWith('hello');
187
184
  });
188
185
  });
189
186
  });
@@ -95,7 +95,7 @@ export function ChatSendButton(props: ChatSendButtonProps): ReactNode {
95
95
  ...rest
96
96
  } = props;
97
97
 
98
- const handleSend = onSend ?? (() => context?.onSubmit(''));
98
+ const handleSend = onSend ?? (() => context?.onSubmit(context.value));
99
99
  const defaultStopIcon = useIcon('stop');
100
100
  const defaultSendIcon = useIcon('arrowUp');
101
101