eidos-ui 3.7.0 → 3.8.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 (407) hide show
  1. package/README.md +10 -0
  2. package/dist/{Avatar.types-BY-C09Ke.d.cts → Avatar.types-DkRznn-7.d.cts} +6 -1
  3. package/dist/{Avatar.types-BY-C09Ke.d.ts → Avatar.types-DkRznn-7.d.ts} +6 -1
  4. package/dist/{Breadcrumb.types-DaykU-C8.d.cts → Breadcrumb.types-C3uADbKU.d.cts} +4 -1
  5. package/dist/{Breadcrumb.types-DaykU-C8.d.ts → Breadcrumb.types-C3uADbKU.d.ts} +4 -1
  6. package/dist/Button.types-BCIK8Qlk.d.ts +59 -0
  7. package/dist/Button.types-DkgWjFsk.d.cts +59 -0
  8. package/dist/{Chip.types-COQfx2Ru.d.ts → Chip.types-BM-UZOCv.d.ts} +10 -1
  9. package/dist/{Chip.types-B6y3Wifa.d.cts → Chip.types-_1bhyKz4.d.cts} +10 -1
  10. package/dist/{Header.types-Ce5Cj301.d.cts → Header.types-a6p0-ZHx.d.cts} +24 -8
  11. package/dist/{Header.types-0XovUp0T.d.ts → Header.types-zbhURbg7.d.ts} +24 -8
  12. package/dist/{Input.types-D7-sWq-q.d.cts → Input.types--K0t_3L2.d.cts} +1 -1
  13. package/dist/{Input.types-CSDMaZNe.d.ts → Input.types--UjucBDd.d.ts} +1 -1
  14. package/dist/{Menu.types-CTnUijv5.d.cts → Menu.types-D6VoK9T9.d.cts} +1 -1
  15. package/dist/{Menu.types-BN4g1-3A.d.ts → Menu.types-tUEhXn52.d.ts} +1 -1
  16. package/dist/{Navigation.types-By5HfPTi.d.ts → Navigation.types-CJRzo9Zo.d.ts} +1 -1
  17. package/dist/{Navigation.types-_MrYqqUI.d.cts → Navigation.types-D95oHZEJ.d.cts} +1 -1
  18. package/dist/{SegmentedControl.types-cjLwwBAm.d.ts → SegmentedControl.types-CHtjABQM.d.ts} +1 -1
  19. package/dist/{SegmentedControl.types-BofrEYyd.d.cts → SegmentedControl.types-D_gHYL9X.d.cts} +1 -1
  20. package/dist/{Select.types-ok-03rLo.d.cts → Select.types-8CGZBgT-.d.cts} +2 -2
  21. package/dist/{Select.types-C2tGy1vj.d.ts → Select.types-CAVh9Gvd.d.ts} +2 -2
  22. package/dist/{Table.types-D8pmgxKA.d.ts → Table.types-BFDE-hhF.d.ts} +2 -2
  23. package/dist/{Table.types-D-9tC0kJ.d.cts → Table.types-Tai7_MTz.d.cts} +2 -2
  24. package/dist/{Toolbar.types-CKnQC_TW.d.ts → Toolbar.types-BqBrPVww.d.ts} +8 -6
  25. package/dist/{Toolbar.types-DUz2mxct.d.cts → Toolbar.types-GCUgzuKW.d.cts} +8 -6
  26. package/dist/alert/index.cjs +8 -5
  27. package/dist/alert/index.cjs.map +1 -1
  28. package/dist/alert/index.d.cts +1 -1
  29. package/dist/alert/index.d.ts +1 -1
  30. package/dist/alert/index.js +7 -4
  31. package/dist/avatar/index.d.cts +2 -2
  32. package/dist/avatar/index.d.ts +2 -2
  33. package/dist/breadcrumb/index.cjs +4 -2
  34. package/dist/breadcrumb/index.cjs.map +1 -1
  35. package/dist/breadcrumb/index.d.cts +2 -2
  36. package/dist/breadcrumb/index.d.ts +2 -2
  37. package/dist/breadcrumb/index.js +3 -1
  38. package/dist/button/index.cjs +7 -4
  39. package/dist/button/index.cjs.map +1 -1
  40. package/dist/button/index.d.cts +5 -5
  41. package/dist/button/index.d.ts +5 -5
  42. package/dist/button/index.js +6 -3
  43. package/dist/button-group/index.d.cts +2 -2
  44. package/dist/button-group/index.d.ts +2 -2
  45. package/dist/chip/index.cjs +7 -4
  46. package/dist/chip/index.cjs.map +1 -1
  47. package/dist/chip/index.d.cts +3 -3
  48. package/dist/chip/index.d.ts +3 -3
  49. package/dist/chip/index.js +6 -3
  50. package/dist/{chunk-DRXPTACG.js → chunk-26PRBZA6.js} +6 -2
  51. package/dist/chunk-26PRBZA6.js.map +1 -0
  52. package/dist/{chunk-L7I5NEGI.js → chunk-2IXCEKLI.js} +2 -2
  53. package/dist/{chunk-GWHZFX2H.js → chunk-2TIMJD4K.js} +29 -6
  54. package/dist/chunk-2TIMJD4K.js.map +1 -0
  55. package/dist/{chunk-RHFD2Z5V.js → chunk-3TF2GZSG.js} +7 -7
  56. package/dist/{chunk-TC5IC6OP.cjs → chunk-3VXUOAIJ.cjs} +3 -3
  57. package/dist/{chunk-TC5IC6OP.cjs.map → chunk-3VXUOAIJ.cjs.map} +1 -1
  58. package/dist/{chunk-JHX6JK3M.js → chunk-3X6QVHTD.js} +2 -2
  59. package/dist/{chunk-7VJCGKVP.cjs → chunk-4HZIXRAJ.cjs} +11 -11
  60. package/dist/{chunk-7VJCGKVP.cjs.map → chunk-4HZIXRAJ.cjs.map} +1 -1
  61. package/dist/{chunk-MQAOXZD4.js → chunk-4S57PE43.js} +4 -4
  62. package/dist/{chunk-JT4KVXJK.js → chunk-4V2XYUQL.js} +2 -2
  63. package/dist/{chunk-PMSENLOA.cjs → chunk-544RAXWO.cjs} +19 -19
  64. package/dist/{chunk-PMSENLOA.cjs.map → chunk-544RAXWO.cjs.map} +1 -1
  65. package/dist/{chunk-4JSTBA4F.cjs → chunk-6CW5QSYV.cjs} +7 -7
  66. package/dist/{chunk-4JSTBA4F.cjs.map → chunk-6CW5QSYV.cjs.map} +1 -1
  67. package/dist/{chunk-AR2ZOO6L.js → chunk-6FXFKMJ5.js} +3 -3
  68. package/dist/{chunk-KREHT4AQ.cjs → chunk-6IB27I5K.cjs} +8 -8
  69. package/dist/{chunk-KREHT4AQ.cjs.map → chunk-6IB27I5K.cjs.map} +1 -1
  70. package/dist/{chunk-LGDODZHI.js → chunk-6LTZV6HN.js} +4 -4
  71. package/dist/{chunk-YP4HUBKN.js → chunk-6NAOAKII.js} +2 -2
  72. package/dist/chunk-75Q5OS7L.cjs +10 -0
  73. package/dist/chunk-75Q5OS7L.cjs.map +1 -0
  74. package/dist/{chunk-LQXFXXMJ.cjs → chunk-7FV2X62W.cjs} +7 -7
  75. package/dist/{chunk-LQXFXXMJ.cjs.map → chunk-7FV2X62W.cjs.map} +1 -1
  76. package/dist/{chunk-2T7ZMMH5.cjs → chunk-7NUVLVSL.cjs} +5 -5
  77. package/dist/{chunk-2T7ZMMH5.cjs.map → chunk-7NUVLVSL.cjs.map} +1 -1
  78. package/dist/chunk-ACH7SYQ2.js +47 -0
  79. package/dist/chunk-ACH7SYQ2.js.map +1 -0
  80. package/dist/{chunk-HNGFRRVZ.cjs → chunk-AUNDBUHM.cjs} +3 -3
  81. package/dist/{chunk-HNGFRRVZ.cjs.map → chunk-AUNDBUHM.cjs.map} +1 -1
  82. package/dist/{chunk-XZLSHEHE.cjs → chunk-B2OHBIAL.cjs} +10 -10
  83. package/dist/{chunk-XZLSHEHE.cjs.map → chunk-B2OHBIAL.cjs.map} +1 -1
  84. package/dist/chunk-BDH2MXJW.js +46 -0
  85. package/dist/chunk-BDH2MXJW.js.map +1 -0
  86. package/dist/{chunk-D7SQ7LHJ.js → chunk-BO3KK3ZQ.js} +2 -2
  87. package/dist/{chunk-NOQF7UQ5.cjs → chunk-CFVUUMQA.cjs} +6 -6
  88. package/dist/{chunk-NOQF7UQ5.cjs.map → chunk-CFVUUMQA.cjs.map} +1 -1
  89. package/dist/chunk-CJT7L764.cjs +21 -0
  90. package/dist/chunk-CJT7L764.cjs.map +1 -0
  91. package/dist/{chunk-5XH2PHT2.js → chunk-CNTG7OOO.js} +14 -14
  92. package/dist/{chunk-I6M6CVI2.cjs → chunk-DG3O5NV4.cjs} +3 -3
  93. package/dist/{chunk-I6M6CVI2.cjs.map → chunk-DG3O5NV4.cjs.map} +1 -1
  94. package/dist/{chunk-WNDDS367.js → chunk-DPTTDHZ5.js} +3 -3
  95. package/dist/{chunk-35LGEPLP.cjs → chunk-ENMDOQQO.cjs} +29 -14
  96. package/dist/chunk-ENMDOQQO.cjs.map +1 -0
  97. package/dist/{chunk-V4BZWBZT.cjs → chunk-F5IRMMZ2.cjs} +7 -7
  98. package/dist/{chunk-V4BZWBZT.cjs.map → chunk-F5IRMMZ2.cjs.map} +1 -1
  99. package/dist/{chunk-WE2SBWZ6.js → chunk-FE7S4RSK.js} +10 -10
  100. package/dist/chunk-FE7S4RSK.js.map +1 -0
  101. package/dist/{chunk-BFKPJ627.js → chunk-FHOD3FUN.js} +4 -4
  102. package/dist/{chunk-SNRRF64M.js → chunk-GDRLVX2A.js} +31 -10
  103. package/dist/chunk-GDRLVX2A.js.map +1 -0
  104. package/dist/{chunk-5O73AALP.cjs → chunk-GP6EEZH5.cjs} +7 -3
  105. package/dist/chunk-GP6EEZH5.cjs.map +1 -0
  106. package/dist/{chunk-SDUGYJGW.js → chunk-H3C6YECZ.js} +6 -6
  107. package/dist/{chunk-RJVHR45I.cjs → chunk-H46ZLPNJ.cjs} +7 -7
  108. package/dist/{chunk-RJVHR45I.cjs.map → chunk-H46ZLPNJ.cjs.map} +1 -1
  109. package/dist/{chunk-66UQTF57.cjs → chunk-HLI4SOH3.cjs} +45 -45
  110. package/dist/{chunk-66UQTF57.cjs.map → chunk-HLI4SOH3.cjs.map} +1 -1
  111. package/dist/{chunk-ZMRINZIO.cjs → chunk-HR5MWA3B.cjs} +5 -5
  112. package/dist/{chunk-ZMRINZIO.cjs.map → chunk-HR5MWA3B.cjs.map} +1 -1
  113. package/dist/{chunk-MPIVBAMY.js → chunk-HYRLK462.js} +2 -2
  114. package/dist/{chunk-FIVMMCGM.js → chunk-IHPSRTVW.js} +4 -4
  115. package/dist/{chunk-THCTUBX6.js → chunk-IKXXXVUO.js} +3 -3
  116. package/dist/{chunk-JPYJQ4TF.cjs → chunk-JFV56ISS.cjs} +6 -6
  117. package/dist/{chunk-JPYJQ4TF.cjs.map → chunk-JFV56ISS.cjs.map} +1 -1
  118. package/dist/{chunk-75GFIQRU.js → chunk-JY77VJAZ.js} +30 -15
  119. package/dist/chunk-JY77VJAZ.js.map +1 -0
  120. package/dist/chunk-KXDGW6LJ.cjs +46 -0
  121. package/dist/chunk-KXDGW6LJ.cjs.map +1 -0
  122. package/dist/{chunk-24HKKSKX.js → chunk-L6ERHCQ2.js} +3 -3
  123. package/dist/{chunk-4LNTZPSQ.js → chunk-L6YJ6QTZ.js} +2 -2
  124. package/dist/{chunk-KBQD4JLK.cjs → chunk-LUDK44NZ.cjs} +3 -3
  125. package/dist/{chunk-KBQD4JLK.cjs.map → chunk-LUDK44NZ.cjs.map} +1 -1
  126. package/dist/{chunk-PCTHJZRO.cjs → chunk-LWCFT5SP.cjs} +3 -3
  127. package/dist/{chunk-PCTHJZRO.cjs.map → chunk-LWCFT5SP.cjs.map} +1 -1
  128. package/dist/{chunk-JNY7TUDS.js → chunk-MCPGI6EI.js} +2 -2
  129. package/dist/{chunk-DU5JKTHK.cjs → chunk-MKC6V3SY.cjs} +6 -6
  130. package/dist/{chunk-DU5JKTHK.cjs.map → chunk-MKC6V3SY.cjs.map} +1 -1
  131. package/dist/{chunk-J76JHN7J.cjs → chunk-N5NXKVFJ.cjs} +10 -10
  132. package/dist/{chunk-J76JHN7J.cjs.map → chunk-N5NXKVFJ.cjs.map} +1 -1
  133. package/dist/{chunk-XERBOFYZ.cjs → chunk-NERASTO2.cjs} +3 -3
  134. package/dist/{chunk-XERBOFYZ.cjs.map → chunk-NERASTO2.cjs.map} +1 -1
  135. package/dist/{chunk-3KBBJZHK.cjs → chunk-NFD7MPX4.cjs} +16 -14
  136. package/dist/chunk-NFD7MPX4.cjs.map +1 -0
  137. package/dist/{chunk-3ZRFOKDM.cjs → chunk-NNAEQR3Y.cjs} +30 -30
  138. package/dist/{chunk-3ZRFOKDM.cjs.map → chunk-NNAEQR3Y.cjs.map} +1 -1
  139. package/dist/{chunk-36JFXFM2.cjs → chunk-OGGZIFTI.cjs} +38 -38
  140. package/dist/chunk-OGGZIFTI.cjs.map +1 -0
  141. package/dist/{chunk-2PCCGQOH.js → chunk-P6OJQ2RN.js} +6 -6
  142. package/dist/{chunk-3RWZC6OW.cjs → chunk-PE2SLXUS.cjs} +5 -5
  143. package/dist/{chunk-3RWZC6OW.cjs.map → chunk-PE2SLXUS.cjs.map} +1 -1
  144. package/dist/chunk-QD32IMMH.js +13 -0
  145. package/dist/chunk-QD32IMMH.js.map +1 -0
  146. package/dist/{chunk-HEXAY6DE.cjs → chunk-QUSO4GFA.cjs} +7 -7
  147. package/dist/{chunk-HEXAY6DE.cjs.map → chunk-QUSO4GFA.cjs.map} +1 -1
  148. package/dist/{chunk-OOCCSMWM.js → chunk-RHWZX7PB.js} +9 -7
  149. package/dist/chunk-RHWZX7PB.js.map +1 -0
  150. package/dist/{chunk-YXRKBKFB.js → chunk-S5CMZFX6.js} +3 -3
  151. package/dist/{chunk-4AO5RKV5.cjs → chunk-SLHIVEFW.cjs} +7 -7
  152. package/dist/{chunk-4AO5RKV5.cjs.map → chunk-SLHIVEFW.cjs.map} +1 -1
  153. package/dist/{chunk-HEX4IMLO.js → chunk-TJQNGJHP.js} +4 -4
  154. package/dist/{chunk-JCKGAAPZ.cjs → chunk-TNQ2ZZ7W.cjs} +9 -9
  155. package/dist/{chunk-JCKGAAPZ.cjs.map → chunk-TNQ2ZZ7W.cjs.map} +1 -1
  156. package/dist/chunk-U32K2H3N.js +10 -0
  157. package/dist/chunk-U32K2H3N.js.map +1 -0
  158. package/dist/{chunk-RHHZRTWM.js → chunk-U34INRFO.js} +28 -13
  159. package/dist/chunk-U34INRFO.js.map +1 -0
  160. package/dist/{chunk-SFFKQQ5Z.js → chunk-U4SVBE2M.js} +5 -5
  161. package/dist/{chunk-O3QM3BFE.js → chunk-UC4NYF6T.js} +2 -2
  162. package/dist/{chunk-6JHVXWDV.cjs → chunk-ULKWUKD2.cjs} +22 -22
  163. package/dist/{chunk-6JHVXWDV.cjs.map → chunk-ULKWUKD2.cjs.map} +1 -1
  164. package/dist/{chunk-BEOECPVJ.cjs → chunk-UTYY35QX.cjs} +3 -3
  165. package/dist/{chunk-BEOECPVJ.cjs.map → chunk-UTYY35QX.cjs.map} +1 -1
  166. package/dist/{chunk-7BFODYNL.cjs → chunk-UUT2VEN5.cjs} +7 -7
  167. package/dist/{chunk-7BFODYNL.cjs.map → chunk-UUT2VEN5.cjs.map} +1 -1
  168. package/dist/chunk-V3T7RO4F.js +21 -0
  169. package/dist/chunk-V3T7RO4F.js.map +1 -0
  170. package/dist/{chunk-GIEDIAPD.js → chunk-V5CM5TH3.js} +3 -3
  171. package/dist/{chunk-L65MHFMD.js → chunk-V64DICJK.js} +3 -3
  172. package/dist/{chunk-KIZVY57H.cjs → chunk-VXC7Z7XB.cjs} +5 -5
  173. package/dist/{chunk-KIZVY57H.cjs.map → chunk-VXC7Z7XB.cjs.map} +1 -1
  174. package/dist/chunk-VYF7WV4K.cjs +47 -0
  175. package/dist/chunk-VYF7WV4K.cjs.map +1 -0
  176. package/dist/{chunk-P4XZH3OR.js → chunk-WHQGJHMD.js} +4 -4
  177. package/dist/{chunk-TTLFY76J.cjs → chunk-WR77IZUU.cjs} +32 -9
  178. package/dist/chunk-WR77IZUU.cjs.map +1 -0
  179. package/dist/{chunk-O2BECFXJ.cjs → chunk-WTFEMOV5.cjs} +43 -22
  180. package/dist/chunk-WTFEMOV5.cjs.map +1 -0
  181. package/dist/{chunk-YAKTVIVK.js → chunk-XIUZT4TO.js} +3 -3
  182. package/dist/chunk-XPG56DLQ.cjs +103 -0
  183. package/dist/chunk-XPG56DLQ.cjs.map +1 -0
  184. package/dist/{chunk-GPVGGBIR.js → chunk-XWMXEJVZ.js} +2 -2
  185. package/dist/chunk-XZILHRKG.cjs +13 -0
  186. package/dist/chunk-XZILHRKG.cjs.map +1 -0
  187. package/dist/{chunk-VQGLVBPL.cjs → chunk-YIOHKQ6Y.cjs} +11 -4
  188. package/dist/chunk-YIOHKQ6Y.cjs.map +1 -0
  189. package/dist/{chunk-A3LMUPG3.js → chunk-Z3IJWYUD.js} +2 -2
  190. package/dist/{chunk-4J25XZDI.js → chunk-ZJWQPZ7E.js} +9 -2
  191. package/dist/chunk-ZJWQPZ7E.js.map +1 -0
  192. package/dist/color-picker/index.cjs +5 -4
  193. package/dist/color-picker/index.cjs.map +1 -1
  194. package/dist/color-picker/index.js +4 -3
  195. package/dist/combobox/index.cjs +7 -6
  196. package/dist/combobox/index.cjs.map +1 -1
  197. package/dist/combobox/index.js +6 -5
  198. package/dist/command-palette/index.cjs +4 -3
  199. package/dist/command-palette/index.cjs.map +1 -1
  200. package/dist/command-palette/index.js +3 -2
  201. package/dist/context-menu/index.cjs +7 -6
  202. package/dist/context-menu/index.cjs.map +1 -1
  203. package/dist/context-menu/index.d.cts +2 -2
  204. package/dist/context-menu/index.d.ts +2 -2
  205. package/dist/context-menu/index.js +6 -5
  206. package/dist/conversation/index.cjs +11 -8
  207. package/dist/conversation/index.cjs.map +1 -1
  208. package/dist/conversation/index.d.cts +3 -3
  209. package/dist/conversation/index.d.ts +3 -3
  210. package/dist/conversation/index.js +10 -7
  211. package/dist/data-grid/index.cjs +18 -15
  212. package/dist/data-grid/index.cjs.map +1 -1
  213. package/dist/data-grid/index.d.cts +8 -8
  214. package/dist/data-grid/index.d.ts +8 -8
  215. package/dist/data-grid/index.js +17 -14
  216. package/dist/date-picker/index.cjs +11 -8
  217. package/dist/date-picker/index.cjs.map +1 -1
  218. package/dist/date-picker/index.d.cts +2 -2
  219. package/dist/date-picker/index.d.ts +2 -2
  220. package/dist/date-picker/index.js +10 -7
  221. package/dist/drawer/index.cjs +8 -5
  222. package/dist/drawer/index.cjs.map +1 -1
  223. package/dist/drawer/index.d.cts +5 -4
  224. package/dist/drawer/index.d.ts +5 -4
  225. package/dist/drawer/index.js +7 -4
  226. package/dist/dropdown/index.cjs +4 -3
  227. package/dist/dropdown/index.cjs.map +1 -1
  228. package/dist/dropdown/index.js +3 -2
  229. package/dist/header/index.cjs +9 -6
  230. package/dist/header/index.cjs.map +1 -1
  231. package/dist/header/index.d.cts +10 -10
  232. package/dist/header/index.d.ts +10 -10
  233. package/dist/header/index.js +8 -5
  234. package/dist/index.cjs +56 -43
  235. package/dist/index.cjs.map +1 -1
  236. package/dist/index.css +48 -14
  237. package/dist/index.d.cts +14 -13
  238. package/dist/index.d.ts +14 -13
  239. package/dist/index.js +60 -47
  240. package/dist/inline-edit/index.cjs +6 -5
  241. package/dist/inline-edit/index.cjs.map +1 -1
  242. package/dist/inline-edit/index.js +5 -4
  243. package/dist/input/index.cjs +5 -4
  244. package/dist/input/index.cjs.map +1 -1
  245. package/dist/input/index.d.cts +3 -3
  246. package/dist/input/index.d.ts +3 -3
  247. package/dist/input/index.js +4 -3
  248. package/dist/link-provider/index.cjs +12 -0
  249. package/dist/link-provider/index.cjs.map +1 -0
  250. package/dist/link-provider/index.d.cts +43 -0
  251. package/dist/link-provider/index.d.ts +43 -0
  252. package/dist/link-provider/index.js +12 -0
  253. package/dist/link-provider/index.js.map +1 -0
  254. package/dist/lucide-icons/index.cjs +9 -0
  255. package/dist/lucide-icons/index.cjs.map +1 -0
  256. package/dist/lucide-icons/index.d.cts +2 -0
  257. package/dist/lucide-icons/index.d.ts +2 -0
  258. package/dist/lucide-icons/index.js +9 -0
  259. package/dist/lucide-icons/index.js.map +1 -0
  260. package/dist/menu/index.cjs +6 -5
  261. package/dist/menu/index.cjs.map +1 -1
  262. package/dist/menu/index.d.cts +3 -3
  263. package/dist/menu/index.d.ts +3 -3
  264. package/dist/menu/index.js +5 -4
  265. package/dist/modal/index.cjs +8 -5
  266. package/dist/modal/index.cjs.map +1 -1
  267. package/dist/modal/index.d.cts +2 -2
  268. package/dist/modal/index.d.ts +2 -2
  269. package/dist/modal/index.js +7 -4
  270. package/dist/navigation/index.cjs +8 -5
  271. package/dist/navigation/index.cjs.map +1 -1
  272. package/dist/navigation/index.d.cts +3 -3
  273. package/dist/navigation/index.d.ts +3 -3
  274. package/dist/navigation/index.js +7 -4
  275. package/dist/number-input/index.cjs +4 -3
  276. package/dist/number-input/index.cjs.map +1 -1
  277. package/dist/number-input/index.js +3 -2
  278. package/dist/page-layout/index.cjs +16 -13
  279. package/dist/page-layout/index.cjs.map +1 -1
  280. package/dist/page-layout/index.d.cts +8 -8
  281. package/dist/page-layout/index.d.ts +8 -8
  282. package/dist/page-layout/index.js +15 -12
  283. package/dist/pagination/index.cjs +11 -8
  284. package/dist/pagination/index.cjs.map +1 -1
  285. package/dist/pagination/index.js +10 -7
  286. package/dist/popover/index.cjs +4 -3
  287. package/dist/popover/index.cjs.map +1 -1
  288. package/dist/popover/index.d.cts +1 -1
  289. package/dist/popover/index.d.ts +1 -1
  290. package/dist/popover/index.js +3 -2
  291. package/dist/renderIcon-BW3PUtg8.d.cts +50 -0
  292. package/dist/renderIcon-BW3PUtg8.d.ts +50 -0
  293. package/dist/segmented-control/index.cjs +5 -4
  294. package/dist/segmented-control/index.cjs.map +1 -1
  295. package/dist/segmented-control/index.d.cts +3 -3
  296. package/dist/segmented-control/index.d.ts +3 -3
  297. package/dist/segmented-control/index.js +4 -3
  298. package/dist/select/index.cjs +7 -6
  299. package/dist/select/index.cjs.map +1 -1
  300. package/dist/select/index.d.cts +4 -4
  301. package/dist/select/index.d.ts +4 -4
  302. package/dist/select/index.js +6 -5
  303. package/dist/snackbar/index.cjs +8 -5
  304. package/dist/snackbar/index.cjs.map +1 -1
  305. package/dist/snackbar/index.js +7 -4
  306. package/dist/split-button/index.cjs +7 -6
  307. package/dist/split-button/index.cjs.map +1 -1
  308. package/dist/split-button/index.d.cts +2 -2
  309. package/dist/split-button/index.d.ts +2 -2
  310. package/dist/split-button/index.js +6 -5
  311. package/dist/split-chip/index.cjs +8 -5
  312. package/dist/split-chip/index.cjs.map +1 -1
  313. package/dist/split-chip/index.d.cts +2 -2
  314. package/dist/split-chip/index.d.ts +2 -2
  315. package/dist/split-chip/index.js +7 -4
  316. package/dist/table/index.cjs +16 -13
  317. package/dist/table/index.cjs.map +1 -1
  318. package/dist/table/index.d.cts +4 -4
  319. package/dist/table/index.d.ts +4 -4
  320. package/dist/table/index.js +15 -12
  321. package/dist/tabs/index.cjs +4 -3
  322. package/dist/tabs/index.cjs.map +1 -1
  323. package/dist/tabs/index.d.cts +1 -1
  324. package/dist/tabs/index.d.ts +1 -1
  325. package/dist/tabs/index.js +3 -2
  326. package/dist/tag-input/index.cjs +9 -6
  327. package/dist/tag-input/index.cjs.map +1 -1
  328. package/dist/tag-input/index.js +8 -5
  329. package/dist/textarea/index.cjs +5 -4
  330. package/dist/textarea/index.cjs.map +1 -1
  331. package/dist/textarea/index.d.cts +1 -1
  332. package/dist/textarea/index.d.ts +1 -1
  333. package/dist/textarea/index.js +4 -3
  334. package/dist/theme-editor/index.cjs +14 -11
  335. package/dist/theme-editor/index.cjs.map +1 -1
  336. package/dist/theme-editor/index.js +13 -10
  337. package/dist/theme-provider/index.cjs +4 -3
  338. package/dist/theme-provider/index.cjs.map +1 -1
  339. package/dist/theme-provider/index.js +3 -2
  340. package/dist/timeline/index.cjs +2 -2
  341. package/dist/timeline/index.d.cts +18 -3
  342. package/dist/timeline/index.d.ts +18 -3
  343. package/dist/timeline/index.js +1 -1
  344. package/dist/toolbar/index.cjs +12 -9
  345. package/dist/toolbar/index.cjs.map +1 -1
  346. package/dist/toolbar/index.d.cts +7 -7
  347. package/dist/toolbar/index.d.ts +7 -7
  348. package/dist/toolbar/index.js +11 -8
  349. package/dist/tooltip/index.cjs +4 -3
  350. package/dist/tooltip/index.cjs.map +1 -1
  351. package/dist/tooltip/index.js +3 -2
  352. package/package.json +4 -2
  353. package/dist/Button.types-BH0CPyPx.d.ts +0 -33
  354. package/dist/Button.types-DZRCVqyN.d.cts +0 -33
  355. package/dist/chunk-35LGEPLP.cjs.map +0 -1
  356. package/dist/chunk-36JFXFM2.cjs.map +0 -1
  357. package/dist/chunk-3KBBJZHK.cjs.map +0 -1
  358. package/dist/chunk-4J25XZDI.js.map +0 -1
  359. package/dist/chunk-5O73AALP.cjs.map +0 -1
  360. package/dist/chunk-75GFIQRU.js.map +0 -1
  361. package/dist/chunk-DA375AI6.cjs +0 -88
  362. package/dist/chunk-DA375AI6.cjs.map +0 -1
  363. package/dist/chunk-DRXPTACG.js.map +0 -1
  364. package/dist/chunk-GWHZFX2H.js.map +0 -1
  365. package/dist/chunk-NEQXEVHM.js +0 -34
  366. package/dist/chunk-NEQXEVHM.js.map +0 -1
  367. package/dist/chunk-O2BECFXJ.cjs.map +0 -1
  368. package/dist/chunk-OOCCSMWM.js.map +0 -1
  369. package/dist/chunk-RHHZRTWM.js.map +0 -1
  370. package/dist/chunk-SNRRF64M.js.map +0 -1
  371. package/dist/chunk-TTLFY76J.cjs.map +0 -1
  372. package/dist/chunk-VQGLVBPL.cjs.map +0 -1
  373. package/dist/chunk-WE2SBWZ6.js.map +0 -1
  374. package/dist/chunk-ZMDZGL5A.cjs +0 -34
  375. package/dist/chunk-ZMDZGL5A.cjs.map +0 -1
  376. package/dist/renderIcon-C2lEMMzb.d.cts +0 -30
  377. package/dist/renderIcon-C2lEMMzb.d.ts +0 -30
  378. /package/dist/{chunk-L7I5NEGI.js.map → chunk-2IXCEKLI.js.map} +0 -0
  379. /package/dist/{chunk-RHFD2Z5V.js.map → chunk-3TF2GZSG.js.map} +0 -0
  380. /package/dist/{chunk-JHX6JK3M.js.map → chunk-3X6QVHTD.js.map} +0 -0
  381. /package/dist/{chunk-MQAOXZD4.js.map → chunk-4S57PE43.js.map} +0 -0
  382. /package/dist/{chunk-JT4KVXJK.js.map → chunk-4V2XYUQL.js.map} +0 -0
  383. /package/dist/{chunk-AR2ZOO6L.js.map → chunk-6FXFKMJ5.js.map} +0 -0
  384. /package/dist/{chunk-LGDODZHI.js.map → chunk-6LTZV6HN.js.map} +0 -0
  385. /package/dist/{chunk-YP4HUBKN.js.map → chunk-6NAOAKII.js.map} +0 -0
  386. /package/dist/{chunk-D7SQ7LHJ.js.map → chunk-BO3KK3ZQ.js.map} +0 -0
  387. /package/dist/{chunk-5XH2PHT2.js.map → chunk-CNTG7OOO.js.map} +0 -0
  388. /package/dist/{chunk-WNDDS367.js.map → chunk-DPTTDHZ5.js.map} +0 -0
  389. /package/dist/{chunk-BFKPJ627.js.map → chunk-FHOD3FUN.js.map} +0 -0
  390. /package/dist/{chunk-SDUGYJGW.js.map → chunk-H3C6YECZ.js.map} +0 -0
  391. /package/dist/{chunk-MPIVBAMY.js.map → chunk-HYRLK462.js.map} +0 -0
  392. /package/dist/{chunk-FIVMMCGM.js.map → chunk-IHPSRTVW.js.map} +0 -0
  393. /package/dist/{chunk-THCTUBX6.js.map → chunk-IKXXXVUO.js.map} +0 -0
  394. /package/dist/{chunk-24HKKSKX.js.map → chunk-L6ERHCQ2.js.map} +0 -0
  395. /package/dist/{chunk-4LNTZPSQ.js.map → chunk-L6YJ6QTZ.js.map} +0 -0
  396. /package/dist/{chunk-JNY7TUDS.js.map → chunk-MCPGI6EI.js.map} +0 -0
  397. /package/dist/{chunk-2PCCGQOH.js.map → chunk-P6OJQ2RN.js.map} +0 -0
  398. /package/dist/{chunk-YXRKBKFB.js.map → chunk-S5CMZFX6.js.map} +0 -0
  399. /package/dist/{chunk-HEX4IMLO.js.map → chunk-TJQNGJHP.js.map} +0 -0
  400. /package/dist/{chunk-SFFKQQ5Z.js.map → chunk-U4SVBE2M.js.map} +0 -0
  401. /package/dist/{chunk-O3QM3BFE.js.map → chunk-UC4NYF6T.js.map} +0 -0
  402. /package/dist/{chunk-GIEDIAPD.js.map → chunk-V5CM5TH3.js.map} +0 -0
  403. /package/dist/{chunk-L65MHFMD.js.map → chunk-V64DICJK.js.map} +0 -0
  404. /package/dist/{chunk-P4XZH3OR.js.map → chunk-WHQGJHMD.js.map} +0 -0
  405. /package/dist/{chunk-YAKTVIVK.js.map → chunk-XIUZT4TO.js.map} +0 -0
  406. /package/dist/{chunk-GPVGGBIR.js.map → chunk-XWMXEJVZ.js.map} +0 -0
  407. /package/dist/{chunk-A3LMUPG3.js.map → chunk-Z3IJWYUD.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/Conversation/Chat.component.tsx","../src/components/Conversation/MessageComposer.component.tsx","../src/components/Conversation/Conversation.hooks.ts","../src/components/Conversation/Conversation.utils.ts","../src/components/Conversation/MessageItem.component.tsx","../src/components/Conversation/CommentThread.component.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from 'react';\nimport { ArrowDown, MessagesSquare } from 'lucide-react';\nimport { Button } from '../Button';\nimport { EmptyState } from '../EmptyState';\nimport { Skeleton } from '../Skeleton';\nimport { Spinner } from '../Spinner';\nimport { MessageComposer } from './MessageComposer.component';\nimport { MessageItem } from './MessageItem.component';\nimport type { ChatProps, ConversationMessage } from './Conversation.types';\nimport {\n useLoadMoreOnScrollTop,\n useNewMessageIds,\n useScrollAnchor,\n useStickToBottom,\n} from './Conversation.hooks';\nimport { classNames, continuesRun, formatDateSeparator, isSameDay } from './Conversation.utils';\n\nconst ChatSkeleton: React.FC = () => (\n <div className=\"eidos-chat-skeleton\" aria-hidden=\"true\">\n {[0, 1, 2, 3].map((row) => (\n <div\n key={row}\n className={classNames(\n 'eidos-chat-skeleton-row',\n row % 2 === 1 && 'eidos-chat-skeleton-row--own',\n )}\n >\n <Skeleton variant=\"circular\" width={28} height={28} />\n <Skeleton variant=\"rounded\" height={48} />\n </div>\n ))}\n </div>\n);\n\n/**\n * A bottom-anchored message thread with a composer.\n *\n * Controlled and transport-agnostic: it renders the `messages` it is given and\n * reports intent through `onSend` / `onLoadMore`. It never fetches, so the\n * same array can be persisted and replayed verbatim.\n */\nexport const Chat: React.FC<ChatProps> = ({\n messages,\n currentUserId,\n onSend,\n onRetry,\n readOnly = false,\n readOnlyMessage,\n renderBody,\n messageActions,\n renderMessageFooter,\n loading = false,\n emptyContent,\n hasMore = false,\n loadingMore = false,\n onLoadMore,\n groupConsecutive = true,\n groupWindowMinutes = 5,\n showDateSeparators = true,\n formatTimestamp,\n animateNewMessages = true,\n allowAttachments = false,\n attachmentAccept,\n typing,\n unreadFromId,\n placeholder = 'Write a message...',\n sendOnEnter = true,\n ariaLabel = 'Conversation',\n className = '',\n}) => {\n const { scrollRef, contentRef, atBottom, scrollToBottom, handleScroll } =\n useStickToBottom(messages);\n const newIds = useNewMessageIds(messages, animateNewMessages);\n useScrollAnchor(scrollRef, messages);\n\n const loadMoreOnScroll = useLoadMoreOnScrollTop(scrollRef, { hasMore, loadingMore, onLoadMore });\n\n const onScroll = useCallback(() => {\n handleScroll();\n loadMoreOnScroll();\n }, [handleScroll, loadMoreOnScroll]);\n\n const byId = useMemo(() => new Map(messages.map((message) => [message.id, message])), [messages]);\n\n // An id that isn't in the current page must not draw a divider above\n // nothing - it would float at the top of whatever happens to be loaded.\n const unreadIndex = useMemo(() => {\n if (!unreadFromId) return -1;\n return messages.findIndex((message) => message.id === unreadFromId);\n }, [messages, unreadFromId]);\n\n const showComposer = !readOnly && Boolean(onSend);\n const isEmpty = !loading && messages.length === 0;\n\n const renderMessage = (message: ConversationMessage, index: number) => {\n const previous = messages[index - 1];\n const actions = readOnly ? undefined : messageActions?.(message);\n const quoted = message.parentId ? byId.get(message.parentId) : undefined;\n\n const nodes: React.ReactNode[] = [];\n\n if (showDateSeparators && (!previous || !isSameDay(previous.sentAt, message.sentAt))) {\n nodes.push(\n <li key={`date-${message.id}`} className=\"eidos-conversation-separator\">\n <span>{formatDateSeparator(message.sentAt)}</span>\n </li>,\n );\n }\n\n if (index === unreadIndex) {\n nodes.push(\n <li\n key={`unread-${message.id}`}\n className=\"eidos-conversation-separator eidos-conversation-separator--unread\"\n >\n <span>Unread messages</span>\n </li>,\n );\n }\n\n // A separator breaks a run: the message under it needs its own header.\n const grouped =\n groupConsecutive &&\n index !== unreadIndex &&\n nodes.length === 0 &&\n continuesRun(previous, message, groupWindowMinutes);\n\n nodes.push(\n <MessageItem\n key={message.id}\n message={message}\n layout=\"chat\"\n isOwn={Boolean(currentUserId) && message.author.id === currentUserId}\n grouped={grouped}\n isNew={newIds.has(message.id)}\n actions={actions}\n footer={renderMessageFooter?.(message)}\n body={renderBody?.(message)}\n onRetry={!readOnly && onRetry ? () => onRetry(message) : undefined}\n quoted={quoted}\n formatTimestamp={formatTimestamp}\n />,\n );\n\n return nodes;\n };\n\n return (\n <div className={classNames('eidos-chat', className)}>\n <div\n ref={scrollRef}\n className=\"eidos-chat-scroll\"\n onScroll={onScroll}\n role=\"log\"\n aria-live=\"polite\"\n aria-relevant=\"additions\"\n aria-busy={loading}\n aria-label={ariaLabel}\n tabIndex={0}\n >\n {/* One wrapper whose height is the content height, so\n `useStickToBottom` can observe growth that doesn't change the\n message count - a streamed reply, the typing indicator. */}\n <div ref={contentRef} className=\"eidos-chat-scroll-content\">\n {hasMore && (\n <div className=\"eidos-chat-load-more\">\n {loadingMore ? (\n <span className=\"eidos-chat-loading-more\">\n <Spinner size=\"sm\" color=\"secondary\" />\n Loading earlier messages…\n </span>\n ) : (\n <Button variant=\"text\" color=\"secondary\" size=\"sm\" onClick={onLoadMore}>\n Load earlier messages\n </Button>\n )}\n </div>\n )}\n\n {loading && <ChatSkeleton />}\n\n {isEmpty &&\n (emptyContent ?? (\n <EmptyState\n icon={<MessagesSquare />}\n title=\"No messages yet\"\n description={\n showComposer ? 'Send the first message to start the conversation.' : undefined\n }\n size=\"sm\"\n />\n ))}\n\n {!loading && messages.length > 0 && (\n <ol className=\"eidos-conversation-list\">{messages.map(renderMessage)}</ol>\n )}\n\n {typing && typing.length > 0 && (\n <div className=\"eidos-chat-typing\" aria-live=\"polite\">\n <span className=\"eidos-chat-typing-dots\" aria-hidden=\"true\">\n <i />\n <i />\n <i />\n </span>\n {typing.length === 1\n ? `${typing[0].name} is typing…`\n : `${typing.length} people are typing…`}\n </div>\n )}\n </div>\n </div>\n\n {!atBottom && messages.length > 0 && (\n <div className=\"eidos-chat-jump\">\n <Button\n size=\"sm\"\n variant=\"filled\"\n color=\"secondary\"\n preIcon={ArrowDown}\n onClick={() => scrollToBottom('smooth')}\n >\n Latest\n </Button>\n </div>\n )}\n\n {showComposer && (\n <div className=\"eidos-chat-composer\">\n <MessageComposer\n onSubmit={onSend as NonNullable<typeof onSend>}\n placeholder={placeholder}\n sendOnEnter={sendOnEnter}\n allowAttachments={allowAttachments}\n attachmentAccept={attachmentAccept}\n />\n </div>\n )}\n\n {readOnly && readOnlyMessage && (\n <p className=\"eidos-conversation-readonly\">{readOnlyMessage}</p>\n )}\n </div>\n );\n};\n\nChat.displayName = 'Chat';\n","import React, { useCallback, useId, useRef, useState } from 'react';\nimport { Paperclip, Send, X } from 'lucide-react';\nimport { Avatar } from '../Avatar';\nimport { Button } from '../Button';\nimport { Chip } from '../Chip';\nimport type { MessageComposerProps } from './Conversation.types';\nimport { useAutoGrow } from './Conversation.hooks';\nimport { classNames, formatFileSize } from './Conversation.utils';\n\n/**\n * The authoring half of a conversation - a growing text field, optional\n * attachments, and a submit control.\n *\n * Exported on its own so a consumer building a bespoke list can still reuse\n * the input, and used internally by both `Chat` and `CommentThread`.\n */\nexport const MessageComposer: React.FC<MessageComposerProps> = ({\n value,\n onChange,\n onSubmit,\n onCancel,\n placeholder = 'Write a message...',\n submitLabel = 'Send',\n sendOnEnter = false,\n parentId,\n replyingTo,\n allowAttachments = false,\n attachmentAccept,\n author,\n disabled = false,\n requireBody = true,\n autoFocus = false,\n maxLength,\n className = '',\n}) => {\n const [internalBody, setInternalBody] = useState('');\n const [attachments, setAttachments] = useState<File[]>([]);\n const [pending, setPending] = useState(false);\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const fileInputId = useId();\n\n const isControlled = value !== undefined;\n const body = isControlled ? value : internalBody;\n\n useAutoGrow(textareaRef, body);\n\n const setBody = useCallback(\n (next: string) => {\n if (!isControlled) setInternalBody(next);\n onChange?.(next);\n },\n [isControlled, onChange],\n );\n\n const canSubmit = !disabled && !pending && (!requireBody || body.trim().length > 0);\n\n const submit = useCallback(async () => {\n if (!canSubmit) return;\n\n const draft = { body: body.trim(), attachments, parentId };\n const result = onSubmit(draft);\n\n // A synchronous handler clears immediately; an async one keeps the draft\n // until it resolves, so a rejected send never loses what was typed.\n if (!(result instanceof Promise)) {\n setBody('');\n setAttachments([]);\n return;\n }\n\n setPending(true);\n try {\n await result;\n setBody('');\n setAttachments([]);\n } catch {\n // Intentionally swallowed: the draft stays put and the consumer owns\n // error reporting (a Snackbar, an Alert, ...). Rethrowing here would\n // surface as an unhandled rejection from a keystroke.\n } finally {\n setPending(false);\n }\n }, [canSubmit, body, attachments, parentId, onSubmit, setBody]);\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (!sendOnEnter) return;\n // Shift+Enter always inserts a newline; the modifier check also leaves\n // IME composition (which fires Enter to commit) alone.\n if (event.key !== 'Enter' || event.shiftKey || event.nativeEvent.isComposing) return;\n event.preventDefault();\n void submit();\n };\n\n const addFiles = (list: FileList | null) => {\n if (!list?.length) return;\n setAttachments((current) => [...current, ...Array.from(list)]);\n // Reset so selecting the same file twice in a row still fires `change`.\n if (fileInputRef.current) fileInputRef.current.value = '';\n };\n\n const removeAttachment = (index: number) =>\n setAttachments((current) => current.filter((_, i) => i !== index));\n\n return (\n <form\n className={classNames('eidos-message-composer', className)}\n onSubmit={(event) => {\n event.preventDefault();\n void submit();\n }}\n >\n {replyingTo && (\n <div className=\"eidos-composer-reply-hint\">\n <span>\n Replying to <strong>{replyingTo}</strong>\n </span>\n {onCancel && (\n <Button\n variant=\"text\"\n color=\"secondary\"\n size=\"sm\"\n icon={X}\n onClick={onCancel}\n tooltip=\"Cancel reply\"\n aria-label=\"Cancel reply\"\n />\n )}\n </div>\n )}\n\n <div className=\"eidos-composer-row\">\n {author && (\n <div className=\"eidos-composer-avatar\">\n <Avatar\n src={author.avatarSrc}\n name={author.name}\n size=\"sm\"\n color={author.avatarColor ?? 'gray'}\n />\n </div>\n )}\n\n <div className=\"eidos-composer-field\">\n <textarea\n ref={textareaRef}\n className=\"eidos-composer-input\"\n value={body}\n onChange={(event) => setBody(event.target.value)}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled || pending}\n rows={1}\n maxLength={maxLength}\n // Opt-in and off by default. Only the reply composer sets it, where\n // the field appears in direct response to the user pressing Reply -\n // moving focus there is the expected outcome, not a hijack.\n autoFocus={autoFocus}\n aria-label={placeholder}\n />\n\n {attachments.length > 0 && (\n <ul className=\"eidos-composer-attachments\">\n {attachments.map((file, index) => (\n <li key={`${file.name}-${file.size}-${index}`}>\n <Chip\n size=\"sm\"\n variant=\"outlined\"\n color=\"secondary\"\n preIcon={Paperclip}\n onRemove={() => removeAttachment(index)}\n >\n {file.name}\n {file.size > 0 && ` (${formatFileSize(file.size)})`}\n </Chip>\n </li>\n ))}\n </ul>\n )}\n </div>\n </div>\n\n <div className=\"eidos-composer-actions\">\n <div className=\"eidos-composer-actions-start\">\n {allowAttachments && (\n <>\n <input\n ref={fileInputRef}\n id={fileInputId}\n type=\"file\"\n multiple\n accept={attachmentAccept}\n // Hidden from both the tab order and the accessibility\n // tree. It is a proxy: the visible button above opens the\n // file dialog via `.click()`, so this input is an\n // implementation detail, not a control.\n //\n // `visually-hidden` keeps an element *focusable* - that is\n // the point of it, for skip links and screen-reader-only\n // text - so a keyboard user landed on an invisible control\n // and met the same \"Attach files\" action twice. `FileUpload`\n // already gets this right with `display: none` +\n // `tabIndex={-1}`; these two had drifted from it.\n //\n // `aria-hidden` is safe here only *because* of the\n // `tabIndex={-1}` beside it - hiding a focusable element is\n // its own violation.\n className=\"eidos-composer-file-input\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onChange={(event) => addFiles(event.target.files)}\n disabled={disabled || pending}\n />\n <Button\n variant=\"text\"\n color=\"secondary\"\n size=\"sm\"\n icon={Paperclip}\n tooltip=\"Attach files\"\n aria-label=\"Attach files\"\n disabled={disabled || pending}\n onClick={() => fileInputRef.current?.click()}\n />\n </>\n )}\n {sendOnEnter && (\n <span className=\"eidos-composer-hint\">\n <kbd>Enter</kbd> to send · <kbd>Shift</kbd>+<kbd>Enter</kbd> for a new line\n </span>\n )}\n </div>\n\n <div className=\"eidos-composer-actions-end\">\n {onCancel && !replyingTo && (\n <Button\n variant=\"text\"\n color=\"secondary\"\n size=\"sm\"\n onClick={onCancel}\n disabled={pending}\n >\n Cancel\n </Button>\n )}\n <Button\n type=\"submit\"\n size=\"sm\"\n color=\"primary\"\n preIcon={Send}\n loading={pending}\n disabled={!canSubmit}\n >\n {submitLabel}\n </Button>\n </div>\n </div>\n </form>\n );\n};\n\nMessageComposer.displayName = 'MessageComposer';\n","import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';\nimport type { ConversationMessage } from './Conversation.types';\n\n/**\n * Ids that arrived *after* the first render.\n *\n * Seeded from the first commit so an initial page of history is never\n * animated - otherwise opening a thread fades forty messages in at once,\n * which reads as a glitch rather than as feedback. Only genuinely new ids get\n * the entrance class, and each one only once.\n */\nexport const useNewMessageIds = (\n messages: ConversationMessage[],\n enabled: boolean,\n): Set<string> => {\n const seen = useRef<Set<string> | null>(null);\n const [fresh, setFresh] = useState<Set<string>>(() => new Set());\n\n useEffect(() => {\n // First commit: everything already on screen counts as pre-existing.\n if (seen.current === null) {\n seen.current = new Set(messages.map((message) => message.id));\n return;\n }\n\n if (!enabled) {\n for (const message of messages) seen.current.add(message.id);\n return;\n }\n\n const added = messages.filter((message) => !seen.current?.has(message.id));\n if (!added.length) return;\n\n for (const message of added) seen.current.add(message.id);\n setFresh(new Set(added.map((message) => message.id)));\n }, [messages, enabled]);\n\n return fresh;\n};\n\ninterface StickToBottom {\n scrollRef: React.RefObject<HTMLDivElement | null>;\n /**\n * The single element wrapping everything inside the scroll region. Its\n * height *is* the content height, so observing it catches every way the\n * content can grow.\n */\n contentRef: React.RefObject<HTMLDivElement | null>;\n /** The viewport is at (or near) the newest message. */\n atBottom: boolean;\n scrollToBottom: (behavior?: ScrollBehavior) => void;\n handleScroll: () => void;\n}\n\n/** Distance from the bottom still counted as \"reading the newest message\". */\nconst BOTTOM_THRESHOLD_PX = 48;\n\n/**\n * Keeps a bottom-anchored list pinned to the newest message - but only while\n * the reader is already there.\n *\n * Scrolling someone back down while they are reading scrollback is the single\n * most common defect in chat UIs, so arrival of a new message only forces a\n * scroll when `atBottom` was already true. Otherwise the caller surfaces a\n * jump-to-latest affordance and leaves the viewport alone.\n */\nexport const useStickToBottom = (messages: ConversationMessage[]): StickToBottom => {\n const scrollRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const [atBottom, setAtBottom] = useState(true);\n // Read during a layout effect, so it must not be state - it has to be\n // correct for the commit that is happening right now, not the next render.\n const atBottomRef = useRef(true);\n const lastCount = useRef(messages.length);\n const lastScrollTop = useRef(0);\n\n const scrollToBottom = useCallback((behavior: ScrollBehavior = 'smooth') => {\n const node = scrollRef.current;\n if (!node) return;\n node.scrollTo({ top: node.scrollHeight, behavior });\n }, []);\n\n // Stickiness is released only by the *reader* moving up, never by distance\n // alone.\n //\n // Measuring distance alone is wrong the moment content can grow while a\n // smooth scroll is in flight: the scroll events fired mid-animation report\n // the gap to a bottom that has since moved further away, so the reader - who\n // never touched anything - is declared \"not at the bottom\" and the thread\n // stops following a streamed reply partway through. A programmatic scroll\n // to the bottom only ever *increases* `scrollTop`, and content growth does\n // not change it at all, so a decrease is a reliable signal of intent: wheel,\n // keyboard, scrollbar drag and touch all produce one.\n const handleScroll = useCallback(() => {\n const node = scrollRef.current;\n if (!node) return;\n const distance = node.scrollHeight - node.scrollTop - node.clientHeight;\n const movedUp = node.scrollTop < lastScrollTop.current;\n lastScrollTop.current = node.scrollTop;\n\n let next = atBottomRef.current;\n if (distance <= BOTTOM_THRESHOLD_PX) next = true;\n else if (movedUp) next = false;\n\n atBottomRef.current = next;\n setAtBottom((current) => (current === next ? current : next));\n }, []);\n\n // Jump (not animate) to the bottom on first paint so a thread opens on its\n // newest message instead of visibly scrolling there.\n useLayoutEffect(() => {\n scrollToBottom('auto');\n // eslint-disable-next-line react-hooks/exhaustive-deps -- mount only\n }, []);\n\n useLayoutEffect(() => {\n if (messages.length > lastCount.current && atBottomRef.current) {\n scrollToBottom('smooth');\n }\n lastCount.current = messages.length;\n }, [messages.length, scrollToBottom]);\n\n // The effect above only reacts to the *number* of messages. A reply that is\n // streamed into an existing message - or a typing indicator appearing, or\n // an image loading - grows the content without changing that number, and\n // used to push the newest text below the fold while the reader was sitting\n // at the bottom waiting for it.\n //\n // Observing the content wrapper covers every one of those, because its\n // height is the content height. The scroll container itself cannot be\n // observed for this: its own box never changes size, only its\n // `scrollHeight` does.\n //\n // `'auto'`, not `'smooth'`: a stream grows the content once per token, and\n // a smooth scroll restarted that often never catches up with the text.\n // `atBottomRef` still holds the reader's position from *before* the growth,\n // which is exactly the question - \"were they following along?\".\n //\n // Growth that coincides with a new message is left to the smooth scroll the\n // layout effect above already started; jumping here as well would cancel\n // that animation on every single arrival.\n useEffect(() => {\n const content = contentRef.current;\n if (!content || typeof ResizeObserver === 'undefined') return;\n\n let lastHeight = content.getBoundingClientRect().height;\n let observedCount = lastCount.current;\n const observer = new ResizeObserver(() => {\n const height = content.getBoundingClientRect().height;\n const countChanged = observedCount !== lastCount.current;\n observedCount = lastCount.current;\n if (height > lastHeight && !countChanged && atBottomRef.current) scrollToBottom('auto');\n lastHeight = height;\n });\n observer.observe(content);\n return () => observer.disconnect();\n }, [scrollToBottom]);\n\n return { scrollRef, contentRef, atBottom, scrollToBottom, handleScroll };\n};\n\n/**\n * Preserves the reader's position when older messages are prepended.\n *\n * Without this, inserting a page above the viewport pushes the content the\n * user was reading down by the height of everything added, which reads as the\n * list jumping to a random place. Capturing `scrollHeight` before the DOM\n * mutation and restoring the delta in a *layout* effect corrects it before the\n * browser paints, so there is no visible shift.\n */\nexport const useScrollAnchor = (\n scrollRef: React.RefObject<HTMLDivElement | null>,\n messages: ConversationMessage[],\n): void => {\n const previous = useRef({ height: 0, firstId: '', count: 0 });\n\n useLayoutEffect(() => {\n const node = scrollRef.current;\n if (!node) return;\n\n const firstId = messages[0]?.id ?? '';\n const before = previous.current;\n // A prepend is the only case where the first id changes while the list\n // grows - an append leaves it untouched, and a replacement shrinks it.\n const prepended =\n before.firstId !== '' && before.firstId !== firstId && messages.length > before.count;\n\n if (prepended) {\n node.scrollTop += node.scrollHeight - before.height;\n }\n\n previous.current = { height: node.scrollHeight, firstId, count: messages.length };\n }, [messages, scrollRef]);\n};\n\n/**\n * Fires `onLoadMore` once the reader approaches the top of the history.\n *\n * Latched on the way in and released only after they scroll back out of the\n * trigger zone, so a single pause near the top can't queue a dozen fetches.\n */\nexport const useLoadMoreOnScrollTop = (\n scrollRef: React.RefObject<HTMLDivElement | null>,\n {\n hasMore,\n loadingMore,\n onLoadMore,\n }: {\n hasMore?: boolean;\n loadingMore?: boolean;\n onLoadMore?: () => void;\n },\n thresholdPx = 80,\n): (() => void) => {\n const armed = useRef(true);\n\n return useCallback(() => {\n const node = scrollRef.current;\n if (!node) return;\n\n if (node.scrollTop > thresholdPx) {\n armed.current = true;\n return;\n }\n\n if (!armed.current || !hasMore || loadingMore || !onLoadMore) return;\n armed.current = false;\n onLoadMore();\n }, [scrollRef, hasMore, loadingMore, onLoadMore, thresholdPx]);\n};\n\n/**\n * Grows a textarea to fit its content, up to `maxHeight`.\n *\n * Height is written to `style.height` directly rather than through a React\n * inline style: it is measured from the live DOM after every keystroke, so it\n * cannot be expressed as a class, and routing it through state would add a\n * render per character. Assigning the property imperatively also keeps it out\n * of the server-rendered `style` attribute that CSP's `style-src-attr` gates.\n */\nexport const useAutoGrow = (\n ref: React.RefObject<HTMLTextAreaElement | null>,\n value: string,\n maxHeight = 200,\n): void => {\n useLayoutEffect(() => {\n const node = ref.current;\n if (!node) return;\n\n node.style.height = 'auto';\n const next = Math.min(node.scrollHeight, maxHeight);\n node.style.height = `${next}px`;\n node.style.overflowY = node.scrollHeight > maxHeight ? 'auto' : 'hidden';\n }, [ref, value, maxHeight]);\n};\n","import type { ConversationMessage } from './Conversation.types';\n\n/**\n * Timestamp formatting goes through `Intl` rather than a date library on\n * purpose: `dayjs` is currently bundled only into the `DatePicker` chunk, and\n * pulling it in here would add it to every consumer importing a conversation.\n * `Intl` is built in and already locale-aware.\n */\n\nconst timeFormat = new Intl.DateTimeFormat(undefined, {\n hour: '2-digit',\n minute: '2-digit',\n});\n\nconst dateFormat = new Intl.DateTimeFormat(undefined, {\n day: 'numeric',\n month: 'long',\n year: 'numeric',\n});\n\nconst dateFormatSameYear = new Intl.DateTimeFormat(undefined, {\n day: 'numeric',\n month: 'long',\n});\n\n/** Parses an ISO string, returning null rather than an `Invalid Date`. */\nexport const parseDate = (iso: string): Date | null => {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? null : date;\n};\n\nexport const formatMessageTime = (iso: string): string => {\n const date = parseDate(iso);\n return date ? timeFormat.format(date) : iso;\n};\n\nconst startOfDay = (date: Date): number =>\n new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n\nexport const isSameDay = (a: string, b: string): boolean => {\n const first = parseDate(a);\n const second = parseDate(b);\n if (!first || !second) return false;\n return startOfDay(first) === startOfDay(second);\n};\n\n/** `Today` / `Yesterday` / a full date, for the divider between days. */\nexport const formatDateSeparator = (iso: string): string => {\n const date = parseDate(iso);\n if (!date) return iso;\n\n const now = new Date();\n const dayDelta = Math.round((startOfDay(now) - startOfDay(date)) / 86_400_000);\n\n if (dayDelta === 0) return 'Today';\n if (dayDelta === 1) return 'Yesterday';\n return date.getFullYear() === now.getFullYear()\n ? dateFormatSameYear.format(date)\n : dateFormat.format(date);\n};\n\nconst FILE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'];\n\nexport const formatFileSize = (bytes: number): string => {\n if (!Number.isFinite(bytes) || bytes < 0) return '';\n if (bytes < 1024) return `${bytes} B`;\n\n let value = bytes;\n let unit = 0;\n while (value >= 1024 && unit < FILE_UNITS.length - 1) {\n value /= 1024;\n unit += 1;\n }\n // One decimal below 10 (9.4 MB), none above it (24 MB) - the extra digit\n // stops carrying information once the integer part is two digits.\n return `${value < 10 ? value.toFixed(1) : Math.round(value)} ${FILE_UNITS[unit]}`;\n};\n\n/**\n * Whether `message` continues a run started by `previous` - same author, same\n * day, and within the grouping window. A grouped message hides its avatar and\n * author line.\n */\nexport const continuesRun = (\n previous: ConversationMessage | undefined,\n message: ConversationMessage,\n windowMinutes: number,\n): boolean => {\n if (!previous) return false;\n if (previous.author.id !== message.author.id) return false;\n if (!isSameDay(previous.sentAt, message.sentAt)) return false;\n\n const before = parseDate(previous.sentAt);\n const after = parseDate(message.sentAt);\n if (!before || !after) return false;\n\n return Math.abs(after.getTime() - before.getTime()) <= windowMinutes * 60_000;\n};\n\nexport const sortBySentAt = (messages: ConversationMessage[]): ConversationMessage[] =>\n [...messages].sort((a, b) => {\n const first = parseDate(a.sentAt)?.getTime() ?? 0;\n const second = parseDate(b.sentAt)?.getTime() ?? 0;\n return first - second;\n });\n\nexport interface ThreadNode {\n message: ConversationMessage;\n replies: ConversationMessage[];\n}\n\n/**\n * Collapses a flat list into one level of nesting.\n *\n * Deeper chains are flattened onto the nearest **top-level** ancestor rather\n * than being dropped or nested further: indentation past one level is\n * unreadable on a phone, and silently discarding a reply-to-a-reply would lose\n * data the consumer stored. `replyingToName` on the rendered reply is what\n * preserves who was actually answered.\n *\n * A `parentId` pointing at a message that isn't present (paged out, deleted)\n * is treated as top-level, so nothing ever disappears from the list.\n */\nexport const buildThread = (messages: ConversationMessage[]): ThreadNode[] => {\n const byId = new Map(messages.map((message) => [message.id, message]));\n\n /** Walks up to the outermost ancestor, guarding against a parentId cycle. */\n const rootIdOf = (message: ConversationMessage): string => {\n const seen = new Set<string>([message.id]);\n let current = message;\n\n while (current.parentId) {\n const parent = byId.get(current.parentId);\n if (!parent || seen.has(parent.id)) break;\n seen.add(parent.id);\n current = parent;\n }\n\n return current.id;\n };\n\n const nodes = new Map<string, ThreadNode>();\n const roots: ThreadNode[] = [];\n\n for (const message of messages) {\n if (message.parentId && byId.has(message.parentId)) continue;\n const node: ThreadNode = { message, replies: [] };\n nodes.set(message.id, node);\n roots.push(node);\n }\n\n for (const message of messages) {\n if (!message.parentId || !byId.has(message.parentId)) continue;\n nodes.get(rootIdOf(message))?.replies.push(message);\n }\n\n for (const node of nodes.values()) {\n node.replies = sortBySentAt(node.replies);\n }\n\n return roots;\n};\n\n/** Name of the author a reply was addressed to, when it isn't its own parent. */\nexport const replyTargetName = (\n message: ConversationMessage,\n byId: Map<string, ConversationMessage>,\n rootId: string,\n): string | undefined => {\n if (!message.parentId || message.parentId === rootId) return undefined;\n return byId.get(message.parentId)?.author.name;\n};\n\n/** Trims a quoted excerpt so a long parent message can't dominate the reply. */\nexport const excerpt = (body: string, maxLength = 120): string => {\n const flat = body.replace(/\\s+/g, ' ').trim();\n return flat.length > maxLength ? `${flat.slice(0, maxLength - 1)}…` : flat;\n};\n\nexport const classNames = (...values: Array<string | false | null | undefined>): string =>\n values.filter(Boolean).join(' ');\n","import React from 'react';\nimport { AlertCircle, MoreHorizontal, Paperclip, RotateCw } from 'lucide-react';\nimport { Avatar } from '../Avatar';\nimport { Button } from '../Button';\nimport { Menu } from '../Menu';\nimport { Pill } from '../Pill';\nimport { Spinner } from '../Spinner';\nimport type { ConversationMessage, MessageAttachment } from './Conversation.types';\nimport type { MenuItemType } from '../Menu';\nimport { classNames, excerpt, formatFileSize, formatMessageTime } from './Conversation.utils';\n\nexport interface MessageItemProps {\n message: ConversationMessage;\n /** 'chat' right-aligns own messages into bubbles; 'comment' renders a flat card. */\n layout: 'chat' | 'comment';\n isOwn: boolean;\n /** Continues a run from the same author - hides the avatar and author line. */\n grouped: boolean;\n /** Plays the entrance animation. */\n isNew: boolean;\n actions?: MenuItemType[];\n footer?: React.ReactNode;\n body?: React.ReactNode;\n onRetry?: () => void;\n /** Author of the message being answered, for a flattened deep reply. */\n replyingToName?: string;\n /** Quoted parent, rendered above the body in chat layout. */\n quoted?: ConversationMessage;\n /** Reply affordance; omitted entirely when the viewer may not reply. */\n onReply?: () => void;\n formatTimestamp?: (iso: string) => string;\n}\n\nconst AttachmentList: React.FC<{ attachments: MessageAttachment[] }> = ({ attachments }) => (\n <ul className=\"eidos-message-attachments\">\n {attachments.map((attachment) => {\n const label = (\n <>\n <Paperclip aria-hidden=\"true\" />\n <span className=\"eidos-message-attachment-name\">{attachment.name}</span>\n {attachment.size !== undefined && (\n <span className=\"eidos-message-attachment-size\">{formatFileSize(attachment.size)}</span>\n )}\n </>\n );\n\n return (\n <li key={attachment.id} className=\"eidos-message-attachment\">\n {attachment.url ? (\n <a\n href={attachment.url}\n className=\"eidos-message-attachment-link\"\n target=\"_blank\"\n rel=\"noreferrer\"\n download={attachment.name}\n >\n {label}\n </a>\n ) : (\n <span className=\"eidos-message-attachment-link\">{label}</span>\n )}\n </li>\n );\n })}\n </ul>\n);\n\nexport const MessageItem: React.FC<MessageItemProps> = ({\n message,\n layout,\n isOwn,\n grouped,\n isNew,\n actions,\n footer,\n body,\n onRetry,\n replyingToName,\n quoted,\n onReply,\n formatTimestamp,\n}) => {\n const { author, status = 'sent' } = message;\n const timestamp = formatTimestamp\n ? formatTimestamp(message.sentAt)\n : formatMessageTime(message.sentAt);\n // An empty action list must not leave a dead trigger behind - see the\n // permissions note in Conversation.types.ts.\n const hasActions = Boolean(actions && actions.length > 0);\n\n // One placement per layout, rather than one per message.\n //\n // `chat` puts the time at the foot of the bubble, where a grouped message\n // already had it; it used to appear in the header for the first message of a\n // group and inside the bubble for the rest, so a single thread showed the\n // same fact in two places. `comment` keeps it in the header, where the row is\n // full width and has space for it.\n const timeInBubble = layout === 'chat';\n\n return (\n <li\n className={classNames(\n 'eidos-message',\n `eidos-message--${layout}`,\n isOwn && 'eidos-message--own',\n grouped && 'eidos-message--grouped',\n status !== 'sent' && `eidos-message--${status}`,\n isNew && 'eidos-message--enter',\n )}\n data-message-id={message.id}\n >\n <div className=\"eidos-message-avatar\">\n {!grouped && (\n <Avatar\n src={author.avatarSrc}\n name={author.name}\n size=\"sm\"\n color={author.avatarColor ?? 'gray'}\n />\n )}\n </div>\n\n <div className=\"eidos-message-main\">\n {!grouped && (\n <div className=\"eidos-message-header\">\n <span className=\"eidos-message-author\">{author.name}</span>\n {author.role && (\n <Pill size=\"sm\" variant=\"outlined\" color=\"secondary\">\n {author.role}\n </Pill>\n )}\n {!timeInBubble && (\n <time className=\"eidos-message-time\" dateTime={message.sentAt}>\n {timestamp}\n </time>\n )}\n {message.edited && <span className=\"eidos-message-edited\">edited</span>}\n </div>\n )}\n\n <div className=\"eidos-message-bubble\">\n {quoted && (\n <blockquote className=\"eidos-message-quote\">\n <span className=\"eidos-message-quote-author\">{quoted.author.name}</span>\n <span className=\"eidos-message-quote-body\">{excerpt(quoted.body)}</span>\n </blockquote>\n )}\n\n {replyingToName && (\n <span className=\"eidos-message-reply-target\">Replying to {replyingToName}</span>\n )}\n\n <div className=\"eidos-message-body\">{body ?? message.body}</div>\n\n {message.attachments && message.attachments.length > 0 && (\n <AttachmentList attachments={message.attachments} />\n )}\n\n {(timeInBubble || grouped) && (\n <time\n className=\"eidos-message-time eidos-message-time--inline\"\n dateTime={message.sentAt}\n >\n {timestamp}\n </time>\n )}\n </div>\n\n {status === 'sending' && (\n <span className=\"eidos-message-status\">\n <Spinner size=\"sm\" color=\"secondary\" />\n Sending…\n </span>\n )}\n\n {status === 'failed' && (\n <span className=\"eidos-message-status eidos-message-status--failed\">\n <AlertCircle aria-hidden=\"true\" />\n Not sent\n {onRetry && (\n <Button variant=\"text\" color=\"danger\" size=\"sm\" preIcon={RotateCw} onClick={onRetry}>\n Retry\n </Button>\n )}\n </span>\n )}\n\n {footer && <div className=\"eidos-message-footer\">{footer}</div>}\n\n {onReply && (\n <div className=\"eidos-message-reply\">\n <Button variant=\"text\" color=\"secondary\" size=\"sm\" onClick={onReply}>\n Reply\n </Button>\n </div>\n )}\n </div>\n\n {hasActions && (\n <div className=\"eidos-message-actions\">\n <Menu\n items={actions ?? []}\n trigger={\n <Button\n variant=\"text\"\n color=\"secondary\"\n size=\"sm\"\n icon={MoreHorizontal}\n aria-label={`Actions for ${author.name}'s message`}\n />\n }\n />\n </div>\n )}\n </li>\n );\n};\n\nMessageItem.displayName = 'MessageItem';\n","import React, { useCallback, useMemo, useState } from 'react';\nimport { MessageSquare } from 'lucide-react';\nimport { Button } from '../Button';\nimport { EmptyState } from '../EmptyState';\nimport { Skeleton } from '../Skeleton';\nimport { Spinner } from '../Spinner';\nimport { MessageComposer } from './MessageComposer.component';\nimport { MessageItem } from './MessageItem.component';\nimport type { CommentThreadProps, ConversationMessage, MessageDraft } from './Conversation.types';\nimport { useNewMessageIds } from './Conversation.hooks';\nimport {\n buildThread,\n classNames,\n continuesRun,\n replyTargetName,\n sortBySentAt,\n} from './Conversation.utils';\n\nconst CommentSkeleton: React.FC = () => (\n <div className=\"eidos-comment-thread-skeleton\" aria-hidden=\"true\">\n {[0, 1, 2].map((row) => (\n <div key={row} className=\"eidos-comment-thread-skeleton-row\">\n <Skeleton variant=\"circular\" width={28} height={28} />\n <Skeleton variant=\"text\" lines={2} />\n </div>\n ))}\n </div>\n);\n\n/**\n * A comment section: document flow, no internal scroll container, one level of\n * nesting.\n *\n * Shares its data model and message rendering with `Chat`, so history captured\n * in one can be displayed in the other. Unlike `Chat` it has no scroll region\n * of its own - it grows with the page and pages *downward* via `onLoadMore`.\n */\nexport const CommentThread: React.FC<CommentThreadProps> = ({\n messages,\n currentUserId,\n onSend,\n onReply,\n onRetry,\n readOnly = false,\n readOnlyMessage,\n renderBody,\n messageActions,\n renderMessageFooter,\n loading = false,\n emptyContent,\n hasMore = false,\n loadingMore = false,\n onLoadMore,\n groupConsecutive = true,\n groupWindowMinutes = 5,\n formatTimestamp,\n animateNewMessages = true,\n allowAttachments = false,\n attachmentAccept,\n order = 'oldest-first',\n composerPosition = 'bottom',\n placeholder = 'Add a comment...',\n sendOnEnter = false,\n title,\n ariaLabel = 'Comments',\n className = '',\n}) => {\n const [replyingToId, setReplyingToId] = useState<string | null>(null);\n const newIds = useNewMessageIds(messages, animateNewMessages);\n\n const byId = useMemo(() => new Map(messages.map((message) => [message.id, message])), [messages]);\n\n const roots = useMemo(() => {\n const thread = buildThread(messages);\n const sorted = sortBySentAt(thread.map((node) => node.message));\n const ordered = order === 'newest-first' ? [...sorted].reverse() : sorted;\n const nodeById = new Map(thread.map((node) => [node.message.id, node]));\n // Replies always read oldest-first, even when roots are reversed - a\n // conversation under a single comment is chronological by nature.\n return ordered.map((message) => nodeById.get(message.id)!);\n }, [messages, order]);\n\n const canReply = !readOnly && Boolean(onReply);\n const showComposer = !readOnly && Boolean(onSend);\n const isEmpty = !loading && messages.length === 0;\n const total = messages.length;\n\n const handleReply = useCallback(\n async (draft: MessageDraft) => {\n await onReply?.(draft);\n setReplyingToId(null);\n },\n [onReply],\n );\n\n const renderComment = (\n message: ConversationMessage,\n options: { rootId: string; previous?: ConversationMessage; isReply: boolean },\n ) => {\n const actions = readOnly ? undefined : messageActions?.(message);\n\n return (\n <MessageItem\n key={message.id}\n message={message}\n layout=\"comment\"\n isOwn={Boolean(currentUserId) && message.author.id === currentUserId}\n grouped={groupConsecutive && continuesRun(options.previous, message, groupWindowMinutes)}\n isNew={newIds.has(message.id)}\n actions={actions}\n footer={renderMessageFooter?.(message)}\n body={renderBody?.(message)}\n onRetry={!readOnly && onRetry ? () => onRetry(message) : undefined}\n replyingToName={\n options.isReply ? replyTargetName(message, byId, options.rootId) : undefined\n }\n onReply={canReply ? () => setReplyingToId(message.id) : undefined}\n formatTimestamp={formatTimestamp}\n />\n );\n };\n\n const composer = showComposer && (\n <MessageComposer\n onSubmit={onSend as NonNullable<typeof onSend>}\n placeholder={placeholder}\n submitLabel=\"Comment\"\n sendOnEnter={sendOnEnter}\n allowAttachments={allowAttachments}\n attachmentAccept={attachmentAccept}\n className=\"eidos-comment-thread-composer\"\n />\n );\n\n return (\n <section className={classNames('eidos-comment-thread', className)} aria-label={ariaLabel}>\n {(title || total > 0) && (\n <header className=\"eidos-comment-thread-header\">\n {title && <h3 className=\"eidos-comment-thread-title\">{title}</h3>}\n {total > 0 && (\n <span className=\"eidos-comment-thread-count\">\n {total} {total === 1 ? 'comment' : 'comments'}\n </span>\n )}\n </header>\n )}\n\n {composerPosition === 'top' && composer}\n\n {loading && <CommentSkeleton />}\n\n {isEmpty &&\n (emptyContent ?? (\n <EmptyState\n icon={<MessageSquare />}\n title=\"No comments yet\"\n description={showComposer ? 'Start the discussion by leaving a comment.' : undefined}\n size=\"sm\"\n />\n ))}\n\n {!loading && roots.length > 0 && (\n <ol className=\"eidos-conversation-list eidos-comment-thread-list\" aria-busy={loadingMore}>\n {roots.map((node) => (\n <li key={node.message.id} className=\"eidos-comment-thread-node\">\n <ol className=\"eidos-conversation-list\">\n {renderComment(node.message, { rootId: node.message.id, isReply: false })}\n </ol>\n\n {node.replies.length > 0 && (\n <ol className=\"eidos-conversation-list eidos-comment-thread-replies\">\n {node.replies.map((reply, index) =>\n renderComment(reply, {\n rootId: node.message.id,\n previous: node.replies[index - 1],\n isReply: true,\n }),\n )}\n </ol>\n )}\n\n {replyingToId &&\n (replyingToId === node.message.id ||\n node.replies.some((reply) => reply.id === replyingToId)) && (\n <div className=\"eidos-comment-thread-reply-composer\">\n <MessageComposer\n onSubmit={handleReply}\n onCancel={() => setReplyingToId(null)}\n parentId={replyingToId}\n replyingTo={byId.get(replyingToId)?.author.name}\n placeholder=\"Write a reply...\"\n submitLabel=\"Reply\"\n sendOnEnter={sendOnEnter}\n allowAttachments={allowAttachments}\n attachmentAccept={attachmentAccept}\n autoFocus\n />\n </div>\n )}\n </li>\n ))}\n </ol>\n )}\n\n {hasMore && (\n <div className=\"eidos-comment-thread-load-more\">\n {loadingMore ? (\n <span className=\"eidos-comment-thread-loading-more\">\n <Spinner size=\"sm\" color=\"secondary\" />\n Loading more comments…\n </span>\n ) : (\n <Button variant=\"outlined\" color=\"secondary\" size=\"sm\" onClick={onLoadMore}>\n Load more comments\n </Button>\n )}\n </div>\n )}\n\n {composerPosition === 'bottom' && composer}\n\n {readOnly && readOnlyMessage && (\n <p className=\"eidos-conversation-readonly\">{readOnlyMessage}</p>\n )}\n </section>\n );\n};\n\nCommentThread.displayName = 'CommentThread';\n"],"mappings":"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","names":["useCallback","useCallback","useRef","useState","useState","useRef","useCallback","Paperclip","Fragment","jsx","jsxs","Paperclip","jsx","jsxs","useCallback","useCallback","useMemo","useState","jsx","jsxs","useState","useMemo","useCallback"]}
