@astryx-vue/core 0.3.0 → 0.4.0

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 (505) hide show
  1. package/dist/AlertDialog/index.js +1 -1
  2. package/dist/{AlertDialog-RAVA_cT1.js → AlertDialog-C2inDZWG.js} +5 -5
  3. package/dist/AppShell/index.js +1 -1
  4. package/dist/{AppShell-0wTvOo3H.js → AppShell-CumzH-8z.js} +3 -3
  5. package/dist/Avatar/index.js +1 -1
  6. package/dist/{Avatar-pPZ4dI_s.js → Avatar-BW0TE8t9.js} +47 -34
  7. package/dist/AvatarGroup/index.d.ts +1 -1
  8. package/dist/AvatarGroup/index.js +1 -1
  9. package/dist/{AvatarGroup-B--NQSB3.js → AvatarGroup-DLC_FFR5.js} +57 -13
  10. package/dist/Banner/index.d.ts +1 -1
  11. package/dist/Banner/index.js +1 -1
  12. package/dist/{Banner-GbGxrqQO.js → Banner-C5VAwo4D.js} +68 -34
  13. package/dist/Blockquote/index.js +1 -1
  14. package/dist/Blockquote-DRoKdcxZ.js +27 -0
  15. package/dist/BottomSheet/index.d.ts +1 -1
  16. package/dist/BottomSheet/index.js +2 -2
  17. package/dist/{BottomSheet-pt7m4CvC.js → BottomSheet-B4sc3F1S.js} +286 -140
  18. package/dist/{BottomSheet-JYMB_Ofl.js → BottomSheet-m54uCMJN.js} +20 -4
  19. package/dist/Breadcrumbs/index.d.ts +2 -2
  20. package/dist/Breadcrumbs/index.js +2 -2
  21. package/dist/Breadcrumbs-CTaz7Kh4.js +223 -0
  22. package/dist/Button/index.d.ts +1 -1
  23. package/dist/Button/index.js +1 -1
  24. package/dist/{Button-B6Hj_O_s.js → Button-ONOoHdkg.js} +25 -15
  25. package/dist/ButtonGroup/index.d.ts +1 -1
  26. package/dist/ButtonGroup/index.js +1 -1
  27. package/dist/ButtonGroup-DnkSZ9a5.js +87 -0
  28. package/dist/{ButtonTooltip-nWWrth8j.js → ButtonTooltip-CNKOQHYR.js} +7 -4
  29. package/dist/Calendar/index.d.ts +1 -1
  30. package/dist/Calendar/index.js +1 -1
  31. package/dist/{Calendar-B7vIowKq.js → Calendar-BAqzzQm2.js} +5 -5
  32. package/dist/Card/index.d.ts +2 -2
  33. package/dist/Carousel/index.js +1 -1
  34. package/dist/{Carousel-CA8zpD9v.js → Carousel-DXC22UWq.js} +4 -4
  35. package/dist/Chat/index.d.ts +1 -1
  36. package/dist/Chat/index.js +1 -1
  37. package/dist/{Chat-Bmna9EOA.js → Chat-BdJW6IX5.js} +147 -83
  38. package/dist/CheckboxIndicator/index.js +1 -1
  39. package/dist/{CheckboxIndicator-D37cm2Rh.js → CheckboxIndicator-fH4d-JE1.js} +9 -3
  40. package/dist/CheckboxInput/index.d.ts +1 -1
  41. package/dist/CheckboxInput/index.js +1 -1
  42. package/dist/{CheckboxInput-BS9J6edf.js → CheckboxInput-DJHCbwgC.js} +19 -11
  43. package/dist/CheckboxList/index.d.ts +1 -1
  44. package/dist/CheckboxList/index.js +1 -1
  45. package/dist/{CheckboxList-CX1i_jVP.js → CheckboxList-BdZIP4_J.js} +155 -38
  46. package/dist/Citation/index.js +1 -1
  47. package/dist/{Citation-Djgwa0ko.js → Citation-DbZn2vms.js} +8 -3
  48. package/dist/ClickableCard/index.d.ts +1 -1
  49. package/dist/ClickableCard/index.js +1 -1
  50. package/dist/{ClickableCard-DUsC-j03.js → ClickableCard-ChAfiw9T.js} +9 -6
  51. package/dist/Code/index.js +3 -3
  52. package/dist/{Code-XnPuGxey.js → Code-Bg7GBdxy.js} +2 -1
  53. package/dist/{CodeBlock-D0BFubut.js → CodeBlock-Caaflp7C.js} +3 -3
  54. package/dist/Collapsible/index.d.ts +1 -1
  55. package/dist/Collapsible/index.js +1 -1
  56. package/dist/{Collapsible-Cov3Pyq5.js → Collapsible-Bdj0WYpb.js} +13 -11
  57. package/dist/CommandPalette/index.d.ts +1 -1
  58. package/dist/CommandPalette/index.js +1 -1
  59. package/dist/{CommandPalette-YHsUNg3V.js → CommandPalette-C_MClfAg.js} +143 -63
  60. package/dist/ComplexSelector/index.d.ts +1 -1
  61. package/dist/ComplexSelector/index.js +1 -1
  62. package/dist/{ComplexSelector-DWLdKPGI.js → ComplexSelector-BeVQaqRf.js} +85 -20
  63. package/dist/ContextMenu/index.d.ts +2 -2
  64. package/dist/ContextMenu/index.js +2 -2
  65. package/dist/{ContextMenu-Bq9b3Ti5.js → ContextMenu-C6hPYvYz.js} +297 -179
  66. package/dist/DateInput/index.d.ts +1 -1
  67. package/dist/DateInput/index.js +1 -1
  68. package/dist/{DateInput-DT518j5E.js → DateInput-BjLdmYor.js} +567 -76
  69. package/dist/DateRangeInput/index.d.ts +1 -1
  70. package/dist/DateRangeInput/index.js +1 -1
  71. package/dist/{DateRangeInput-Bqi5tlIA.js → DateRangeInput-Br3wVEfD.js} +85 -20
  72. package/dist/DateTimeInput/index.d.ts +1 -1
  73. package/dist/DateTimeInput/index.js +1 -1
  74. package/dist/DateTimeInput-CAZBwoRe.js +562 -0
  75. package/dist/Dialog/index.d.ts +1 -1
  76. package/dist/Dialog/index.js +2 -2
  77. package/dist/{Dialog-BiOSKQso.js → Dialog-Dce4Y97V.js} +28 -11
  78. package/dist/{Dialog-FGHfDu5M.js → Dialog-fhyxB00e.js} +32 -5
  79. package/dist/Divider/index.d.ts +1 -1
  80. package/dist/Divider/index.js +1 -1
  81. package/dist/{Divider-BtwnL18I.js → Divider-mOZ6vIQw.js} +5 -1
  82. package/dist/DropdownMenu/index.d.ts +2 -2
  83. package/dist/DropdownMenu/index.js +3 -3
  84. package/dist/{DropdownMenu-CoOQVlRp.js → DropdownMenu-BdGmQVb1.js} +85 -57
  85. package/dist/{DropdownMenu-DEb2dSSP.js → DropdownMenu-BzQrNV9C.js} +479 -264
  86. package/dist/{DropdownMenuRadioItem.vue-CXEURBcq.d.ts → DropdownMenuRadioItem.vue-Qd-8Rg4Q.d.ts} +236 -230
  87. package/dist/EmptyState/index.js +1 -1
  88. package/dist/{EmptyState-C_GH7IV5.js → EmptyState-CmOQf2SH.js} +2 -2
  89. package/dist/Field/index.d.ts +4 -3
  90. package/dist/Field/index.js +4 -3
  91. package/dist/{Field-D5gUEGw4.js → Field--OEsLBfE.js} +4 -3
  92. package/dist/{FieldInfoTip-Ds-sW_jY.js → FieldInfoTip-gxsnfkZw.js} +3 -3
  93. package/dist/{FieldLabel-BNeXRuGH.js → FieldLabel-jxIiWgLw.js} +12 -7
  94. package/dist/FieldStatus/index.d.ts +1 -1
  95. package/dist/FileInput/index.d.ts +1 -1
  96. package/dist/FileInput/index.js +1 -1
  97. package/dist/{FileInput-BpdiO1V8.js → FileInput-B_pUxB0Y.js} +106 -29
  98. package/dist/FormLayout/index.d.ts +1 -1
  99. package/dist/FormLayout/index.js +1 -1
  100. package/dist/{FormLayout-D47FjiOq.js → FormLayout-B9dUB6Ps.js} +1 -1
  101. package/dist/Heading/index.d.ts +1 -1
  102. package/dist/Heading/index.js +1 -1
  103. package/dist/{Heading-BnwWEWkp.js → Heading-BzBunfN7.js} +1 -1
  104. package/dist/HoverCard/index.js +1 -1
  105. package/dist/{HoverCard-ycY50pRN.js → HoverCard-BpJhT0sn.js} +35 -22
  106. package/dist/Icon/index.d.ts +4 -4
  107. package/dist/Icon/index.js +1 -1
  108. package/dist/{Icon-bteSId7T.js → Icon-KDnUyY7f.js} +12 -20
  109. package/dist/IconButton/index.js +1 -1
  110. package/dist/{IconButton-DDNgNl7B.js → IconButton-DI-XBbtV.js} +1 -1
  111. package/dist/Indicator/index.d.ts +2 -2
  112. package/dist/Indicator/index.js +2 -1
  113. package/dist/InputClearButton-CwXPan8c.js +40 -0
  114. package/dist/InputGroup/index.d.ts +1 -1
  115. package/dist/InputGroup/index.js +2 -2
  116. package/dist/{InputGroup-CA03Smrs.js → InputGroup-DiiocoIW.js} +2 -2
  117. package/dist/InternationalizationProvider/index.d.ts +1 -1
  118. package/dist/InternationalizationProvider/index.js +1 -1
  119. package/dist/{InternationalizationProvider-DJay_w3B.js → InternationalizationProvider-kBapgKAQ.js} +5 -9
  120. package/dist/{Item-KhFKX9St.js → Item-DWMIjN8n.js} +34 -9
  121. package/dist/Kbd/index.js +1 -1
  122. package/dist/{Kbd-BB-Dw6zE.js → Kbd-CV3LO2Ge.js} +18 -2
  123. package/dist/LayerContentBoundary-CvsKxwwm.js +27 -0
  124. package/dist/LayerProvider/index.js +1 -1
  125. package/dist/{LayerProvider-D9NsQFzL.js → LayerProvider-B6zpMBWC.js} +15 -3
  126. package/dist/Layout/index.d.ts +1 -1
  127. package/dist/Layout/index.js +2 -2
  128. package/dist/{Layout-C6RHllr-.js → Layout-JJRCG7Mf.js} +1 -1
  129. package/dist/{LayoutPanel-DXOsaeQb.js → LayoutPanel-zM5vjrKS.js} +12 -8
  130. package/dist/Lightbox/index.js +1 -1
  131. package/dist/{Lightbox-DTF9EdTG.js → Lightbox-D8wyPgMK.js} +8 -6
  132. package/dist/Link/index.js +1 -1
  133. package/dist/{Link-BqHCtiyt.js → Link-DweIpOtN.js} +29 -12
  134. package/dist/List/index.d.ts +1 -1
  135. package/dist/List/index.js +2 -2
  136. package/dist/{ListItem-8RWT8XAG.js → ListItem-BQXMu1Tb.js} +1 -1
  137. package/dist/Markdown/index.d.ts +5 -2
  138. package/dist/Markdown/index.js +5 -2
  139. package/dist/Markdown/parser/index.d.ts +4 -0
  140. package/dist/Markdown/parser/index.js +3 -0
  141. package/dist/Markdown/plugin-protocol/index.d.ts +35 -0
  142. package/dist/Markdown/plugin-protocol/index.js +107 -0
  143. package/dist/Markdown/plugin-renderer/index.d.ts +31 -0
  144. package/dist/Markdown/plugin-renderer/index.js +42 -0
  145. package/dist/{Markdown-CvtN7HnF.js → Markdown-DhVfOvXk.js} +195 -484
  146. package/dist/MediaTheme-DlLqYhDy.js +433 -0
  147. package/dist/MetadataList/index.js +1 -1
  148. package/dist/{MetadataList-B-OelQlt.js → MetadataList-CEYceIlN.js} +15 -7
  149. package/dist/MobileNav/index.js +1 -1
  150. package/dist/{MobileNavToggle-DxGz0xKA.js → MobileNavToggle-pdoJFZHx.js} +52 -17
  151. package/dist/MoreMenu/index.d.ts +1 -1
  152. package/dist/MoreMenu/index.js +1 -1
  153. package/dist/{MoreMenu-Dlb7MLlW.js → MoreMenu-CFNqSRev.js} +72 -59
  154. package/dist/MultiSelector/index.d.ts +1 -1
  155. package/dist/MultiSelector/index.js +1 -1
  156. package/dist/MultiSelector-DuVatmq5.js +1456 -0
  157. package/dist/{NavDisclosure-C_fugrQ3.js → NavDisclosure-Bq9DTZLO.js} +29 -7
  158. package/dist/{NavHeadingSurface-B3yJspSN.js → NavHeadingSurface-C4v_MtkX.js} +29 -26
  159. package/dist/NavItem/index.d.ts +1 -1
  160. package/dist/NavItem/index.js +2 -2
  161. package/dist/{NavItem-BBIGSvDj.js → NavItem-BPb3yfgz.js} +17 -4
  162. package/dist/NavMenu/index.d.ts +1 -1
  163. package/dist/NavMenu/index.js +3 -3
  164. package/dist/{NavMenu-ThXguZAz.js → NavMenu-BYIDzjix.js} +42 -15
  165. package/dist/{NavMenuItem-BvJNsDFC.js → NavMenuItem-D3FO90GR.js} +14 -12
  166. package/dist/NumberInput/index.d.ts +1 -1
  167. package/dist/NumberInput/index.js +1 -1
  168. package/dist/NumberInput-B0vzOg3N.js +727 -0
  169. package/dist/Outline/index.d.ts +2 -2
  170. package/dist/Outline/index.js +2 -2
  171. package/dist/{Outline-755h-lMP.js → Outline-CfGv2F1o.js} +91 -6
  172. package/dist/OverflowList/index.d.ts +2 -2
  173. package/dist/OverflowList/index.js +1 -1
  174. package/dist/{OverflowList-NmrSMbxb.js → OverflowList-BgRLZ3dh.js} +23 -6
  175. package/dist/Pagination/index.d.ts +1 -1
  176. package/dist/Pagination/index.js +1 -1
  177. package/dist/{Pagination-DqwNQFRp.js → Pagination-Bfe12018.js} +2 -2
  178. package/dist/PickerWheel-CSwUYfes.js +69 -0
  179. package/dist/Popover/index.d.ts +1 -1
  180. package/dist/Popover/index.js +1 -1
  181. package/dist/{Popover-DJf8POzL.js → Popover-78dFjTb9.js} +20 -15
  182. package/dist/PowerSearch/index.d.ts +1 -1
  183. package/dist/PowerSearch/index.js +1 -1
  184. package/dist/{PowerSearch-DvjiPqMZ.js → PowerSearch-BoAMdFaT.js} +774 -586
  185. package/dist/ProgressBar/index.d.ts +1 -1
  186. package/dist/ProgressBar/index.js +1 -1
  187. package/dist/{ProgressBar-CVLzdoBK.js → ProgressBar-VP4JS7vm.js} +10 -7
  188. package/dist/Radio/index.d.ts +1 -1
  189. package/dist/Radio/index.js +1 -1
  190. package/dist/{RadioGroup-Bfu6JSNV.js → RadioGroup-BIipql-L.js} +94 -26
  191. package/dist/RadioList/index.d.ts +1 -1
  192. package/dist/RadioList/index.js +1 -1
  193. package/dist/{RadioList-xY1cwLdZ.js → RadioList-GyhgBg4j.js} +57 -8
  194. package/dist/Resizable/index.d.ts +1 -1
  195. package/dist/Resizable/index.js +1 -1
  196. package/dist/{ResizeHandle-q4nD_586.js → ResizeHandle-TPlUCAHD.js} +103 -50
  197. package/dist/ScrollableArea/index.d.ts +1 -1
  198. package/dist/ScrollableArea/index.js +1 -1
  199. package/dist/{ScrollableArea-D4dCJv9I.js → ScrollableArea-0u6RWtGG.js} +1 -1
  200. package/dist/SegmentedControl/index.d.ts +1 -1
  201. package/dist/SegmentedControl/index.js +1 -1
  202. package/dist/{SegmentedControl-ChHmFrrC.js → SegmentedControl-D1wWGBZo.js} +11 -5
  203. package/dist/SelectableCard/index.d.ts +1 -1
  204. package/dist/SelectableCard/index.js +1 -1
  205. package/dist/{SelectableCard-Cku4dRzc.js → SelectableCard-BEqnhPaX.js} +16 -11
  206. package/dist/Selector/index.d.ts +1 -1
  207. package/dist/Selector/index.js +1 -1
  208. package/dist/Selector-CPISLzp7.js +1049 -0
  209. package/dist/SideNav/index.d.ts +1 -1
  210. package/dist/SideNav/index.js +1 -1
  211. package/dist/{SideNav-BF8mYDxl.js → SideNav-CN2QeAtY.js} +51 -37
  212. package/dist/Slider/index.d.ts +1 -1
  213. package/dist/Slider/index.js +1 -1
  214. package/dist/{Slider-DWobsPgm.js → Slider-pdC0jpHu.js} +172 -46
  215. package/dist/Spinner/index.js +1 -1
  216. package/dist/Spinner-DdVUadii.js +200 -0
  217. package/dist/Stack/index.d.ts +1 -1
  218. package/dist/Stack/index.js +2 -2
  219. package/dist/{Stack-CTsTFfar.js → Stack-Bb_h60t3.js} +1 -1
  220. package/dist/{Stack-kQlYbbL4.js → Stack-Bp-XN9J4.js} +12 -7
  221. package/dist/StatusDot/index.d.ts +1 -1
  222. package/dist/StatusDot/index.js +1 -1
  223. package/dist/{StatusDot-BPUhMOff.js → StatusDot-BS_ohXhd.js} +8 -4
  224. package/dist/Stepper/index.js +1 -1
  225. package/dist/{Stepper-CE8dHysu.js → Stepper-CyaSRSdu.js} +101 -79
  226. package/dist/Switch/index.d.ts +1 -1
  227. package/dist/Switch/index.js +1 -1
  228. package/dist/{Switch-DaVPRxvN.js → Switch-Z2Vfiiic.js} +38 -22
  229. package/dist/TabList/index.d.ts +2 -2
  230. package/dist/TabList/index.js +1 -1
  231. package/dist/{TabList-DIkK9sgK.js → TabList-DRqP0Hrv.js} +205 -63
  232. package/dist/Table/index.d.ts +3 -3
  233. package/dist/Table/index.js +1 -1
  234. package/dist/{Table-fecqnm7P.js → Table-BcrrylMX.js} +726 -452
  235. package/dist/Text/index.d.ts +1 -1
  236. package/dist/Text/index.js +1 -1
  237. package/dist/{Text-CV3LmscH.js → Text-CmTOgYXf.js} +1 -1
  238. package/dist/TextArea/index.d.ts +1 -1
  239. package/dist/TextArea/index.js +1 -1
  240. package/dist/{TextArea-Ab5Sw60T.js → TextArea-DA9CCG_J.js} +104 -50
  241. package/dist/TextInput/index.d.ts +1 -1
  242. package/dist/TextInput/index.js +1 -1
  243. package/dist/{TextInput-zFT1_qgI.js → TextInput-CI96einV.js} +71 -38
  244. package/dist/Theme/index.d.ts +3 -3
  245. package/dist/Theme/index.js +3 -2
  246. package/dist/Theme-BbDT8B_C.js +2125 -0
  247. package/dist/Thumbnail/index.js +1 -1
  248. package/dist/{Thumbnail-C3NnJUFG.js → Thumbnail-B2ZAY59J.js} +13 -10
  249. package/dist/{TimeField-CoHDGmsP.js → TimeField-CpAgja9D.js} +297 -40
  250. package/dist/TimeInput/index.d.ts +1 -1
  251. package/dist/TimeInput/index.js +1 -1
  252. package/dist/{TimeInput-D2k3Ux3p.js → TimeInput-Bw_lHS4M.js} +78 -9
  253. package/dist/Timer/index.d.ts +1 -1
  254. package/dist/Timer/index.js +1 -1
  255. package/dist/{Timer-avMQk5DN.js → Timer-CH7GsEVu.js} +1 -1
  256. package/dist/Timestamp/index.d.ts +1 -1
  257. package/dist/Timestamp/index.js +1 -1
  258. package/dist/{Timestamp-xpQKCk0d.js → Timestamp-BFNuoTZ0.js} +5 -5
  259. package/dist/Toast/index.d.ts +1 -1
  260. package/dist/Toast/index.js +1 -1
  261. package/dist/Toast-DwnPjx6j.js +685 -0
  262. package/dist/ToggleButton/index.d.ts +1 -1
  263. package/dist/ToggleButton/index.js +1 -1
  264. package/dist/{ToggleButton-B-C-Q7XP.js → ToggleButton-cLjh9W-x.js} +5 -4
  265. package/dist/Token/index.d.ts +1 -1
  266. package/dist/Token/index.js +1 -1
  267. package/dist/{Token-DsntTYhQ.js → Token-BfS4vi__.js} +32 -17
  268. package/dist/Tokenizer/index.d.ts +1 -1
  269. package/dist/Tokenizer/index.js +1 -1
  270. package/dist/{Tokenizer-B5C_qY7t.js → Tokenizer-Ci3E5bvP.js} +107 -23
  271. package/dist/Toolbar/index.d.ts +2 -2
  272. package/dist/Toolbar/index.js +1 -1
  273. package/dist/{Toolbar-BrgvvTCk.js → Toolbar-C0pMWL4S.js} +1 -1
  274. package/dist/Tooltip/index.d.ts +1 -1
  275. package/dist/Tooltip/index.js +1 -1
  276. package/dist/{Tooltip-C4Vaqd3G.js → Tooltip-sAM8i1eO.js} +23 -19
  277. package/dist/TopNav/index.d.ts +1 -1
  278. package/dist/TopNav/index.js +1 -1
  279. package/dist/{TopNav-Ciq0l1w7.js → TopNav-gW59zp1o.js} +16 -15
  280. package/dist/TreeList/index.d.ts +1 -1
  281. package/dist/TreeList/index.js +1 -1
  282. package/dist/{TreeList-BUz-KZJd.js → TreeList-DaoI7zaH.js} +124 -41
  283. package/dist/Typeahead/index.d.ts +1 -1
  284. package/dist/Typeahead/index.js +2 -2
  285. package/dist/{Typeahead-JP9RT87x.js → Typeahead-D4JjvjK4.js} +123 -26
  286. package/dist/{TypeaheadMenu-DBW6rHeO.js → TypeaheadMenu-BQlMrfqX.js} +141 -51
  287. package/dist/{announce-Cnio10Wk.js → announce-B210eJVf.js} +17 -2
  288. package/dist/characterReferences-BJ-jLhsR.js +65 -0
  289. package/dist/characters-rcDbGt71.d.ts +29 -0
  290. package/dist/characters-wTnzjkkR.js +58 -0
  291. package/dist/{colorMode-CBgdgDSn.js → colorMode-BxqfDP4P.js} +1 -4
  292. package/dist/composables/index.d.ts +5 -4
  293. package/dist/composables/index.js +23 -18
  294. package/dist/{composables-CbKx9C1Y.js → composables-Bc02zKAO.js} +167 -197
  295. package/dist/context-B6UElI5X.js +5 -0
  296. package/dist/{context-Cfjh8te1.js → context-Cfml4jaK.js} +5 -3
  297. package/dist/{context-iABt_ueM.js → context-DWfi56sq.js} +451 -122
  298. package/dist/context-IvbU9c3T.js +8 -0
  299. package/dist/context-pjBxaMSh.js +28 -0
  300. package/dist/fieldParts--SyRZVQG.js +44 -0
  301. package/dist/fieldParts-LXpQMKE8.d.ts +27 -0
  302. package/dist/{focus-CpficIgf.js → focus-l8jVTcqd.js} +1 -1
  303. package/dist/hoverIntent-DMHGb85c.js +115 -0
  304. package/dist/{index-Cde5JvtX.d.ts → index-B-nESNam.d.ts} +8 -7
  305. package/dist/{index-CsNi1I8j.d.ts → index-B08-Uxhv.d.ts} +4 -2
  306. package/dist/{index-Cn-sSds-.d.ts → index-B56j4eI2.d.ts} +24 -1
  307. package/dist/{index-BkjSF265.d.ts → index-BEZ4ezJk.d.ts} +3 -3
  308. package/dist/{index-DeQwYJbg.d.ts → index-BNaRK-s5.d.ts} +10 -1
  309. package/dist/{index-0QGtSf3r.d.ts → index-BO9TY87G.d.ts} +3 -2
  310. package/dist/{index-IBAInumL.d.ts → index-BQEJj72c.d.ts} +23 -10
  311. package/dist/{index-D97pQbua.d.ts → index-BV2D2x_u.d.ts} +1 -1
  312. package/dist/{index-Crp3NFLW.d.ts → index-BZKgbyN9.d.ts} +1 -1
  313. package/dist/index-BkUkm6Al.d.ts +11 -0
  314. package/dist/{index-ClNU2Th8.d.ts → index-Bn-v89Vt.d.ts} +10 -6
  315. package/dist/{index-Bu8NA2SD.d.ts → index-BnEhvmdR.d.ts} +16 -7
  316. package/dist/index-Bo-ofFyg.d.ts +166 -0
  317. package/dist/{index-i0tNFWfz.d.ts → index-BqhgeAT4.d.ts} +2 -0
  318. package/dist/{index-DWh2WC8W.d.ts → index-C4Cjz6OK.d.ts} +2 -2
  319. package/dist/{index-B7yhzGUT.d.ts → index-C7sam-SB.d.ts} +2 -2
  320. package/dist/{index-BrJzFA5X.d.ts → index-C90l2rH1.d.ts} +1 -1
  321. package/dist/{index-vP0EtrJJ.d.ts → index-C9gAlDt_.d.ts} +6 -3
  322. package/dist/{index-xrzJC4wm.d.ts → index-CJ6ajsUC.d.ts} +1 -1
  323. package/dist/{index-B9e52paP.d.ts → index-CK-Dbh0f.d.ts} +1 -1
  324. package/dist/index-CKUfpmFL.d.ts +375 -0
  325. package/dist/{index-DXpSFlPG.d.ts → index-CKgBTAzC.d.ts} +4 -4
  326. package/dist/{index-gW0HW02U.d.ts → index-COxy6LEW.d.ts} +1 -1
  327. package/dist/{index-B4OOtNP8.d.ts → index-CPtDjmcX.d.ts} +3 -3
  328. package/dist/{index-12QYAbiz.d.ts → index-CRrSHbok.d.ts} +3 -2
  329. package/dist/{index-DG52Bg0W.d.ts → index-CTf3SK0b.d.ts} +6 -0
  330. package/dist/{index-BVKivP59.d.ts → index-CTjkJP4x.d.ts} +32 -3
  331. package/dist/{index-COgrQZIL.d.ts → index-CdvmnNMH.d.ts} +1 -1
  332. package/dist/{index-GI9xIV9l.d.ts → index-CikMzeab.d.ts} +2 -2
  333. package/dist/{index-DUaLJO7l.d.ts → index-CpNlPLBF.d.ts} +172 -126
  334. package/dist/{index-yT1yiiww.d.ts → index-Cs1xsHKi.d.ts} +24 -12
  335. package/dist/{index-Cyb9Du5Z.d.ts → index-CtTGt6Dv.d.ts} +1 -1
  336. package/dist/{index-Byar3h1e.d.ts → index-D05JGsT3.d.ts} +6 -3
  337. package/dist/{index-B3Fomy15.d.ts → index-D0_HsuC3.d.ts} +3 -3
  338. package/dist/{index-BgT6mH3U.d.ts → index-D7ShT2c-.d.ts} +1 -1
  339. package/dist/{index-CkKPMIeX.d.ts → index-D7XRtUTY.d.ts} +9 -0
  340. package/dist/{index-TntQsADQ.d.ts → index-DEm3kRBO.d.ts} +4 -3
  341. package/dist/{index-C2nbK2AA.d.ts → index-DLAG3m9W.d.ts} +13 -3
  342. package/dist/{index-DVmgNb78.d.ts → index-DRJZ-v1E.d.ts} +4 -4
  343. package/dist/{index-CL1T2j4y.d.ts → index-DY8Wph-A.d.ts} +3 -3
  344. package/dist/{index-B1WJxt-n.d.ts → index-DfC05uKG.d.ts} +17 -7
  345. package/dist/{index-C5e-7Obr.d.ts → index-Dj1_1t3j.d.ts} +19 -6
  346. package/dist/{index-D41_xqjs.d.ts → index-Dr4b_oji.d.ts} +20 -13
  347. package/dist/{index-CqE4Bf3Q.d.ts → index-Ds201-d2.d.ts} +16 -2
  348. package/dist/{index-DIXAzTKL.d.ts → index-DxxudRgB.d.ts} +1 -1
  349. package/dist/{index-B42oE_F-.d.ts → index-IfsSCj8J.d.ts} +18 -5
  350. package/dist/{index-XuAAcYiP.d.ts → index-f3d9cVtj.d.ts} +1 -1
  351. package/dist/{index-T2FOcOuI.d.ts → index-jOwU3YoR.d.ts} +400 -90
  352. package/dist/{index-CICeEoZV.d.ts → index-pNtfr-RW.d.ts} +1 -1
  353. package/dist/{index-BhpAUzUr.d.ts → index-unAZVFGz.d.ts} +2 -2
  354. package/dist/index.d.ts +80 -74
  355. package/dist/index.js +149 -134
  356. package/dist/inlineSize-BNe8wggI.js +66 -0
  357. package/dist/inputPresentation-BOyHkCDr.js +62 -0
  358. package/dist/interactionModality-ACpTMhak.js +44 -0
  359. package/dist/isApplePlatform-B1ju6F5B.js +27 -0
  360. package/dist/isRenderable-BnKHIqfd.js +21 -0
  361. package/dist/layerDepth-CNDh-IHb.js +181 -0
  362. package/dist/link-DuuA2eCL.js +30 -0
  363. package/dist/{loadCatalog-BGHKG_9N.d.ts → loadCatalog-DlLFZreI.d.ts} +281 -7
  364. package/dist/loadCatalog-eopw74qb.js +424 -0
  365. package/dist/locale/index.d.ts +2 -2
  366. package/dist/locale/index.js +4 -3
  367. package/dist/locale-CabGJlGp.js +343 -0
  368. package/dist/modalOutlet-CUOcrhIu.js +56 -0
  369. package/dist/optionAction-Cg7xQLUA.d.ts +6 -0
  370. package/dist/{power-search-DrDfcoL1.d.ts → power-search-gHLIYXs5.d.ts} +2 -0
  371. package/dist/protocol-DHxY0NI8.js +113 -0
  372. package/dist/protocol-RSeMzAN1.d.ts +238 -0
  373. package/dist/publicParser-B0MRoikr.d.ts +141 -0
  374. package/dist/publicParser-uHC_T0Fo.js +895 -0
  375. package/dist/resizableChannel-3vivrEcT.js +20 -0
  376. package/dist/safeUrl-CsvfcZ9m.js +54 -0
  377. package/dist/scopedProvide-C-Df7c15.js +30 -0
  378. package/dist/scrollKeyboardDelegation-D7cumnOl.js +238 -0
  379. package/dist/scrollLock-C3aT4-0z.js +102 -0
  380. package/dist/{searchResultMessage-hXXNOFJP.js → searchResultMessage-mCpJBvra.js} +5 -14
  381. package/dist/{semantic-CKH9XVqa.d.ts → semantic-BF_AjLvk.d.ts} +6 -3
  382. package/dist/slug-C65CUsf9.js +32 -0
  383. package/dist/syntaxContext-DmIfNNtb.js +4 -0
  384. package/dist/triggerVariant-BsL8jMHs.js +16 -0
  385. package/dist/{types-0Q_SJv_F.d.ts → types-Bb7OGivY.d.ts} +6 -1
  386. package/dist/{types-CwyibrRB.d.ts → types-C5GQ2KCK.d.ts} +23 -3
  387. package/dist/{types-gKsEkk2g.d.ts → types-CsqwQkf1.d.ts} +143 -10
  388. package/dist/upstreamMap-xr3gvREu.js +731 -0
  389. package/dist/{useAnchoredListbox-DwztMNjP.js → useAnchoredListbox-DGxxKHZb.js} +2 -2
  390. package/dist/{useAsyncSource-xpQovjV_.d.ts → useAsyncSource-aGzrvRkI.d.ts} +3 -0
  391. package/dist/{useClickableContainer-DyNpnSEa.js → useClickableContainer-CdGp_Cev.js} +1 -1
  392. package/dist/{useClipboard-BDfbEsWd.js → useClipboard-Dk8cS810.js} +1 -1
  393. package/dist/useHoverLayerDismiss-kYJ_NqL4.js +27 -0
  394. package/dist/{useIndicator-i1NORM7W.js → useIndicator-MZmfBWid.js} +5 -23
  395. package/dist/{useInputContainer-CpgDe2-4.js → useInputContainer-CLcYrby4.js} +1 -1
  396. package/dist/{useInputStatusIcon-DBOwxV4x.js → useInputStatusIcon-DAE7PExr.js} +1 -1
  397. package/dist/useLayerMountTarget-BmZyeKWE.js +156 -0
  398. package/dist/{useListFocus-D0iOJl39.js → useListFocus-ChxLg0b4.js} +3 -2
  399. package/dist/{useMenuDrillIn-DzKGkTho.js → useMenuDrillIn-DhUnPvKs.js} +6 -5
  400. package/dist/useMenuHover-Djreu23i.js +170 -0
  401. package/dist/useMenuPress-8foxY8z4.js +764 -0
  402. package/dist/{useMergedRefs-CfHHlCsn.js → useMergedRefs-Cb6_w93m.js} +24 -4
  403. package/dist/{useNumberField-4-dIGVed.js → useNumberField-Dk1BE3-K.js} +3 -3
  404. package/dist/useOptionActionGrid-CkJcuvaU.js +97 -0
  405. package/dist/{usePositionedLayer-Cru9_00b.js → usePositionedLayer-B7cvG-_v.js} +43 -49
  406. package/dist/usePressFeedback-BJCpjEpv.js +319 -0
  407. package/dist/{useResizable-DDwPpPe6.d.ts → useResizable-1MHPNaRD.d.ts} +19 -1
  408. package/dist/{useResizable-B3ahKLoZ.js → useResizable-I3BCiLSL.js} +72 -40
  409. package/dist/useResolvedLabelHidden-B2rlWiaI.js +30 -0
  410. package/dist/{useRestoreFocus-Djw9RUIf.js → useRestoreFocus-XEKs5-gp.js} +49 -7
  411. package/dist/useScrollOverflow-DuMoGXmm.js +67 -0
  412. package/dist/useScrollableArea-BE8b3qm7.js +222 -0
  413. package/dist/{useTimeValue-6ufHM15W.js → useTimeValue-BJd0xBhG.js} +4 -22
  414. package/dist/useTranslator-BmWt2BBt.js +35 -0
  415. package/dist/{useTypeahead-PAK8lMYz.js → useTypeahead-BvtflkRk.js} +4 -5
  416. package/dist/utils/index.d.ts +3 -0
  417. package/dist/utils/index.js +5 -0
  418. package/dist/{utils-D33VQDnk.js → utils-ClVseK2w.js} +29 -2
  419. package/dist/utils-z3Q6BGIJ.js +819 -0
  420. package/locales/SOURCE.json +1 -1
  421. package/package.json +18 -2
  422. package/reset.css +364 -1
  423. package/styles/avatar-group.css +9 -1
  424. package/styles/badge.css +8 -5
  425. package/styles/banner.css +124 -26
  426. package/styles/blockquote.css +1 -0
  427. package/styles/bordered-control.css +1 -1
  428. package/styles/bottom-sheet.css +74 -6
  429. package/styles/breadcrumbs.css +16 -2
  430. package/styles/button-group.css +3 -1
  431. package/styles/button.css +53 -11
  432. package/styles/card.css +1 -1
  433. package/styles/chat.css +16 -6
  434. package/styles/checkbox-input.css +10 -0
  435. package/styles/clickable-card.css +10 -3
  436. package/styles/collapsible.css +12 -5
  437. package/styles/command-palette.css +29 -14
  438. package/styles/complex-selector.css +22 -5
  439. package/styles/context-menu.css +3 -3
  440. package/styles/date-input.css +111 -1
  441. package/styles/dialog-header.css +4 -1
  442. package/styles/dialog.css +7 -0
  443. package/styles/dropdown-menu.css +12 -3
  444. package/styles/field.css +5 -0
  445. package/styles/form-layout.css +1 -0
  446. package/styles/heading.css +18 -8
  447. package/styles/icon.css +4 -0
  448. package/styles/kbd.css +1 -1
  449. package/styles/layer.css +72 -0
  450. package/styles/list.css +9 -2
  451. package/styles/metadata-list.css +1 -0
  452. package/styles/mobile-nav.css +4 -1
  453. package/styles/multi-selector.css +48 -1
  454. package/styles/nav-item.css +9 -2
  455. package/styles/nav-menu.css +12 -2
  456. package/styles/number-input.css +9 -1
  457. package/styles/overflow-list.css +1 -1
  458. package/styles/popover.css +2 -1
  459. package/styles/power-search.css +5 -3
  460. package/styles/pressable.css +63 -22
  461. package/styles/progress-bar.css +15 -3
  462. package/styles/radio.css +16 -0
  463. package/styles/resize-handle.css +42 -0
  464. package/styles/segmented-control.css +12 -4
  465. package/styles/selector.css +53 -1
  466. package/styles/side-nav.css +19 -0
  467. package/styles/slider.css +4 -3
  468. package/styles/spinner.css +48 -42
  469. package/styles/stepper.css +58 -4
  470. package/styles/switch.css +26 -0
  471. package/styles/tab-list.css +132 -3
  472. package/styles/table.css +88 -10
  473. package/styles/text-area.css +1 -1
  474. package/styles/text-input.css +1 -1
  475. package/styles/text.css +6 -6
  476. package/styles/thumbnail.css +11 -3
  477. package/styles/time-input.css +8 -0
  478. package/styles/toast.css +37 -3
  479. package/styles/token.css +2 -2
  480. package/styles/tokenizer.css +1 -1
  481. package/styles/toolbar.css +4 -1
  482. package/styles/tree-list.css +1 -1
  483. package/styles/typeahead.css +34 -1
  484. package/styles.css +1 -0
  485. package/dist/Blockquote-DFqBv_oJ.js +0 -18
  486. package/dist/Breadcrumbs-DIm4figq.js +0 -141
  487. package/dist/ButtonGroup-ySQWanDP.js +0 -125
  488. package/dist/DateTimeInput-A7m2O3bg.js +0 -268
  489. package/dist/MultiSelector-BtAUfQ3t.js +0 -990
  490. package/dist/NumberInput-AZ9x3oja.js +0 -473
  491. package/dist/Selector-DJ2BhUTV.js +0 -677
  492. package/dist/Spinner-9cYUCnDy.js +0 -84
  493. package/dist/Theme-CtaUWo4g.js +0 -1246
  494. package/dist/Toast-BuqIZV5z.js +0 -322
  495. package/dist/context-4PuqD1Ic.js +0 -4
  496. package/dist/context-D5-MwxnN.js +0 -4
  497. package/dist/index-BH9PzQ1F.d.ts +0 -87
  498. package/dist/link-C4_WogdF.js +0 -18
  499. package/dist/loadCatalog-CXKqEB9s.js +0 -877
  500. package/dist/locale-DgkZEMTn.js +0 -105
  501. package/dist/platform-B_9W_aHW.js +0 -33
  502. package/dist/scrollLock-BzIvIimL.js +0 -42
  503. package/dist/useMenuPress-D-FRNrBW.js +0 -573
  504. package/dist/useScrollableArea-DDk_CluT.js +0 -172
  505. /package/dist/{index-lgvUFSCO.d.ts → index-CryFtTT6.d.ts} +0 -0
