@astryxdesign/core 0.6.2 → 0.6.3-canary.039a67e

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 (621) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/dist/Avatar/Avatar.d.ts.map +1 -1
  3. package/dist/Avatar/Avatar.js +33 -12
  4. package/dist/BottomSheet/BottomSheet.d.ts +1 -1
  5. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  6. package/dist/BottomSheet/BottomSheet.js +3 -1
  7. package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
  8. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  9. package/dist/BottomSheet/BottomSheetPanel.js +56 -19
  10. package/dist/Button/Button.d.ts.map +1 -1
  11. package/dist/Button/Button.js +13 -28
  12. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  13. package/dist/Chat/ChatComposer.js +10 -5
  14. package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
  15. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  16. package/dist/Chat/ChatComposerDrawer.js +48 -23
  17. package/dist/Chat/ChatComposerInput.d.ts +11 -3
  18. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  19. package/dist/Chat/ChatComposerInput.js +63 -16
  20. package/dist/Chat/ChatDictationButton.d.ts +3 -2
  21. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  22. package/dist/Chat/ChatDictationButton.js +6 -4
  23. package/dist/Chat/ChatLayout.d.ts +19 -0
  24. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  25. package/dist/Chat/ChatLayout.js +19 -0
  26. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  27. package/dist/Chat/ChatLayoutScrollButton.js +44 -34
  28. package/dist/Chat/ChatMessageBubble.d.ts +2 -0
  29. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  30. package/dist/Chat/ChatMessageBubble.js +5 -3
  31. package/dist/Chat/ChatMessageList.d.ts +2 -1
  32. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  33. package/dist/Chat/ChatMessageList.js +4 -3
  34. package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
  35. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  36. package/dist/Chat/ChatMessageMetadata.js +12 -9
  37. package/dist/Chat/ChatSendButton.d.ts +2 -1
  38. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  39. package/dist/Chat/ChatSendButton.js +6 -4
  40. package/dist/Chat/ChatSystemMessage.d.ts +3 -3
  41. package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
  42. package/dist/Chat/ChatSystemMessage.js +2 -2
  43. package/dist/Chat/ChatTokenizedText.d.ts +6 -6
  44. package/dist/Chat/ChatTokenizedText.js +10 -6
  45. package/dist/Chat/ChatToolCalls.d.ts +7 -9
  46. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  47. package/dist/Chat/ChatToolCalls.js +43 -26
  48. package/dist/Chat/index.d.ts +1 -1
  49. package/dist/Chat/index.d.ts.map +1 -1
  50. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  51. package/dist/CheckboxInput/CheckboxInput.js +12 -2
  52. package/dist/Citation/Citation.d.ts +1 -1
  53. package/dist/Citation/Citation.d.ts.map +1 -1
  54. package/dist/Citation/Citation.js +3 -2
  55. package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
  56. package/dist/CodeBlock/highlightRanges.js +14 -3
  57. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  58. package/dist/Collapsible/Collapsible.js +6 -1
  59. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  60. package/dist/CommandPalette/CommandPaletteInput.js +1 -1
  61. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  62. package/dist/ComplexSelector/ComplexSelector.js +1 -1
  63. package/dist/DateInput/DateInput.d.ts +25 -5
  64. package/dist/DateInput/DateInput.d.ts.map +1 -1
  65. package/dist/DateInput/DateInput.js +29 -17
  66. package/dist/DateInput/NativeDateField.d.ts.map +1 -1
  67. package/dist/DateInput/NativeDateField.js +16 -16
  68. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  69. package/dist/DateInput/TouchDateField.js +2 -2
  70. package/dist/DateInput/index.d.ts +1 -1
  71. package/dist/DateInput/index.d.ts.map +1 -1
  72. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  73. package/dist/DateRangeInput/DateRangeInput.js +4 -4
  74. package/dist/DateTimeInput/DateTimeInput.d.ts +32 -15
  75. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  76. package/dist/DateTimeInput/DateTimeInput.js +55 -30
  77. package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
  78. package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
  79. package/dist/DateTimeInput/index.d.ts +1 -1
  80. package/dist/DateTimeInput/index.d.ts.map +1 -1
  81. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
  82. package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
  83. package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
  84. package/dist/Dialog/DialogHeader.d.ts +8 -1
  85. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  86. package/dist/Dialog/DialogHeader.js +13 -4
  87. package/dist/Field/InputClearButton.d.ts +4 -2
  88. package/dist/Field/InputClearButton.d.ts.map +1 -1
  89. package/dist/Field/InputClearButton.js +4 -2
  90. package/dist/Field/PanelSearchInput.d.ts.map +1 -1
  91. package/dist/Field/PanelSearchInput.js +1 -1
  92. package/dist/FileInput/FileInput.d.ts.map +1 -1
  93. package/dist/FileInput/FileInput.js +7 -7
  94. package/dist/Icon/Icon.d.ts +6 -31
  95. package/dist/Icon/Icon.d.ts.map +1 -1
  96. package/dist/Icon/Icon.js +8 -71
  97. package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
  98. package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
  99. package/dist/Icon/IconDefaultSizeContext.js +18 -0
  100. package/dist/Icon/IconSize.stylex.d.ts +65 -0
  101. package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
  102. package/dist/Icon/IconSize.stylex.js +75 -0
  103. package/dist/Item/Item.d.ts +1 -1
  104. package/dist/Item/Item.d.ts.map +1 -1
  105. package/dist/Item/Item.js +4 -3
  106. package/dist/Kbd/Kbd.d.ts +5 -3
  107. package/dist/Kbd/Kbd.d.ts.map +1 -1
  108. package/dist/Kbd/Kbd.js +36 -42
  109. package/dist/Link/Link.d.ts.map +1 -1
  110. package/dist/Link/Link.js +6 -2
  111. package/dist/Link/useLinkComponent.d.ts +5 -15
  112. package/dist/Link/useLinkComponent.d.ts.map +1 -1
  113. package/dist/Link/useLinkComponent.js +34 -51
  114. package/dist/List/List.d.ts +19 -1
  115. package/dist/List/List.d.ts.map +1 -1
  116. package/dist/List/List.js +9 -2
  117. package/dist/List/ListContext.d.ts +1 -0
  118. package/dist/List/ListContext.d.ts.map +1 -1
  119. package/dist/List/ListContext.js +2 -1
  120. package/dist/List/ListItem.d.ts +1 -1
  121. package/dist/List/ListItem.d.ts.map +1 -1
  122. package/dist/List/ListItem.js +9 -2
  123. package/dist/Markdown/Markdown.d.ts +8 -2
  124. package/dist/Markdown/Markdown.d.ts.map +1 -1
  125. package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
  126. package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
  127. package/dist/Markdown/Markdown.fr23.bench.js +150 -0
  128. package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
  129. package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
  130. package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
  131. package/dist/Markdown/Markdown.js +262 -109
  132. package/dist/Markdown/ast.d.ts +162 -0
  133. package/dist/Markdown/ast.d.ts.map +1 -0
  134. package/dist/Markdown/ast.js +74 -0
  135. package/dist/Markdown/index.d.ts +5 -3
  136. package/dist/Markdown/index.d.ts.map +1 -1
  137. package/dist/Markdown/index.js +3 -2
  138. package/dist/Markdown/parser/index.d.ts +10 -0
  139. package/dist/Markdown/parser/index.d.ts.map +1 -0
  140. package/dist/Markdown/parser/index.js +10 -0
  141. package/dist/Markdown/parser.d.ts +126 -58
  142. package/dist/Markdown/parser.d.ts.map +1 -1
  143. package/dist/Markdown/parser.js +726 -177
  144. package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
  145. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
  146. package/dist/Markdown/plugins/frontmatter.js +132 -0
  147. package/dist/Markdown/plugins/index.d.ts +17 -0
  148. package/dist/Markdown/plugins/index.d.ts.map +1 -0
  149. package/dist/Markdown/plugins/index.js +14 -0
  150. package/dist/Markdown/plugins/protocol.d.ts +191 -0
  151. package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
  152. package/dist/Markdown/plugins/protocol.js +957 -0
  153. package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
  154. package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
  155. package/dist/Markdown/plugins/semanticFence.js +213 -0
  156. package/dist/Markdown/plugins/softBreaks.d.ts +3 -0
  157. package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
  158. package/dist/Markdown/plugins/softBreaks.js +172 -0
  159. package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
  160. package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
  161. package/dist/Markdown/plugins/sourceDecoration.js +393 -0
  162. package/dist/Markdown/plugins/textTransform.d.ts +30 -0
  163. package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
  164. package/dist/Markdown/plugins/textTransform.js +374 -0
  165. package/dist/Markdown/remark.d.ts +196 -0
  166. package/dist/Markdown/remark.d.ts.map +1 -0
  167. package/dist/Markdown/remark.js +1062 -0
  168. package/dist/Markdown/url.d.ts +6 -0
  169. package/dist/Markdown/url.d.ts.map +1 -0
  170. package/dist/Markdown/url.js +31 -0
  171. package/dist/Markdown/utils.d.ts +4 -2
  172. package/dist/Markdown/utils.d.ts.map +1 -1
  173. package/dist/Markdown/utils.js +2 -1
  174. package/dist/MetadataList/MetadataList.js +3 -3
  175. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  176. package/dist/NumberInput/NumberInput.js +4 -4
  177. package/dist/Outline/index.d.ts +1 -0
  178. package/dist/Outline/index.d.ts.map +1 -1
  179. package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
  180. package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
  181. package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
  182. package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
  183. package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
  184. package/dist/Outline/useOutlineFromMarkdown.js +8 -3
  185. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  186. package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
  187. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  188. package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
  189. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  190. package/dist/ProgressBar/ProgressBar.js +36 -31
  191. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  192. package/dist/RadioList/RadioListItem.js +13 -1
  193. package/dist/ScrollableArea/ScrollableArea.d.ts +1 -0
  194. package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
  195. package/dist/ScrollableArea/ScrollableArea.js +1 -0
  196. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  197. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  198. package/dist/SegmentedControl/SegmentedControl.js +1 -0
  199. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  200. package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
  201. package/dist/Selector/Selector.d.ts +9 -7
  202. package/dist/Selector/Selector.d.ts.map +1 -1
  203. package/dist/Selector/Selector.js +16 -7
  204. package/dist/SideNav/SideNav.d.ts +2 -1
  205. package/dist/SideNav/SideNav.d.ts.map +1 -1
  206. package/dist/SideNav/SideNav.js +9 -3
  207. package/dist/Slider/Slider.d.ts.map +1 -1
  208. package/dist/Slider/Slider.js +28 -12
  209. package/dist/Spinner/Spinner.d.ts.map +1 -1
  210. package/dist/Spinner/Spinner.js +23 -7
  211. package/dist/Switch/Switch.d.ts.map +1 -1
  212. package/dist/Switch/Switch.js +11 -0
  213. package/dist/TabList/Tab.d.ts +1 -1
  214. package/dist/TabList/Tab.d.ts.map +1 -1
  215. package/dist/TabList/Tab.js +20 -7
  216. package/dist/Table/Table.d.ts +1 -0
  217. package/dist/Table/Table.d.ts.map +1 -1
  218. package/dist/Table/Table.js +29 -13
  219. package/dist/TextArea/TextArea.d.ts.map +1 -1
  220. package/dist/TextArea/TextArea.js +1 -1
  221. package/dist/TextInput/TextInput.d.ts.map +1 -1
  222. package/dist/TextInput/TextInput.js +2 -2
  223. package/dist/TimeInput/TimeInput.d.ts +30 -14
  224. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  225. package/dist/TimeInput/TimeInput.js +61 -13
  226. package/dist/TimeInput/TouchTimeField.d.ts +11 -0
  227. package/dist/TimeInput/TouchTimeField.d.ts.map +1 -0
  228. package/dist/TimeInput/TouchTimeField.js +417 -0
  229. package/dist/TimeInput/index.d.ts +1 -1
  230. package/dist/TimeInput/index.d.ts.map +1 -1
  231. package/dist/Timer/Timer.d.ts +49 -0
  232. package/dist/Timer/Timer.d.ts.map +1 -0
  233. package/dist/Timer/Timer.js +158 -0
  234. package/dist/Timer/index.d.ts +9 -0
  235. package/dist/Timer/index.d.ts.map +1 -0
  236. package/dist/Timer/index.js +10 -0
  237. package/dist/ToggleButton/ToggleButton.d.ts +9 -6
  238. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  239. package/dist/ToggleButton/ToggleButton.js +15 -27
  240. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  241. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  242. package/dist/TopNav/TopNavMenu.js +3 -2
  243. package/dist/TreeList/TreeList.d.ts.map +1 -1
  244. package/dist/TreeList/TreeList.js +3 -0
  245. package/dist/TreeList/TreeListItem.d.ts +6 -1
  246. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  247. package/dist/TreeList/TreeListItem.js +12 -2
  248. package/dist/TreeList/TreeListTypes.d.ts +8 -1
  249. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  250. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  251. package/dist/Typeahead/BaseTypeahead.js +16 -7
  252. package/dist/astryx.css +27 -11
  253. package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
  254. package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
  255. package/dist/hooks/scrollKeyboardDelegation.js +146 -0
  256. package/dist/hooks/useClickableContainer.d.ts +10 -1
  257. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  258. package/dist/hooks/useClickableContainer.js +15 -4
  259. package/dist/hooks/useScrollableArea.d.ts +6 -2
  260. package/dist/hooks/useScrollableArea.d.ts.map +1 -1
  261. package/dist/hooks/useScrollableArea.js +17 -5
  262. package/dist/index.d.ts +1 -0
  263. package/dist/index.d.ts.map +1 -1
  264. package/dist/index.js +3 -0
  265. package/dist/theme/declarationBoundary.d.ts +17 -0
  266. package/dist/theme/declarationBoundary.d.ts.map +1 -0
  267. package/dist/theme/declarationBoundary.js +343 -0
  268. package/dist/theme/defineTheme.d.ts +3 -0
  269. package/dist/theme/defineTheme.d.ts.map +1 -1
  270. package/dist/theme/defineTheme.js +4 -1
  271. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  272. package/dist/theme/derivedVarRegistry.js +4 -0
  273. package/dist/theme/generateThemeRules.d.ts +15 -7
  274. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  275. package/dist/theme/generateThemeRules.js +143 -35
  276. package/dist/theme/themeAdaptations.d.ts +5 -3
  277. package/dist/theme/themeAdaptations.d.ts.map +1 -1
  278. package/dist/theme/themeAdaptations.js +33 -5
  279. package/dist/utils/inputPresentation.d.ts +55 -0
  280. package/dist/utils/inputPresentation.d.ts.map +1 -0
  281. package/dist/utils/inputPresentation.js +108 -0
  282. package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
  283. package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
  284. package/dist/utils/interactionOverlay.stylex.js +9 -0
  285. package/dist/utils/safeUrl.d.ts +11 -0
  286. package/dist/utils/safeUrl.d.ts.map +1 -0
  287. package/dist/utils/safeUrl.js +78 -0
  288. package/locales/af-ZA.json +530 -1
  289. package/locales/ar-SA.json +490 -1
  290. package/locales/ca-ES.json +514 -1
  291. package/locales/cs-CZ.json +498 -1
  292. package/locales/da-DK.json +522 -1
  293. package/locales/de-DE.json +522 -1
  294. package/locales/el-GR.json +498 -1
  295. package/locales/es-ES.json +510 -1
  296. package/locales/fi-FI.json +498 -1
  297. package/locales/fr-FR.json +534 -1
  298. package/locales/he-IL.json +498 -1
  299. package/locales/hu-HU.json +498 -1
  300. package/locales/it-IT.json +510 -1
  301. package/locales/ja-JP.json +490 -1
  302. package/locales/ko-KR.json +498 -1
  303. package/locales/nl-NL.json +534 -1
  304. package/locales/no-NO.json +510 -1
  305. package/locales/pl-PL.json +506 -1
  306. package/locales/pt-BR.json +506 -1
  307. package/locales/pt-PT.json +506 -1
  308. package/locales/ro-RO.json +506 -1
  309. package/locales/ru-RU.json +498 -1
  310. package/locales/sr-SP.json +498 -1
  311. package/locales/sv-SE.json +502 -1
  312. package/locales/tr-TR.json +498 -1
  313. package/locales/uk-UA.json +498 -1
  314. package/locales/vi-VN.json +502 -1
  315. package/locales/zh-CN.json +490 -1
  316. package/locales/zh-TW.json +490 -1
  317. package/package.json +24 -4
  318. package/src/Avatar/Avatar.doc.mjs +1 -1
  319. package/src/Avatar/Avatar.test.tsx +30 -0
  320. package/src/Avatar/Avatar.tsx +38 -14
  321. package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
  322. package/src/BottomSheet/BottomSheet.spec.md +46 -20
  323. package/src/BottomSheet/BottomSheet.test.tsx +6 -3
  324. package/src/BottomSheet/BottomSheet.tsx +3 -1
  325. package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
  326. package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
  327. package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
  328. package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
  329. package/src/Button/Button.doc.mjs +5 -5
  330. package/src/Button/Button.tsx +15 -13
  331. package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
  332. package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
  333. package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
  334. package/src/Button/__tests__/Button.a11y.states.ts +9 -0
  335. package/src/Chat/ChatComposer.doc.mjs +14 -0
  336. package/src/Chat/ChatComposer.spec.md +230 -0
  337. package/src/Chat/ChatComposer.test.tsx +57 -0
  338. package/src/Chat/ChatComposer.tsx +21 -9
  339. package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
  340. package/src/Chat/ChatComposerDrawer.spec.md +267 -0
  341. package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
  342. package/src/Chat/ChatComposerDrawer.tsx +38 -9
  343. package/src/Chat/ChatComposerInput.doc.mjs +114 -26
  344. package/src/Chat/ChatComposerInput.spec.md +185 -0
  345. package/src/Chat/ChatComposerInput.test.tsx +113 -3
  346. package/src/Chat/ChatComposerInput.tsx +78 -13
  347. package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
  348. package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
  349. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  350. package/src/Chat/ChatDictationButton.spec.md +160 -0
  351. package/src/Chat/ChatDictationButton.test.tsx +92 -27
  352. package/src/Chat/ChatDictationButton.tsx +8 -6
  353. package/src/Chat/ChatLayout.doc.mjs +12 -4
  354. package/src/Chat/ChatLayout.spec.md +271 -0
  355. package/src/Chat/ChatLayout.test.tsx +28 -0
  356. package/src/Chat/ChatLayout.tsx +19 -0
  357. package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
  358. package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
  359. package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
  360. package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
  361. package/src/Chat/ChatMessageBubble.spec.md +263 -0
  362. package/src/Chat/ChatMessageBubble.test.tsx +93 -0
  363. package/src/Chat/ChatMessageBubble.tsx +8 -3
  364. package/src/Chat/ChatMessageList.spec.md +222 -0
  365. package/src/Chat/ChatMessageList.test.tsx +64 -2
  366. package/src/Chat/ChatMessageList.tsx +4 -3
  367. package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
  368. package/src/Chat/ChatMessageMetadata.spec.md +220 -0
  369. package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
  370. package/src/Chat/ChatMessageMetadata.tsx +13 -13
  371. package/src/Chat/ChatSendButton.doc.mjs +32 -0
  372. package/src/Chat/ChatSendButton.spec.md +227 -0
  373. package/src/Chat/ChatSendButton.test.tsx +128 -8
  374. package/src/Chat/ChatSendButton.tsx +6 -4
  375. package/src/Chat/ChatSystemMessage.doc.mjs +115 -12
  376. package/src/Chat/ChatSystemMessage.spec.md +225 -0
  377. package/src/Chat/ChatSystemMessage.test.tsx +112 -20
  378. package/src/Chat/ChatSystemMessage.tsx +4 -6
  379. package/src/Chat/ChatTokenizedText.doc.mjs +96 -9
  380. package/src/Chat/ChatTokenizedText.spec.md +190 -0
  381. package/src/Chat/ChatTokenizedText.test.tsx +60 -1
  382. package/src/Chat/ChatTokenizedText.tsx +14 -8
  383. package/src/Chat/ChatToolCalls.doc.mjs +4 -1
  384. package/src/Chat/ChatToolCalls.spec.md +194 -0
  385. package/src/Chat/ChatToolCalls.test.tsx +83 -0
  386. package/src/Chat/ChatToolCalls.tsx +46 -21
  387. package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
  388. package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
  389. package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
  390. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
  391. package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
  392. package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
  393. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
  394. package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1522 -0
  395. package/src/Chat/__tests__/ChatSystemMessage.a11y.chromium.spec.ts +1004 -0
  396. package/src/Chat/__tests__/ChatTokenizedText.a11y.chromium.spec.ts +573 -0
  397. package/src/Chat/index.ts +1 -0
  398. package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
  399. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  400. package/src/CheckboxInput/CheckboxInput.tsx +21 -1
  401. package/src/Citation/Citation.doc.mjs +2 -2
  402. package/src/Citation/Citation.test.tsx +17 -0
  403. package/src/Citation/Citation.tsx +4 -2
  404. package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
  405. package/src/ClickableCard/ClickableCard.test.tsx +102 -5
  406. package/src/CodeBlock/highlightRanges.test.ts +143 -1
  407. package/src/CodeBlock/highlightRanges.ts +15 -5
  408. package/src/Collapsible/Collapsible.doc.mjs +11 -0
  409. package/src/Collapsible/Collapsible.test.tsx +21 -0
  410. package/src/Collapsible/Collapsible.tsx +5 -0
  411. package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
  412. package/src/ComplexSelector/ComplexSelector.tsx +6 -1
  413. package/src/DateInput/DateInput.doc.mjs +38 -9
  414. package/src/DateInput/DateInput.tsx +59 -17
  415. package/src/DateInput/NativeDateField.tsx +24 -8
  416. package/src/DateInput/Presentation.test.tsx +121 -0
  417. package/src/DateInput/TouchDateField.tsx +6 -2
  418. package/src/DateInput/index.ts +1 -0
  419. package/src/DateRangeInput/DateRangeInput.tsx +6 -1
  420. package/src/DateTimeInput/DateTimeInput.doc.mjs +28 -12
  421. package/src/DateTimeInput/DateTimeInput.tsx +93 -37
  422. package/src/DateTimeInput/Presentation.test.tsx +89 -0
  423. package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
  424. package/src/DateTimeInput/index.ts +1 -0
  425. package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
  426. package/src/Dialog/Dialog.doc.mjs +2 -0
  427. package/src/Dialog/DialogHeader.doc.mjs +22 -0
  428. package/src/Dialog/DialogHeader.test.tsx +167 -3
  429. package/src/Dialog/DialogHeader.tsx +37 -6
  430. package/src/Dialog/modules/DialogHeader.spec.md +101 -42
  431. package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
  432. package/src/Field/InputClearButton.test.tsx +17 -3
  433. package/src/Field/InputClearButton.tsx +5 -2
  434. package/src/Field/PanelSearchInput.tsx +5 -2
  435. package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
  436. package/src/FileInput/FileInput.tsx +11 -2
  437. package/src/Icon/Icon.doc.mjs +7 -5
  438. package/src/Icon/Icon.spec.md +81 -40
  439. package/src/Icon/Icon.test.tsx +6 -3
  440. package/src/Icon/Icon.tsx +20 -68
  441. package/src/Icon/IconDefaultSizeContext.ts +23 -0
  442. package/src/Icon/IconSize.stylex.ts +70 -0
  443. package/src/IconButton/IconButton.doc.mjs +3 -3
  444. package/src/IconButton/IconButton.test.tsx +40 -0
  445. package/src/Item/Item.doc.mjs +6 -2
  446. package/src/Item/Item.tsx +9 -3
  447. package/src/Kbd/Kbd.doc.mjs +3 -3
  448. package/src/Kbd/Kbd.test.tsx +57 -1
  449. package/src/Kbd/Kbd.tsx +57 -37
  450. package/src/Layout/LayoutFooter.doc.mjs +17 -0
  451. package/src/Link/Link.doc.mjs +17 -4
  452. package/src/Link/Link.test.tsx +24 -0
  453. package/src/Link/Link.tsx +5 -0
  454. package/src/Link/LinkProvider.doc.mjs +2 -2
  455. package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
  456. package/src/Link/useLinkComponent.test.tsx +333 -0
  457. package/src/Link/useLinkComponent.ts +29 -57
  458. package/src/List/List.doc.mjs +6 -0
  459. package/src/List/List.spec.md +200 -0
  460. package/src/List/List.test.tsx +117 -1
  461. package/src/List/List.tsx +22 -2
  462. package/src/List/ListContext.tsx +3 -1
  463. package/src/List/ListItem.doc.mjs +2 -2
  464. package/src/List/ListItem.source-build.test.mjs +41 -0
  465. package/src/List/ListItem.tsx +26 -2
  466. package/src/Markdown/Markdown.doc.mjs +300 -2
  467. package/src/Markdown/Markdown.fr23.bench.ts +174 -0
  468. package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
  469. package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
  470. package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
  471. package/src/Markdown/Markdown.public.test.ts +130 -3
  472. package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
  473. package/src/Markdown/Markdown.spec.md +210 -45
  474. package/src/Markdown/Markdown.test.tsx +87 -3
  475. package/src/Markdown/Markdown.tsx +414 -135
  476. package/src/Markdown/ast.test.ts +307 -0
  477. package/src/Markdown/ast.ts +337 -0
  478. package/src/Markdown/incremental.test.ts +43 -0
  479. package/src/Markdown/index.ts +37 -1
  480. package/src/Markdown/modules/remark.spec.md +269 -0
  481. package/src/Markdown/modules/softBreaks.spec.md +137 -0
  482. package/src/Markdown/parser/index.ts +64 -0
  483. package/src/Markdown/parser.public.test.ts +103 -0
  484. package/src/Markdown/parser.test.ts +38 -6
  485. package/src/Markdown/parser.ts +1221 -242
  486. package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
  487. package/src/Markdown/plugins/frontmatter.ts +198 -0
  488. package/src/Markdown/plugins/index.ts +54 -0
  489. package/src/Markdown/plugins/protocol.test.tsx +1022 -0
  490. package/src/Markdown/plugins/protocol.ts +1618 -0
  491. package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
  492. package/src/Markdown/plugins/semanticFence.ts +424 -0
  493. package/src/Markdown/plugins/softBreaks.test.tsx +172 -0
  494. package/src/Markdown/plugins/softBreaks.ts +169 -0
  495. package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
  496. package/src/Markdown/plugins/sourceDecoration.ts +539 -0
  497. package/src/Markdown/plugins/textTransform.test.ts +467 -0
  498. package/src/Markdown/plugins/textTransform.ts +554 -0
  499. package/src/Markdown/remark.test.tsx +1877 -0
  500. package/src/Markdown/remark.ts +1574 -0
  501. package/src/Markdown/url.ts +36 -0
  502. package/src/Markdown/utils.ts +13 -1
  503. package/src/MetadataList/MetadataList.test.tsx +4 -2
  504. package/src/MetadataList/MetadataList.tsx +3 -3
  505. package/src/MultiSelector/MultiSelector.test.tsx +1 -35
  506. package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
  507. package/src/NumberInput/NumberInput.tsx +6 -1
  508. package/src/Outline/Outline.doc.mjs +7 -5
  509. package/src/Outline/Outline.spec.md +1 -1
  510. package/src/Outline/index.ts +1 -0
  511. package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
  512. package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
  513. package/src/Outline/useOutlineFromMarkdown.ts +15 -3
  514. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  515. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
  516. package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
  517. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
  518. package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
  519. package/src/ProgressBar/ProgressBar.test.tsx +29 -11
  520. package/src/ProgressBar/ProgressBar.tsx +59 -72
  521. package/src/RadioList/RadioList.doc.mjs +11 -0
  522. package/src/RadioList/RadioList.test.tsx +32 -0
  523. package/src/RadioList/RadioListItem.tsx +25 -1
  524. package/src/ScrollableArea/ScrollableArea.tsx +1 -0
  525. package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
  526. package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
  527. package/src/SegmentedControl/SegmentedControl.test.tsx +61 -0
  528. package/src/SegmentedControl/SegmentedControl.tsx +2 -1
  529. package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
  530. package/src/Selector/Selector.doc.mjs +3 -3
  531. package/src/Selector/Selector.spec.md +51 -49
  532. package/src/Selector/Selector.test.tsx +61 -55
  533. package/src/Selector/Selector.tsx +34 -15
  534. package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
  535. package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
  536. package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
  537. package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
  538. package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
  539. package/src/Selector/__tests__/Selector.a11y.chromium.spec.ts +45 -0
  540. package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
  541. package/src/SideNav/SideNav.doc.mjs +1 -1
  542. package/src/SideNav/SideNav.test.tsx +10 -0
  543. package/src/SideNav/SideNav.tsx +14 -2
  544. package/src/Slider/Slider.doc.mjs +17 -3
  545. package/src/Slider/Slider.test.tsx +221 -0
  546. package/src/Slider/Slider.tsx +40 -9
  547. package/src/Spinner/Spinner.test.tsx +4 -0
  548. package/src/Spinner/Spinner.tsx +31 -18
  549. package/src/Switch/Switch.doc.mjs +11 -0
  550. package/src/Switch/Switch.test.tsx +16 -0
  551. package/src/Switch/Switch.tsx +28 -0
  552. package/src/TabList/Tab.tsx +35 -7
  553. package/src/TabList/TabList.doc.mjs +11 -0
  554. package/src/TabList/TabList.spec.md +204 -0
  555. package/src/TabList/TabList.test.tsx +66 -0
  556. package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
  557. package/src/Table/Table.doc.mjs +1 -1
  558. package/src/Table/Table.spec.md +54 -40
  559. package/src/Table/Table.test.tsx +83 -10
  560. package/src/Table/Table.tsx +30 -22
  561. package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
  562. package/src/TextArea/TextArea.tsx +6 -1
  563. package/src/TextInput/TextInput.test.tsx +20 -1
  564. package/src/TextInput/TextInput.tsx +6 -1
  565. package/src/TimeInput/NativeTimeInput.test.tsx +36 -3
  566. package/src/TimeInput/Presentation.test.tsx +148 -0
  567. package/src/TimeInput/TimeInput.doc.mjs +21 -5
  568. package/src/TimeInput/TimeInput.tsx +102 -11
  569. package/src/TimeInput/TouchTimeField.tsx +572 -0
  570. package/src/TimeInput/index.ts +1 -0
  571. package/src/Timer/Timer.doc.mjs +183 -0
  572. package/src/Timer/Timer.spec.md +215 -0
  573. package/src/Timer/Timer.test.tsx +302 -0
  574. package/src/Timer/Timer.tsx +258 -0
  575. package/src/Timer/index.ts +11 -0
  576. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  577. package/src/ToggleButton/ToggleButton.test.tsx +299 -4
  578. package/src/ToggleButton/ToggleButton.tsx +26 -33
  579. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
  580. package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
  581. package/src/Token/Token.doc.mjs +2 -2
  582. package/src/Tokenizer/Tokenizer.spec.md +142 -75
  583. package/src/TopNav/TopNavMenu.doc.mjs +2 -2
  584. package/src/TopNav/TopNavMenu.test.tsx +30 -0
  585. package/src/TopNav/TopNavMenu.tsx +7 -2
  586. package/src/TreeList/TreeList.doc.mjs +3 -3
  587. package/src/TreeList/TreeList.spec.md +123 -75
  588. package/src/TreeList/TreeList.test.tsx +29 -0
  589. package/src/TreeList/TreeList.tsx +3 -0
  590. package/src/TreeList/TreeListItem.tsx +15 -1
  591. package/src/TreeList/TreeListTypes.ts +11 -1
  592. package/src/Typeahead/BaseTypeahead.spec.md +4 -3
  593. package/src/Typeahead/BaseTypeahead.tsx +21 -7
  594. package/src/Typeahead/Typeahead.test.tsx +53 -0
  595. package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
  596. package/src/__tests__/pressState.ts +93 -0
  597. package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
  598. package/src/hooks/scrollKeyboardDelegation.ts +233 -0
  599. package/src/hooks/useClickableContainer.test.tsx +236 -0
  600. package/src/hooks/useClickableContainer.ts +20 -4
  601. package/src/hooks/useScrollableArea.doc.mjs +15 -3
  602. package/src/hooks/useScrollableArea.test.tsx +59 -1
  603. package/src/hooks/useScrollableArea.ts +34 -10
  604. package/src/index.ts +3 -0
  605. package/src/inputFontFloor.test.ts +106 -0
  606. package/src/tailwind-theme.css +0 -6
  607. package/src/theme/Theme.test.tsx +32 -0
  608. package/src/theme/declarationBoundary.test.ts +126 -0
  609. package/src/theme/declarationBoundary.ts +347 -0
  610. package/src/theme/defineTheme.ts +4 -0
  611. package/src/theme/derivedVarRegistry.test.ts +7 -0
  612. package/src/theme/derivedVarRegistry.ts +1 -0
  613. package/src/theme/generateThemeRules.test.ts +526 -1
  614. package/src/theme/generateThemeRules.ts +231 -50
  615. package/src/theme/themeAdaptations.test.ts +211 -1
  616. package/src/theme/themeAdaptations.ts +50 -4
  617. package/src/theme/tokenValueCompat.test.ts +4 -1
  618. package/src/utils/inputPresentation.ts +143 -0
  619. package/src/utils/interactionOverlay.stylex.ts +20 -0
  620. package/src/utils/safeUrl.test.ts +88 -0
  621. package/src/utils/safeUrl.ts +85 -0
