eidos-ui 3.3.0 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/README.md +17 -5
  2. package/dist/{Input.types-XrJTI0JC.d.ts → Input.types-CSDMaZNe.d.ts} +10 -0
  3. package/dist/{Input.types-DFZNyJGF.d.cts → Input.types-D7-sWq-q.d.cts} +10 -0
  4. package/dist/{Select.types-CAkT2ACt.d.cts → Select.types-2p-mpaBL.d.cts} +1 -1
  5. package/dist/{Select.types-B4kDpkGB.d.ts → Select.types-BqaD7bmB.d.ts} +1 -1
  6. package/dist/alert/index.cjs +5 -5
  7. package/dist/alert/index.js +4 -4
  8. package/dist/button/index.cjs +4 -4
  9. package/dist/button/index.js +3 -3
  10. package/dist/checkbox/index.cjs +2 -2
  11. package/dist/checkbox/index.js +1 -1
  12. package/dist/chip/index.cjs +4 -4
  13. package/dist/chip/index.js +3 -3
  14. package/dist/{chunk-RYOQYYDO.js → chunk-22EKNTWJ.js} +9 -5
  15. package/dist/chunk-22EKNTWJ.js.map +1 -0
  16. package/dist/{chunk-3E7TKBQI.cjs → chunk-27UANGPW.cjs} +14 -6
  17. package/dist/chunk-27UANGPW.cjs.map +1 -0
  18. package/dist/{chunk-CJGFRPAS.cjs → chunk-3QQKWXMV.cjs} +4 -4
  19. package/dist/chunk-3QQKWXMV.cjs.map +1 -0
  20. package/dist/{chunk-Q5KQVBQP.cjs → chunk-3S33BIN2.cjs} +18 -16
  21. package/dist/chunk-3S33BIN2.cjs.map +1 -0
  22. package/dist/{chunk-ZPDETHQ7.js → chunk-3WV6RTXX.js} +3 -3
  23. package/dist/{chunk-ZPDETHQ7.js.map → chunk-3WV6RTXX.js.map} +1 -1
  24. package/dist/chunk-44T4HMFU.js +88 -0
  25. package/dist/chunk-44T4HMFU.js.map +1 -0
  26. package/dist/{chunk-3EPND5M2.cjs → chunk-4LET2PEX.cjs} +12 -12
  27. package/dist/chunk-4LET2PEX.cjs.map +1 -0
  28. package/dist/{chunk-R4M6SNUU.cjs → chunk-5E4DYTZ3.cjs} +48 -37
  29. package/dist/chunk-5E4DYTZ3.cjs.map +1 -0
  30. package/dist/{chunk-I5XR2V4A.cjs → chunk-5V7DXZWT.cjs} +79 -76
  31. package/dist/chunk-5V7DXZWT.cjs.map +1 -0
  32. package/dist/{chunk-6CPCNQKV.js → chunk-67EXHO4T.js} +2 -2
  33. package/dist/{chunk-K7T25Y3A.cjs → chunk-6LCYO2HG.cjs} +10 -9
  34. package/dist/chunk-6LCYO2HG.cjs.map +1 -0
  35. package/dist/{chunk-ZNWIHUHZ.cjs → chunk-7KVXXHFX.cjs} +9 -3
  36. package/dist/chunk-7KVXXHFX.cjs.map +1 -0
  37. package/dist/{chunk-55J4LEKT.cjs → chunk-AHVDTWVM.cjs} +11 -8
  38. package/dist/chunk-AHVDTWVM.cjs.map +1 -0
  39. package/dist/{chunk-OAPOGYA5.cjs → chunk-AXPEJ5IG.cjs} +7 -4
  40. package/dist/chunk-AXPEJ5IG.cjs.map +1 -0
  41. package/dist/{chunk-GDQWSCJQ.js → chunk-BBU7QG7L.js} +4 -4
  42. package/dist/{chunk-T2KB3DJJ.js → chunk-BGBAZMFE.js} +9 -3
  43. package/dist/chunk-BGBAZMFE.js.map +1 -0
  44. package/dist/{chunk-EH42ND5Q.cjs → chunk-BIANFFJL.cjs} +5 -5
  45. package/dist/{chunk-EH42ND5Q.cjs.map → chunk-BIANFFJL.cjs.map} +1 -1
  46. package/dist/{chunk-O2AACVSF.js → chunk-BO4LTIJI.js} +3 -3
  47. package/dist/{chunk-G5N3C6AU.cjs → chunk-CBT3TTQR.cjs} +36 -36
  48. package/dist/{chunk-G5N3C6AU.cjs.map → chunk-CBT3TTQR.cjs.map} +1 -1
  49. package/dist/{chunk-JRLUZDKA.js → chunk-CEC3GO4R.js} +20 -7
  50. package/dist/chunk-CEC3GO4R.js.map +1 -0
  51. package/dist/{chunk-BNVQ34FD.js → chunk-CP335H4Q.js} +4 -4
  52. package/dist/{chunk-H6CWTMAH.js → chunk-DGXHR6FV.js} +5 -2
  53. package/dist/chunk-DGXHR6FV.js.map +1 -0
  54. package/dist/{chunk-OU7DCYIA.js → chunk-DMOZURHV.js} +2 -2
  55. package/dist/{chunk-L5W2XC6M.js → chunk-EWTMX4DK.js} +8 -8
  56. package/dist/{chunk-SXGCRHBZ.js → chunk-FDMYDIGI.js} +8 -6
  57. package/dist/chunk-FDMYDIGI.js.map +1 -0
  58. package/dist/{chunk-AOGNTG3W.cjs → chunk-FODRHCRP.cjs} +5 -4
  59. package/dist/chunk-FODRHCRP.cjs.map +1 -0
  60. package/dist/{chunk-E7FGY7BJ.js → chunk-FPLX5FIK.js} +4 -4
  61. package/dist/{chunk-NEYLNRVG.cjs → chunk-FXMRDNR6.cjs} +21 -16
  62. package/dist/chunk-FXMRDNR6.cjs.map +1 -0
  63. package/dist/{chunk-VXO2MYYH.cjs → chunk-G74DHVHV.cjs} +9 -9
  64. package/dist/{chunk-VXO2MYYH.cjs.map → chunk-G74DHVHV.cjs.map} +1 -1
  65. package/dist/{chunk-O3LG7B2J.cjs → chunk-GMDVW76A.cjs} +13 -5
  66. package/dist/chunk-GMDVW76A.cjs.map +1 -0
  67. package/dist/{chunk-NQ4L6PYW.js → chunk-GOF6A4M4.js} +2 -2
  68. package/dist/{chunk-NQ4L6PYW.js.map → chunk-GOF6A4M4.js.map} +1 -1
  69. package/dist/{chunk-TQGO5WK6.js → chunk-GPK2THIG.js} +7 -6
  70. package/dist/chunk-GPK2THIG.js.map +1 -0
  71. package/dist/{chunk-HYDNZXPU.js → chunk-H2RS6Z6Q.js} +41 -25
  72. package/dist/{chunk-HYDNZXPU.js.map → chunk-H2RS6Z6Q.js.map} +1 -1
  73. package/dist/{chunk-OJDYTCMO.cjs → chunk-H5D3ZFBM.cjs} +68 -61
  74. package/dist/chunk-H5D3ZFBM.cjs.map +1 -0
  75. package/dist/{chunk-MHZIBV2C.js → chunk-IXVM2XNS.js} +7 -6
  76. package/dist/chunk-IXVM2XNS.js.map +1 -0
  77. package/dist/{chunk-MCWTQT3M.cjs → chunk-JKBBHAIC.cjs} +21 -20
  78. package/dist/chunk-JKBBHAIC.cjs.map +1 -0
  79. package/dist/{chunk-QQIALSTX.cjs → chunk-KPMIIGHH.cjs} +27 -17
  80. package/dist/chunk-KPMIIGHH.cjs.map +1 -0
  81. package/dist/{chunk-QJRKXT54.cjs → chunk-KWDOOMHR.cjs} +7 -7
  82. package/dist/{chunk-QJRKXT54.cjs.map → chunk-KWDOOMHR.cjs.map} +1 -1
  83. package/dist/{chunk-HALVTKW7.js → chunk-LH5A2SIX.js} +78 -75
  84. package/dist/{chunk-HALVTKW7.js.map → chunk-LH5A2SIX.js.map} +1 -1
  85. package/dist/{chunk-27ZWUEPE.js → chunk-LIKSLFX6.js} +20 -9
  86. package/dist/chunk-LIKSLFX6.js.map +1 -0
  87. package/dist/{chunk-Z5U4NJTW.cjs → chunk-MLUHM3VG.cjs} +48 -19
  88. package/dist/chunk-MLUHM3VG.cjs.map +1 -0
  89. package/dist/{chunk-M7PF4FKQ.js → chunk-MP7LN5CW.js} +6 -3
  90. package/dist/chunk-MP7LN5CW.js.map +1 -0
  91. package/dist/{chunk-ACNTH2OQ.cjs → chunk-MW4YZVP5.cjs} +96 -97
  92. package/dist/chunk-MW4YZVP5.cjs.map +1 -0
  93. package/dist/{chunk-ZXJU3TQD.cjs → chunk-N5ZWQJTM.cjs} +11 -10
  94. package/dist/chunk-N5ZWQJTM.cjs.map +1 -0
  95. package/dist/{chunk-OGC44JFZ.cjs → chunk-N77VOYCK.cjs} +7 -7
  96. package/dist/{chunk-OGC44JFZ.cjs.map → chunk-N77VOYCK.cjs.map} +1 -1
  97. package/dist/{chunk-OAK7HFOJ.js → chunk-NACA72XI.js} +21 -16
  98. package/dist/chunk-NACA72XI.js.map +1 -0
  99. package/dist/{chunk-TEVZHN5I.cjs → chunk-NCZUQFKL.cjs} +28 -15
  100. package/dist/chunk-NCZUQFKL.cjs.map +1 -0
  101. package/dist/{chunk-NZO2I5AL.cjs → chunk-NF55JG2V.cjs} +7 -7
  102. package/dist/{chunk-NZO2I5AL.cjs.map → chunk-NF55JG2V.cjs.map} +1 -1
  103. package/dist/{chunk-ZWAFL2B3.cjs → chunk-O46UJUZM.cjs} +21 -19
  104. package/dist/chunk-O46UJUZM.cjs.map +1 -0
  105. package/dist/{chunk-25PSIDPC.js → chunk-OIXPYXR6.js} +79 -21
  106. package/dist/chunk-OIXPYXR6.js.map +1 -0
  107. package/dist/chunk-OWWPHXAF.cjs +88 -0
  108. package/dist/chunk-OWWPHXAF.cjs.map +1 -0
  109. package/dist/{chunk-65PC3YDT.cjs → chunk-OZQKWDFH.cjs} +7 -7
  110. package/dist/{chunk-65PC3YDT.cjs.map → chunk-OZQKWDFH.cjs.map} +1 -1
  111. package/dist/{chunk-P2JM22BF.cjs → chunk-P7J6WZTO.cjs} +3 -3
  112. package/dist/{chunk-P2JM22BF.cjs.map → chunk-P7J6WZTO.cjs.map} +1 -1
  113. package/dist/{chunk-KQJ3IAFT.js → chunk-PG2EII6U.js} +2 -2
  114. package/dist/{chunk-E6SE552P.cjs → chunk-RUDXHT76.cjs} +41 -25
  115. package/dist/chunk-RUDXHT76.cjs.map +1 -0
  116. package/dist/{chunk-S4S4LB63.js → chunk-SCLFJHN2.js} +11 -3
  117. package/dist/chunk-SCLFJHN2.js.map +1 -0
  118. package/dist/{chunk-WKDT2XFQ.js → chunk-SFRILDXY.js} +4 -4
  119. package/dist/{chunk-J5RMLZ4P.cjs → chunk-SKBKTNEQ.cjs} +80 -22
  120. package/dist/chunk-SKBKTNEQ.cjs.map +1 -0
  121. package/dist/{chunk-YW65NAKH.cjs → chunk-SKLMBE3Z.cjs} +7 -7
  122. package/dist/{chunk-YW65NAKH.cjs.map → chunk-SKLMBE3Z.cjs.map} +1 -1
  123. package/dist/{chunk-PY2376XI.js → chunk-SVCWSW2F.js} +8 -8
  124. package/dist/chunk-SVCWSW2F.js.map +1 -0
  125. package/dist/{chunk-2RXQMQYW.js → chunk-SXL4DMZ7.js} +27 -17
  126. package/dist/{chunk-2RXQMQYW.js.map → chunk-SXL4DMZ7.js.map} +1 -1
  127. package/dist/{chunk-7SVDYEKM.js → chunk-TLECMA3B.js} +5 -4
  128. package/dist/{chunk-7SVDYEKM.js.map → chunk-TLECMA3B.js.map} +1 -1
  129. package/dist/{chunk-FXZJL2AM.cjs → chunk-TWXZKUCG.cjs} +9 -5
  130. package/dist/chunk-TWXZKUCG.cjs.map +1 -0
  131. package/dist/{chunk-GG5YGESX.js → chunk-TYGVKSL6.js} +4 -3
  132. package/dist/chunk-TYGVKSL6.js.map +1 -0
  133. package/dist/{chunk-TTO7JXDB.cjs → chunk-TYSNOPMQ.cjs} +3 -3
  134. package/dist/{chunk-TTO7JXDB.cjs.map → chunk-TYSNOPMQ.cjs.map} +1 -1
  135. package/dist/{chunk-ZZSPQFMX.js → chunk-U233KQZX.js} +2 -1
  136. package/dist/{chunk-ZZSPQFMX.js.map → chunk-U233KQZX.js.map} +1 -1
  137. package/dist/{chunk-5HUZYY54.js → chunk-UDRAM6JU.js} +13 -5
  138. package/dist/chunk-UDRAM6JU.js.map +1 -0
  139. package/dist/{chunk-3EUTXQDB.js → chunk-UGTKZ7HP.js} +30 -23
  140. package/dist/chunk-UGTKZ7HP.js.map +1 -0
  141. package/dist/{chunk-FKXKBJUI.cjs → chunk-VHO6JPRR.cjs} +2 -1
  142. package/dist/chunk-VHO6JPRR.cjs.map +1 -0
  143. package/dist/chunk-VHSTB7GB.cjs +123 -0
  144. package/dist/chunk-VHSTB7GB.cjs.map +1 -0
  145. package/dist/{chunk-VPRUHE35.js → chunk-VRNCXYEP.js} +4 -4
  146. package/dist/{chunk-ITXDSQT2.js → chunk-WGCGSM5P.js} +96 -97
  147. package/dist/chunk-WGCGSM5P.js.map +1 -0
  148. package/dist/chunk-WT4WBHBR.js +123 -0
  149. package/dist/chunk-WT4WBHBR.js.map +1 -0
  150. package/dist/{chunk-L23WWO3D.js → chunk-X6UKU3C3.js} +2 -2
  151. package/dist/{chunk-5WH3JMR5.js → chunk-XK5USBHB.js} +7 -4
  152. package/dist/chunk-XK5USBHB.js.map +1 -0
  153. package/dist/{chunk-ND526PMG.cjs → chunk-XMXL6NVJ.cjs} +11 -11
  154. package/dist/{chunk-ND526PMG.cjs.map → chunk-XMXL6NVJ.cjs.map} +1 -1
  155. package/dist/{chunk-YV57RSPD.js → chunk-XO7WTE6O.js} +47 -18
  156. package/dist/chunk-XO7WTE6O.js.map +1 -0
  157. package/dist/{chunk-3CXULV4G.cjs → chunk-XRVRGRC3.cjs} +2 -2
  158. package/dist/{chunk-3CXULV4G.cjs.map → chunk-XRVRGRC3.cjs.map} +1 -1
  159. package/dist/{chunk-GPRJYPIG.js → chunk-Y7VSWZWM.js} +6 -4
  160. package/dist/chunk-Y7VSWZWM.js.map +1 -0
  161. package/dist/{chunk-2QEKSRVX.js → chunk-YIBPOLNN.js} +4 -4
  162. package/dist/{chunk-IJ4DXG7D.cjs → chunk-YJNQLH2L.cjs} +5 -2
  163. package/dist/chunk-YJNQLH2L.cjs.map +1 -0
  164. package/dist/{chunk-6CSUUQ5M.cjs → chunk-YUH56CJI.cjs} +6 -6
  165. package/dist/{chunk-6CSUUQ5M.cjs.map → chunk-YUH56CJI.cjs.map} +1 -1
  166. package/dist/color-picker/index.cjs +4 -4
  167. package/dist/color-picker/index.d.cts +8 -0
  168. package/dist/color-picker/index.d.ts +8 -0
  169. package/dist/color-picker/index.js +3 -3
  170. package/dist/combobox/index.cjs +6 -6
  171. package/dist/combobox/index.js +5 -5
  172. package/dist/command-palette/index.cjs +3 -2
  173. package/dist/command-palette/index.cjs.map +1 -1
  174. package/dist/command-palette/index.js +2 -1
  175. package/dist/context-menu/index.cjs +6 -6
  176. package/dist/context-menu/index.js +5 -5
  177. package/dist/conversation/index.cjs +8 -8
  178. package/dist/conversation/index.js +7 -7
  179. package/dist/data-grid/index.cjs +16 -16
  180. package/dist/data-grid/index.d.cts +2 -2
  181. package/dist/data-grid/index.d.ts +2 -2
  182. package/dist/data-grid/index.js +15 -15
  183. package/dist/date-picker/index.cjs +8 -8
  184. package/dist/date-picker/index.d.cts +1 -1
  185. package/dist/date-picker/index.d.ts +1 -1
  186. package/dist/date-picker/index.js +7 -7
  187. package/dist/drawer/index.cjs +5 -5
  188. package/dist/drawer/index.js +4 -4
  189. package/dist/dropdown/index.cjs +3 -3
  190. package/dist/dropdown/index.js +2 -2
  191. package/dist/file-upload/index.cjs +2 -2
  192. package/dist/file-upload/index.js +1 -1
  193. package/dist/header/index.cjs +6 -6
  194. package/dist/header/index.js +5 -5
  195. package/dist/index.cjs +42 -42
  196. package/dist/index.css +93 -38
  197. package/dist/index.d.cts +2 -2
  198. package/dist/index.d.ts +2 -2
  199. package/dist/index.js +41 -41
  200. package/dist/inline-edit/index.cjs +5 -5
  201. package/dist/inline-edit/index.js +4 -4
  202. package/dist/input/index.cjs +4 -4
  203. package/dist/input/index.d.cts +2 -2
  204. package/dist/input/index.d.ts +2 -2
  205. package/dist/input/index.js +3 -3
  206. package/dist/menu/index.cjs +5 -5
  207. package/dist/menu/index.js +4 -4
  208. package/dist/modal/index.cjs +5 -5
  209. package/dist/modal/index.js +4 -4
  210. package/dist/navigation/index.cjs +5 -5
  211. package/dist/navigation/index.js +4 -4
  212. package/dist/number-input/index.cjs +3 -3
  213. package/dist/number-input/index.js +2 -2
  214. package/dist/o-t-p-input/index.cjs +2 -2
  215. package/dist/o-t-p-input/index.js +1 -1
  216. package/dist/page-layout/index.cjs +12 -12
  217. package/dist/page-layout/index.js +11 -11
  218. package/dist/pagination/index.cjs +8 -8
  219. package/dist/pagination/index.js +7 -7
  220. package/dist/popover/index.cjs +3 -2
  221. package/dist/popover/index.cjs.map +1 -1
  222. package/dist/popover/index.js +2 -1
  223. package/dist/radio/index.cjs +2 -2
  224. package/dist/radio/index.js +1 -1
  225. package/dist/segmented-control/index.cjs +4 -4
  226. package/dist/segmented-control/index.js +3 -3
  227. package/dist/select/index.cjs +6 -6
  228. package/dist/select/index.d.cts +3 -3
  229. package/dist/select/index.d.ts +3 -3
  230. package/dist/select/index.js +5 -5
  231. package/dist/snackbar/index.cjs +5 -5
  232. package/dist/snackbar/index.d.cts +4 -0
  233. package/dist/snackbar/index.d.ts +4 -0
  234. package/dist/snackbar/index.js +4 -4
  235. package/dist/split-button/index.cjs +6 -6
  236. package/dist/split-button/index.js +5 -5
  237. package/dist/table/index.cjs +14 -14
  238. package/dist/table/index.js +13 -13
  239. package/dist/tabs/index.cjs +3 -3
  240. package/dist/tabs/index.js +2 -2
  241. package/dist/tag-input/index.cjs +6 -6
  242. package/dist/tag-input/index.js +5 -5
  243. package/dist/textarea/index.cjs +4 -4
  244. package/dist/textarea/index.js +3 -3
  245. package/dist/theme-editor/index.cjs +11 -11
  246. package/dist/theme-editor/index.js +10 -10
  247. package/dist/theme-provider/index.cjs +3 -3
  248. package/dist/theme-provider/index.js +2 -2
  249. package/dist/toolbar/index.cjs +8 -8
  250. package/dist/toolbar/index.js +7 -7
  251. package/dist/tooltip/index.cjs +3 -2
  252. package/dist/tooltip/index.cjs.map +1 -1
  253. package/dist/tooltip/index.js +2 -1
  254. package/dist/virtual-list/index.cjs +2 -2
  255. package/dist/virtual-list/index.js +1 -1
  256. package/package.json +7 -2
  257. package/dist/chunk-25PSIDPC.js.map +0 -1
  258. package/dist/chunk-27ZWUEPE.js.map +0 -1
  259. package/dist/chunk-3E7TKBQI.cjs.map +0 -1
  260. package/dist/chunk-3EPND5M2.cjs.map +0 -1
  261. package/dist/chunk-3EUTXQDB.js.map +0 -1
  262. package/dist/chunk-55J4LEKT.cjs.map +0 -1
  263. package/dist/chunk-5HUZYY54.js.map +0 -1
  264. package/dist/chunk-5WH3JMR5.js.map +0 -1
  265. package/dist/chunk-ACNTH2OQ.cjs.map +0 -1
  266. package/dist/chunk-AOGNTG3W.cjs.map +0 -1
  267. package/dist/chunk-CJGFRPAS.cjs.map +0 -1
  268. package/dist/chunk-CUJBNRJJ.cjs +0 -38
  269. package/dist/chunk-CUJBNRJJ.cjs.map +0 -1
  270. package/dist/chunk-E6SE552P.cjs.map +0 -1
  271. package/dist/chunk-EAJHEYZM.js +0 -38
  272. package/dist/chunk-EAJHEYZM.js.map +0 -1
  273. package/dist/chunk-FKXKBJUI.cjs.map +0 -1
  274. package/dist/chunk-FXZJL2AM.cjs.map +0 -1
  275. package/dist/chunk-GG5YGESX.js.map +0 -1
  276. package/dist/chunk-GPRJYPIG.js.map +0 -1
  277. package/dist/chunk-H6CWTMAH.js.map +0 -1
  278. package/dist/chunk-I5XR2V4A.cjs.map +0 -1
  279. package/dist/chunk-IJ4DXG7D.cjs.map +0 -1
  280. package/dist/chunk-ITXDSQT2.js.map +0 -1
  281. package/dist/chunk-J5RMLZ4P.cjs.map +0 -1
  282. package/dist/chunk-JRLUZDKA.js.map +0 -1
  283. package/dist/chunk-K7T25Y3A.cjs.map +0 -1
  284. package/dist/chunk-L5Q6UDY3.js +0 -69
  285. package/dist/chunk-L5Q6UDY3.js.map +0 -1
  286. package/dist/chunk-M7PF4FKQ.js.map +0 -1
  287. package/dist/chunk-MCWTQT3M.cjs.map +0 -1
  288. package/dist/chunk-MHZIBV2C.js.map +0 -1
  289. package/dist/chunk-NEYLNRVG.cjs.map +0 -1
  290. package/dist/chunk-O3LG7B2J.cjs.map +0 -1
  291. package/dist/chunk-OAK7HFOJ.js.map +0 -1
  292. package/dist/chunk-OAPOGYA5.cjs.map +0 -1
  293. package/dist/chunk-OJDYTCMO.cjs.map +0 -1
  294. package/dist/chunk-PY2376XI.js.map +0 -1
  295. package/dist/chunk-Q5KQVBQP.cjs.map +0 -1
  296. package/dist/chunk-QQIALSTX.cjs.map +0 -1
  297. package/dist/chunk-R4M6SNUU.cjs.map +0 -1
  298. package/dist/chunk-RYOQYYDO.js.map +0 -1
  299. package/dist/chunk-S4S4LB63.js.map +0 -1
  300. package/dist/chunk-SXGCRHBZ.js.map +0 -1
  301. package/dist/chunk-T2KB3DJJ.js.map +0 -1
  302. package/dist/chunk-TEVZHN5I.cjs.map +0 -1
  303. package/dist/chunk-TQGO5WK6.js.map +0 -1
  304. package/dist/chunk-WWYJNWJY.cjs +0 -69
  305. package/dist/chunk-WWYJNWJY.cjs.map +0 -1
  306. package/dist/chunk-YV57RSPD.js.map +0 -1
  307. package/dist/chunk-Z5U4NJTW.cjs.map +0 -1
  308. package/dist/chunk-ZNWIHUHZ.cjs.map +0 -1
  309. package/dist/chunk-ZWAFL2B3.cjs.map +0 -1
  310. package/dist/chunk-ZXJU3TQD.cjs.map +0 -1
  311. /package/dist/{chunk-6CPCNQKV.js.map → chunk-67EXHO4T.js.map} +0 -0
  312. /package/dist/{chunk-GDQWSCJQ.js.map → chunk-BBU7QG7L.js.map} +0 -0
  313. /package/dist/{chunk-O2AACVSF.js.map → chunk-BO4LTIJI.js.map} +0 -0
  314. /package/dist/{chunk-BNVQ34FD.js.map → chunk-CP335H4Q.js.map} +0 -0
  315. /package/dist/{chunk-OU7DCYIA.js.map → chunk-DMOZURHV.js.map} +0 -0
  316. /package/dist/{chunk-L5W2XC6M.js.map → chunk-EWTMX4DK.js.map} +0 -0
  317. /package/dist/{chunk-E7FGY7BJ.js.map → chunk-FPLX5FIK.js.map} +0 -0
  318. /package/dist/{chunk-KQJ3IAFT.js.map → chunk-PG2EII6U.js.map} +0 -0
  319. /package/dist/{chunk-WKDT2XFQ.js.map → chunk-SFRILDXY.js.map} +0 -0
  320. /package/dist/{chunk-VPRUHE35.js.map → chunk-VRNCXYEP.js.map} +0 -0
  321. /package/dist/{chunk-L23WWO3D.js.map → chunk-X6UKU3C3.js.map} +0 -0
  322. /package/dist/{chunk-2QEKSRVX.js.map → chunk-YIBPOLNN.js.map} +0 -0
