eidos-ui 3.8.1 → 4.0.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 (244) hide show
  1. package/README.md +2 -2
  2. package/dist/alert/index.cjs +5 -5
  3. package/dist/alert/index.js +4 -4
  4. package/dist/button/index.cjs +4 -4
  5. package/dist/button/index.js +3 -3
  6. package/dist/chip/index.cjs +4 -4
  7. package/dist/chip/index.js +3 -3
  8. package/dist/{chunk-V5CM5TH3.js → chunk-2OBOD3GO.js} +3 -3
  9. package/dist/{chunk-CFVUUMQA.cjs → chunk-2URFSWJT.cjs} +6 -8
  10. package/dist/chunk-2URFSWJT.cjs.map +1 -0
  11. package/dist/{chunk-4S57PE43.js → chunk-2WDL2ZVP.js} +6 -7
  12. package/dist/chunk-2WDL2ZVP.js.map +1 -0
  13. package/dist/{chunk-V64DICJK.js → chunk-363IKX3C.js} +3 -3
  14. package/dist/{chunk-LWCFT5SP.cjs → chunk-3QBMSZSE.cjs} +3 -3
  15. package/dist/{chunk-LWCFT5SP.cjs.map → chunk-3QBMSZSE.cjs.map} +1 -1
  16. package/dist/{chunk-IC2PIK3E.js → chunk-43DJ3GGR.js} +4 -4
  17. package/dist/{chunk-L6ERHCQ2.js → chunk-57BVERWD.js} +3 -3
  18. package/dist/{chunk-AUNDBUHM.cjs → chunk-5HRVHEHE.cjs} +3 -3
  19. package/dist/{chunk-AUNDBUHM.cjs.map → chunk-5HRVHEHE.cjs.map} +1 -1
  20. package/dist/{chunk-6IB27I5K.cjs → chunk-6JYXGRJ3.cjs} +8 -8
  21. package/dist/{chunk-6IB27I5K.cjs.map → chunk-6JYXGRJ3.cjs.map} +1 -1
  22. package/dist/{chunk-NERASTO2.cjs → chunk-6ZFXIYH7.cjs} +3 -3
  23. package/dist/{chunk-NERASTO2.cjs.map → chunk-6ZFXIYH7.cjs.map} +1 -1
  24. package/dist/{chunk-IKXXXVUO.js → chunk-7TQUJ6BJ.js} +3 -3
  25. package/dist/{chunk-544RAXWO.cjs → chunk-7VMF6LIC.cjs} +19 -19
  26. package/dist/{chunk-544RAXWO.cjs.map → chunk-7VMF6LIC.cjs.map} +1 -1
  27. package/dist/{chunk-WTFEMOV5.cjs → chunk-ADB7QRX5.cjs} +16 -16
  28. package/dist/{chunk-WTFEMOV5.cjs.map → chunk-ADB7QRX5.cjs.map} +1 -1
  29. package/dist/{chunk-6CW5QSYV.cjs → chunk-AFGC62AL.cjs} +7 -7
  30. package/dist/{chunk-6CW5QSYV.cjs.map → chunk-AFGC62AL.cjs.map} +1 -1
  31. package/dist/{chunk-U4SVBE2M.js → chunk-AWPJH3UB.js} +4 -4
  32. package/dist/{chunk-B2OHBIAL.cjs → chunk-BKUZF7CW.cjs} +10 -11
  33. package/dist/chunk-BKUZF7CW.cjs.map +1 -0
  34. package/dist/{chunk-WR77IZUU.cjs → chunk-BPVOQLCA.cjs} +7 -7
  35. package/dist/{chunk-WR77IZUU.cjs.map → chunk-BPVOQLCA.cjs.map} +1 -1
  36. package/dist/{chunk-MCPGI6EI.js → chunk-BUSMGQJ4.js} +2 -2
  37. package/dist/{chunk-H3C6YECZ.js → chunk-D2PXPX56.js} +6 -6
  38. package/dist/{chunk-L6YJ6QTZ.js → chunk-DCUIT7SI.js} +2 -2
  39. package/dist/{chunk-HYRLK462.js → chunk-EDPCI2JC.js} +2 -2
  40. package/dist/{chunk-DPTTDHZ5.js → chunk-FAGQGGT3.js} +3 -3
  41. package/dist/{chunk-CNTG7OOO.js → chunk-FAXDWZQH.js} +12 -12
  42. package/dist/{chunk-7NUVLVSL.cjs → chunk-FJSK2RT7.cjs} +5 -5
  43. package/dist/{chunk-7NUVLVSL.cjs.map → chunk-FJSK2RT7.cjs.map} +1 -1
  44. package/dist/{chunk-P6OJQ2RN.js → chunk-FSX7DDLO.js} +8 -9
  45. package/dist/chunk-FSX7DDLO.js.map +1 -0
  46. package/dist/{chunk-XIUZT4TO.js → chunk-GE3QCXT7.js} +6 -7
  47. package/dist/chunk-GE3QCXT7.js.map +1 -0
  48. package/dist/{chunk-JY77VJAZ.js → chunk-GHUEVNNU.js} +3 -3
  49. package/dist/{chunk-4V2XYUQL.js → chunk-GLEPKX2R.js} +2 -2
  50. package/dist/{chunk-GZDT2AHJ.cjs → chunk-GRKC4PIX.cjs} +7 -7
  51. package/dist/{chunk-GZDT2AHJ.cjs.map → chunk-GRKC4PIX.cjs.map} +1 -1
  52. package/dist/{chunk-SLHIVEFW.cjs → chunk-HKLLKNRQ.cjs} +6 -9
  53. package/dist/chunk-HKLLKNRQ.cjs.map +1 -0
  54. package/dist/{chunk-2TIMJD4K.js → chunk-IBT535UH.js} +3 -3
  55. package/dist/{chunk-HR5MWA3B.cjs → chunk-IJW6YCJB.cjs} +5 -5
  56. package/dist/{chunk-HR5MWA3B.cjs.map → chunk-IJW6YCJB.cjs.map} +1 -1
  57. package/dist/{chunk-NNAEQR3Y.cjs → chunk-K6VEUJLY.cjs} +30 -30
  58. package/dist/{chunk-NNAEQR3Y.cjs.map → chunk-K6VEUJLY.cjs.map} +1 -1
  59. package/dist/{chunk-F5IRMMZ2.cjs → chunk-K73JO4FK.cjs} +7 -7
  60. package/dist/{chunk-F5IRMMZ2.cjs.map → chunk-K73JO4FK.cjs.map} +1 -1
  61. package/dist/{chunk-4HZIXRAJ.cjs → chunk-KF2OGUAD.cjs} +11 -12
  62. package/dist/chunk-KF2OGUAD.cjs.map +1 -0
  63. package/dist/{chunk-TJQNGJHP.js → chunk-KLHC5BHS.js} +4 -4
  64. package/dist/{chunk-XWMXEJVZ.js → chunk-KZKBZ2AV.js} +5 -7
  65. package/dist/chunk-KZKBZ2AV.js.map +1 -0
  66. package/dist/{chunk-DG3O5NV4.cjs → chunk-LLHR6QW3.cjs} +3 -3
  67. package/dist/{chunk-DG3O5NV4.cjs.map → chunk-LLHR6QW3.cjs.map} +1 -1
  68. package/dist/{chunk-GDRLVX2A.js → chunk-LXRNFQEI.js} +4 -4
  69. package/dist/{chunk-VXC7Z7XB.cjs → chunk-MKQVDEHI.cjs} +5 -6
  70. package/dist/chunk-MKQVDEHI.cjs.map +1 -0
  71. package/dist/{chunk-TNQ2ZZ7W.cjs → chunk-MUMTPMWD.cjs} +7 -7
  72. package/dist/{chunk-TNQ2ZZ7W.cjs.map → chunk-MUMTPMWD.cjs.map} +1 -1
  73. package/dist/{chunk-RHWZX7PB.js → chunk-NONYIHXD.js} +4 -4
  74. package/dist/{chunk-XPG56DLQ.cjs → chunk-NSA7ASZ7.cjs} +8 -8
  75. package/dist/{chunk-XPG56DLQ.cjs.map → chunk-NSA7ASZ7.cjs.map} +1 -1
  76. package/dist/{chunk-6NAOAKII.js → chunk-NWFGXLQP.js} +2 -2
  77. package/dist/{chunk-HLI4SOH3.cjs → chunk-NYGRVB2J.cjs} +45 -45
  78. package/dist/{chunk-HLI4SOH3.cjs.map → chunk-NYGRVB2J.cjs.map} +1 -1
  79. package/dist/{chunk-UUT2VEN5.cjs → chunk-OC2OBBGM.cjs} +7 -8
  80. package/dist/chunk-OC2OBBGM.cjs.map +1 -0
  81. package/dist/{chunk-3X6QVHTD.js → chunk-OERK3T7E.js} +3 -4
  82. package/dist/chunk-OERK3T7E.js.map +1 -0
  83. package/dist/{chunk-ZJWQPZ7E.js → chunk-OQWG7NLI.js} +3 -11
  84. package/dist/chunk-OQWG7NLI.js.map +1 -0
  85. package/dist/{chunk-U34INRFO.js → chunk-PP6HS4GR.js} +5 -16
  86. package/dist/chunk-PP6HS4GR.js.map +1 -0
  87. package/dist/{chunk-OGGZIFTI.cjs → chunk-PVNBH7XN.cjs} +36 -36
  88. package/dist/{chunk-OGGZIFTI.cjs.map → chunk-PVNBH7XN.cjs.map} +1 -1
  89. package/dist/{chunk-H46ZLPNJ.cjs → chunk-QDZVZY53.cjs} +7 -7
  90. package/dist/{chunk-H46ZLPNJ.cjs.map → chunk-QDZVZY53.cjs.map} +1 -1
  91. package/dist/{chunk-ENMDOQQO.cjs → chunk-R5WI5IGR.cjs} +6 -17
  92. package/dist/{chunk-ENMDOQQO.cjs.map → chunk-R5WI5IGR.cjs.map} +1 -1
  93. package/dist/{chunk-UTYY35QX.cjs → chunk-RZMQCVAS.cjs} +3 -3
  94. package/dist/{chunk-UTYY35QX.cjs.map → chunk-RZMQCVAS.cjs.map} +1 -1
  95. package/dist/{chunk-7FV2X62W.cjs → chunk-SJKD3WCV.cjs} +7 -7
  96. package/dist/{chunk-7FV2X62W.cjs.map → chunk-SJKD3WCV.cjs.map} +1 -1
  97. package/dist/{chunk-LUDK44NZ.cjs → chunk-SJPCBRKR.cjs} +3 -3
  98. package/dist/{chunk-LUDK44NZ.cjs.map → chunk-SJPCBRKR.cjs.map} +1 -1
  99. package/dist/{chunk-3TF2GZSG.js → chunk-SONL2RCW.js} +7 -7
  100. package/dist/{chunk-2IXCEKLI.js → chunk-SOS4K7VC.js} +2 -2
  101. package/dist/{chunk-WHQGJHMD.js → chunk-TOLNPD7S.js} +4 -4
  102. package/dist/{chunk-FE7S4RSK.js → chunk-U5KD4BWL.js} +7 -7
  103. package/dist/{chunk-FHOD3FUN.js → chunk-UTOTOWPS.js} +4 -4
  104. package/dist/{chunk-YIOHKQ6Y.cjs → chunk-VCG647BY.cjs} +5 -13
  105. package/dist/chunk-VCG647BY.cjs.map +1 -0
  106. package/dist/{chunk-N5NXKVFJ.cjs → chunk-VPN7AR7T.cjs} +10 -10
  107. package/dist/{chunk-N5NXKVFJ.cjs.map → chunk-VPN7AR7T.cjs.map} +1 -1
  108. package/dist/{chunk-6FXFKMJ5.js → chunk-XBIMNWE6.js} +3 -3
  109. package/dist/{chunk-Z3IJWYUD.js → chunk-XOUNVK45.js} +2 -2
  110. package/dist/{chunk-3VXUOAIJ.cjs → chunk-XR72A66Q.cjs} +3 -7
  111. package/dist/chunk-XR72A66Q.cjs.map +1 -0
  112. package/dist/{chunk-ULKWUKD2.cjs → chunk-YHSCUPP6.cjs} +22 -23
  113. package/dist/chunk-YHSCUPP6.cjs.map +1 -0
  114. package/dist/{chunk-S5CMZFX6.js → chunk-YPEJH57Z.js} +6 -7
  115. package/dist/chunk-YPEJH57Z.js.map +1 -0
  116. package/dist/{chunk-BO3KK3ZQ.js → chunk-YPPG7NLW.js} +2 -6
  117. package/dist/chunk-YPPG7NLW.js.map +1 -0
  118. package/dist/{chunk-PE2SLXUS.cjs → chunk-YWXS4IPH.cjs} +5 -5
  119. package/dist/{chunk-PE2SLXUS.cjs.map → chunk-YWXS4IPH.cjs.map} +1 -1
  120. package/dist/{chunk-UC4NYF6T.js → chunk-YYA5SWXD.js} +2 -2
  121. package/dist/{chunk-JFV56ISS.cjs → chunk-YZEALKC4.cjs} +6 -6
  122. package/dist/{chunk-JFV56ISS.cjs.map → chunk-YZEALKC4.cjs.map} +1 -1
  123. package/dist/{chunk-IHPSRTVW.js → chunk-Z3OEYDNI.js} +4 -7
  124. package/dist/chunk-Z3OEYDNI.js.map +1 -0
  125. package/dist/{chunk-MKC6V3SY.cjs → chunk-Z6FZ7GI5.cjs} +6 -6
  126. package/dist/{chunk-MKC6V3SY.cjs.map → chunk-Z6FZ7GI5.cjs.map} +1 -1
  127. package/dist/{chunk-NFD7MPX4.cjs → chunk-ZVA5KJAJ.cjs} +11 -11
  128. package/dist/{chunk-NFD7MPX4.cjs.map → chunk-ZVA5KJAJ.cjs.map} +1 -1
  129. package/dist/color-picker/index.cjs +4 -4
  130. package/dist/color-picker/index.js +3 -3
  131. package/dist/combobox/index.cjs +6 -6
  132. package/dist/combobox/index.js +5 -5
  133. package/dist/command-palette/index.cjs +3 -3
  134. package/dist/command-palette/index.js +2 -2
  135. package/dist/context-menu/index.cjs +6 -6
  136. package/dist/context-menu/index.js +5 -5
  137. package/dist/conversation/index.cjs +8 -8
  138. package/dist/conversation/index.js +7 -7
  139. package/dist/data-grid/index.cjs +15 -15
  140. package/dist/data-grid/index.js +14 -14
  141. package/dist/date-picker/index.cjs +8 -8
  142. package/dist/date-picker/index.js +7 -7
  143. package/dist/drawer/index.cjs +5 -5
  144. package/dist/drawer/index.js +4 -4
  145. package/dist/dropdown/index.cjs +3 -3
  146. package/dist/dropdown/index.js +2 -2
  147. package/dist/header/index.cjs +6 -6
  148. package/dist/header/index.js +5 -5
  149. package/dist/index.cjs +38 -38
  150. package/dist/index.js +37 -37
  151. package/dist/inline-edit/index.cjs +5 -5
  152. package/dist/inline-edit/index.js +4 -4
  153. package/dist/input/index.cjs +4 -4
  154. package/dist/input/index.js +3 -3
  155. package/dist/menu/index.cjs +5 -5
  156. package/dist/menu/index.js +4 -4
  157. package/dist/modal/index.cjs +5 -5
  158. package/dist/modal/index.js +4 -4
  159. package/dist/navigation/index.cjs +5 -5
  160. package/dist/navigation/index.js +4 -4
  161. package/dist/number-input/index.cjs +2 -4
  162. package/dist/number-input/index.cjs.map +1 -1
  163. package/dist/number-input/index.js +1 -3
  164. package/dist/page-layout/index.cjs +12 -12
  165. package/dist/page-layout/index.js +11 -11
  166. package/dist/pagination/index.cjs +8 -8
  167. package/dist/pagination/index.js +7 -7
  168. package/dist/popover/index.cjs +3 -3
  169. package/dist/popover/index.d.cts +1 -3
  170. package/dist/popover/index.d.ts +1 -3
  171. package/dist/popover/index.js +2 -2
  172. package/dist/segmented-control/index.cjs +4 -4
  173. package/dist/segmented-control/index.js +3 -3
  174. package/dist/select/index.cjs +6 -6
  175. package/dist/select/index.js +5 -5
  176. package/dist/snackbar/index.cjs +5 -5
  177. package/dist/snackbar/index.js +4 -4
  178. package/dist/split-button/index.cjs +6 -6
  179. package/dist/split-button/index.js +5 -5
  180. package/dist/split-chip/index.cjs +5 -5
  181. package/dist/split-chip/index.js +4 -4
  182. package/dist/table/index.cjs +13 -13
  183. package/dist/table/index.js +12 -12
  184. package/dist/tabs/index.cjs +3 -3
  185. package/dist/tabs/index.js +2 -2
  186. package/dist/tag-input/index.cjs +6 -6
  187. package/dist/tag-input/index.js +5 -5
  188. package/dist/textarea/index.cjs +4 -4
  189. package/dist/textarea/index.js +3 -3
  190. package/dist/theme-editor/index.cjs +11 -11
  191. package/dist/theme-editor/index.js +10 -10
  192. package/dist/theme-provider/index.cjs +3 -3
  193. package/dist/theme-provider/index.js +2 -2
  194. package/dist/toolbar/index.cjs +8 -8
  195. package/dist/toolbar/index.js +7 -7
  196. package/dist/tooltip/index.cjs +3 -3
  197. package/dist/tooltip/index.js +2 -2
  198. package/package.json +4 -2
  199. package/dist/chunk-3VXUOAIJ.cjs.map +0 -1
  200. package/dist/chunk-3X6QVHTD.js.map +0 -1
  201. package/dist/chunk-4HZIXRAJ.cjs.map +0 -1
  202. package/dist/chunk-4S57PE43.js.map +0 -1
  203. package/dist/chunk-B2OHBIAL.cjs.map +0 -1
  204. package/dist/chunk-BO3KK3ZQ.js.map +0 -1
  205. package/dist/chunk-CFVUUMQA.cjs.map +0 -1
  206. package/dist/chunk-IHPSRTVW.js.map +0 -1
  207. package/dist/chunk-P6OJQ2RN.js.map +0 -1
  208. package/dist/chunk-S5CMZFX6.js.map +0 -1
  209. package/dist/chunk-SLHIVEFW.cjs.map +0 -1
  210. package/dist/chunk-U34INRFO.js.map +0 -1
  211. package/dist/chunk-ULKWUKD2.cjs.map +0 -1
  212. package/dist/chunk-UUT2VEN5.cjs.map +0 -1
  213. package/dist/chunk-VXC7Z7XB.cjs.map +0 -1
  214. package/dist/chunk-XIUZT4TO.js.map +0 -1
  215. package/dist/chunk-XWMXEJVZ.js.map +0 -1
  216. package/dist/chunk-YIOHKQ6Y.cjs.map +0 -1
  217. package/dist/chunk-ZJWQPZ7E.js.map +0 -1
  218. /package/dist/{chunk-V5CM5TH3.js.map → chunk-2OBOD3GO.js.map} +0 -0
  219. /package/dist/{chunk-V64DICJK.js.map → chunk-363IKX3C.js.map} +0 -0
  220. /package/dist/{chunk-IC2PIK3E.js.map → chunk-43DJ3GGR.js.map} +0 -0
  221. /package/dist/{chunk-L6ERHCQ2.js.map → chunk-57BVERWD.js.map} +0 -0
  222. /package/dist/{chunk-IKXXXVUO.js.map → chunk-7TQUJ6BJ.js.map} +0 -0
  223. /package/dist/{chunk-U4SVBE2M.js.map → chunk-AWPJH3UB.js.map} +0 -0
  224. /package/dist/{chunk-MCPGI6EI.js.map → chunk-BUSMGQJ4.js.map} +0 -0
  225. /package/dist/{chunk-H3C6YECZ.js.map → chunk-D2PXPX56.js.map} +0 -0
  226. /package/dist/{chunk-L6YJ6QTZ.js.map → chunk-DCUIT7SI.js.map} +0 -0
  227. /package/dist/{chunk-HYRLK462.js.map → chunk-EDPCI2JC.js.map} +0 -0
  228. /package/dist/{chunk-DPTTDHZ5.js.map → chunk-FAGQGGT3.js.map} +0 -0
  229. /package/dist/{chunk-CNTG7OOO.js.map → chunk-FAXDWZQH.js.map} +0 -0
  230. /package/dist/{chunk-JY77VJAZ.js.map → chunk-GHUEVNNU.js.map} +0 -0
  231. /package/dist/{chunk-4V2XYUQL.js.map → chunk-GLEPKX2R.js.map} +0 -0
  232. /package/dist/{chunk-2TIMJD4K.js.map → chunk-IBT535UH.js.map} +0 -0
  233. /package/dist/{chunk-TJQNGJHP.js.map → chunk-KLHC5BHS.js.map} +0 -0
  234. /package/dist/{chunk-GDRLVX2A.js.map → chunk-LXRNFQEI.js.map} +0 -0
  235. /package/dist/{chunk-RHWZX7PB.js.map → chunk-NONYIHXD.js.map} +0 -0
  236. /package/dist/{chunk-6NAOAKII.js.map → chunk-NWFGXLQP.js.map} +0 -0
  237. /package/dist/{chunk-3TF2GZSG.js.map → chunk-SONL2RCW.js.map} +0 -0
  238. /package/dist/{chunk-2IXCEKLI.js.map → chunk-SOS4K7VC.js.map} +0 -0
  239. /package/dist/{chunk-WHQGJHMD.js.map → chunk-TOLNPD7S.js.map} +0 -0
  240. /package/dist/{chunk-FE7S4RSK.js.map → chunk-U5KD4BWL.js.map} +0 -0
  241. /package/dist/{chunk-FHOD3FUN.js.map → chunk-UTOTOWPS.js.map} +0 -0
  242. /package/dist/{chunk-6FXFKMJ5.js.map → chunk-XBIMNWE6.js.map} +0 -0
  243. /package/dist/{chunk-Z3IJWYUD.js.map → chunk-XOUNVK45.js.map} +0 -0
  244. /package/dist/{chunk-UC4NYF6T.js.map → chunk-YYA5SWXD.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-ENMDOQQO.cjs","../src/utils/renderIcon.tsx","../src/utils/devWarn.ts","../src/utils/dualModifier.ts","../src/utils/useDialogFocus.ts","../src/utils/useIsClient.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACA;ACJA,2CAAsB;ADMtB;AACA;AEOA,IAAM,OAAA,kBAAS,IAAI,GAAA,CAAY,CAAA;AAExB,SAAS,OAAA,CAAQ,GAAA,EAAa,OAAA,EAAuB;AAC1D,EAAA,MAAM,QAAA,kBAAW,UAAA,mBAA6D,OAAA,6BAAS,GAAA,6BACnF,UAAA;AACJ,EAAA,GAAA,CAAI,QAAA,IAAY,YAAA,EAAc,MAAA;AAC9B,EAAA,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAG,MAAA;AACrB,EAAA,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AACd,EAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,WAAA,EAAc,OAAO,CAAA,CAAA;AACpC;AFPqC;AACA;ACiBxB;AAN0C;AACnC,EAAA;AAEY,EAAA;AACT,IAAA;AACH,IAAA;AACN,MAAA;AACV,IAAA;AAQ+B,IAAA;AACwB,IAAA;AAEvC,IAAA;AACd,MAAA;AAC0B,QAAA;AACX,QAAA;AACf,MAAA;AACQ,MAAA;AACV,IAAA;AAGQ,IAAA;AACV,EAAA;AAGsB,EAAA;AACd,EAAA;AACV;ADrBqC;AACA;AGdO;AAK1C;AHYmC;AACA;AI9CK;AA+CR;AAChC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACQ;AASA;AAGR;AACqC,EAAA;AACrC;AAGgC;AAqBhC;AAGgB,EAAA;AACiB,IAAA;AACJ,IAAA;AAMD,IAAA;AAEF,IAAA;AAeL,IAAA;AACP,IAAA;AACG,IAAA;AAEQ,IAAA;AACQ,MAAA;AACjB,MAAA;AACG,QAAA;AACR,MAAA;AAIuB,QAAA;AACZ,QAAA;AAClB,MAAA;AAEwB,MAAA;AACV,QAAA;AACJ,QAAA;AACV,MAAA;AACF,IAAA;AAES,IAAA;AAEmC,IAAA;AACjB,MAAA;AAED,MAAA;AAKO,MAAA;AACH,MAAA;AACL,QAAA;AACrB,QAAA;AACF,MAAA;AAEyB,MAAA;AACF,MAAA;AACQ,MAAA;AAIR,MAAA;AACA,QAAA;AACI,QAAA;AACzB,QAAA;AACF,MAAA;AAEsB,MAAA;AACC,QAAA;AACV,QAAA;AACiB,MAAA;AACP,QAAA;AACT,QAAA;AACd,MAAA;AACF,IAAA;AAEsB,IAAA;AAET,IAAA;AACe,MAAA;AACG,MAAA;AAEL,MAAA;AACI,MAAA;AAeJ,MAAA;AACM,MAAA;AAEV,MAAA;AACM,QAAA;AAC1B,MAAA;AACF,IAAA;AACwB,EAAA;AAC5B;AJvFqC;AACA;AKjIjB;AA4CsB;AACR,EAAA;AAEhB,EAAA;AACE,IAAA;AACb,EAAA;AAEE,EAAA;AACT;ALsFqC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-ENMDOQQO.cjs","sourcesContent":[null,"import React from 'react';\nimport { icons } from 'lucide-react';\nimport { devWarn } from './devWarn';\nimport { resolveRegisteredIcon, toIconKey, type IconComponent } from './iconRegistry';\n\nexport type IconType = IconComponent | string;\n\n/**\n * Renders an icon prop.\n *\n * @param icon - An icon component, or a string: a name registered with\n * `registerIcons`, or CSS classes for an icon font.\n * @param className - Optional CSS class name to apply to the icon.\n * @returns React node representing the icon, or null if no icon provided.\n *\n * @example\n * // Component - the recommended form; only the icons you import are bundled\n * import { Heart } from 'lucide-react';\n * renderIcon(Heart, 'my-icon-class');\n *\n * @example\n * // Registered name\n * registerIcons({ Heart });\n * renderIcon('heart', 'my-icon-class');\n *\n * @example\n * // CSS classes for an icon font (Font Awesome, Remixicon, ...)\n * renderIcon('fas fa-heart', 'my-icon-class');\n */\nexport const renderIcon = (icon: IconType | undefined, className?: string): React.ReactNode => {\n if (!icon) return null;\n\n if (typeof icon === 'string') {\n const Registered = resolveRegisteredIcon(icon);\n if (Registered) {\n return <Registered className={className} aria-hidden=\"true\" />;\n }\n\n // Deprecated fallback, removed in 4.0: resolving an unregistered name\n // against Lucide's full `icons` map. Referencing that map is what puts\n // every Lucide icon (~1,800 modules) into a consumer's bundle, however\n // few they use - no bundler can tree-shake a lookup by a runtime string.\n // It stays for one minor so existing string names keep working while\n // the warning below points at the migration.\n const iconName = toIconKey(icon);\n const LucideIcon = icons[iconName as keyof typeof icons] as IconComponent | undefined;\n\n if (LucideIcon) {\n devWarn(\n `icon-string-fallback-${iconName}`,\n `Icon \"${icon}\" was resolved by name from the full Lucide icon set. That lookup is deprecated and is removed in 4.0, because it bundles every Lucide icon. Pass the component instead (\\`import { ${iconName} } from 'lucide-react'\\`), register it once with \\`registerIcons({ ${iconName} })\\`, or \\`import 'eidos-ui/lucide-icons'\\` to register them all.`,\n );\n return <LucideIcon className={className} aria-hidden=\"true\" />;\n }\n\n // Fallback: render as a CSS class (for Font Awesome, Remixicon, etc.)\n return <i className={`${icon} ${className || ''}`} aria-hidden=\"true\" />;\n }\n\n // It's a React component\n const IconComponent = icon;\n return <IconComponent className={className} aria-hidden=\"true\" />;\n};\n","/**\n * Logs a misconfiguration warning, once per `key`, and never in production.\n *\n * Deliberately reads `process.env.NODE_ENV` off `globalThis` behind a cast\n * rather than referencing `process` directly: this is a browser library, and\n * a bare `process` reference fails the `tsup` dts build (its worker resolves\n * without node types, so `npm run typecheck` passing is not enough) as well\n * as throwing at runtime anywhere a bundler hasn't substituted it. The\n * optional chaining covers every case - no `process`, no `env`, no value.\n *\n * Because the check is dynamic rather than a statically replaceable\n * `process.env.NODE_ENV` expression, the message text stays in production\n * bundles; only the logging is skipped. That is the trade for not shipping a\n * `process` reference at all, and these strings are small.\n */\nconst warned = new Set<string>();\n\nexport function devWarn(key: string, message: string): void {\n const nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env\n ?.NODE_ENV;\n if (nodeEnv === 'production') return;\n if (warned.has(key)) return;\n warned.add(key);\n console.warn(`[eidos-ui] ${message}`);\n}\n","/**\n * Emits a BEM modifier in both its canonical kebab-case spelling and a legacy\n * camelCase one.\n *\n * The library shipped two conventions for the same idea: eight components\n * used `--fullWidth` while four used `--full-width`, and `Tabs` had\n * `--hideScrollbar`. Kebab-case is the canonical form - every block name\n * (`eidos-date-picker-trigger`) and every design token (`--font-size-sm`) is\n * already kebab, so a camelCase modifier was inconsistent with the very\n * selector it hung off.\n *\n * Renaming outright would be a **breaking** change: `README.md` presents the\n * `eidos-*` class names as things consumers may target, so a stylesheet out\n * there is matching the old spelling. Emitting both keeps every existing\n * selector working while new code has one spelling to learn.\n *\n * Deliberately a helper rather than a duplicated string literal at each call\n * site: two near-identical classes in a `className` read as a copy-paste slip\n * and invite exactly the \"tidy up\" that would silently break those consumer\n * stylesheets. It also makes dropping the aliases at the next major a change\n * to this one file rather than an edit in every component.\n *\n * Internal only - deliberately not re-exported from `src/index.ts`.\n *\n * @example\n * dualModifier('eidos-input', 'full-width', 'fullWidth');\n * // 'eidos-input--full-width eidos-input--fullWidth'\n */\nexport const dualModifier = (block: string, canonical: string, legacy: string): string =>\n `${block}--${canonical} ${block}--${legacy}`;\n\n/** `dualModifier` preset for the library's most widespread split modifier. */\nexport const fullWidthModifier = (block: string): string =>\n dualModifier(block, 'full-width', 'fullWidth');\n","import { useEffect, type RefObject } from 'react';\n\n/**\n * Focus management for a dialog: move focus in on open, optionally trap Tab\n * inside it, and restore focus to the opener on close.\n *\n * Named for the job rather than the mechanism because the trap is optional.\n * `Popover` declares `aria-modal=\"false\"` - an honest non-modal dialog - so\n * trapping Tab in it would be wrong, but it still needs the other two: its\n * panel is portaled to `document.body`, so without moving focus in, Tab from\n * the trigger goes to whatever follows it in the page and the panel's own\n * controls are unreachable by keyboard entirely.\n *\n * ## Why this exists\n *\n * `Modal`, `Drawer` and `CommandPalette` all rendered\n * `role=\"dialog\" aria-modal=\"true\"` with no focus management whatsoever. That\n * attribute is a **promise to assistive technology that the rest of the page\n * is inert**, and it was false: measured in a browser, focus never entered the\n * dialog, and Tab moved to the page behind the scrim on the first press\n * (Drawer on the second). Drawer additionally dropped focus onto `<body>` when\n * it closed, so a keyboard user was returned to the top of the document.\n *\n * That is WCAG 2.4.3 Focus Order (Level A), and it is invisible to axe - a\n * static snapshot of the DOM looks perfectly correct.\n *\n * ## Nesting\n *\n * Traps register on a module-level stack and only the innermost one acts, so a\n * dialog opened from a dialog behaves correctly. Without this, both listeners\n * fire for the same Tab and fight over where focus lands.\n *\n * ## What this does *not* do\n *\n * It does not mark the background `inert`. A trap plus `aria-modal` is the\n * widely-supported approach and is what screen readers act on; `inert` on\n * every sibling of the portal root would be stronger, but it needs the\n * component to know about DOM it does not own. Worth revisiting if a\n * consumer reports a screen reader escaping the dialog in browse mode.\n */\n\n/**\n * Deliberately not `[tabindex]` in general - that would match `tabindex=\"-1\"`,\n * which is programmatically focusable but explicitly removed from the Tab\n * sequence, so including it would make Tab stop somewhere the user cannot\n * reach by tabbing in the first place.\n */\nexport const FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled]):not([type=\"hidden\"])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'details > summary:first-of-type',\n 'iframe',\n 'audio[controls]',\n 'video[controls]',\n '[contenteditable]:not([contenteditable=\"false\"])',\n '[tabindex]:not([tabindex^=\"-\"])',\n].join(',');\n\n/**\n * `offsetParent === null` is the usual visibility check and is wrong here: it\n * is also null for `position: fixed` elements, which is exactly what a modal\n * is. `getClientRects()` is empty only when the element genuinely does not\n * render.\n */\nconst isVisible = (element: HTMLElement): boolean =>\n element.getClientRects().length > 0 && getComputedStyle(element).visibility !== 'hidden';\n\nconst getFocusable = (container: HTMLElement): HTMLElement[] =>\n Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n (element) => isVisible(element) && element.closest('[aria-hidden=\"true\"]') === null,\n );\n\n/** Innermost trap last. Only the last entry responds to Tab. */\nconst trapStack: HTMLElement[] = [];\n\nexport interface UseDialogFocusOptions {\n /** Focused when the trap activates. Defaults to the first focusable child. */\n initialFocus?: RefObject<HTMLElement | null>;\n /**\n * Whether to return focus to whatever had it when the trap activated.\n * Defaults to `true`; pass `false` when the caller restores focus itself.\n */\n restoreFocus?: boolean;\n /**\n * Whether Tab is confined to the container. Defaults to `true`.\n *\n * Set `false` for a non-modal dialog (`aria-modal=\"false\"`), where the rest\n * of the page stays available and trapping would strand the user.\n */\n trapTab?: boolean;\n}\n\nexport const useDialogFocus = (\n active: boolean,\n containerRef: RefObject<HTMLElement | null>,\n { initialFocus, restoreFocus = true, trapTab = true }: UseDialogFocusOptions = {},\n): void => {\n useEffect(() => {\n const container = containerRef.current;\n if (!active || !container) return;\n\n // Captured before focus moves. The caller must only flip `active` to true\n // once the container is in the DOM - for the animated overlays that means\n // `isOpen && isMounted`, since `isMounted` is set in an effect one render\n // later and the container does not exist before it.\n const previouslyFocused = document.activeElement as HTMLElement | null;\n\n trapStack.push(container);\n\n // Moving focus in is retried across a few frames rather than attempted\n // once.\n //\n // These overlays animate open, and `.focus()` on an element that is still\n // `visibility: hidden` is a silent no-op - it does not throw, it just\n // leaves focus where it was. `Modal` sets its `--is-open` class two\n // animation frames after mounting, and the computed style has not caught\n // up at the moment the effect runs, so a single attempt focused nothing\n // and the trap looked broken.\n //\n // Retrying is better than keying off any particular animation: the hook\n // stays ignorant of each component's transition duration, and simply\n // stops as soon as focus has actually landed inside.\n const MAX_FRAMES = 10;\n let frame = 0;\n let attempts = 0;\n\n const tryFocus = () => {\n const target = initialFocus?.current ?? getFocusable(container)[0];\n if (target) {\n target.focus();\n } else {\n // A dialog with nothing focusable in it still must not leave focus on\n // the page behind, so the container takes it. `tabindex=\"-1\"` keeps\n // it out of the Tab sequence while allowing `.focus()`.\n if (!container.hasAttribute('tabindex')) container.setAttribute('tabindex', '-1');\n container.focus();\n }\n\n if (!container.contains(document.activeElement) && attempts < MAX_FRAMES) {\n attempts += 1;\n frame = requestAnimationFrame(tryFocus);\n }\n };\n\n tryFocus();\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Tab') return;\n // Only the innermost trap acts.\n if (trapStack[trapStack.length - 1] !== container) return;\n\n // Re-queried on every Tab rather than cached: dialog contents change\n // (a disabled Confirm button becoming enabled, a list filtering down),\n // and a stale list sends focus to an element that is no longer there.\n const focusable = getFocusable(container);\n if (focusable.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeElement = document.activeElement as HTMLElement | null;\n\n // Focus outside the container - e.g. a click landed on the backdrop.\n // Pull it back in rather than letting Tab continue through the page.\n if (!activeElement || !container.contains(activeElement)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n return;\n }\n\n if (event.shiftKey && activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n\n if (trapTab) document.addEventListener('keydown', onKeyDown, true);\n\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener('keydown', onKeyDown, true);\n\n const index = trapStack.lastIndexOf(container);\n if (index !== -1) trapStack.splice(index, 1);\n\n // Restore only if focus still belongs to the closing dialog.\n //\n // Two cases count as \"belongs\":\n //\n // 1. Focus is still inside the container.\n // 2. Focus has been lost to `<body>`. When the overlay hides, the\n // browser blurs whatever was focused inside it, so by the time this\n // cleanup runs `activeElement` is often already `<body>` - checking\n // only case 1 meant `CommandPalette` never restored at all.\n //\n // Anything else means something took focus deliberately - a confirm\n // action moving to a new region, say - and stealing it back would be\n // worse than doing nothing.\n const active = document.activeElement;\n const focusIsOurs = container.contains(active) || active === document.body || active === null;\n\n if (restoreFocus && focusIsOurs && previouslyFocused?.isConnected) {\n previouslyFocused.focus();\n }\n };\n }, [active, containerRef, initialFocus, restoreFocus, trapTab]);\n};\n","import { useEffect, useState } from 'react';\n\n/**\n * `false` on the server and on the very first client render, `true` from the\n * first effect onwards.\n *\n * ## Why this exists\n *\n * Every overlay in this library renders through `createPortal(…,\n * document.body)`. A portal is a client-only construct: there is no\n * `document` during `renderToString`, so any overlay that is *already open on\n * its first render* does not merely render oddly - it throws, and takes the\n * whole server render down with it. Measured against the built package:\n *\n * ```\n * renderToString(<Modal isOpen>) ReferenceError: document is not defined\n * renderToString(<Dropdown defaultOpen>) ReferenceError: DOMRect is not defined\n * renderToString(<Select autoOpen>) ReferenceError: DOMRect is not defined\n * ```\n *\n * `Modal`, `Drawer` and `CommandPalette` each keep an `isMounted` flag, which\n * looks like it would prevent this and does not: it is initialised to\n * `useState(isOpen)`, so it is already `true` on the first render. It exists\n * to sequence the open/close *animation*, not to defer the portal.\n *\n * With this hook the server renders nothing for the panel, and the portal\n * appears on the client after mount.\n *\n * ## Why a state flag rather than `typeof document !== 'undefined'`\n *\n * That check is `true` during hydration, so the client's first render would\n * produce the portal while the server's produced nothing - a hydration\n * mismatch, which React resolves by discarding and re-rendering the subtree.\n * A state flag set in an effect makes the first client render agree with the\n * server by construction, and the portal arrive one render later.\n *\n * ## Scope\n *\n * Only for components that can be open on their first render - `Dropdown`\n * (`defaultOpen`), `Popover`, `Modal`, `Drawer`, `CommandPalette`. `Tooltip`,\n * `ContextMenu` and `Snackbar` can only open in response to an event, which\n * cannot happen during a server render, so they need nothing. `check-ssr.js`\n * asserts all of them either way.\n */\nexport const useIsClient = (): boolean => {\n const [isClient, setIsClient] = useState(false);\n\n useEffect(() => {\n setIsClient(true);\n }, []);\n\n return isClient;\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-R5WI5IGR.cjs","../src/utils/devWarn.ts","../src/utils/renderIcon.tsx","../src/utils/useDialogFocus.ts","../src/utils/useIsClient.ts"],"names":[],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACA;ACUA,IAAM,OAAA,kBAAS,IAAI,GAAA,CAAY,CAAA;AAExB,SAAS,OAAA,CAAQ,GAAA,EAAa,OAAA,EAAuB;AAC1D,EAAA,MAAM,QAAA,kBAAW,UAAA,mBAA6D,OAAA,6BAAS,GAAA,6BACnF,UAAA;AACJ,EAAA,GAAA,CAAI,QAAA,IAAY,YAAA,EAAc,MAAA;AAC9B,EAAA,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA,EAAG,MAAA;AACrB,EAAA,MAAA,CAAO,GAAA,CAAI,GAAG,CAAA;AACd,EAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,WAAA,EAAc,OAAO,CAAA,CAAA;AACpC;ADVqC;AACA;AEmBxB;AAN0C;AACnC,EAAA;AAEY,EAAA;AACT,IAAA;AACH,IAAA;AACN,MAAA;AACV,IAAA;AAasB,IAAA;AACW,MAAA;AAC/B,MAAA;AAC+B,QAAA;AAChB,QAAA;AACf,MAAA;AACF,IAAA;AAEQ,IAAA;AACV,EAAA;AAGsB,EAAA;AACd,EAAA;AACV;AF1BqC;AACA;AGrCK;AA+CR;AAChC,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACQ;AASA;AAGR;AACqC,EAAA;AACrC;AAGgC;AAqBhC;AAGgB,EAAA;AACiB,IAAA;AACJ,IAAA;AAMD,IAAA;AAEF,IAAA;AAeL,IAAA;AACP,IAAA;AACG,IAAA;AAEQ,IAAA;AACQ,MAAA;AACjB,MAAA;AACG,QAAA;AACR,MAAA;AAIuB,QAAA;AACZ,QAAA;AAClB,MAAA;AAEwB,MAAA;AACV,QAAA;AACJ,QAAA;AACV,MAAA;AACF,IAAA;AAES,IAAA;AAEmC,IAAA;AACjB,MAAA;AAED,MAAA;AAKO,MAAA;AACH,MAAA;AACL,QAAA;AACrB,QAAA;AACF,MAAA;AAEyB,MAAA;AACF,MAAA;AACQ,MAAA;AAIR,MAAA;AACA,QAAA;AACI,QAAA;AACzB,QAAA;AACF,MAAA;AAEsB,MAAA;AACC,QAAA;AACV,QAAA;AACiB,MAAA;AACP,QAAA;AACT,QAAA;AACd,MAAA;AACF,IAAA;AAEsB,IAAA;AAET,IAAA;AACe,MAAA;AACG,MAAA;AAEL,MAAA;AACI,MAAA;AAeJ,MAAA;AACM,MAAA;AAEV,MAAA;AACM,QAAA;AAC1B,MAAA;AACF,IAAA;AACwB,EAAA;AAC5B;AHhGqC;AACA;AIxHjB;AA4CsB;AACR,EAAA;AAEhB,EAAA;AACE,IAAA;AACb,EAAA;AAEE,EAAA;AACT;AJ6EqC;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-R5WI5IGR.cjs","sourcesContent":[null,"/**\n * Logs a misconfiguration warning, once per `key`, and never in production.\n *\n * Deliberately reads `process.env.NODE_ENV` off `globalThis` behind a cast\n * rather than referencing `process` directly: this is a browser library, and\n * a bare `process` reference fails the `tsup` dts build (its worker resolves\n * without node types, so `npm run typecheck` passing is not enough) as well\n * as throwing at runtime anywhere a bundler hasn't substituted it. The\n * optional chaining covers every case - no `process`, no `env`, no value.\n *\n * Because the check is dynamic rather than a statically replaceable\n * `process.env.NODE_ENV` expression, the message text stays in production\n * bundles; only the logging is skipped. That is the trade for not shipping a\n * `process` reference at all, and these strings are small.\n */\nconst warned = new Set<string>();\n\nexport function devWarn(key: string, message: string): void {\n const nodeEnv = (globalThis as { process?: { env?: { NODE_ENV?: string } } }).process?.env\n ?.NODE_ENV;\n if (nodeEnv === 'production') return;\n if (warned.has(key)) return;\n warned.add(key);\n console.warn(`[eidos-ui] ${message}`);\n}\n","import React from 'react';\nimport { devWarn } from './devWarn';\nimport { resolveRegisteredIcon, toIconKey, type IconComponent } from './iconRegistry';\n\nexport type IconType = IconComponent | string;\n\n/**\n * Renders an icon prop.\n *\n * @param icon - An icon component, or a string: a name registered with\n * `registerIcons`, or CSS classes for an icon font.\n * @param className - Optional CSS class name to apply to the icon.\n * @returns React node representing the icon, or null if no icon provided.\n *\n * @example\n * // Component - the recommended form; only the icons you import are bundled\n * import { Heart } from 'lucide-react';\n * renderIcon(Heart, 'my-icon-class');\n *\n * @example\n * // Registered name\n * registerIcons({ Heart });\n * renderIcon('heart', 'my-icon-class');\n *\n * @example\n * // CSS classes for an icon font (Font Awesome, Remixicon, ...)\n * renderIcon('fas fa-heart', 'my-icon-class');\n */\nexport const renderIcon = (icon: IconType | undefined, className?: string): React.ReactNode => {\n if (!icon) return null;\n\n if (typeof icon === 'string') {\n const Registered = resolveRegisteredIcon(icon);\n if (Registered) {\n return <Registered className={className} aria-hidden=\"true\" />;\n }\n\n // No lookup against Lucide's full `icons` map. There was one until 4.0,\n // and referencing that map put every Lucide icon (~1,800 modules) into\n // every consumer's bundle, however few they used - no bundler can\n // tree-shake a lookup by a runtime string. Do not reintroduce it: a\n // consumer who wants every name opts in with `eidos-ui/lucide-icons`.\n //\n // An unregistered string is treated as icon-font classes. A single token\n // with no space is far more often a forgotten registration than a font\n // class, so it warns - once per name. The cost is one dev-only warning\n // for single-class fonts (Remixicon's `ri-home-line`); the alternative is\n // an upgrade that silently renders empty `<i>` elements where icons were.\n if (!/\\s/.test(icon)) {\n const iconName = toIconKey(icon);\n devWarn(\n `icon-unregistered-${iconName}`,\n `Icon \"${icon}\" is not registered, so it is rendered as the CSS class \"${icon}\". If it is a Lucide icon, pass the component (\\`import { ${iconName} } from 'lucide-react'\\`), register it once with \\`registerIcons({ ${iconName} })\\`, or \\`import 'eidos-ui/lucide-icons'\\` to register them all. If it is an icon-font class, ignore this.`,\n );\n }\n\n return <i className={`${icon} ${className || ''}`} aria-hidden=\"true\" />;\n }\n\n // It's a React component\n const IconComponent = icon;\n return <IconComponent className={className} aria-hidden=\"true\" />;\n};\n","import { useEffect, type RefObject } from 'react';\n\n/**\n * Focus management for a dialog: move focus in on open, optionally trap Tab\n * inside it, and restore focus to the opener on close.\n *\n * Named for the job rather than the mechanism because the trap is optional.\n * `Popover` declares `aria-modal=\"false\"` - an honest non-modal dialog - so\n * trapping Tab in it would be wrong, but it still needs the other two: its\n * panel is portaled to `document.body`, so without moving focus in, Tab from\n * the trigger goes to whatever follows it in the page and the panel's own\n * controls are unreachable by keyboard entirely.\n *\n * ## Why this exists\n *\n * `Modal`, `Drawer` and `CommandPalette` all rendered\n * `role=\"dialog\" aria-modal=\"true\"` with no focus management whatsoever. That\n * attribute is a **promise to assistive technology that the rest of the page\n * is inert**, and it was false: measured in a browser, focus never entered the\n * dialog, and Tab moved to the page behind the scrim on the first press\n * (Drawer on the second). Drawer additionally dropped focus onto `<body>` when\n * it closed, so a keyboard user was returned to the top of the document.\n *\n * That is WCAG 2.4.3 Focus Order (Level A), and it is invisible to axe - a\n * static snapshot of the DOM looks perfectly correct.\n *\n * ## Nesting\n *\n * Traps register on a module-level stack and only the innermost one acts, so a\n * dialog opened from a dialog behaves correctly. Without this, both listeners\n * fire for the same Tab and fight over where focus lands.\n *\n * ## What this does *not* do\n *\n * It does not mark the background `inert`. A trap plus `aria-modal` is the\n * widely-supported approach and is what screen readers act on; `inert` on\n * every sibling of the portal root would be stronger, but it needs the\n * component to know about DOM it does not own. Worth revisiting if a\n * consumer reports a screen reader escaping the dialog in browse mode.\n */\n\n/**\n * Deliberately not `[tabindex]` in general - that would match `tabindex=\"-1\"`,\n * which is programmatically focusable but explicitly removed from the Tab\n * sequence, so including it would make Tab stop somewhere the user cannot\n * reach by tabbing in the first place.\n */\nexport const FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled]):not([type=\"hidden\"])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'details > summary:first-of-type',\n 'iframe',\n 'audio[controls]',\n 'video[controls]',\n '[contenteditable]:not([contenteditable=\"false\"])',\n '[tabindex]:not([tabindex^=\"-\"])',\n].join(',');\n\n/**\n * `offsetParent === null` is the usual visibility check and is wrong here: it\n * is also null for `position: fixed` elements, which is exactly what a modal\n * is. `getClientRects()` is empty only when the element genuinely does not\n * render.\n */\nconst isVisible = (element: HTMLElement): boolean =>\n element.getClientRects().length > 0 && getComputedStyle(element).visibility !== 'hidden';\n\nconst getFocusable = (container: HTMLElement): HTMLElement[] =>\n Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter(\n (element) => isVisible(element) && element.closest('[aria-hidden=\"true\"]') === null,\n );\n\n/** Innermost trap last. Only the last entry responds to Tab. */\nconst trapStack: HTMLElement[] = [];\n\nexport interface UseDialogFocusOptions {\n /** Focused when the trap activates. Defaults to the first focusable child. */\n initialFocus?: RefObject<HTMLElement | null>;\n /**\n * Whether to return focus to whatever had it when the trap activated.\n * Defaults to `true`; pass `false` when the caller restores focus itself.\n */\n restoreFocus?: boolean;\n /**\n * Whether Tab is confined to the container. Defaults to `true`.\n *\n * Set `false` for a non-modal dialog (`aria-modal=\"false\"`), where the rest\n * of the page stays available and trapping would strand the user.\n */\n trapTab?: boolean;\n}\n\nexport const useDialogFocus = (\n active: boolean,\n containerRef: RefObject<HTMLElement | null>,\n { initialFocus, restoreFocus = true, trapTab = true }: UseDialogFocusOptions = {},\n): void => {\n useEffect(() => {\n const container = containerRef.current;\n if (!active || !container) return;\n\n // Captured before focus moves. The caller must only flip `active` to true\n // once the container is in the DOM - for the animated overlays that means\n // `isOpen && isMounted`, since `isMounted` is set in an effect one render\n // later and the container does not exist before it.\n const previouslyFocused = document.activeElement as HTMLElement | null;\n\n trapStack.push(container);\n\n // Moving focus in is retried across a few frames rather than attempted\n // once.\n //\n // These overlays animate open, and `.focus()` on an element that is still\n // `visibility: hidden` is a silent no-op - it does not throw, it just\n // leaves focus where it was. `Modal` sets its `--is-open` class two\n // animation frames after mounting, and the computed style has not caught\n // up at the moment the effect runs, so a single attempt focused nothing\n // and the trap looked broken.\n //\n // Retrying is better than keying off any particular animation: the hook\n // stays ignorant of each component's transition duration, and simply\n // stops as soon as focus has actually landed inside.\n const MAX_FRAMES = 10;\n let frame = 0;\n let attempts = 0;\n\n const tryFocus = () => {\n const target = initialFocus?.current ?? getFocusable(container)[0];\n if (target) {\n target.focus();\n } else {\n // A dialog with nothing focusable in it still must not leave focus on\n // the page behind, so the container takes it. `tabindex=\"-1\"` keeps\n // it out of the Tab sequence while allowing `.focus()`.\n if (!container.hasAttribute('tabindex')) container.setAttribute('tabindex', '-1');\n container.focus();\n }\n\n if (!container.contains(document.activeElement) && attempts < MAX_FRAMES) {\n attempts += 1;\n frame = requestAnimationFrame(tryFocus);\n }\n };\n\n tryFocus();\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== 'Tab') return;\n // Only the innermost trap acts.\n if (trapStack[trapStack.length - 1] !== container) return;\n\n // Re-queried on every Tab rather than cached: dialog contents change\n // (a disabled Confirm button becoming enabled, a list filtering down),\n // and a stale list sends focus to an element that is no longer there.\n const focusable = getFocusable(container);\n if (focusable.length === 0) {\n event.preventDefault();\n return;\n }\n\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const activeElement = document.activeElement as HTMLElement | null;\n\n // Focus outside the container - e.g. a click landed on the backdrop.\n // Pull it back in rather than letting Tab continue through the page.\n if (!activeElement || !container.contains(activeElement)) {\n event.preventDefault();\n (event.shiftKey ? last : first).focus();\n return;\n }\n\n if (event.shiftKey && activeElement === first) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && activeElement === last) {\n event.preventDefault();\n first.focus();\n }\n };\n\n if (trapTab) document.addEventListener('keydown', onKeyDown, true);\n\n return () => {\n cancelAnimationFrame(frame);\n document.removeEventListener('keydown', onKeyDown, true);\n\n const index = trapStack.lastIndexOf(container);\n if (index !== -1) trapStack.splice(index, 1);\n\n // Restore only if focus still belongs to the closing dialog.\n //\n // Two cases count as \"belongs\":\n //\n // 1. Focus is still inside the container.\n // 2. Focus has been lost to `<body>`. When the overlay hides, the\n // browser blurs whatever was focused inside it, so by the time this\n // cleanup runs `activeElement` is often already `<body>` - checking\n // only case 1 meant `CommandPalette` never restored at all.\n //\n // Anything else means something took focus deliberately - a confirm\n // action moving to a new region, say - and stealing it back would be\n // worse than doing nothing.\n const active = document.activeElement;\n const focusIsOurs = container.contains(active) || active === document.body || active === null;\n\n if (restoreFocus && focusIsOurs && previouslyFocused?.isConnected) {\n previouslyFocused.focus();\n }\n };\n }, [active, containerRef, initialFocus, restoreFocus, trapTab]);\n};\n","import { useEffect, useState } from 'react';\n\n/**\n * `false` on the server and on the very first client render, `true` from the\n * first effect onwards.\n *\n * ## Why this exists\n *\n * Every overlay in this library renders through `createPortal(…,\n * document.body)`. A portal is a client-only construct: there is no\n * `document` during `renderToString`, so any overlay that is *already open on\n * its first render* does not merely render oddly - it throws, and takes the\n * whole server render down with it. Measured against the built package:\n *\n * ```\n * renderToString(<Modal isOpen>) ReferenceError: document is not defined\n * renderToString(<Dropdown defaultOpen>) ReferenceError: DOMRect is not defined\n * renderToString(<Select autoOpen>) ReferenceError: DOMRect is not defined\n * ```\n *\n * `Modal`, `Drawer` and `CommandPalette` each keep an `isMounted` flag, which\n * looks like it would prevent this and does not: it is initialised to\n * `useState(isOpen)`, so it is already `true` on the first render. It exists\n * to sequence the open/close *animation*, not to defer the portal.\n *\n * With this hook the server renders nothing for the panel, and the portal\n * appears on the client after mount.\n *\n * ## Why a state flag rather than `typeof document !== 'undefined'`\n *\n * That check is `true` during hydration, so the client's first render would\n * produce the portal while the server's produced nothing - a hydration\n * mismatch, which React resolves by discarding and re-rendering the subtree.\n * A state flag set in an effect makes the first client render agree with the\n * server by construction, and the portal arrive one render later.\n *\n * ## Scope\n *\n * Only for components that can be open on their first render - `Dropdown`\n * (`defaultOpen`), `Popover`, `Modal`, `Drawer`, `CommandPalette`. `Tooltip`,\n * `ContextMenu` and `Snackbar` can only open in response to an event, which\n * cannot happen during a server render, so they need nothing. `check-ssr.js`\n * asserts all of them either way.\n */\nexport const useIsClient = (): boolean => {\n const [isClient, setIsClient] = useState(false);\n\n useEffect(() => {\n setIsClient(true);\n }, []);\n\n return isClient;\n};\n"]}
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); 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 _chunkENMDOQQOcjs = require('./chunk-ENMDOQQO.cjs');
3
+ var _chunkR5WI5IGRcjs = require('./chunk-R5WI5IGR.cjs');
4
4
 
5
5
  // src/components/Tooltip/Tooltip.component.tsx
6
6
  var _react = require('react');
@@ -266,7 +266,7 @@ var Tooltip = ({
266
266
  const [triggerNeedsFocus, setTriggerNeedsFocus] = _react.useState.call(void 0, false);
267
267
  _react.useEffect.call(void 0, () => {
268
268
  const el = triggerRef.current;
269
- setTriggerNeedsFocus(!!el && el.querySelector(_chunkENMDOQQOcjs.FOCUSABLE_SELECTOR) === null);
269
+ setTriggerNeedsFocus(!!el && el.querySelector(_chunkR5WI5IGRcjs.FOCUSABLE_SELECTOR) === null);
270
270
  }, [children, triggerType]);
271
271
  const getTriggerProps = () => {
272
272
  const props = {
@@ -327,4 +327,4 @@ Tooltip.displayName = "Tooltip";
327
327
 
328
328
 
329
329
  exports.Tooltip = Tooltip;
330
- //# sourceMappingURL=chunk-UTYY35QX.cjs.map
330
+ //# sourceMappingURL=chunk-RZMQCVAS.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-UTYY35QX.cjs","../src/components/Tooltip/Tooltip.component.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACJA,8BAAgE;AAChE,qCAA6B;AAwVhB,+CAAA;AA/Ub,IAAM,eAAA,EAAiB,GAAA;AAEhB,IAAM,QAAA,EAAkC,CAAC;AAAA,EAC9C,QAAA;AAAA,EACA,OAAA;AAAA,EACA,SAAA,EAAW,SAAA;AAAA,EACX,cAAA;AAAA,EACA,SAAA,EAAW,mBAAA,EAAqB,KAAA;AAAA,EAChC,MAAA,EAAQ,GAAA;AAAA,EACR,SAAA,EAAW,KAAA;AAAA,EACX,UAAA,EAAY,EAAA;AAAA,EACZ,YAAA,EAAc,OAAA;AAAA,EACd,oBAAA,EAAsB,IAAA;AAAA,EACtB,cAAA,EAAgB;AAClB,CAAA,EAAA,GAAM;AACJ,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,EAAA,EAAI,6BAAA;AAAuB,IAC7D,SAAA,EAAW,KAAA;AAAA,IACX,QAAA,EAAU,EAAE,GAAA,EAAK,CAAA,EAAG,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,MAAM,CAAA;AAAA,IAC9C,YAAA,EAAc;AAAA,EAChB,CAAC,CAAA;AAED,EAAA,MAAM,WAAA,EAAa,2BAAA,IAA2B,CAAA;AAC9C,EAAA,MAAM,WAAA,EAAa,2BAAA,IAA2B,CAAA;AAC9C,EAAA,MAAM,WAAA,EAAa,2BAAA,KAAkD,CAAS,CAAA;AAC9E,EAAA,MAAM,kBAAA,EAAoB,2BAAA,KAA2B,CAAS,CAAA;AAC9D,EAAA,MAAM,eAAA,EAAiB,2BAAA,KAAY,CAAA;AAEnC,EAAA,MAAM,yBAAA,EAA2B,gCAAA;AAAA,IAC/B,CAAC,WAAA,EAAsB,WAAA,EAAA,GAAyB;AAC9C,MAAA,MAAM,cAAA,EAAgB,MAAA,CAAO,UAAA;AAC7B,MAAA,MAAM,eAAA,EAAiB,MAAA,CAAO,WAAA;AAC9B,MAAA,MAAM,IAAA,EAAM,CAAA;AAEZ,MAAA,IAAI,UAAA,EAAiD,kBAAA;AACrD,MAAA,IAAI,IAAA,EAAM,CAAA;AACV,MAAA,IAAI,KAAA,EAAO,CAAA;AAEX,MAAA,OAAA,CAAQ,kBAAA,EAAoB;AAAA,QAC1B,KAAK,KAAA;AACH,UAAA,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,GAAA;AAC7C,UAAA,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,EAAA,EAAI,WAAA,CAAY,MAAA,EAAQ,CAAA;AACtE,UAAA,KAAA;AAAA,QACF,KAAK,QAAA;AACH,UAAA,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,GAAA;AAC3B,UAAA,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,EAAA,EAAI,WAAA,CAAY,MAAA,EAAQ,CAAA;AACtE,UAAA,KAAA;AAAA,QACF,KAAK,MAAA;AACH,UAAA,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,EAAA,EAAI,WAAA,CAAY,OAAA,EAAS,CAAA;AACtE,UAAA,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,GAAA;AAC9C,UAAA,KAAA;AAAA,QACF,KAAK,OAAA;AACH,UAAA,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,EAAA,EAAI,WAAA,CAAY,OAAA,EAAS,CAAA;AACtE,UAAA,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,GAAA;AAC3B,UAAA,KAAA;AAAA,MACJ;AAEA,MAAA,GAAA,CAAI,UAAA,IAAc,MAAA,GAAS,IAAA,EAAM,GAAA,EAAK;AACpC,QAAA,UAAA,EAAY,QAAA;AACZ,QAAA,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,GAAA;AAC3B,QAAA,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,EAAA,EAAI,WAAA,CAAY,MAAA,EAAQ,CAAA;AAAA,MACxE,EAAA,KAAA,GAAA,CAAW,UAAA,IAAc,SAAA,GAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,eAAA,EAAiB,GAAA,EAAK;AACpF,QAAA,UAAA,EAAY,KAAA;AACZ,QAAA,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,GAAA;AAC7C,QAAA,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,EAAA,EAAI,WAAA,CAAY,MAAA,EAAQ,CAAA;AAAA,MACxE,EAAA,KAAA,GAAA,CAAW,UAAA,IAAc,OAAA,GAAU,KAAA,EAAO,GAAA,EAAK;AAC7C,QAAA,UAAA,EAAY,OAAA;AACZ,QAAA,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,EAAA,EAAI,WAAA,CAAY,OAAA,EAAS,CAAA;AACtE,QAAA,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,GAAA;AAAA,MAC7B,EAAA,KAAA,GAAA,CAAW,UAAA,IAAc,QAAA,GAAW,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,cAAA,EAAgB,GAAA,EAAK;AAClF,QAAA,UAAA,EAAY,MAAA;AACZ,QAAA,IAAA,EAAM,WAAA,CAAY,IAAA,EAAM,WAAA,CAAY,OAAA,EAAS,EAAA,EAAI,WAAA,CAAY,OAAA,EAAS,CAAA;AACtE,QAAA,KAAA,EAAO,WAAA,CAAY,KAAA,EAAO,WAAA,CAAY,MAAA,EAAQ,GAAA;AAAA,MAChD;AAEA,MAAA,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,eAAA,EAAiB,WAAA,CAAY,OAAA,EAAS,GAAG,CAAC,CAAA;AAC5E,MAAA,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,cAAA,EAAgB,WAAA,CAAY,MAAA,EAAQ,GAAG,CAAC,CAAA;AAE5E,MAAA,OAAO,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,CAAC,kBAAkB;AAAA,EACrB,CAAA;AAEA,EAAA,MAAM,aAAA,EAAe,gCAAA,CAAY,EAAA,GAAM;AACrC,IAAA,GAAA,CAAI,CAAC,YAAA,CAAa,UAAA,GAAa,CAAC,YAAA,CAAa,aAAA,GAAgB,cAAA,CAAe,OAAA,EAAS,MAAA;AAErF,IAAA,cAAA,CAAe,QAAA,EAAU,IAAA;AAEzB,IAAA,iBAAA,CAAkB,QAAA,EAAU,qBAAA,CAAsB,CAAA,EAAA,GAAM;AACtD,MAAA,GAAA,CAAI,UAAA,CAAW,QAAA,GAAW,UAAA,CAAW,OAAA,EAAS;AAC5C,QAAA,MAAM,YAAA,EAAc,UAAA,CAAW,OAAA,CAAQ,qBAAA,CAAsB,CAAA;AAC7D,QAAA,MAAM,YAAA,EAAc,UAAA,CAAW,OAAA,CAAQ,qBAAA,CAAsB,CAAA;AAE7D,QAAA,MAAM,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU,EAAA,EAAI,wBAAA,CAAyB,WAAA,EAAa,WAAW,CAAA;AAElF,QAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,UACzB,GAAG,IAAA;AAAA,UACH,QAAA,EAAU,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU;AAAA,QACnC,CAAA,CAAE,CAAA;AAAA,MACJ;AAEA,MAAA,cAAA,CAAe,QAAA,EAAU,KAAA;AAAA,IAC3B,CAAC,CAAA;AAAA,EACH,CAAA,EAAG,CAAC,YAAA,CAAa,SAAA,EAAW,YAAA,CAAa,YAAA,EAAc,wBAAwB,CAAC,CAAA;AAEhF,EAAA,MAAM,iBAAA,EAAmB,gCAAA,CAAY,EAAA,GAAM;AACzC,IAAA,GAAA,CAAI,SAAA,GAAY,YAAA,IAAgB,OAAA,EAAS,MAAA;AAKzC,IAAA,GAAA,CAAI,UAAA,CAAW,OAAA,EAAS;AACtB,MAAA,YAAA,CAAa,UAAA,CAAW,OAAO,CAAA;AAAA,IACjC;AAEA,IAAA,UAAA,CAAW,QAAA,EAAU,UAAA,CAAW,CAAA,EAAA,GAAM;AAIpC,MAAA,eAAA;AAAA,QAAgB,CAAC,IAAA,EAAA,GACf,IAAA,CAAK,UAAA,EAAY,KAAA,EAAO,EAAE,GAAG,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,YAAA,EAAc,MAAM;AAAA,MAC1E,CAAA;AAAA,IACF,CAAA,EAAG,KAAK,CAAA;AAAA,EACV,CAAA,EAAG,CAAC,QAAA,EAAU,KAAA,EAAO,WAAW,CAAC,CAAA;AAEjC,EAAA,MAAM,iBAAA,EAAmB,gCAAA,CAAY,EAAA,GAAM;AACzC,IAAA,GAAA,CAAI,YAAA,IAAgB,OAAA,EAAS,MAAA;AAE7B,IAAA,GAAA,CAAI,UAAA,CAAW,OAAA,EAAS;AACtB,MAAA,YAAA,CAAa,UAAA,CAAW,OAAO,CAAA;AAAA,IACjC;AAUA,IAAA,UAAA,CAAW,QAAA,EAAU,UAAA,CAAW,CAAA,EAAA,GAAM;AACpC,MAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,QACzB,GAAG,IAAA;AAAA,QACH,SAAA,EAAW,KAAA;AAAA,QACX,YAAA,EAAc;AAAA,MAChB,CAAA,CAAE,CAAA;AAAA,IACJ,CAAA,EAAG,cAAc,CAAA;AAAA,EACnB,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,YAAA,EAAc,gCAAA,CAAY,EAAA,GAAM;AACpC,IAAA,GAAA,CAAI,SAAA,GAAY,YAAA,IAAgB,OAAA,EAAS,MAAA;AAEzC,IAAA,GAAA,CAAI,YAAA,CAAa,SAAA,EAAW;AAC1B,MAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,QACzB,GAAG,IAAA;AAAA,QACH,SAAA,EAAW,KAAA;AAAA,QACX,YAAA,EAAc;AAAA,MAChB,CAAA,CAAE,CAAA;AAAA,IACJ,EAAA,KAAO;AACL,MAAA,GAAA,CAAI,MAAA,EAAQ,CAAA,EAAG;AACb,QAAA,UAAA,CAAW,QAAA,EAAU,UAAA,CAAW,CAAA,EAAA,GAAM;AACpC,UAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,YACzB,GAAG,IAAA;AAAA,YACH,SAAA,EAAW,IAAA;AAAA,YACX,YAAA,EAAc;AAAA,UAChB,CAAA,CAAE,CAAA;AAAA,QACJ,CAAA,EAAG,KAAK,CAAA;AAAA,MACV,EAAA,KAAO;AACL,QAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,UACzB,GAAG,IAAA;AAAA,UACH,SAAA,EAAW,IAAA;AAAA,UACX,YAAA,EAAc;AAAA,QAChB,CAAA,CAAE,CAAA;AAAA,MACJ;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,QAAA,EAAU,WAAA,EAAa,YAAA,CAAa,SAAA,EAAW,KAAK,CAAC,CAAA;AAEzD,EAAA,MAAM,YAAA,EAAc,gCAAA,CAAY,EAAA,GAAM;AACpC,IAAA,GAAA,CAAI,SAAA,GAAY,YAAA,IAAgB,OAAA,EAAS,MAAA;AAEzC,IAAA,UAAA,CAAW,QAAA,EAAU,UAAA,CAAW,CAAA,EAAA,GAAM;AACpC,MAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,QACzB,GAAG,IAAA;AAAA,QACH,SAAA,EAAW,IAAA;AAAA,QACX,YAAA,EAAc;AAAA,MAChB,CAAA,CAAE,CAAA;AAAA,IACJ,CAAA,EAAG,KAAK,CAAA;AAAA,EACV,CAAA,EAAG,CAAC,QAAA,EAAU,WAAA,EAAa,KAAK,CAAC,CAAA;AAEjC,EAAA,MAAM,WAAA,EAAa,gCAAA,CAAY,EAAA,GAAM;AACnC,IAAA,GAAA,CAAI,YAAA,IAAgB,OAAA,EAAS,MAAA;AAE7B,IAAA,GAAA,CAAI,UAAA,CAAW,OAAA,EAAS;AACtB,MAAA,YAAA,CAAa,UAAA,CAAW,OAAO,CAAA;AAAA,IACjC;AACA,IAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,MACzB,GAAG,IAAA;AAAA,MACH,SAAA,EAAW,KAAA;AAAA,MACX,YAAA,EAAc;AAAA,IAChB,CAAA,CAAE,CAAA;AAAA,EACJ,CAAA,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,MAAM,mBAAA,EAAqB,gCAAA;AAAA,IACzB,CAAC,KAAA,EAAA,GAAsB;AACrB,MAAA,GAAA,CAAI,CAAC,oBAAA,GAAuB,CAAC,YAAA,CAAa,UAAA,GAAa,YAAA,IAAgB,OAAA,EAAS,MAAA;AAEhF,MAAA,MAAM,OAAA,EAAS,KAAA,CAAM,MAAA;AAErB,MAAA,GAAA,iBAAI,UAAA,mBAAW,OAAA,6BAAS,QAAA,mBAAS,MAAM,IAAA,mBAAK,UAAA,qBAAW,OAAA,6BAAS,QAAA,mBAAS,MAAM,GAAA,EAAG;AAChF,QAAA,MAAA;AAAA,MACF;AAEA,MAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,QACzB,GAAG,IAAA;AAAA,QACH,SAAA,EAAW,KAAA;AAAA,QACX,YAAA,EAAc;AAAA,MAChB,CAAA,CAAE,CAAA;AAAA,IACJ,CAAA;AAAA,IACA,CAAC,mBAAA,EAAqB,YAAA,CAAa,SAAA,EAAW,WAAW;AAAA,EAC3D,CAAA;AAEA,EAAA,MAAM,gBAAA,EAAkB,gCAAA;AAAA,IACtB,CAAC,KAAA,EAAA,GAAyB;AAQxB,MAAA,GAAA,CAAI,cAAA,GAAiB,KAAA,CAAM,IAAA,IAAQ,SAAA,GAAY,YAAA,CAAa,SAAA,EAAW;AACrE,QAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,UACzB,GAAG,IAAA;AAAA,UACH,SAAA,EAAW,KAAA;AAAA,UACX,YAAA,EAAc;AAAA,QAChB,CAAA,CAAE,CAAA;AAAA,MACJ;AAAA,IACF,CAAA;AAAA,IACA,CAAC,aAAA,EAAe,YAAA,CAAa,SAAS;AAAA,EACxC,CAAA;AAEA,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,GAAA,CACE,YAAA,CAAa,UAAA,GACb,CAAC,YAAA,CAAa,aAAA,GACd,UAAA,CAAW,QAAA,GACX,UAAA,CAAW,OAAA,EACX;AACA,MAAA,MAAM,YAAA,EAAc,UAAA,CAAW,OAAA,CAAQ,qBAAA,CAAsB,CAAA;AAC7D,MAAA,MAAM,YAAA,EAAc,UAAA,CAAW,OAAA,CAAQ,qBAAA,CAAsB,CAAA;AAE7D,MAAA,MAAM,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU,EAAA,EAAI,wBAAA,CAAyB,WAAA,EAAa,WAAW,CAAA;AAElF,MAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,QACzB,GAAG,IAAA;AAAA,QACH,QAAA,EAAU,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU,CAAA;AAAA,QACjC,YAAA,EAAc;AAAA,MAChB,CAAA,CAAE,CAAA;AAAA,IACJ;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,CAAa,SAAA,EAAW,YAAA,CAAa,YAAA,EAAc,wBAAwB,CAAC,CAAA;AAEhF,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,MAAM,aAAA,EAAe,CAAA,EAAA,GAAM;AACzB,MAAA,GAAA,CACE,YAAA,CAAa,UAAA,GACb,YAAA,CAAa,aAAA,GACb,UAAA,CAAW,QAAA,GACX,UAAA,CAAW,OAAA,EACX;AACA,QAAA,MAAM,YAAA,EAAc,UAAA,CAAW,OAAA,CAAQ,qBAAA,CAAsB,CAAA;AAC7D,QAAA,MAAM,YAAA,EAAc,UAAA,CAAW,OAAA,CAAQ,qBAAA,CAAsB,CAAA;AAE7D,QAAA,MAAM,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU,EAAA,EAAI,wBAAA,CAAyB,WAAA,EAAa,WAAW,CAAA;AAElF,QAAA,eAAA,CAAgB,CAAC,IAAA,EAAA,GAAA,CAAU;AAAA,UACzB,GAAG,IAAA;AAAA,UACH,QAAA,EAAU,EAAE,GAAA,EAAK,IAAA,EAAM,UAAU;AAAA,QACnC,CAAA,CAAE,CAAA;AAAA,MACJ;AAAA,IACF,CAAA;AAEA,IAAA,MAAA,CAAO,gBAAA,CAAiB,QAAA,EAAU,YAAY,CAAA;AAC9C,IAAA,OAAO,CAAA,EAAA,GAAM,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,YAAY,CAAA;AAAA,EAChE,CAAA,EAAG,CAAC,YAAA,CAAa,SAAA,EAAW,YAAA,CAAa,YAAA,EAAc,wBAAwB,CAAC,CAAA;AAEhF,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,GAAA,CAAI,YAAA,CAAa,SAAA,EAAW;AAK1B,MAAA,QAAA,CAAS,gBAAA,CAAiB,QAAA,EAAU,YAAA,EAAc,EAAE,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,KAAK,CAAC,CAAA;AAAA,IACpF;AAEA,IAAA,OAAO,CAAA,EAAA,GAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,QAAA,EAAU,YAAA,EAAc,EAAE,OAAA,EAAS,KAAK,CAAC,CAAA;AAAA,IACxE,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,CAAa,SAAA,EAAW,YAAY,CAAC,CAAA;AAMzC,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,GAAA,CAAI,YAAA,CAAa,UAAA,GAAa,YAAA,IAAgB,OAAA,EAAS;AACrD,MAAA,QAAA,CAAS,gBAAA,CAAiB,WAAA,EAAa,kBAAkB,CAAA;AAAA,IAC3D;AAEA,IAAA,OAAO,CAAA,EAAA,GAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,WAAA,EAAa,kBAAkB,CAAA;AAAA,IAC9D,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,CAAa,SAAA,EAAW,WAAA,EAAa,kBAAkB,CAAC,CAAA;AAE5D,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,GAAA,CAAI,YAAA,CAAa,SAAA,EAAW;AAC1B,MAAA,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,eAAe,CAAA;AAAA,IACtD;AAEA,IAAA,OAAO,CAAA,EAAA,GAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,eAAe,CAAA;AAAA,IACzD,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAA,CAAa,SAAA,EAAW,eAAe,CAAC,CAAA;AAE5C,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,OAAO,CAAA,EAAA,GAAM;AACX,MAAA,GAAA,CAAI,UAAA,CAAW,OAAA,EAAS;AACtB,QAAA,YAAA,CAAa,UAAA,CAAW,OAAO,CAAA;AAAA,MACjC;AACA,MAAA,GAAA,CAAI,iBAAA,CAAkB,OAAA,EAAS;AAC7B,QAAA,oBAAA,CAAqB,iBAAA,CAAkB,OAAO,CAAA;AAAA,MAChD;AAAA,IACF,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,MAAM,qBAAA,EAAuB,CAAA,EAAA,GAAM;AACjC,IAAA,GAAA,CAAI,OAAA,EAAS;AACX,MAAA,uBAAO,6BAAA,MAAC,EAAA,EAAK,SAAA,EAAU,uBAAA,EAAyB,QAAA,EAAA,QAAA,CAAQ,CAAA;AAAA,IAC1D;AACA,IAAA,GAAA,CAAI,SAAA,EAAW;AACb,MAAA,uBAAO,6BAAA,SAAC,EAAA,EAAW,GAAI,eAAA,GAAkB,CAAC,EAAA,CAAI,CAAA;AAAA,IAChD;AACA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAMA,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,EAAA,EAAI,6BAAA,KAAc,CAAA;AAEhE,EAAA,8BAAA,CAAU,EAAA,GAAM;AACd,IAAA,MAAM,GAAA,EAAK,UAAA,CAAW,OAAA;AACtB,IAAA,oBAAA,CAAqB,CAAC,CAAC,GAAA,GAAM,EAAA,CAAG,aAAA,CAAc,oCAAkB,EAAA,IAAM,IAAI,CAAA;AAAA,EAC5E,CAAA,EAAG,CAAC,QAAA,EAAU,WAAW,CAAC,CAAA;AAE1B,EAAA,MAAM,gBAAA,EAAkB,CAAA,EAAA,GAAM;AAC5B,IAAA,MAAM,MAAA,EAAiC;AAAA,MACrC,GAAA,EAAK,UAAA;AAAA,MACL,SAAA,EAAW;AAAA,IACb,CAAA;AAEA,IAAA,OAAA,CAAQ,WAAA,EAAa;AAAA,MACnB,KAAK,OAAA;AACH,QAAA,KAAA,CAAM,aAAA,EAAe,gBAAA;AACrB,QAAA,KAAA,CAAM,aAAA,EAAe,gBAAA;AACrB,QAAA,KAAA;AAAA,MACF,KAAK,OAAA;AACH,QAAA,KAAA,CAAM,QAAA,EAAU,WAAA;AAMhB,QAAA,GAAA,CAAI,iBAAA,EAAmB;AACrB,UAAA,KAAA,CAAM,KAAA,EAAO,QAAA;AACb,UAAA,KAAA,CAAM,SAAA,EAAW,CAAA;AACjB,UAAA,KAAA,CAAM,UAAA,EAAY,CAAC,KAAA,EAAA,GAA+B;AAChD,YAAA,GAAA,CAAI,KAAA,CAAM,IAAA,IAAQ,QAAA,GAAW,KAAA,CAAM,IAAA,IAAQ,GAAA,EAAK;AAC9C,cAAA,KAAA,CAAM,cAAA,CAAe,CAAA;AACrB,cAAA,WAAA,CAAY,CAAA;AAAA,YACd;AAAA,UACF,CAAA;AAAA,QACF;AACA,QAAA,KAAA;AAAA,MACF,KAAK,OAAA;AACH,QAAA,KAAA,CAAM,QAAA,EAAU,WAAA;AAChB,QAAA,KAAA,CAAM,OAAA,EAAS,UAAA;AAIf,QAAA,GAAA,CAAI,iBAAA,EAAmB,KAAA,CAAM,SAAA,EAAW,CAAA;AACxC,QAAA,KAAA;AAAA,IACJ;AAEA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,uBACE,8BAAA,oBAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAA,6BAAA,KAAC,EAAA,EAAK,GAAG,eAAA,CAAgB,CAAA,EAAI,SAAA,CAAS,CAAA;AAAA,IACrC,YAAA,CAAa,UAAA,GACZ,oCAAA;AAAA,sBACE,6BAAA;AAAA,QAAC,KAAA;AAAA,QAAA;AAAA,UACC,GAAA,EAAK,UAAA;AAAA,UAKL,YAAA,EAAc,gBAAA;AAAA,UACd,YAAA,EAAc,gBAAA;AAAA,UACd,SAAA,EAAW,CAAA,6BAAA,EAAgC,YAAA,CAAa,QAAA,CAAS,SAAS,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA;AAChF,UAAA;AACsB,YAAA;AACC,YAAA;AAC9B,UAAA;AACoD,UAAA;AAC/C,UAAA;AAEiB,UAAA;AAAA,QAAA;AACxB,MAAA;AACS,MAAA;AACX,IAAA;AACJ,EAAA;AAEJ;AAEsB;AD9G4E;AACA;AACA;AACA","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-UTYY35QX.cjs","sourcesContent":[null,"import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { TooltipProps, TooltipState } from './Tooltip.types';\nimport { FOCUSABLE_SELECTOR } from '../../utils';\n\n/**\n * How long the tooltip stays open after the pointer leaves, so it can be\n * moved onto the panel itself (SC 1.4.13, \"hoverable\"). Long enough to cross\n * the gap, short enough not to feel stuck.\n */\nconst HOVER_GRACE_MS = 150;\n\nexport const Tooltip: React.FC<TooltipProps> = ({\n children,\n message,\n component: Component,\n componentProps,\n placement: preferredPlacement = 'top',\n delay = 100,\n disabled = false,\n className = '',\n triggerType = 'hover',\n closeOnClickOutside = true,\n closeOnEscape = true,\n}) => {\n const [tooltipState, setTooltipState] = useState<TooltipState>({\n isVisible: false,\n position: { top: 0, left: 0, placement: 'top' },\n isPositioned: false,\n });\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const animationFrameRef = useRef<number | undefined>(undefined);\n const isScrollingRef = useRef(false);\n\n const calculateOptimalPosition = useCallback(\n (triggerRect: DOMRect, tooltipRect: DOMRect) => {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const gap = 8;\n\n let placement: 'top' | 'bottom' | 'left' | 'right' = preferredPlacement;\n let top = 0;\n let left = 0;\n\n switch (preferredPlacement) {\n case 'top':\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n break;\n case 'bottom':\n top = triggerRect.bottom + gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n break;\n case 'left':\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n break;\n case 'right':\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.right + gap;\n break;\n }\n\n if (placement === 'top' && top < gap) {\n placement = 'bottom';\n top = triggerRect.bottom + gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n } else if (placement === 'bottom' && top + tooltipRect.height > viewportHeight - gap) {\n placement = 'top';\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n } else if (placement === 'left' && left < gap) {\n placement = 'right';\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.right + gap;\n } else if (placement === 'right' && left + tooltipRect.width > viewportWidth - gap) {\n placement = 'left';\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n }\n\n top = Math.max(gap, Math.min(top, viewportHeight - tooltipRect.height - gap));\n left = Math.max(gap, Math.min(left, viewportWidth - tooltipRect.width - gap));\n\n return { top, left, placement };\n },\n [preferredPlacement],\n );\n\n const handleScroll = useCallback(() => {\n if (!tooltipState.isVisible || !tooltipState.isPositioned || isScrollingRef.current) return;\n\n isScrollingRef.current = true;\n\n animationFrameRef.current = requestAnimationFrame(() => {\n if (triggerRef.current && tooltipRef.current) {\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n\n const { top, left, placement } = calculateOptimalPosition(triggerRect, tooltipRect);\n\n setTooltipState((prev) => ({\n ...prev,\n position: { top, left, placement },\n }));\n }\n\n isScrollingRef.current = false;\n });\n }, [tooltipState.isVisible, tooltipState.isPositioned, calculateOptimalPosition]);\n\n const handleMouseEnter = useCallback(() => {\n if (disabled || triggerType !== 'hover') return;\n\n // Cancels a pending hide as well as scheduling the show. Both handlers\n // are bound to the trigger *and* to the panel, so this is what catches\n // the pointer as it crosses from one to the other.\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n // Left untouched when already open. Re-entering from the panel would\n // otherwise re-run the open transition and reposition a tooltip the\n // user is in the middle of reading.\n setTooltipState((prev) =>\n prev.isVisible ? prev : { ...prev, isVisible: true, isPositioned: false },\n );\n }, delay);\n }, [disabled, delay, triggerType]);\n\n const handleMouseLeave = useCallback(() => {\n if (triggerType !== 'hover') return;\n\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n // Closing is delayed, not immediate.\n //\n // SC 1.4.13 requires the pointer to be able to reach the tooltip's own\n // content. The panel is portaled and sits a few pixels off the trigger,\n // so an immediate hide made that gap impossible to cross - the tooltip\n // disappeared the moment the pointer left the trigger, however fast the\n // user moved. The grace period is what makes \"hoverable\" reachable in\n // practice.\n timeoutRef.current = setTimeout(() => {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n }, HOVER_GRACE_MS);\n }, [triggerType]);\n\n const handleClick = useCallback(() => {\n if (disabled || triggerType !== 'click') return;\n\n if (tooltipState.isVisible) {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n } else {\n if (delay > 0) {\n timeoutRef.current = setTimeout(() => {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: true,\n isPositioned: false,\n }));\n }, delay);\n } else {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: true,\n isPositioned: false,\n }));\n }\n }\n }, [disabled, triggerType, tooltipState.isVisible, delay]);\n\n const handleFocus = useCallback(() => {\n if (disabled || triggerType !== 'focus') return;\n\n timeoutRef.current = setTimeout(() => {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: true,\n isPositioned: false,\n }));\n }, delay);\n }, [disabled, triggerType, delay]);\n\n const handleBlur = useCallback(() => {\n if (triggerType !== 'focus') return;\n\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n }, [triggerType]);\n\n const handleClickOutside = useCallback(\n (event: MouseEvent) => {\n if (!closeOnClickOutside || !tooltipState.isVisible || triggerType !== 'click') return;\n\n const target = event.target as Node;\n\n if (tooltipRef.current?.contains(target) || triggerRef.current?.contains(target)) {\n return;\n }\n\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n },\n [closeOnClickOutside, tooltipState.isVisible, triggerType],\n );\n\n const handleEscapeKey = useCallback(\n (event: KeyboardEvent) => {\n // Every trigger type, not just `click`.\n //\n // SC 1.4.13 requires content shown on hover *or focus* to be\n // dismissible without moving the pointer or focus - and `hover` is the\n // default, so the one configuration that could be dismissed was the\n // one least likely to be used. A tooltip covering the text you are\n // trying to read had to be escaped by physically moving the mouse.\n if (closeOnEscape && event.key === 'Escape' && tooltipState.isVisible) {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n }\n },\n [closeOnEscape, tooltipState.isVisible],\n );\n\n useEffect(() => {\n if (\n tooltipState.isVisible &&\n !tooltipState.isPositioned &&\n tooltipRef.current &&\n triggerRef.current\n ) {\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n\n const { top, left, placement } = calculateOptimalPosition(triggerRect, tooltipRect);\n\n setTooltipState((prev) => ({\n ...prev,\n position: { top, left, placement },\n isPositioned: true,\n }));\n }\n }, [tooltipState.isVisible, tooltipState.isPositioned, calculateOptimalPosition]);\n\n useEffect(() => {\n const handleResize = () => {\n if (\n tooltipState.isVisible &&\n tooltipState.isPositioned &&\n tooltipRef.current &&\n triggerRef.current\n ) {\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n\n const { top, left, placement } = calculateOptimalPosition(triggerRect, tooltipRect);\n\n setTooltipState((prev) => ({\n ...prev,\n position: { top, left, placement },\n }));\n }\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [tooltipState.isVisible, tooltipState.isPositioned, calculateOptimalPosition]);\n\n useEffect(() => {\n if (tooltipState.isVisible) {\n // Capture phase on `document` - see the note in `Dropdown`. `scroll` does\n // not bubble, so listeners on `window`/`document.body` miss every\n // ancestor scroll container and the portaled tooltip detaches from its\n // trigger.\n document.addEventListener('scroll', handleScroll, { capture: true, passive: true });\n }\n\n return () => {\n document.removeEventListener('scroll', handleScroll, { capture: true });\n };\n }, [tooltipState.isVisible, handleScroll]);\n\n // Click-outside is only meaningful for a click-triggered tooltip; Escape\n // is not. Registering them together meant a hover tooltip had no way to be\n // dismissed from the keyboard at all (SC 1.4.13, \"dismissible\") - and\n // `hover` is the default, so the failing case was the common one.\n useEffect(() => {\n if (tooltipState.isVisible && triggerType === 'click') {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [tooltipState.isVisible, triggerType, handleClickOutside]);\n\n useEffect(() => {\n if (tooltipState.isVisible) {\n document.addEventListener('keydown', handleEscapeKey);\n }\n\n return () => {\n document.removeEventListener('keydown', handleEscapeKey);\n };\n }, [tooltipState.isVisible, handleEscapeKey]);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n };\n }, []);\n\n const renderTooltipContent = () => {\n if (message) {\n return <span className=\"eidos-tooltip-message\">{message}</span>;\n }\n if (Component) {\n return <Component {...(componentProps || {})} />;\n }\n return null;\n };\n\n // Whether the trigger wrapper has to become focusable itself, i.e. whether\n // the consumer's child is not already a control. Measured from the DOM\n // rather than guessed from the node type, because `children` is an\n // arbitrary `ReactNode` and the control may be nested inside it.\n const [triggerNeedsFocus, setTriggerNeedsFocus] = useState(false);\n\n useEffect(() => {\n const el = triggerRef.current;\n setTriggerNeedsFocus(!!el && el.querySelector(FOCUSABLE_SELECTOR) === null);\n }, [children, triggerType]);\n\n const getTriggerProps = () => {\n const props: Record<string, unknown> = {\n ref: triggerRef,\n className: 'eidos-tooltip-trigger',\n };\n\n switch (triggerType) {\n case 'hover':\n props.onMouseEnter = handleMouseEnter;\n props.onMouseLeave = handleMouseLeave;\n break;\n case 'click':\n props.onClick = handleClick;\n // Only when the trigger has no control of its own. Making this\n // wrapper a button unconditionally put a button inside a button\n // whenever the child was one - which is the common case, since\n // `Button` wraps *itself* in a Tooltip when given `tooltip`. That is\n // invalid (`nested-interactive`) and gives one action two tab stops.\n if (triggerNeedsFocus) {\n props.role = 'button';\n props.tabIndex = 0;\n props.onKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleClick();\n }\n };\n }\n break;\n case 'focus':\n props.onFocus = handleFocus;\n props.onBlur = handleBlur;\n // Same reasoning: a focusable child already receives the focus that\n // opens the tooltip, and adding `tabIndex` here would just add a\n // second stop in front of it.\n if (triggerNeedsFocus) props.tabIndex = 0;\n break;\n }\n\n return props;\n };\n\n return (\n <>\n <div {...getTriggerProps()}>{children}</div>\n {tooltipState.isVisible &&\n createPortal(\n <div\n ref={tooltipRef}\n // SC 1.4.13 \"hoverable\": the pointer has to be able to reach the\n // tooltip's own content - to read a long message, or select text\n // from it - without it vanishing. The panel used to be\n // `pointer-events: none`, so moving towards it dismissed it.\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className={`eidos-tooltip eidos-tooltip--${tooltipState.position.placement} ${className}`}\n style={{\n top: tooltipState.position.top,\n left: tooltipState.position.left,\n }}\n data-state={tooltipState.isPositioned ? 'entered' : 'entering'}\n role=\"tooltip\"\n >\n {renderTooltipContent()}\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nTooltip.displayName = 'Tooltip';\n"]}
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-RZMQCVAS.cjs","../src/components/Tooltip/Tooltip.component.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-RZMQCVAS.cjs","sourcesContent":[null,"import React, { useState, useRef, useCallback, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport type { TooltipProps, TooltipState } from './Tooltip.types';\nimport { FOCUSABLE_SELECTOR } from '../../utils';\n\n/**\n * How long the tooltip stays open after the pointer leaves, so it can be\n * moved onto the panel itself (SC 1.4.13, \"hoverable\"). Long enough to cross\n * the gap, short enough not to feel stuck.\n */\nconst HOVER_GRACE_MS = 150;\n\nexport const Tooltip: React.FC<TooltipProps> = ({\n children,\n message,\n component: Component,\n componentProps,\n placement: preferredPlacement = 'top',\n delay = 100,\n disabled = false,\n className = '',\n triggerType = 'hover',\n closeOnClickOutside = true,\n closeOnEscape = true,\n}) => {\n const [tooltipState, setTooltipState] = useState<TooltipState>({\n isVisible: false,\n position: { top: 0, left: 0, placement: 'top' },\n isPositioned: false,\n });\n\n const triggerRef = useRef<HTMLDivElement>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n const animationFrameRef = useRef<number | undefined>(undefined);\n const isScrollingRef = useRef(false);\n\n const calculateOptimalPosition = useCallback(\n (triggerRect: DOMRect, tooltipRect: DOMRect) => {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n const gap = 8;\n\n let placement: 'top' | 'bottom' | 'left' | 'right' = preferredPlacement;\n let top = 0;\n let left = 0;\n\n switch (preferredPlacement) {\n case 'top':\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n break;\n case 'bottom':\n top = triggerRect.bottom + gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n break;\n case 'left':\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n break;\n case 'right':\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.right + gap;\n break;\n }\n\n if (placement === 'top' && top < gap) {\n placement = 'bottom';\n top = triggerRect.bottom + gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n } else if (placement === 'bottom' && top + tooltipRect.height > viewportHeight - gap) {\n placement = 'top';\n top = triggerRect.top - tooltipRect.height - gap;\n left = triggerRect.left + triggerRect.width / 2 - tooltipRect.width / 2;\n } else if (placement === 'left' && left < gap) {\n placement = 'right';\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.right + gap;\n } else if (placement === 'right' && left + tooltipRect.width > viewportWidth - gap) {\n placement = 'left';\n top = triggerRect.top + triggerRect.height / 2 - tooltipRect.height / 2;\n left = triggerRect.left - tooltipRect.width - gap;\n }\n\n top = Math.max(gap, Math.min(top, viewportHeight - tooltipRect.height - gap));\n left = Math.max(gap, Math.min(left, viewportWidth - tooltipRect.width - gap));\n\n return { top, left, placement };\n },\n [preferredPlacement],\n );\n\n const handleScroll = useCallback(() => {\n if (!tooltipState.isVisible || !tooltipState.isPositioned || isScrollingRef.current) return;\n\n isScrollingRef.current = true;\n\n animationFrameRef.current = requestAnimationFrame(() => {\n if (triggerRef.current && tooltipRef.current) {\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n\n const { top, left, placement } = calculateOptimalPosition(triggerRect, tooltipRect);\n\n setTooltipState((prev) => ({\n ...prev,\n position: { top, left, placement },\n }));\n }\n\n isScrollingRef.current = false;\n });\n }, [tooltipState.isVisible, tooltipState.isPositioned, calculateOptimalPosition]);\n\n const handleMouseEnter = useCallback(() => {\n if (disabled || triggerType !== 'hover') return;\n\n // Cancels a pending hide as well as scheduling the show. Both handlers\n // are bound to the trigger *and* to the panel, so this is what catches\n // the pointer as it crosses from one to the other.\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n timeoutRef.current = setTimeout(() => {\n // Left untouched when already open. Re-entering from the panel would\n // otherwise re-run the open transition and reposition a tooltip the\n // user is in the middle of reading.\n setTooltipState((prev) =>\n prev.isVisible ? prev : { ...prev, isVisible: true, isPositioned: false },\n );\n }, delay);\n }, [disabled, delay, triggerType]);\n\n const handleMouseLeave = useCallback(() => {\n if (triggerType !== 'hover') return;\n\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n\n // Closing is delayed, not immediate.\n //\n // SC 1.4.13 requires the pointer to be able to reach the tooltip's own\n // content. The panel is portaled and sits a few pixels off the trigger,\n // so an immediate hide made that gap impossible to cross - the tooltip\n // disappeared the moment the pointer left the trigger, however fast the\n // user moved. The grace period is what makes \"hoverable\" reachable in\n // practice.\n timeoutRef.current = setTimeout(() => {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n }, HOVER_GRACE_MS);\n }, [triggerType]);\n\n const handleClick = useCallback(() => {\n if (disabled || triggerType !== 'click') return;\n\n if (tooltipState.isVisible) {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n } else {\n if (delay > 0) {\n timeoutRef.current = setTimeout(() => {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: true,\n isPositioned: false,\n }));\n }, delay);\n } else {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: true,\n isPositioned: false,\n }));\n }\n }\n }, [disabled, triggerType, tooltipState.isVisible, delay]);\n\n const handleFocus = useCallback(() => {\n if (disabled || triggerType !== 'focus') return;\n\n timeoutRef.current = setTimeout(() => {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: true,\n isPositioned: false,\n }));\n }, delay);\n }, [disabled, triggerType, delay]);\n\n const handleBlur = useCallback(() => {\n if (triggerType !== 'focus') return;\n\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n }, [triggerType]);\n\n const handleClickOutside = useCallback(\n (event: MouseEvent) => {\n if (!closeOnClickOutside || !tooltipState.isVisible || triggerType !== 'click') return;\n\n const target = event.target as Node;\n\n if (tooltipRef.current?.contains(target) || triggerRef.current?.contains(target)) {\n return;\n }\n\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n },\n [closeOnClickOutside, tooltipState.isVisible, triggerType],\n );\n\n const handleEscapeKey = useCallback(\n (event: KeyboardEvent) => {\n // Every trigger type, not just `click`.\n //\n // SC 1.4.13 requires content shown on hover *or focus* to be\n // dismissible without moving the pointer or focus - and `hover` is the\n // default, so the one configuration that could be dismissed was the\n // one least likely to be used. A tooltip covering the text you are\n // trying to read had to be escaped by physically moving the mouse.\n if (closeOnEscape && event.key === 'Escape' && tooltipState.isVisible) {\n setTooltipState((prev) => ({\n ...prev,\n isVisible: false,\n isPositioned: false,\n }));\n }\n },\n [closeOnEscape, tooltipState.isVisible],\n );\n\n useEffect(() => {\n if (\n tooltipState.isVisible &&\n !tooltipState.isPositioned &&\n tooltipRef.current &&\n triggerRef.current\n ) {\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n\n const { top, left, placement } = calculateOptimalPosition(triggerRect, tooltipRect);\n\n setTooltipState((prev) => ({\n ...prev,\n position: { top, left, placement },\n isPositioned: true,\n }));\n }\n }, [tooltipState.isVisible, tooltipState.isPositioned, calculateOptimalPosition]);\n\n useEffect(() => {\n const handleResize = () => {\n if (\n tooltipState.isVisible &&\n tooltipState.isPositioned &&\n tooltipRef.current &&\n triggerRef.current\n ) {\n const triggerRect = triggerRef.current.getBoundingClientRect();\n const tooltipRect = tooltipRef.current.getBoundingClientRect();\n\n const { top, left, placement } = calculateOptimalPosition(triggerRect, tooltipRect);\n\n setTooltipState((prev) => ({\n ...prev,\n position: { top, left, placement },\n }));\n }\n };\n\n window.addEventListener('resize', handleResize);\n return () => window.removeEventListener('resize', handleResize);\n }, [tooltipState.isVisible, tooltipState.isPositioned, calculateOptimalPosition]);\n\n useEffect(() => {\n if (tooltipState.isVisible) {\n // Capture phase on `document` - see the note in `Dropdown`. `scroll` does\n // not bubble, so listeners on `window`/`document.body` miss every\n // ancestor scroll container and the portaled tooltip detaches from its\n // trigger.\n document.addEventListener('scroll', handleScroll, { capture: true, passive: true });\n }\n\n return () => {\n document.removeEventListener('scroll', handleScroll, { capture: true });\n };\n }, [tooltipState.isVisible, handleScroll]);\n\n // Click-outside is only meaningful for a click-triggered tooltip; Escape\n // is not. Registering them together meant a hover tooltip had no way to be\n // dismissed from the keyboard at all (SC 1.4.13, \"dismissible\") - and\n // `hover` is the default, so the failing case was the common one.\n useEffect(() => {\n if (tooltipState.isVisible && triggerType === 'click') {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [tooltipState.isVisible, triggerType, handleClickOutside]);\n\n useEffect(() => {\n if (tooltipState.isVisible) {\n document.addEventListener('keydown', handleEscapeKey);\n }\n\n return () => {\n document.removeEventListener('keydown', handleEscapeKey);\n };\n }, [tooltipState.isVisible, handleEscapeKey]);\n\n useEffect(() => {\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n }\n };\n }, []);\n\n const renderTooltipContent = () => {\n if (message) {\n return <span className=\"eidos-tooltip-message\">{message}</span>;\n }\n if (Component) {\n return <Component {...(componentProps || {})} />;\n }\n return null;\n };\n\n // Whether the trigger wrapper has to become focusable itself, i.e. whether\n // the consumer's child is not already a control. Measured from the DOM\n // rather than guessed from the node type, because `children` is an\n // arbitrary `ReactNode` and the control may be nested inside it.\n const [triggerNeedsFocus, setTriggerNeedsFocus] = useState(false);\n\n useEffect(() => {\n const el = triggerRef.current;\n setTriggerNeedsFocus(!!el && el.querySelector(FOCUSABLE_SELECTOR) === null);\n }, [children, triggerType]);\n\n const getTriggerProps = () => {\n const props: Record<string, unknown> = {\n ref: triggerRef,\n className: 'eidos-tooltip-trigger',\n };\n\n switch (triggerType) {\n case 'hover':\n props.onMouseEnter = handleMouseEnter;\n props.onMouseLeave = handleMouseLeave;\n break;\n case 'click':\n props.onClick = handleClick;\n // Only when the trigger has no control of its own. Making this\n // wrapper a button unconditionally put a button inside a button\n // whenever the child was one - which is the common case, since\n // `Button` wraps *itself* in a Tooltip when given `tooltip`. That is\n // invalid (`nested-interactive`) and gives one action two tab stops.\n if (triggerNeedsFocus) {\n props.role = 'button';\n props.tabIndex = 0;\n props.onKeyDown = (event: React.KeyboardEvent) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n handleClick();\n }\n };\n }\n break;\n case 'focus':\n props.onFocus = handleFocus;\n props.onBlur = handleBlur;\n // Same reasoning: a focusable child already receives the focus that\n // opens the tooltip, and adding `tabIndex` here would just add a\n // second stop in front of it.\n if (triggerNeedsFocus) props.tabIndex = 0;\n break;\n }\n\n return props;\n };\n\n return (\n <>\n <div {...getTriggerProps()}>{children}</div>\n {tooltipState.isVisible &&\n createPortal(\n <div\n ref={tooltipRef}\n // SC 1.4.13 \"hoverable\": the pointer has to be able to reach the\n // tooltip's own content - to read a long message, or select text\n // from it - without it vanishing. The panel used to be\n // `pointer-events: none`, so moving towards it dismissed it.\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n className={`eidos-tooltip eidos-tooltip--${tooltipState.position.placement} ${className}`}\n style={{\n top: tooltipState.position.top,\n left: tooltipState.position.left,\n }}\n data-state={tooltipState.isPositioned ? 'entered' : 'entering'}\n role=\"tooltip\"\n >\n {renderTooltipContent()}\n </div>,\n document.body,\n )}\n </>\n );\n};\n\nTooltip.displayName = 'Tooltip';\n"]}
@@ -1,12 +1,12 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
2
 
3
- var _chunkN5NXKVFJcjs = require('./chunk-N5NXKVFJ.cjs');
3
+ var _chunkVPN7AR7Tcjs = require('./chunk-VPN7AR7T.cjs');
4
4
 
5
5
 
6
- var _chunkVXC7Z7XBcjs = require('./chunk-VXC7Z7XB.cjs');
6
+ var _chunkMKQVDEHIcjs = require('./chunk-MKQVDEHI.cjs');
7
7
 
8
8
 
9
- var _chunkENMDOQQOcjs = require('./chunk-ENMDOQQO.cjs');
9
+ var _chunkR5WI5IGRcjs = require('./chunk-R5WI5IGR.cjs');
10
10
 
11
11
  // src/components/SplitButton/SplitButton.component.tsx
12
12
  var _react = require('react');
@@ -72,16 +72,16 @@ var SplitButton = ({
72
72
  disabled: disabledOrLoading,
73
73
  onClick,
74
74
  children: [
75
- loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { className: "eidos-split-button__spinner", "aria-hidden": "true" }) : preIcon && _chunkENMDOQQOcjs.renderIcon.call(void 0, preIcon, "eidos-split-button__pre-icon"),
75
+ loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { className: "eidos-split-button__spinner", "aria-hidden": "true" }) : preIcon && _chunkR5WI5IGRcjs.renderIcon.call(void 0, preIcon, "eidos-split-button__pre-icon"),
76
76
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-split-button__label", children: label })
77
77
  ]
78
78
  }
79
79
  ),
80
80
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
81
- _chunkVXC7Z7XBcjs.Dropdown,
81
+ _chunkMKQVDEHIcjs.Dropdown,
82
82
  {
83
83
  trigger: chevronTrigger,
84
- content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkN5NXKVFJcjs.MenuPanel, { items: menuItems, onItemClick: handleItemClick }),
84
+ content: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVPN7AR7Tcjs.MenuPanel, { items: menuItems, onItemClick: handleItemClick }),
85
85
  placement: "bottom",
86
86
  align: "end",
87
87
  disabled: disabledOrLoading
@@ -95,4 +95,4 @@ var SplitButton = ({
95
95
 
96
96
 
97
97
  exports.SplitButton = SplitButton;
98
- //# sourceMappingURL=chunk-7FV2X62W.cjs.map
98
+ //# sourceMappingURL=chunk-SJKD3WCV.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-7FV2X62W.cjs","../src/components/SplitButton/SplitButton.component.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACA;ACVA,8BAAmC;AACnC,2CAA0C;AAsEpC,+CAAA;AA5CC,IAAM,YAAA,EAA0C,CAAC;AAAA,EACtD,KAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA,EAAU,QAAA;AAAA,EACV,MAAA,EAAQ,SAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,SAAA,EAAW,KAAA;AAAA,EACX,QAAA,EAAU,KAAA;AAAA,EACV,OAAA;AAAA,EACA,UAAA,EAAY;AACd,CAAA,EAAA,GAAM;AAEJ,EAAA,MAAM,UAAA,EAAwB,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,EAAA,GAAA,CAAS;AAAA,IAClD,IAAA,EAAM,MAAA;AAAA,IACN,EAAA,EAAI,GAAA,CAAI,EAAA;AAAA,IACR,KAAA,EAAO,GAAA,CAAI,KAAA;AAAA,IACX,IAAA,EAAM,GAAA,CAAI,IAAA;AAAA,IACV,QAAA,EAAU,GAAA,CAAI,QAAA;AAAA,IACd,OAAA,EAAS,GAAA,CAAI;AAAA,EACf,CAAA,CAAE,CAAA;AAEF,EAAA,MAAM,gBAAA,EAAkB,gCAAA,CAAY,EAAA,GAAM;AAExC,IAAA,UAAA,CAAW,CAAA,EAAA,GAAM;AACf,MAAA,QAAA,CAAS,aAAA;AAAA,QACP,IAAI,UAAA,CAAW,WAAA,EAAa,EAAE,OAAA,EAAS,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,IAAA,EAAM,OAAO,CAAC;AAAA,MAC/E,CAAA;AAAA,IACF,CAAA,EAAG,EAAE,CAAA;AAAA,EACP,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,MAAM,UAAA,EAAY,CAAA,2BAAA,EAA8B,OAAO,CAAA,eAAA,EAAkB,KAAK,CAAA,eAAA,EAAkB,IAAI,CAAA,CAAA;AAC9D,EAAA;AAGpC,EAAA;AAAC,IAAA;AAAA,IAAA;AACM,MAAA;AACkB,MAAA;AACb,MAAA;AACC,MAAA;AAGG,MAAA;AAE4C,MAAA;AAAmB,IAAA;AAC/E,EAAA;AAIA,EAAA;AAAC,IAAA;AAAA,IAAA;AACY,MAAA;AACT,QAAA;AAC8B,QAAA;AACF,QAAA;AACD,QAAA;AACN,QAAA;AACrB,QAAA;AAGS,MAAA;AAGX,MAAA;AAAA,wBAAA;AAAC,UAAA;AAAA,UAAA;AACM,YAAA;AACkB,YAAA;AACb,YAAA;AACV,YAAA;AAEC,YAAA;AACuD,cAAA;AAIL,8BAAA;AAAA,YAAA;AAAA,UAAA;AACrD,QAAA;AAGA,wBAAA;AAAC,UAAA;AAAA,UAAA;AACU,YAAA;AAC2D,YAAA;AAC1D,YAAA;AACJ,YAAA;AACI,YAAA;AAAA,UAAA;AACZ,QAAA;AAAA,MAAA;AAAA,IAAA;AACF,EAAA;AAEJ;ADpBuG;AACA;AACA;AACA","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-7FV2X62W.cjs","sourcesContent":[null,"import React, { useCallback } from 'react';\nimport { ChevronDown, LoaderCircle } from 'lucide-react';\nimport { Dropdown } from '../Dropdown/Dropdown.component';\nimport { MenuPanel } from '../Menu';\nimport type { MenuItem } from '../Menu';\nimport { renderIcon } from '../../utils';\nimport type { SplitButtonProps } from './SplitButton.types';\n\n/**\n * SplitButton - a two-part control with a primary action button on the left\n * and a chevron that opens a dropdown of secondary actions on the right.\n *\n * The primary button fires `onClick` directly; clicking the chevron opens the\n * dropdown. Visually the two parts share a single bordered unit.\n *\n * @example\n * ```tsx\n * <SplitButton\n * label=\"Save\"\n * onClick={() => save()}\n * options={[\n * { id: 'draft', label: 'Save as draft', onClick: saveDraft },\n * { id: 'template', label: 'Save as template', onClick: saveTemplate },\n * ]}\n * />\n * ```\n */\nexport const SplitButton: React.FC<SplitButtonProps> = ({\n label,\n onClick,\n options,\n variant = 'filled',\n color = 'primary',\n size = 'md',\n disabled = false,\n loading = false,\n preIcon,\n className = '',\n}) => {\n // Convert SplitButtonOption → MenuItemType so MenuPanel can render them.\n const menuItems: MenuItem[] = options.map((opt) => ({\n type: 'item' as const,\n id: opt.id,\n label: opt.label,\n icon: opt.icon,\n disabled: opt.disabled,\n onClick: opt.onClick,\n }));\n\n const handleItemClick = useCallback(() => {\n // Close the dropdown by dispatching a mousedown outside it.\n setTimeout(() => {\n document.dispatchEvent(\n new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }),\n );\n }, 10);\n }, []);\n\n const baseClass = `eidos-button eidos-button--${variant} eidos-button--${color} eidos-button--${size}`;\n const disabledOrLoading = disabled || loading;\n\n const chevronTrigger = (\n <button\n type=\"button\"\n className={`${baseClass} eidos-split-button__chevron`}\n disabled={disabledOrLoading}\n aria-label=\"More options\"\n // The chevron opens a `MenuPanel`. `Dropdown` adds no ARIA to its trigger,\n // so without this the control is announced as a plain button.\n aria-haspopup=\"menu\"\n >\n <ChevronDown className=\"eidos-split-button__chevron-icon\" aria-hidden=\"true\" />\n </button>\n );\n\n return (\n <div\n className={[\n 'eidos-split-button',\n `eidos-split-button--${variant}`,\n `eidos-split-button--${color}`,\n `eidos-split-button--${size}`,\n disabledOrLoading && 'eidos-split-button--disabled',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Primary action */}\n <button\n type=\"button\"\n className={`${baseClass} eidos-split-button__primary`}\n disabled={disabledOrLoading}\n onClick={onClick}\n >\n {loading ? (\n <LoaderCircle className=\"eidos-split-button__spinner\" aria-hidden=\"true\" />\n ) : (\n preIcon && renderIcon(preIcon, 'eidos-split-button__pre-icon')\n )}\n <span className=\"eidos-split-button__label\">{label}</span>\n </button>\n\n {/* Secondary actions dropdown */}\n <Dropdown\n trigger={chevronTrigger}\n content={<MenuPanel items={menuItems} onItemClick={handleItemClick} />}\n placement=\"bottom\"\n align=\"end\"\n disabled={disabledOrLoading}\n />\n </div>\n );\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-SJKD3WCV.cjs","../src/components/SplitButton/SplitButton.component.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACE;AACF,wDAA6B;AAC7B;AACA;ACVA,8BAAmC;AACnC,2CAA0C;AAsEpC,+CAAA;AA5CC,IAAM,YAAA,EAA0C,CAAC;AAAA,EACtD,KAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,QAAA,EAAU,QAAA;AAAA,EACV,MAAA,EAAQ,SAAA;AAAA,EACR,KAAA,EAAO,IAAA;AAAA,EACP,SAAA,EAAW,KAAA;AAAA,EACX,QAAA,EAAU,KAAA;AAAA,EACV,OAAA;AAAA,EACA,UAAA,EAAY;AACd,CAAA,EAAA,GAAM;AAEJ,EAAA,MAAM,UAAA,EAAwB,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,EAAA,GAAA,CAAS;AAAA,IAClD,IAAA,EAAM,MAAA;AAAA,IACN,EAAA,EAAI,GAAA,CAAI,EAAA;AAAA,IACR,KAAA,EAAO,GAAA,CAAI,KAAA;AAAA,IACX,IAAA,EAAM,GAAA,CAAI,IAAA;AAAA,IACV,QAAA,EAAU,GAAA,CAAI,QAAA;AAAA,IACd,OAAA,EAAS,GAAA,CAAI;AAAA,EACf,CAAA,CAAE,CAAA;AAEF,EAAA,MAAM,gBAAA,EAAkB,gCAAA,CAAY,EAAA,GAAM;AAExC,IAAA,UAAA,CAAW,CAAA,EAAA,GAAM;AACf,MAAA,QAAA,CAAS,aAAA;AAAA,QACP,IAAI,UAAA,CAAW,WAAA,EAAa,EAAE,OAAA,EAAS,IAAA,EAAM,UAAA,EAAY,IAAA,EAAM,IAAA,EAAM,OAAO,CAAC;AAAA,MAC/E,CAAA;AAAA,IACF,CAAA,EAAG,EAAE,CAAA;AAAA,EACP,CAAA,EAAG,CAAC,CAAC,CAAA;AAEL,EAAA,MAAM,UAAA,EAAY,CAAA,2BAAA,EAA8B,OAAO,CAAA,eAAA,EAAkB,KAAK,CAAA,eAAA,EAAkB,IAAI,CAAA,CAAA;AAC9D,EAAA;AAGpC,EAAA;AAAC,IAAA;AAAA,IAAA;AACM,MAAA;AACkB,MAAA;AACb,MAAA;AACC,MAAA;AAGG,MAAA;AAE4C,MAAA;AAAmB,IAAA;AAC/E,EAAA;AAIA,EAAA;AAAC,IAAA;AAAA,IAAA;AACY,MAAA;AACT,QAAA;AAC8B,QAAA;AACF,QAAA;AACD,QAAA;AACN,QAAA;AACrB,QAAA;AAGS,MAAA;AAGX,MAAA;AAAA,wBAAA;AAAC,UAAA;AAAA,UAAA;AACM,YAAA;AACkB,YAAA;AACb,YAAA;AACV,YAAA;AAEC,YAAA;AACuD,cAAA;AAIL,8BAAA;AAAA,YAAA;AAAA,UAAA;AACrD,QAAA;AAGA,wBAAA;AAAC,UAAA;AAAA,UAAA;AACU,YAAA;AAC2D,YAAA;AAC1D,YAAA;AACJ,YAAA;AACI,YAAA;AAAA,UAAA;AACZ,QAAA;AAAA,MAAA;AAAA,IAAA;AACF,EAAA;AAEJ;ADpBuG;AACA;AACA;AACA","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-SJKD3WCV.cjs","sourcesContent":[null,"import React, { useCallback } from 'react';\nimport { ChevronDown, LoaderCircle } from 'lucide-react';\nimport { Dropdown } from '../Dropdown/Dropdown.component';\nimport { MenuPanel } from '../Menu';\nimport type { MenuItem } from '../Menu';\nimport { renderIcon } from '../../utils';\nimport type { SplitButtonProps } from './SplitButton.types';\n\n/**\n * SplitButton - a two-part control with a primary action button on the left\n * and a chevron that opens a dropdown of secondary actions on the right.\n *\n * The primary button fires `onClick` directly; clicking the chevron opens the\n * dropdown. Visually the two parts share a single bordered unit.\n *\n * @example\n * ```tsx\n * <SplitButton\n * label=\"Save\"\n * onClick={() => save()}\n * options={[\n * { id: 'draft', label: 'Save as draft', onClick: saveDraft },\n * { id: 'template', label: 'Save as template', onClick: saveTemplate },\n * ]}\n * />\n * ```\n */\nexport const SplitButton: React.FC<SplitButtonProps> = ({\n label,\n onClick,\n options,\n variant = 'filled',\n color = 'primary',\n size = 'md',\n disabled = false,\n loading = false,\n preIcon,\n className = '',\n}) => {\n // Convert SplitButtonOption → MenuItemType so MenuPanel can render them.\n const menuItems: MenuItem[] = options.map((opt) => ({\n type: 'item' as const,\n id: opt.id,\n label: opt.label,\n icon: opt.icon,\n disabled: opt.disabled,\n onClick: opt.onClick,\n }));\n\n const handleItemClick = useCallback(() => {\n // Close the dropdown by dispatching a mousedown outside it.\n setTimeout(() => {\n document.dispatchEvent(\n new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }),\n );\n }, 10);\n }, []);\n\n const baseClass = `eidos-button eidos-button--${variant} eidos-button--${color} eidos-button--${size}`;\n const disabledOrLoading = disabled || loading;\n\n const chevronTrigger = (\n <button\n type=\"button\"\n className={`${baseClass} eidos-split-button__chevron`}\n disabled={disabledOrLoading}\n aria-label=\"More options\"\n // The chevron opens a `MenuPanel`. `Dropdown` adds no ARIA to its trigger,\n // so without this the control is announced as a plain button.\n aria-haspopup=\"menu\"\n >\n <ChevronDown className=\"eidos-split-button__chevron-icon\" aria-hidden=\"true\" />\n </button>\n );\n\n return (\n <div\n className={[\n 'eidos-split-button',\n `eidos-split-button--${variant}`,\n `eidos-split-button--${color}`,\n `eidos-split-button--${size}`,\n disabledOrLoading && 'eidos-split-button--disabled',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {/* Primary action */}\n <button\n type=\"button\"\n className={`${baseClass} eidos-split-button__primary`}\n disabled={disabledOrLoading}\n onClick={onClick}\n >\n {loading ? (\n <LoaderCircle className=\"eidos-split-button__spinner\" aria-hidden=\"true\" />\n ) : (\n preIcon && renderIcon(preIcon, 'eidos-split-button__pre-icon')\n )}\n <span className=\"eidos-split-button__label\">{label}</span>\n </button>\n\n {/* Secondary actions dropdown */}\n <Dropdown\n trigger={chevronTrigger}\n content={<MenuPanel items={menuItems} onItemClick={handleItemClick} />}\n placement=\"bottom\"\n align=\"end\"\n disabled={disabledOrLoading}\n />\n </div>\n );\n};\n"]}
@@ -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 _chunkVXC7Z7XBcjs = require('./chunk-VXC7Z7XB.cjs');
3
+ var _chunkMKQVDEHIcjs = require('./chunk-MKQVDEHI.cjs');
4
4
 
5
5
  // src/components/ColorPicker/ColorPicker.component.tsx
6
6
  var _react = require('react');
@@ -497,7 +497,7 @@ var ColorPicker = ({
497
497
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: rootClasses, children: [
498
498
  label && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "eidos-color-picker-label", children: label }),
499
499
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
500
- _chunkVXC7Z7XBcjs.Dropdown,
500
+ _chunkMKQVDEHIcjs.Dropdown,
501
501
  {
502
502
  trigger: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
503
503
  "button",
@@ -532,4 +532,4 @@ ColorPicker.displayName = "ColorPicker";
532
532
 
533
533
 
534
534
  exports.ColorPicker = ColorPicker;
535
- //# sourceMappingURL=chunk-LUDK44NZ.cjs.map
535
+ //# sourceMappingURL=chunk-SJPCBRKR.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-LUDK44NZ.cjs","../src/components/ColorPicker/ColorPicker.component.tsx"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACJA,8BAAgE;AAChE,2CAA4B;AAsfpB,+CAAA;AAxeR,IAAM,iBAAA,EAA6B;AAAA,EACjC,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAMA,SAAS,QAAA,CAAS,CAAA,EAAW,CAAA,EAAW,CAAA,EAAqB;AAE3D,EAAA,MAAM,GAAA,EAAK,EAAA,EAAI,GAAA;AACf,EAAA,MAAM,GAAA,EAAK,EAAA,EAAI,GAAA;AACf,EAAA,MAAM,EAAA,EAAI,GAAA,EAAK,EAAA;AACf,EAAA,MAAM,EAAA,EAAI,EAAA,EAAA,CAAK,EAAA,EAAI,IAAA,CAAK,GAAA,CAAM,EAAA,EAAI,GAAA,EAAM,EAAA,EAAK,CAAC,CAAA,CAAA;AAC9C,EAAA,MAAM,EAAA,EAAI,GAAA,EAAK,CAAA;AAEf,EAAA,IAAI,CAAA,EAAW,CAAA,EAAW,CAAA;AAC1B,EAAA,GAAA,CAAI,EAAA,EAAI,EAAA,EAAI;AACV,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AAAA,EACN,EAAA,KAAA,GAAA,CAAW,EAAA,EAAI,GAAA,EAAK;AAClB,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AAAA,EACN,EAAA,KAAA,GAAA,CAAW,EAAA,EAAI,GAAA,EAAK;AAClB,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AAAA,EACN,EAAA,KAAA,GAAA,CAAW,EAAA,EAAI,GAAA,EAAK;AAClB,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AAAA,EACN,EAAA,KAAA,GAAA,CAAW,EAAA,EAAI,GAAA,EAAK;AAClB,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AAAA,EACN,EAAA,KAAO;AACL,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AACJ,IAAA,EAAA,EAAI,CAAA;AAAA,EACN;AAEA,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAA,CAAK,KAAA,CAAA,CAAO,EAAA,EAAI,CAAA,EAAA,EAAK,GAAG,CAAA;AAAA,IAC3B,CAAA,EAAG,IAAA,CAAK,KAAA,CAAA,CAAO,EAAA,EAAI,CAAA,EAAA,EAAK,GAAG,CAAA;AAAA,IAC3B,CAAA,EAAG,IAAA,CAAK,KAAA,CAAA,CAAO,EAAA,EAAI,CAAA,EAAA,EAAK,GAAG;AAAA,EAC7B,CAAA;AACF;AAEA,SAAS,QAAA,CAAS,CAAA,EAAW,CAAA,EAAW,CAAA,EAAqB;AAE3D,EAAA,MAAM,GAAA,EAAK,EAAA,EAAI,GAAA;AACf,EAAA,MAAM,GAAA,EAAK,EAAA,EAAI,GAAA;AACf,EAAA,MAAM,GAAA,EAAK,EAAA,EAAI,GAAA;AAEf,EAAA,MAAM,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA;AAC/B,EAAA,MAAM,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAA,EAAI,EAAE,CAAA;AAC/B,EAAA,MAAM,MAAA,EAAQ,IAAA,EAAM,GAAA;AAEpB,EAAA,MAAM,EAAA,EAAI,IAAA,EAAM,GAAA;AAChB,EAAA,MAAM,EAAA,EAAI,IAAA,IAAQ,EAAA,EAAI,EAAA,EAAK,MAAA,EAAQ,IAAA,EAAO,GAAA;AAE1C,EAAA,IAAI,EAAA,EAAI,CAAA;AACR,EAAA,GAAA,CAAI,MAAA,IAAU,CAAA,EAAG;AACf,IAAA,GAAA,CAAI,IAAA,IAAQ,EAAA,EAAI,EAAA,EAAA,CAAM,GAAA,EAAK,EAAA,EAAA,EAAM,MAAA,EAAS,CAAA;AAAA,IAAA,KAAA,GAAA,CACjC,IAAA,IAAQ,EAAA,EAAI,EAAA,EAAA,CAAK,GAAA,EAAK,EAAA,EAAA,EAAM,MAAA,EAAQ,CAAA;AAAA,IAAA,KACxC,EAAA,EAAA,CAAK,GAAA,EAAK,EAAA,EAAA,EAAM,MAAA,EAAQ,CAAA;AAC7B,IAAA,EAAA,EAAI,EAAA,EAAI,EAAA;AACR,IAAA,GAAA,CAAI,EAAA,EAAI,CAAA,EAAG,EAAA,GAAK,GAAA;AAAA,EAClB;AASA,EAAA,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,EAAE,CAAA;AACnB;AAEA,SAAS,QAAA,CAAS,CAAA,EAAW,CAAA,EAAW,CAAA,EAAmB;AACzD,EAAA,MAAM,GAAA,EAAK,CAAC,CAAA,EAAA,GACV,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,CAAC,CAAC,CAAC,CAAA,CACrC,QAAA,CAAS,EAAE,CAAA,CACX,QAAA,CAAS,CAAA,EAAG,GAAG,CAAA;AACpB,EAAA,OAAO,CAAA,CAAA,EAAI,EAAA,CAAG,CAAC,CAAC,CAAA,EAAA;AAClB;AAEkB;AACF,EAAA;AACY,EAAA;AAET,EAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACJ,EAAA;AACI,IAAA;AACA,IAAA;AACA,IAAA;AACV,EAAA;AACE,IAAA;AACT,EAAA;AAEgB,EAAA;AACC,EAAA;AACnB;AAEkB;AAED,EAAA;AACA,EAAA;AACA,EAAA;AAEE,EAAA;AACA,EAAA;AACH,EAAA;AACG,EAAA;AAET,EAAA;AACA,EAAA;AAES,EAAA;AACF,IAAA;AACG,IAAA;AACP,IAAA;AACM,IAAA;AACP,IAAA;AACG,IAAA;AACb,EAAA;AAEiB,EAAA;AACnB;AAEkB;AAED,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAEW,EAAA;AACd,EAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACS,EAAA;AACT,IAAA;AACA,IAAA;AACA,IAAA;AACS,EAAA;AACT,IAAA;AACA,IAAA;AACA,IAAA;AACS,EAAA;AACT,IAAA;AACA,IAAA;AACA,IAAA;AACS,EAAA;AACT,IAAA;AACA,IAAA;AACA,IAAA;AACC,EAAA;AACD,IAAA;AACA,IAAA;AACA,IAAA;AACN,EAAA;AAEO,EAAA;AACU,IAAA;AACA,IAAA;AACA,IAAA;AACjB,EAAA;AACF;AAMS;AACK,EAAA;AAEC,EAAA;AACN,IAAA;AACI,MAAA;AACJ,IAAA;AACI,MAAA;AAGG,IAAA;AACE,MAAA;AACL,MAAA;AAGT,IAAA;AACF,EAAA;AACF;AAES;AACQ,EAAA;AAGT,EAAA;AACY,EAAA;AAGD,EAAA;AACH,EAAA;AACL,IAAA;AACO,MAAA;AACA,MAAA;AACA,MAAA;AACd,IAAA;AACF,EAAA;AAGiB,EAAA;AACH,EAAA;AACL,IAAA;AACI,MAAA;AACA,MAAA;AACA,MAAA;AACX,IAAA;AACF,EAAA;AAEO,EAAA;AACT;AAGkB;AACJ,EAAA;AACC,EAAA;AACf;AAMwD;AACtD,EAAA;AACA,EAAA;AACA,EAAA;AACS,EAAA;AACG,EAAA;AACG,EAAA;AACJ,EAAA;AACA,EAAA;AACJ,EAAA;AACE,EAAA;AACT,EAAA;AACA,EAAA;AACY,EAAA;AACR;AAEE,EAAA;AAGM,EAAA;AACE,EAAA;AACP,EAAA;AACA,EAAA;AACL,IAAA;AACF,EAAA;AACe,EAAA;AAGA,EAAA;AACE,EAAA;AAEA,EAAA;AACR,EAAA;AAEH,EAAA;AACU,EAAA;AAGV,EAAA;AACM,EAAA;AAEN,EAAA;AACA,EAAA;AAGA,EAAA;AAKA,EAAA;AAGA,EAAA;AACA,EAAA;AAMU,EAAA;AACA,IAAA;AACF,IAAA;AACF,IAAA;AACK,IAAA;AACT,IAAA;AACO,MAAA;AACb,IAAA;AAGI,IAAA;AACS,IAAA;AACR,IAAA;AACU,MAAA;AACf,IAAA;AACS,EAAA;AAGK,EAAA;AACD,IAAA;AACP,MAAA;AACO,QAAA;AACA,QAAA;AACX,MAAA;AACI,MAAA;AACN,IAAA;AACG,EAAA;AAIC,EAAA;AACS,IAAA;AACJ,IAAA;AAEJ,IAAA;AACU,MAAA;AACf,IAAA;AAEY,IAAA;AACA,IAAA;AACA,oBAAA;AACT,EAAA;AAGC,EAAA;AACqC,IAAA;AACzB,MAAA;AACZ,MAAA;AAEW,MAAA;AACL,QAAA;AACD,QAAA;AACC,QAAA;AACI,QAAA;AACA,QAAA;AACC,QAAA;AACb,MAAA;AAEO,MAAA;AAED,MAAA;AACA,MAAA;AACK,QAAA;AACA,QAAA;AACT,QAAA;AACF,MAAA;AAEA,MAAA;AACS,MAAA;AACA,MAAA;AACX,IAAA;AACW,IAAA;AACb,EAAA;AAGM,EAAA;AACwC,IAAA;AAC7B,MAAA;AACf,IAAA;AACW,IAAA;AACb,EAAA;AAGM,EAAA;AACwC,IAAA;AAC/B,MAAA;AACb,IAAA;AACW,IAAA;AACb,EAAA;AAGM,EAAA;AACJ,IAAA;AACa,IAAA;AACV,EAAA;AAGC,EAAA;AACQ,IAAA;AACF,IAAA;AAEK,MAAA;AACb,MAAA;AACF,IAAA;AACe,IAAA;AACJ,IAAA;AAEE,IAAA;AACA,EAAA;AAGT,EAAA;AACa,IAAA;AACH,MAAA;AACF,MAAA;AACC,MAAA;AACb,IAAA;AACW,IAAA;AACb,EAAA;AAGM,EAAA;AACS,IAAA;AACH,IAAA;AAGI,MAAA;AACN,MAAA;AACJ,MAAA;AAEW,IAAA;AAEZ,IAAA;AACA,EAAA;AAKC,EAAA;AAEA,EAAA;AACJ,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACS,IAAA;AACX,IAAA;AACA,IAAA;AACF,EAAA;AAUE,EAAA;AAAC,IAAA;AAAA,IAAA;AACY,MAAA;AAKX,MAAA;AAAA,wBAAA;AAAC,UAAA;AAAA,UAAA;AACM,YAAA;AACL,YAAA;AACO,YAAA;AACL,cAAA;AACE,gBAAA;AACA,gBAAA;AACA,cAAA;AACJ,YAAA;AACA,YAAA;AACK,YAAA;AAEL,YAAA;AAAC,cAAA;AAAA,cAAA;AACC,gBAAA;AACA,gBAAA;AAAO;AAAA;AAGL,kBAAA;AACA,kBAAA;AACA,kBAAA;AACF,gBAAA;AAAA,cAAA;AACF,YAAA;AAAA,UAAA;AACF,QAAA;AAGA,wBAAA;AAEE,0BAAA;AAAC,YAAA;AAAA,YAAA;AACC,cAAA;AACA,cAAA;AACK,cAAA;AACA,cAAA;AACL,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AAAW,YAAA;AACb,UAAA;AAGC,UAAA;AAEG,4BAAA;AACA,4BAAA;AAAC,cAAA;AAAA,cAAA;AACC,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,gBAAA;AACA,gBAAA;AAAW,cAAA;AACb,YAAA;AACF,UAAA;AAEJ,QAAA;AAGA,wBAAA;AACE,0BAAA;AAEK,YAAA;AAAA,YAAA;AAEC,cAAA;AACA,cAAA;AACE,gBAAA;AACA,gBAAA;AAEC,cAAA;AAEH,cAAA;AACA,cAAA;AACA,cAAA;AAEC,cAAA;AAAgB,YAAA;AAZZ,YAAA;AAeX,UAAA;AAEA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACC,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AACE,gBAAA;AACF,cAAA;AACA,cAAA;AACE,gBAAA;AACA,gBAAA;AACF,cAAA;AACA,cAAA;AACE,gBAAA;AACA,gBAAA;AACE,kBAAA;AACF,gBAAA;AACF,cAAA;AAAA,YAAA;AACF,UAAA;AAEA,0BAAA;AAAC,YAAA;AAAA,YAAA;AACC,cAAA;AACA,cAAA;AAGA,cAAA;AACA,cAAA;AACA,cAAA;AACA,cAAA;AAEC,cAAA;AAA+C,YAAA;AAClD,UAAA;AACF,QAAA;AAGC,QAAA;AAGM,UAAA;AAAA,UAAA;AAEM,YAAA;AACL,YAAA;AACE,cAAA;AACA,cAAA;AAEC,YAAA;AAEI,YAAA;AACP,YAAA;AACA,YAAA;AACA,YAAA;AACO,YAAA;AAAA,UAAA;AAZF,UAAA;AAeX,QAAA;AAAA,MAAA;AAAA,IAAA;AAEJ,EAAA;AAII,EAAA;AACJ,IAAA;AACA,IAAA;AACY,IAAA;AACZ,IAAA;AAEe,EAAA;AAIL,EAAA;AAER,IAAA;AACY,MAAA;AACT,MAAA;AACH,IAAA;AAEJ,EAAA;AAIE,EAAA;AACY,IAAA;AACV,oBAAA;AAAC,MAAA;AAAA,MAAA;AAEG,QAAA;AAAC,UAAA;AAAA,UAAA;AACM,YAAA;AACL,YAAA;AACA,YAAA;AACA,YAAA;AAEA,YAAA;AAAA,8BAAA;AAAC,gBAAA;AAAA,gBAAA;AACC,kBAAA;AACA,kBAAA;AAAgC,gBAAA;AAClC,cAAA;AACA,8BAAA;AAA+D,YAAA;AAAA,UAAA;AACjE,QAAA;AAEO,QAAA;AACC,QAAA;AACC,QAAA;AACD,QAAA;AACV,QAAA;AAAA,MAAA;AACF,IAAA;AACF,EAAA;AAEJ;AAEY;ADxJO;AACA;AACA;AACA","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-LUDK44NZ.cjs","sourcesContent":[null,"import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { Copy, Check } from 'lucide-react';\nimport { Dropdown } from '../Dropdown/Dropdown.component';\nimport type {\n ColorPickerProps,\n HSVColor,\n RGBColor,\n HSLColor,\n ColorFormat,\n} from './ColorPicker.types';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_SWATCHES: string[] = [\n '#ef4444',\n '#f97316',\n '#f59e0b',\n '#10b981',\n '#06b6d4',\n '#6366f1',\n '#8b5cf6',\n '#ec4899',\n '#64748b',\n '#1e293b',\n];\n\n// ============================================================================\n// Pure colour-utility functions\n// ============================================================================\n\nfunction hsvToRgb(h: number, s: number, v: number): RGBColor {\n // h: 0–360, s: 0–100, v: 0–100 → r,g,b: 0–255\n const sn = s / 100;\n const vn = v / 100;\n const c = vn * sn;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = vn - c;\n\n let r: number, g: number, b: number;\n if (h < 60) {\n r = c;\n g = x;\n b = 0;\n } else if (h < 120) {\n r = x;\n g = c;\n b = 0;\n } else if (h < 180) {\n r = 0;\n g = c;\n b = x;\n } else if (h < 240) {\n r = 0;\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n g = 0;\n b = c;\n } else {\n r = c;\n g = 0;\n b = x;\n }\n\n return {\n r: Math.round((r + m) * 255),\n g: Math.round((g + m) * 255),\n b: Math.round((b + m) * 255),\n };\n}\n\nfunction rgbToHsv(r: number, g: number, b: number): HSVColor {\n // r,g,b: 0–255 → h: 0–360, s: 0–100, v: 0–100\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const delta = max - min;\n\n const v = max * 100;\n const s = max === 0 ? 0 : (delta / max) * 100;\n\n let h = 0;\n if (delta !== 0) {\n if (max === rn) h = ((gn - bn) / delta) % 6;\n else if (max === gn) h = (bn - rn) / delta + 2;\n else h = (rn - gn) / delta + 4;\n h = h * 60;\n if (h < 0) h += 360;\n }\n\n // Deliberately NOT rounded. HSV is this component's internal state, and\n // rounding s/v to whole percent makes the hex -> HSV -> hex round trip lossy:\n // `#5c5de8` came back as `#5d5de8`, so a controlled `value` displayed a\n // different colour than the one passed in, and any interaction committed the\n // drifted value. `hsvToRgb` already rounds to whole channels at the end, so\n // precision is only needed in between. Every consumer of these floats (the\n // hue gradient, the thumb offsets, the hue slider) accepts them.\n return { h, s, v };\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n const ch = (n: number) =>\n Math.round(Math.max(0, Math.min(255, n)))\n .toString(16)\n .padStart(2, '0');\n return `#${ch(r)}${ch(g)}${ch(b)}`;\n}\n\nfunction hexToRgb(hex: string): RGBColor | null {\n const c = hex.trim().replace(/^#/, '');\n let r: number, g: number, b: number;\n\n if (c.length === 3) {\n r = parseInt(c[0] + c[0], 16);\n g = parseInt(c[1] + c[1], 16);\n b = parseInt(c[2] + c[2], 16);\n } else if (c.length === 6) {\n r = parseInt(c.slice(0, 2), 16);\n g = parseInt(c.slice(2, 4), 16);\n b = parseInt(c.slice(4, 6), 16);\n } else {\n return null;\n }\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null;\n return { r, g, b };\n}\n\nfunction rgbToHsl(r: number, g: number, b: number): HSLColor {\n // r,g,b: 0–255 → h: 0–360, s: 0–100, l: 0–100\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const delta = max - min;\n const l = (max + min) / 2;\n\n let h = 0;\n let s = 0;\n\n if (delta !== 0) {\n s = delta / (1 - Math.abs(2 * l - 1));\n if (max === rn) h = ((gn - bn) / delta) % 6;\n else if (max === gn) h = (bn - rn) / delta + 2;\n else h = (rn - gn) / delta + 4;\n h = h * 60;\n if (h < 0) h += 360;\n }\n\n return { h: Math.round(h), s: Math.round(s * 100), l: Math.round(l * 100) };\n}\n\nfunction hslToRgb(h: number, s: number, l: number): RGBColor {\n // h: 0–360, s: 0–100, l: 0–100 → r,g,b: 0–255\n const sn = s / 100;\n const ln = l / 100;\n const c = (1 - Math.abs(2 * ln - 1)) * sn;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = ln - c / 2;\n\n let r: number, g: number, b: number;\n if (h < 60) {\n r = c;\n g = x;\n b = 0;\n } else if (h < 120) {\n r = x;\n g = c;\n b = 0;\n } else if (h < 180) {\n r = 0;\n g = c;\n b = x;\n } else if (h < 240) {\n r = 0;\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n g = 0;\n b = c;\n } else {\n r = c;\n g = 0;\n b = x;\n }\n\n return {\n r: Math.round((r + m) * 255),\n g: Math.round((g + m) * 255),\n b: Math.round((b + m) * 255),\n };\n}\n\n// ============================================================================\n// Format helpers\n// ============================================================================\n\nfunction colorToText(hsv: HSVColor, alpha: number, fmt: ColorFormat): string {\n const rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);\n\n switch (fmt) {\n case 'hex':\n return rgbToHex(rgb.r, rgb.g, rgb.b);\n case 'rgb':\n return alpha < 1\n ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha.toFixed(2)})`\n : `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;\n case 'hsl': {\n const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);\n return alpha < 1\n ? `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${alpha.toFixed(2)})`\n : `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;\n }\n }\n}\n\nfunction parseColorText(text: string): RGBColor | null {\n const t = text.trim();\n\n // Try hex (with or without leading #)\n const hexCandidate = t.startsWith('#') ? t : /^[0-9a-f]{3,6}$/i.test(t) ? `#${t}` : null;\n if (hexCandidate) return hexToRgb(hexCandidate);\n\n // Try rgb() / rgba()\n const rgbMatch = t.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i);\n if (rgbMatch) {\n return {\n r: parseInt(rgbMatch[1], 10),\n g: parseInt(rgbMatch[2], 10),\n b: parseInt(rgbMatch[3], 10),\n };\n }\n\n // Try hsl() / hsla()\n const hslMatch = t.match(/hsla?\\(\\s*(\\d+)\\s*,\\s*(\\d+)%?\\s*,\\s*(\\d+)%?/i);\n if (hslMatch) {\n return hslToRgb(\n parseInt(hslMatch[1], 10),\n parseInt(hslMatch[2], 10),\n parseInt(hslMatch[3], 10),\n );\n }\n\n return null;\n}\n\n/** Parse a hex string to HSVColor, falling back to red on failure. */\nfunction hexToHsv(hex: string): HSVColor {\n const rgb = hexToRgb(hex);\n return rgb ? rgbToHsv(rgb.r, rgb.g, rgb.b) : { h: 0, s: 100, v: 100 };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ColorPicker: React.FC<ColorPickerProps> = ({\n value,\n defaultValue,\n onChange,\n format = 'hex',\n showAlpha = false,\n showSwatches = true,\n swatches = DEFAULT_SWATCHES,\n disabled = false,\n size = 'md',\n inline = false,\n label,\n ariaLabel,\n className = '',\n}) => {\n // ── Initial hex (only used on first render by useState) ──────────────────\n const initialHex = value ?? defaultValue ?? '#6366f1';\n\n // ── State ─────────────────────────────────────────────────────────────────\n const [hsv, setHsv] = useState<HSVColor>(() => hexToHsv(initialHex));\n const [alpha, setAlpha] = useState<number>(1);\n const [activeFormat, setActiveFormat] = useState<ColorFormat>(format);\n const [inputText, setInputText] = useState<string>(() =>\n colorToText(hexToHsv(initialHex), 1, format),\n );\n const [copied, setCopied] = useState(false);\n\n // ── Refs - give event handlers always-fresh values without stale closures ──\n const hsvRef = useRef<HSVColor>(hsv);\n hsvRef.current = hsv;\n\n const alphaRef = useRef<number>(alpha);\n alphaRef.current = alpha;\n\n const activeFormatRef = useRef<ColorFormat>(activeFormat);\n activeFormatRef.current = activeFormat;\n\n // onChange is stored in a ref so applyColor never becomes stale\n const onChangeRef = useRef<ColorPickerProps['onChange']>(onChange);\n onChangeRef.current = onChange;\n\n const inputFocusedRef = useRef(false);\n const canvasRef = useRef<HTMLDivElement>(null);\n\n // Refs for in-flight drag listeners - cleaned up on mouseup and on unmount\n const dragHandlersRef = useRef<{\n move: (e: MouseEvent) => void;\n up: () => void;\n } | null>(null);\n\n const copiedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // ── Derived ───────────────────────────────────────────────────────────────\n const currentRgb = hsvToRgb(hsv.h, hsv.s, hsv.v);\n const currentHex = rgbToHex(currentRgb.r, currentRgb.g, currentRgb.b);\n\n // ── Sync from controlled `value` prop ─────────────────────────────────────\n // Runs only when `value` changes. We normalize both sides to the same\n // hex format before comparing so that round-trip conversions don't trigger\n // spurious updates (which would overwrite the preserved hue when s/v = 0).\n useEffect(() => {\n if (value === undefined) return;\n const rgb = hexToRgb(value);\n if (!rgb) return;\n const newHsv = rgbToHsv(rgb.r, rgb.g, rgb.b);\n const newNormalised = rgbToHex(\n ...(Object.values(hsvToRgb(newHsv.h, newHsv.s, newHsv.v)) as [number, number, number]),\n );\n // currentHex is captured from this render - guards against echo loops\n // when the parent echoes back our own onChange emission\n if (newNormalised === currentHex) return;\n setHsv(newHsv);\n if (!inputFocusedRef.current) {\n setInputText(colorToText(newHsv, alphaRef.current, activeFormatRef.current));\n }\n }, [value, currentHex]);\n\n // ── Cleanup drag listeners and timers on unmount ──────────────────────────\n useEffect(() => {\n return () => {\n if (dragHandlersRef.current) {\n document.removeEventListener('mousemove', dragHandlersRef.current.move);\n document.removeEventListener('mouseup', dragHandlersRef.current.up);\n }\n if (copiedTimerRef.current) clearTimeout(copiedTimerRef.current);\n };\n }, []);\n\n // ── Core: apply a new HSV + alpha, emit onChange ───────────────────────────\n // Stable (empty dep array) - reads live values exclusively via refs.\n const applyColor = useCallback((newHsv: HSVColor, newAlpha: number) => {\n setHsv(newHsv);\n setAlpha(newAlpha);\n\n if (!inputFocusedRef.current) {\n setInputText(colorToText(newHsv, newAlpha, activeFormatRef.current));\n }\n\n const rgb = hsvToRgb(newHsv.h, newHsv.s, newHsv.v);\n const hex = rgbToHex(rgb.r, rgb.g, rgb.b);\n onChangeRef.current?.(hex);\n }, []);\n\n // ── 2-D saturation / brightness canvas ────────────────────────────────────\n const handleCanvasMouseDown = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n\n const pick = (clientX: number, clientY: number) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const rect = canvas.getBoundingClientRect();\n const s = Math.max(0, Math.min(100, ((clientX - rect.left) / rect.width) * 100));\n const v = Math.max(0, Math.min(100, 100 - ((clientY - rect.top) / rect.height) * 100));\n applyColor({ h: hsvRef.current.h, s, v }, alphaRef.current);\n };\n\n pick(e.clientX, e.clientY);\n\n const handleMouseMove = (me: MouseEvent) => pick(me.clientX, me.clientY);\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n dragHandlersRef.current = null;\n };\n\n dragHandlersRef.current = { move: handleMouseMove, up: handleMouseUp };\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n },\n [disabled, applyColor],\n );\n\n // ── Hue slider ────────────────────────────────────────────────────────────\n const handleHueChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n applyColor({ ...hsvRef.current, h: Number(e.target.value) }, alphaRef.current);\n },\n [applyColor],\n );\n\n // ── Alpha slider ──────────────────────────────────────────────────────────\n const handleAlphaChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n applyColor(hsvRef.current, Number(e.target.value) / 100);\n },\n [applyColor],\n );\n\n // ── Format toggle ─────────────────────────────────────────────────────────\n const handleFormatChange = useCallback((fmt: ColorFormat) => {\n setActiveFormat(fmt);\n setInputText(colorToText(hsvRef.current, alphaRef.current, fmt));\n }, []);\n\n // ── Text-input commit (Enter / blur) ──────────────────────────────────────\n const handleInputCommit = useCallback(() => {\n const rgb = parseColorText(inputText);\n if (!rgb) {\n // Invalid - reset to the current valid colour\n setInputText(colorToText(hsvRef.current, alphaRef.current, activeFormatRef.current));\n return;\n }\n const newHsv = rgbToHsv(rgb.r, rgb.g, rgb.b);\n applyColor(newHsv, alphaRef.current);\n // Always normalise the text after a commit (even if the input still has focus)\n setInputText(colorToText(newHsv, alphaRef.current, activeFormatRef.current));\n }, [inputText, applyColor]);\n\n // ── Swatch click ──────────────────────────────────────────────────────────\n const handleSwatchClick = useCallback(\n (hex: string) => {\n const rgb = hexToRgb(hex);\n if (!rgb) return;\n applyColor(rgbToHsv(rgb.r, rgb.g, rgb.b), alphaRef.current);\n },\n [applyColor],\n );\n\n // ── Copy to clipboard ─────────────────────────────────────────────────────\n const handleCopy = useCallback(() => {\n const text = colorToText(hsvRef.current, alphaRef.current, activeFormatRef.current);\n navigator.clipboard\n .writeText(text)\n .then(() => {\n setCopied(true);\n if (copiedTimerRef.current) clearTimeout(copiedTimerRef.current);\n copiedTimerRef.current = setTimeout(() => setCopied(false), 2000);\n })\n .catch(() => {\n // Clipboard access denied - silently ignore\n });\n }, []);\n\n // ── Alpha-slider background gradient ─────────────────────────────────────\n // We use a transparent-to-current-colour gradient layered over a checkerboard\n // so the alpha slider always shows the correct colour transition.\n const transparentColor = `rgba(${currentRgb.r}, ${currentRgb.g}, ${currentRgb.b}, 0)`;\n\n const alphaTrackBg = {\n backgroundImage: [\n `linear-gradient(to right, ${transparentColor}, ${currentHex})`,\n 'linear-gradient(45deg, #e2e8f0 25%, transparent 25%)',\n 'linear-gradient(-45deg, #e2e8f0 25%, transparent 25%)',\n 'linear-gradient(45deg, transparent 75%, #e2e8f0 75%)',\n 'linear-gradient(-45deg, transparent 75%, #e2e8f0 75%)',\n ].join(', '),\n backgroundSize: '100%, 8px 8px, 8px 8px, 8px 8px, 8px 8px',\n backgroundPosition: '0 0, 0 0, 0 4px, 4px -4px, -4px 0',\n };\n\n // ── Picker panel (shared between inline and popover modes) ────────────────\n //\n // The size modifier has to live on the panel itself, not only on the root:\n // in popover mode the panel is portaled to document.body by Dropdown, so\n // anything inside it that sized itself off a `.eidos-color-picker--{size}`\n // ancestor matched nothing and collapsed. That is what removed the\n // saturation/brightness canvas entirely from every non-inline picker.\n const panel = (\n <div\n className={`eidos-color-picker-panel eidos-color-picker-panel--${size}${\n inline ? ' eidos-color-picker-panel--inline' : ''\n }`}\n >\n {/* 2-D sat / brightness canvas */}\n <div\n ref={canvasRef}\n className=\"eidos-color-picker-canvas\"\n style={{\n background: [\n 'linear-gradient(to top, #000, transparent)',\n `linear-gradient(to right, #fff, hsl(${hsv.h}, 100%, 50%))`,\n ].join(', '),\n }}\n onMouseDown={handleCanvasMouseDown}\n role=\"presentation\"\n >\n <div\n className=\"eidos-color-picker-thumb\"\n style={{\n // Rounded for display only - hsv.s/v are unrounded floats so the\n // hex round trip stays lossless (see rgbToHsv).\n left: `${hsv.s.toFixed(2)}%`,\n top: `${(100 - hsv.v).toFixed(2)}%`,\n background: currentHex,\n }}\n />\n </div>\n\n {/* Sliders */}\n <div className=\"eidos-color-picker-sliders\">\n {/* Hue */}\n <input\n type=\"range\"\n className=\"eidos-color-picker-hue\"\n min={0}\n max={360}\n step={1}\n value={hsv.h}\n disabled={disabled}\n onChange={handleHueChange}\n aria-label=\"Hue\"\n />\n\n {/* Alpha */}\n {showAlpha && (\n <div className=\"eidos-color-picker-alpha-wrapper\">\n <div className=\"eidos-color-picker-alpha-bg\" style={alphaTrackBg} />\n <input\n type=\"range\"\n className=\"eidos-color-picker-alpha\"\n min={0}\n max={100}\n step={1}\n value={Math.round(alpha * 100)}\n disabled={disabled}\n onChange={handleAlphaChange}\n aria-label=\"Opacity\"\n />\n </div>\n )}\n </div>\n\n {/* Text input + format toggles + copy */}\n <div className=\"eidos-color-picker-inputs\">\n <div className=\"eidos-color-picker-format-btns\" role=\"group\" aria-label=\"Colour format\">\n {(['hex', 'rgb', 'hsl'] as ColorFormat[]).map((fmt) => (\n <button\n key={fmt}\n type=\"button\"\n className={[\n 'eidos-color-picker-format-btn',\n activeFormat === fmt && 'eidos-color-picker-format-btn--active',\n ]\n .filter(Boolean)\n .join(' ')}\n onClick={() => handleFormatChange(fmt)}\n disabled={disabled}\n aria-pressed={activeFormat === fmt}\n >\n {fmt.toUpperCase()}\n </button>\n ))}\n </div>\n\n <input\n type=\"text\"\n className=\"eidos-color-picker-input\"\n value={inputText}\n disabled={disabled}\n spellCheck={false}\n aria-label=\"Colour value\"\n onChange={(e) => setInputText(e.target.value)}\n onFocus={() => {\n inputFocusedRef.current = true;\n }}\n onBlur={() => {\n inputFocusedRef.current = false;\n handleInputCommit();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleInputCommit();\n if (e.key === 'Escape') {\n setInputText(colorToText(hsvRef.current, alphaRef.current, activeFormatRef.current));\n }\n }}\n />\n\n <button\n type=\"button\"\n className={['eidos-color-picker-copy', copied && 'eidos-color-picker-copy--copied']\n .filter(Boolean)\n .join(' ')}\n onClick={handleCopy}\n disabled={disabled}\n aria-label=\"Copy colour value\"\n title=\"Copy colour value\"\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n </div>\n\n {/* Swatches */}\n {showSwatches && (\n <div className=\"eidos-color-picker-swatches\" role=\"group\" aria-label=\"Colour presets\">\n {swatches.map((swatchHex) => (\n <button\n key={swatchHex}\n type=\"button\"\n className={[\n 'eidos-color-picker-swatch',\n currentHex === swatchHex && 'eidos-color-picker-swatch--active',\n ]\n .filter(Boolean)\n .join(' ')}\n style={{ background: swatchHex }}\n onClick={() => handleSwatchClick(swatchHex)}\n disabled={disabled}\n aria-label={`Select ${swatchHex}`}\n title={swatchHex}\n />\n ))}\n </div>\n )}\n </div>\n );\n\n // ── Root element classes ───────────────────────────────────────────────────\n const rootClasses = [\n 'eidos-color-picker',\n `eidos-color-picker--${size}`,\n disabled && 'eidos-color-picker--disabled',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n // ── Inline mode ───────────────────────────────────────────────────────────\n if (inline) {\n return (\n <div className={rootClasses}>\n {label && <span className=\"eidos-color-picker-label\">{label}</span>}\n {panel}\n </div>\n );\n }\n\n // ── Popover (trigger + Dropdown) ──────────────────────────────────────────\n return (\n <div className={rootClasses}>\n {label && <span className=\"eidos-color-picker-label\">{label}</span>}\n <Dropdown\n trigger={\n <button\n type=\"button\"\n className=\"eidos-color-picker-trigger\"\n disabled={disabled}\n aria-label={label ?? ariaLabel ?? 'Open colour picker'}\n >\n <span\n className=\"eidos-color-picker-trigger-swatch\"\n style={{ background: currentHex }}\n />\n <span className=\"eidos-color-picker-trigger-value\">{currentHex}</span>\n </button>\n }\n content={panel}\n placement=\"bottom\"\n autoWidth={false}\n minWidth={260}\n disabled={disabled}\n />\n </div>\n );\n};\n\nColorPicker.displayName = 'ColorPicker';\n"]}
1
+ {"version":3,"sources":["/home/runner/work/eidos-ui/eidos-ui/dist/chunk-SJPCBRKR.cjs","../src/components/ColorPicker/ColorPicker.component.tsx"],"names":[],"mappings":"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","file":"/home/runner/work/eidos-ui/eidos-ui/dist/chunk-SJPCBRKR.cjs","sourcesContent":[null,"import React, { useState, useRef, useEffect, useCallback } from 'react';\nimport { Copy, Check } from 'lucide-react';\nimport { Dropdown } from '../Dropdown/Dropdown.component';\nimport type {\n ColorPickerProps,\n HSVColor,\n RGBColor,\n HSLColor,\n ColorFormat,\n} from './ColorPicker.types';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\nconst DEFAULT_SWATCHES: string[] = [\n '#ef4444',\n '#f97316',\n '#f59e0b',\n '#10b981',\n '#06b6d4',\n '#6366f1',\n '#8b5cf6',\n '#ec4899',\n '#64748b',\n '#1e293b',\n];\n\n// ============================================================================\n// Pure colour-utility functions\n// ============================================================================\n\nfunction hsvToRgb(h: number, s: number, v: number): RGBColor {\n // h: 0–360, s: 0–100, v: 0–100 → r,g,b: 0–255\n const sn = s / 100;\n const vn = v / 100;\n const c = vn * sn;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = vn - c;\n\n let r: number, g: number, b: number;\n if (h < 60) {\n r = c;\n g = x;\n b = 0;\n } else if (h < 120) {\n r = x;\n g = c;\n b = 0;\n } else if (h < 180) {\n r = 0;\n g = c;\n b = x;\n } else if (h < 240) {\n r = 0;\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n g = 0;\n b = c;\n } else {\n r = c;\n g = 0;\n b = x;\n }\n\n return {\n r: Math.round((r + m) * 255),\n g: Math.round((g + m) * 255),\n b: Math.round((b + m) * 255),\n };\n}\n\nfunction rgbToHsv(r: number, g: number, b: number): HSVColor {\n // r,g,b: 0–255 → h: 0–360, s: 0–100, v: 0–100\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const delta = max - min;\n\n const v = max * 100;\n const s = max === 0 ? 0 : (delta / max) * 100;\n\n let h = 0;\n if (delta !== 0) {\n if (max === rn) h = ((gn - bn) / delta) % 6;\n else if (max === gn) h = (bn - rn) / delta + 2;\n else h = (rn - gn) / delta + 4;\n h = h * 60;\n if (h < 0) h += 360;\n }\n\n // Deliberately NOT rounded. HSV is this component's internal state, and\n // rounding s/v to whole percent makes the hex -> HSV -> hex round trip lossy:\n // `#5c5de8` came back as `#5d5de8`, so a controlled `value` displayed a\n // different colour than the one passed in, and any interaction committed the\n // drifted value. `hsvToRgb` already rounds to whole channels at the end, so\n // precision is only needed in between. Every consumer of these floats (the\n // hue gradient, the thumb offsets, the hue slider) accepts them.\n return { h, s, v };\n}\n\nfunction rgbToHex(r: number, g: number, b: number): string {\n const ch = (n: number) =>\n Math.round(Math.max(0, Math.min(255, n)))\n .toString(16)\n .padStart(2, '0');\n return `#${ch(r)}${ch(g)}${ch(b)}`;\n}\n\nfunction hexToRgb(hex: string): RGBColor | null {\n const c = hex.trim().replace(/^#/, '');\n let r: number, g: number, b: number;\n\n if (c.length === 3) {\n r = parseInt(c[0] + c[0], 16);\n g = parseInt(c[1] + c[1], 16);\n b = parseInt(c[2] + c[2], 16);\n } else if (c.length === 6) {\n r = parseInt(c.slice(0, 2), 16);\n g = parseInt(c.slice(2, 4), 16);\n b = parseInt(c.slice(4, 6), 16);\n } else {\n return null;\n }\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) return null;\n return { r, g, b };\n}\n\nfunction rgbToHsl(r: number, g: number, b: number): HSLColor {\n // r,g,b: 0–255 → h: 0–360, s: 0–100, l: 0–100\n const rn = r / 255;\n const gn = g / 255;\n const bn = b / 255;\n\n const max = Math.max(rn, gn, bn);\n const min = Math.min(rn, gn, bn);\n const delta = max - min;\n const l = (max + min) / 2;\n\n let h = 0;\n let s = 0;\n\n if (delta !== 0) {\n s = delta / (1 - Math.abs(2 * l - 1));\n if (max === rn) h = ((gn - bn) / delta) % 6;\n else if (max === gn) h = (bn - rn) / delta + 2;\n else h = (rn - gn) / delta + 4;\n h = h * 60;\n if (h < 0) h += 360;\n }\n\n return { h: Math.round(h), s: Math.round(s * 100), l: Math.round(l * 100) };\n}\n\nfunction hslToRgb(h: number, s: number, l: number): RGBColor {\n // h: 0–360, s: 0–100, l: 0–100 → r,g,b: 0–255\n const sn = s / 100;\n const ln = l / 100;\n const c = (1 - Math.abs(2 * ln - 1)) * sn;\n const x = c * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = ln - c / 2;\n\n let r: number, g: number, b: number;\n if (h < 60) {\n r = c;\n g = x;\n b = 0;\n } else if (h < 120) {\n r = x;\n g = c;\n b = 0;\n } else if (h < 180) {\n r = 0;\n g = c;\n b = x;\n } else if (h < 240) {\n r = 0;\n g = x;\n b = c;\n } else if (h < 300) {\n r = x;\n g = 0;\n b = c;\n } else {\n r = c;\n g = 0;\n b = x;\n }\n\n return {\n r: Math.round((r + m) * 255),\n g: Math.round((g + m) * 255),\n b: Math.round((b + m) * 255),\n };\n}\n\n// ============================================================================\n// Format helpers\n// ============================================================================\n\nfunction colorToText(hsv: HSVColor, alpha: number, fmt: ColorFormat): string {\n const rgb = hsvToRgb(hsv.h, hsv.s, hsv.v);\n\n switch (fmt) {\n case 'hex':\n return rgbToHex(rgb.r, rgb.g, rgb.b);\n case 'rgb':\n return alpha < 1\n ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha.toFixed(2)})`\n : `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;\n case 'hsl': {\n const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);\n return alpha < 1\n ? `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${alpha.toFixed(2)})`\n : `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;\n }\n }\n}\n\nfunction parseColorText(text: string): RGBColor | null {\n const t = text.trim();\n\n // Try hex (with or without leading #)\n const hexCandidate = t.startsWith('#') ? t : /^[0-9a-f]{3,6}$/i.test(t) ? `#${t}` : null;\n if (hexCandidate) return hexToRgb(hexCandidate);\n\n // Try rgb() / rgba()\n const rgbMatch = t.match(/rgba?\\(\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)/i);\n if (rgbMatch) {\n return {\n r: parseInt(rgbMatch[1], 10),\n g: parseInt(rgbMatch[2], 10),\n b: parseInt(rgbMatch[3], 10),\n };\n }\n\n // Try hsl() / hsla()\n const hslMatch = t.match(/hsla?\\(\\s*(\\d+)\\s*,\\s*(\\d+)%?\\s*,\\s*(\\d+)%?/i);\n if (hslMatch) {\n return hslToRgb(\n parseInt(hslMatch[1], 10),\n parseInt(hslMatch[2], 10),\n parseInt(hslMatch[3], 10),\n );\n }\n\n return null;\n}\n\n/** Parse a hex string to HSVColor, falling back to red on failure. */\nfunction hexToHsv(hex: string): HSVColor {\n const rgb = hexToRgb(hex);\n return rgb ? rgbToHsv(rgb.r, rgb.g, rgb.b) : { h: 0, s: 100, v: 100 };\n}\n\n// ============================================================================\n// Component\n// ============================================================================\n\nexport const ColorPicker: React.FC<ColorPickerProps> = ({\n value,\n defaultValue,\n onChange,\n format = 'hex',\n showAlpha = false,\n showSwatches = true,\n swatches = DEFAULT_SWATCHES,\n disabled = false,\n size = 'md',\n inline = false,\n label,\n ariaLabel,\n className = '',\n}) => {\n // ── Initial hex (only used on first render by useState) ──────────────────\n const initialHex = value ?? defaultValue ?? '#6366f1';\n\n // ── State ─────────────────────────────────────────────────────────────────\n const [hsv, setHsv] = useState<HSVColor>(() => hexToHsv(initialHex));\n const [alpha, setAlpha] = useState<number>(1);\n const [activeFormat, setActiveFormat] = useState<ColorFormat>(format);\n const [inputText, setInputText] = useState<string>(() =>\n colorToText(hexToHsv(initialHex), 1, format),\n );\n const [copied, setCopied] = useState(false);\n\n // ── Refs - give event handlers always-fresh values without stale closures ──\n const hsvRef = useRef<HSVColor>(hsv);\n hsvRef.current = hsv;\n\n const alphaRef = useRef<number>(alpha);\n alphaRef.current = alpha;\n\n const activeFormatRef = useRef<ColorFormat>(activeFormat);\n activeFormatRef.current = activeFormat;\n\n // onChange is stored in a ref so applyColor never becomes stale\n const onChangeRef = useRef<ColorPickerProps['onChange']>(onChange);\n onChangeRef.current = onChange;\n\n const inputFocusedRef = useRef(false);\n const canvasRef = useRef<HTMLDivElement>(null);\n\n // Refs for in-flight drag listeners - cleaned up on mouseup and on unmount\n const dragHandlersRef = useRef<{\n move: (e: MouseEvent) => void;\n up: () => void;\n } | null>(null);\n\n const copiedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // ── Derived ───────────────────────────────────────────────────────────────\n const currentRgb = hsvToRgb(hsv.h, hsv.s, hsv.v);\n const currentHex = rgbToHex(currentRgb.r, currentRgb.g, currentRgb.b);\n\n // ── Sync from controlled `value` prop ─────────────────────────────────────\n // Runs only when `value` changes. We normalize both sides to the same\n // hex format before comparing so that round-trip conversions don't trigger\n // spurious updates (which would overwrite the preserved hue when s/v = 0).\n useEffect(() => {\n if (value === undefined) return;\n const rgb = hexToRgb(value);\n if (!rgb) return;\n const newHsv = rgbToHsv(rgb.r, rgb.g, rgb.b);\n const newNormalised = rgbToHex(\n ...(Object.values(hsvToRgb(newHsv.h, newHsv.s, newHsv.v)) as [number, number, number]),\n );\n // currentHex is captured from this render - guards against echo loops\n // when the parent echoes back our own onChange emission\n if (newNormalised === currentHex) return;\n setHsv(newHsv);\n if (!inputFocusedRef.current) {\n setInputText(colorToText(newHsv, alphaRef.current, activeFormatRef.current));\n }\n }, [value, currentHex]);\n\n // ── Cleanup drag listeners and timers on unmount ──────────────────────────\n useEffect(() => {\n return () => {\n if (dragHandlersRef.current) {\n document.removeEventListener('mousemove', dragHandlersRef.current.move);\n document.removeEventListener('mouseup', dragHandlersRef.current.up);\n }\n if (copiedTimerRef.current) clearTimeout(copiedTimerRef.current);\n };\n }, []);\n\n // ── Core: apply a new HSV + alpha, emit onChange ───────────────────────────\n // Stable (empty dep array) - reads live values exclusively via refs.\n const applyColor = useCallback((newHsv: HSVColor, newAlpha: number) => {\n setHsv(newHsv);\n setAlpha(newAlpha);\n\n if (!inputFocusedRef.current) {\n setInputText(colorToText(newHsv, newAlpha, activeFormatRef.current));\n }\n\n const rgb = hsvToRgb(newHsv.h, newHsv.s, newHsv.v);\n const hex = rgbToHex(rgb.r, rgb.g, rgb.b);\n onChangeRef.current?.(hex);\n }, []);\n\n // ── 2-D saturation / brightness canvas ────────────────────────────────────\n const handleCanvasMouseDown = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n if (disabled) return;\n e.preventDefault();\n\n const pick = (clientX: number, clientY: number) => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const rect = canvas.getBoundingClientRect();\n const s = Math.max(0, Math.min(100, ((clientX - rect.left) / rect.width) * 100));\n const v = Math.max(0, Math.min(100, 100 - ((clientY - rect.top) / rect.height) * 100));\n applyColor({ h: hsvRef.current.h, s, v }, alphaRef.current);\n };\n\n pick(e.clientX, e.clientY);\n\n const handleMouseMove = (me: MouseEvent) => pick(me.clientX, me.clientY);\n const handleMouseUp = () => {\n document.removeEventListener('mousemove', handleMouseMove);\n document.removeEventListener('mouseup', handleMouseUp);\n dragHandlersRef.current = null;\n };\n\n dragHandlersRef.current = { move: handleMouseMove, up: handleMouseUp };\n document.addEventListener('mousemove', handleMouseMove);\n document.addEventListener('mouseup', handleMouseUp);\n },\n [disabled, applyColor],\n );\n\n // ── Hue slider ────────────────────────────────────────────────────────────\n const handleHueChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n applyColor({ ...hsvRef.current, h: Number(e.target.value) }, alphaRef.current);\n },\n [applyColor],\n );\n\n // ── Alpha slider ──────────────────────────────────────────────────────────\n const handleAlphaChange = useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n applyColor(hsvRef.current, Number(e.target.value) / 100);\n },\n [applyColor],\n );\n\n // ── Format toggle ─────────────────────────────────────────────────────────\n const handleFormatChange = useCallback((fmt: ColorFormat) => {\n setActiveFormat(fmt);\n setInputText(colorToText(hsvRef.current, alphaRef.current, fmt));\n }, []);\n\n // ── Text-input commit (Enter / blur) ──────────────────────────────────────\n const handleInputCommit = useCallback(() => {\n const rgb = parseColorText(inputText);\n if (!rgb) {\n // Invalid - reset to the current valid colour\n setInputText(colorToText(hsvRef.current, alphaRef.current, activeFormatRef.current));\n return;\n }\n const newHsv = rgbToHsv(rgb.r, rgb.g, rgb.b);\n applyColor(newHsv, alphaRef.current);\n // Always normalise the text after a commit (even if the input still has focus)\n setInputText(colorToText(newHsv, alphaRef.current, activeFormatRef.current));\n }, [inputText, applyColor]);\n\n // ── Swatch click ──────────────────────────────────────────────────────────\n const handleSwatchClick = useCallback(\n (hex: string) => {\n const rgb = hexToRgb(hex);\n if (!rgb) return;\n applyColor(rgbToHsv(rgb.r, rgb.g, rgb.b), alphaRef.current);\n },\n [applyColor],\n );\n\n // ── Copy to clipboard ─────────────────────────────────────────────────────\n const handleCopy = useCallback(() => {\n const text = colorToText(hsvRef.current, alphaRef.current, activeFormatRef.current);\n navigator.clipboard\n .writeText(text)\n .then(() => {\n setCopied(true);\n if (copiedTimerRef.current) clearTimeout(copiedTimerRef.current);\n copiedTimerRef.current = setTimeout(() => setCopied(false), 2000);\n })\n .catch(() => {\n // Clipboard access denied - silently ignore\n });\n }, []);\n\n // ── Alpha-slider background gradient ─────────────────────────────────────\n // We use a transparent-to-current-colour gradient layered over a checkerboard\n // so the alpha slider always shows the correct colour transition.\n const transparentColor = `rgba(${currentRgb.r}, ${currentRgb.g}, ${currentRgb.b}, 0)`;\n\n const alphaTrackBg = {\n backgroundImage: [\n `linear-gradient(to right, ${transparentColor}, ${currentHex})`,\n 'linear-gradient(45deg, #e2e8f0 25%, transparent 25%)',\n 'linear-gradient(-45deg, #e2e8f0 25%, transparent 25%)',\n 'linear-gradient(45deg, transparent 75%, #e2e8f0 75%)',\n 'linear-gradient(-45deg, transparent 75%, #e2e8f0 75%)',\n ].join(', '),\n backgroundSize: '100%, 8px 8px, 8px 8px, 8px 8px, 8px 8px',\n backgroundPosition: '0 0, 0 0, 0 4px, 4px -4px, -4px 0',\n };\n\n // ── Picker panel (shared between inline and popover modes) ────────────────\n //\n // The size modifier has to live on the panel itself, not only on the root:\n // in popover mode the panel is portaled to document.body by Dropdown, so\n // anything inside it that sized itself off a `.eidos-color-picker--{size}`\n // ancestor matched nothing and collapsed. That is what removed the\n // saturation/brightness canvas entirely from every non-inline picker.\n const panel = (\n <div\n className={`eidos-color-picker-panel eidos-color-picker-panel--${size}${\n inline ? ' eidos-color-picker-panel--inline' : ''\n }`}\n >\n {/* 2-D sat / brightness canvas */}\n <div\n ref={canvasRef}\n className=\"eidos-color-picker-canvas\"\n style={{\n background: [\n 'linear-gradient(to top, #000, transparent)',\n `linear-gradient(to right, #fff, hsl(${hsv.h}, 100%, 50%))`,\n ].join(', '),\n }}\n onMouseDown={handleCanvasMouseDown}\n role=\"presentation\"\n >\n <div\n className=\"eidos-color-picker-thumb\"\n style={{\n // Rounded for display only - hsv.s/v are unrounded floats so the\n // hex round trip stays lossless (see rgbToHsv).\n left: `${hsv.s.toFixed(2)}%`,\n top: `${(100 - hsv.v).toFixed(2)}%`,\n background: currentHex,\n }}\n />\n </div>\n\n {/* Sliders */}\n <div className=\"eidos-color-picker-sliders\">\n {/* Hue */}\n <input\n type=\"range\"\n className=\"eidos-color-picker-hue\"\n min={0}\n max={360}\n step={1}\n value={hsv.h}\n disabled={disabled}\n onChange={handleHueChange}\n aria-label=\"Hue\"\n />\n\n {/* Alpha */}\n {showAlpha && (\n <div className=\"eidos-color-picker-alpha-wrapper\">\n <div className=\"eidos-color-picker-alpha-bg\" style={alphaTrackBg} />\n <input\n type=\"range\"\n className=\"eidos-color-picker-alpha\"\n min={0}\n max={100}\n step={1}\n value={Math.round(alpha * 100)}\n disabled={disabled}\n onChange={handleAlphaChange}\n aria-label=\"Opacity\"\n />\n </div>\n )}\n </div>\n\n {/* Text input + format toggles + copy */}\n <div className=\"eidos-color-picker-inputs\">\n <div className=\"eidos-color-picker-format-btns\" role=\"group\" aria-label=\"Colour format\">\n {(['hex', 'rgb', 'hsl'] as ColorFormat[]).map((fmt) => (\n <button\n key={fmt}\n type=\"button\"\n className={[\n 'eidos-color-picker-format-btn',\n activeFormat === fmt && 'eidos-color-picker-format-btn--active',\n ]\n .filter(Boolean)\n .join(' ')}\n onClick={() => handleFormatChange(fmt)}\n disabled={disabled}\n aria-pressed={activeFormat === fmt}\n >\n {fmt.toUpperCase()}\n </button>\n ))}\n </div>\n\n <input\n type=\"text\"\n className=\"eidos-color-picker-input\"\n value={inputText}\n disabled={disabled}\n spellCheck={false}\n aria-label=\"Colour value\"\n onChange={(e) => setInputText(e.target.value)}\n onFocus={() => {\n inputFocusedRef.current = true;\n }}\n onBlur={() => {\n inputFocusedRef.current = false;\n handleInputCommit();\n }}\n onKeyDown={(e) => {\n if (e.key === 'Enter') handleInputCommit();\n if (e.key === 'Escape') {\n setInputText(colorToText(hsvRef.current, alphaRef.current, activeFormatRef.current));\n }\n }}\n />\n\n <button\n type=\"button\"\n className={['eidos-color-picker-copy', copied && 'eidos-color-picker-copy--copied']\n .filter(Boolean)\n .join(' ')}\n onClick={handleCopy}\n disabled={disabled}\n aria-label=\"Copy colour value\"\n title=\"Copy colour value\"\n >\n {copied ? <Check size={14} /> : <Copy size={14} />}\n </button>\n </div>\n\n {/* Swatches */}\n {showSwatches && (\n <div className=\"eidos-color-picker-swatches\" role=\"group\" aria-label=\"Colour presets\">\n {swatches.map((swatchHex) => (\n <button\n key={swatchHex}\n type=\"button\"\n className={[\n 'eidos-color-picker-swatch',\n currentHex === swatchHex && 'eidos-color-picker-swatch--active',\n ]\n .filter(Boolean)\n .join(' ')}\n style={{ background: swatchHex }}\n onClick={() => handleSwatchClick(swatchHex)}\n disabled={disabled}\n aria-label={`Select ${swatchHex}`}\n title={swatchHex}\n />\n ))}\n </div>\n )}\n </div>\n );\n\n // ── Root element classes ───────────────────────────────────────────────────\n const rootClasses = [\n 'eidos-color-picker',\n `eidos-color-picker--${size}`,\n disabled && 'eidos-color-picker--disabled',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n // ── Inline mode ───────────────────────────────────────────────────────────\n if (inline) {\n return (\n <div className={rootClasses}>\n {label && <span className=\"eidos-color-picker-label\">{label}</span>}\n {panel}\n </div>\n );\n }\n\n // ── Popover (trigger + Dropdown) ──────────────────────────────────────────\n return (\n <div className={rootClasses}>\n {label && <span className=\"eidos-color-picker-label\">{label}</span>}\n <Dropdown\n trigger={\n <button\n type=\"button\"\n className=\"eidos-color-picker-trigger\"\n disabled={disabled}\n aria-label={label ?? ariaLabel ?? 'Open colour picker'}\n >\n <span\n className=\"eidos-color-picker-trigger-swatch\"\n style={{ background: currentHex }}\n />\n <span className=\"eidos-color-picker-trigger-value\">{currentHex}</span>\n </button>\n }\n content={panel}\n placement=\"bottom\"\n autoWidth={false}\n minWidth={260}\n disabled={disabled}\n />\n </div>\n );\n};\n\nColorPicker.displayName = 'ColorPicker';\n"]}
@@ -11,13 +11,13 @@ import {
11
11
  useSensor,
12
12
  useSensors,
13
13
  useSortable
14
- } from "./chunk-H3C6YECZ.js";
14
+ } from "./chunk-D2PXPX56.js";
15
15
  import {
16
16
  SplitButton
17
- } from "./chunk-FHOD3FUN.js";
17
+ } from "./chunk-UTOTOWPS.js";
18
18
  import {
19
19
  Pagination
20
- } from "./chunk-DPTTDHZ5.js";
20
+ } from "./chunk-FAGQGGT3.js";
21
21
  import {
22
22
  Checkbox
23
23
  } from "./chunk-DGXHR6FV.js";
@@ -29,13 +29,13 @@ import {
29
29
  } from "./chunk-3TUCQAYL.js";
30
30
  import {
31
31
  Dropdown
32
- } from "./chunk-3X6QVHTD.js";
32
+ } from "./chunk-OERK3T7E.js";
33
33
  import {
34
34
  Button
35
- } from "./chunk-JY77VJAZ.js";
35
+ } from "./chunk-GHUEVNNU.js";
36
36
  import {
37
37
  devWarn
38
- } from "./chunk-U34INRFO.js";
38
+ } from "./chunk-PP6HS4GR.js";
39
39
 
40
40
  // src/components/Table/Table.component.tsx
41
41
  import { useState, useMemo, useEffect, useLayoutEffect, useRef, useCallback } from "react";
@@ -918,4 +918,4 @@ var Table = ({
918
918
  export {
919
919
  Table
920
920
  };
921
- //# sourceMappingURL=chunk-3TF2GZSG.js.map
921
+ //# sourceMappingURL=chunk-SONL2RCW.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Chip
3
- } from "./chunk-2TIMJD4K.js";
3
+ } from "./chunk-IBT535UH.js";
4
4
 
5
5
  // src/components/SplitChip/SplitChip.utils.ts
6
6
  var hasVisibleBorder = (segment) => segment.variant === "outlined" || segment.disabled;
@@ -79,4 +79,4 @@ var SplitChip = ({
79
79
  export {
80
80
  SplitChip
81
81
  };
82
- //# sourceMappingURL=chunk-2IXCEKLI.js.map
82
+ //# sourceMappingURL=chunk-SOS4K7VC.js.map
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  Dropdown
3
- } from "./chunk-3X6QVHTD.js";
3
+ } from "./chunk-OERK3T7E.js";
4
4
  import {
5
5
  Kbd
6
6
  } from "./chunk-LYH3EKKQ.js";
7
7
  import {
8
8
  Tooltip
9
- } from "./chunk-MCPGI6EI.js";
9
+ } from "./chunk-BUSMGQJ4.js";
10
10
  import {
11
11
  renderIcon,
12
12
  useDialogFocus
13
- } from "./chunk-U34INRFO.js";
13
+ } from "./chunk-PP6HS4GR.js";
14
14
 
15
15
  // src/components/Menu/Menu.component.tsx
16
16
  import React, { useCallback, useMemo, useRef, useState } from "react";
@@ -222,4 +222,4 @@ export {
222
222
  MenuPanel,
223
223
  Menu
224
224
  };
225
- //# sourceMappingURL=chunk-WHQGJHMD.js.map
225
+ //# sourceMappingURL=chunk-TOLNPD7S.js.map