@@ -6,14 +6,22 @@
6
6
  * Shared logic for generating CSS rules from a resolved theme definition,
7
7
  * including one component-leaf lowering path for root, adaptation, and
8
8
  * media-surface values plus condition-correct Heading weight precedence guards.
9
+ * Built adaptation metadata resolves against the same root component defaults
10
+ * as defineTheme, so scale-only rules do not reset authored component styles.
9
11
  * Used by both the runtime path (Theme injects <style>) and the build
10
12
  * path (`astryx theme build` pre-compiles to CSS files).
11
13
  *
14
+ * Every consumer-supplied declaration is checked by declarationBoundary.ts
15
+ * before it is emitted, so a value can never end its declaration or rule
16
+ * early. A refused declaration is dropped and reported in the supplied
17
+ * warnings array (build receipts), or through `console.warn` (runtime).
18
+ *
12
19
  * Extracted from defineTheme.ts to reduce cyclomatic complexity and provide
13
20
  * a clear single-responsibility module for CSS generation.
14
21
  *
15
- * @input DefinedTheme (resolved theme object from defineTheme)
16
- * @output CSS rule strings, split by layer (component vs prose)
22
+ * @input DefinedTheme (resolved theme object from defineTheme), optional warnings array
23
+ * @output CSS rule strings, split by layer (component vs prose), and warning text
24
+ * for each dropped declaration
17
25
  * @position packages/core/src/theme/generateThemeRules.ts