@@ -1,4 +1,8 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/components/Breadcrumb/Breadcrumb.component.tsx
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
+
3
+ var _chunkKXDGW6LJcjs = require('./chunk-KXDGW6LJ.cjs');
4
+
5
+ // src/components/Breadcrumb/Breadcrumb.component.tsx
2
6
  var _jsxruntime = require('react/jsx-runtime');
3
7
  var Breadcrumb = ({
4
8
  items,
@@ -19,7 +23,7 @@ var Breadcrumb = ({
19
23
  isLast ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "aria-current": "page", className: "eidos-breadcrumb-current", children: [
20
24
  item.icon && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-breadcrumb-icon", children: item.icon }),
21
25
  item.label
22
- ] }) : item.href ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "a", { href: item.href, onClick: item.onClick, className: "eidos-breadcrumb-link", children: [
26
+ ] }) : item.href ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkKXDGW6LJcjs.EidosLink, { href: item.href, onClick: item.onClick, className: "eidos-breadcrumb-link", children: [
23
27
  item.icon && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-breadcrumb-icon", children: item.icon }),
24
28
  item.label
25
29
  ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -47,4 +51,4 @@ Breadcrumb.displayName = "Breadcrumb";
47
51
 
48
52
 
49
53
  exports.Breadcrumb = Breadcrumb;
50
- //# sourceMappingURL=chunk-5O73AALP.cjs.map
54
+ //# sourceMappingURL=chunk-GP6EEZH5.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-GP6EEZH5.cjs","../src/components/Breadcrumb/Breadcrumb.component.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACqBc,+CAAA;AArBP,IAAM,WAAA,EAAwC,CAAC;AAAA,EACpD,KAAA;AAAA,EACA,UAAA,EAAY,GAAA;AAAA,EACZ,UAAA,EAAY;AACd,CAAA,EAAA,mBACE,6BAAA;AAAA,EAAC,KAAA;AAAA,EAAA;AAAA,IACC,YAAA,EAAW,YAAA;AAAA,IACX,SAAA,EAAW,CAAC,sBAAA,EAAwB,SAAS,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AAAA,IAEvE,QAAA,kBAAA,6BAAA,IAAC,EAAA,EAAG,SAAA,EAAU,kBAAA,EACX,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,EAAA,GAAU;AAC1B,MAAA,MAAM,OAAA,EAAS,MAAA,IAAU,KAAA,CAAM,OAAA,EAAS,CAAA;AAExC,MAAA,uBACE,8BAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UAEC,SAAA,EAAW,CAAC,uBAAA,EAAyB,OAAA,GAAU,gCAAgC,CAAA,CAC5E,MAAA,CAAO,OAAO,CAAA,CACd,IAAA,CAAK,GAAG,CAAA;AAAA,UAEV,QAAA,EAAA;AAAA,YAAA,OAAA,kBACC,8BAAA,MAAC,EAAA,EAAK,cAAA,EAAa,MAAA,EAAO,SAAA,EAAU,0BAAA,EACjC,QAAA,EAAA;AAAA,cAAA,IAAA,CAAK,KAAA,mBAAQ,6BAAA,MAAC,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,IAAA,CAAK,KAAA,CAAK,CAAA;AAAA,cAChE,IAAA,CAAK;AAAA,YAAA,EAAA,CACR,EAAA,EACE,IAAA,CAAK,KAAA,kBACP,8BAAA,2BAAC,EAAA,EAAU,IAAA,EAAM,IAAA,CAAK,IAAA,EAAM,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,SAAA,EAAU,uBAAA,EAC1D,QAAA,EAAA;AAAA,cAAA,IAAA,CAAK,KAAA,mBAAQ,6BAAA,MAAC,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,IAAA,CAAK,KAAA,CAAK,CAAA;AAAA,cAChE,IAAA,CAAK;AAAA,YAAA,EAAA,CACR,EAAA,kBAEA,8BAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBACC,IAAA,EAAK,QAAA;AAAA,gBACL,OAAA,EAAS,IAAA,CAAK,OAAA;AAAA,gBACd,SAAA,EAAU,qDAAA;AAAA,gBAET,QAAA,EAAA;AAAA,kBAAA,IAAA,CAAK,KAAA,mBAAQ,6BAAA,MAAC,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,IAAA,CAAK,KAAA,CAAK,CAAA;AAAA,kBAChE,IAAA,CAAK;AAAA,gBAAA;AAAA,cAAA;AAAA,YACR,CAAA;AAAA,YAGD,CAAC,OAAA,mBACA,6BAAA,MAAC,EAAA,EAAK,aAAA,EAAY,MAAA,EAAO,SAAA,EAAU,4BAAA,EAChC,QAAA,EAAA,UAAA,CACH;AAAA,UAAA;AAAA,QAAA,CAAA;AAAA,QA7BG;AAAA,MA+BP,CAAA;AAAA,IAEJ,CAAC,EAAA,CACH;AAAA,EAAA;AACF,CAAA;AAGF,UAAA,CAAW,YAAA,EAAc,YAAA;ADRzB;AACA;AACE;AACF,gCAAC","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-GP6EEZH5.cjs","sourcesContent":[null,"import React from 'react';\nimport type { BreadcrumbProps } from './Breadcrumb.types';\nimport { EidosLink } from '../LinkProvider/Link.component';\n\nexport const Breadcrumb: React.FC<BreadcrumbProps> = ({\n items,\n separator = '/',\n className = '',\n}) => (\n <nav\n aria-label=\"Breadcrumb\"\n className={['eidos-breadcrumb-nav', className].filter(Boolean).join(' ')}\n >\n <ol className=\"eidos-breadcrumb\">\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n\n return (\n <li\n key={index}\n className={['eidos-breadcrumb-item', isLast && 'eidos-breadcrumb-item--current']\n .filter(Boolean)\n .join(' ')}\n >\n {isLast ? (\n <span aria-current=\"page\" className=\"eidos-breadcrumb-current\">\n {item.icon && <span className=\"eidos-breadcrumb-icon\">{item.icon}</span>}\n {item.label}\n </span>\n ) : item.href ? (\n <EidosLink href={item.href} onClick={item.onClick} className=\"eidos-breadcrumb-link\">\n {item.icon && <span className=\"eidos-breadcrumb-icon\">{item.icon}</span>}\n {item.label}\n </EidosLink>\n ) : (\n <button\n type=\"button\"\n onClick={item.onClick}\n className=\"eidos-breadcrumb-link eidos-breadcrumb-link--button\"\n >\n {item.icon && <span className=\"eidos-breadcrumb-icon\">{item.icon}</span>}\n {item.label}\n </button>\n )}\n\n {!isLast && (\n <span aria-hidden=\"true\" className=\"eidos-breadcrumb-separator\">\n {separator}\n </span>\n )}\n </li>\n );\n })}\n </ol>\n </nav>\n);\n\nBreadcrumb.displayName = 'Breadcrumb';\n"]}
@@ -1,21 +1,21 @@
1
1
  import {
2
2
  DatePicker
3
- } from "./chunk-2PCCGQOH.js";
3
+ } from "./chunk-P6OJQ2RN.js";
4
4
  import {
5
5
  Select
6
- } from "./chunk-MQAOXZD4.js";
6
+ } from "./chunk-4S57PE43.js";
7
7
  import {
8
8
  Input
9
- } from "./chunk-YAKTVIVK.js";
9
+ } from "./chunk-XIUZT4TO.js";
10
10
  import {
11
11
  Dropdown
12
- } from "./chunk-JHX6JK3M.js";
12
+ } from "./chunk-3X6QVHTD.js";
13
13
  import {
14
14
  Badge
15
15
  } from "./chunk-3SKI6FXB.js";