@@ -13,35 +13,35 @@
13
13
 
14
14
 
15
15
 
16
- var _chunkNZO2I5ALcjs = require('./chunk-NZO2I5AL.cjs');
16
+ var _chunkNF55JG2Vcjs = require('./chunk-NF55JG2V.cjs');
17
17
 
18
18
 
19
19
  var _chunkOZZHOEN5cjs = require('./chunk-OZZHOEN5.cjs');
20
20
 
21
21
 
22
- var _chunkK7T25Y3Acjs = require('./chunk-K7T25Y3A.cjs');
22
+ var _chunk6LCYO2HGcjs = require('./chunk-6LCYO2HG.cjs');
23
23
 
24
24
 
25
25
  var _chunkV5RS3JZNcjs = require('./chunk-V5RS3JZN.cjs');
26
26
 
27
27
 
28
- var _chunkAOGNTG3Wcjs = require('./chunk-AOGNTG3W.cjs');
28
+ var _chunkFODRHCRPcjs = require('./chunk-FODRHCRP.cjs');
29
29
 
30
30
 
31
- var _chunkEH42ND5Qcjs = require('./chunk-EH42ND5Q.cjs');
31
+ var _chunkBIANFFJLcjs = require('./chunk-BIANFFJL.cjs');
32
32
 