18
26
  */
19
27
 
@@ -26,6 +34,10 @@ import {parseStyleKey} from '../utils/parseStyleKey';
26
34
  import {getDerivedVars} from './derivedVarRegistry';
27
35
  import {dataTokenDefaults} from './domainTokens/dataTokens';
28
36
  import {cssVar, classPrefix, dataAttrNamespace} from '../naming';
37
+ import {
38
+ checkDeclarationName,
39
+ checkDeclarationValue,
40
+ } from './declarationBoundary';
29
41
 
30
42
  /**
31
43
  * Theme @scope selectors.
@@ -366,6 +378,117 @@ function expandContainerPadding(
366
378
  return tokens;
367
379
  }
368
380
 
381
+ // =============================================================================
382
+ // Declaration assembly: a declaration always stays one declaration
383
+ // =============================================================================
384
+
385
+ type DiagnosticSink = (message: string) => void;
386
+
387
+ const warnToConsole: DiagnosticSink = message => {
388
+ console.warn(`[astryx theme] ${message}`);
389
+ };
390
+
391
+ /** Build receipts collect warning text; runtime callers warn by default. */
392
+ function diagnosticSink(warnings: string[] | undefined): DiagnosticSink {
393
+ return warnings ? message => warnings.push(message) : warnToConsole;
394
+ }
395
+
396
+ /** Shorten an authored value for a one-line message. */
397
+ function previewValue(value: string): string {
398
+ const oneLine = JSON.stringify(value);
399
+ return oneLine.length > 80 ? `${oneLine.slice(0, 77)}..."` : oneLine;
400
+ }
401
+
402
+ function reportDrop(
403
+ sink: DiagnosticSink,
404
+ property: string,
405
+ value: string,
406
+ location: string,
407
+ reason: string,
408
+ ): void {
409
+ sink(
410
+ `dropped "${property}" in ${location}: ${reason} (value: ${previewValue(value)})`,
411
+ );
412
+ }
413
+
414
+ /**
415
+ * True when `name: value;` stays exactly one declaration; otherwise reports
416
+ * the drop and returns false. Both checks follow CSS syntax, so valid CSS a
417
+ * browser keeps inside one declaration (a `data:` URI, `Gill\ Sans`, a closed
418
+ * comment, a vendor-prefixed property) is never refused; see
419
+ * declarationBoundary.ts for the rules.
420
+ */
421
+ function acceptDeclaration(
422
+ property: string,
423
+ value: string,
424
+ location: string,
425
+ sink: DiagnosticSink,
426
+ ): boolean {
427
+ const reason = checkDeclarationName(property) ?? checkDeclarationValue(value);
428
+ if (reason === null) {
429
+ return true;
430
+ }
431
+ reportDrop(sink, property, value, location, reason);
432
+ return false;
433
+ }
434
+
435
+ /**
436
+ * Assemble `prop: value;` lines, dropping (and reporting) any entry whose
437
+ * property or value could not stay a single declaration. Theme definitions
438
+ * are code, but apps do assemble them from stored input (brand colors,
439
+ * white-labeling), so the generated stylesheet must never extend beyond the
440
+ * declarations it means to emit.
441
+ */
442
+ function joinDeclarations(
443
+ entries: [string, string][],
444
+ location: string,
445
+ sink: DiagnosticSink,
446
+ mapProp: (prop: string) => string = p => p,
447
+ ): string {
448
+ const lines: string[] = [];
449
+ for (const [rawProp, rawValue] of entries) {
450
+ // Legacy unenrolled tokens retain non-string values. Scan the same text
451
+ // interpolation has always emitted, without changing the normalized theme.
452
+ const value = `${rawValue}`;
453
+ const prop = mapProp(rawProp);
454
+ if (acceptDeclaration(prop, value, location, sink)) {
455
+ lines.push(` ${prop}: ${value};`);
456
+ }
457
+ }
458
+ return lines.join('\n');
459
+ }
460
+
461
+ /** The `:scope` token block for portable and theme-local token values. */
462
+ function tokenBlock(
463
+ source: ThemeRuleSource,
464
+ location: string,
465
+ sink: DiagnosticSink,
466
+ ): string | null {
467
+ const declarations = [
468
+ joinDeclarations(Object.entries(source.tokens), `${location}tokens`, sink),
469
+ joinDeclarations(
470
+ Object.entries(source.localTokens ?? {}),
471
+ `${location}localTokens`,
472
+ sink,
473
+ ),
474
+ ]
475
+ .filter(block => block.length > 0)
476
+ .join('\n');
477
+ const hasEntries =
478
+ Object.keys(source.tokens).length > 0 ||
479
+ Object.keys(source.localTokens ?? {}).length > 0;
480
+ return hasEntries ? ` :scope {\n${declarations}\n }` : null;
481
+ }
482
+
483
+ /** `components.button["variant:secondary"]`-style location for a rule. */
484
+ function componentLocation(
485
+ prefix: string,
486
+ component: string,
487
+ key: string,
488
+ ): string {
489
+ return `${prefix}components.${component}[${JSON.stringify(key)}]`;
490
+ }
491
+
369
492
  // =============================================================================