16
16
  import {
17
17
  Button
18
- } from "./chunk-75GFIQRU.js";
18
+ } from "./chunk-JY77VJAZ.js";
19
19
 
20
20
  // src/components/Table/TableFiltersDropdown.component.tsx
21
21
  import { useMemo, useState, useEffect, useRef } from "react";
@@ -4443,4 +4443,4 @@ export {
4443
4443
  sortableKeyboardCoordinates,
4444
4444
  TableFiltersDropdown
4445
4445
  };
4446
- //# sourceMappingURL=chunk-SDUGYJGW.js.map
4446
+ //# sourceMappingURL=chunk-H3C6YECZ.js.map
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
2
2
 
3
- var _chunk35LGEPLPcjs = require('./chunk-35LGEPLP.cjs');
3
+ var _chunkENMDOQQOcjs = require('./chunk-ENMDOQQO.cjs');
4
4
 
5
5
  // src/components/ThemeProvider/ThemeProvider.component.tsx
6
6
  var _react = require('react');
@@ -248,7 +248,7 @@ var resolveTheme = (theme) => {
248
248
  }
249
249
  const { base, contrast } = normalizeColor(supplied);
250
250
  if (!isValidHex(base)) {
251
- _chunk35LGEPLPcjs.devWarn.call(void 0,
251
+ _chunkENMDOQQOcjs.devWarn.call(void 0,
252
252
  `theme-color-${key}`,
253
253
  `ThemeProvider: colors.${key} is not a valid hex colour (received ${JSON.stringify(base)}). Falling back to the preset.`
254
254
  );
@@ -256,7 +256,7 @@ var resolveTheme = (theme) => {
256
256
  continue;
257
257
  }
258
258
  if (contrast !== void 0 && !isValidHex(contrast)) {
259
- _chunk35LGEPLPcjs.devWarn.call(void 0,
259
+ _chunkENMDOQQOcjs.devWarn.call(void 0,
260
260
  `theme-contrast-${key}`,
261
261
  `ThemeProvider: colors.${key}.contrast is not a valid hex colour (received ${JSON.stringify(contrast)}). It will be computed instead.`
262
262
  );
@@ -269,7 +269,7 @@ var resolveTheme = (theme) => {
269
269
  let fontScale = defaultTheme.typography.fontScale;
270
270
  if (scale !== void 0) {
271
271
  if (!Number.isFinite(scale) || scale < FONT_SCALE_MIN || scale > FONT_SCALE_MAX) {
272
- _chunk35LGEPLPcjs.devWarn.call(void 0,
272
+ _chunkENMDOQQOcjs.devWarn.call(void 0,
273
273
  "theme-font-scale",
274
274
  `ThemeProvider: typography.fontScale must be between ${FONT_SCALE_MIN} and ${FONT_SCALE_MAX} (received ${String(scale)}). Falling back to ${fontScale}.`
275
275
  );
@@ -301,7 +301,7 @@ var buildTokens = (resolved) => {
301
301
  const isPreset = base === normalizeColor(defaultTheme.colors[key]).base;
302
302
  const ramp = isPreset ? DEFAULT_PRIMARY_RAMP : buildRamp(base);
303
303
  if (!isPreset && !isRampViable(base)) {
304
- _chunk35LGEPLPcjs.devWarn.call(void 0,
304
+ _chunkENMDOQQOcjs.devWarn.call(void 0,
305
305
  `theme-ramp-${key}`,
306
306
  `ThemeProvider: colors.${key} (${base}) is too light or too dark to generate a usable --${key}-50\u2026900 scale; several steps will be identical. Pick a colour with more headroom.`
307
307
  );
@@ -357,7 +357,7 @@ var ThemeProvider = ({
357
357
  _react.useEffect.call(void 0, () => {
358
358
  mountedProviders += 1;
359
359
  if (mountedProviders > 1) {
360
- _chunk35LGEPLPcjs.devWarn.call(void 0,
360
+ _chunkENMDOQQOcjs.devWarn.call(void 0,
361
361
  "theme-multiple-providers",
362
362
  `ThemeProvider: ${mountedProviders} providers are mounted at once. They all write to document.documentElement, so the last one to apply each token wins for the whole page - nested or sibling providers cannot theme separate subtrees. Use a single provider at your app root.`
363
363
  );
@@ -521,4 +521,4 @@ var isFontStackAvailable = (stack) => isFontAvailable(_nullishCoalesce(stack.spl
521
521
 
522
522
 
523
523
  exports.useTheme = useTheme; exports.contrastRatio = contrastRatio; exports.CONTRAST_LIGHT = CONTRAST_LIGHT; exports.CONTRAST_DARK = CONTRAST_DARK; exports.pickContrast = pickContrast; exports.THEME_COLOR_KEYS = THEME_COLOR_KEYS; exports.defaultTheme = defaultTheme; exports.FONT_SCALE_MIN = FONT_SCALE_MIN; exports.FONT_SCALE_MAX = FONT_SCALE_MAX; exports.ThemeProvider = ThemeProvider; exports.familyNameFromFile = familyNameFromFile; exports.toFontStack = toFontStack; exports.FONT_ACCEPT = FONT_ACCEPT; exports.registerFontFace = registerFontFace; exports.registerFontFile = registerFontFile; exports.subscribeToFontLoads = subscribeToFontLoads; exports.isFontAvailable = isFontAvailable; exports.isFontStackAvailable = isFontStackAvailable;
524
- //# sourceMappingURL=chunk-RJVHR45I.cjs.map
524
+ //# sourceMappingURL=chunk-H46ZLPNJ.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-RJVHR45I.cjs","../src/components/ThemeProvider/ThemeProvider.component.tsx","../src/components/ThemeProvider/ThemeProvider.context.tsx","../src/components/ThemeProvider/ThemeProvider.color.ts","../src/components/ThemeProvider/ThemeProvider.tokens.ts","../src/components/ThemeProvider/ThemeProvider.fonts.ts"],"names":["value"],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-RJVHR45I.cjs","sourcesContent":[null,"import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { devWarn } from '../../utils';\nimport { ThemeContext } from './ThemeProvider.context';\nimport { buildTokens, diffFromDefault, resolveTheme, themeToCss } from './ThemeProvider.tokens';\nimport type { ThemeConfig, ThemeContextValue, ThemeProviderProps } from './ThemeProvider.types';\n\nconst EMPTY_THEME: ThemeConfig = {};\n\n/**\n * Number of providers currently mounted.\n *\n * Because tokens are written to `document.documentElement` (see the component\n * comment for why), providers do not compose: two of them target the same\n * element, so whichever applied a given token last wins for the entire page -\n * including for the subtree of the other one. That looks like a broken theme\n * rather than a misuse, so it is worth saying out loud.\n */\nlet mountedProviders = 0;\n\n/** Merges `patch` over `base` one level into `colors`/`typography`. */\nconst mergeTheme = (base: ThemeConfig, patch: ThemeConfig): ThemeConfig => ({\n colors: { ...base.colors, ...patch.colors },\n typography: { ...base.typography, ...patch.typography },\n});\n\n/**\n * Applies a theme by writing CSS custom properties to `document.documentElement`.\n *\n * Two deliberate choices worth knowing:\n *\n * **The target is `documentElement`, not a wrapper element.** Every overlay in\n * this library (`Dropdown`, `Modal`, `Drawer`, `Snackbar`, `Tooltip`, …) portals\n * to `document.body`, so tokens scoped to a wrapper `<div>` would leave every\n * popup rendering the preset instead.\n *\n * **Properties are set through the CSSOM** (`style.setProperty`), which no CSP\n * directive gates - `style-src` and `style-src-attr` only cover the `style`\n * HTML attribute and stylesheet loads. Nothing here needs a nonce, and no\n * `<style>` element is ever created. See `ContentSecurityPolicy.mdx`.\n *\n * Under SSR the server sends the preset from `dist/index.css` and the theme is\n * applied on hydration; use `toCss()` if you need a themed first paint.\n */\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({\n children,\n theme: controlledTheme,\n defaultTheme: initialTheme,\n onThemeChange,\n}) => {\n const isControlled = controlledTheme !== undefined;\n const [uncontrolledTheme, setUncontrolledTheme] = useState<ThemeConfig>(\n initialTheme ?? EMPTY_THEME,\n );\n const theme = isControlled ? controlledTheme : uncontrolledTheme;\n\n useEffect(() => {\n mountedProviders += 1;\n if (mountedProviders > 1) {\n devWarn(\n 'theme-multiple-providers',\n `ThemeProvider: ${mountedProviders} providers are mounted at once. They all write to document.documentElement, so the last one to apply each token wins for the whole page - nested or sibling providers cannot theme separate subtrees. Use a single provider at your app root.`,\n );\n }\n return () => {\n mountedProviders -= 1;\n };\n }, []);\n\n const resolvedTheme = useMemo(() => resolveTheme(theme), [theme]);\n const tokens = useMemo(() => diffFromDefault(buildTokens(resolvedTheme)), [resolvedTheme]);\n\n // Names written on the previous pass, so properties dropped from the theme\n // are removed rather than left behind at their last value.\n const appliedRef = useRef<string[]>([]);\n\n useLayoutEffect(() => {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n\n for (const name of appliedRef.current) {\n if (!(name in tokens)) root.style.removeProperty(name);\n }\n for (const [name, value] of Object.entries(tokens)) {\n root.style.setProperty(name, value);\n }\n appliedRef.current = Object.keys(tokens);\n\n return () => {\n for (const name of appliedRef.current) {\n root.style.removeProperty(name);\n }\n appliedRef.current = [];\n };\n }, [tokens]);\n\n const commit = useCallback(\n (next: ThemeConfig) => {\n if (!isControlled) setUncontrolledTheme(next);\n onThemeChange?.(next);\n },\n [isControlled, onThemeChange],\n );\n\n const setTheme = useCallback((next: ThemeConfig) => commit(next), [commit]);\n\n const updateTheme = useCallback(\n (patch: ThemeConfig) => commit(mergeTheme(theme, patch)),\n [commit, theme],\n );\n\n const resetTheme = useCallback(() => commit(EMPTY_THEME), [commit]);\n\n const toCss = useCallback(() => themeToCss(resolvedTheme), [resolvedTheme]);\n\n const value = useMemo<ThemeContextValue>(\n () => ({\n theme,\n resolvedTheme,\n setTheme,\n updateTheme,\n resetTheme,\n isDefault: Object.keys(tokens).length === 0,\n toCss,\n }),\n [theme, resolvedTheme, setTheme, updateTheme, resetTheme, tokens, toCss],\n );\n\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n};\n\nThemeProvider.displayName = 'ThemeProvider';\n","import { createContext, useContext } from 'react';\nimport type { ThemeContextValue } from './ThemeProvider.types';\n\nexport const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\n/**\n * Reads the active theme. Throws outside a `ThemeProvider`, matching\n * `useSnackbarContext` - a silent fallback would make a missing provider look\n * like a theme that simply is not applying.\n */\nexport const useTheme = (): ThemeContextValue => {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n};\n","/**\n * Colour maths for the theme system.\n *\n * All conversions are done in JS and emitted as `#rrggbb`, so browser support\n * for `oklch()` is irrelevant here - nothing in the generated CSS uses a modern\n * colour function.\n *\n * OKLab is used rather than HSL for every interpolation. HSL lightness\n * interpolation is ~40 lines shorter but produces muddy, desaturated ramps for\n * exactly the saturated brand hues this feature exists to support, because its\n * \"lightness\" is not perceptual.\n */\n\n// ============================================================================\n// sRGB <-> OKLab\n// ============================================================================\n\nexport interface Oklch {\n /** Perceptual lightness, 0-1. */\n l: number;\n /** Chroma (colourfulness), 0 to ~0.4 in sRGB. */\n c: number;\n /** Hue angle in radians. */\n h: number;\n}\n\nconst srgbToLinear = (v: number): number =>\n v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n\nconst linearToSrgb = (v: number): number =>\n v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;\n\nconst clamp01 = (v: number): number => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/** Parses `#rgb` / `#rrggbb` into 0-1 sRGB channels. Returns null if unparseable. */\nexport const parseHex = (hex: string): [number, number, number] | null => {\n if (typeof hex !== 'string') return null;\n const raw = hex.trim().replace(/^#/, '');\n const full =\n raw.length === 3\n ? raw\n .split('')\n .map((c) => c + c)\n .join('')\n : raw;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n const n = parseInt(full, 16);\n return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255];\n};\n\nexport const isValidHex = (hex: string): boolean => parseHex(hex) !== null;\n\nconst toHex = ([r, g, b]: [number, number, number]): string =>\n '#' +\n [r, g, b]\n .map((v) =>\n Math.round(clamp01(v) * 255)\n .toString(16)\n .padStart(2, '0'),\n )\n .join('');\n\n/** `#rrggbb` -> the comma-separated triple the `--x-rgb` tokens use. */\nexport const hexToRgbTriple = (hex: string): string => {\n const rgb = parseHex(hex);\n if (!rgb) return '0, 0, 0';\n return rgb.map((v) => Math.round(v * 255)).join(', ');\n};\n\nconst linearToOklab = ([r, g, b]: [number, number, number]): [number, number, number] => {\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n return [\n 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n ];\n};\n\nconst oklabToLinear = ([L, A, B]: [number, number, number]): [number, number, number] => {\n const l = (L + 0.3963377774 * A + 0.2158037573 * B) ** 3;\n const m = (L - 0.1055613458 * A - 0.0638541728 * B) ** 3;\n const s = (L - 0.0894841775 * A - 1.291485548 * B) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n};\n\nexport const hexToOklch = (hex: string): Oklch => {\n const rgb = parseHex(hex) ?? [0, 0, 0];\n const [l, a, b] = linearToOklab(rgb.map(srgbToLinear) as [number, number, number]);\n return { l, c: Math.hypot(a, b), h: Math.atan2(b, a) };\n};\n\nconst inGamut = ([r, g, b]: [number, number, number]): boolean =>\n [r, g, b].every((v) => v >= -1e-4 && v <= 1 + 1e-4);\n\n/**\n * Largest chroma that still fits in sRGB at this lightness and hue.\n *\n * Needed because OKLab is a much larger space than sRGB: naively keeping a\n * colour's chroma while changing its lightness frequently lands outside the\n * gamut, where channels clip and the hue visibly shifts.\n */\nconst maxChroma = (l: number, h: number): number => {\n let lo = 0;\n let hi = 0.45;\n for (let i = 0; i < 24; i++) {\n const mid = (lo + hi) / 2;\n if (inGamut(oklabToLinear([l, mid * Math.cos(h), mid * Math.sin(h)]))) lo = mid;\n else hi = mid;\n }\n return lo;\n};\n\nexport const oklchToHex = ({ l, c, h }: Oklch): string => {\n const lc = clamp01(l);\n const cc = Math.min(Math.max(c, 0), maxChroma(lc, h));\n return toHex(\n oklabToLinear([lc, cc * Math.cos(h), cc * Math.sin(h)]).map(linearToSrgb) as [\n number,\n number,\n number,\n ],\n );\n};\n\n// ============================================================================\n// WCAG 2.1 contrast\n// ============================================================================\n\n/**\n * WCAG 2.1 is used rather than APCA. APCA models perception better but is\n * still a draft (targeted at WCAG 3), while WCAG 2 is what consumers are\n * actually audited against. Its known weakness - mis-ranking some mid-tone\n * blues and greens - is accepted for that reason.\n */\nexport const relativeLuminance = (hex: string): number => {\n const [r, g, b] = (parseHex(hex) ?? [0, 0, 0]).map(srgbToLinear);\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n};\n\n/** Contrast ratio between two colours, 1 (identical) to 21 (black on white). */\nexport const contrastRatio = (a: string, b: string): number => {\n const [x, y] = [relativeLuminance(a), relativeLuminance(b)];\n return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);\n};\n\n/** The two foreground candidates, matching `--white` and `--gray-900`. */\nexport const CONTRAST_LIGHT = '#ffffff';\nexport const CONTRAST_DARK = '#0f172a';\n\n/**\n * Foreground to place on `fill`.\n *\n * White wins unless it drops below 3:1, at which point the better of the two\n * candidates is used. The threshold is deliberately 3:1 rather than \"whichever\n * scores higher\": on mid-tone reds the dark candidate often scores marginally\n * better while looking plainly wrong, and every preset base clears 4.5:1\n * against white anyway.\n */\nexport const pickContrast = (fill: string): string => {\n const onLight = contrastRatio(fill, CONTRAST_LIGHT);\n if (onLight >= 3) return CONTRAST_LIGHT;\n return onLight >= contrastRatio(fill, CONTRAST_DARK) ? CONTRAST_LIGHT : CONTRAST_DARK;\n};\n\n// ============================================================================\n// Ramp generation\n// ============================================================================\n\n/** The ramp steps, in the order `--x-50` … `--x-900` are declared. */\nexport const RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900] as const;\n\nexport type RampStep = (typeof RAMP_STEPS)[number];\n\n/** The step the supplied base colour occupies; the ramp is built around it. */\nconst BASE_STEP = 500;\n\n/**\n * Target lightness per step, and how much of the base's chroma to keep.\n *\n * Measured from the preset indigo ramp, so feeding the preset primary through\n * `buildRamp` lands close to the shipped `--primary-*` values rather than\n * something arbitrary. It is deliberately not an exact reproduction - see the\n * note on `buildRamp`.\n */\nconst RAMP_CURVE: Record<RampStep, { l: number; chroma: number }> = {\n 50: { l: 0.962, chroma: 0.09 },\n 100: { l: 0.93, chroma: 0.16 },\n 200: { l: 0.87, chroma: 0.3 },\n 300: { l: 0.785, chroma: 0.51 },\n 400: { l: 0.68, chroma: 0.77 },\n 500: { l: 0.558, chroma: 1.0 },\n 600: { l: 0.511, chroma: 1.12 },\n 700: { l: 0.457, chroma: 1.05 },\n 800: { l: 0.398, chroma: 0.87 },\n 900: { l: 0.359, chroma: 0.66 },\n};\n\n/** Ceiling/floor the generated ends aim for, leaving the base itself untouched. */\nconst LIGHT_CEILING = 0.985;\nconst DARK_FLOOR = 0.22;\n\n/** Minimum lightness gap between adjacent steps, so none can collapse together. */\nconst MIN_STEP_DELTA = 0.012;\n\n/**\n * Generates a 50-900 ramp around `base`, which is placed at the 500 step.\n *\n * The base's own hue is always preserved, and `--x-500` is returned as the base\n * hex verbatim, so the colour a consumer picked is never silently replaced.\n *\n * The curve above is *rescaled* to whatever lightness headroom the base leaves,\n * rather than being applied absolutely or simply shifted:\n *\n * - Applying it absolutely would reassign the base - pick a pale yellow and\n * `--x-500` would come back a mid-olive, contradicting `--x-color`.\n * - Shifting it so 500 sits at the base's lightness pushes the light end past\n * `l = 1`, where it clips and 50/100/200/300 all come out pure white.\n *\n * The ends are **absolute**, not relative to the base: step 50 lands near-white\n * and step 900 near-dark whatever lightness the base has, with the remaining\n * steps interpolated between the base and those anchors. Only a base that is\n * already past an anchor compresses that side into what headroom is left.\n *\n * Getting this wrong is subtle. An earlier version offset every step *from the\n * base* by the curve's own distances, capped so the preset reproduced exactly.\n * That looks right - and reproduces the preset ramp perfectly - but it makes the\n * tints relative: a dark navy base (`#1a1a2e`) returned `--primary-50: #8a8a8c`,\n * a mid grey rather than a tint, because 50 sits only 0.404 lightness above 500\n * on the curve. Every consumer of the tint end broke visibly - `Navigation`'s\n * active item paints `--primary-50` and turned into a charcoal pill.\n *\n * Two inputs are genuinely degenerate and are handled rather than solved: a\n * base at or above `LIGHT_CEILING` has no room for tints, and one with zero\n * chroma (pure white, black, any gray) has no saturation to separate them with\n * either. For those the light end converges, and `isRampViable` reports it so\n * the caller can warn. Realistic light picks are fine - `#fde047` still yields\n * five distinct tints.\n */\nexport const buildRamp = (base: string): Record<RampStep, string> => {\n const { l: baseL, c: baseC, h } = hexToOklch(base);\n const anchor = RAMP_CURVE[BASE_STEP].l;\n\n // Where the ends of the scale sit, independent of the base. A base already\n // lighter than the curve's own 50 (or darker than its 900) has nowhere left\n // to go, so that side compresses into the remaining headroom instead.\n const curveLight = RAMP_CURVE[50].l;\n const curveDark = RAMP_CURVE[900].l;\n const lightTarget = baseL >= curveLight ? Math.min(LIGHT_CEILING, baseL + 0.02) : curveLight;\n const darkTarget = baseL <= curveDark ? Math.max(DARK_FLOOR * 0.2, baseL - 0.02) : curveDark;\n\n const lightSpan = curveLight - anchor;\n const darkSpan = anchor - curveDark;\n\n const out = {} as Record<RampStep, string>;\n for (const step of RAMP_STEPS) {\n if (step === BASE_STEP) {\n out[step] = base;\n continue;\n }\n const { l: curveL, chroma } = RAMP_CURVE[step];\n const offset = curveL - anchor;\n // How far along its half of the curve this step sits: 0 at the base, 1 at\n // the end. Interpolating that fraction between the base and the target\n // keeps the curve's shape while pinning where it ends up.\n const t = offset > 0 ? offset / lightSpan : -offset / darkSpan;\n const l = offset > 0 ? baseL + t * (lightTarget - baseL) : baseL - t * (baseL - darkTarget);\n out[step] = oklchToHex({ l, c: baseC * chroma, h });\n }\n\n return enforceSeparation(out, h, baseC);\n};\n\n/**\n * Walks outward from the base step, pushing any step that ended up too close to\n * its neighbour further away. Only bites for extreme inputs (near-white,\n * near-black, zero-chroma), where the rescale above has almost no room left.\n */\nconst enforceSeparation = (\n ramp: Record<RampStep, string>,\n h: number,\n baseC: number,\n): Record<RampStep, string> => {\n const baseIndex = RAMP_STEPS.indexOf(BASE_STEP);\n const lightness = RAMP_STEPS.map((s) => hexToOklch(ramp[s]).l);\n\n // Lighter steps: walk from the base toward 50, each must be lighter.\n for (let i = baseIndex - 1; i >= 0; i--) {\n const limit = lightness[i + 1] + MIN_STEP_DELTA;\n if (lightness[i] < limit) lightness[i] = Math.min(1, limit);\n }\n // Darker steps: walk from the base toward 900, each must be darker.\n for (let i = baseIndex + 1; i < RAMP_STEPS.length; i++) {\n const limit = lightness[i - 1] - MIN_STEP_DELTA;\n if (lightness[i] > limit) lightness[i] = Math.max(0, limit);\n }\n\n const out = {} as Record<RampStep, string>;\n RAMP_STEPS.forEach((step, i) => {\n if (step === BASE_STEP) {\n out[step] = ramp[step];\n return;\n }\n out[step] = oklchToHex({\n l: lightness[i],\n c: baseC * RAMP_CURVE[step].chroma,\n h,\n });\n });\n return out;\n};\n\n/** How far `--x-dark` / `--x-light` sit from the base, in OKLab lightness. */\nconst DARK_DELTA = 0.086;\nconst LIGHT_DELTA = 0.169;\n\n/** Below this lightness there is no room left to darken, so the hover lightens. */\nconst HOVER_INVERT_BELOW = DARK_DELTA * 1.5;\n\n/**\n * The hover/active colour. Must differ *visibly* from the base and stay legible\n * as text on white, since `--x-dark` is used both as a fill (Button, Chip\n * hovers) and as text (Snackbar, link hover in `global.scss`).\n *\n * A fixed ramp step is not good enough: for a near-white base the 600 step\n * lands barely darker than the base and the hover reads as no change at all.\n * Hence a guaranteed delta.\n *\n * For a base that is already near-black the delta is applied *upwards* instead.\n * Clamping to a floor would return a colour lighter than the base while still\n * being named \"dark\", and returning the base unchanged would leave the control\n * with no hover affordance at all; lightening is what dark-surface design\n * systems do anyway.\n */\nexport const deriveDark = (base: string): string => {\n const { l, c, h } = hexToOklch(base);\n const target = l < HOVER_INVERT_BELOW ? l + DARK_DELTA : l - DARK_DELTA;\n return oklchToHex({ l: target, c, h });\n};\n\n/**\n * The light companion. Lightening has a hard ceiling, so for an already-pale\n * base this lands very close to it - acceptable, as `--x-light` is a public\n * token that nothing inside the library currently consumes.\n */\nexport const deriveLight = (base: string): string => {\n const { l, c, h } = hexToOklch(base);\n return oklchToHex({ l: Math.min(LIGHT_CEILING, l + LIGHT_DELTA), c, h });\n};\n\n/**\n * Whether `base` leaves enough lightness headroom to generate a usable 50-900\n * ramp. False only for near-white and near-black, where the tint or shade end\n * necessarily converges - the caller surfaces that as a developer warning\n * rather than silently shipping identical tokens.\n *\n * Deliberately does not test chroma: an unsaturated gray separates perfectly\n * well by lightness alone, and a saturated light colour like `#fde047` still\n * produces five distinct tints. Only the extremes genuinely fail.\n */\nexport const isRampViable = (base: string): boolean => {\n const { l } = hexToOklch(base);\n return l < 0.95 && l > 0.12;\n};\n","import { devWarn } from '../../utils';\nimport {\n RAMP_STEPS,\n buildRamp,\n deriveDark,\n deriveLight,\n hexToRgbTriple,\n isValidHex,\n isRampViable,\n pickContrast,\n} from './ThemeProvider.color';\nimport type {\n ResolvedTheme,\n ThemeColorKey,\n ThemeColorValue,\n ThemeConfig,\n} from './ThemeProvider.types';\n\nexport const THEME_COLOR_KEYS: readonly ThemeColorKey[] = [\n 'primary',\n 'secondary',\n 'success',\n 'danger',\n 'warning',\n 'info',\n 'hyperlink',\n] as const;\n\n/**\n * `hyperlink` is link text on a surface, never a fill, so it has no\n * `--hyperlink-contrast` token - nothing in the library would read it.\n */\nconst FILL_COLOR_KEYS: readonly ThemeColorKey[] = [\n 'primary',\n 'secondary',\n 'success',\n 'danger',\n 'warning',\n 'info',\n] as const;\n\n/** Only `primary` has a 50-900 ramp in `variables.scss`. */\nconst RAMP_COLOR_KEY: ThemeColorKey = 'primary';\n\n/** The eight preset `--font-size-*` values, in declaration order. */\nconst FONT_SIZE_STEPS: readonly [string, number][] = [\n ['xs', 0.75],\n ['sm', 0.875],\n ['base', 1],\n ['md', 1.1],\n ['lg', 1.125],\n ['xl', 1.25],\n ['2xl', 1.5],\n ['3xl', 1.875],\n] as const;\n\n/**\n * The shipped values from `src/styles/variables.scss`.\n *\n * This is a literal copy, not something derived: the ramp is hand-tuned and no\n * generator reproduces it byte for byte. Keeping it literal means a theme equal\n * to the preset writes no CSS properties at all, so default rendering is\n * identical to `dist/index.css`.\n *\n * Must be kept in sync with `variables.scss` by hand. The bases are all chosen\n * to clear WCAG AA against white text; see the comment at the top of that file.\n */\nexport const defaultTheme: Required<ThemeConfig> = {\n colors: {\n primary: '#5c5de8',\n secondary: '#617087',\n success: '#007f57',\n danger: '#d6272f',\n warning: '#9c6300',\n info: '#007a90',\n hyperlink: '#007b84',\n },\n typography: {\n fontFamily:\n \"'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif\",\n monoFamily:\n \"'JetBrains Mono', 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', monospace\",\n fontScale: 1,\n },\n};\n\n/** The preset `--primary-*` ramp, needed so an unthemed primary emits nothing. */\nconst DEFAULT_PRIMARY_RAMP: Record<number, string> = {\n 50: '#eef2ff',\n 100: '#e0e7ff',\n 200: '#c7d2fe',\n 300: '#a5b4fc',\n 400: '#818cf8',\n 500: '#5c5de8',\n 600: '#4f46e5',\n 700: '#4338ca',\n 800: '#3730a3',\n 900: '#312e81',\n};\n\nexport const FONT_SCALE_MIN = 0.875;\nexport const FONT_SCALE_MAX = 1.25;\n\nconst normalizeColor = (value: ThemeColorValue): { base: string; contrast?: string } =>\n typeof value === 'string' ? { base: value } : value;\n\n/** Fills every absent field from the preset. */\nexport const resolveTheme = (theme: ThemeConfig): ResolvedTheme => {\n const colors = {} as ResolvedTheme['colors'];\n\n for (const key of THEME_COLOR_KEYS) {\n const supplied = theme.colors?.[key];\n const fallback = normalizeColor(defaultTheme.colors[key]!);\n if (supplied === undefined) {\n colors[key] = fallback;\n continue;\n }\n const { base, contrast } = normalizeColor(supplied);\n if (!isValidHex(base)) {\n devWarn(\n `theme-color-${key}`,\n `ThemeProvider: colors.${key} is not a valid hex colour (received ${JSON.stringify(base)}). Falling back to the preset.`,\n );\n colors[key] = fallback;\n continue;\n }\n if (contrast !== undefined && !isValidHex(contrast)) {\n devWarn(\n `theme-contrast-${key}`,\n `ThemeProvider: colors.${key}.contrast is not a valid hex colour (received ${JSON.stringify(contrast)}). It will be computed instead.`,\n );\n colors[key] = { base };\n continue;\n }\n colors[key] = contrast === undefined ? { base } : { base, contrast };\n }\n\n const scale = theme.typography?.fontScale;\n let fontScale = defaultTheme.typography.fontScale!;\n if (scale !== undefined) {\n if (!Number.isFinite(scale) || scale < FONT_SCALE_MIN || scale > FONT_SCALE_MAX) {\n devWarn(\n 'theme-font-scale',\n `ThemeProvider: typography.fontScale must be between ${FONT_SCALE_MIN} and ${FONT_SCALE_MAX} (received ${String(scale)}). Falling back to ${fontScale}.`,\n );\n } else {\n fontScale = scale;\n }\n }\n\n return {\n colors,\n typography: {\n fontFamily: theme.typography?.fontFamily || defaultTheme.typography.fontFamily!,\n monoFamily: theme.typography?.monoFamily || defaultTheme.typography.monoFamily!,\n fontScale,\n },\n };\n};\n\n/**\n * Expands a resolved theme into the flat `--token: value` map to apply.\n *\n * Every family contributes `--x-color`, `--x-rgb`, `--x-dark` and `--x-light`;\n * the six fill families also get `--x-contrast`, and `primary` additionally\n * gets the full `--primary-50…900` ramp.\n */\nexport const buildTokens = (resolved: ResolvedTheme): Record<string, string> => {\n const tokens: Record<string, string> = {};\n\n for (const key of THEME_COLOR_KEYS) {\n const { base, contrast } = resolved.colors[key];\n tokens[`--${key}-color`] = base;\n tokens[`--${key}-rgb`] = hexToRgbTriple(base);\n tokens[`--${key}-dark`] = deriveDark(base);\n tokens[`--${key}-light`] = deriveLight(base);\n\n if (FILL_COLOR_KEYS.includes(key)) {\n tokens[`--${key}-contrast`] = contrast ?? pickContrast(base);\n }\n\n if (key === RAMP_COLOR_KEY) {\n const isPreset = base === normalizeColor(defaultTheme.colors[key]!).base;\n // The preset ramp is hand-tuned, so reuse it verbatim rather than\n // regenerating a near-identical one.\n const ramp = isPreset ? DEFAULT_PRIMARY_RAMP : buildRamp(base);\n if (!isPreset && !isRampViable(base)) {\n devWarn(\n `theme-ramp-${key}`,\n `ThemeProvider: colors.${key} (${base}) is too light or too dark to generate a usable --${key}-50…900 scale; several steps will be identical. Pick a colour with more headroom.`,\n );\n }\n for (const step of RAMP_STEPS) {\n tokens[`--${key}-${step}`] = ramp[step];\n }\n }\n }\n\n const { fontFamily, monoFamily, fontScale } = resolved.typography;\n tokens['--font-family-primary'] = fontFamily;\n tokens['--font-family-mono'] = monoFamily;\n for (const [name, rem] of FONT_SIZE_STEPS) {\n // Trailing zeros trimmed so 1 * 0.75 reads as `0.75rem`, not `0.750rem`.\n tokens[`--font-size-${name}`] = `${parseFloat((rem * fontScale).toFixed(4))}rem`;\n }\n\n return tokens;\n};\n\n/** Tokens for the preset, used to tell which of them are actually overrides. */\nconst DEFAULT_TOKENS = buildTokens(resolveTheme(defaultTheme));\n\n/**\n * Only the tokens that differ from the preset.\n *\n * This is what makes an unthemed `ThemeProvider` a no-op: it writes nothing, so\n * `dist/index.css` stays authoritative and there is no inline-style churn on\n * `documentElement` for values that already match.\n */\nexport const diffFromDefault = (tokens: Record<string, string>): Record<string, string> => {\n const diff: Record<string, string> = {};\n for (const [name, value] of Object.entries(tokens)) {\n if (DEFAULT_TOKENS[name] !== value) diff[name] = value;\n }\n return diff;\n};\n\n/**\n * The resolved theme as a `:root { … }` block.\n *\n * Paste the output into your own stylesheet to bake a theme in at build time -\n * that avoids the brief flash of the preset that any runtime theme has when the\n * value arrives after first paint, and needs no JavaScript at all.\n */\nexport const themeToCss = (resolved: ResolvedTheme): string => {\n const tokens = buildTokens(resolved);\n const body = Object.entries(tokens)\n .map(([name, value]) => ` ${name}: ${value};`)\n .join('\\n');\n return `:root {\\n${body}\\n}`;\n};\n","/**\n * Runtime font registration for the theme system.\n *\n * `--font-family-primary` only *names* families - it cannot make a font\n * available. Selecting \"Plus Jakarta Sans\" on a machine that doesn't have it\n * installed silently falls through to the next stack entry, which is why a\n * theme needs a way to supply the font data itself.\n *\n * ## Why this is CSP-safe\n *\n * Fonts are registered with the CSS Font Loading API from an `ArrayBuffer`:\n *\n * ```ts\n * document.fonts.add(new FontFace(family, buffer));\n * ```\n *\n * CSP's `font-src` directive governs *fetching* a font resource by URL - it is\n * what gates `@font-face { src: url(...) }` and the string form of the\n * `FontFace` constructor. The binary form performs no fetch at all, so there is\n * no request for `font-src` to check and no allowance to configure. Notably\n * this also avoids `blob:` URLs, which *would* require `font-src blob:`.\n *\n * No `<style>` element is created either, so nothing here needs a nonce - the\n * same position as the rest of the theme system.\n */\n\n/** A font registered at runtime, as listed by the editor. */\nexport interface RegisteredFont {\n /** The family name to reference in a font stack. */\n family: string;\n /** Where it came from, so the UI can distinguish uploads from built-ins. */\n source: 'upload';\n}\n\n/**\n * Turns a filename into a usable CSS family name.\n *\n * Deliberately conservative: the real family name lives in the font's internal\n * `name` table, and parsing SFNT tables to read it would be a disproportionate\n * amount of binary handling for a label. The filename is what the user\n * recognises anyway.\n */\nexport const familyNameFromFile = (filename: string): string => {\n const base = filename.replace(/\\.[^.]+$/, '');\n const cleaned = base\n // Strip the weight/style suffixes font vendors append.\n .replace(/[-_](regular|normal|book|roman)$/i, '')\n .replace(/[-_]+/g, ' ')\n // A quoted family name may contain spaces but not quotes or control chars.\n .replace(/[\"'\\\\]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n return cleaned || 'Custom Font';\n};\n\n/** Wraps a family name for use in a CSS font stack if it needs quoting. */\nexport const quoteFamily = (family: string): string =>\n /^[a-zA-Z][a-zA-Z0-9-]*$/.test(family) ? family : `'${family}'`;\n\n/**\n * Builds a full stack from a custom family, keeping sensible fallbacks so the\n * page stays readable if the font is ever unavailable.\n */\nexport const toFontStack = (family: string, mono = false): string =>\n mono\n ? `${quoteFamily(family)}, 'SF Mono', Monaco, monospace`\n : `${quoteFamily(family)}, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif`;\n\n/** Font formats accepted for upload, as an `accept` attribute value. */\nexport const FONT_ACCEPT = '.woff2,.woff,.ttf,.otf';\n\nconst SUPPORTED_EXTENSIONS = /\\.(woff2|woff|ttf|otf)$/i;\n\nexport const isSupportedFontFile = (filename: string): boolean =>\n SUPPORTED_EXTENSIONS.test(filename);\n\n/**\n * Registers font data with the document so a theme can reference its family.\n *\n * Resolves with the family name actually registered. Rejects if the data is not\n * a font the browser can parse, or if the Font Loading API is unavailable\n * (notably during SSR, where there is no `document` to register against).\n */\nexport const registerFontFace = async (family: string, data: ArrayBuffer): Promise<string> => {\n if (typeof document === 'undefined' || !document.fonts) {\n throw new Error('registerFontFace requires a document with the CSS Font Loading API.');\n }\n\n // ArrayBuffer source - no URL is fetched, so CSP's font-src never applies.\n const face = new FontFace(family, data);\n await face.load();\n document.fonts.add(face);\n // No cache invalidation needed: only positive results are cached, and this\n // family could not have been cached positive while it was still unavailable.\n // `document.fonts.add` also fires `loadingdone`, which wakes subscribers.\n return family;\n};\n\n/** Reads a File and registers it, returning the family name it was given. */\nexport const registerFontFile = async (file: File, family?: string): Promise<string> => {\n if (!isSupportedFontFile(file.name)) {\n throw new Error(`Unsupported font format: ${file.name}. Use ${FONT_ACCEPT}.`);\n }\n const buffer = await file.arrayBuffer();\n return registerFontFace(family ?? familyNameFromFile(file.name), buffer);\n};\n\n/**\n * CSS generic families, which always resolve and must never be reported\n * missing. They also cannot be probed by the method below, since asking for\n * `monospace, monospace` measures identically to `monospace` alone.\n */\nconst GENERIC_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'math',\n 'emoji',\n 'fangsong',\n 'inherit',\n 'initial',\n 'unset',\n]);\n\n/**\n * Mixed-width glyphs, so a real font is very unlikely to measure identically\n * to a fallback by coincidence.\n */\nconst PROBE_TEXT = 'mmmmmmmmmmlliI0OWw@';\n\n/** Two structurally different fallbacks - a font need only differ from one. */\nconst PROBE_FALLBACKS = ['monospace', 'serif'] as const;\n\n/**\n * Cached per family - **positive results only**.\n *\n * A negative answer is not stable: web fonts load asynchronously (always, with\n * `font-display: swap`), so a family probed during the first render is\n * legitimately unavailable and becomes available moments later. Caching that\n * `false` pinned the answer forever, which showed a permanent \"not installed\"\n * warning for fonts that had in fact loaded.\n *\n * A positive answer cannot go stale the same way - a loaded font is not\n * unloaded - so those are worth keeping. Re-probing the misses costs one canvas\n * measurement each.\n */\nconst availabilityCache = new Map<string, true>();\n\n/**\n * Notifies when the set of usable fonts changes, so a caller rendering an\n * availability state can re-check.\n *\n * Both signals are needed: `loadingdone` covers fonts that begin loading after\n * subscription, while `ready` covers those already in flight when the listener\n * was attached - which is the common case for a stylesheet's `@font-face`\n * rules, since they start loading before any component mounts.\n */\nexport const subscribeToFontLoads = (onChange: () => void): (() => void) => {\n if (typeof document === 'undefined' || !document.fonts) return () => {};\n\n let active = true;\n const handler = () => {\n if (active) onChange();\n };\n\n document.fonts.addEventListener('loadingdone', handler);\n void document.fonts.ready.then(handler);\n\n return () => {\n active = false;\n document.fonts.removeEventListener('loadingdone', handler);\n };\n};\n\n/**\n * Whether a font family will actually render, rather than silently falling\n * through to the next entry in the stack.\n *\n * **`document.fonts.check` cannot answer this.** Per spec it reports whether\n * the faces *in the FontFaceSet* matching the query are loaded, so with no\n * matching face it returns `true` vacuously. Verified in a real browser: it\n * answers `true` for `'Totally Not A Real Font 12345'`, and therefore for every\n * uninstalled system font too. Using it here produced a check that could never\n * fail.\n *\n * Instead the family is measured on a canvas against two fallbacks. If it\n * resolves to anything real, the text measures differently from at least one\n * fallback alone; if it does not resolve, the browser renders that fallback and\n * the widths match exactly.\n */\nexport const isFontAvailable = (family: string): boolean => {\n const name = family.trim().replace(/^['\"]|['\"]$/g, '');\n if (!name) return true;\n if (GENERIC_FAMILIES.has(name.toLowerCase())) return true;\n if (typeof document === 'undefined') return true;\n\n if (availabilityCache.get(name)) return true;\n\n try {\n const context = document.createElement('canvas').getContext('2d');\n if (!context) return true;\n\n const available = PROBE_FALLBACKS.some((fallback) => {\n context.font = `100px ${fallback}`;\n const baseline = context.measureText(PROBE_TEXT).width;\n context.font = `100px ${quoteFamily(name)}, ${fallback}`;\n // An invalid font shorthand leaves `font` untouched, which measures as\n // the baseline and correctly reports the family as unavailable.\n return Math.abs(context.measureText(PROBE_TEXT).width - baseline) > 0.5;\n });\n\n if (available) availabilityCache.set(name, true);\n return available;\n } catch {\n // Never report a font missing because probing itself failed - and don't\n // cache a failure, so a later call can still get a real answer.\n return true;\n }\n};\n\n/** Whether the first family in a stack will render. */\nexport const isFontStackAvailable = (stack: string): boolean =>\n isFontAvailable(stack.split(',')[0] ?? '');\n"]}
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-H46ZLPNJ.cjs","../src/components/ThemeProvider/ThemeProvider.component.tsx","../src/components/ThemeProvider/ThemeProvider.context.tsx","../src/components/ThemeProvider/ThemeProvider.color.ts","../src/components/ThemeProvider/ThemeProvider.tokens.ts","../src/components/ThemeProvider/ThemeProvider.fonts.ts"],"names":["value"],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-H46ZLPNJ.cjs","sourcesContent":[null,"import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\nimport { devWarn } from '../../utils';\nimport { ThemeContext } from './ThemeProvider.context';\nimport { buildTokens, diffFromDefault, resolveTheme, themeToCss } from './ThemeProvider.tokens';\nimport type { ThemeConfig, ThemeContextValue, ThemeProviderProps } from './ThemeProvider.types';\n\nconst EMPTY_THEME: ThemeConfig = {};\n\n/**\n * Number of providers currently mounted.\n *\n * Because tokens are written to `document.documentElement` (see the component\n * comment for why), providers do not compose: two of them target the same\n * element, so whichever applied a given token last wins for the entire page -\n * including for the subtree of the other one. That looks like a broken theme\n * rather than a misuse, so it is worth saying out loud.\n */\nlet mountedProviders = 0;\n\n/** Merges `patch` over `base` one level into `colors`/`typography`. */\nconst mergeTheme = (base: ThemeConfig, patch: ThemeConfig): ThemeConfig => ({\n colors: { ...base.colors, ...patch.colors },\n typography: { ...base.typography, ...patch.typography },\n});\n\n/**\n * Applies a theme by writing CSS custom properties to `document.documentElement`.\n *\n * Two deliberate choices worth knowing:\n *\n * **The target is `documentElement`, not a wrapper element.** Every overlay in\n * this library (`Dropdown`, `Modal`, `Drawer`, `Snackbar`, `Tooltip`, …) portals\n * to `document.body`, so tokens scoped to a wrapper `<div>` would leave every\n * popup rendering the preset instead.\n *\n * **Properties are set through the CSSOM** (`style.setProperty`), which no CSP\n * directive gates - `style-src` and `style-src-attr` only cover the `style`\n * HTML attribute and stylesheet loads. Nothing here needs a nonce, and no\n * `<style>` element is ever created. See `ContentSecurityPolicy.mdx`.\n *\n * Under SSR the server sends the preset from `dist/index.css` and the theme is\n * applied on hydration; use `toCss()` if you need a themed first paint.\n */\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({\n children,\n theme: controlledTheme,\n defaultTheme: initialTheme,\n onThemeChange,\n}) => {\n const isControlled = controlledTheme !== undefined;\n const [uncontrolledTheme, setUncontrolledTheme] = useState<ThemeConfig>(\n initialTheme ?? EMPTY_THEME,\n );\n const theme = isControlled ? controlledTheme : uncontrolledTheme;\n\n useEffect(() => {\n mountedProviders += 1;\n if (mountedProviders > 1) {\n devWarn(\n 'theme-multiple-providers',\n `ThemeProvider: ${mountedProviders} providers are mounted at once. They all write to document.documentElement, so the last one to apply each token wins for the whole page - nested or sibling providers cannot theme separate subtrees. Use a single provider at your app root.`,\n );\n }\n return () => {\n mountedProviders -= 1;\n };\n }, []);\n\n const resolvedTheme = useMemo(() => resolveTheme(theme), [theme]);\n const tokens = useMemo(() => diffFromDefault(buildTokens(resolvedTheme)), [resolvedTheme]);\n\n // Names written on the previous pass, so properties dropped from the theme\n // are removed rather than left behind at their last value.\n const appliedRef = useRef<string[]>([]);\n\n useLayoutEffect(() => {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n\n for (const name of appliedRef.current) {\n if (!(name in tokens)) root.style.removeProperty(name);\n }\n for (const [name, value] of Object.entries(tokens)) {\n root.style.setProperty(name, value);\n }\n appliedRef.current = Object.keys(tokens);\n\n return () => {\n for (const name of appliedRef.current) {\n root.style.removeProperty(name);\n }\n appliedRef.current = [];\n };\n }, [tokens]);\n\n const commit = useCallback(\n (next: ThemeConfig) => {\n if (!isControlled) setUncontrolledTheme(next);\n onThemeChange?.(next);\n },\n [isControlled, onThemeChange],\n );\n\n const setTheme = useCallback((next: ThemeConfig) => commit(next), [commit]);\n\n const updateTheme = useCallback(\n (patch: ThemeConfig) => commit(mergeTheme(theme, patch)),\n [commit, theme],\n );\n\n const resetTheme = useCallback(() => commit(EMPTY_THEME), [commit]);\n\n const toCss = useCallback(() => themeToCss(resolvedTheme), [resolvedTheme]);\n\n const value = useMemo<ThemeContextValue>(\n () => ({\n theme,\n resolvedTheme,\n setTheme,\n updateTheme,\n resetTheme,\n isDefault: Object.keys(tokens).length === 0,\n toCss,\n }),\n [theme, resolvedTheme, setTheme, updateTheme, resetTheme, tokens, toCss],\n );\n\n return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;\n};\n\nThemeProvider.displayName = 'ThemeProvider';\n","import { createContext, useContext } from 'react';\nimport type { ThemeContextValue } from './ThemeProvider.types';\n\nexport const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);\n\n/**\n * Reads the active theme. Throws outside a `ThemeProvider`, matching\n * `useSnackbarContext` - a silent fallback would make a missing provider look\n * like a theme that simply is not applying.\n */\nexport const useTheme = (): ThemeContextValue => {\n const context = useContext(ThemeContext);\n if (!context) {\n throw new Error('useTheme must be used within a ThemeProvider');\n }\n return context;\n};\n","/**\n * Colour maths for the theme system.\n *\n * All conversions are done in JS and emitted as `#rrggbb`, so browser support\n * for `oklch()` is irrelevant here - nothing in the generated CSS uses a modern\n * colour function.\n *\n * OKLab is used rather than HSL for every interpolation. HSL lightness\n * interpolation is ~40 lines shorter but produces muddy, desaturated ramps for\n * exactly the saturated brand hues this feature exists to support, because its\n * \"lightness\" is not perceptual.\n */\n\n// ============================================================================\n// sRGB <-> OKLab\n// ============================================================================\n\nexport interface Oklch {\n /** Perceptual lightness, 0-1. */\n l: number;\n /** Chroma (colourfulness), 0 to ~0.4 in sRGB. */\n c: number;\n /** Hue angle in radians. */\n h: number;\n}\n\nconst srgbToLinear = (v: number): number =>\n v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n\nconst linearToSrgb = (v: number): number =>\n v <= 0.0031308 ? 12.92 * v : 1.055 * Math.pow(v, 1 / 2.4) - 0.055;\n\nconst clamp01 = (v: number): number => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/** Parses `#rgb` / `#rrggbb` into 0-1 sRGB channels. Returns null if unparseable. */\nexport const parseHex = (hex: string): [number, number, number] | null => {\n if (typeof hex !== 'string') return null;\n const raw = hex.trim().replace(/^#/, '');\n const full =\n raw.length === 3\n ? raw\n .split('')\n .map((c) => c + c)\n .join('')\n : raw;\n if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;\n const n = parseInt(full, 16);\n return [((n >> 16) & 255) / 255, ((n >> 8) & 255) / 255, (n & 255) / 255];\n};\n\nexport const isValidHex = (hex: string): boolean => parseHex(hex) !== null;\n\nconst toHex = ([r, g, b]: [number, number, number]): string =>\n '#' +\n [r, g, b]\n .map((v) =>\n Math.round(clamp01(v) * 255)\n .toString(16)\n .padStart(2, '0'),\n )\n .join('');\n\n/** `#rrggbb` -> the comma-separated triple the `--x-rgb` tokens use. */\nexport const hexToRgbTriple = (hex: string): string => {\n const rgb = parseHex(hex);\n if (!rgb) return '0, 0, 0';\n return rgb.map((v) => Math.round(v * 255)).join(', ');\n};\n\nconst linearToOklab = ([r, g, b]: [number, number, number]): [number, number, number] => {\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);\n return [\n 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,\n 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,\n 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,\n ];\n};\n\nconst oklabToLinear = ([L, A, B]: [number, number, number]): [number, number, number] => {\n const l = (L + 0.3963377774 * A + 0.2158037573 * B) ** 3;\n const m = (L - 0.1055613458 * A - 0.0638541728 * B) ** 3;\n const s = (L - 0.0894841775 * A - 1.291485548 * B) ** 3;\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ];\n};\n\nexport const hexToOklch = (hex: string): Oklch => {\n const rgb = parseHex(hex) ?? [0, 0, 0];\n const [l, a, b] = linearToOklab(rgb.map(srgbToLinear) as [number, number, number]);\n return { l, c: Math.hypot(a, b), h: Math.atan2(b, a) };\n};\n\nconst inGamut = ([r, g, b]: [number, number, number]): boolean =>\n [r, g, b].every((v) => v >= -1e-4 && v <= 1 + 1e-4);\n\n/**\n * Largest chroma that still fits in sRGB at this lightness and hue.\n *\n * Needed because OKLab is a much larger space than sRGB: naively keeping a\n * colour's chroma while changing its lightness frequently lands outside the\n * gamut, where channels clip and the hue visibly shifts.\n */\nconst maxChroma = (l: number, h: number): number => {\n let lo = 0;\n let hi = 0.45;\n for (let i = 0; i < 24; i++) {\n const mid = (lo + hi) / 2;\n if (inGamut(oklabToLinear([l, mid * Math.cos(h), mid * Math.sin(h)]))) lo = mid;\n else hi = mid;\n }\n return lo;\n};\n\nexport const oklchToHex = ({ l, c, h }: Oklch): string => {\n const lc = clamp01(l);\n const cc = Math.min(Math.max(c, 0), maxChroma(lc, h));\n return toHex(\n oklabToLinear([lc, cc * Math.cos(h), cc * Math.sin(h)]).map(linearToSrgb) as [\n number,\n number,\n number,\n ],\n );\n};\n\n// ============================================================================\n// WCAG 2.1 contrast\n// ============================================================================\n\n/**\n * WCAG 2.1 is used rather than APCA. APCA models perception better but is\n * still a draft (targeted at WCAG 3), while WCAG 2 is what consumers are\n * actually audited against. Its known weakness - mis-ranking some mid-tone\n * blues and greens - is accepted for that reason.\n */\nexport const relativeLuminance = (hex: string): number => {\n const [r, g, b] = (parseHex(hex) ?? [0, 0, 0]).map(srgbToLinear);\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n};\n\n/** Contrast ratio between two colours, 1 (identical) to 21 (black on white). */\nexport const contrastRatio = (a: string, b: string): number => {\n const [x, y] = [relativeLuminance(a), relativeLuminance(b)];\n return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05);\n};\n\n/** The two foreground candidates, matching `--white` and `--gray-900`. */\nexport const CONTRAST_LIGHT = '#ffffff';\nexport const CONTRAST_DARK = '#0f172a';\n\n/**\n * Foreground to place on `fill`.\n *\n * White wins unless it drops below 3:1, at which point the better of the two\n * candidates is used. The threshold is deliberately 3:1 rather than \"whichever\n * scores higher\": on mid-tone reds the dark candidate often scores marginally\n * better while looking plainly wrong, and every preset base clears 4.5:1\n * against white anyway.\n */\nexport const pickContrast = (fill: string): string => {\n const onLight = contrastRatio(fill, CONTRAST_LIGHT);\n if (onLight >= 3) return CONTRAST_LIGHT;\n return onLight >= contrastRatio(fill, CONTRAST_DARK) ? CONTRAST_LIGHT : CONTRAST_DARK;\n};\n\n// ============================================================================\n// Ramp generation\n// ============================================================================\n\n/** The ramp steps, in the order `--x-50` … `--x-900` are declared. */\nexport const RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900] as const;\n\nexport type RampStep = (typeof RAMP_STEPS)[number];\n\n/** The step the supplied base colour occupies; the ramp is built around it. */\nconst BASE_STEP = 500;\n\n/**\n * Target lightness per step, and how much of the base's chroma to keep.\n *\n * Measured from the preset indigo ramp, so feeding the preset primary through\n * `buildRamp` lands close to the shipped `--primary-*` values rather than\n * something arbitrary. It is deliberately not an exact reproduction - see the\n * note on `buildRamp`.\n */\nconst RAMP_CURVE: Record<RampStep, { l: number; chroma: number }> = {\n 50: { l: 0.962, chroma: 0.09 },\n 100: { l: 0.93, chroma: 0.16 },\n 200: { l: 0.87, chroma: 0.3 },\n 300: { l: 0.785, chroma: 0.51 },\n 400: { l: 0.68, chroma: 0.77 },\n 500: { l: 0.558, chroma: 1.0 },\n 600: { l: 0.511, chroma: 1.12 },\n 700: { l: 0.457, chroma: 1.05 },\n 800: { l: 0.398, chroma: 0.87 },\n 900: { l: 0.359, chroma: 0.66 },\n};\n\n/** Ceiling/floor the generated ends aim for, leaving the base itself untouched. */\nconst LIGHT_CEILING = 0.985;\nconst DARK_FLOOR = 0.22;\n\n/** Minimum lightness gap between adjacent steps, so none can collapse together. */\nconst MIN_STEP_DELTA = 0.012;\n\n/**\n * Generates a 50-900 ramp around `base`, which is placed at the 500 step.\n *\n * The base's own hue is always preserved, and `--x-500` is returned as the base\n * hex verbatim, so the colour a consumer picked is never silently replaced.\n *\n * The curve above is *rescaled* to whatever lightness headroom the base leaves,\n * rather than being applied absolutely or simply shifted:\n *\n * - Applying it absolutely would reassign the base - pick a pale yellow and\n * `--x-500` would come back a mid-olive, contradicting `--x-color`.\n * - Shifting it so 500 sits at the base's lightness pushes the light end past\n * `l = 1`, where it clips and 50/100/200/300 all come out pure white.\n *\n * The ends are **absolute**, not relative to the base: step 50 lands near-white\n * and step 900 near-dark whatever lightness the base has, with the remaining\n * steps interpolated between the base and those anchors. Only a base that is\n * already past an anchor compresses that side into what headroom is left.\n *\n * Getting this wrong is subtle. An earlier version offset every step *from the\n * base* by the curve's own distances, capped so the preset reproduced exactly.\n * That looks right - and reproduces the preset ramp perfectly - but it makes the\n * tints relative: a dark navy base (`#1a1a2e`) returned `--primary-50: #8a8a8c`,\n * a mid grey rather than a tint, because 50 sits only 0.404 lightness above 500\n * on the curve. Every consumer of the tint end broke visibly - `Navigation`'s\n * active item paints `--primary-50` and turned into a charcoal pill.\n *\n * Two inputs are genuinely degenerate and are handled rather than solved: a\n * base at or above `LIGHT_CEILING` has no room for tints, and one with zero\n * chroma (pure white, black, any gray) has no saturation to separate them with\n * either. For those the light end converges, and `isRampViable` reports it so\n * the caller can warn. Realistic light picks are fine - `#fde047` still yields\n * five distinct tints.\n */\nexport const buildRamp = (base: string): Record<RampStep, string> => {\n const { l: baseL, c: baseC, h } = hexToOklch(base);\n const anchor = RAMP_CURVE[BASE_STEP].l;\n\n // Where the ends of the scale sit, independent of the base. A base already\n // lighter than the curve's own 50 (or darker than its 900) has nowhere left\n // to go, so that side compresses into the remaining headroom instead.\n const curveLight = RAMP_CURVE[50].l;\n const curveDark = RAMP_CURVE[900].l;\n const lightTarget = baseL >= curveLight ? Math.min(LIGHT_CEILING, baseL + 0.02) : curveLight;\n const darkTarget = baseL <= curveDark ? Math.max(DARK_FLOOR * 0.2, baseL - 0.02) : curveDark;\n\n const lightSpan = curveLight - anchor;\n const darkSpan = anchor - curveDark;\n\n const out = {} as Record<RampStep, string>;\n for (const step of RAMP_STEPS) {\n if (step === BASE_STEP) {\n out[step] = base;\n continue;\n }\n const { l: curveL, chroma } = RAMP_CURVE[step];\n const offset = curveL - anchor;\n // How far along its half of the curve this step sits: 0 at the base, 1 at\n // the end. Interpolating that fraction between the base and the target\n // keeps the curve's shape while pinning where it ends up.\n const t = offset > 0 ? offset / lightSpan : -offset / darkSpan;\n const l = offset > 0 ? baseL + t * (lightTarget - baseL) : baseL - t * (baseL - darkTarget);\n out[step] = oklchToHex({ l, c: baseC * chroma, h });\n }\n\n return enforceSeparation(out, h, baseC);\n};\n\n/**\n * Walks outward from the base step, pushing any step that ended up too close to\n * its neighbour further away. Only bites for extreme inputs (near-white,\n * near-black, zero-chroma), where the rescale above has almost no room left.\n */\nconst enforceSeparation = (\n ramp: Record<RampStep, string>,\n h: number,\n baseC: number,\n): Record<RampStep, string> => {\n const baseIndex = RAMP_STEPS.indexOf(BASE_STEP);\n const lightness = RAMP_STEPS.map((s) => hexToOklch(ramp[s]).l);\n\n // Lighter steps: walk from the base toward 50, each must be lighter.\n for (let i = baseIndex - 1; i >= 0; i--) {\n const limit = lightness[i + 1] + MIN_STEP_DELTA;\n if (lightness[i] < limit) lightness[i] = Math.min(1, limit);\n }\n // Darker steps: walk from the base toward 900, each must be darker.\n for (let i = baseIndex + 1; i < RAMP_STEPS.length; i++) {\n const limit = lightness[i - 1] - MIN_STEP_DELTA;\n if (lightness[i] > limit) lightness[i] = Math.max(0, limit);\n }\n\n const out = {} as Record<RampStep, string>;\n RAMP_STEPS.forEach((step, i) => {\n if (step === BASE_STEP) {\n out[step] = ramp[step];\n return;\n }\n out[step] = oklchToHex({\n l: lightness[i],\n c: baseC * RAMP_CURVE[step].chroma,\n h,\n });\n });\n return out;\n};\n\n/** How far `--x-dark` / `--x-light` sit from the base, in OKLab lightness. */\nconst DARK_DELTA = 0.086;\nconst LIGHT_DELTA = 0.169;\n\n/** Below this lightness there is no room left to darken, so the hover lightens. */\nconst HOVER_INVERT_BELOW = DARK_DELTA * 1.5;\n\n/**\n * The hover/active colour. Must differ *visibly* from the base and stay legible\n * as text on white, since `--x-dark` is used both as a fill (Button, Chip\n * hovers) and as text (Snackbar, link hover in `global.scss`).\n *\n * A fixed ramp step is not good enough: for a near-white base the 600 step\n * lands barely darker than the base and the hover reads as no change at all.\n * Hence a guaranteed delta.\n *\n * For a base that is already near-black the delta is applied *upwards* instead.\n * Clamping to a floor would return a colour lighter than the base while still\n * being named \"dark\", and returning the base unchanged would leave the control\n * with no hover affordance at all; lightening is what dark-surface design\n * systems do anyway.\n */\nexport const deriveDark = (base: string): string => {\n const { l, c, h } = hexToOklch(base);\n const target = l < HOVER_INVERT_BELOW ? l + DARK_DELTA : l - DARK_DELTA;\n return oklchToHex({ l: target, c, h });\n};\n\n/**\n * The light companion. Lightening has a hard ceiling, so for an already-pale\n * base this lands very close to it - acceptable, as `--x-light` is a public\n * token that nothing inside the library currently consumes.\n */\nexport const deriveLight = (base: string): string => {\n const { l, c, h } = hexToOklch(base);\n return oklchToHex({ l: Math.min(LIGHT_CEILING, l + LIGHT_DELTA), c, h });\n};\n\n/**\n * Whether `base` leaves enough lightness headroom to generate a usable 50-900\n * ramp. False only for near-white and near-black, where the tint or shade end\n * necessarily converges - the caller surfaces that as a developer warning\n * rather than silently shipping identical tokens.\n *\n * Deliberately does not test chroma: an unsaturated gray separates perfectly\n * well by lightness alone, and a saturated light colour like `#fde047` still\n * produces five distinct tints. Only the extremes genuinely fail.\n */\nexport const isRampViable = (base: string): boolean => {\n const { l } = hexToOklch(base);\n return l < 0.95 && l > 0.12;\n};\n","import { devWarn } from '../../utils';\nimport {\n RAMP_STEPS,\n buildRamp,\n deriveDark,\n deriveLight,\n hexToRgbTriple,\n isValidHex,\n isRampViable,\n pickContrast,\n} from './ThemeProvider.color';\nimport type {\n ResolvedTheme,\n ThemeColorKey,\n ThemeColorValue,\n ThemeConfig,\n} from './ThemeProvider.types';\n\nexport const THEME_COLOR_KEYS: readonly ThemeColorKey[] = [\n 'primary',\n 'secondary',\n 'success',\n 'danger',\n 'warning',\n 'info',\n 'hyperlink',\n] as const;\n\n/**\n * `hyperlink` is link text on a surface, never a fill, so it has no\n * `--hyperlink-contrast` token - nothing in the library would read it.\n */\nconst FILL_COLOR_KEYS: readonly ThemeColorKey[] = [\n 'primary',\n 'secondary',\n 'success',\n 'danger',\n 'warning',\n 'info',\n] as const;\n\n/** Only `primary` has a 50-900 ramp in `variables.scss`. */\nconst RAMP_COLOR_KEY: ThemeColorKey = 'primary';\n\n/** The eight preset `--font-size-*` values, in declaration order. */\nconst FONT_SIZE_STEPS: readonly [string, number][] = [\n ['xs', 0.75],\n ['sm', 0.875],\n ['base', 1],\n ['md', 1.1],\n ['lg', 1.125],\n ['xl', 1.25],\n ['2xl', 1.5],\n ['3xl', 1.875],\n] as const;\n\n/**\n * The shipped values from `src/styles/variables.scss`.\n *\n * This is a literal copy, not something derived: the ramp is hand-tuned and no\n * generator reproduces it byte for byte. Keeping it literal means a theme equal\n * to the preset writes no CSS properties at all, so default rendering is\n * identical to `dist/index.css`.\n *\n * Must be kept in sync with `variables.scss` by hand. The bases are all chosen\n * to clear WCAG AA against white text; see the comment at the top of that file.\n */\nexport const defaultTheme: Required<ThemeConfig> = {\n colors: {\n primary: '#5c5de8',\n secondary: '#617087',\n success: '#007f57',\n danger: '#d6272f',\n warning: '#9c6300',\n info: '#007a90',\n hyperlink: '#007b84',\n },\n typography: {\n fontFamily:\n \"'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif\",\n monoFamily:\n \"'JetBrains Mono', 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', 'Source Code Pro', monospace\",\n fontScale: 1,\n },\n};\n\n/** The preset `--primary-*` ramp, needed so an unthemed primary emits nothing. */\nconst DEFAULT_PRIMARY_RAMP: Record<number, string> = {\n 50: '#eef2ff',\n 100: '#e0e7ff',\n 200: '#c7d2fe',\n 300: '#a5b4fc',\n 400: '#818cf8',\n 500: '#5c5de8',\n 600: '#4f46e5',\n 700: '#4338ca',\n 800: '#3730a3',\n 900: '#312e81',\n};\n\nexport const FONT_SCALE_MIN = 0.875;\nexport const FONT_SCALE_MAX = 1.25;\n\nconst normalizeColor = (value: ThemeColorValue): { base: string; contrast?: string } =>\n typeof value === 'string' ? { base: value } : value;\n\n/** Fills every absent field from the preset. */\nexport const resolveTheme = (theme: ThemeConfig): ResolvedTheme => {\n const colors = {} as ResolvedTheme['colors'];\n\n for (const key of THEME_COLOR_KEYS) {\n const supplied = theme.colors?.[key];\n const fallback = normalizeColor(defaultTheme.colors[key]!);\n if (supplied === undefined) {\n colors[key] = fallback;\n continue;\n }\n const { base, contrast } = normalizeColor(supplied);\n if (!isValidHex(base)) {\n devWarn(\n `theme-color-${key}`,\n `ThemeProvider: colors.${key} is not a valid hex colour (received ${JSON.stringify(base)}). Falling back to the preset.`,\n );\n colors[key] = fallback;\n continue;\n }\n if (contrast !== undefined && !isValidHex(contrast)) {\n devWarn(\n `theme-contrast-${key}`,\n `ThemeProvider: colors.${key}.contrast is not a valid hex colour (received ${JSON.stringify(contrast)}). It will be computed instead.`,\n );\n colors[key] = { base };\n continue;\n }\n colors[key] = contrast === undefined ? { base } : { base, contrast };\n }\n\n const scale = theme.typography?.fontScale;\n let fontScale = defaultTheme.typography.fontScale!;\n if (scale !== undefined) {\n if (!Number.isFinite(scale) || scale < FONT_SCALE_MIN || scale > FONT_SCALE_MAX) {\n devWarn(\n 'theme-font-scale',\n `ThemeProvider: typography.fontScale must be between ${FONT_SCALE_MIN} and ${FONT_SCALE_MAX} (received ${String(scale)}). Falling back to ${fontScale}.`,\n );\n } else {\n fontScale = scale;\n }\n }\n\n return {\n colors,\n typography: {\n fontFamily: theme.typography?.fontFamily || defaultTheme.typography.fontFamily!,\n monoFamily: theme.typography?.monoFamily || defaultTheme.typography.monoFamily!,\n fontScale,\n },\n };\n};\n\n/**\n * Expands a resolved theme into the flat `--token: value` map to apply.\n *\n * Every family contributes `--x-color`, `--x-rgb`, `--x-dark` and `--x-light`;\n * the six fill families also get `--x-contrast`, and `primary` additionally\n * gets the full `--primary-50…900` ramp.\n */\nexport const buildTokens = (resolved: ResolvedTheme): Record<string, string> => {\n const tokens: Record<string, string> = {};\n\n for (const key of THEME_COLOR_KEYS) {\n const { base, contrast } = resolved.colors[key];\n tokens[`--${key}-color`] = base;\n tokens[`--${key}-rgb`] = hexToRgbTriple(base);\n tokens[`--${key}-dark`] = deriveDark(base);\n tokens[`--${key}-light`] = deriveLight(base);\n\n if (FILL_COLOR_KEYS.includes(key)) {\n tokens[`--${key}-contrast`] = contrast ?? pickContrast(base);\n }\n\n if (key === RAMP_COLOR_KEY) {\n const isPreset = base === normalizeColor(defaultTheme.colors[key]!).base;\n // The preset ramp is hand-tuned, so reuse it verbatim rather than\n // regenerating a near-identical one.\n const ramp = isPreset ? DEFAULT_PRIMARY_RAMP : buildRamp(base);\n if (!isPreset && !isRampViable(base)) {\n devWarn(\n `theme-ramp-${key}`,\n `ThemeProvider: colors.${key} (${base}) is too light or too dark to generate a usable --${key}-50…900 scale; several steps will be identical. Pick a colour with more headroom.`,\n );\n }\n for (const step of RAMP_STEPS) {\n tokens[`--${key}-${step}`] = ramp[step];\n }\n }\n }\n\n const { fontFamily, monoFamily, fontScale } = resolved.typography;\n tokens['--font-family-primary'] = fontFamily;\n tokens['--font-family-mono'] = monoFamily;\n for (const [name, rem] of FONT_SIZE_STEPS) {\n // Trailing zeros trimmed so 1 * 0.75 reads as `0.75rem`, not `0.750rem`.\n tokens[`--font-size-${name}`] = `${parseFloat((rem * fontScale).toFixed(4))}rem`;\n }\n\n return tokens;\n};\n\n/** Tokens for the preset, used to tell which of them are actually overrides. */\nconst DEFAULT_TOKENS = buildTokens(resolveTheme(defaultTheme));\n\n/**\n * Only the tokens that differ from the preset.\n *\n * This is what makes an unthemed `ThemeProvider` a no-op: it writes nothing, so\n * `dist/index.css` stays authoritative and there is no inline-style churn on\n * `documentElement` for values that already match.\n */\nexport const diffFromDefault = (tokens: Record<string, string>): Record<string, string> => {\n const diff: Record<string, string> = {};\n for (const [name, value] of Object.entries(tokens)) {\n if (DEFAULT_TOKENS[name] !== value) diff[name] = value;\n }\n return diff;\n};\n\n/**\n * The resolved theme as a `:root { … }` block.\n *\n * Paste the output into your own stylesheet to bake a theme in at build time -\n * that avoids the brief flash of the preset that any runtime theme has when the\n * value arrives after first paint, and needs no JavaScript at all.\n */\nexport const themeToCss = (resolved: ResolvedTheme): string => {\n const tokens = buildTokens(resolved);\n const body = Object.entries(tokens)\n .map(([name, value]) => ` ${name}: ${value};`)\n .join('\\n');\n return `:root {\\n${body}\\n}`;\n};\n","/**\n * Runtime font registration for the theme system.\n *\n * `--font-family-primary` only *names* families - it cannot make a font\n * available. Selecting \"Plus Jakarta Sans\" on a machine that doesn't have it\n * installed silently falls through to the next stack entry, which is why a\n * theme needs a way to supply the font data itself.\n *\n * ## Why this is CSP-safe\n *\n * Fonts are registered with the CSS Font Loading API from an `ArrayBuffer`:\n *\n * ```ts\n * document.fonts.add(new FontFace(family, buffer));\n * ```\n *\n * CSP's `font-src` directive governs *fetching* a font resource by URL - it is\n * what gates `@font-face { src: url(...) }` and the string form of the\n * `FontFace` constructor. The binary form performs no fetch at all, so there is\n * no request for `font-src` to check and no allowance to configure. Notably\n * this also avoids `blob:` URLs, which *would* require `font-src blob:`.\n *\n * No `<style>` element is created either, so nothing here needs a nonce - the\n * same position as the rest of the theme system.\n */\n\n/** A font registered at runtime, as listed by the editor. */\nexport interface RegisteredFont {\n /** The family name to reference in a font stack. */\n family: string;\n /** Where it came from, so the UI can distinguish uploads from built-ins. */\n source: 'upload';\n}\n\n/**\n * Turns a filename into a usable CSS family name.\n *\n * Deliberately conservative: the real family name lives in the font's internal\n * `name` table, and parsing SFNT tables to read it would be a disproportionate\n * amount of binary handling for a label. The filename is what the user\n * recognises anyway.\n */\nexport const familyNameFromFile = (filename: string): string => {\n const base = filename.replace(/\\.[^.]+$/, '');\n const cleaned = base\n // Strip the weight/style suffixes font vendors append.\n .replace(/[-_](regular|normal|book|roman)$/i, '')\n .replace(/[-_]+/g, ' ')\n // A quoted family name may contain spaces but not quotes or control chars.\n .replace(/[\"'\\\\]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n return cleaned || 'Custom Font';\n};\n\n/** Wraps a family name for use in a CSS font stack if it needs quoting. */\nexport const quoteFamily = (family: string): string =>\n /^[a-zA-Z][a-zA-Z0-9-]*$/.test(family) ? family : `'${family}'`;\n\n/**\n * Builds a full stack from a custom family, keeping sensible fallbacks so the\n * page stays readable if the font is ever unavailable.\n */\nexport const toFontStack = (family: string, mono = false): string =>\n mono\n ? `${quoteFamily(family)}, 'SF Mono', Monaco, monospace`\n : `${quoteFamily(family)}, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif`;\n\n/** Font formats accepted for upload, as an `accept` attribute value. */\nexport const FONT_ACCEPT = '.woff2,.woff,.ttf,.otf';\n\nconst SUPPORTED_EXTENSIONS = /\\.(woff2|woff|ttf|otf)$/i;\n\nexport const isSupportedFontFile = (filename: string): boolean =>\n SUPPORTED_EXTENSIONS.test(filename);\n\n/**\n * Registers font data with the document so a theme can reference its family.\n *\n * Resolves with the family name actually registered. Rejects if the data is not\n * a font the browser can parse, or if the Font Loading API is unavailable\n * (notably during SSR, where there is no `document` to register against).\n */\nexport const registerFontFace = async (family: string, data: ArrayBuffer): Promise<string> => {\n if (typeof document === 'undefined' || !document.fonts) {\n throw new Error('registerFontFace requires a document with the CSS Font Loading API.');\n }\n\n // ArrayBuffer source - no URL is fetched, so CSP's font-src never applies.\n const face = new FontFace(family, data);\n await face.load();\n document.fonts.add(face);\n // No cache invalidation needed: only positive results are cached, and this\n // family could not have been cached positive while it was still unavailable.\n // `document.fonts.add` also fires `loadingdone`, which wakes subscribers.\n return family;\n};\n\n/** Reads a File and registers it, returning the family name it was given. */\nexport const registerFontFile = async (file: File, family?: string): Promise<string> => {\n if (!isSupportedFontFile(file.name)) {\n throw new Error(`Unsupported font format: ${file.name}. Use ${FONT_ACCEPT}.`);\n }\n const buffer = await file.arrayBuffer();\n return registerFontFace(family ?? familyNameFromFile(file.name), buffer);\n};\n\n/**\n * CSS generic families, which always resolve and must never be reported\n * missing. They also cannot be probed by the method below, since asking for\n * `monospace, monospace` measures identically to `monospace` alone.\n */\nconst GENERIC_FAMILIES = new Set([\n 'serif',\n 'sans-serif',\n 'monospace',\n 'cursive',\n 'fantasy',\n 'system-ui',\n 'ui-serif',\n 'ui-sans-serif',\n 'ui-monospace',\n 'ui-rounded',\n 'math',\n 'emoji',\n 'fangsong',\n 'inherit',\n 'initial',\n 'unset',\n]);\n\n/**\n * Mixed-width glyphs, so a real font is very unlikely to measure identically\n * to a fallback by coincidence.\n */\nconst PROBE_TEXT = 'mmmmmmmmmmlliI0OWw@';\n\n/** Two structurally different fallbacks - a font need only differ from one. */\nconst PROBE_FALLBACKS = ['monospace', 'serif'] as const;\n\n/**\n * Cached per family - **positive results only**.\n *\n * A negative answer is not stable: web fonts load asynchronously (always, with\n * `font-display: swap`), so a family probed during the first render is\n * legitimately unavailable and becomes available moments later. Caching that\n * `false` pinned the answer forever, which showed a permanent \"not installed\"\n * warning for fonts that had in fact loaded.\n *\n * A positive answer cannot go stale the same way - a loaded font is not\n * unloaded - so those are worth keeping. Re-probing the misses costs one canvas\n * measurement each.\n */\nconst availabilityCache = new Map<string, true>();\n\n/**\n * Notifies when the set of usable fonts changes, so a caller rendering an\n * availability state can re-check.\n *\n * Both signals are needed: `loadingdone` covers fonts that begin loading after\n * subscription, while `ready` covers those already in flight when the listener\n * was attached - which is the common case for a stylesheet's `@font-face`\n * rules, since they start loading before any component mounts.\n */\nexport const subscribeToFontLoads = (onChange: () => void): (() => void) => {\n if (typeof document === 'undefined' || !document.fonts) return () => {};\n\n let active = true;\n const handler = () => {\n if (active) onChange();\n };\n\n document.fonts.addEventListener('loadingdone', handler);\n void document.fonts.ready.then(handler);\n\n return () => {\n active = false;\n document.fonts.removeEventListener('loadingdone', handler);\n };\n};\n\n/**\n * Whether a font family will actually render, rather than silently falling\n * through to the next entry in the stack.\n *\n * **`document.fonts.check` cannot answer this.** Per spec it reports whether\n * the faces *in the FontFaceSet* matching the query are loaded, so with no\n * matching face it returns `true` vacuously. Verified in a real browser: it\n * answers `true` for `'Totally Not A Real Font 12345'`, and therefore for every\n * uninstalled system font too. Using it here produced a check that could never\n * fail.\n *\n * Instead the family is measured on a canvas against two fallbacks. If it\n * resolves to anything real, the text measures differently from at least one\n * fallback alone; if it does not resolve, the browser renders that fallback and\n * the widths match exactly.\n */\nexport const isFontAvailable = (family: string): boolean => {\n const name = family.trim().replace(/^['\"]|['\"]$/g, '');\n if (!name) return true;\n if (GENERIC_FAMILIES.has(name.toLowerCase())) return true;\n if (typeof document === 'undefined') return true;\n\n if (availabilityCache.get(name)) return true;\n\n try {\n const context = document.createElement('canvas').getContext('2d');\n if (!context) return true;\n\n const available = PROBE_FALLBACKS.some((fallback) => {\n context.font = `100px ${fallback}`;\n const baseline = context.measureText(PROBE_TEXT).width;\n context.font = `100px ${quoteFamily(name)}, ${fallback}`;\n // An invalid font shorthand leaves `font` untouched, which measures as\n // the baseline and correctly reports the family as unavailable.\n return Math.abs(context.measureText(PROBE_TEXT).width - baseline) > 0.5;\n });\n\n if (available) availabilityCache.set(name, true);\n return available;\n } catch {\n // Never report a font missing because probing itself failed - and don't\n // cache a failure, so a later call can still get a real answer.\n return true;\n }\n};\n\n/** Whether the first family in a stack will render. */\nexport const isFontStackAvailable = (stack: string): boolean =>\n isFontAvailable(stack.split(',')[0] ?? '');\n"]}