33
33
 
34
34
 
35
- var _chunkWWYJNWJYcjs = require('./chunk-WWYJNWJY.cjs');
35
+ var _chunkOWWPHXAFcjs = require('./chunk-OWWPHXAF.cjs');
36
36
 
37
37
 
38
- var _chunkZ5U4NJTWcjs = require('./chunk-Z5U4NJTW.cjs');
38
+ var _chunkMLUHM3VGcjs = require('./chunk-MLUHM3VG.cjs');
39
39
 
40
40
  // src/components/ThemeEditor/ThemeEditor.component.tsx
41
41
  var _react = require('react');
42
42
  var _lucidereact = require('lucide-react');
43
43
  var _jsxruntime = require('react/jsx-runtime');
44
- var PAGE_SURFACE = _chunkNZO2I5ALcjs.CONTRAST_LIGHT;
44
+ var PAGE_SURFACE = _chunkNF55JG2Vcjs.CONTRAST_LIGHT;
45
45
  var EDGE_MIN_RATIO = 1.5;
46
46
  var COLOR_LABELS = {
47
47
  primary: "Primary",
@@ -58,7 +58,7 @@ var FONT_STACKS = [
58
58
  // matches an option exactly. A hand-copied shorter stack did not match, and
59
59
  // the row fell back to showing a synthetic "custom" entry instead of the
60
60
  // name of the font actually in use.
61
- { label: "Plus Jakarta Sans (theme default)", value: _chunkNZO2I5ALcjs.defaultTheme.typography.fontFamily },
61
+ { label: "Plus Jakarta Sans (theme default)", value: _chunkNF55JG2Vcjs.defaultTheme.typography.fontFamily },
62
62
  { label: "System UI", value: "system-ui, -apple-system, 'Segoe UI', sans-serif" },
63
63
  { label: "Helvetica / Arial", value: "Helvetica, Arial, sans-serif" },
64
64
  { label: "Georgia", value: "Georgia, 'Times New Roman', serif" },
@@ -66,7 +66,7 @@ var FONT_STACKS = [
66
66
  { label: "Serif (generic)", value: "serif" }
67
67
  ];
68
68
  var MONO_STACKS = [
69
- { label: "JetBrains Mono (theme default)", value: _chunkNZO2I5ALcjs.defaultTheme.typography.monoFamily },
69
+ { label: "JetBrains Mono (theme default)", value: _chunkNF55JG2Vcjs.defaultTheme.typography.monoFamily },
70
70
  { label: "Menlo / Consolas", value: "Menlo, Consolas, monospace" },
71
71
  { label: "Courier New", value: "'Courier New', Courier, monospace" },
72
72
  { label: "Monospace (generic)", value: "monospace" }
@@ -88,7 +88,7 @@ var GRADE_BADGE = {
88
88
  };
89
89
  var diagnose = (key, base, explicitContrast) => {
90
90
  if (!isFill(key)) {
91
- const ratio2 = _chunkNZO2I5ALcjs.contrastRatio.call(void 0, base, PAGE_SURFACE);
91
+ const ratio2 = _chunkNF55JG2Vcjs.contrastRatio.call(void 0, base, PAGE_SURFACE);
92
92
  const grade2 = gradeFor(ratio2);
93
93
  return {
94
94
  grade: grade2,
@@ -96,10 +96,10 @@ var diagnose = (key, base, explicitContrast) => {
96
96
  detail: `Link text on the page background: ${ratio2.toFixed(2)}:1 against white.${_nullishCoalesce(GRADE_CAVEAT[grade2], () => ( ""))}`
97
97
  };
98
98
  }
99
- const foreground = _nullishCoalesce(explicitContrast, () => ( _chunkNZO2I5ALcjs.pickContrast.call(void 0, base)));
100
- const ratio = _chunkNZO2I5ALcjs.contrastRatio.call(void 0, base, foreground);
101
- const name = foreground.toLowerCase() === _chunkNZO2I5ALcjs.CONTRAST_DARK ? "dark" : "white";
102
- const edge = _chunkNZO2I5ALcjs.contrastRatio.call(void 0, base, PAGE_SURFACE);
99
+ const foreground = _nullishCoalesce(explicitContrast, () => ( _chunkNF55JG2Vcjs.pickContrast.call(void 0, base)));
100
+ const ratio = _chunkNF55JG2Vcjs.contrastRatio.call(void 0, base, foreground);
101
+ const name = foreground.toLowerCase() === _chunkNF55JG2Vcjs.CONTRAST_DARK ? "dark" : "white";
102
+ const edge = _chunkNF55JG2Vcjs.contrastRatio.call(void 0, base, PAGE_SURFACE);
103
103
  const grade = gradeFor(ratio);
104
104
  return {
105
105
  grade,
@@ -121,14 +121,14 @@ var FontRow = ({
121
121
  const inputRef = _react.useRef.call(void 0, null);
122
122
  const [error, setError] = _react.useState.call(void 0, null);
123
123
  const [, onFontsLoaded] = _react.useReducer.call(void 0, (count) => count + 1, 0);
124
- _react.useEffect.call(void 0, () => _chunkNZO2I5ALcjs.subscribeToFontLoads.call(void 0, onFontsLoaded), [onFontsLoaded]);
124
+ _react.useEffect.call(void 0, () => _chunkNF55JG2Vcjs.subscribeToFontLoads.call(void 0, onFontsLoaded), [onFontsLoaded]);
125
125
  const baseOptions = _react.useMemo.call(void 0, () => {
126
126
  const known = options.some((o) => o.value === value);
127
127
  return known ? options : [...options, { label: `${firstFamily(value)} (custom)`, value }];
128
128
  }, [options, value]);
129
129
  const selectOptions = baseOptions.map((option) => ({
130
130
  id: option.value,
131
- label: _chunkNZO2I5ALcjs.isFontStackAvailable.call(void 0, option.value) ? option.label : `${option.label} - not installed`,
131
+ label: _chunkNF55JG2Vcjs.isFontStackAvailable.call(void 0, option.value) ? option.label : `${option.label} - not installed`,
132
132
  value: option.value
133
133
  }));
134
134
  const handleFile = _react.useCallback.call(void 0,
@@ -136,8 +136,8 @@ var FontRow = ({
136
136
  if (!file) return;
137
137
  setError(null);
138
138
  try {
139
- const family = await _chunkNZO2I5ALcjs.registerFontFile.call(void 0, file);
140
- const stack = _chunkNZO2I5ALcjs.toFontStack.call(void 0, family, mono);
139
+ const family = await _chunkNF55JG2Vcjs.registerFontFile.call(void 0, file);
140
+ const stack = _chunkNF55JG2Vcjs.toFontStack.call(void 0, family, mono);
141
141
  onUploaded({ label: `${family} (this session)`, value: stack }, file, family);
142
142
  onChange(stack);
143
143
  } catch (cause) {
@@ -148,21 +148,22 @@ var FontRow = ({
148
148
  },
149
149
  [mono, onChange, onUploaded]
150
150
  );
151
- const unavailable = !_chunkNZO2I5ALcjs.isFontStackAvailable.call(void 0, value);
151
+ const unavailable = !_chunkNF55JG2Vcjs.isFontStackAvailable.call(void 0, value);
152
152
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "eidos-theme-editor-row eidos-theme-editor-row--wide", children: [
153
153
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-theme-editor-row__label", children: label }),
154
154
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "eidos-theme-editor-row__control", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
155
- _chunkK7T25Y3Acjs.Select,
155
+ _chunk6LCYO2HGcjs.Select,
156
156
  {
157
157
  options: selectOptions,
158
158
  value,
159
159
  onChange: (next) => onChange(Array.isArray(next) ? next[0] : next),
160
- fullWidth: true
160
+ fullWidth: true,
161
+ inputProps: { "aria-label": label }
161
162
  }
162
163
  ) }),
163
164
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "eidos-theme-editor-row__diagnostics", children: [
164
165
  unavailable && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
165
- _chunkZ5U4NJTWcjs.Tooltip,
166
+ _chunkMLUHM3VGcjs.Tooltip,
166
167
  {
167
168
  message: `${firstFamily(value)} isn't available here, so the browser is rendering the next family in the stack instead. Upload the file, or have your app serve it, to use it.`,
168
169
  children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "eidos-theme-editor-badge eidos-theme-editor-badge--aa-large", children: [
@@ -171,14 +172,14 @@ var FontRow = ({
171
172
  ] })
172
173
  }
173
174
  ),
174
- error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZ5U4NJTWcjs.Tooltip, { message: error, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "eidos-theme-editor-badge eidos-theme-editor-badge--fail", children: [
175
+ error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkMLUHM3VGcjs.Tooltip, { message: error, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "eidos-theme-editor-badge eidos-theme-editor-badge--fail", children: [
175
176
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.CircleX, { className: "eidos-theme-editor-badge__icon" }),
176
177
  "Upload failed"
177
178
  ] }) })
178
179
  ] }),
179
180
  allowUpload && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "eidos-theme-editor-row__actions", children: [
180
181
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
181
- _chunkWWYJNWJYcjs.Button,
182
+ _chunkOWWPHXAFcjs.Button,
182
183
  {
183
184
  variant: "text",
184
185
  color: "secondary",
@@ -194,8 +195,10 @@ var FontRow = ({
194
195
  {
195
196
  ref: inputRef,
196
197
  type: "file",
197
- accept: _chunkNZO2I5ALcjs.FONT_ACCEPT,
198
+ accept: _chunkNF55JG2Vcjs.FONT_ACCEPT,
198
199
  className: "eidos-theme-editor-file",
200
+ tabIndex: -1,
201
+ "aria-hidden": "true",
199
202
  onChange: (event) => {
200
203
  void handleFile(_optionalChain([event, 'access', _11 => _11.target, 'access', _12 => _12.files, 'optionalAccess', _13 => _13[0]]));
201
204
  event.target.value = "";
@@ -206,7 +209,7 @@ var FontRow = ({
206
209
  ] });
207
210
  };
208
211
  var ThemeEditor = ({
209
- colors = _chunkNZO2I5ALcjs.THEME_COLOR_KEYS,
212
+ colors = _chunkNF55JG2Vcjs.THEME_COLOR_KEYS,
210
213
  fontOptions = FONT_STACKS,
211
214
  monoFontOptions = MONO_STACKS,
212
215
  allowFontUpload = true,
@@ -216,7 +219,7 @@ var ThemeEditor = ({
216
219
  hideCssExport = false,
217
220
  className
218
221
  }) => {
219
- const { theme, resolvedTheme, setTheme, updateTheme, resetTheme, isDefault, toCss } = _chunkNZO2I5ALcjs.useTheme.call(void 0, );
222
+ const { theme, resolvedTheme, setTheme, updateTheme, resetTheme, isDefault, toCss } = _chunkNF55JG2Vcjs.useTheme.call(void 0, );
220
223
  const [copied, setCopied] = _react.useState.call(void 0, false);
221
224
  const [uploaded, setUploaded] = _react.useState.call(void 0, []);
222
225
  const [monoUploaded, setMonoUploaded] = _react.useState.call(void 0, []);
@@ -258,7 +261,7 @@ var ThemeEditor = ({
258
261
  done();
259
262
  }, [toCss]);
260
263
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: ["eidos-theme-editor", className].filter(Boolean).join(" "), children: [
261
- (failing.length > 0 || invisible.length > 0) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkEH42ND5Qcjs.Alert, { variant: "warning", title: "Contrast issues", children: [
264
+ (failing.length > 0 || invisible.length > 0) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkBIANFFJLcjs.Alert, { variant: "warning", title: "Contrast issues", children: [
262
265
  failing.length > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { children: [
263
266
  "Cannot reach WCAG AA (4.5:1) with either foreground:",
264
267
  " ",
@@ -282,19 +285,27 @@ var ThemeEditor = ({
282
285
  const overridden = _optionalChain([theme, 'access', _18 => _18.colors, 'optionalAccess', _19 => _19[key]]) !== void 0;
283
286
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "eidos-theme-editor-row", children: [
284
287
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-theme-editor-row__label", children: COLOR_LABELS[key] }),
285
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAOGNTG3Wcjs.ColorPicker, { value: base, onChange: (hex) => setColor(key, hex), size: "md" }),
288
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
289
+ _chunkFODRHCRPcjs.ColorPicker,
290
+ {
291
+ value: base,
292
+ onChange: (hex) => setColor(key, hex),
293
+ size: "md",
294
+ ariaLabel: COLOR_LABELS[key]
295
+ }
296
+ ),
286
297
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "eidos-theme-editor-row__diagnostics", children: [
287
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZ5U4NJTWcjs.Tooltip, { message: detail, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: `eidos-theme-editor-badge eidos-theme-editor-badge--${grade}`, children: [
298
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkMLUHM3VGcjs.Tooltip, { message: detail, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: `eidos-theme-editor-badge eidos-theme-editor-badge--${grade}`, children: [
288
299
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, badge.icon, { className: "eidos-theme-editor-badge__icon" }),
289
300
  `${ratio.toFixed(2)}:1 ${badge.label}`
290
301
  ] }) }),
291
- edgeWarning && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZ5U4NJTWcjs.Tooltip, { message: edgeWarning, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "eidos-theme-editor-badge eidos-theme-editor-badge--fail", children: [
302
+ edgeWarning && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkMLUHM3VGcjs.Tooltip, { message: edgeWarning, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "eidos-theme-editor-badge eidos-theme-editor-badge--fail", children: [
292
303
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.CircleX, { className: "eidos-theme-editor-badge__icon" }),
293
304
  "Invisible on page"
294
305
  ] }) })
295
306
  ] }),
296
307
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "eidos-theme-editor-row__actions", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
297
- _chunkWWYJNWJYcjs.IconButton,
308
+ _chunkOWWPHXAFcjs.IconButton,
298
309
  {
299
310
  icon: "RotateCcw",
300
311
  variant: "text",
@@ -355,8 +366,8 @@ var ThemeEditor = ({
355
366
  _chunkOZZHOEN5cjs.Slider,
356
367
  {
357
368
  value: resolvedTheme.typography.fontScale,
358
- min: _chunkNZO2I5ALcjs.FONT_SCALE_MIN,
359
- max: _chunkNZO2I5ALcjs.FONT_SCALE_MAX,
369
+ min: _chunkNF55JG2Vcjs.FONT_SCALE_MIN,
370
+ max: _chunkNF55JG2Vcjs.FONT_SCALE_MAX,
360
371
  step: 0.025,
361
372
  showValue: true,
362
373
  showMinMax: true,
@@ -368,9 +379,9 @@ var ThemeEditor = ({
368
379
  ] })
369
380
  ] }),
370
381
  (!hideReset || !hideCssExport) && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "eidos-theme-editor-actions", children: [
371
- !hideReset && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkWWYJNWJYcjs.Button, { variant: "outlined", color: "secondary", disabled: isDefault, onClick: resetTheme, children: "Reset all" }),
382
+ !hideReset && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkOWWPHXAFcjs.Button, { variant: "outlined", color: "secondary", disabled: isDefault, onClick: resetTheme, children: "Reset all" }),
372
383
  !hideCssExport && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
373
- _chunkWWYJNWJYcjs.Button,
384
+ _chunkOWWPHXAFcjs.Button,
374
385
  {
375
386
  variant: "outlined",
376
387
  preIcon: copied ? "Check" : "Clipboard",
@@ -387,4 +398,4 @@ ThemeEditor.displayName = "ThemeEditor";
387
398
 
388
399
 
389
400
  exports.ThemeEditor = ThemeEditor;
390
- //# sourceMappingURL=chunk-R4M6SNUU.cjs.map
401
+ //# sourceMappingURL=chunk-5E4DYTZ3.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-5E4DYTZ3.cjs","../src/components/ThemeEditor/ThemeEditor.component.tsx"],"names":["ratio","grade"],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-5E4DYTZ3.cjs","sourcesContent":[null,"import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react';\nimport { CircleCheck, CircleX, TriangleAlert } from 'lucide-react';\nimport { Alert } from '../Alert';\nimport { Button, IconButton } from '../Button';\nimport { Card } from '../Card';\nimport { ColorPicker } from '../ColorPicker';\nimport { Select } from '../Select';\nimport { Slider } from '../Slider';\nimport { Tooltip } from '../Tooltip';\nimport { useTheme } from '../ThemeProvider';\nimport type { ThemeColorKey, ThemeFontOption } from '../ThemeProvider';\nimport {\n THEME_COLOR_KEYS,\n FONT_SCALE_MAX,\n FONT_SCALE_MIN,\n defaultTheme,\n} from '../ThemeProvider/ThemeProvider.tokens';\nimport {\n CONTRAST_DARK,\n CONTRAST_LIGHT,\n contrastRatio,\n pickContrast,\n} from '../ThemeProvider/ThemeProvider.color';\nimport {\n FONT_ACCEPT,\n isFontStackAvailable,\n registerFontFile,\n subscribeToFontLoads,\n toFontStack,\n} from '../ThemeProvider/ThemeProvider.fonts';\nimport type { ThemeEditorProps } from './ThemeEditor.types';\n\n/** The page surface every diagnostic is measured against - `--white`. */\nconst PAGE_SURFACE = CONTRAST_LIGHT;\n\n/** Below this, a fill is effectively invisible against the page behind it. */\nconst EDGE_MIN_RATIO = 1.5;\n\nconst COLOR_LABELS: Record<ThemeColorKey, string> = {\n primary: 'Primary',\n secondary: 'Secondary',\n success: 'Success',\n danger: 'Danger',\n warning: 'Warning',\n info: 'Info',\n hyperlink: 'Hyperlink',\n};\n\n/** `hyperlink` is only ever text on a surface, so it is graded differently. */\nconst isFill = (key: ThemeColorKey): boolean => key !== 'hyperlink';\n\n/**\n * Built-in stacks, deliberately limited to fonts that can be relied on.\n *\n * A dropdown implies its entries are available, but a font stack is only a list\n * of *names* - nothing here can install a font. So the list is restricted to\n * generic families (guaranteed by CSS), `system-ui` (whatever the OS provides),\n * and the handful of genuinely web-safe faces. Fonts like Inter, which are not\n * installed anywhere by default, were removed: offering one is offering a\n * choice that silently does nothing on most machines.\n *\n * The preset is included because it is the shipped default and therefore has to\n * be representable - and note that `eidos-ui` does not ship the Plus Jakarta\n * Sans file either, so it renders only where the consumer provides it. That is\n * exactly why unavailable options are labelled as such.\n *\n * Anything beyond this belongs to the consuming app, via `fontOptions`.\n */\nconst FONT_STACKS: ThemeFontOption[] = [\n // Taken from the preset rather than retyped, so the shipped default always\n // matches an option exactly. A hand-copied shorter stack did not match, and\n // the row fell back to showing a synthetic \"custom\" entry instead of the\n // name of the font actually in use.\n { label: 'Plus Jakarta Sans (theme default)', value: defaultTheme.typography.fontFamily! },\n { label: 'System UI', value: \"system-ui, -apple-system, 'Segoe UI', sans-serif\" },\n { label: 'Helvetica / Arial', value: 'Helvetica, Arial, sans-serif' },\n { label: 'Georgia', value: \"Georgia, 'Times New Roman', serif\" },\n { label: 'Sans-serif (generic)', value: 'sans-serif' },\n { label: 'Serif (generic)', value: 'serif' },\n];\n\nconst MONO_STACKS: ThemeFontOption[] = [\n { label: 'JetBrains Mono (theme default)', value: defaultTheme.typography.monoFamily! },\n { label: 'Menlo / Consolas', value: 'Menlo, Consolas, monospace' },\n { label: 'Courier New', value: \"'Courier New', Courier, monospace\" },\n { label: 'Monospace (generic)', value: 'monospace' },\n];\n\ntype Grade = 'aa' | 'aa-large' | 'fail';\n\nconst gradeFor = (ratio: number): Grade => (ratio >= 4.5 ? 'aa' : ratio >= 3 ? 'aa-large' : 'fail');\n\n/** Spelled out for the middle grade, which is the one that misleads. */\nconst GRADE_CAVEAT: Partial<Record<Grade, string>> = {\n 'aa-large':\n ' WCAG AA needs 4.5:1 for normal text and allows 3:1 only at 24px or larger - button and label text here is around 12px, so this does not pass.',\n fail: ' Below 3:1, which fails WCAG AA at every text size.',\n};\n\n/**\n * Severity is carried by an icon and the label text, not by colour.\n *\n * These badges cannot use `Pill`, or any themed `--x-color`: the theme being\n * edited also styles this editor, so a washed-out `success` colour would render\n * the \"passes AA\" badge illegible at precisely the moment it is reporting that\n * a colour is illegible. The badge styling comes from the gray ramp, which is\n * deliberately not themeable.\n *\n * Not relying on colour alone also satisfies WCAG 1.4.1 (Use of Colour).\n */\nconst GRADE_BADGE: Record<\n Grade,\n { label: string; icon: React.ComponentType<{ className?: string }> }\n> = {\n aa: { label: 'AA', icon: CircleCheck },\n // Named for what it means in practice, not just for the threshold it clears.\n // WCAG's relaxed 3:1 tier applies only to text at 24px (or 18.7px bold) and\n // above, and nothing in this library is that large - `--font-size-sm` is\n // ~12.25px at the default root size. A bare \"AA large only\" reads as a pass\n // when for every component here it is a fail.\n 'aa-large': { label: 'Too low for body text', icon: TriangleAlert },\n fail: { label: 'Fails AA', icon: CircleX },\n};\n\ninterface Diagnostic {\n grade: Grade;\n ratio: number;\n /** What the ratio describes, for the tooltip. */\n detail: string;\n /** Set when the fill is too close to the page surface to be seen. */\n edgeWarning?: string;\n}\n\nconst diagnose = (key: ThemeColorKey, base: string, explicitContrast?: string): Diagnostic => {\n if (!isFill(key)) {\n // Link text sits on the page, so the page is what it must contrast with.\n const ratio = contrastRatio(base, PAGE_SURFACE);\n const grade = gradeFor(ratio);\n return {\n grade,\n ratio,\n detail: `Link text on the page background: ${ratio.toFixed(2)}:1 against white.${GRADE_CAVEAT[grade] ?? ''}`,\n };\n }\n\n const foreground = explicitContrast ?? pickContrast(base);\n const ratio = contrastRatio(base, foreground);\n const name = foreground.toLowerCase() === CONTRAST_DARK ? 'dark' : 'white';\n const edge = contrastRatio(base, PAGE_SURFACE);\n\n const grade = gradeFor(ratio);\n\n return {\n grade,\n ratio,\n detail: `${name === 'white' ? 'White' : 'Near-black'} text on this fill is ${ratio.toFixed(2)}:1.${\n explicitContrast ? ' Foreground pinned via the theme.' : ''\n }${GRADE_CAVEAT[grade] ?? ''}`,\n edgeWarning:\n edge < EDGE_MIN_RATIO\n ? `Only ${edge.toFixed(2)}:1 against the page background - this fill is barely distinguishable from the page it sits on.`\n : undefined,\n };\n};\n\ninterface FontRowProps {\n label: string;\n /** Stack currently applied, used to pick the matching option. */\n value: string;\n options: ThemeFontOption[];\n mono: boolean;\n allowUpload: boolean;\n onChange: (stack: string) => void;\n onUploaded: (option: ThemeFontOption, file: File, family: string) => void;\n}\n\n/** Pulls the first family out of a stack, unquoted. */\nconst firstFamily = (stack: string): string =>\n stack\n .split(',')[0]\n ?.trim()\n .replace(/^['\"]|['\"]$/g, '') || 'Custom';\n\n/**\n * One font row: a `Select` over the known stacks, an optional upload, and an\n * availability warning.\n *\n * Uses `Select` rather than `Combobox` deliberately. `Combobox` filters its\n * options against the text in the field, and the field holds a full font stack\n * (`'Plus Jakarta Sans', -apple-system, …`) which matches no option label - so\n * the list read \"No results found\" until the text was cleared by hand. A font\n * is a choice from a known set, not a search.\n */\nconst FontRow: React.FC<FontRowProps> = ({\n label,\n value,\n options,\n mono,\n allowUpload,\n onChange,\n onUploaded,\n}) => {\n const inputRef = useRef<HTMLInputElement>(null);\n const [error, setError] = useState<string | null>(null);\n\n // Web fonts load asynchronously, so the first render always sees them as\n // unavailable. Without re-checking once they arrive, the row would sit on a\n // stale \"not installed\" warning for a font that is rendering perfectly.\n // The reducer exists only to schedule that re-render; its value is unused.\n const [, onFontsLoaded] = useReducer((count: number) => count + 1, 0);\n useEffect(() => subscribeToFontLoads(onFontsLoaded), [onFontsLoaded]);\n\n const baseOptions = useMemo(() => {\n // A stack the theme carries but that isn't in the list (loaded by the host\n // app, or set programmatically) still needs to be selectable, labelled with\n // its own first family so the row names the font actually in use.\n const known = options.some((o) => o.value === value);\n return known ? options : [...options, { label: `${firstFamily(value)} (custom)`, value }];\n }, [options, value]);\n\n // Probed on every render rather than memoised: availability changes over time\n // as fonts load, so a cached answer is a wrong answer. Four canvas\n // measurements are far cheaper than getting this wrong.\n //\n // Availability is annotated per option rather than filtered or disabled. A\n // theme is shared across machines, so a font present here may be absent for\n // the next user - and vice versa, which would mean hiding a font someone\n // legitimately wants. Annotating keeps every choice selectable while making\n // the list stop implying that a name is a guarantee.\n const selectOptions = baseOptions.map((option) => ({\n id: option.value,\n label: isFontStackAvailable(option.value) ? option.label : `${option.label} - not installed`,\n value: option.value,\n }));\n\n const handleFile = useCallback(\n async (file: File | undefined) => {\n if (!file) return;\n setError(null);\n try {\n const family = await registerFontFile(file);\n const stack = toFontStack(family, mono);\n onUploaded({ label: `${family} (this session)`, value: stack }, file, family);\n onChange(stack);\n } catch (cause) {\n setError(\n cause instanceof Error ? cause.message : 'That file could not be loaded as a font.',\n );\n }\n },\n [mono, onChange, onUploaded],\n );\n\n const unavailable = !isFontStackAvailable(value);\n\n return (\n <div className=\"eidos-theme-editor-row eidos-theme-editor-row--wide\">\n <span className=\"eidos-theme-editor-row__label\">{label}</span>\n\n <div className=\"eidos-theme-editor-row__control\">\n <Select\n options={selectOptions}\n value={value}\n onChange={(next) => onChange(Array.isArray(next) ? next[0] : next)}\n fullWidth\n // The row's visible label is a `<span>`, not a `<label htmlFor>`,\n // so nothing associates it with the control. Naming the input\n // directly keeps the two in step without restructuring the row.\n inputProps={{ 'aria-label': label }}\n />\n </div>\n\n {/* Occasional - lives before the action so it can never displace it. */}\n <div className=\"eidos-theme-editor-row__diagnostics\">\n {unavailable && (\n <Tooltip\n message={`${firstFamily(value)} isn't available here, so the browser is rendering the next family in the stack instead. Upload the file, or have your app serve it, to use it.`}\n >\n <span className=\"eidos-theme-editor-badge eidos-theme-editor-badge--aa-large\">\n <TriangleAlert className=\"eidos-theme-editor-badge__icon\" />\n Not installed\n </span>\n </Tooltip>\n )}\n {error && (\n <Tooltip message={error}>\n <span className=\"eidos-theme-editor-badge eidos-theme-editor-badge--fail\">\n <CircleX className=\"eidos-theme-editor-badge__icon\" />\n Upload failed\n </span>\n </Tooltip>\n )}\n </div>\n\n {allowUpload && (\n <div className=\"eidos-theme-editor-row__actions\">\n <Button\n variant=\"text\"\n color=\"secondary\"\n size=\"sm\"\n preIcon=\"Upload\"\n onClick={() => inputRef.current?.click()}\n tooltip=\"Load a font file to use it right away. Not saved - see onFontUpload to persist it.\"\n >\n Upload\n </Button>\n {/* Plain input rather than FileUpload: this is a single inline\n action in a dense row, not a drop zone. */}\n <input\n ref={inputRef}\n type=\"file\"\n accept={FONT_ACCEPT}\n // Same proxy pattern as `MessageComposer` - see the note there.\n className=\"eidos-theme-editor-file\"\n tabIndex={-1}\n aria-hidden=\"true\"\n onChange={(event) => {\n void handleFile(event.target.files?.[0]);\n // Allow re-picking the same file after a failure.\n event.target.value = '';\n }}\n />\n </div>\n )}\n </div>\n );\n};\n\n/**\n * Live editor for the active `ThemeProvider` theme.\n *\n * Renders no preview of its own: the provider writes tokens to\n * `document.documentElement`, so the surrounding page is the preview.\n *\n * Contrast readouts are diagnostics only - a colour that fails is still\n * applied. Automatically \"correcting\" a chosen colour would mean silently\n * rendering something other than what was picked.\n */\nexport const ThemeEditor: React.FC<ThemeEditorProps> = ({\n colors = THEME_COLOR_KEYS as ThemeColorKey[],\n fontOptions = FONT_STACKS,\n monoFontOptions = MONO_STACKS,\n allowFontUpload = true,\n onFontUpload,\n hideTypography = false,\n hideReset = false,\n hideCssExport = false,\n className,\n}) => {\n const { theme, resolvedTheme, setTheme, updateTheme, resetTheme, isDefault, toCss } = useTheme();\n const [copied, setCopied] = useState(false);\n\n // Fonts registered through the upload control this session. Kept local\n // because font *data* cannot live in a ThemeConfig - see the .mdx.\n const [uploaded, setUploaded] = useState<ThemeFontOption[]>([]);\n const [monoUploaded, setMonoUploaded] = useState<ThemeFontOption[]>([]);\n\n const setColor = useCallback(\n (key: ThemeColorKey, hex: string) => {\n const current = theme.colors?.[key];\n // Only the base is written here. A `contrast` pinned in the theme is\n // preserved rather than dropped, since the editor never sets one.\n const pinned = typeof current === 'object' ? current.contrast : undefined;\n updateTheme({ colors: { [key]: pinned ? { base: hex, contrast: pinned } : hex } });\n },\n [theme.colors, updateTheme],\n );\n\n const resetColor = useCallback(\n (key: ThemeColorKey) => {\n // Must go through setTheme, not updateTheme: updateTheme merges, so a key\n // left out of the patch keeps its existing value instead of being removed.\n // Removal is what restores the preset, since resolveTheme fills gaps.\n const nextColors = { ...theme.colors };\n delete nextColors[key];\n setTheme({ ...theme, colors: nextColors });\n },\n [theme, setTheme],\n );\n\n const diagnostics = useMemo(\n () =>\n colors.map((key) => {\n const { base, contrast } = resolvedTheme.colors[key];\n return { key, base, ...diagnose(key, base, contrast) };\n }),\n [colors, resolvedTheme],\n );\n\n const failing = diagnostics.filter((d) => d.grade === 'fail');\n const invisible = diagnostics.filter((d) => d.edgeWarning);\n\n const copyCss = useCallback(() => {\n const css = toCss();\n const done = () => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1600);\n };\n if (navigator.clipboard?.writeText) {\n navigator.clipboard.writeText(css).then(done, done);\n return;\n }\n done();\n }, [toCss]);\n\n return (\n <div className={['eidos-theme-editor', className].filter(Boolean).join(' ')}>\n {(failing.length > 0 || invisible.length > 0) && (\n <Alert variant=\"warning\" title=\"Contrast issues\">\n {failing.length > 0 && (\n <p>\n Cannot reach WCAG AA (4.5:1) with either foreground:{' '}\n {failing.map((d) => COLOR_LABELS[d.key]).join(', ')}.\n </p>\n )}\n {invisible.length > 0 && (\n <p>\n Too close to the page background to read as a filled surface:{' '}\n {invisible.map((d) => COLOR_LABELS[d.key]).join(', ')}.\n </p>\n )}\n </Alert>\n )}\n\n <Card variant=\"outlined\" padding=\"lg\" className=\"eidos-theme-editor-section\">\n <div className=\"eidos-theme-editor-section__header\">\n <span className=\"eidos-theme-editor-section__title\">Colours</span>\n <span className=\"eidos-theme-editor-section__hint\">\n Shades, tints and foregrounds are derived from each base colour.\n </span>\n </div>\n\n <div className=\"eidos-theme-editor-rows\">\n {diagnostics.map(({ key, base, grade, ratio, detail, edgeWarning }) => {\n const badge = GRADE_BADGE[grade];\n const overridden = theme.colors?.[key] !== undefined;\n return (\n <div className=\"eidos-theme-editor-row\" key={key}>\n <span className=\"eidos-theme-editor-row__label\">{COLOR_LABELS[key]}</span>\n\n {/* `md` rather than `sm`: the size drives the panel's\n saturation/brightness canvas, and 120px is cramped for\n picking a lightness precisely. */}\n <ColorPicker\n value={base}\n onChange={(hex) => setColor(key, hex)}\n size=\"md\"\n // The row draws its own visible label, so the picker must\n // not draw a second one - but without a name of its own\n // every picker here announced as \"Open colour picker\" and\n // they were indistinguishable.\n ariaLabel={COLOR_LABELS[key]}\n />\n\n <div className=\"eidos-theme-editor-row__diagnostics\">\n <Tooltip message={detail}>\n <span className={`eidos-theme-editor-badge eidos-theme-editor-badge--${grade}`}>\n <badge.icon className=\"eidos-theme-editor-badge__icon\" />\n {`${ratio.toFixed(2)}:1 ${badge.label}`}\n </span>\n </Tooltip>\n {edgeWarning && (\n <Tooltip message={edgeWarning}>\n <span className=\"eidos-theme-editor-badge eidos-theme-editor-badge--fail\">\n <CircleX className=\"eidos-theme-editor-badge__icon\" />\n Invisible on page\n </span>\n </Tooltip>\n )}\n </div>\n\n <div className=\"eidos-theme-editor-row__actions\">\n <IconButton\n icon=\"RotateCcw\"\n variant=\"text\"\n color=\"secondary\"\n size=\"sm\"\n disabled={!overridden}\n onClick={() => resetColor(key)}\n tooltip={overridden ? `Reset ${COLOR_LABELS[key]} to the preset` : 'Unchanged'}\n aria-label={`Reset ${COLOR_LABELS[key]}`}\n />\n </div>\n </div>\n );\n })}\n </div>\n </Card>\n\n {!hideTypography && (\n <Card variant=\"outlined\" padding=\"lg\" className=\"eidos-theme-editor-section\">\n <div className=\"eidos-theme-editor-section__header\">\n <span className=\"eidos-theme-editor-section__title\">Typography</span>\n <span className=\"eidos-theme-editor-section__hint\">\n A stack only names a font - upload the file to use one the browser doesn&apos;t\n already have. Spacing is declared in <code>em</code>, so the scale moves padding with\n the text.\n </span>\n </div>\n\n <div className=\"eidos-theme-editor-rows\">\n <FontRow\n label=\"Body font\"\n value={resolvedTheme.typography.fontFamily}\n options={[...fontOptions, ...uploaded]}\n mono={false}\n allowUpload={allowFontUpload}\n onChange={(fontFamily) => updateTheme({ typography: { fontFamily } })}\n onUploaded={(option, file, family) => {\n setUploaded((prev) => [...prev, option]);\n onFontUpload?.(file, family, false);\n }}\n />\n\n <FontRow\n label=\"Mono font\"\n value={resolvedTheme.typography.monoFamily}\n options={[...monoFontOptions, ...monoUploaded]}\n mono\n allowUpload={allowFontUpload}\n onChange={(monoFamily) => updateTheme({ typography: { monoFamily } })}\n onUploaded={(option, file, family) => {\n setMonoUploaded((prev) => [...prev, option]);\n onFontUpload?.(file, family, true);\n }}\n />\n\n <div className=\"eidos-theme-editor-row eidos-theme-editor-row--wide\">\n <span className=\"eidos-theme-editor-row__label\">Scale</span>\n <div className=\"eidos-theme-editor-row__control\">\n <Slider\n value={resolvedTheme.typography.fontScale}\n min={FONT_SCALE_MIN}\n max={FONT_SCALE_MAX}\n step={0.025}\n showValue\n showMinMax\n unit=\"×\"\n onChange={(value) => updateTheme({ typography: { fontScale: value } })}\n />\n </div>\n </div>\n </div>\n </Card>\n )}\n\n {(!hideReset || !hideCssExport) && (\n <div className=\"eidos-theme-editor-actions\">\n {!hideReset && (\n <Button variant=\"outlined\" color=\"secondary\" disabled={isDefault} onClick={resetTheme}>\n Reset all\n </Button>\n )}\n {!hideCssExport && (\n <Button\n variant=\"outlined\"\n preIcon={copied ? 'Check' : 'Clipboard'}\n onClick={copyCss}\n tooltip=\"Copy the resolved tokens as a :root block you can paste into your own stylesheet\"\n >\n {copied ? 'Copied' : 'Copy as CSS'}\n </Button>\n )}\n </div>\n )}\n </div>\n );\n};\n\nThemeEditor.displayName = 'ThemeEditor';\n"]}
@@ -1,12 +1,12 @@
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 _chunkTEVZHN5Icjs = require('./chunk-TEVZHN5I.cjs');
3
+ var _chunkNCZUQFKLcjs = require('./chunk-NCZUQFKL.cjs');
4
4
 
5
5
 
6
- var _chunkP2JM22BFcjs = require('./chunk-P2JM22BF.cjs');
6
+ var _chunkP7J6WZTOcjs = require('./chunk-P7J6WZTO.cjs');
7
7
 
8
8
 
9
- var _chunkCUJBNRJJcjs = require('./chunk-CUJBNRJJ.cjs');
9
+ var _chunkVHSTB7GBcjs = require('./chunk-VHSTB7GB.cjs');
10
10
 
11
11
  // src/components/Combobox/Combobox.component.tsx
12
12
  var _react = require('react');
@@ -370,83 +370,86 @@ var Combobox = ({
370
370
  const posIconClick = hasClearableValue ? handleClearClick : handleChevronClick;
371
371
  const containerClasses = [
372
372
  "eidos-combobox",
373
- fullWidth && _chunkCUJBNRJJcjs.fullWidthModifier.call(void 0, "eidos-combobox"),
373
+ fullWidth && _chunkVHSTB7GBcjs.fullWidthModifier.call(void 0, "eidos-combobox"),
374
374
  error && "eidos-combobox--error",
375
375
  disabled && "eidos-combobox--disabled",
376
376
  className
377
377
  ].filter(Boolean).join(" ");
378
378
  const maxHeightValue = typeof maxHeight === "number" ? `${maxHeight}px` : maxHeight;
379
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
380
- "div",
381
- {
382
- ref: containerRef,
383
- className: containerClasses,
384
- "aria-expanded": isOpen,
385
- "aria-haspopup": "listbox",
386
- children: [
387
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: comboboxTriggerRef, className: "eidos-combobox-trigger", children: [
388
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
389
- _chunkTEVZHN5Icjs.Input,
390
- {
391
- ref: inputRef,
392
- value: inputValue,
393
- onChange: handleChange,
394
- onFocus: handleFocus,
395
- onBlur: handleBlur,
396
- onKeyDown: handleKeyDown,
397
- placeholder,
398
- disabled,
399
- size,
400
- fullWidth: true,
401
- label,
402
- clearable: false,
403
- isSelect: false,
404
- posIcon,
405
- posIconButton: true,
406
- onPosIconClick: posIconClick,
407
- "aria-autocomplete": "list",
408
- "aria-controls": `${uid}-listbox`,
409
- "aria-activedescendant": focusedIndex >= 0 ? `${uid}-option-${focusedIndex}` : void 0
410
- }
411
- ),
412
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
413
- _chunkP2JM22BFcjs.Dropdown,
414
- {
415
- trigger: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
416
- "span",
417
- {
418
- ref: dropdownSpanRef,
419
- className: "eidos-combobox-dropdown-anchor",
420
- "aria-hidden": "true"
421
- }
422
- ),
423
- content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
424
- "div",
425
- {
426
- id: `${uid}-listbox`,
427
- className: "eidos-combobox-options",
428
- role: "listbox",
429
- "aria-label": _nullishCoalesce(label, () => ( "Options")),
430
- onMouseDown: (e) => e.preventDefault(),
431
- children: dropdownContent
432
- }
433
- ),
434
- triggerRef: comboboxTriggerRef,
435
- maxHeight: maxHeightValue,
436
- autoWidth: true,
437
- closeOnClickOutside: false,
438
- closeOnEscape: false
439
- },
440
- menuKey
441
- )
442
- ] }),
443
- hint && !error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-combobox-hint", children: hint }),
444
- error && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "eidos-combobox-error-message", children: [
445
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.CircleAlert, { className: "eidos-combobox-error-icon" }),
446
- error
447
- ] })
448
- ]
449
- }
379
+ return (
380
+ // No ARIA on this wrapper.
381
+ //
382
+ // It carried `aria-expanded` and `aria-haspopup` while having no role at
383
+ // all, which is invalid - both are only meaningful on an element whose
384
+ // role supports them. They belong on the input, which is the combobox.
385
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: containerRef, className: containerClasses, children: [
386
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { ref: comboboxTriggerRef, className: "eidos-combobox-trigger", children: [
387
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
388
+ _chunkNCZUQFKLcjs.Input,
389
+ {
390
+ ref: inputRef,
391
+ value: inputValue,
392
+ onChange: handleChange,
393
+ onFocus: handleFocus,
394
+ onBlur: handleBlur,
395
+ onKeyDown: handleKeyDown,
396
+ placeholder,
397
+ disabled,
398
+ size,
399
+ fullWidth: true,
400
+ label,
401
+ clearable: false,
402
+ isSelect: false,
403
+ posIcon,
404
+ posIconButton: true,
405
+ onPosIconClick: posIconClick,
406
+ posIconLabel: hasClearableValue ? "Clear selection" : "Show options",
407
+ role: "combobox",
408
+ "aria-expanded": isOpen,
409
+ "aria-invalid": error ? true : void 0,
410
+ "aria-describedby": error ? `${uid}-error` : void 0,
411
+ "aria-autocomplete": "list",
412
+ "aria-controls": isOpen ? `${uid}-listbox` : void 0,
413
+ "aria-activedescendant": focusedIndex >= 0 ? `${uid}-option-${focusedIndex}` : void 0
414
+ }
415
+ ),
416
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
417
+ _chunkP7J6WZTOcjs.Dropdown,
418
+ {
419
+ trigger: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
420
+ "span",
421
+ {
422
+ ref: dropdownSpanRef,
423
+ className: "eidos-combobox-dropdown-anchor",
424
+ "aria-hidden": "true"
425
+ }
426
+ ),
427
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
428
+ "div",
429
+ {
430
+ id: `${uid}-listbox`,
431
+ className: "eidos-combobox-options",
432
+ role: "listbox",
433
+ "aria-label": _nullishCoalesce(label, () => ( "Options")),
434
+ onMouseDown: (e) => e.preventDefault(),
435
+ children: dropdownContent
436
+ }
437
+ ),
438
+ triggerRef: comboboxTriggerRef,
439
+ maxHeight: maxHeightValue,
440
+ autoWidth: true,
441
+ closeOnClickOutside: false,
442
+ closeOnEscape: false
443
+ },
444
+ menuKey
445
+ )
446
+ ] }),
447
+ hint && !error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-combobox-hint", children: hint }),
448
+ error && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { id: `${uid}-error`, className: "eidos-combobox-error-message", children: [
449
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.CircleAlert, { className: "eidos-combobox-error-icon" }),
450
+ error
451
+ ] })
452
+ ] })
450
453
  );