370
493
  // Public API
371
494
  // =============================================================================
@@ -393,9 +516,12 @@ export interface ThemeRuleSource {
393
516
  components?: ComponentStyleMap;
394
517
  }
395
518
 
396
- export function generateThemeRules(theme: ThemeRuleSource): string[] {
519
+ export function generateThemeRules(
520
+ theme: ThemeRuleSource,
521
+ warnings?: string[],
522
+ ): string[] {
397
523
  const parts: string[] = [];
398
- const tokens = theme.tokens;
524
+ const sink = diagnosticSink(warnings);
399
525
 
400
526
  // Bare prose rules reference semantic variables instead of baking the root
401
527
  // value. That lets adaptation token writes take effect through CSS alone
@@ -403,21 +529,25 @@ export function generateThemeRules(theme: ThemeRuleSource): string[] {
403
529
  const val = (key: string): string => `var(${key})`;
404
530
 
405
531
  // 1. Token block — CSS custom properties on :scope
406
- const tokenEntries = [
407
- ...Object.entries(tokens),
408
- ...Object.entries(theme.localTokens ?? {}),
409
- ];
410
- if (tokenEntries.length > 0) {
411
- const declarations = tokenEntries
412
- .map(([prop, value]) => ` ${prop}: ${value};`)
413
- .join('\n');
414
- parts.push(` :scope {\n${declarations}\n }`);
532
+ const tokenRules = tokenBlock(theme, '', sink);
533
+ if (tokenRules !== null) {
534
+ parts.push(tokenRules);
535
+ }
536
+
537
+ // 1b. Base font — apply the theme's declared body font to the scope root.
538
+ // Components styled with `font-family: inherit` (SideNav items, Buttons)
539
+ // otherwise resolve against the browser default serif, since nothing else
540
+ // sets a page font. `font-family` inherits, so one rule on :scope covers
541
+ // the tree. Only emitted when the theme declares a body font, so a bare
542
+ // theme still contributes no scope rules of its own.
543
+ if (theme.tokens['--font-family-body']) {
544
+ parts.push(` :scope {\n font-family: var(--font-family-body);\n }`);
415
545
  }
416
546
 
417
547
  // 2. Component overrides: stable .astryx-* target classes combined with
418
548
  // reflected data-* selectors for visual props and runtime states.
419
549
  if (theme.components) {
420
- generateComponentRules(theme.components, parts);
550
+ generateComponentRules(theme.components, parts, {sink});
421
551
  }
422
552
 
423
553
  // 3. Prose HTML element rules (h1-h6, p, small, code, hr)
@@ -513,6 +643,13 @@ function generateHeadingWeightOverrides(
513
643
  }
514
644
  }
515
645
 
646
+ /**
647
+ * The `fontWeight` a heading rule authors for `styleKey`, or undefined when
648
+ * it has none. A value that cannot stay one declaration is treated as not
649
+ * authored, so the override falls back to the inherited or token weight
650
+ * instead of interpolating it; the drop itself is reported where that same
651
+ * rule's declarations are emitted, so it is not reported twice here.
652
+ */
516
653
  function getAuthoredHeadingWeight(
517
654
  headingRuleMap: Record<string, unknown>,
518
655
  styleKey: string,
@@ -522,13 +659,20 @@ function getAuthoredHeadingWeight(
522
659
  return undefined;
523
660
  }
524
661
  const fontWeight = (rule as Record<string, unknown>).fontWeight;
525
- return typeof fontWeight === 'string' ? fontWeight : undefined;
662
+ return typeof fontWeight === 'string' &&
663
+ checkDeclarationValue(fontWeight) === null
664
+ ? fontWeight
665
+ : undefined;
526
666
  }
527
667
 
528
668
  /** Options shared by root, adaptation, and media-surface component lowering. */
529
669
  interface ComponentRuleOptions {
530
670
  resetInheritedPaddingSpecificity?: boolean;
531
671
  surface?: MediaSurface;
672
+ /** Receives dropped declarations; defaults to `console.warn`. */
673
+ sink?: DiagnosticSink;
674
+ /** Location prefix for diagnostics, e.g. `onDark.` or `adaptations[0].`. */
675
+ location?: string;
532
676
  }
533
677
 
534
678
  /**
@@ -545,6 +689,8 @@ function generateComponentRules(
545
689
  {
546
690
  resetInheritedPaddingSpecificity = false,
547
691
  surface,
692
+ sink = warnToConsole,
693
+ location: locationPrefix = '',
548
694
  }: ComponentRuleOptions = {},
549
695
  ): void {
550
696
  for (const [component, rules] of Object.entries(components)) {
@@ -556,6 +702,7 @@ function generateComponentRules(
556
702
 
557
703
  const suffix = parseStyleKey(key);
558
704
  const baseSelector = componentSelector(component, suffix, surface);
705
+ const location = componentLocation(locationPrefix, component, key);
559
706
 
560
707
  // Separate regular properties from pseudo-class overrides
561
708
  const props: [string, string][] = [];
@@ -564,7 +711,14 @@ function generateComponentRules(
564
711
  for (const [prop, value] of entries) {
565
712
  if (prop.startsWith(':') && typeof value === 'object') {
566
713
  pseudos.push([prop, value]);
567
- } else {
714
+ } else if (
715
+ acceptDeclaration(
716
+ toKebabCase(prop),
717
+ `${value as string}`,
718
+ location,
719
+ sink,
720
+ )
721
+ ) {
568
722
  props.push([prop, value as string]);
569
723
  }
570
724
  }
@@ -644,9 +798,12 @@ function generateComponentRules(
644
798
 
645
799
  // Emit base rule
646
800
  if (finalProps.length > 0) {
647
- const declarations = finalProps
648
- .map(([prop, value]) => ` ${toKebabCase(prop)}: ${value};`)
649
- .join('\n');
801
+ const declarations = joinDeclarations(
802
+ finalProps,
803
+ location,
804
+ sink,
805
+ toKebabCase,
806
+ );
650
807
  parts.push(` ${baseSelector} {\n${declarations}\n }`);
651
808
  }
652
809
 
@@ -654,9 +811,12 @@ function generateComponentRules(
654
811
  for (const [pseudo, pseudoStyles] of pseudos) {
655
812
  const pseudoEntries = Object.entries(pseudoStyles);
656
813
  if (pseudoEntries.length > 0) {
657
- const declarations = pseudoEntries
658
- .map(([prop, value]) => ` ${toKebabCase(prop)}: ${value};`)
659
- .join('\n');
814
+ const declarations = joinDeclarations(
815
+ pseudoEntries,
816
+ `${location}[${JSON.stringify(pseudo)}]`,
817
+ sink,
818
+ toKebabCase,
819
+ );
660
820
  parts.push(
661
821
  ` ${appendPseudoToSelectorList(baseSelector, pseudo)} {\n${declarations}\n }`,
662
822
  );
@@ -822,8 +982,11 @@ function generateSizeOverrides(
822
982
  * Component rules (tokens, stable .astryx-* targets plus data-* selectors) are
823
983
  * that need to beat StyleX — they stay in astryx-theme (above StyleX layers).
824
984
  */
825
- export function generateThemeRulesSplit(theme: DefinedTheme): ThemeRulesSplit {
826
- const allRules = generateThemeRules(theme);
985
+ export function generateThemeRulesSplit(
986
+ theme: DefinedTheme,
987
+ warnings?: string[],
988
+ ): ThemeRulesSplit {
989
+ const allRules = generateThemeRules(theme, warnings);
827
990
 
828
991
  const prose: string[] = [];
829
992
  const component: string[] = [];
@@ -847,22 +1010,29 @@ export function generateThemeRulesSplit(theme: DefinedTheme): ThemeRulesSplit {
847
1010
  * to media contexts — only tokens change. Themes can further customize
848
1011
  * via onDark.components / onLight.components.
849
1012
  */
850
- export function generateOnMediaCSS(theme: DefinedTheme): string {
1013
+ export function generateOnMediaCSS(
1014
+ theme: DefinedTheme,
1015
+ warnings?: string[],
1016
+ ): string {
851
1017
  const parts: string[] = [];
852
1018
  const scopeSelector = themeScopeStart(theme.name);
1019
+ const sink = diagnosticSink(warnings);
853
1020
 
854
1021
  for (const surface of ['dark', 'light'] as const) {
855
1022
  const onMedia = surface === 'dark' ? theme.__onDark : theme.__onLight;
856
1023
  if (!onMedia) {
857
1024
  continue;
858
1025
  }
1026
+ const location = surface === 'dark' ? 'onDark.' : 'onLight.';
859
1027
 
860
1028
  // Token overrides
861
1029
  const tokenEntries = Object.entries(onMedia.tokens);
862
1030
  if (tokenEntries.length > 0) {
863
- const declarations = tokenEntries
864
- .map(([prop, value]) => ` ${prop}: ${value};`)
865
- .join('\n');
1031
+ const declarations = joinDeclarations(
1032
+ tokenEntries,
1033
+ `${location}tokens`,
1034
+ sink,
1035
+ );
866
1036
  parts.push(` ${mediaSelector(surface)} {\n${declarations}\n }`);
867
1037
  }
868
1038
 
@@ -872,6 +1042,8 @@ export function generateOnMediaCSS(theme: DefinedTheme): string {
872
1042
  generateComponentRules(onMedia.components, parts, {
873
1043
  resetInheritedPaddingSpecificity: true,
874
1044
  surface,
1045
+ sink,
1046
+ location,
875
1047
  });
876
1048
  generateColorOverrides(onMedia.components, parts, surface);
877
1049
  generateSizeOverrides(onMedia.components, parts, surface);
@@ -895,22 +1067,22 @@ export function generateOnMediaCSS(theme: DefinedTheme): string {
895
1067
  }
896
1068
 
897
1069
  /** Generate only the declarations one adaptation rule writes. */
898
- function generateAdaptationRuleRules(rule: ThemeRuleSource): string[] {
1070
+ function generateAdaptationRuleRules(
1071
+ rule: ThemeRuleSource,
1072
+ location: string,
1073
+ sink: DiagnosticSink,
1074
+ ): string[] {
899
1075
  const parts: string[] = [];
900
- const tokenEntries = [
901
- ...Object.entries(rule.tokens),
902
- ...Object.entries(rule.localTokens ?? {}),
903
- ];
904
- if (tokenEntries.length > 0) {
905
- const declarations = tokenEntries
906
- .map(([prop, value]) => ` ${prop}: ${value};`)
907
- .join('\n');
908
- parts.push(` :scope {\n${declarations}\n }`);
1076
+ const tokens = tokenBlock(rule, location, sink);
1077
+ if (tokens !== null) {
1078
+ parts.push(tokens);
909
1079
  }
910
1080
 
911
1081
  if (rule.components) {
912
1082
  generateComponentRules(rule.components, parts, {
913
1083
  resetInheritedPaddingSpecificity: true,
1084
+ sink,
1085
+ location,
914
1086
  });
915
1087
  generateColorOverrides(rule.components, parts);
916
1088
  generateSizeOverrides(rule.components, parts);
@@ -948,7 +1120,11 @@ function generateAdaptationMediaBlock(
948
1120
  * rule. Bare prose follows semantic variables, so token writes need no duplicate
949
1121
  * prose selectors here.
950
1122
  */
951
- export function generateAdaptationCSS(theme: DefinedTheme): ThemeCSSOutput {
1123
+ export function generateAdaptationCSS(
1124
+ theme: DefinedTheme,
1125
+ warnings?: string[],
1126
+ ): ThemeCSSOutput {
1127
+ const sink = diagnosticSink(warnings);
952
1128
  // Built themes can reach this compiler without passing through defineTheme.
953
1129
  // Validate retained metadata even when it has no rules (and therefore emits
954
1130
  // no CSS): width points remain observable through AppShell and inheritance.
@@ -965,6 +1141,7 @@ export function generateAdaptationCSS(theme: DefinedTheme): ThemeCSSOutput {
965
1141
  theme.__axes ?? {},
966
1142
  theme.tokens,
967
1143
  theme.localTokens,
1144
+ theme.components,
968
1145
  )
969
1146
  : undefined);
970
1147
  if (!rules || rules.length === 0) {
@@ -982,8 +1159,12 @@ export function generateAdaptationCSS(theme: DefinedTheme): ThemeCSSOutput {
982
1159
  // active whenever the later condition matches, even if the earlier condition
983
1160
  // does not. Pairwise merging cannot repair that: multiple mutually exclusive
984
1161
  // earlier rules can each overlap one broad later rule.
985
- for (const rule of rules) {
986
- const parts = generateAdaptationRuleRules(rule);
1162
+ for (const [index, rule] of rules.entries()) {
1163
+ const parts = generateAdaptationRuleRules(
1164
+ rule,
1165
+ `adaptations[${index}].`,
1166
+ sink,
1167
+ );
987
1168
  if (parts.length === 0) {
988
1169
  continue;
989
1170
  }
@@ -1029,12 +1210,9 @@ export function generateAdaptationCSS(theme: DefinedTheme): ThemeCSSOutput {
1029
1210
  return {prose: '', component: blocks.join('\n\n')};
1030
1211
  }
1031
1212
 
1032
- /** Indent a generated rule one level further, for nesting inside `@media`. */
1213
+ /** Indent the rule start without rewriting newlines inside authored values. */
1033
1214
  function indentRule(rule: string): string {
1034
- return rule
1035
- .split('\n')
1036
- .map(line => (line.length > 0 ? ` ${line}` : line))
1037
- .join('\n');
1215
+ return ` ${rule}`;
1038
1216
  }
1039
1217
 
1040
1218
  /**
@@ -1075,8 +1253,11 @@ export function generateDataTokenDefaultsCSS(): string {
1075
1253
  * The theme-independent `--color-data-*` defaults are not part of this output:
1076
1254
  * see `generateDataTokenDefaultsCSS`.
1077
1255
  */
1078
- export function generateThemeCSS(theme: DefinedTheme): ThemeCSSOutput {
1079
- const {component, prose} = generateThemeRulesSplit(theme);
1256
+ export function generateThemeCSS(
1257
+ theme: DefinedTheme,
1258
+ warnings?: string[],
1259
+ ): ThemeCSSOutput {
1260
+ const {component, prose} = generateThemeRulesSplit(theme, warnings);
1080
1261
  const scopeSelector = themeScopeStart(theme.name);
1081
1262
  const scopeTo = THEME_SCOPE_TO;
1082
1263
 
@@ -1096,14 +1277,14 @@ export function generateThemeCSS(theme: DefinedTheme): ThemeCSSOutput {
1096
1277
 
1097
1278
  // Adaptations follow the root theme in authored order. Media-surface rules
1098
1279
  // follow adaptations so onDark/onLight keep their specified precedence.
1099
- const adaptationCss = generateAdaptationCSS(theme);
1280
+ const adaptationCss = generateAdaptationCSS(theme, warnings);
1100
1281
  if (adaptationCss.component) {
1101
1282
  componentCss = componentCss
1102
1283
  ? `${componentCss}\n\n${adaptationCss.component}`
1103
1284
  : adaptationCss.component;
1104
1285
  }
1105
1286
 
1106
- const onMediaCss = generateOnMediaCSS(theme);
1287
+ const onMediaCss = generateOnMediaCSS(theme, warnings);
1107
1288
  if (onMediaCss) {
1108
1289
  componentCss = componentCss
1109
1290
  ? `${componentCss}\n\n${onMediaCss}`
@@ -3,7 +3,8 @@
3
3
  /**
4
4
  * @file themeAdaptations.test.ts
5
5
  * Tests AST-012's ordered, closed, CSS-first theme adaptation contract,
6
- * including normalization and final reachable-cascade validation.
6
+ * including normalization, root-dependent type-scale component writes, and final
7
+ * reachable-cascade validation.
7
8
  */
8
9
 
9
10
  import {describe, expect, it} from 'vitest';
@@ -378,6 +379,215 @@ describe('rule order and writes', () => {
378
379
  });
379
380
  });
380
381
 
382
+ describe('adapted type-scale component defaults', () => {
383
+ const displayFamily = 'Sarina, "Brush Script MT", "Snell Roundhand", cursive';
384
+ const butterShapedInput: DefineThemeInput = {
385
+ name: 'butter-shaped',
386
+ typography: {
387
+ scale: {base: 16, ratio: 1.25},
388
+ body: {family: 'Outfit', fallbacks: 'sans-serif'},
389
+ },
390
+ components: {
391
+ text: Object.fromEntries(
392
+ ['display-1', 'display-2', 'display-3'].map(type => [
393
+ `type:${type}`,
394
+ {fontFamily: displayFamily},
395
+ ]),
396
+ ),
397
+ button: {base: {borderRadius: '12px'}},
398
+ },
399
+ adaptations: {
400
+ rules: [
401
+ {
402
+ when: {width: {below: 'md'}, pointer: 'coarse'},
403
+ value: {typography: {scale: {base: 14, ratio: 1.2}}},
404
+ },
405
+ ],
406
+ },
407
+ };
408
+
409
+ it('keeps butter-shaped display families while adapting scale tokens only', () => {
410
+ const theme = defineTheme(butterShapedInput);
411
+ const rule = theme.__adaptationRules![0];
412
+ const css = generateThemeCSS(theme).component;
413
+ const adaptiveCSS = generateAdaptationCSS(theme).component;
414
+
415
+ expect(rule.query).toBe('(width < 768px) and (pointer: coarse)');
416
+ expect(theme.tokens['--font-size-base']).toBe('1rem');
417
+ expect(rule.tokens['--font-size-base']).toBe('0.875rem');
418
+ expect(rule.tokens['--font-size-5xl']).not.toBe(
419
+ theme.tokens['--font-size-5xl'],
420
+ );
421
+ expect(adaptiveCSS).toContain('--font-size-base: 0.875rem');
422
+ // The root owns the var() wiring and its authored overrides. Re-emitting
423
+ // either would turn an unrelated scale change into a component write.
424
+ expect(rule.components).toBeUndefined();
425
+ expect(adaptiveCSS).not.toContain('.astryx-text');
426
+ expect(adaptiveCSS).not.toContain('.astryx-heading');
427
+ expect(adaptiveCSS).not.toContain('.astryx-button');
428
+ for (const type of ['display-1', 'display-2', 'display-3']) {
429
+ expect(theme.components?.text[`type:${type}`].fontFamily).toBe(
430
+ displayFamily,
431
+ );
432
+ expect(count(css, `.astryx-text[data-type="${type}"] {`)).toBe(1);
433
+ }
434
+ expect(count(css, `font-family: ${displayFamily};`)).toBe(3);
435
+ // Built modules retain root components + intent, not resolved rule layers.
436
+ expect(generateThemeCSS({...theme, __adaptationRules: undefined})).toEqual(
437
+ generateThemeCSS(theme),
438
+ );
439
+ });
440
+
441
+ it('fills only missing generated leaves when the root has no scale', () => {
442
+ const components = {
443
+ heading: {
444
+ 'level:1': {fontFamily: 'serif', fontWeight: '900'},
445
+ 'type:display-1': {fontSize: '5rem'},
446
+ },
447
+ text: {
448
+ 'type:display-1': {fontFamily: displayFamily, lineHeight: '1.1'},
449
+ 'type:body': {fontSize: '18px'},
450
+ 'type:custom': {fontFamily: 'monospace'},
451
+ },
452
+ button: {base: {borderRadius: '12px'}},
453
+ };
454
+ const before = structuredClone(components);
455
+ const theme = defineTheme({
456
+ ...butterShapedInput,
457
+ typography: undefined,
458
+ components,
459
+ });
460
+ const generated = theme.__adaptationRules![0].components!;
461
+
462
+ expect(generated.heading['level:1']).toEqual({
463
+ fontSize: 'var(--text-heading-1-size)',
464
+ lineHeight: 'var(--text-heading-1-leading)',
465
+ });
466
+ expect(generated.heading['type:display-1']).toEqual({
467
+ fontFamily: 'var(--font-family-heading)',
468
+ lineHeight: 'var(--text-display-1-leading)',
469
+ });
470
+ expect(generated.text['type:display-1']).toEqual({
471
+ fontSize: 'var(--text-display-1-size)',
472
+ });
473
+ expect(generated.text['type:body']).toEqual({
474
+ fontFamily: 'var(--font-family-body)',
475
+ lineHeight: 'var(--text-body-leading)',
476
+ });
477
+ expect(generated.text['type:custom']).toBeUndefined();
478
+ expect(generated.button).toBeUndefined();
479
+ expect(components).toEqual(before);
480
+ expect(theme.components).toEqual(before);
481
+ });
482
+
483
+ it('preserves explicit rule writes, including a later root-restoring value', () => {
484
+ const theme = defineTheme({
485
+ ...butterShapedInput,
486
+ adaptations: {
487
+ rules: [
488
+ {
489
+ when: {pointer: 'coarse'},
490
+ value: {
491
+ typography: {scale: {base: 15}},
492
+ components: {
493
+ text: {'type:display-1': {fontFamily: 'monospace'}},
494
+ heading: {'level:1': {fontWeight: '300'}},
495
+ },
496
+ },
497
+ },
498
+ ...butterShapedInput.adaptations!.rules!,
499
+ {
500
+ when: {contrast: 'more'},
501
+ value: {
502
+ typography: {scale: {base: 14}},
503
+ components: {
504
+ text: {'type:display-1': {fontFamily: displayFamily}},
505
+ },
506
+ },
507
+ },
508
+ ],
509
+ },
510
+ });
511
+ const [first, scaleOnly, restore] = theme.__adaptationRules!;
512
+ expect(first.components).toEqual({
513
+ text: {'type:display-1': {fontFamily: 'monospace'}},
514
+ heading: {'level:1': {fontWeight: '300'}},
515
+ });
516
+ expect(scaleOnly.components).toBeUndefined();
517
+ expect(restore.components).toEqual({
518
+ text: {'type:display-1': {fontFamily: displayFamily}},
519
+ });
520
+ const css = generateAdaptationCSS(theme).component;
521
+ expect(css.indexOf('font-family: monospace')).toBeLessThan(
522
+ css.indexOf(`font-family: ${displayFamily}`),
523
+ );
524
+ // Explicit heading defaults still trigger the public weight-prop guard.
525
+ expect(css).toContain(
526
+ '.astryx-heading[data-weight="bold"] { font-weight: var(--font-weight-bold); }',
527
+ );
528
+ });
529
+
530
+ it('lets a later generated component leaf win when its root path is absent', () => {
531
+ const theme = defineTheme(
532
+ adaptationInput([
533
+ {
534
+ when: {pointer: 'coarse'},
535
+ value: {components: {text: {'type:body': {fontSize: '2rem'}}}},
536
+ },
537
+ {
538
+ when: {pointer: 'coarse'},
539
+ value: {typography: {scale: {base: 14, ratio: 1.2}}},
540
+ },
541
+ ]),
542
+ );
543
+ expect(theme.__axes.typography).toBeUndefined();
544
+ expect(theme.components).toBeUndefined();
545
+ const [authored, generated] = theme.__adaptationRules!;
546
+ expect(authored.components?.text['type:body'].fontSize).toBe('2rem');
547
+ expect(generated.components?.text['type:body'].fontSize).toBe(
548
+ 'var(--text-body-size)',
549
+ );
550
+
551
+ // FR4/FR6: only existing root paths suppress generated defaults. Without
552
+ // root wiring, the later scale produces a component write, so it beats the
553
+ // earlier authored leaf when both conditions match (unlike the case above).
554
+ const css = generateAdaptationCSS(theme).component;
555
+ const bodyRules = [
556
+ ...css.matchAll(/\.astryx-text\[data-type="body"\] \{([^}]+)\}/g),
557
+ ].map(match => match[1]);
558
+ expect(bodyRules).toHaveLength(2);
559
+ expect(bodyRules[0]).toContain('font-size: 2rem;');
560
+ expect(bodyRules[1]).toContain('font-size: var(--text-body-size);');
561
+ expect(mediaPreludes(css)).toEqual([
562
+ '(pointer: coarse)',
563
+ '(pointer: coarse)',
564
+ ]);
565
+ expect(generateThemeCSS({...theme, __adaptationRules: undefined})).toEqual(
566
+ generateThemeCSS(theme),
567
+ );
568
+ });
569
+
570
+ it('uses the effective child root without mutating inherited components', () => {
571
+ const base = defineTheme(butterShapedInput);
572
+ const before = structuredClone(base.components);
573
+ const child = defineTheme({
574
+ name: 'child-display',
575
+ extends: base,
576
+ components: {
577
+ text: {'type:display-2': {fontFamily: 'serif'}},
578
+ heading: {'level:2': {fontFamily: 'monospace'}},
579
+ },
580
+ });
581
+ expect(child.__adaptationRules![0].components).toBeUndefined();
582
+ expect(child.components?.text['type:display-1'].fontFamily).toBe(
583
+ displayFamily,
584
+ );
585
+ expect(child.components?.text['type:display-2'].fontFamily).toBe('serif');
586
+ expect(child.components?.heading['level:2'].fontFamily).toBe('monospace');
587
+ expect(base.components).toEqual(before);
588
+ });
589
+ });
590
+
381
591
  describe('theme-local adaptation values', () => {
382
592
  const localName = '--astryx-theme-local-root-control-height';
383
593