@@ -0,0 +1,2125 @@
1
+ import { n as themeContextKey, r as themeNestingKey, t as mediaThemeKey } from "./context-Cws_tXTr.js";
2
+ import { a as syntaxThemeStyle } from "./syntaxTheme-R7xnu5x5.js";
3
+ import { t as syntaxThemeKey } from "./syntaxContext-DmIfNNtb.js";
4
+ import { a as normalizeTokenName, c as parseColor, i as isPortableTokenName, o as prefixTokenReferences, r as bridgeComponentTokens, s as contrastRatio } from "./MediaTheme-DlLqYhDy.js";
5
+ import { computed, createBlock, createCommentVNode, createElementBlock, defineComponent, h, inject, markRaw, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, provide, renderSlot, unref, useAttrs, useTemplateRef, watch } from "vue";
6
+ import "../styles/theme.css";
7
+ //#region src/Theme/adaptationTypes.ts
8
+ /** Fixed names for viewport-width tier start points. */
9
+ const WIDTH_BREAKPOINT_NAMES = [
10
+ "sm",
11
+ "md",
12
+ "lg",
13
+ "xl",
14
+ "2xl"
15
+ ];
16
+ /** Default width tier start points, in CSS px. */
17
+ const DEFAULT_WIDTH_BREAKPOINTS = Object.freeze({
18
+ "sm": 640,
19
+ "md": 768,
20
+ "lg": 1024,
21
+ "xl": 1280,
22
+ "2xl": 1536
23
+ });
24
+ //#endregion
25
+ //#region src/Theme/declarationBoundary.ts
26
+ /**
27
+ * Whether one theme value can be written as exactly one CSS declaration.
28
+ *
29
+ * Theme objects are code, but apps also build them from stored input such as
30
+ * brand colors. A value that closes the rule, opens a block, or ends the
31
+ * declaration early would let one entry write CSS the theme never meant to.
32
+ *
33
+ * The checks follow CSS tokenization, so valid CSS a browser keeps inside one
34
+ * declaration is accepted: a `;` inside a quoted string or a quoted `url()`,
35
+ * an escaped character such as `Gill\ Sans`, and a closed comment. Rejected:
36
+ * a top-level `;`, an unmatched bracket, an unclosed string, comment, or
37
+ * `url(`, and a trailing backslash.
38
+ *
39
+ * Each check returns `null` when the input is safe, or a short reason.
40
+ */
41
+ function isNewline(ch) {
42
+ return ch === "\n" || ch === "\r" || ch === "\f";
43
+ }
44
+ function isWhitespace(ch) {
45
+ return ch === " " || ch === " " || isNewline(ch);
46
+ }
47
+ function isHexDigit(ch) {
48
+ return ch != null && /^[0-9a-f]$/i.test(ch);
49
+ }
50
+ function isNameStart(ch) {
51
+ return ch != null && (/^[a-z_]$/i.test(ch) || ch.charCodeAt(0) >= 128);
52
+ }
53
+ function isNameChar(ch) {
54
+ return isNameStart(ch) || ch != null && /^[0-9-]$/.test(ch);
55
+ }
56
+ function preprocess(input) {
57
+ return input.replace(/\r\n?|\f/g, "\n").replace(/\0/g, "�");
58
+ }
59
+ const NON_PRINTABLE = /[\x01-\x08\v\x0E-\x1F\x7F]/;
60
+ function isValidEscape(input, pos) {
61
+ return input[pos] === "\\" && pos + 1 < input.length && !isNewline(input[pos + 1]);
62
+ }
63
+ function startsIdent(input, pos) {
64
+ const ch = input[pos];
65
+ if (ch === "-") {
66
+ const next = input[pos + 1];
67
+ return next === "-" || isNameStart(next) || isValidEscape(input, pos + 1);
68
+ }
69
+ if (ch === "\\") return isValidEscape(input, pos);
70
+ return isNameStart(ch);
71
+ }
72
+ /** Index just past an escape whose backslash sits at `pos - 1`. */
73
+ function consumeEscape(input, pos) {
74
+ if (isHexDigit(input[pos])) {
75
+ let end = pos;
76
+ while (end < input.length && end - pos < 6 && isHexDigit(input[end])) end += 1;
77
+ return isWhitespace(input[end]) ? end + 1 : end;
78
+ }
79
+ return pos + ((input.codePointAt(pos) ?? 0) > 65535 ? 2 : 1);
80
+ }
81
+ function consumeIdent(input, pos) {
82
+ let name = "";
83
+ let i = pos;
84
+ while (i < input.length) {
85
+ const ch = input[i] ?? "";
86
+ if (isNameChar(ch)) {
87
+ name += ch;
88
+ i += 1;
89
+ } else if (isValidEscape(input, i)) {
90
+ const end = consumeEscape(input, i + 1);
91
+ name += input.slice(i + 1, end).trim();
92
+ i = end;
93
+ } else break;
94
+ }
95
+ return {
96
+ end: i,
97
+ name
98
+ };
99
+ }
100
+ function consumeString(input, pos) {
101
+ const quote = input[pos];
102
+ let i = pos + 1;
103
+ while (i < input.length) {
104
+ const ch = input[i];
105
+ if (ch === quote) return { end: i + 1 };
106
+ if (isNewline(ch)) return { reason: "a newline inside a quoted string makes a bad string" };
107
+ if (ch === "\\") {
108
+ if (i + 1 >= input.length) break;
109
+ i = isNewline(input[i + 1]) ? i + 2 : consumeEscape(input, i + 1);
110
+ continue;
111
+ }
112
+ i += 1;
113
+ }
114
+ return { reason: `an unclosed ${quote} string would swallow the rest of the rule` };
115
+ }
116
+ function consumeUrl(input, pos) {
117
+ let i = pos;
118
+ while (i < input.length) {
119
+ const ch = input[i] ?? "";
120
+ if (ch === ")") return { end: i + 1 };
121
+ if (isWhitespace(ch)) {
122
+ while (i < input.length && isWhitespace(input[i])) i += 1;
123
+ if (i >= input.length) break;
124
+ if (input[i] === ")") return { end: i + 1 };
125
+ return { reason: "whitespace inside an unquoted url() makes a bad url" };
126
+ }
127
+ if (NON_PRINTABLE.test(ch)) return { reason: "a non-printable character inside url() makes a bad url" };
128
+ if (ch === "\"" || ch === "'" || ch === "(") return { reason: `"${ch}" inside an unquoted url() makes a bad url; quote the URL instead` };
129
+ if (ch === "\\") {
130
+ if (!isValidEscape(input, i)) return { reason: "a stray backslash inside url() makes a bad url" };
131
+ i = consumeEscape(input, i + 1);
132
+ continue;
133
+ }
134
+ i += 1;
135
+ }
136
+ return { reason: "an unclosed url( would swallow the rest of the rule" };
137
+ }
138
+ const CLOSER = {
139
+ "(": ")",
140
+ "[": "]",
141
+ "{": "}"
142
+ };
143
+ const OPENER = {
144
+ ")": "(",
145
+ "]": "[",
146
+ "}": "{"
147
+ };
148
+ /** Why `input` cannot be the value of one declaration, or `null` when it can. */
149
+ function checkDeclarationValue(input) {
150
+ const value = preprocess(input);
151
+ const open = [];
152
+ let i = 0;
153
+ while (i < value.length) {
154
+ const ch = value[i] ?? "";
155
+ if (ch === "/" && value[i + 1] === "*") {
156
+ const close = value.indexOf("*/", i + 2);
157
+ if (close === -1) return "an unclosed /* comment would swallow the rest of the rule";
158
+ i = close + 2;
159
+ continue;
160
+ }
161
+ if (ch === "\"" || ch === "'") {
162
+ const scanned = consumeString(value, i);
163
+ if ("reason" in scanned) return scanned.reason;
164
+ i = scanned.end;
165
+ continue;
166
+ }
167
+ if (startsIdent(value, i)) {
168
+ const ident = consumeIdent(value, i);
169
+ i = ident.end;
170
+ if (value[i] === "(" && ident.name.toLowerCase() === "url") {
171
+ let j = i + 1;
172
+ while (j < value.length && isWhitespace(value[j])) j += 1;
173
+ if (value[j] === "\"" || value[j] === "'") {
174
+ open.push(")");
175
+ i += 1;
176
+ continue;
177
+ }
178
+ const scanned = consumeUrl(value, j);
179
+ if ("reason" in scanned) return scanned.reason;
180
+ i = scanned.end;
181
+ }
182
+ continue;
183
+ }
184
+ if (ch === "\\") {
185
+ if (i + 1 >= value.length) return "a trailing backslash would escape the declaration terminator";
186
+ i = isNewline(value[i + 1]) ? i + 1 : consumeEscape(value, i + 1);
187
+ continue;
188
+ }
189
+ if (ch in CLOSER) {
190
+ if (ch === "{" && open.length === 0) return "an unquoted \"{\" would open a nested block";
191
+ open.push(CLOSER[ch] ?? "");
192
+ i += 1;
193
+ continue;
194
+ }
195
+ if (ch in OPENER) {
196
+ if (open.length === 0) return ch === "}" ? "an unquoted \"}\" would close the rule" : `an unbalanced "${ch}" has nothing to close`;
197
+ const expected = open.pop();
198
+ if (expected !== ch) return `"${ch}" does not close the open "${OPENER[expected ?? ""] ?? ""}"`;
199
+ i += 1;
200
+ continue;
201
+ }
202
+ if (ch === ";" && open.length === 0) return "an unquoted \";\" would end the declaration";
203
+ i += 1;
204
+ }
205
+ const closer = open[open.length - 1];
206
+ if (closer != null) return `an unclosed "${OPENER[closer]}" would swallow the rest of the rule`;
207
+ return null;
208
+ }
209
+ /** Shorten a value for a one-line message. */
210
+ function previewValue(value) {
211
+ const oneLine = JSON.stringify(value);
212
+ return oneLine.length > 80 ? `${oneLine.slice(0, 77)}..."` : oneLine;
213
+ }
214
+ /**
215
+ * Report one dropped declaration. The theme keeps every other declaration,
216
+ * so a bad brand color from stored input cannot blank the whole theme.
217
+ */
218
+ function warnDroppedDeclaration(property, value, location, reason) {
219
+ if (typeof console === "undefined") return;
220
+ console.warn(`[astryx theme] dropped "${property}" in ${location}: ${reason} (value: ${previewValue(value)})`);
221
+ }
222
+ /**
223
+ * Why `input` cannot be a declaration's property name, or `null` when it can.
224
+ * A property name is one CSS identifier: `color`, `-webkit-line-clamp`, or a
225
+ * custom property such as `--brand-accent`.
226
+ */
227
+ function checkDeclarationName(input) {
228
+ const name = preprocess(input);
229
+ if (name.length === 0 || !startsIdent(name, 0)) return "a property name must be a CSS identifier";
230
+ const { end } = consumeIdent(name, 0);
231
+ if (end !== name.length) return `a property name must be one CSS identifier; "${name[end]}" cannot appear in one`;
232
+ return null;
233
+ }
234
+ //#endregion
235
+ //#region src/Theme/hct.ts
236
+ const D65_WHITE = [
237
+ .95047,
238
+ 1,
239
+ 1.08883
240
+ ];
241
+ const PALETTE_TONES = [
242
+ 0,
243
+ 5,
244
+ 10,
245
+ 20,
246
+ 30,
247
+ 40,
248
+ 50,
249
+ 60,
250
+ 70,
251
+ 80,
252
+ 90,
253
+ 95,
254
+ 99,
255
+ 100
256
+ ];
257
+ const HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
258
+ function isHexColor(value) {
259
+ return HEX.test(value.trim());
260
+ }
261
+ function srgbToLinear(channel) {
262
+ const scaled = channel / 255;
263
+ return scaled <= .04045 ? scaled / 12.92 : ((scaled + .055) / 1.055) ** 2.4;
264
+ }
265
+ function linearToSrgb(channel) {
266
+ const scaled = channel <= .0031308 ? channel * 12.92 : 1.055 * channel ** (1 / 2.4) - .055;
267
+ return Math.round(Math.min(255, Math.max(0, scaled * 255)));
268
+ }
269
+ function linearRgbToXyz(r, g, b) {
270
+ return [
271
+ .4124564 * r + .3575761 * g + .1804375 * b,
272
+ .2126729 * r + .7151522 * g + .072175 * b,
273
+ .0193339 * r + .119192 * g + .9503041 * b
274
+ ];
275
+ }
276
+ function xyzToLinearRgb(x, y, z) {
277
+ return [
278
+ 3.2404542 * x - 1.5371385 * y - .4985314 * z,
279
+ -.969266 * x + 1.8760108 * y + .041556 * z,
280
+ .0556434 * x - .2040259 * y + 1.0572252 * z
281
+ ];
282
+ }
283
+ function labF(t) {
284
+ const delta = 6 / 29;
285
+ return t > delta ** 3 ? Math.cbrt(t) : t / (3 * delta * delta) + 4 / 29;
286
+ }
287
+ function labFInv(t) {
288
+ const delta = 6 / 29;
289
+ return t > delta ? t ** 3 : 3 * delta * delta * (t - 4 / 29);
290
+ }
291
+ function xyzToLab(x, y, z) {
292
+ const fx = labF(x / D65_WHITE[0]);
293
+ const fy = labF(y / D65_WHITE[1]);
294
+ const fz = labF(z / D65_WHITE[2]);
295
+ return [
296
+ 116 * fy - 16,
297
+ 500 * (fx - fy),
298
+ 200 * (fy - fz)
299
+ ];
300
+ }
301
+ function labToXyz(l, a, b) {
302
+ const fy = (l + 16) / 116;
303
+ const fx = a / 500 + fy;
304
+ const fz = fy - b / 200;
305
+ return [
306
+ labFInv(fx) * D65_WHITE[0],
307
+ labFInv(fy) * D65_WHITE[1],
308
+ labFInv(fz) * D65_WHITE[2]
309
+ ];
310
+ }
311
+ function toneToY(tone) {
312
+ return labFInv((tone + 16) / 116);
313
+ }
314
+ function formatHex(r, g, b) {
315
+ return `#${[
316
+ r,
317
+ g,
318
+ b
319
+ ].map((channel) => channel.toString(16).padStart(2, "0")).join("")}`.toUpperCase();
320
+ }
321
+ function parseHexChannels(hex) {
322
+ const raw = HEX.exec(hex.trim())?.[1];
323
+ if (!raw) return null;
324
+ const expanded = raw.length === 3 ? raw.split("").map((part) => part + part).join("") : raw;
325
+ return [
326
+ Number.parseInt(expanded.slice(0, 2), 16),
327
+ Number.parseInt(expanded.slice(2, 4), 16),
328
+ Number.parseInt(expanded.slice(4, 6), 16)
329
+ ];
330
+ }
331
+ /** Hue 0–360, chroma from 0, tone 0–100. An unreadable hex is black. */
332
+ function hexToHct(hex) {
333
+ const [r, g, b] = parseHexChannels(hex) ?? [
334
+ 0,
335
+ 0,
336
+ 0
337
+ ];
338
+ const [x, y, z] = linearRgbToXyz(srgbToLinear(r), srgbToLinear(g), srgbToLinear(b));
339
+ const [l, a, bLab] = xyzToLab(x, y, z);
340
+ let hue = Math.atan2(bLab, a) * 180 / Math.PI;
341
+ if (hue < 0) hue += 360;
342
+ return {
343
+ hue,
344
+ chroma: Math.sqrt(a * a + bLab * bLab),
345
+ tone: Math.max(0, Math.min(100, l))
346
+ };
347
+ }
348
+ function toneToGray(tone) {
349
+ return linearToSrgb(toneToY(tone));
350
+ }
351
+ function hctComponentToHex(hue, chroma, tone) {
352
+ const hueRad = hue * Math.PI / 180;
353
+ const [x, y, z] = labToXyz(tone, Math.cos(hueRad) * chroma, Math.sin(hueRad) * chroma);
354
+ const [linearR, linearG, linearB] = xyzToLinearRgb(x, y, z);
355
+ const r = linearToSrgb(linearR);
356
+ const g = linearToSrgb(linearG);
357
+ const bOut = linearToSrgb(linearB);
358
+ const tolerance = .02;
359
+ if (Math.abs(srgbToLinear(r) - linearR) > tolerance || Math.abs(srgbToLinear(g) - linearG) > tolerance || Math.abs(srgbToLinear(bOut) - linearB) > tolerance || r < 0 || r > 255 || g < 0 || g > 255 || bOut < 0 || bOut > 255) return null;
360
+ return formatHex(r, g, bOut);
361
+ }
362
+ /** Fit chroma down until the color is inside sRGB. */
363
+ function hctToHex(hct) {
364
+ const { hue, chroma, tone } = hct;
365
+ if (tone <= 0) return "#000000";
366
+ if (tone >= 100) return "#FFFFFF";
367
+ if (chroma < .5) {
368
+ const gray = toneToGray(tone);
369
+ return formatHex(gray, gray, gray);
370
+ }
371
+ let low = 0;
372
+ let high = chroma;
373
+ let best = "#000000";
374
+ for (let step = 0; step < 16; step += 1) {
375
+ const mid = (low + high) / 2;
376
+ const candidate = hctComponentToHex(hue, mid, tone);
377
+ if (candidate != null) {
378
+ best = candidate;
379
+ low = mid;
380
+ } else high = mid;
381
+ }
382
+ return best;
383
+ }
384
+ /** Hex stops at the standard tones for one hue and chroma. */
385
+ function tonalPalette(hue, chroma) {
386
+ const palette = {};
387
+ for (const tone of PALETTE_TONES) palette[tone] = hctToHex({
388
+ hue,
389
+ chroma,
390
+ tone
391
+ });
392
+ return palette;
393
+ }
394
+ /** `#RRGGBB` plus an alpha byte, for example `0.1` becomes `1A`. */
395
+ function hexWithAlpha(hex, alpha) {
396
+ return `${hex}${Math.round(alpha * 255).toString(16).padStart(2, "0").toUpperCase()}`;
397
+ }
398
+ //#endregion
399
+ //#region src/Theme/expandColorScale.ts
400
+ const NEUTRAL_CHROMA = {
401
+ warm: 7,
402
+ cool: 5,
403
+ neutral: 3
404
+ };
405
+ const NEUTRAL_VARIANT_CHROMA = {
406
+ warm: 10,
407
+ cool: 8,
408
+ neutral: 6
409
+ };
410
+ /** Hue source when `accent` is omitted. Accent tokens themselves stay unset. */
411
+ const DEFAULT_ACCENT_SEED = "#0064E0";
412
+ const NON_TEXT_MIN_CONTRAST = 3;
413
+ function lightDark(light, dark) {
414
+ return `light-dark(${light}, ${dark})`;
415
+ }
416
+ function accentWithAlpha(alpha) {
417
+ return `color-mix(in srgb, var(--color-accent) ${alpha * 100}%, transparent)`;
418
+ }
419
+ function ratio(foreground, background) {
420
+ const fg = parseColor(foreground);
421
+ const bg = parseColor(background);
422
+ if (!fg || !bg) return 1;
423
+ return contrastRatio(fg, bg);
424
+ }
425
+ /**
426
+ * Walk tone until the color reaches `minRatio` against `background`.
427
+ * Tone is Lab lightness, so each step moves luminance in one direction.
428
+ */
429
+ function ensureContrastTone(hue, chroma, startTone, step, background, minRatio) {
430
+ let tone = startTone;
431
+ let hex = hctToHex({
432
+ hue,
433
+ chroma,
434
+ tone
435
+ });
436
+ while (ratio(hex, background) < minRatio && tone + step >= 0 && tone + step <= 100) {
437
+ tone += step;
438
+ hex = hctToHex({
439
+ hue,
440
+ chroma,
441
+ tone
442
+ });
443
+ }
444
+ return hex;
445
+ }
446
+ function assertAccent(value, which) {
447
+ if (!isHexColor(value)) throw new Error(`Theme color ${which} must be a hex color such as #0064E0.`);
448
+ }
449
+ function seedPair(accent) {
450
+ if (accent == null) return [DEFAULT_ACCENT_SEED, DEFAULT_ACCENT_SEED];
451
+ if (typeof accent === "string") {
452
+ assertAccent(accent, "accent");
453
+ return [accent, accent];
454
+ }
455
+ const [light, dark] = accent;
456
+ assertAccent(light, "accent light stop");
457
+ assertAccent(dark, "accent dark stop");
458
+ return [light, dark];
459
+ }
460
+ /**
461
+ * Semantic color tokens derived from an accent.
462
+ *
463
+ * Status colors, chart colors, and on-dark / on-light stay out of this map.
464
+ * `--color-accent-muted`, `--color-text-accent`, and `--color-icon-accent`
465
+ * point at `var(--color-accent)`. `--color-on-accent` is baked from the seed,
466
+ * because the contrast pick cannot be expressed as a CSS reference.
467
+ *
468
+ * Names are the upstream names. `defineTheme()` adds the `--astryx-` prefix.
469
+ */
470
+ function expandColorScale(config = {}) {
471
+ const { accent, neutralStyle = "cool", contrast = "standard" } = config;
472
+ const [lightAccent, darkAccent] = seedPair(accent);
473
+ const lightSeed = hexToHct(lightAccent);
474
+ const sameSeed = darkAccent.toLowerCase() === lightAccent.toLowerCase();
475
+ const darkSeed = sameSeed ? lightSeed : hexToHct(darkAccent);
476
+ const neutralChroma = NEUTRAL_CHROMA[neutralStyle] ?? 5;
477
+ const neutralVariantChroma = NEUTRAL_VARIANT_CHROMA[neutralStyle] ?? 8;
478
+ const accentLight = tonalPalette(lightSeed.hue, Math.max(lightSeed.chroma, 48));
479
+ const neutralLight = tonalPalette(lightSeed.hue, neutralChroma);
480
+ const neutralVariantLight = tonalPalette(lightSeed.hue, neutralVariantChroma);
481
+ const accentDark = sameSeed ? accentLight : tonalPalette(darkSeed.hue, Math.max(darkSeed.chroma, 48));
482
+ const neutralDark = sameSeed ? neutralLight : tonalPalette(darkSeed.hue, neutralChroma);
483
+ const neutralVariantDark = sameSeed ? neutralVariantLight : tonalPalette(darkSeed.hue, neutralVariantChroma);
484
+ const high = contrast === "high";
485
+ const textPrimaryLight = high ? 0 : 10;
486
+ const textPrimaryDark = high ? 99 : 90;
487
+ const textSecondaryLight = high ? 20 : 30;
488
+ const textSecondaryDark = high ? 80 : 70;
489
+ const borderAlpha = high ? .2 : .1;
490
+ const borderEmphasized = lightDark(ensureContrastTone(lightSeed.hue, neutralVariantChroma, high ? 50 : 70, -1, neutralLight[99] ?? "#FFFFFF", NON_TEXT_MIN_CONTRAST), ensureContrastTone(darkSeed.hue, neutralVariantChroma, high ? 50 : 30, 1, neutralDark[10] ?? "#000000", NON_TEXT_MIN_CONTRAST));
491
+ return {
492
+ ...accent != null ? {
493
+ "--color-accent": lightDark(accentLight[40] ?? "#000000", accentDark[80] ?? "#FFFFFF"),
494
+ "--color-accent-muted": lightDark(accentWithAlpha(.2), accentWithAlpha(.25)),
495
+ "--color-on-accent": lightDark(accentLight[100] ?? "#FFFFFF", accentDark[20] ?? "#000000")
496
+ } : {},
497
+ "--color-neutral": lightDark(hexWithAlpha(neutralLight[10] ?? "#000000", .1), hexWithAlpha(neutralDark[90] ?? "#FFFFFF", .2)),
498
+ "--color-background-surface": lightDark(neutralLight[99] ?? "#FFFFFF", neutralDark[10] ?? "#000000"),
499
+ "--color-background-body": lightDark(neutralLight[95] ?? "#FFFFFF", neutralDark[5] ?? "#000000"),
500
+ "--color-overlay": lightDark(hexWithAlpha(neutralLight[10] ?? "#000000", .4), hexWithAlpha(neutralDark[10] ?? "#000000", .6)),
501
+ "--color-overlay-hover": lightDark(hexWithAlpha(neutralLight[10] ?? "#000000", .05), hexWithAlpha(neutralDark[100] ?? "#FFFFFF", .05)),
502
+ "--color-overlay-pressed": lightDark(hexWithAlpha(neutralLight[10] ?? "#000000", .1), hexWithAlpha(neutralDark[100] ?? "#FFFFFF", .1)),
503
+ "--color-background-muted": lightDark(hexWithAlpha(neutralLight[10] ?? "#000000", .05), hexWithAlpha(neutralDark[10] ?? "#000000", .5)),
504
+ "--color-text-primary": lightDark(neutralLight[textPrimaryLight] ?? "#000000", neutralDark[textPrimaryDark] ?? "#FFFFFF"),
505
+ "--color-text-secondary": lightDark(neutralVariantLight[textSecondaryLight] ?? "#000000", neutralVariantDark[textSecondaryDark] ?? "#FFFFFF"),
506
+ "--color-text-disabled": lightDark(neutralVariantLight[60] ?? "#000000", neutralVariantDark[40] ?? "#FFFFFF"),
507
+ "--color-text-accent": "var(--color-accent)",
508
+ "--color-icon-accent": "var(--color-accent)",
509
+ "--color-icon-primary": lightDark(neutralLight[textPrimaryLight] ?? "#000000", neutralDark[textPrimaryDark] ?? "#FFFFFF"),
510
+ "--color-icon-secondary": lightDark(neutralVariantLight[textSecondaryLight] ?? "#000000", neutralVariantDark[textSecondaryDark] ?? "#FFFFFF"),
511
+ "--color-icon-disabled": lightDark(neutralVariantLight[60] ?? "#000000", neutralVariantDark[40] ?? "#FFFFFF"),
512
+ "--color-background-card": lightDark(neutralLight[99] ?? "#FFFFFF", neutralDark[10] ?? "#000000"),
513
+ "--color-background-popover": lightDark(neutralLight[99] ?? "#FFFFFF", neutralDark[20] ?? "#000000"),
514
+ "--color-background-inverted": lightDark(neutralLight[10] ?? "#000000", neutralDark[99] ?? "#FFFFFF"),
515
+ "--color-border": lightDark(hexWithAlpha(neutralLight[10] ?? "#000000", borderAlpha), hexWithAlpha(neutralDark[95] ?? "#FFFFFF", borderAlpha)),
516
+ "--color-border-emphasized": borderEmphasized,
517
+ "--color-skeleton": lightDark(neutralVariantLight[70] ?? "#000000", neutralVariantDark[30] ?? "#FFFFFF"),
518
+ "--color-track": lightDark(neutralVariantLight[70] ?? "#000000", neutralVariantDark[30] ?? "#FFFFFF"),
519
+ "--color-shadow": lightDark(hexWithAlpha(neutralLight[0] ?? "#000000", .1), hexWithAlpha(neutralDark[0] ?? "#000000", .3)),
520
+ "--color-tint-hover": lightDark("black", "white")
521
+ };
522
+ }
523
+ //#endregion
524
+ //#region src/Theme/expandMotionScale.ts
525
+ function assertMotion(config) {
526
+ for (const [label, value] of [
527
+ ["fast", config.fast],
528
+ ["medium", config.medium],
529
+ ["slow", config.slow]
530
+ ]) {
531
+ if (value == null) continue;
532
+ if (!Number.isFinite(value) || value < 0) throw new Error(`Theme motion ${label} must be a non-negative number of milliseconds.`);
533
+ }
534
+ if (!Number.isFinite(config.ratio) || config.ratio <= 0 || config.ratio > 1) throw new Error("Theme motion ratio must be greater than 0 and at most 1.");
535
+ if (config.easing != null && /[;{}<>\n\r]/.test(config.easing)) throw new Error("Theme motion easing has an unsupported value.");
536
+ }
537
+ function roundMs(ms) {
538
+ return Math.round(ms / 5) * 5;
539
+ }
540
+ /** `--duration-*` and an optional `--ease-standard`. */
541
+ function expandMotionScale(config) {
542
+ assertMotion(config);
543
+ const { fast, medium, slow, ratio, easing } = config;
544
+ const tokens = {
545
+ "--duration-fast-min": `${roundMs(fast * ratio)}ms`,
546
+ "--duration-fast": `${roundMs(fast)}ms`,
547
+ "--duration-fast-max": `${roundMs(fast / ratio)}ms`,
548
+ "--duration-medium-min": `${roundMs(medium * ratio)}ms`,
549
+ "--duration-medium": `${roundMs(medium)}ms`,
550
+ "--duration-medium-max": `${roundMs(medium / ratio)}ms`
551
+ };
552
+ if (slow != null) {
553
+ tokens["--duration-slow-min"] = `${roundMs(slow * ratio)}ms`;
554
+ tokens["--duration-slow"] = `${roundMs(slow)}ms`;
555
+ tokens["--duration-slow-max"] = `${roundMs(slow / ratio)}ms`;
556
+ }
557
+ if (easing) tokens["--ease-standard"] = easing;
558
+ return tokens;
559
+ }
560
+ //#endregion
561
+ //#region src/Theme/expandRadiusScale.ts
562
+ function assertRadius(config) {
563
+ if (!Number.isFinite(config.base) || config.base < 0) throw new Error("Theme radius base must be a non-negative number of pixels.");
564
+ if (!Number.isFinite(config.multiplier) || config.multiplier < 0) throw new Error("Theme radius multiplier must be a non-negative number.");
565
+ }
566
+ /** `--radius-*` tokens. Names are unprefixed; `defineTheme()` adds `--astryx-`. */
567
+ function expandRadiusScale(config) {
568
+ assertRadius(config);
569
+ const { base, multiplier } = config;
570
+ const step = (factor) => `${Math.round(base * factor * multiplier)}px`;
571
+ return {
572
+ "--radius-none": "0px",
573
+ "--radius-inner": step(1),
574
+ "--radius-element": step(2),
575
+ "--radius-container": step(3),
576
+ "--radius-page": step(7),
577
+ "--radius-chat": step(7),
578
+ "--radius-full": "9999px"
579
+ };
580
+ }
581
+ //#endregion
582
+ //#region src/Theme/expandTypeScale.ts
583
+ const STEP_TO_SIZE_TOKEN = {
584
+ [-5]: "--font-size-4xs",
585
+ [-4]: "--font-size-3xs",
586
+ [-3]: "--font-size-2xs",
587
+ [-2]: "--font-size-xs",
588
+ [-1]: "--font-size-sm",
589
+ 0: "--font-size-base",
590
+ 1: "--font-size-lg",
591
+ 2: "--font-size-xl",
592
+ 3: "--font-size-2xl",
593
+ 4: "--font-size-3xl",
594
+ 5: "--font-size-4xl",
595
+ 6: "--font-size-5xl"
596
+ };
597
+ const HEADING_STEPS = {
598
+ 1: 3,
599
+ 2: 2,
600
+ 3: 1,
601
+ 4: 0,
602
+ 5: -1,
603
+ 6: -2
604
+ };
605
+ const TEXT_STEPS = {
606
+ "body": 0,
607
+ "large": 1,
608
+ "label": 0,
609
+ "code": 0,
610
+ "supporting": -1,
611
+ "display-1": 6,
612
+ "display-2": 5,
613
+ "display-3": 4
614
+ };
615
+ const DEFAULT_HEADING_WEIGHTS = {
616
+ 1: "var(--font-weight-semibold)",
617
+ 2: "var(--font-weight-semibold)",
618
+ 3: "var(--font-weight-semibold)",
619
+ 4: "var(--font-weight-semibold)",
620
+ 5: "var(--font-weight-semibold)",
621
+ 6: "var(--font-weight-semibold)"
622
+ };
623
+ const DEFAULT_TEXT_WEIGHTS = {
624
+ "body": "var(--font-weight-normal)",
625
+ "large": "var(--font-weight-semibold)",
626
+ "label": "var(--font-weight-medium)",
627
+ "code": "var(--font-weight-normal)",
628
+ "supporting": "var(--font-weight-normal)",
629
+ "display-1": "var(--font-weight-normal)",
630
+ "display-2": "var(--font-weight-normal)",
631
+ "display-3": "var(--font-weight-normal)"
632
+ };
633
+ const TEXT_FONT_FAMILIES = {
634
+ "body": "var(--font-family-body)",
635
+ "large": "var(--font-family-body)",
636
+ "label": "var(--font-family-body)",
637
+ "code": "var(--font-family-code)",
638
+ "supporting": "var(--font-family-body)",
639
+ "display-1": "var(--font-family-heading)",
640
+ "display-2": "var(--font-family-heading)",
641
+ "display-3": "var(--font-family-heading)"
642
+ };
643
+ function assertScale(config) {
644
+ if (!Number.isFinite(config.base) || config.base <= 0) throw new Error("Theme type scale base must be a positive number of pixels.");
645
+ if (!Number.isFinite(config.ratio) || config.ratio <= 0) throw new Error("Theme type scale ratio must be a positive number.");
646
+ }
647
+ function computeSize(base, ratio, step) {
648
+ return Math.round(base * ratio ** step);
649
+ }
650
+ function pxToRem(px) {
651
+ return `${Math.round(px / 16 * 1e4) / 1e4}rem`;
652
+ }
653
+ /** Under 20px uses 1.5, under 32px uses 1.4, and the rest uses 1.25. */
654
+ function targetLeadingRatio(fontSize) {
655
+ if (fontSize < 20) return 1.5;
656
+ if (fontSize < 32) return 1.4;
657
+ return 1.25;
658
+ }
659
+ function computeLeading(fontSize) {
660
+ const raw = fontSize * targetLeadingRatio(fontSize);
661
+ const snapped = Math.max(Math.round(raw / 4) * 4, Math.ceil((fontSize + 4) / 4) * 4);
662
+ return Math.round(snapped / fontSize * 1e4) / 1e4;
663
+ }
664
+ /**
665
+ * Raw `--font-size-*` steps, then heading and text roles.
666
+ *
667
+ * Sizes on the roles point at the raw steps with `var()`. Line heights are
668
+ * unitless ratios snapped onto a 4px grid. Weights point at `--font-weight-*`.
669
+ */
670
+ function expandTypeScale(config) {
671
+ assertScale(config);
672
+ const { base, ratio, weights } = config;
673
+ const tokens = {};
674
+ const headingWeights = {
675
+ ...DEFAULT_HEADING_WEIGHTS,
676
+ ...weights?.heading
677
+ };
678
+ const textWeights = {
679
+ ...DEFAULT_TEXT_WEIGHTS,
680
+ ...weights?.text
681
+ };
682
+ for (let step = -5; step <= 6; step += 1) {
683
+ const name = STEP_TO_SIZE_TOKEN[step];
684
+ if (name) tokens[name] = pxToRem(computeSize(base, ratio, step));
685
+ }
686
+ for (const level of [
687
+ 1,
688
+ 2,
689
+ 3,
690
+ 4,
691
+ 5,
692
+ 6
693
+ ]) {
694
+ const step = HEADING_STEPS[level] ?? 0;
695
+ const size = computeSize(base, ratio, step);
696
+ const sizeToken = STEP_TO_SIZE_TOKEN[step];
697
+ tokens[`--text-heading-${level}-size`] = `var(${sizeToken})`;
698
+ tokens[`--text-heading-${level}-weight`] = headingWeights[level] ?? "var(--font-weight-semibold)";
699
+ tokens[`--text-heading-${level}-leading`] = `${computeLeading(size)}`;
700
+ }
701
+ for (const [type, step] of Object.entries(TEXT_STEPS)) {
702
+ const size = computeSize(base, ratio, step);
703
+ tokens[`--text-${type}-size`] = `var(${STEP_TO_SIZE_TOKEN[step]})`;
704
+ tokens[`--text-${type}-weight`] = textWeights[type] ?? DEFAULT_TEXT_WEIGHTS[type] ?? "var(--font-weight-normal)";
705
+ tokens[`--text-${type}-leading`] = `${computeLeading(size)}`;
706
+ }
707
+ return tokens;
708
+ }
709
+ /**
710
+ * Heading and text rules that read the generated tokens.
711
+ *
712
+ * `type:display-*` is emitted after `level:*` so display sizing wins when a
713
+ * heading carries both classes.
714
+ */
715
+ function generateTypeScaleComponents() {
716
+ const heading = {};
717
+ for (const level of [
718
+ 1,
719
+ 2,
720
+ 3,
721
+ 4,
722
+ 5,
723
+ 6
724
+ ]) heading[`level:${level}`] = {
725
+ fontFamily: "var(--font-family-heading)",
726
+ fontSize: `var(--text-heading-${level}-size)`,
727
+ fontWeight: `var(--text-heading-${level}-weight)`,
728
+ lineHeight: `var(--text-heading-${level}-leading)`
729
+ };
730
+ for (const type of [
731
+ "display-1",
732
+ "display-2",
733
+ "display-3"
734
+ ]) heading[`type:${type}`] = {
735
+ fontFamily: "var(--font-family-heading)",
736
+ fontSize: `var(--text-${type}-size)`,
737
+ lineHeight: `var(--text-${type}-leading)`
738
+ };
739
+ const text = {};
740
+ for (const type of [
741
+ "body",
742
+ "large",
743
+ "label",
744
+ "code",
745
+ "supporting",
746
+ "display-1",
747
+ "display-2",
748
+ "display-3"
749
+ ]) text[`type:${type}`] = {
750
+ fontFamily: TEXT_FONT_FAMILIES[type] ?? "var(--font-family-body)",
751
+ fontSize: `var(--text-${type}-size)`,
752
+ lineHeight: `var(--text-${type}-leading)`
753
+ };
754
+ return {
755
+ heading,
756
+ text
757
+ };
758
+ }
759
+ //#endregion
760
+ //#region src/Theme/typography.ts
761
+ const NAMED_WEIGHTS = {
762
+ normal: "var(--font-weight-normal)",
763
+ regular: "var(--font-weight-normal)",
764
+ medium: "var(--font-weight-medium)",
765
+ semibold: "var(--font-weight-semibold)",
766
+ bold: "var(--font-weight-bold)"
767
+ };
768
+ function weightToken(value) {
769
+ return NAMED_WEIGHTS[value.trim()] ?? value;
770
+ }
771
+ function quoteFamily(family) {
772
+ const trimmed = family.trim();
773
+ if (trimmed.startsWith("\"") || trimmed.startsWith("'")) return trimmed;
774
+ if (/[^a-z0-9-]/i.test(trimmed)) return `"${trimmed.replace(/"/g, "")}"`;
775
+ return trimmed;
776
+ }
777
+ function fontStack(role) {
778
+ if (!role?.family && !role?.fallbacks) return void 0;
779
+ const family = role.family ? quoteFamily(role.family) : void 0;
780
+ if (family && role.fallbacks) return `${family}, ${role.fallbacks}`;
781
+ return family ?? role.fallbacks;
782
+ }
783
+ function headingSizeAliases(tokens) {
784
+ const aliases = {};
785
+ for (let level = 1; level <= 6; level += 1) {
786
+ const size = `--text-heading-${level}-size`;
787
+ if (tokens[size]) aliases[`--heading-level-${level}-size`] = `var(${size})`;
788
+ }
789
+ for (const step of [
790
+ 1,
791
+ 2,
792
+ 3
793
+ ]) {
794
+ const size = `--text-display-${step}-size`;
795
+ if (tokens[size]) aliases[`--heading-display-${step}-size`] = `var(${size})`;
796
+ }
797
+ return aliases;
798
+ }
799
+ function assignHeadingWeight(heading, level, weight) {
800
+ if (level >= 1 && level <= 6) heading[level] = weightToken(weight);
801
+ }
802
+ function scaleConfig(config) {
803
+ const scale = config.scale;
804
+ if (!scale) throw new Error("Theme typography scale is missing.");
805
+ const heading = {};
806
+ if (config.heading?.weight) {
807
+ const weight = weightToken(config.heading.weight);
808
+ for (const level of [
809
+ 1,
810
+ 2,
811
+ 3,
812
+ 4,
813
+ 5,
814
+ 6
815
+ ]) heading[level] = weight;
816
+ }
817
+ for (const [level, weight] of Object.entries(config.heading?.weights ?? {})) if (weight) assignHeadingWeight(heading, Number(level), weight);
818
+ for (const [level, weight] of Object.entries(scale.weights?.heading ?? {})) if (weight) assignHeadingWeight(heading, Number(level), weight);
819
+ const text = {};
820
+ if (config.body?.weight) text.body = weightToken(config.body.weight);
821
+ if (config.code?.weight) text.code = weightToken(config.code.weight);
822
+ for (const [name, weight] of Object.entries(scale.weights?.text ?? {})) if (weight) text[name] = weightToken(weight);
823
+ return {
824
+ base: scale.base,
825
+ ratio: scale.ratio,
826
+ weights: {
827
+ heading,
828
+ text
829
+ }
830
+ };
831
+ }
832
+ /**
833
+ * Font stacks, the type scale, and the heading size aliases Heading reads.
834
+ * Heading inherits the body stack when it does not name its own.
835
+ */
836
+ function resolveTypography(config) {
837
+ if (!config) return { tokens: {} };
838
+ const tokens = {};
839
+ const bodyStack = fontStack(config.body);
840
+ const headingStack = fontStack(config.heading) ?? bodyStack;
841
+ const codeStack = fontStack(config.code);
842
+ if (bodyStack) tokens["--font-family-body"] = bodyStack;
843
+ if (headingStack) tokens["--font-family-heading"] = headingStack;
844
+ if (codeStack) tokens["--font-family-code"] = codeStack;
845
+ const components = {};
846
+ if (config.scale) {
847
+ Object.assign(tokens, expandTypeScale(scaleConfig(config)));
848
+ Object.assign(tokens, headingSizeAliases(tokens));
849
+ Object.assign(components, generateTypeScaleComponents());
850
+ }
851
+ if (fontStack(config.heading)) components.heading = {
852
+ ...components.heading,
853
+ base: {
854
+ fontFamily: "var(--font-family-heading)",
855
+ ...components.heading?.base
856
+ }
857
+ };
858
+ if (codeStack) components.text = {
859
+ ...components.text,
860
+ "type:code": {
861
+ fontFamily: "var(--font-family-code)",
862
+ ...components.text?.["type:code"]
863
+ }
864
+ };
865
+ return {
866
+ tokens,
867
+ ...Object.keys(components).length > 0 ? { components } : {}
868
+ };
869
+ }
870
+ //#endregion
871
+ //#region src/Theme/resolveThemeValues.ts
872
+ function isTokenPair(value) {
873
+ return Array.isArray(value) && value.length === 2 && typeof value[0] === "string" && typeof value[1] === "string";
874
+ }
875
+ /**
876
+ * One token value as CSS. A string is used as written and a `[light, dark]`
877
+ * tuple becomes `light-dark()`. Anything else is not a token value.
878
+ */
879
+ function tokenValueToCss(value, path) {
880
+ if (typeof value === "string") return prefixTokenReferences(value);
881
+ if (isTokenPair(value)) return prefixTokenReferences(`light-dark(${value[0]}, ${value[1]})`);
882
+ throw new Error(`${path} must be a CSS string or a [light, dark] string tuple.`);
883
+ }
884
+ /**
885
+ * Write a token map with the `--astryx-` prefix.
886
+ *
887
+ * A name or value that cannot stay one CSS declaration is dropped with a
888
+ * warning, and the rest of the theme still applies.
889
+ */
890
+ function resolveTokenMap(tokens, location) {
891
+ const resolved = {};
892
+ for (const [name, value] of Object.entries(tokens ?? {})) {
893
+ if (value == null) continue;
894
+ const key = normalizeTokenName(name);
895
+ const css = tokenValueToCss(value, `${location}["${name}"]`);
896
+ const reason = checkDeclarationName(key) ?? checkDeclarationValue(css);
897
+ if (reason != null) {
898
+ warnDroppedDeclaration(key, css, location, reason);
899
+ continue;
900
+ }
901
+ resolved[key] = css;
902
+ }
903
+ return resolved;
904
+ }
905
+ /**
906
+ * Merge component maps. `next` wins per style key and per property, so a
907
+ * child that restates one property of `button.base` keeps the rest.
908
+ */
909
+ function mergeComponentMaps(base, next) {
910
+ if (base == null) return next;
911
+ if (next == null) return base;
912
+ const merged = {};
913
+ for (const [component, rules] of Object.entries(base)) merged[component] = { ...rules };
914
+ for (const [component, rules] of Object.entries(next)) {
915
+ const target = merged[component] ?? {};
916
+ for (const [key, styles] of Object.entries(rules)) target[key] = {
917
+ ...target[key],
918
+ ...styles
919
+ };
920
+ merged[component] = target;
921
+ }
922
+ return merged;
923
+ }
924
+ /**
925
+ * Expand the generator axes, then lay explicit `tokens` over the result.
926
+ * Explicit tokens win token by token. Authored component styles win over
927
+ * the generated type-scale rules property by property.
928
+ */
929
+ function resolveThemeValues(input, location) {
930
+ const typography = resolveTypography(input.typography);
931
+ return {
932
+ tokens: {
933
+ ...resolveTokenMap({
934
+ ...input.color ? expandColorScale(input.color) : {},
935
+ ...typography.tokens,
936
+ ...input.radius ? expandRadiusScale(input.radius) : {},
937
+ ...input.motion ? expandMotionScale(input.motion) : {}
938
+ }, `${location}generated`),
939
+ ...resolveTokenMap(input.tokens, `${location}tokens`)
940
+ },
941
+ components: mergeComponentMaps(typography.components, input.components)
942
+ };
943
+ }
944
+ //#endregion
945
+ //#region src/Theme/localTokens.ts
946
+ const CUSTOM_PROPERTY_NAME = /^--[\w-]+$/;
947
+ const VAR_REFERENCE = /var\(\s*(--[\w-]+)/g;
948
+ function references(value) {
949
+ return [...value.matchAll(VAR_REFERENCE)].map((match) => match[1] ?? "");
950
+ }
951
+ /** A readable loop inside one strongly connected group, starting at `start`. */
952
+ function cyclePath(start, group, edges) {
953
+ const path = [start];
954
+ const seen = new Set(path);
955
+ const search = (name) => {
956
+ for (const next of edges.get(name) ?? []) {
957
+ if (!group.has(next)) continue;
958
+ if (next === start) {
959
+ path.push(start);
960
+ return true;
961
+ }
962
+ if (seen.has(next)) continue;
963
+ path.push(next);
964
+ seen.add(next);
965
+ if (search(next)) return true;
966
+ path.pop();
967
+ }
968
+ return false;
969
+ };
970
+ search(start);
971
+ return path;
972
+ }
973
+ /**
974
+ * Throw when values in `tokens` reference each other in a loop.
975
+ *
976
+ * A loop makes every token on it invalid at computed-value time, so the
977
+ * theme would silently lose those values. `relevant` limits the report to
978
+ * loops whose strongly connected group holds at least one of those names,
979
+ * so a loop that was already in the root theme is not blamed on a rule.
980
+ */
981
+ function assertNoTokenCycles(tokens, context, relevant) {
982
+ const edges = /* @__PURE__ */ new Map();
983
+ for (const [name, value] of Object.entries(tokens)) edges.set(name, references(value).filter((next) => Object.hasOwn(tokens, next)));
984
+ let counter = 0;
985
+ const index = /* @__PURE__ */ new Map();
986
+ const low = /* @__PURE__ */ new Map();
987
+ const stack = [];
988
+ const onStack = /* @__PURE__ */ new Set();
989
+ const visit = (name) => {
990
+ const own = counter++;
991
+ index.set(name, own);
992
+ low.set(name, own);
993
+ stack.push(name);
994
+ onStack.add(name);
995
+ for (const next of edges.get(name) ?? []) if (!index.has(next)) {
996
+ visit(next);
997
+ low.set(name, Math.min(low.get(name) ?? own, low.get(next) ?? own));
998
+ } else if (onStack.has(next)) low.set(name, Math.min(low.get(name) ?? own, index.get(next) ?? own));
999
+ if (low.get(name) !== own) return;
1000
+ const group = [];
1001
+ let member;
1002
+ do {
1003
+ member = stack.pop();
1004
+ if (member === void 0) break;
1005
+ onStack.delete(member);
1006
+ group.push(member);
1007
+ } while (member !== name);
1008
+ if (!(group.length > 1 || (edges.get(name) ?? []).includes(name)) || relevant && !group.some((item) => relevant.has(item))) return;
1009
+ const start = group.find((item) => relevant?.has(item)) ?? name;
1010
+ throw new Error(`${context}: theme token cycle detected: ${cyclePath(start, new Set(group), edges).join(" -> ")}.`);
1011
+ };
1012
+ for (const name of Object.keys(tokens)) if (!index.has(name)) visit(name);
1013
+ }
1014
+ /**
1015
+ * Resolve `localTokens` for one theme.
1016
+ *
1017
+ * Names are kept exactly as written: a theme-local token is the theme
1018
+ * family's own vocabulary, not a shared token, so no prefix is added.
1019
+ * A child theme inherits its base's local tokens and may replace their
1020
+ * values; the first theme to declare a name stays its owner.
1021
+ *
1022
+ * Refused:
1023
+ * - a name that is not a custom property;
1024
+ * - a shared token name such as `--color-accent` or `--astryx-spacing-4`,
1025
+ * because components already read that name with a fixed meaning;
1026
+ * - a name the theme also sets through `tokens`;
1027
+ * - a reference cycle among the local tokens.
1028
+ */
1029
+ function resolveLocalTokens(themeName, declarations, base, portableTokens) {
1030
+ if (declarations === void 0 && base?.localTokens === void 0) return void 0;
1031
+ if (declarations !== void 0 && (declarations === null || typeof declarations !== "object" || Array.isArray(declarations))) throw new Error(`defineTheme("${themeName}"): localTokens must be a token map.`);
1032
+ const localTokens = { ...base?.localTokens };
1033
+ const owners = { ...base?.localTokenOwners };
1034
+ for (const [name, value] of Object.entries(declarations ?? {})) {
1035
+ const path = `defineTheme("${themeName}").localTokens["${name}"]`;
1036
+ if (!CUSTOM_PROPERTY_NAME.test(name)) throw new Error(`${path}: a local token name must be a CSS custom property such as --brand-ink.`);
1037
+ if (isPortableTokenName(name)) throw new Error(`${path}: "${name}" is a shared theme token. Set it through tokens, or pick a name outside the shared vocabulary.`);
1038
+ const css = tokenValueToCss(value, path);
1039
+ const reason = checkDeclarationValue(css);
1040
+ if (reason != null) throw new Error(`${path}: ${reason}.`);
1041
+ localTokens[name] = css;
1042
+ owners[name] ??= themeName;
1043
+ }
1044
+ for (const name of Object.keys(localTokens)) if (Object.hasOwn(portableTokens, name)) throw new Error(`defineTheme("${themeName}"): token "${name}" cannot be declared in both tokens and localTokens.`);
1045
+ assertNoTokenCycles(localTokens, `defineTheme("${themeName}").localTokens`);
1046
+ return {
1047
+ localTokens,
1048
+ owners
1049
+ };
1050
+ }
1051
+ /**
1052
+ * Resolve the local-token writes of one adaptation rule.
1053
+ *
1054
+ * A rule may give a new value to a name the root theme lineage declared. It
1055
+ * cannot introduce a name of its own.
1056
+ */
1057
+ function resolveAdaptationLocalTokens(path, declarations, rootLocalTokens) {
1058
+ if (declarations === void 0) return void 0;
1059
+ const resolved = {};
1060
+ for (const [name, value] of Object.entries(declarations)) {
1061
+ if (!rootLocalTokens || !Object.hasOwn(rootLocalTokens, name)) throw new Error(`${path}["${name}"] cannot add a theme-local token. Declare it in the root theme or a theme it extends first.`);
1062
+ const css = tokenValueToCss(value, `${path}["${name}"]`);
1063
+ const reason = checkDeclarationValue(css);
1064
+ if (reason != null) throw new Error(`${path}["${name}"]: ${reason}.`);
1065
+ resolved[name] = css;
1066
+ }
1067
+ return Object.keys(resolved).length > 0 ? resolved : void 0;
1068
+ }
1069
+ //#endregion
1070
+ //#region src/Theme/adaptations.ts
1071
+ const BREAKPOINT_NAMES = new Set(WIDTH_BREAKPOINT_NAMES);
1072
+ const CONDITION_KEYS = /* @__PURE__ */ new Set([
1073
+ "width",
1074
+ "pointer",
1075
+ "contrast",
1076
+ "motion"
1077
+ ]);
1078
+ const VALUE_KEYS = /* @__PURE__ */ new Set([
1079
+ "typography",
1080
+ "color",
1081
+ "radius",
1082
+ "motion",
1083
+ "tokens",
1084
+ "localTokens",
1085
+ "components"
1086
+ ]);
1087
+ const CONDITION_VALUES = {
1088
+ pointer: ["coarse", "fine"],
1089
+ contrast: [
1090
+ "more",
1091
+ "less",
1092
+ "no-preference"
1093
+ ],
1094
+ motion: ["reduce", "no-preference"]
1095
+ };
1096
+ function isRecord(value) {
1097
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1098
+ }
1099
+ function assertRecord(value, path, allowed) {
1100
+ if (!isRecord(value)) throw new Error(`${path} must be an object.`);
1101
+ for (const key of Object.keys(value)) if (allowed && !allowed.has(key)) throw new Error(`${path}.${key} is not supported.`);
1102
+ }
1103
+ function normalizeBreakpoints(value, path) {
1104
+ assertRecord(value, path, BREAKPOINT_NAMES);
1105
+ const points = {};
1106
+ for (const name of WIDTH_BREAKPOINT_NAMES) {
1107
+ const point = value[name];
1108
+ if (point === void 0) continue;
1109
+ if (typeof point !== "number" || !Number.isFinite(point) || point <= 0) throw new Error(`${path}.${name} must be a finite positive number of CSS pixels.`);
1110
+ points[name] = point;
1111
+ }
1112
+ return points;
1113
+ }
1114
+ function normalizeCondition(value, path) {
1115
+ assertRecord(value, path, CONDITION_KEYS);
1116
+ const defined = Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== void 0));
1117
+ if (Object.keys(defined).length === 0) throw new Error(`${path} must contain at least one condition.`);
1118
+ if (defined.width !== void 0) {
1119
+ assertRecord(defined.width, `${path}.width`, /* @__PURE__ */ new Set(["from", "below"]));
1120
+ const { from, below } = defined.width;
1121
+ if (from === void 0 && below === void 0) throw new Error(`${path}.width must contain \`from\`, \`below\`, or both.`);
1122
+ for (const [edge, name] of [["from", from], ["below", below]]) if (name !== void 0 && (typeof name !== "string" || !BREAKPOINT_NAMES.has(name))) throw new Error(`${path}.width.${edge} must be one of ${WIDTH_BREAKPOINT_NAMES.join(", ")}.`);
1123
+ }
1124
+ for (const [key, allowed] of Object.entries(CONDITION_VALUES)) {
1125
+ const field = defined[key];
1126
+ if (field !== void 0 && !allowed.includes(field)) throw new Error(`${path}.${key} must be ${allowed.map((item) => `'${item}'`).join(" or ")}.`);
1127
+ }
1128
+ return structuredClone(defined);
1129
+ }
1130
+ function normalizeRule(value, path) {
1131
+ assertRecord(value, path, /* @__PURE__ */ new Set(["when", "value"]));
1132
+ if (!Object.hasOwn(value, "when")) throw new Error(`${path}.when is required.`);
1133
+ if (!Object.hasOwn(value, "value")) throw new Error(`${path}.value is required.`);
1134
+ assertRecord(value.value, `${path}.value`, VALUE_KEYS);
1135
+ for (const key of VALUE_KEYS) {
1136
+ const nested = value.value[key];
1137
+ if (nested !== void 0 && !isRecord(nested)) throw new Error(`${path}.value.${key} must be an object.`);
1138
+ }
1139
+ return {
1140
+ when: normalizeCondition(value.when, `${path}.when`),
1141
+ value: structuredClone(value.value)
1142
+ };
1143
+ }
1144
+ /**
1145
+ * Validate adaptations and append them to the inherited ones.
1146
+ *
1147
+ * Width points merge over the inherited map and must strictly increase.
1148
+ * Inherited rules come first, so a child's rules win when both match.
1149
+ */
1150
+ function normalizeThemeAdaptations(themeName, inherited, input) {
1151
+ const path = `defineTheme("${themeName}").adaptations`;
1152
+ let points = {};
1153
+ let rules = [];
1154
+ if (input !== void 0) {
1155
+ assertRecord(input, path, /* @__PURE__ */ new Set(["widthBreakpoints", "rules"]));
1156
+ if (input.widthBreakpoints !== void 0) points = normalizeBreakpoints(input.widthBreakpoints, `${path}.widthBreakpoints`);
1157
+ if (input.rules !== void 0) {
1158
+ if (!Array.isArray(input.rules)) throw new Error(`${path}.rules must be an array of {when, value} objects.`);
1159
+ rules = Array.from(input.rules, (rule, index) => normalizeRule(rule, `${path}.rules[${index}]`));
1160
+ }
1161
+ }
1162
+ const widthBreakpoints = {
1163
+ ...DEFAULT_WIDTH_BREAKPOINTS,
1164
+ ...inherited?.widthBreakpoints,
1165
+ ...points
1166
+ };
1167
+ WIDTH_BREAKPOINT_NAMES.reduce((previous, name) => {
1168
+ if (widthBreakpoints[name] <= widthBreakpoints[previous]) throw new Error(`${path}.widthBreakpoints must be strictly increasing: ${name} (${widthBreakpoints[name]}) is not above ${previous} (${widthBreakpoints[previous]}).`);
1169
+ return name;
1170
+ });
1171
+ return {
1172
+ widthBreakpoints,
1173
+ rules: [...inherited?.rules ?? [], ...rules]
1174
+ };
1175
+ }
1176
+ /** Media query text for one condition, in a fixed field order. */
1177
+ function mediaQuery(condition, points, path) {
1178
+ const parts = [];
1179
+ const { from, below } = condition.width ?? {};
1180
+ if (from !== void 0 && below !== void 0 && points[from] >= points[below]) throw new Error(`${path}.width must resolve to \`from < below\`; ${from} is ${points[from]}px and ${below} is ${points[below]}px.`);
1181
+ if (from !== void 0) parts.push(`(width >= ${points[from]}px)`);
1182
+ if (below !== void 0) parts.push(`(width < ${points[below]}px)`);
1183
+ if (condition.pointer !== void 0) parts.push(`(pointer: ${condition.pointer})`);
1184
+ if (condition.contrast !== void 0) parts.push(`(prefers-contrast: ${condition.contrast})`);
1185
+ if (condition.motion !== void 0) parts.push(`(prefers-reduced-motion: ${condition.motion})`);
1186
+ return parts.join(" and ");
1187
+ }
1188
+ function mergeRole$1(root, rule) {
1189
+ if (!root || !rule) return rule ?? root;
1190
+ return {
1191
+ ...root,
1192
+ ...rule,
1193
+ weights: root.weights || rule.weights ? {
1194
+ ...root.weights,
1195
+ ...rule.weights
1196
+ } : void 0
1197
+ };
1198
+ }
1199
+ function completeNumbers(root, rule, required, path) {
1200
+ const merged = {
1201
+ ...root,
1202
+ ...rule
1203
+ };
1204
+ for (const key of required) {
1205
+ const value = merged[key];
1206
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`${path}.${String(key)} is missing; supply it in the rule or on the root theme.`);
1207
+ }
1208
+ return merged;
1209
+ }
1210
+ function ruleInput(value, axes, path) {
1211
+ let typography;
1212
+ if (value.typography) {
1213
+ const scale = value.typography.scale || axes.typography?.scale ? completeNumbers(axes.typography?.scale, value.typography.scale ?? {}, ["base", "ratio"], `${path}.typography.scale`) : void 0;
1214
+ typography = {
1215
+ ...scale ? { scale: {
1216
+ base: scale.base,
1217
+ ratio: scale.ratio
1218
+ } } : {},
1219
+ body: mergeRole$1(axes.typography?.body, value.typography.body),
1220
+ heading: mergeRole$1(axes.typography?.heading, value.typography.heading),
1221
+ code: mergeRole$1(axes.typography?.code, value.typography.code)
1222
+ };
1223
+ }
1224
+ return {
1225
+ typography,
1226
+ color: value.color ? {
1227
+ ...axes.color,
1228
+ ...value.color
1229
+ } : void 0,
1230
+ radius: value.radius ? completeNumbers(axes.radius, value.radius, ["base", "multiplier"], `${path}.radius`) : void 0,
1231
+ motion: value.motion ? completeNumbers(axes.motion, value.motion, [
1232
+ "fast",
1233
+ "medium",
1234
+ "ratio"
1235
+ ], `${path}.motion`) : void 0,
1236
+ tokens: value.tokens,
1237
+ components: value.components
1238
+ };
1239
+ }
1240
+ /**
1241
+ * Type-scale rules a rule regenerates that the root already declares with the
1242
+ * same value only repeat root CSS. Dropping them keeps the root's authored
1243
+ * component pins in force. Authored rule writes are always kept.
1244
+ */
1245
+ function omitRootDuplicates(resolved, root, authored) {
1246
+ if (!resolved || !root) return resolved;
1247
+ const kept = {};
1248
+ for (const [target, rules] of Object.entries(resolved)) for (const [key, styles] of Object.entries(rules)) {
1249
+ const writes = Object.fromEntries(Object.entries(styles).filter(([property]) => root[target]?.[key]?.[property] === void 0 || Object.hasOwn(authored?.[target]?.[key] ?? {}, property)));
1250
+ if (Object.keys(writes).length > 0) (kept[target] ??= {})[key] = writes;
1251
+ }
1252
+ return Object.keys(kept).length > 0 ? kept : void 0;
1253
+ }
1254
+ function conditionMatches(condition, points, env) {
1255
+ const { from, below } = condition.width ?? {};
1256
+ if (from !== void 0 && env.width < points[from]) return false;
1257
+ if (below !== void 0 && env.width >= points[below]) return false;
1258
+ return [
1259
+ "pointer",
1260
+ "contrast",
1261
+ "motion"
1262
+ ].every((key) => condition[key] === void 0 || condition[key] === env[key]);
1263
+ }
1264
+ /**
1265
+ * Check every environment the rules can meet together. In each one the
1266
+ * matching rules write in order over the root, like the CSS cascade, and the
1267
+ * result must hold no reference cycle through a name a rule wrote. A later
1268
+ * matching rule may repair a cycle an earlier one made.
1269
+ */
1270
+ function assertNoReachableCycles(themeName, points, root, rules) {
1271
+ const writers = rules.flatMap((rule, index) => Object.keys(rule.tokens).length > 0 || rule.localTokens ? [index] : []);
1272
+ if (writers.length === 0) return;
1273
+ const checked = /* @__PURE__ */ new Set();
1274
+ for (const width of [0, ...WIDTH_BREAKPOINT_NAMES.map((name) => points[name])]) for (const pointer of [
1275
+ "coarse",
1276
+ "fine",
1277
+ "none"
1278
+ ]) for (const contrast of [
1279
+ "more",
1280
+ "less",
1281
+ "no-preference",
1282
+ "custom"
1283
+ ]) for (const motion of ["reduce", "no-preference"]) {
1284
+ const matching = writers.filter((index) => conditionMatches(rules[index].when, points, {
1285
+ width,
1286
+ pointer,
1287
+ contrast,
1288
+ motion
1289
+ }));
1290
+ const signature = matching.join(",");
1291
+ if (matching.length === 0 || checked.has(signature)) continue;
1292
+ checked.add(signature);
1293
+ const effective = {
1294
+ ...root.tokens,
1295
+ ...root.localTokens
1296
+ };
1297
+ const written = /* @__PURE__ */ new Set();
1298
+ for (const index of matching) {
1299
+ const rule = rules[index];
1300
+ Object.assign(effective, rule.tokens, rule.localTokens);
1301
+ for (const name of [...Object.keys(rule.tokens), ...Object.keys(rule.localTokens ?? {})]) written.add(name);
1302
+ }
1303
+ const label = matching.length === 1 ? "rule" : "overlapping rules";
1304
+ const queries = matching.map((index) => rules[index].query).join("; ");
1305
+ assertNoTokenCycles(effective, `defineTheme("${themeName}").adaptations ${label} [${matching.join(", ")}] (${queries})`, written);
1306
+ }
1307
+ }
1308
+ /** Lower every rule to concrete writes and reject reference cycles they create. */
1309
+ function resolveThemeAdaptationRules(themeName, adaptations, axes, root) {
1310
+ if (adaptations.rules.length === 0) return void 0;
1311
+ const resolved = adaptations.rules.map((rule, index) => {
1312
+ const path = `defineTheme("${themeName}").adaptations.rules[${index}]`;
1313
+ const input = ruleInput(rule.value, axes, `${path}.value`);
1314
+ const values = resolveThemeValues(input, `${path}.value.`);
1315
+ for (const name of Object.keys(rule.value.tokens ?? {})) if (root.localTokens && Object.hasOwn(root.localTokens, name)) throw new Error(`${path}.value.tokens["${name}"] is a theme-local token; write it through value.localTokens.`);
1316
+ const localTokens = resolveAdaptationLocalTokens(`${path}.value.localTokens`, rule.value.localTokens, root.localTokens);
1317
+ return {
1318
+ when: rule.when,
1319
+ query: mediaQuery(rule.when, adaptations.widthBreakpoints, `${path}.when`),
1320
+ tokens: values.tokens,
1321
+ ...localTokens ? { localTokens } : {},
1322
+ components: input.typography?.scale ? omitRootDuplicates(values.components, root.components, rule.value.components) : values.components
1323
+ };
1324
+ });
1325
+ assertNoReachableCycles(themeName, adaptations.widthBreakpoints, root, resolved);
1326
+ return resolved;
1327
+ }
1328
+ //#endregion
1329
+ //#region src/Theme/derivedVars.ts
1330
+ const DERIVED_VARS = {
1331
+ "bottom-sheet": [{
1332
+ property: "padding",
1333
+ expand: "container"
1334
+ }],
1335
+ "card": [{
1336
+ property: "borderRadius",
1337
+ vars: ["--_card-radius"]
1338
+ }, {
1339
+ property: "padding",
1340
+ expand: "container"
1341
+ }],
1342
+ "chat": [{
1343
+ property: "borderRadius",
1344
+ vars: ["--_chat-composer-radius"]
1345
+ }, {
1346
+ property: "padding",
1347
+ vars: ["--_chat-composer-padding"]
1348
+ }],
1349
+ "context-menu": [{
1350
+ property: "borderRadius",
1351
+ vars: ["--_context-menu-radius"]
1352
+ }, {
1353
+ property: "padding",
1354
+ vars: ["--_context-menu-padding"]
1355
+ }],
1356
+ "dialog": [{
1357
+ property: "borderRadius",
1358
+ vars: ["--_dialog-radius"]
1359
+ }, {
1360
+ property: "padding",
1361
+ expand: "container"
1362
+ }],
1363
+ "dropdown-menu": [{
1364
+ property: "borderRadius",
1365
+ vars: ["--_dropdown-menu-radius"]
1366
+ }, {
1367
+ property: "padding",
1368
+ vars: ["--_dropdown-menu-padding"]
1369
+ }],
1370
+ "progress-bar-mark": [{
1371
+ property: "width",
1372
+ vars: ["--_progressbar-mark-width"]
1373
+ }, {
1374
+ property: "height",
1375
+ vars: ["--_progressbar-mark-height"]
1376
+ }],
1377
+ "segmented-control": [{
1378
+ property: "borderRadius",
1379
+ vars: ["--_segmented-control-radius"]
1380
+ }, {
1381
+ property: "padding",
1382
+ vars: ["--_segmented-control-padding"]
1383
+ }]
1384
+ };
1385
+ const PADDING_PROPS = /* @__PURE__ */ new Set([
1386
+ "padding",
1387
+ "paddingBlock",
1388
+ "paddingInline",
1389
+ "paddingBlockStart",
1390
+ "paddingBlockEnd",
1391
+ "paddingInlineStart",
1392
+ "paddingInlineEnd"
1393
+ ]);
1394
+ /**
1395
+ * Physical block longhands and the logical longhand each one is in every
1396
+ * horizontal writing mode. `paddingLeft` and `paddingRight` are not mapped:
1397
+ * which edge they mean flips in right-to-left text.
1398
+ */
1399
+ const PHYSICAL_BLOCK_PADDING = {
1400
+ paddingTop: "paddingBlockStart",
1401
+ paddingBottom: "paddingBlockEnd"
1402
+ };
1403
+ function words(value) {
1404
+ return value.trim().split(/\s+/);
1405
+ }
1406
+ function parsePadding(entries) {
1407
+ const parsed = {};
1408
+ for (const [raw, value] of entries) {
1409
+ const prop = PHYSICAL_BLOCK_PADDING[raw] ?? raw;
1410
+ const parts = words(value);
1411
+ if (prop === "padding") {
1412
+ parsed.blockStart = parts[0];
1413
+ parsed.inline = parts[1] ?? parts[0];
1414
+ parsed.blockEnd = parts[2] ?? parts[0];
1415
+ } else if (prop === "paddingBlock") {
1416
+ parsed.blockStart = parts[0];
1417
+ parsed.blockEnd = parts[1] ?? parts[0];
1418
+ } else if (prop === "paddingInline") {
1419
+ if (parts.length === 1) parsed.inline = parts[0];
1420
+ else {
1421
+ parsed.inlineStart = parts[0];
1422
+ parsed.inlineEnd = parts[1];
1423
+ }
1424
+ } else if (prop === "paddingBlockStart") parsed.blockStart = value;
1425
+ else if (prop === "paddingBlockEnd") parsed.blockEnd = value;
1426
+ else if (prop === "paddingInlineStart") parsed.inlineStart = value;
1427
+ else if (prop === "paddingInlineEnd") parsed.inlineEnd = value;
1428
+ }
1429
+ return parsed;
1430
+ }
1431
+ /** Published container padding variables for one component. */
1432
+ function containerPadding(component, parsed) {
1433
+ const prefix = `--astryx-${component}-padding`;
1434
+ const start = parsed.inlineStart ?? parsed.inline;
1435
+ const end = parsed.inlineEnd ?? parsed.inline;
1436
+ if (start != null && start === end && start === parsed.blockStart && start === parsed.blockEnd) return [[prefix, start]];
1437
+ const out = [];
1438
+ if (parsed.inlineStart != null || parsed.inlineEnd != null) {
1439
+ if (start != null) out.push([`${prefix}-inline-start`, start]);
1440
+ if (end != null) out.push([`${prefix}-inline-end`, end]);
1441
+ } else if (parsed.inline != null) out.push([`${prefix}-inline`, parsed.inline]);
1442
+ if (parsed.blockStart != null) out.push([`${prefix}-block-start`, parsed.blockStart]);
1443
+ if (parsed.blockEnd != null) out.push([`${prefix}-block-end`, parsed.blockEnd]);
1444
+ return out;
1445
+ }
1446
+ function entriesFor(component, property) {
1447
+ const entries = DERIVED_VARS[component] ?? [];
1448
+ const lookup = PADDING_PROPS.has(property) || property in PHYSICAL_BLOCK_PADDING ? "padding" : property;
1449
+ return entries.filter((entry) => entry.property === property || entry.property === lookup);
1450
+ }
1451
+ /**
1452
+ * Lower one rule's declarations through the component's derived variables.
1453
+ *
1454
+ * Input and output are `[camelCase or custom property, value]` pairs. A
1455
+ * container-expanded padding replaces the padding properties; every other
1456
+ * derived variable is written next to the property it mirrors.
1457
+ */
1458
+ function applyDerivedVars(component, declarations) {
1459
+ const derived = [];
1460
+ const padding = [];
1461
+ for (const [property, value] of declarations) for (const entry of entriesFor(component, property)) {
1462
+ if (entry.expand === "container") padding.push([property, value]);
1463
+ for (const name of entry.vars ?? []) derived.push([name, value]);
1464
+ }
1465
+ if (padding.length === 0) return [...declarations.map(([p, v]) => [p, v]), ...derived];
1466
+ const expanded = new Set(padding.map(([property]) => property));
1467
+ return [
1468
+ ...declarations.filter(([property]) => !expanded.has(property)).map(([p, v]) => [p, v]),
1469
+ ...containerPadding(component, parsePadding(padding)),
1470
+ ...derived
1471
+ ];
1472
+ }
1473
+ //#endregion
1474
+ //#region src/Theme/componentStyles.ts
1475
+ /** A theme target: `<component-kebab>` or `<component-kebab>-<part>`. */
1476
+ const TARGET_NAME = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
1477
+ const PROP_NAME = /^[a-z][a-z0-9-]*$/i;
1478
+ const PSEUDO = /* @__PURE__ */ new Set([
1479
+ ":hover",
1480
+ ":focus",
1481
+ ":focus-visible",
1482
+ ":focus-within",
1483
+ ":active",
1484
+ ":checked",
1485
+ ":disabled",
1486
+ ":invalid",
1487
+ ":valid",
1488
+ ":placeholder-shown",
1489
+ ":read-only",
1490
+ ":required"
1491
+ ]);
1492
+ /**
1493
+ * Keeps a themed `:hover` off disabled controls. `:where()` adds no
1494
+ * specificity, so the hover rule still weighs what it would without it.
1495
+ */
1496
+ const HOVER_GUARD = ":where(:not(:disabled, [aria-disabled=\"true\"]))";
1497
+ /**
1498
+ * Check a theme target name.
1499
+ *
1500
+ * Only `<component-kebab>-<part>` names reach the selector. A camelCase or
1501
+ * run-together name such as `buttonIcon`, `progressbar`, or `codeblock` is not
1502
+ * rewritten; it is refused so the author sees the canonical name instead of a
1503
+ * rule that silently matches nothing.
1504
+ */
1505
+ function assertTargetName(name) {
1506
+ if (!TARGET_NAME.test(name)) throw new Error(`Theme component target "${name}" must be written as <component-kebab>-<part>, for example "button" or "card-header".`);
1507
+ return name;
1508
+ }
1509
+ function escapeAttributeValue(value) {
1510
+ return value.replace(/["\\]/g, (char) => `\\${char}`);
1511
+ }
1512
+ function parseStyleKey(key) {
1513
+ return key.split("+").map((part) => {
1514
+ const separator = part.indexOf(":");
1515
+ const prop = separator === -1 ? part : part.slice(0, separator);
1516
+ const value = separator === -1 ? part : part.slice(separator + 1);
1517
+ if (!PROP_NAME.test(prop) || value === "") throw new Error(`Theme component style "${key}" must be base, a state, or prop:value.`);
1518
+ return {
1519
+ axis: prop.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(),
1520
+ value
1521
+ };
1522
+ });
1523
+ }
1524
+ /**
1525
+ * Selectors for one target and style key.
1526
+ *
1527
+ * `variant:secondary` matches the reflected attribute
1528
+ * `.astryx-button[data-variant="secondary"]`, and also this package's
1529
+ * modifier class `.astryx-button--variant-secondary`. The modifier is how
1530
+ * components that do not reflect that axis as `data-*` yet still receive the
1531
+ * rule. Both are scoped to the target, so neither is a bare value class.
1532
+ */
1533
+ function targetSelectors(target, key, surface) {
1534
+ const root = `.astryx-${assertTargetName(target)}`;
1535
+ const selectors = key === "base" ? [root] : (() => {
1536
+ const parts = parseStyleKey(key);
1537
+ const attributes = parts.map((part) => `[data-${part.axis}="${escapeAttributeValue(part.value)}"]`).join("");
1538
+ const modifiers = parts.map((part) => `${root}--${part.axis}-${part.value}`).join("");
1539
+ return parts.every((part) => /^[\w-]+$/.test(part.value)) ? [`${root}${attributes}`, `${root}${modifiers}`] : [`${root}${attributes}`];
1540
+ })();
1541
+ return surface ? selectors.map((selector) => `[data-astryx-media="${surface}"] ${selector}`) : selectors;
1542
+ }
1543
+ function withPseudo(selectors, pseudo) {
1544
+ const suffix = pseudo === ":hover" ? `:hover${HOVER_GUARD}` : pseudo;
1545
+ return selectors.map((selector) => `${selector}${suffix}`).join(", ");
1546
+ }
1547
+ /**
1548
+ * A component style property as CSS. camelCase becomes kebab-case. A custom
1549
+ * property gets the `--astryx-` prefix, so `--button-radius` and
1550
+ * `--astryx-button-radius` name the same variable; a component-internal
1551
+ * `--_name` is kept as written.
1552
+ */
1553
+ function cssProperty(name) {
1554
+ if (name.startsWith("--")) return name.startsWith("--_") ? name : normalizeTokenName(name);
1555
+ return name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
1556
+ }
1557
+ function declarationBlock(entries, location, { toProperty = cssProperty } = {}) {
1558
+ const lines = [];
1559
+ for (const [raw, rawValue] of entries) {
1560
+ const property = toProperty(raw);
1561
+ const value = prefixTokenReferences(rawValue);
1562
+ const reason = checkDeclarationName(property) ?? checkDeclarationValue(value);
1563
+ if (reason != null) {
1564
+ warnDroppedDeclaration(property, value, location, reason);
1565
+ continue;
1566
+ }
1567
+ lines.push(` ${property}: ${value};`);
1568
+ }
1569
+ return lines.join("\n");
1570
+ }
1571
+ function splitOverrides(overrides, location) {
1572
+ const base = [];
1573
+ const pseudos = [];
1574
+ for (const [key, value] of Object.entries(overrides)) {
1575
+ if (key.startsWith(":")) {
1576
+ if (!PSEUDO.has(key) || typeof value === "string") throw new Error(`${location}: theme style pseudo "${key}" is not supported.`);
1577
+ pseudos.push([key, value]);
1578
+ continue;
1579
+ }
1580
+ if (typeof value !== "string") throw new Error(`${location}: theme style property "${key}" must be a CSS value.`);
1581
+ base.push([key, value]);
1582
+ }
1583
+ return {
1584
+ base,
1585
+ pseudos
1586
+ };
1587
+ }
1588
+ /**
1589
+ * Compile a component style map into rule text, without scope or layer.
1590
+ *
1591
+ * Each rule targets the stable `.astryx-<target>` class plus the reflected
1592
+ * `data-*` attributes for the style key. Derived variables come along, so
1593
+ * a themed `borderRadius` or `padding` reaches the component's internals.
1594
+ */
1595
+ function compileComponentRules(components, location, surface) {
1596
+ const rules = [];
1597
+ for (const [target, styles] of Object.entries(components ?? {})) for (const [key, overrides] of Object.entries(styles)) {
1598
+ const where = `${location}components.${target}["${key}"]`;
1599
+ const selectors = targetSelectors(target, key, surface);
1600
+ const { base, pseudos } = splitOverrides(overrides, where);
1601
+ const body = declarationBlock(applyDerivedVars(target, base), where);
1602
+ if (body) rules.push(`${selectors.join(", ")} {\n${body}\n}`);
1603
+ for (const [pseudo, block] of pseudos) {
1604
+ const pseudoBody = declarationBlock(applyDerivedVars(target, Object.entries(block)), `${where}["${pseudo}"]`);
1605
+ if (pseudoBody) rules.push(`${withPseudo(selectors, pseudo)} {\n${pseudoBody}\n}`);
1606
+ }
1607
+ }
1608
+ return rules;
1609
+ }
1610
+ /**
1611
+ * One `selector { name: value; }` block from a resolved token map, or nothing
1612
+ * when empty. Names are written exactly as given: shared tokens already carry
1613
+ * the `--astryx-` prefix and theme-local tokens keep their own names.
1614
+ */
1615
+ function tokenRule(selector, tokens, location) {
1616
+ const entries = Object.entries(tokens ?? {});
1617
+ if (entries.length === 0) return [];
1618
+ const body = declarationBlock(entries, location, { toProperty: (name) => name });
1619
+ return body ? [`${selector} {\n${body}\n}`] : [];
1620
+ }
1621
+ //#endregion
1622
+ //#region src/Theme/themeAxes.ts
1623
+ function mergeRole(base, own) {
1624
+ if (!base || !own) return own ?? base;
1625
+ return {
1626
+ ...base,
1627
+ ...own,
1628
+ weights: base.weights || own.weights ? {
1629
+ ...base.weights,
1630
+ ...own.weights
1631
+ } : void 0
1632
+ };
1633
+ }
1634
+ /**
1635
+ * Resolve one font role through `extends`.
1636
+ *
1637
+ * A child that names a family replaces the inherited family and fallbacks.
1638
+ * A fallback without a family has no effect, matching how font tokens are
1639
+ * built. A child heading follows the child's own body family when the child
1640
+ * sets a body family and no heading family.
1641
+ */
1642
+ function resolveFamily(base, own, followsOwnBody = false) {
1643
+ const merged = mergeRole(base, own);
1644
+ if (!merged) return void 0;
1645
+ if (own?.family) return {
1646
+ ...merged,
1647
+ family: own.family,
1648
+ fallbacks: own.fallbacks
1649
+ };
1650
+ if (followsOwnBody) return {
1651
+ ...merged,
1652
+ family: void 0,
1653
+ fallbacks: void 0
1654
+ };
1655
+ return {
1656
+ ...merged,
1657
+ family: base?.family,
1658
+ fallbacks: base?.fallbacks
1659
+ };
1660
+ }
1661
+ /**
1662
+ * The generator configs a theme effectively uses, after `extends`.
1663
+ *
1664
+ * Adaptation rules write partial values, such as only a new type-scale base,
1665
+ * and are completed from these. A child's own color config replaces the
1666
+ * base's, because a color config regenerates every neutral. Radius and
1667
+ * motion merge field by field. Weights belong to the most recent config that
1668
+ * declares a type scale, since weights only reach tokens through a scale.
1669
+ */
1670
+ function resolveGenerativeAxes(inherited, own) {
1671
+ const base = inherited?.typography;
1672
+ const mine = own.typography;
1673
+ let typography = base || mine ? {
1674
+ ...base,
1675
+ ...mine,
1676
+ scale: mine?.scale ?? base?.scale,
1677
+ body: resolveFamily(base?.body, mine?.body),
1678
+ heading: resolveFamily(base?.heading, mine?.heading, Boolean(mine?.body?.family && !mine?.heading?.family)),
1679
+ code: resolveFamily(base?.code, mine?.code)
1680
+ } : void 0;
1681
+ if (typography) {
1682
+ const owner = mine?.scale ? mine : base?.scale ? base : void 0;
1683
+ const withWeights = (role, from) => role ? {
1684
+ ...role,
1685
+ weight: from?.weight,
1686
+ weights: from?.weights
1687
+ } : void 0;
1688
+ typography = {
1689
+ ...typography,
1690
+ body: withWeights(typography.body, owner?.body),
1691
+ heading: withWeights(typography.heading, owner?.heading),
1692
+ code: withWeights(typography.code, owner?.code)
1693
+ };
1694
+ }
1695
+ const color = own.color ?? inherited?.color;
1696
+ const radius = own.radius ? {
1697
+ ...inherited?.radius,
1698
+ ...own.radius
1699
+ } : inherited?.radius;
1700
+ const motion = own.motion ? {
1701
+ ...inherited?.motion,
1702
+ ...own.motion
1703
+ } : inherited?.motion;
1704
+ return {
1705
+ ...typography ? { typography } : {},
1706
+ ...color ? { color } : {},
1707
+ ...radius ? { radius } : {},
1708
+ ...motion ? { motion } : {}
1709
+ };
1710
+ }
1711
+ //#endregion
1712
+ //#region src/Theme/propGuards.ts
1713
+ /** An authored value as CSS, or undefined when it cannot stay one declaration. */
1714
+ function safeValue(value) {
1715
+ if (typeof value !== "string") return void 0;
1716
+ const css = prefixTokenReferences(value);
1717
+ return checkDeclarationValue(css) === null ? css : void 0;
1718
+ }
1719
+ /**
1720
+ * Explicit props that must keep winning over a theme's own type rules.
1721
+ *
1722
+ * Theme rules sit in `astryx.overrides`, above the component layer. A theme
1723
+ * that styles `heading level:2` or `text type:body` would otherwise beat an
1724
+ * explicit `weight`, `color`, or `size` prop on that element. Restating the
1725
+ * prop classes after the theme rules puts the prop back on top.
1726
+ *
1727
+ * Values mirror the component stylesheets in `packages/core/styles`, so a
1728
+ * restated prop looks exactly as it does without a theme.
1729
+ */
1730
+ const GUARDS = {
1731
+ heading: {
1732
+ "weight:regular": { fontWeight: "var(--astryx-font-weight-regular, 400)" },
1733
+ "weight:medium": { fontWeight: "var(--astryx-font-weight-medium, 500)" },
1734
+ "weight:semibold": { fontWeight: "var(--astryx-font-weight-semibold, 600)" },
1735
+ "weight:bold": { fontWeight: "var(--astryx-font-weight-bold, 700)" },
1736
+ "color:primary": { color: "var(--astryx-color-text-primary, light-dark(#171717, #fafafa))" },
1737
+ "color:secondary": { color: "var(--astryx-color-text-secondary, light-dark(#525252, #a3a3a3))" },
1738
+ "color:accent": { color: "var(--astryx-color-text-accent, #0074e2)" }
1739
+ },
1740
+ text: {
1741
+ "weight:regular": { fontWeight: "var(--astryx-font-weight-regular, 400)" },
1742
+ "weight:medium": { fontWeight: "var(--astryx-font-weight-medium, 500)" },
1743
+ "weight:semibold": { fontWeight: "var(--astryx-font-weight-semibold, 600)" },
1744
+ "weight:bold": { fontWeight: "var(--astryx-font-weight-bold, 700)" },
1745
+ "size:sm": { fontSize: "var(--astryx-text-sm-size, 0.75rem)" },
1746
+ "size:md": { fontSize: "var(--astryx-text-md-size, 0.875rem)" },
1747
+ "size:lg": { fontSize: "var(--astryx-text-lg-size, 1rem)" },
1748
+ "size:xl": { fontSize: "var(--astryx-text-xl-size, 1.25rem)" },
1749
+ "color:primary": { color: "var(--astryx-color-text-primary, light-dark(#171717, #fafafa))" },
1750
+ "color:secondary": { color: "var(--astryx-color-text-secondary, light-dark(#525252, #a3a3a3))" },
1751
+ "color:accent": { color: "var(--astryx-color-text-accent, #0074e2)" },
1752
+ "color:disabled": { color: "var(--astryx-color-text-disabled, light-dark(#a3a3a3, #525252))" },
1753
+ "color:placeholder": { color: "var(--astryx-color-text-placeholder, #737373)" }
1754
+ },
1755
+ link: {
1756
+ "color:primary": { color: "var(--astryx-link-primary-foreground, var(--astryx-color-text-primary, #171717))" },
1757
+ "color:secondary": { color: "var(--astryx-link-secondary-foreground, var(--astryx-color-text-secondary, #525252))" },
1758
+ "color:accent": { color: "var(--astryx-link-accent-foreground, #0074e2)" }
1759
+ }
1760
+ };
1761
+ const PROPERTY_CSS = {
1762
+ fontWeight: "font-weight",
1763
+ fontSize: "font-size",
1764
+ color: "color"
1765
+ };
1766
+ /**
1767
+ * Prop rules for every guarded target this component map touches.
1768
+ *
1769
+ * A theme may restyle a prop on purpose, for example
1770
+ * `heading: { 'weight:medium': { fontWeight: '450' } }`; that authored value
1771
+ * is what gets restated. A value that cannot stay one declaration was
1772
+ * already reported where the component rule was compiled, so the default
1773
+ * is restated instead.
1774
+ */
1775
+ function propGuardRules(components, options = {}) {
1776
+ const rules = [];
1777
+ for (const [target, keys] of Object.entries(GUARDS)) {
1778
+ const own = components?.[target];
1779
+ if (own === void 0 && !options.force) continue;
1780
+ for (const [key, declarations] of Object.entries(keys)) {
1781
+ const authored = own?.[key];
1782
+ if (options.authoredOnly && authored === void 0) continue;
1783
+ const fallback = options.inherited?.[target]?.[key];
1784
+ const body = Object.entries(declarations).map(([property, value]) => {
1785
+ const written = safeValue(authored?.[property]) ?? safeValue(fallback?.[property]);
1786
+ return `${PROPERTY_CSS[property]}: ${written ?? value};`;
1787
+ }).join(" ");
1788
+ rules.push(`${targetSelectors(target, key, options.surface).join(", ")} { ${body} }`);
1789
+ }
1790
+ }
1791
+ return rules;
1792
+ }
1793
+ /** Whether a component map touches any guarded target. */
1794
+ function touchesGuardedTargets(components) {
1795
+ return Object.keys(GUARDS).some((target) => components?.[target] !== void 0);
1796
+ }
1797
+ //#endregion
1798
+ //#region src/Theme/themeCss.ts
1799
+ /** Wrap rules in this theme's subtree, stopping at a nested theme. */
1800
+ function scoped(themeName, rules) {
1801
+ return `@scope (${`[data-astryx-theme="${themeName}"]`}) to ([data-astryx-theme]) {\n${rules.join("\n")}\n}`;
1802
+ }
1803
+ /**
1804
+ * Token writes target the `Theme` wrapper itself, the scope root, and never
1805
+ * `<html>`. `<html>` also carries the outermost theme's name so component rules
1806
+ * reach content teleported to `<body>`; tokens stay on the wrapper, so a
1807
+ * `Theme` that wraps one part of a page does not recolor the rest of it.
1808
+ */
1809
+ const TOKEN_SCOPE = ":scope.astryx-theme";
1810
+ /** Root token values: semantic tokens with their aliases, locals, syntax. */
1811
+ function rootTokens(source) {
1812
+ const tokens = {
1813
+ ...bridgeComponentTokens(source.tokens),
1814
+ ...source.localTokens
1815
+ };
1816
+ if (source.syntax) Object.assign(tokens, syntaxThemeStyle(source.syntax));
1817
+ return tokens;
1818
+ }
1819
+ /** Token values one adaptation rule rewrites. */
1820
+ function adaptedTokens(rule) {
1821
+ return {
1822
+ ...bridgeComponentTokens(rule.tokens),
1823
+ ...rule.localTokens
1824
+ };
1825
+ }
1826
+ function rootRules(source) {
1827
+ const rules = [];
1828
+ rules.push(...tokenRule(TOKEN_SCOPE, rootTokens(source), ""));
1829
+ rules.push(...compileComponentRules(source.components, ""));
1830
+ rules.push(...propGuardRules(source.components));
1831
+ return rules;
1832
+ }
1833
+ function adaptationBlocks(source) {
1834
+ const rules = source.adaptationRules ?? [];
1835
+ const blocks = [];
1836
+ for (const [index, rule] of rules.entries()) {
1837
+ const location = `adaptations[${index}].`;
1838
+ const inner = [...tokenRule(TOKEN_SCOPE, adaptedTokens(rule), `${location}tokens`), ...compileComponentRules(rule.components, location)];
1839
+ if (inner.length > 0) blocks.push(`@media ${rule.query} {\n${scoped(source.name, inner)}\n}`);
1840
+ }
1841
+ if (!rules.some((rule) => touchesGuardedTargets(rule.components))) return blocks;
1842
+ blocks.push(scoped(source.name, propGuardRules(source.components, { force: true })));
1843
+ for (const rule of rules) {
1844
+ const authored = propGuardRules(rule.components, { authoredOnly: true });
1845
+ if (authored.length > 0) blocks.push(`@media ${rule.query} {\n${scoped(source.name, authored)}\n}`);
1846
+ }
1847
+ return blocks;
1848
+ }
1849
+ function surfaceRules(source, surface) {
1850
+ const components = surface === "dark" ? source.onDarkComponents : source.onLightComponents;
1851
+ if (!components) return [];
1852
+ return [...compileComponentRules(components, surface === "dark" ? "onDark." : "onLight.", surface), ...propGuardRules(components, {
1853
+ surface,
1854
+ inherited: source.components
1855
+ })];
1856
+ }
1857
+ /**
1858
+ * Compile one theme's stylesheet into the `astryx.overrides` layer.
1859
+ *
1860
+ * Order is the cascade order: root rules, then each adaptation in authored
1861
+ * order, then media-surface rules, so a later section wins at equal
1862
+ * specificity. Every block is scoped to this theme and stops at a nested
1863
+ * theme, so an inner theme's components keep their own styling.
1864
+ *
1865
+ * Root tokens are the first rule of the sheet, written on the `Theme` wrapper.
1866
+ * An adaptation's token writes land in a later block with the same selector, so
1867
+ * a matching media query wins by source order. No declaration here outranks a
1868
+ * user rule, so a user can still override a token with ordinary specificity.
1869
+ * A nested theme inherits every token it does not set, adapted or not.
1870
+ */
1871
+ function compileThemeCss(source) {
1872
+ const blocks = [];
1873
+ const root = rootRules(source);
1874
+ if (root.length > 0) blocks.push(scoped(source.name, root));
1875
+ blocks.push(...adaptationBlocks(source));
1876
+ const surfaces = [...surfaceRules(source, "dark"), ...surfaceRules(source, "light")];
1877
+ if (surfaces.length > 0) blocks.push(scoped(source.name, surfaces));
1878
+ if (blocks.length === 0) return void 0;
1879
+ return `@layer astryx.overrides {\n${blocks.join("\n")}\n}\n`.replace(/<\/(style)/gi, "<\\/$1");
1880
+ }
1881
+ //#endregion
1882
+ //#region src/Theme/defineTheme.ts
1883
+ const THEME_NAME = /^[a-z0-9][a-z0-9-]*$/i;
1884
+ function isDefinedTheme(value) {
1885
+ return !!value && typeof value === "object" && value.__astryxTheme === true;
1886
+ }
1887
+ function describeBadBase(value) {
1888
+ if (value === void 0 || value === null) return String(value);
1889
+ if (typeof value !== "object") return typeof value;
1890
+ const keys = Object.keys(value);
1891
+ return `an object with keys [${keys.slice(0, 4).join(", ")}${keys.length > 4 ? ", …" : ""}]`;
1892
+ }
1893
+ function mergeMaps(base, next) {
1894
+ if (base == null && next == null) return void 0;
1895
+ return {
1896
+ ...base,
1897
+ ...next
1898
+ };
1899
+ }
1900
+ function sealIndicators(indicators) {
1901
+ if (indicators == null) return void 0;
1902
+ const sealed = {};
1903
+ for (const [name, component] of Object.entries(indicators)) if (component) sealed[name] = markRaw(component);
1904
+ return sealed;
1905
+ }
1906
+ function assertTargets(components) {
1907
+ for (const target of Object.keys(components ?? {})) assertTargetName(target);
1908
+ }
1909
+ /**
1910
+ * Create a theme object that `Theme` can apply to a subtree.
1911
+ *
1912
+ * Token names are the upstream names (`--color-accent`) or this package's
1913
+ * prefixed names (`--astryx-color-accent`). A `[light, dark]` tuple becomes
1914
+ * `light-dark()`. `color`, `typography`, `radius`, and `motion` generate
1915
+ * tokens; an explicit `tokens` entry wins for that name.
1916
+ *
1917
+ * `extends` starts from everything the base theme resolved to: tokens,
1918
+ * local tokens, component styles, surfaces, adaptations, icons, indicators.
1919
+ * This theme's own values win, and the result is self-contained.
1920
+ */
1921
+ function defineTheme(input) {
1922
+ if (!THEME_NAME.test(input.name)) throw new Error(`Theme name "${input.name}" must use letters, numbers, and hyphens.`);
1923
+ if ("extends" in input && !isDefinedTheme(input.extends)) throw new Error(`defineTheme("${input.name}"): \`extends\` must be a theme from defineTheme(), got ${describeBadBase(input.extends)}. Check that the import naming the base theme resolves to it.`);
1924
+ assertTargets(input.components);
1925
+ assertTargets(input.onDark?.components);
1926
+ assertTargets(input.onLight?.components);
1927
+ const base = input.extends;
1928
+ const own = resolveThemeValues(input, "");
1929
+ const tokens = {
1930
+ ...base?.tokens,
1931
+ ...own.tokens
1932
+ };
1933
+ const components = mergeComponentMaps(base?.components, own.components);
1934
+ const local = resolveLocalTokens(input.name, input.localTokens, base, tokens);
1935
+ const ownAxes = {
1936
+ typography: input.typography,
1937
+ color: input.color,
1938
+ radius: input.radius,
1939
+ motion: input.motion
1940
+ };
1941
+ const axes = resolveGenerativeAxes(base?.axes, ownAxes);
1942
+ const adaptations = normalizeThemeAdaptations(input.name, base?.adaptations, input.adaptations);
1943
+ const adaptationRules = resolveThemeAdaptationRules(input.name, adaptations, axes, {
1944
+ tokens,
1945
+ localTokens: local?.localTokens,
1946
+ components
1947
+ });
1948
+ const onDark = {
1949
+ ...base?.onDark,
1950
+ ...resolveTokenMap(input.onDark?.tokens, "onDark.tokens")
1951
+ };
1952
+ const onLight = {
1953
+ ...base?.onLight,
1954
+ ...resolveTokenMap(input.onLight?.tokens, "onLight.tokens")
1955
+ };
1956
+ const onDarkComponents = mergeComponentMaps(base?.onDarkComponents, input.onDark?.components);
1957
+ const onLightComponents = mergeComponentMaps(base?.onLightComponents, input.onLight?.components);
1958
+ const icons = mergeMaps(base?.icons, input.icons);
1959
+ const indicators = sealIndicators(mergeMaps(base?.indicators, input.indicators));
1960
+ const css = compileThemeCss({
1961
+ name: input.name,
1962
+ tokens,
1963
+ localTokens: local?.localTokens,
1964
+ components,
1965
+ adaptationRules,
1966
+ onDarkComponents,
1967
+ onLightComponents,
1968
+ syntax: input.syntax ?? base?.syntax
1969
+ });
1970
+ return {
1971
+ __astryxTheme: true,
1972
+ name: input.name,
1973
+ tokens,
1974
+ ...local ? {
1975
+ localTokens: local.localTokens,
1976
+ localTokenOwners: local.owners
1977
+ } : {},
1978
+ onDark,
1979
+ onLight,
1980
+ ...onDarkComponents ? { onDarkComponents } : {},
1981
+ ...onLightComponents ? { onLightComponents } : {},
1982
+ syntax: input.syntax ?? base?.syntax,
1983
+ ...icons ? { icons } : {},
1984
+ ...indicators ? { indicators } : {},
1985
+ ...components ? { components } : {},
1986
+ ...css ? { css } : {},
1987
+ adaptations,
1988
+ ...adaptationRules ? { adaptationRules } : {},
1989
+ axes
1990
+ };
1991
+ }
1992
+ /** Neutral, with no token overrides. Colors come from `@astryx-vue/themes/neutral.css`. */
1993
+ const neutralTheme = defineTheme({ name: "neutral" });
1994
+ //#endregion
1995
+ //#region src/Theme/themeStyleTag.ts
1996
+ /**
1997
+ * Injects a theme's compiled sheet. A template `<style>` is ignored by Vue.
1998
+ *
1999
+ * The sheet goes in as raw text: server rendering would otherwise
2000
+ * HTML-escape the quotes in `[data-astryx-theme="..."]` and `>` in
2001
+ * selectors, and break them. `compileThemeCss` never writes `</style`, so
2002
+ * the text cannot close the element early.
2003
+ */
2004
+ const ThemeStyle = defineComponent({
2005
+ name: "AstryxThemeStyle",
2006
+ props: { css: {
2007
+ type: String,
2008
+ required: true
2009
+ } },
2010
+ setup(props) {
2011
+ return () => h("style", {
2012
+ "data-astryx-theme-style": "",
2013
+ "innerHTML": props.css
2014
+ });
2015
+ }
2016
+ });
2017
+ //#endregion
2018
+ //#region src/Theme/useThemeRootSync.ts
2019
+ const entries = [];
2020
+ let baseSnapshot = null;
2021
+ function capture() {
2022
+ const root = document.documentElement;
2023
+ return {
2024
+ theme: root.getAttribute("data-astryx-theme"),
2025
+ mode: root.getAttribute("data-astryx-color-mode")
2026
+ };
2027
+ }
2028
+ function writeAttribute(name, value) {
2029
+ const root = document.documentElement;
2030
+ if (value == null) root.removeAttribute(name);
2031
+ else root.setAttribute(name, value);
2032
+ }
2033
+ function apply(entry) {
2034
+ const root = document.documentElement;
2035
+ root.setAttribute("data-astryx-theme", entry.name());
2036
+ const mode = entry.mode();
2037
+ if (mode === "light" || mode === "dark") root.setAttribute("data-astryx-color-mode", mode);
2038
+ else root.removeAttribute("data-astryx-color-mode");
2039
+ }
2040
+ function restoreBase() {
2041
+ if (!baseSnapshot) return;
2042
+ writeAttribute("data-astryx-theme", baseSnapshot.theme);
2043
+ writeAttribute("data-astryx-color-mode", baseSnapshot.mode);
2044
+ baseSnapshot = null;
2045
+ }
2046
+ /**
2047
+ * The outermost Theme mirrors its name and mode onto `documentElement`, so
2048
+ * portaled UI and browser chrome see the same theme. Nested themes do not.
2049
+ */
2050
+ function useThemeRootSync(isNested, themeName, mode) {
2051
+ if (isNested || typeof document === "undefined") return;
2052
+ const entry = {
2053
+ name: themeName,
2054
+ mode
2055
+ };
2056
+ onMounted(() => {
2057
+ if (entries.length === 0) baseSnapshot = capture();
2058
+ entries.push(entry);
2059
+ apply(entry);
2060
+ });
2061
+ watch(() => [themeName(), mode()], () => {
2062
+ if (entries[entries.length - 1] === entry) apply(entry);
2063
+ });
2064
+ onBeforeUnmount(() => {
2065
+ const index = entries.lastIndexOf(entry);
2066
+ if (index >= 0) entries.splice(index, 1);
2067
+ const top = entries[entries.length - 1];
2068
+ if (top) apply(top);
2069
+ else restoreBase();
2070
+ });
2071
+ }
2072
+ //#endregion
2073
+ //#region src/Theme/Theme.vue
2074
+ const _hoisted_1 = ["data-astryx-theme", "data-astryx-color-mode"];
2075
+ const _sfc_main = /*@__PURE__*/ defineComponent({
2076
+ name: "AstryxTheme",
2077
+ inheritAttrs: false,
2078
+ __name: "Theme",
2079
+ props: {
2080
+ theme: {},
2081
+ mode: { default: "system" }
2082
+ },
2083
+ setup(__props, { expose: __expose }) {
2084
+ const props = __props;
2085
+ const attrs = useAttrs();
2086
+ const root = useTemplateRef("root");
2087
+ const isNested = inject(themeNestingKey, false);
2088
+ const parentSyntax = inject(syntaxThemeKey, null);
2089
+ provide(themeNestingKey, true);
2090
+ provide(themeContextKey, computed(() => ({
2091
+ theme: props.theme,
2092
+ mode: props.mode
2093
+ })));
2094
+ if (parentSyntax || props.theme.syntax) provide(syntaxThemeKey, computed(() => props.theme.syntax ?? parentSyntax?.value ?? null));
2095
+ useThemeRootSync(isNested, () => props.theme.name, () => props.mode);
2096
+ const colorScheme = computed(() => {
2097
+ if (props.mode === "dark") return "dark";
2098
+ if (props.mode === "light") return "light";
2099
+ return "light dark";
2100
+ });
2101
+ const rootStyle = computed(() => ({ colorScheme: colorScheme.value }));
2102
+ __expose({ element: root });
2103
+ return (_ctx, _cache) => {
2104
+ return openBlock(), createElementBlock("div", {
2105
+ ref_key: "root",
2106
+ ref: root,
2107
+ class: normalizeClass(["astryx-theme", unref(attrs).class]),
2108
+ "data-astryx-theme": __props.theme.name,
2109
+ "data-astryx-color-mode": __props.mode === "system" ? void 0 : __props.mode,
2110
+ style: normalizeStyle([rootStyle.value, unref(attrs).style])
2111
+ }, [__props.theme.css ? (openBlock(), createBlock(unref(ThemeStyle), {
2112
+ key: 0,
2113
+ css: __props.theme.css
2114
+ }, null, 8, ["css"])) : createCommentVNode("v-if", true), renderSlot(_ctx.$slots, "default")], 14, _hoisted_1);
2115
+ };
2116
+ }
2117
+ });
2118
+ //#endregion
2119
+ //#region src/Theme/useMediaTheme.ts
2120
+ /** Read the nearest MediaTheme. Outside one, the mode is `off`. */
2121
+ function useMediaTheme() {
2122
+ return { mode: inject(mediaThemeKey, null) ?? computed(() => "off") };
2123
+ }
2124
+ //#endregion
2125
+ export { neutralTheme as a, expandMotionScale as c, WIDTH_BREAKPOINT_NAMES as d, isDefinedTheme as i, expandColorScale as l, _sfc_main as n, expandTypeScale as o, defineTheme as r, expandRadiusScale as s, useMediaTheme as t, DEFAULT_WIDTH_BREAKPOINTS as u };