451
454
  };
452
455
  Combobox.displayName = "Combobox";
@@ -454,4 +457,4 @@ Combobox.displayName = "Combobox";
454
457
 
455
458
 
456
459
  exports.Combobox = Combobox;
457
- //# sourceMappingURL=chunk-I5XR2V4A.cjs.map
460
+ //# sourceMappingURL=chunk-5V7DXZWT.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-5V7DXZWT.cjs","../src/components/Combobox/Combobox.component.tsx"],"names":["label"],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-5V7DXZWT.cjs","sourcesContent":[null,"import React, { useState, useCallback, useRef, useEffect, useMemo, useId } from 'react';\nimport { Check, ChevronDown, X, Loader2, CircleAlert } from 'lucide-react';\nimport { Input } from '../Input/Input.component';\nimport { Dropdown } from '../Dropdown/Dropdown.component';\nimport { fullWidthModifier } from '../../utils';\nimport type { ComboboxProps, ComboboxOption } from './Combobox.types';\nimport './Combobox.scss';\n\n// ─── Types ───────────────────────────────────────────────────────────────────\n\ntype OptionEntry =\n | { type: 'group'; group: string; key: string }\n | { type: 'option'; option: ComboboxOption; index: number; key: string };\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\nexport const Combobox: React.FC<ComboboxProps> = ({\n options = [],\n value,\n defaultValue,\n onChange,\n onSearch,\n placeholder = 'Search or select…',\n loading = false,\n loadingText = 'Searching…',\n emptyText = 'No results found',\n allowFreeText = false,\n clearable = true,\n disabled = false,\n size = 'md',\n label,\n error,\n hint,\n fullWidth = false,\n className = '',\n maxHeight = '300px',\n renderOption,\n}) => {\n const uid = useId();\n\n // ─── Refs ─────────────────────────────────────────────────────────────────\n\n /** Entire combobox wrapper - used for click-outside detection */\n const containerRef = useRef<HTMLDivElement>(null);\n\n /** The trigger wrapper div - passed to Dropdown as externalTriggerRef for width */\n const comboboxTriggerRef = useRef<HTMLDivElement>(null);\n\n /** The 0-height span that IS the Dropdown trigger element - programmatically clicked to open */\n const dropdownSpanRef = useRef<HTMLSpanElement>(null);\n\n /** Native input element */\n const inputRef = useRef<HTMLInputElement>(null);\n\n /** Focusable option divs for scroll-into-view */\n const optionRefs = useRef<(HTMLDivElement | null)[]>([]);\n\n /**\n * Synchronous open-state flag.\n * React state updates are async; reading this ref inside event handlers\n * gives us the true current value without waiting for a re-render.\n */\n const isOpenRef = useRef(false);\n\n // ─── State ────────────────────────────────────────────────────────────────\n\n const isControlled = value !== undefined;\n\n const getInitialInputValue = (): string => {\n const seed = isControlled ? value : defaultValue;\n if (!seed) return '';\n const match = options.find((o) => o.value === seed);\n return match ? match.label : allowFreeText ? seed : '';\n };\n\n const getInitialCommittedValue = (): string => {\n return isControlled ? (value ?? '') : (defaultValue ?? '');\n };\n\n const [inputValue, _setInputValue] = useState<string>(getInitialInputValue);\n const inputValueRef = useRef<string>(inputValue);\n const setInputValue = useCallback((v: string) => {\n inputValueRef.current = v;\n _setInputValue(v);\n }, []);\n\n const [committedValue, _setCommittedValue] = useState<string>(getInitialCommittedValue);\n const committedValueRef = useRef<string>(committedValue);\n const setCommittedValue = useCallback((v: string) => {\n committedValueRef.current = v;\n _setCommittedValue(v);\n }, []);\n\n const [isOpen, setIsOpen] = useState(false);\n const [menuKey, setMenuKey] = useState(0);\n const [focusedIndex, setFocusedIndex] = useState(-1);\n\n // ─── Sync controlled value ────────────────────────────────────────────────\n\n useEffect(() => {\n if (!isControlled) return;\n const v = value ?? '';\n const match = options.find((o) => o.value === v);\n const label = match ? match.label : allowFreeText ? v : '';\n setInputValue(label);\n setCommittedValue(v);\n }, [value, isControlled, options, allowFreeText, setInputValue, setCommittedValue]);\n\n // ─── Derived: filtered options ────────────────────────────────────────────\n\n const filteredOptions = useMemo<ComboboxOption[]>(() => {\n const q = inputValue.toLowerCase();\n if (!q) return options;\n return options.filter((o) => o.label.toLowerCase().includes(q));\n }, [options, inputValue]);\n\n // Reset focused index when the filtered set changes\n useEffect(() => {\n setFocusedIndex(-1);\n }, [filteredOptions]);\n\n // Keep optionRefs array in sync with filteredOptions length\n useEffect(() => {\n optionRefs.current = optionRefs.current.slice(0, filteredOptions.length);\n }, [filteredOptions.length]);\n\n // ─── Derived: option entries (with group headers) ─────────────────────────\n\n const optionEntries = useMemo<OptionEntry[]>(() => {\n const entries: OptionEntry[] = [];\n const hasGroups = filteredOptions.some((o) => o.group);\n\n if (!hasGroups) {\n filteredOptions.forEach((option, index) => {\n entries.push({ type: 'option', option, index, key: option.id });\n });\n return entries;\n }\n\n // Build ordered group map while preserving insertion order\n const groupMap = new Map<string | null, ComboboxOption[]>();\n for (const option of filteredOptions) {\n const g = option.group ?? null;\n if (!groupMap.has(g)) groupMap.set(g, []);\n groupMap.get(g)!.push(option);\n }\n\n let optionIndex = 0;\n for (const [group, opts] of groupMap.entries()) {\n if (group !== null) {\n entries.push({ type: 'group', group, key: `group-${group}` });\n }\n for (const option of opts) {\n entries.push({ type: 'option', option, index: optionIndex++, key: option.id });\n }\n }\n\n return entries;\n }, [filteredOptions]);\n\n // ─── Open / Close helpers ─────────────────────────────────────────────────\n\n /**\n * Open the dropdown by programmatically clicking the 0-height span trigger.\n * The click bubbles to div.eidos-dropdown-trigger → Dropdown.handleTriggerClick → opens.\n *\n * We set isOpenRef AFTER the synthetic click so that the Dropdown's toggle\n * handler fires while isOpenRef is still false (allowing it to open).\n */\n const openDropdown = useCallback(() => {\n if (isOpenRef.current || disabled) return;\n dropdownSpanRef.current?.click(); // opens the Dropdown (bubbles to trigger)\n isOpenRef.current = true;\n setIsOpen(true);\n }, [disabled]);\n\n /**\n * Close the dropdown by remounting it (menuKey increment resets internal state).\n * Optionally revert inputValue to the last committed value.\n */\n const closeDropdown = useCallback(\n (revertInput = false) => {\n isOpenRef.current = false;\n setIsOpen(false);\n setFocusedIndex(-1);\n setMenuKey((prev) => prev + 1);\n\n if (revertInput) {\n const match = options.find((o) => o.value === committedValueRef.current);\n setInputValue(match ? match.label : allowFreeText ? committedValueRef.current : '');\n }\n },\n [options, allowFreeText, setInputValue],\n );\n\n // ─── Click-outside detection ──────────────────────────────────────────────\n\n useEffect(() => {\n const handleMouseDown = (e: MouseEvent) => {\n if (!isOpenRef.current) return;\n // defaultPrevented is set by the listbox's onMouseDown - means the user\n // clicked an option in the portal, not truly outside the combobox.\n if (e.defaultPrevented) return;\n if (containerRef.current?.contains(e.target as Node)) return;\n\n // Focus leaving to a non-focusable target: validate and close\n isOpenRef.current = false;\n setIsOpen(false);\n setFocusedIndex(-1);\n setMenuKey((prev) => prev + 1);\n\n const current = inputValueRef.current;\n const committed = committedValueRef.current;\n\n if (!allowFreeText) {\n const match = options.find((o) => o.label.toLowerCase() === current.toLowerCase());\n if (match) {\n if (match.value !== committed) {\n setCommittedValue(match.value);\n onChange?.(match.value);\n setInputValue(match.label);\n }\n } else {\n const revertMatch = options.find((o) => o.value === committed);\n setInputValue(revertMatch ? revertMatch.label : '');\n }\n } else {\n if (current !== committed) {\n setCommittedValue(current);\n onChange?.(current);\n }\n }\n };\n\n document.addEventListener('mousedown', handleMouseDown);\n return () => document.removeEventListener('mousedown', handleMouseDown);\n }, [allowFreeText, options, onChange, setCommittedValue, setInputValue]);\n\n // ─── Input handlers ───────────────────────────────────────────────────────\n\n const handleFocus = useCallback(() => {\n openDropdown();\n }, [openDropdown]);\n\n const handleChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n const query = e.target.value;\n setInputValue(query);\n onSearch?.(query);\n if (!isOpenRef.current) openDropdown();\n },\n [setInputValue, onSearch, openDropdown],\n );\n\n /**\n * On blur, validate the typed value against options.\n * A 0ms defer ensures a click on a posIcon button (X / chevron) inside the\n * Input completes its onClick before we run close logic, so we can check\n * document.activeElement reliably.\n */\n const handleBlur = useCallback(() => {\n setTimeout(() => {\n // If focus came back inside the container (e.g., posIcon button clicked),\n // don't close or validate yet.\n if (containerRef.current?.contains(document.activeElement)) return;\n\n // Read both refs *inside* the deferred callback, never captured at blur\n // time - that's the whole reason they're kept in sync by the setters.\n // Anything can run in the gap this 0ms defer opens, including the click\n // that caused the blur: a controlled consumer clearing `value` from\n // another control (e.g. DataGrid's \"Clear filters\", which resets every\n // quick filter at once) updates the refs via the sync effect, and stale\n // captured values would then resurrect the label that was just cleared.\n const current = inputValueRef.current;\n const committed = committedValueRef.current;\n\n // Close\n isOpenRef.current = false;\n setIsOpen(false);\n setFocusedIndex(-1);\n setMenuKey((prev) => prev + 1);\n\n // Validate\n if (!allowFreeText) {\n const match = options.find((o) => o.label.toLowerCase() === current.toLowerCase());\n if (match) {\n if (match.value !== committed) {\n setCommittedValue(match.value);\n onChange?.(match.value);\n setInputValue(match.label);\n } else {\n // Normalize the display label (fix casing)\n setInputValue(match.label);\n }\n } else {\n // No match - revert to last committed value\n const revertMatch = options.find((o) => o.value === committed);\n setInputValue(revertMatch ? revertMatch.label : '');\n }\n } else {\n // allowFreeText: commit whatever the user typed\n if (current !== committed) {\n setCommittedValue(current);\n onChange?.(current);\n }\n }\n }, 0);\n }, [allowFreeText, options, onChange, setCommittedValue, setInputValue]);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (disabled) return;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isOpenRef.current) {\n openDropdown();\n setFocusedIndex(0);\n } else {\n setFocusedIndex((prev) => {\n const next = prev < filteredOptions.length - 1 ? prev + 1 : 0;\n setTimeout(\n () =>\n optionRefs.current[next]?.scrollIntoView({\n block: 'nearest',\n behavior: 'smooth',\n }),\n 0,\n );\n return next;\n });\n }\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n if (!isOpenRef.current) {\n openDropdown();\n setFocusedIndex(filteredOptions.length - 1);\n } else {\n setFocusedIndex((prev) => {\n const next = prev > 0 ? prev - 1 : filteredOptions.length - 1;\n setTimeout(\n () =>\n optionRefs.current[next]?.scrollIntoView({\n block: 'nearest',\n behavior: 'smooth',\n }),\n 0,\n );\n return next;\n });\n }\n break;\n\n case 'Enter':\n e.preventDefault();\n if (isOpenRef.current && focusedIndex >= 0 && focusedIndex < filteredOptions.length) {\n handleOptionSelect(filteredOptions[focusedIndex]);\n } else if (allowFreeText && inputValue.trim()) {\n const trimmed = inputValue.trim();\n setCommittedValue(trimmed);\n onChange?.(trimmed);\n closeDropdown();\n }\n break;\n\n case 'Escape':\n e.preventDefault();\n if (isOpenRef.current) {\n closeDropdown(true /* revert */);\n }\n break;\n\n default:\n break;\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [\n disabled,\n filteredOptions,\n focusedIndex,\n allowFreeText,\n inputValue,\n onChange,\n openDropdown,\n closeDropdown,\n setCommittedValue,\n ],\n );\n\n // ─── Option selection ─────────────────────────────────────────────────────\n\n const handleOptionSelect = useCallback(\n (option: ComboboxOption) => {\n if (option.disabled) return;\n setInputValue(option.label);\n setCommittedValue(option.value);\n onChange?.(option.value);\n closeDropdown();\n // Return focus to the input so the user can continue interacting\n inputRef.current?.focus();\n },\n [onChange, closeDropdown, setInputValue, setCommittedValue],\n );\n\n // ─── Clear ────────────────────────────────────────────────────────────────\n\n const handleClearClick = useCallback(() => {\n setInputValue('');\n setCommittedValue('');\n onChange?.('');\n // Re-focus input so the user can immediately start typing again\n inputRef.current?.focus();\n }, [onChange, setInputValue, setCommittedValue]);\n\n // ─── Chevron toggle ───────────────────────────────────────────────────────\n\n const handleChevronClick = useCallback(() => {\n if (isOpenRef.current) {\n closeDropdown();\n } else {\n openDropdown();\n }\n }, [closeDropdown, openDropdown]);\n\n // ─── Render: individual option ────────────────────────────────────────────\n\n const renderOptionItem = useCallback(\n (option: ComboboxOption, index: number): React.ReactNode => {\n const isSelected = option.value === committedValue;\n const isFocused = index === focusedIndex;\n\n const classes = [\n 'eidos-combobox-option',\n isSelected && 'eidos-combobox-option--selected',\n isFocused && 'eidos-combobox-option--focused',\n option.disabled && 'eidos-combobox-option--disabled',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div\n key={option.id}\n ref={(el) => {\n optionRefs.current[index] = el;\n }}\n className={classes}\n onClick={() => handleOptionSelect(option)}\n onMouseEnter={() => !option.disabled && setFocusedIndex(index)}\n role=\"option\"\n aria-selected={isSelected}\n aria-disabled={option.disabled}\n id={`${uid}-option-${index}`}\n >\n {renderOption ? (\n renderOption(option)\n ) : (\n <>\n <Check\n className={`eidos-combobox-option-icon${\n !isSelected ? ' eidos-combobox-option-icon--hidden' : ''\n }`}\n />\n <span className=\"eidos-combobox-option-label\">{option.label}</span>\n {option.description && (\n <span className=\"eidos-combobox-option-description\">{option.description}</span>\n )}\n </>\n )}\n </div>\n );\n },\n [committedValue, focusedIndex, handleOptionSelect, renderOption, uid],\n );\n\n // ─── Render: dropdown content ─────────────────────────────────────────────\n\n const dropdownContent = useMemo(() => {\n if (loading) {\n return (\n <div className=\"eidos-combobox-loading\">\n <Loader2 className=\"eidos-combobox-loading-icon\" />\n <span>{loadingText}</span>\n </div>\n );\n }\n\n if (filteredOptions.length === 0) {\n return <div className=\"eidos-combobox-empty\">{emptyText}</div>;\n }\n\n return optionEntries.map((entry) => {\n if (entry.type === 'group') {\n return (\n <div key={entry.key} className=\"eidos-combobox-option-group-label\">\n {entry.group}\n </div>\n );\n }\n return renderOptionItem(entry.option, entry.index);\n });\n }, [loading, loadingText, filteredOptions.length, emptyText, optionEntries, renderOptionItem]);\n\n // ─── posIcon / posIconButton wiring ───────────────────────────────────────\n\n const hasClearableValue = clearable && !!inputValue;\n const posIcon = hasClearableValue ? X : ChevronDown;\n const posIconClick = hasClearableValue ? handleClearClick : handleChevronClick;\n\n // ─── CSS classes ──────────────────────────────────────────────────────────\n\n const containerClasses = [\n 'eidos-combobox',\n fullWidth && fullWidthModifier('eidos-combobox'),\n error && 'eidos-combobox--error',\n disabled && 'eidos-combobox--disabled',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const maxHeightValue = typeof maxHeight === 'number' ? `${maxHeight}px` : maxHeight;\n\n // ─── Render ───────────────────────────────────────────────────────────────\n\n return (\n // No ARIA on this wrapper.\n //\n // It carried `aria-expanded` and `aria-haspopup` while having no role at\n // all, which is invalid - both are only meaningful on an element whose\n // role supports them. They belong on the input, which is the combobox.\n <div ref={containerRef} className={containerClasses}>\n <div ref={comboboxTriggerRef} className=\"eidos-combobox-trigger\">\n {/*\n The Input is a direct child of eidos-combobox-trigger.\n It is NOT inside the Dropdown trigger div, so clicking it\n never bubbles to Dropdown.handleTriggerClick and never\n accidentally toggles the dropdown closed mid-edit.\n */}\n <Input\n ref={inputRef}\n value={inputValue}\n onChange={handleChange}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n placeholder={placeholder}\n disabled={disabled}\n size={size}\n fullWidth\n label={label}\n clearable={false} // we render our own clear via posIcon\n isSelect={false}\n posIcon={posIcon}\n posIconButton\n onPosIconClick={posIconClick}\n // The same button does two jobs depending on state, so the name\n // has to follow the icon - \"Clear\" on a chevron would be a lie.\n posIconLabel={hasClearableValue ? 'Clear selection' : 'Show options'}\n // The ARIA 1.2 combobox pattern: the input *is* the combobox.\n role=\"combobox\"\n aria-expanded={isOpen}\n // `Combobox` renders its own error message rather than passing\n // `error` down, so it does not inherit `Input`'s wiring and has to\n // associate the message itself (SC 3.3.1).\n aria-invalid={error ? true : undefined}\n aria-describedby={error ? `${uid}-error` : undefined}\n aria-autocomplete=\"list\"\n // Only while the listbox exists. `aria-controls` pointing at an id\n // that is not in the document is invalid, and that is what shipped\n // - the listbox only renders once the dropdown opens.\n aria-controls={isOpen ? `${uid}-listbox` : undefined}\n aria-activedescendant={focusedIndex >= 0 ? `${uid}-option-${focusedIndex}` : undefined}\n />\n\n {/*\n The Dropdown trigger is a 0-height span placed AFTER the Input\n in the normal document flow. Its getBoundingClientRect sits at\n exactly the bottom edge of the Input, giving the Dropdown correct\n placement without any click-toggle collision with the Input above.\n closeOnClickOutside and closeOnEscape are disabled because we own\n those interactions in our mousedown listener and onKeyDown handler.\n */}\n <Dropdown\n key={menuKey}\n trigger={\n <span\n ref={dropdownSpanRef}\n className=\"eidos-combobox-dropdown-anchor\"\n aria-hidden=\"true\"\n />\n }\n content={\n <div\n id={`${uid}-listbox`}\n className=\"eidos-combobox-options\"\n role=\"listbox\"\n aria-label={label ?? 'Options'}\n // Prevent the input from blurring when the user clicks an option,\n // and mark this event so the click-outside handler ignores it.\n onMouseDown={(e) => e.preventDefault()}\n >\n {dropdownContent}\n </div>\n }\n triggerRef={comboboxTriggerRef as React.RefObject<HTMLElement | null>}\n maxHeight={maxHeightValue}\n autoWidth\n closeOnClickOutside={false}\n closeOnEscape={false}\n />\n </div>\n\n {hint && !error && <span className=\"eidos-combobox-hint\">{hint}</span>}\n {error && (\n <span id={`${uid}-error`} className=\"eidos-combobox-error-message\">\n <CircleAlert className=\"eidos-combobox-error-icon\" />\n {error}\n </span>\n )}\n </div>\n );\n};\n\nCombobox.displayName = 'Combobox';\n"]}
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  fullWidthModifier
3
- } from "./chunk-EAJHEYZM.js";
3
+ } from "./chunk-WT4WBHBR.js";
4
4
 
5
5
  // src/components/Dropdown/Dropdown.context.types.ts
6
6
  import { createContext } from "react";
@@ -400,4 +400,4 @@ export {
400
400
  useDropdownContext,
401
401
  Dropdown
402
402
  };
403
- //# sourceMappingURL=chunk-6CPCNQKV.js.map
403
+ //# sourceMappingURL=chunk-67EXHO4T.js.map