@zentauri-ui/zentauri-components 1.4.61 → 1.4.62

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 (260) hide show
  1. package/dist/{chunk-UXGHUBNJ.mjs → chunk-2PJF7DLJ.mjs} +3 -3
  2. package/dist/{chunk-UXGHUBNJ.mjs.map → chunk-2PJF7DLJ.mjs.map} +1 -1
  3. package/dist/{chunk-WDCIZHXY.mjs → chunk-45FCOQ63.mjs} +5 -3
  4. package/dist/chunk-45FCOQ63.mjs.map +1 -0
  5. package/dist/{chunk-RDSPHBHK.mjs → chunk-4ANBTJ5G.mjs} +49 -6
  6. package/dist/chunk-4ANBTJ5G.mjs.map +1 -0
  7. package/dist/chunk-4E66ICIR.mjs +158 -0
  8. package/dist/chunk-4E66ICIR.mjs.map +1 -0
  9. package/dist/{chunk-XLAFQ24R.js → chunk-4U6FOCFK.js} +22 -14
  10. package/dist/chunk-4U6FOCFK.js.map +1 -0
  11. package/dist/{chunk-XWM2S6VV.mjs → chunk-EQSSYK27.mjs} +12 -10
  12. package/dist/chunk-EQSSYK27.mjs.map +1 -0
  13. package/dist/{chunk-5QB2KNZQ.js → chunk-FGGYDAX3.js} +5 -3
  14. package/dist/chunk-FGGYDAX3.js.map +1 -0
  15. package/dist/{chunk-7HL3A4YF.mjs → chunk-IK75NHRX.mjs} +63 -14
  16. package/dist/chunk-IK75NHRX.mjs.map +1 -0
  17. package/dist/{chunk-BORK3BJO.mjs → chunk-J56L4ZQ3.mjs} +10 -10
  18. package/dist/{chunk-BORK3BJO.mjs.map → chunk-J56L4ZQ3.mjs.map} +1 -1
  19. package/dist/{chunk-PGH27VTL.mjs → chunk-JF3FKUUP.mjs} +21 -13
  20. package/dist/chunk-JF3FKUUP.mjs.map +1 -0
  21. package/dist/{chunk-WZKGRU3U.js → chunk-MQZB5EPD.js} +92 -27
  22. package/dist/chunk-MQZB5EPD.js.map +1 -0
  23. package/dist/{chunk-N4NO3SYL.js → chunk-NX3IHMT7.js} +22 -14
  24. package/dist/chunk-NX3IHMT7.js.map +1 -0
  25. package/dist/{chunk-BVXTOEBI.mjs → chunk-OG2WM5YK.mjs} +45 -17
  26. package/dist/chunk-OG2WM5YK.mjs.map +1 -0
  27. package/dist/{chunk-IXDJ3IPG.mjs → chunk-OXS6UJUG.mjs} +21 -13
  28. package/dist/chunk-OXS6UJUG.mjs.map +1 -0
  29. package/dist/{chunk-PCK6LX3K.js → chunk-PFOV3U7W.js} +3 -3
  30. package/dist/{chunk-PCK6LX3K.js.map → chunk-PFOV3U7W.js.map} +1 -1
  31. package/dist/{chunk-2PQEXQVR.js → chunk-THCNTPPL.js} +62 -13
  32. package/dist/chunk-THCNTPPL.js.map +1 -0
  33. package/dist/chunk-UP6S75V5.js +160 -0
  34. package/dist/chunk-UP6S75V5.js.map +1 -0
  35. package/dist/{chunk-P5HUBXUX.js → chunk-V2IWLR4O.js} +48 -5
  36. package/dist/chunk-V2IWLR4O.js.map +1 -0
  37. package/dist/{chunk-3OR47XMY.js → chunk-VSKL5LOB.js} +45 -17
  38. package/dist/chunk-VSKL5LOB.js.map +1 -0
  39. package/dist/{chunk-E3DZNJAD.js → chunk-Y4EDWZKH.js} +12 -10
  40. package/dist/chunk-Y4EDWZKH.js.map +1 -0
  41. package/dist/{chunk-YNCD6TKE.mjs → chunk-Y4IFVO46.mjs} +93 -28
  42. package/dist/chunk-Y4IFVO46.mjs.map +1 -0
  43. package/dist/{chunk-BITDSQMR.js → chunk-ZNDHS5OK.js} +10 -10
  44. package/dist/{chunk-BITDSQMR.js.map → chunk-ZNDHS5OK.js.map} +1 -1
  45. package/dist/hooks/useFocusManagement/useFocusManagement.d.ts +5 -14
  46. package/dist/hooks/useFocusManagement/useFocusManagement.d.ts.map +1 -1
  47. package/dist/hooks/useFocusManagement.js +2 -2
  48. package/dist/hooks/useFocusManagement.mjs +1 -1
  49. package/dist/ui/badge/animated.js +2 -2
  50. package/dist/ui/badge/animated.mjs +1 -1
  51. package/dist/ui/badge/badge-base.d.ts +1 -1
  52. package/dist/ui/badge/badge-base.d.ts.map +1 -1
  53. package/dist/ui/badge/types.d.ts +1 -0
  54. package/dist/ui/badge/types.d.ts.map +1 -1
  55. package/dist/ui/badge/variants.d.ts +7 -7
  56. package/dist/ui/badge.js +4 -4
  57. package/dist/ui/badge.mjs +2 -2
  58. package/dist/ui/buttons/animated.js +3 -3
  59. package/dist/ui/buttons/animated.mjs +1 -1
  60. package/dist/ui/buttons.js +4 -4
  61. package/dist/ui/buttons.mjs +2 -2
  62. package/dist/ui/drawer/animated/drawer-content-animated.d.ts.map +1 -1
  63. package/dist/ui/drawer/animated.js +17 -18
  64. package/dist/ui/drawer/animated.js.map +1 -1
  65. package/dist/ui/drawer/animated.mjs +8 -9
  66. package/dist/ui/drawer/animated.mjs.map +1 -1
  67. package/dist/ui/drawer/drawer-base.d.ts +1 -1
  68. package/dist/ui/drawer/drawer-base.d.ts.map +1 -1
  69. package/dist/ui/drawer/types.d.ts +1 -0
  70. package/dist/ui/drawer/types.d.ts.map +1 -1
  71. package/dist/ui/drawer.js +12 -12
  72. package/dist/ui/drawer.mjs +2 -2
  73. package/dist/ui/dropdown/dropdown.d.ts +1 -1
  74. package/dist/ui/dropdown/dropdown.d.ts.map +1 -1
  75. package/dist/ui/dropdown/types.d.ts +1 -0
  76. package/dist/ui/dropdown/types.d.ts.map +1 -1
  77. package/dist/ui/dropdown/variants.d.ts +1 -1
  78. package/dist/ui/dropdown.js +25 -7
  79. package/dist/ui/dropdown.js.map +1 -1
  80. package/dist/ui/dropdown.mjs +26 -8
  81. package/dist/ui/dropdown.mjs.map +1 -1
  82. package/dist/ui/empty-state/animated.js +2 -2
  83. package/dist/ui/empty-state/animated.mjs +1 -1
  84. package/dist/ui/empty-state/empty-state-base.d.ts.map +1 -1
  85. package/dist/ui/empty-state/types.d.ts +1 -0
  86. package/dist/ui/empty-state/types.d.ts.map +1 -1
  87. package/dist/ui/empty-state.js +10 -10
  88. package/dist/ui/empty-state.mjs +2 -2
  89. package/dist/ui/file-upload/file-upload.d.ts.map +1 -1
  90. package/dist/ui/file-upload.js +1 -3
  91. package/dist/ui/file-upload.js.map +1 -1
  92. package/dist/ui/file-upload.mjs +1 -3
  93. package/dist/ui/file-upload.mjs.map +1 -1
  94. package/dist/ui/inputs/input-base.d.ts.map +1 -1
  95. package/dist/ui/inputs/types.d.ts +3 -1
  96. package/dist/ui/inputs/types.d.ts.map +1 -1
  97. package/dist/ui/inputs.js +46 -2
  98. package/dist/ui/inputs.js.map +1 -1
  99. package/dist/ui/inputs.mjs +46 -2
  100. package/dist/ui/inputs.mjs.map +1 -1
  101. package/dist/ui/modal/animated/modal-content-animated.d.ts.map +1 -1
  102. package/dist/ui/modal/animated.js +10 -11
  103. package/dist/ui/modal/animated.js.map +1 -1
  104. package/dist/ui/modal/animated.mjs +7 -8
  105. package/dist/ui/modal/animated.mjs.map +1 -1
  106. package/dist/ui/modal/modal-base.d.ts +4 -2
  107. package/dist/ui/modal/modal-base.d.ts.map +1 -1
  108. package/dist/ui/modal.js +13 -13
  109. package/dist/ui/modal.mjs +3 -3
  110. package/dist/ui/pagination.js +6 -6
  111. package/dist/ui/pagination.js.map +1 -1
  112. package/dist/ui/pagination.mjs +3 -3
  113. package/dist/ui/pagination.mjs.map +1 -1
  114. package/dist/ui/progress/animated/progress-animated.d.ts.map +1 -1
  115. package/dist/ui/progress/animated.js +49 -11
  116. package/dist/ui/progress/animated.js.map +1 -1
  117. package/dist/ui/progress/animated.mjs +44 -6
  118. package/dist/ui/progress/animated.mjs.map +1 -1
  119. package/dist/ui/progress/progress-base.d.ts.map +1 -1
  120. package/dist/ui/progress/types.d.ts +3 -0
  121. package/dist/ui/progress/types.d.ts.map +1 -1
  122. package/dist/ui/progress.js +9 -9
  123. package/dist/ui/progress.mjs +2 -2
  124. package/dist/ui/search/search-bar.d.ts +1 -1
  125. package/dist/ui/search/search-bar.d.ts.map +1 -1
  126. package/dist/ui/search.js +2 -0
  127. package/dist/ui/search.js.map +1 -1
  128. package/dist/ui/search.mjs +2 -0
  129. package/dist/ui/search.mjs.map +1 -1
  130. package/dist/ui/select/select.d.ts +1 -1
  131. package/dist/ui/select/select.d.ts.map +1 -1
  132. package/dist/ui/select/types.d.ts +1 -0
  133. package/dist/ui/select/types.d.ts.map +1 -1
  134. package/dist/ui/select/variants.d.ts +1 -1
  135. package/dist/ui/select/variants.d.ts.map +1 -1
  136. package/dist/ui/select.js +121 -39
  137. package/dist/ui/select.js.map +1 -1
  138. package/dist/ui/select.mjs +122 -40
  139. package/dist/ui/select.mjs.map +1 -1
  140. package/dist/ui/skeleton/variants.d.ts +1 -1
  141. package/dist/ui/slider/slider.d.ts.map +1 -1
  142. package/dist/ui/slider/types.d.ts +8 -2
  143. package/dist/ui/slider/types.d.ts.map +1 -1
  144. package/dist/ui/slider.js +43 -7
  145. package/dist/ui/slider.js.map +1 -1
  146. package/dist/ui/slider.mjs +43 -7
  147. package/dist/ui/slider.mjs.map +1 -1
  148. package/dist/ui/spinner/animated/spinner.d.ts.map +1 -1
  149. package/dist/ui/spinner/animated.js +62 -50
  150. package/dist/ui/spinner/animated.js.map +1 -1
  151. package/dist/ui/spinner/animated.mjs +63 -51
  152. package/dist/ui/spinner/animated.mjs.map +1 -1
  153. package/dist/ui/stepper/stepper.d.ts +2 -7
  154. package/dist/ui/stepper/stepper.d.ts.map +1 -1
  155. package/dist/ui/stepper/types.d.ts +3 -3
  156. package/dist/ui/stepper/types.d.ts.map +1 -1
  157. package/dist/ui/stepper/variants.d.ts +1 -1
  158. package/dist/ui/stepper.js +7 -5
  159. package/dist/ui/stepper.js.map +1 -1
  160. package/dist/ui/stepper.mjs +7 -5
  161. package/dist/ui/stepper.mjs.map +1 -1
  162. package/dist/ui/table/animated.js +8 -8
  163. package/dist/ui/table/animated.mjs +2 -2
  164. package/dist/ui/table/table-base.d.ts +1 -1
  165. package/dist/ui/table/table-base.d.ts.map +1 -1
  166. package/dist/ui/table/types.d.ts +5 -1
  167. package/dist/ui/table/types.d.ts.map +1 -1
  168. package/dist/ui/table.js +14 -14
  169. package/dist/ui/table.mjs +1 -1
  170. package/dist/ui/tabs/animated.js +2 -2
  171. package/dist/ui/tabs/animated.mjs +1 -1
  172. package/dist/ui/tabs/tabs-base.d.ts.map +1 -1
  173. package/dist/ui/tabs/types.d.ts +2 -1
  174. package/dist/ui/tabs/types.d.ts.map +1 -1
  175. package/dist/ui/tabs.js +9 -9
  176. package/dist/ui/tabs.mjs +1 -1
  177. package/dist/ui/toast/animated.js +7 -7
  178. package/dist/ui/toast/animated.mjs +1 -1
  179. package/dist/ui/toast.js +12 -12
  180. package/dist/ui/toast.mjs +1 -1
  181. package/dist/ui/toggle/toggle-base.d.ts.map +1 -1
  182. package/dist/ui/toggle.js +28 -3
  183. package/dist/ui/toggle.js.map +1 -1
  184. package/dist/ui/toggle.mjs +29 -4
  185. package/dist/ui/toggle.mjs.map +1 -1
  186. package/dist/ui/tooltip/animated.js +3 -3
  187. package/dist/ui/tooltip/animated.mjs +1 -1
  188. package/dist/ui/tooltip/tooltip-base.d.ts.map +1 -1
  189. package/dist/ui/tooltip/types.d.ts +1 -0
  190. package/dist/ui/tooltip/types.d.ts.map +1 -1
  191. package/dist/ui/tooltip.js +7 -7
  192. package/dist/ui/tooltip.mjs +1 -1
  193. package/package.json +1 -1
  194. package/src/hooks/useFocusManagement/useFocusManagement.test.tsx +8 -0
  195. package/src/hooks/useFocusManagement/useFocusManagement.ts +162 -33
  196. package/src/ui/badge/badge-base.tsx +4 -1
  197. package/src/ui/badge/types.ts +1 -0
  198. package/src/ui/badge/variants.ts +7 -7
  199. package/src/ui/buttons/button.test.tsx +1 -1
  200. package/src/ui/buttons/variants.ts +8 -8
  201. package/src/ui/drawer/animated/drawer-content-animated.tsx +4 -5
  202. package/src/ui/drawer/drawer-base.tsx +16 -8
  203. package/src/ui/drawer/types.ts +1 -0
  204. package/src/ui/dropdown/dropdown.test.tsx +1 -3
  205. package/src/ui/dropdown/dropdown.tsx +23 -5
  206. package/src/ui/dropdown/types.ts +1 -0
  207. package/src/ui/dropdown/variants.ts +2 -2
  208. package/src/ui/empty-state/empty-state-base.tsx +9 -1
  209. package/src/ui/empty-state/types.ts +1 -0
  210. package/src/ui/file-upload/file-upload.tsx +0 -2
  211. package/src/ui/inputs/input-base.tsx +60 -6
  212. package/src/ui/inputs/types.ts +3 -1
  213. package/src/ui/modal/animated/modal-content-animated.tsx +4 -5
  214. package/src/ui/modal/modal-base.tsx +19 -9
  215. package/src/ui/modal/modal.test.tsx +38 -0
  216. package/src/ui/pagination/pagination.tsx +2 -2
  217. package/src/ui/progress/animated/progress-animated.tsx +42 -3
  218. package/src/ui/progress/progress-base.tsx +59 -3
  219. package/src/ui/progress/types.ts +3 -0
  220. package/src/ui/search/search-bar.tsx +5 -0
  221. package/src/ui/select/select.tsx +97 -6
  222. package/src/ui/select/types.ts +1 -0
  223. package/src/ui/select/variants.ts +5 -3
  224. package/src/ui/slider/slider.test.tsx +25 -1
  225. package/src/ui/slider/slider.tsx +45 -4
  226. package/src/ui/slider/types.ts +8 -2
  227. package/src/ui/spinner/animated/spinner.tsx +4 -0
  228. package/src/ui/stepper/stepper.test.tsx +6 -7
  229. package/src/ui/stepper/stepper.tsx +11 -10
  230. package/src/ui/stepper/types.ts +7 -3
  231. package/src/ui/table/table-base.tsx +32 -6
  232. package/src/ui/table/types.ts +8 -1
  233. package/src/ui/tabs/tabs-base.tsx +71 -10
  234. package/src/ui/tabs/types.ts +2 -1
  235. package/src/ui/tabs/variants.ts +1 -1
  236. package/src/ui/toast/toast-base.tsx +1 -1
  237. package/src/ui/toggle/toggle-base.tsx +37 -4
  238. package/src/ui/tooltip/tooltip-base.tsx +119 -22
  239. package/src/ui/tooltip/types.ts +1 -0
  240. package/src/ui/tooltip/variants.ts +2 -2
  241. package/dist/chunk-2PQEXQVR.js.map +0 -1
  242. package/dist/chunk-3OR47XMY.js.map +0 -1
  243. package/dist/chunk-5QB2KNZQ.js.map +0 -1
  244. package/dist/chunk-7HL3A4YF.mjs.map +0 -1
  245. package/dist/chunk-BVXTOEBI.mjs.map +0 -1
  246. package/dist/chunk-E3DZNJAD.js.map +0 -1
  247. package/dist/chunk-IXDJ3IPG.mjs.map +0 -1
  248. package/dist/chunk-N4NO3SYL.js.map +0 -1
  249. package/dist/chunk-P5HUBXUX.js.map +0 -1
  250. package/dist/chunk-PGH27VTL.mjs.map +0 -1
  251. package/dist/chunk-RDSPHBHK.mjs.map +0 -1
  252. package/dist/chunk-WDCIZHXY.mjs.map +0 -1
  253. package/dist/chunk-WL5I7RVS.mjs +0 -54
  254. package/dist/chunk-WL5I7RVS.mjs.map +0 -1
  255. package/dist/chunk-WZKGRU3U.js.map +0 -1
  256. package/dist/chunk-XLAFQ24R.js.map +0 -1
  257. package/dist/chunk-XWM2S6VV.mjs.map +0 -1
  258. package/dist/chunk-YNCD6TKE.mjs.map +0 -1
  259. package/dist/chunk-YPLVTUYL.js +0 -56
  260. package/dist/chunk-YPLVTUYL.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/toggle/toggle-base.tsx","../../src/ui/toggle/toggle.tsx"],"names":["useState","useCallback","jsxs","cn","toggleTrackVariants","jsx","toggleThumbVariants"],"mappings":";;;;;;;AASO,SAAS,WAAW,KAAA,EAAoB;AAC7C,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,IAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA,GAAiB,KAAA;AAAA,IACjB,eAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAA;AAAA,IACA,cAAc,SAAA,GAAY,QAAA;AAAA,IAC1B,QAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AACJ,EAAA,MAAM,eAAe,OAAA,KAAY,MAAA;AACjC,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAIA,eAAS,cAAc,CAAA;AAC/D,EAAA,MAAM,QAAA,GAAW,YAAA,GAAe,OAAA,CAAQ,OAAO,CAAA,GAAI,YAAA;AAEnD,EAAA,MAAM,UAAA,GAAaC,iBAAA;AAAA,IACjB,CAAC,IAAA,KAAkB;AACjB,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,MACtB;AACA,MAAA,eAAA,GAAkB,IAAI,CAAA;AAAA,IACxB,CAAA;AAAA,IACA,CAAC,cAAc,eAAe;AAAA,GAChC;AAEA,EAAA,MAAM,eAAe,IAAA,KAAS,IAAA,GAAO,EAAA,GAAK,IAAA,KAAS,OAAO,EAAA,GAAK,EAAA;AAE/D,EAAA,uBACEC,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA,EAAK,QAAA;AAAA,MACL,IAAA,EAAK,QAAA;AAAA,MACL,WAAA,EAAU,QAAA;AAAA,MACV,cAAA,EAAc,QAAA;AAAA,MACd,YAAA,EAAY,SAAA;AAAA,MACZ,YAAA,EAAY,WAAW,SAAA,GAAY,WAAA;AAAA,MACnC,QAAA;AAAA,MACA,SAAA,EAAWC,oBAAGC,oCAAA,CAAoB,EAAE,MAAM,UAAA,EAAY,GAAG,SAAS,CAAA;AAAA,MAClE,SAAS,MAAM;AACb,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,UAAA,CAAW,CAAC,QAAQ,CAAA;AAAA,QACtB;AAAA,MACF,CAAA;AAAA,MACC,GAAG,IAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAAC,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,QAAA,EAAS,CAAA;AAAA,wBACpCA,cAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAWF,mBAAA;AAAA,cACTG,oCAAA,CAAoB,EAAE,IAAA,EAAM,CAAA;AAAA,cAC5B;AAAA,aACF;AAAA,YACA,OAAO,EAAE,SAAA,EAAW,cAAc,QAAA,GAAW,YAAA,GAAe,CAAC,CAAA,GAAA,CAAA;AAAM;AAAA;AACrE;AAAA;AAAA,GACF;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,QAAA;ACjElB,SAAS,OAAO,KAAA,EAAoB;AACzC,EAAA,uBAAOD,cAAAA,CAAC,UAAA,EAAA,EAAY,GAAG,KAAA,EAAO,CAAA;AAChC;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"toggle.js","sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ToggleProps } from \"./types\";\nimport { toggleThumbVariants, toggleTrackVariants } from \"./variants\";\n\nexport function ToggleBase(props: ToggleProps) {\n const {\n className,\n size,\n appearance,\n checked,\n defaultChecked = false,\n onCheckedChange,\n disabled,\n ref,\n \"aria-label\": ariaLabel = \"Toggle\",\n children,\n ...rest\n } = props;\n const isControlled = checked !== undefined;\n const [uncontrolled, setUncontrolled] = useState(defaultChecked);\n const resolved = isControlled ? Boolean(checked) : uncontrolled;\n\n const setChecked = useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setUncontrolled(next);\n }\n onCheckedChange?.(next);\n },\n [isControlled, onCheckedChange],\n );\n\n const thumbShiftPx = size === \"sm\" ? 14 : size === \"lg\" ? 26 : 20;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"switch\"\n data-slot=\"toggle\"\n aria-checked={resolved}\n aria-label={ariaLabel}\n data-state={resolved ? \"checked\" : \"unchecked\"}\n disabled={disabled}\n className={cn(toggleTrackVariants({ size, appearance }), className)}\n onClick={() => {\n if (!disabled) {\n setChecked(!resolved);\n }\n }}\n {...rest}\n >\n <span className=\"sr-only\">{children}</span>\n <span\n className={cn(\n toggleThumbVariants({ size }),\n \"absolute left-1 top-1/2 -translate-y-1/2 transition-[transform] duration-200 ease-out\",\n )}\n style={{ transform: `translateX(${resolved ? thumbShiftPx : 0}px)` }}\n />\n </button>\n );\n}\n\nToggleBase.displayName = \"Toggle\";\n","// toggle.tsx — default static entry (no framer-motion)\nimport { ToggleBase } from \"./toggle-base\";\nimport type { ToggleProps } from \"./types\";\n\nexport function Toggle(props: ToggleProps) {\n return <ToggleBase {...props} />;\n}\n\nToggle.displayName = \"Toggle\";\n"]}
1
+ {"version":3,"sources":["../../src/ui/toggle/toggle-base.tsx","../../src/ui/toggle/toggle.tsx"],"names":["useId","useState","useCallback","jsxs","cn","toggleTrackVariants","jsx","toggleThumbVariants"],"mappings":"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","file":"toggle.js","sourcesContent":["\"use client\";\n\nimport { useCallback, useId, useState, type ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ToggleProps } from \"./types\";\nimport { toggleThumbVariants, toggleTrackVariants } from \"./variants\";\n\nfunction hasToggleLabelChildren(node: ReactNode): boolean {\n if (node === undefined || node === null) {\n return false;\n }\n if (typeof node === \"boolean\") {\n return false;\n }\n if (typeof node === \"string\") {\n return node.trim().length > 0;\n }\n if (typeof node === \"number\") {\n return true;\n }\n if (Array.isArray(node)) {\n return node.some(hasToggleLabelChildren);\n }\n return true;\n}\n\nexport function ToggleBase(props: ToggleProps) {\n const {\n className,\n size,\n appearance,\n checked,\n defaultChecked = false,\n onCheckedChange,\n disabled,\n ref,\n \"aria-label\": ariaLabelProp,\n children,\n ...rest\n } = props;\n const toggleLabelId = useId();\n const isControlled = checked !== undefined;\n const [uncontrolled, setUncontrolled] = useState(defaultChecked);\n const resolved = isControlled ? Boolean(checked) : uncontrolled;\n\n const setChecked = useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setUncontrolled(next);\n }\n onCheckedChange?.(next);\n },\n [isControlled, onCheckedChange],\n );\n\n const thumbShiftPx = size === \"sm\" ? 14 : size === \"lg\" ? 26 : 20;\n const labeledByChildren = hasToggleLabelChildren(children);\n const labeling =\n labeledByChildren ?\n {\n \"aria-labelledby\": toggleLabelId,\n }\n : {\n \"aria-label\": ariaLabelProp ?? \"Toggle\",\n };\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"switch\"\n data-slot=\"toggle\"\n aria-checked={resolved}\n data-state={resolved ? \"checked\" : \"unchecked\"}\n disabled={disabled}\n className={cn(toggleTrackVariants({ size, appearance }), className)}\n {...labeling}\n onClick={() => {\n if (!disabled) {\n setChecked(!resolved);\n }\n }}\n {...rest}\n >\n {labeledByChildren ?\n <span id={toggleLabelId} className=\"sr-only\">\n {children}\n </span>\n : null}\n <span\n className={cn(\n toggleThumbVariants({ size }),\n \"absolute left-1 top-1/2 -translate-y-1/2 transition-[transform] duration-200 ease-out\",\n )}\n style={{ transform: `translateX(${resolved ? thumbShiftPx : 0}px)` }}\n />\n </button>\n );\n}\n\nToggleBase.displayName = \"Toggle\";\n","// toggle.tsx — default static entry (no framer-motion)\nimport { ToggleBase } from \"./toggle-base\";\nimport type { ToggleProps } from \"./types\";\n\nexport function Toggle(props: ToggleProps) {\n return <ToggleBase {...props} />;\n}\n\nToggle.displayName = \"Toggle\";\n"]}
@@ -2,9 +2,27 @@
2
2
  import { toggleThumbVariants, toggleTrackVariants } from '../chunk-JQ5TIJ4F.mjs';
3
3
  export { toggleThumbVariants, toggleTrackVariants } from '../chunk-JQ5TIJ4F.mjs';
4
4
  import { cn } from '../chunk-DFEZH7TC.mjs';
5
- import { useState, useCallback } from 'react';
5
+ import { useId, useState, useCallback } from 'react';
6
6
  import { jsx, jsxs } from 'react/jsx-runtime';
7
7
 
8
+ function hasToggleLabelChildren(node) {
9
+ if (node === void 0 || node === null) {
10
+ return false;
11
+ }
12
+ if (typeof node === "boolean") {
13
+ return false;
14
+ }
15
+ if (typeof node === "string") {
16
+ return node.trim().length > 0;
17
+ }
18
+ if (typeof node === "number") {
19
+ return true;
20
+ }
21
+ if (Array.isArray(node)) {
22
+ return node.some(hasToggleLabelChildren);
23
+ }
24
+ return true;
25
+ }
8
26
  function ToggleBase(props) {
9
27
  const {
10
28
  className,
@@ -15,10 +33,11 @@ function ToggleBase(props) {
15
33
  onCheckedChange,
16
34
  disabled,
17
35
  ref,
18
- "aria-label": ariaLabel = "Toggle",
36
+ "aria-label": ariaLabelProp,
19
37
  children,
20
38
  ...rest
21
39
  } = props;
40
+ const toggleLabelId = useId();
22
41
  const isControlled = checked !== void 0;
23
42
  const [uncontrolled, setUncontrolled] = useState(defaultChecked);
24
43
  const resolved = isControlled ? Boolean(checked) : uncontrolled;
@@ -32,6 +51,12 @@ function ToggleBase(props) {
32
51
  [isControlled, onCheckedChange]
33
52
  );
34
53
  const thumbShiftPx = size === "sm" ? 14 : size === "lg" ? 26 : 20;
54
+ const labeledByChildren = hasToggleLabelChildren(children);
55
+ const labeling = labeledByChildren ? {
56
+ "aria-labelledby": toggleLabelId
57
+ } : {
58
+ "aria-label": ariaLabelProp ?? "Toggle"
59
+ };
35
60
  return /* @__PURE__ */ jsxs(
36
61
  "button",
37
62
  {
@@ -40,10 +65,10 @@ function ToggleBase(props) {
40
65
  role: "switch",
41
66
  "data-slot": "toggle",
42
67
  "aria-checked": resolved,
43
- "aria-label": ariaLabel,
44
68
  "data-state": resolved ? "checked" : "unchecked",
45
69
  disabled,
46
70
  className: cn(toggleTrackVariants({ size, appearance }), className),
71
+ ...labeling,
47
72
  onClick: () => {
48
73
  if (!disabled) {
49
74
  setChecked(!resolved);
@@ -51,7 +76,7 @@ function ToggleBase(props) {
51
76
  },
52
77
  ...rest,
53
78
  children: [
54
- /* @__PURE__ */ jsx("span", { className: "sr-only", children }),
79
+ labeledByChildren ? /* @__PURE__ */ jsx("span", { id: toggleLabelId, className: "sr-only", children }) : null,
55
80
  /* @__PURE__ */ jsx(
56
81
  "span",
57
82
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/ui/toggle/toggle-base.tsx","../../src/ui/toggle/toggle.tsx"],"names":["jsx"],"mappings":";;;;;;AASO,SAAS,WAAW,KAAA,EAAoB;AAC7C,EAAA,MAAM;AAAA,IACJ,SAAA;AAAA,IACA,IAAA;AAAA,IACA,UAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA,GAAiB,KAAA;AAAA,IACjB,eAAA;AAAA,IACA,QAAA;AAAA,IACA,GAAA;AAAA,IACA,cAAc,SAAA,GAAY,QAAA;AAAA,IAC1B,QAAA;AAAA,IACA,GAAG;AAAA,GACL,GAAI,KAAA;AACJ,EAAA,MAAM,eAAe,OAAA,KAAY,MAAA;AACjC,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,SAAS,cAAc,CAAA;AAC/D,EAAA,MAAM,QAAA,GAAW,YAAA,GAAe,OAAA,CAAQ,OAAO,CAAA,GAAI,YAAA;AAEnD,EAAA,MAAM,UAAA,GAAa,WAAA;AAAA,IACjB,CAAC,IAAA,KAAkB;AACjB,MAAA,IAAI,CAAC,YAAA,EAAc;AACjB,QAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,MACtB;AACA,MAAA,eAAA,GAAkB,IAAI,CAAA;AAAA,IACxB,CAAA;AAAA,IACA,CAAC,cAAc,eAAe;AAAA,GAChC;AAEA,EAAA,MAAM,eAAe,IAAA,KAAS,IAAA,GAAO,EAAA,GAAK,IAAA,KAAS,OAAO,EAAA,GAAK,EAAA;AAE/D,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,IAAA,EAAK,QAAA;AAAA,MACL,IAAA,EAAK,QAAA;AAAA,MACL,WAAA,EAAU,QAAA;AAAA,MACV,cAAA,EAAc,QAAA;AAAA,MACd,YAAA,EAAY,SAAA;AAAA,MACZ,YAAA,EAAY,WAAW,SAAA,GAAY,WAAA;AAAA,MACnC,QAAA;AAAA,MACA,SAAA,EAAW,GAAG,mBAAA,CAAoB,EAAE,MAAM,UAAA,EAAY,GAAG,SAAS,CAAA;AAAA,MAClE,SAAS,MAAM;AACb,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA,UAAA,CAAW,CAAC,QAAQ,CAAA;AAAA,QACtB;AAAA,MACF,CAAA;AAAA,MACC,GAAG,IAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,SAAA,EAAW,QAAA,EAAS,CAAA;AAAA,wBACpC,GAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,SAAA,EAAW,EAAA;AAAA,cACT,mBAAA,CAAoB,EAAE,IAAA,EAAM,CAAA;AAAA,cAC5B;AAAA,aACF;AAAA,YACA,OAAO,EAAE,SAAA,EAAW,cAAc,QAAA,GAAW,YAAA,GAAe,CAAC,CAAA,GAAA,CAAA;AAAM;AAAA;AACrE;AAAA;AAAA,GACF;AAEJ;AAEA,UAAA,CAAW,WAAA,GAAc,QAAA;ACjElB,SAAS,OAAO,KAAA,EAAoB;AACzC,EAAA,uBAAOA,GAAAA,CAAC,UAAA,EAAA,EAAY,GAAG,KAAA,EAAO,CAAA;AAChC;AAEA,MAAA,CAAO,WAAA,GAAc,QAAA","file":"toggle.mjs","sourcesContent":["\"use client\";\n\nimport { useCallback, useState } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ToggleProps } from \"./types\";\nimport { toggleThumbVariants, toggleTrackVariants } from \"./variants\";\n\nexport function ToggleBase(props: ToggleProps) {\n const {\n className,\n size,\n appearance,\n checked,\n defaultChecked = false,\n onCheckedChange,\n disabled,\n ref,\n \"aria-label\": ariaLabel = \"Toggle\",\n children,\n ...rest\n } = props;\n const isControlled = checked !== undefined;\n const [uncontrolled, setUncontrolled] = useState(defaultChecked);\n const resolved = isControlled ? Boolean(checked) : uncontrolled;\n\n const setChecked = useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setUncontrolled(next);\n }\n onCheckedChange?.(next);\n },\n [isControlled, onCheckedChange],\n );\n\n const thumbShiftPx = size === \"sm\" ? 14 : size === \"lg\" ? 26 : 20;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"switch\"\n data-slot=\"toggle\"\n aria-checked={resolved}\n aria-label={ariaLabel}\n data-state={resolved ? \"checked\" : \"unchecked\"}\n disabled={disabled}\n className={cn(toggleTrackVariants({ size, appearance }), className)}\n onClick={() => {\n if (!disabled) {\n setChecked(!resolved);\n }\n }}\n {...rest}\n >\n <span className=\"sr-only\">{children}</span>\n <span\n className={cn(\n toggleThumbVariants({ size }),\n \"absolute left-1 top-1/2 -translate-y-1/2 transition-[transform] duration-200 ease-out\",\n )}\n style={{ transform: `translateX(${resolved ? thumbShiftPx : 0}px)` }}\n />\n </button>\n );\n}\n\nToggleBase.displayName = \"Toggle\";\n","// toggle.tsx — default static entry (no framer-motion)\nimport { ToggleBase } from \"./toggle-base\";\nimport type { ToggleProps } from \"./types\";\n\nexport function Toggle(props: ToggleProps) {\n return <ToggleBase {...props} />;\n}\n\nToggle.displayName = \"Toggle\";\n"]}
1
+ {"version":3,"sources":["../../src/ui/toggle/toggle-base.tsx","../../src/ui/toggle/toggle.tsx"],"names":["jsx"],"mappings":"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","file":"toggle.mjs","sourcesContent":["\"use client\";\n\nimport { useCallback, useId, useState, type ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\nimport type { ToggleProps } from \"./types\";\nimport { toggleThumbVariants, toggleTrackVariants } from \"./variants\";\n\nfunction hasToggleLabelChildren(node: ReactNode): boolean {\n if (node === undefined || node === null) {\n return false;\n }\n if (typeof node === \"boolean\") {\n return false;\n }\n if (typeof node === \"string\") {\n return node.trim().length > 0;\n }\n if (typeof node === \"number\") {\n return true;\n }\n if (Array.isArray(node)) {\n return node.some(hasToggleLabelChildren);\n }\n return true;\n}\n\nexport function ToggleBase(props: ToggleProps) {\n const {\n className,\n size,\n appearance,\n checked,\n defaultChecked = false,\n onCheckedChange,\n disabled,\n ref,\n \"aria-label\": ariaLabelProp,\n children,\n ...rest\n } = props;\n const toggleLabelId = useId();\n const isControlled = checked !== undefined;\n const [uncontrolled, setUncontrolled] = useState(defaultChecked);\n const resolved = isControlled ? Boolean(checked) : uncontrolled;\n\n const setChecked = useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setUncontrolled(next);\n }\n onCheckedChange?.(next);\n },\n [isControlled, onCheckedChange],\n );\n\n const thumbShiftPx = size === \"sm\" ? 14 : size === \"lg\" ? 26 : 20;\n const labeledByChildren = hasToggleLabelChildren(children);\n const labeling =\n labeledByChildren ?\n {\n \"aria-labelledby\": toggleLabelId,\n }\n : {\n \"aria-label\": ariaLabelProp ?? \"Toggle\",\n };\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"switch\"\n data-slot=\"toggle\"\n aria-checked={resolved}\n data-state={resolved ? \"checked\" : \"unchecked\"}\n disabled={disabled}\n className={cn(toggleTrackVariants({ size, appearance }), className)}\n {...labeling}\n onClick={() => {\n if (!disabled) {\n setChecked(!resolved);\n }\n }}\n {...rest}\n >\n {labeledByChildren ?\n <span id={toggleLabelId} className=\"sr-only\">\n {children}\n </span>\n : null}\n <span\n className={cn(\n toggleThumbVariants({ size }),\n \"absolute left-1 top-1/2 -translate-y-1/2 transition-[transform] duration-200 ease-out\",\n )}\n style={{ transform: `translateX(${resolved ? thumbShiftPx : 0}px)` }}\n />\n </button>\n );\n}\n\nToggleBase.displayName = \"Toggle\";\n","// toggle.tsx — default static entry (no framer-motion)\nimport { ToggleBase } from \"./toggle-base\";\nimport type { ToggleProps } from \"./types\";\n\nexport function Toggle(props: ToggleProps) {\n return <ToggleBase {...props} />;\n}\n\nToggle.displayName = \"Toggle\";\n"]}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkWZKGRU3U_js = require('../../chunk-WZKGRU3U.js');
4
+ var chunkMQZB5EPD_js = require('../../chunk-MQZB5EPD.js');
5
5
  var chunkUOZYPWDZ_js = require('../../chunk-UOZYPWDZ.js');
6
6
  var framerMotion = require('framer-motion');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -28,7 +28,7 @@ var TooltipContentAnimated = ({
28
28
  width,
29
29
  animation = "none"
30
30
  }) => {
31
- const { open, position } = chunkWZKGRU3U_js.useTooltip();
31
+ const { open, position } = chunkMQZB5EPD_js.useTooltip();
32
32
  if (!open) return null;
33
33
  const positionStyles = {
34
34
  top: "bottom-full mb-2",
@@ -44,7 +44,7 @@ var TooltipContentAnimated = ({
44
44
  role: "tooltip",
45
45
  ...motionProps,
46
46
  className: chunkUOZYPWDZ_js.cn(
47
- chunkWZKGRU3U_js.tooltipVariants({ variant, size, width }),
47
+ chunkMQZB5EPD_js.tooltipVariants({ variant, size, width }),
48
48
  positionStyles[position],
49
49
  className
50
50
  ),
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { useTooltip, tooltipVariants } from '../../chunk-YNCD6TKE.mjs';
2
+ import { useTooltip, tooltipVariants } from '../../chunk-Y4IFVO46.mjs';
3
3
  import { cn } from '../../chunk-DFEZH7TC.mjs';
4
4
  import { motion } from 'framer-motion';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip-base.d.ts","sourceRoot":"","sources":["../../../src/ui/tooltip/tooltip-base.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAGjB,eAAO,MAAM,cAAc,oDAAiD,CAAC;AAE7E,eAAO,MAAM,UAAU,0BAMtB,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,iFAOrB,YAAY,4CA+Cd,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,0BAG5B,mBAAmB,4CA4BrB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,gDAM5B,mBAAmB,mDAyBrB,CAAC"}
1
+ {"version":3,"file":"tooltip-base.d.ts","sourceRoot":"","sources":["../../../src/ui/tooltip/tooltip-base.tsx"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,EACpB,MAAM,SAAS,CAAC;AAGjB,eAAO,MAAM,cAAc,oDAAiD,CAAC;AAE7E,eAAO,MAAM,UAAU,0BAMtB,CAAC;AAkBF,eAAO,MAAM,OAAO,GAAI,iFAOrB,YAAY,4CAiDd,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,0BAG5B,mBAAmB,4CAkGrB,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,gDAM5B,mBAAmB,mDA0BrB,CAAC"}
@@ -7,6 +7,7 @@ export type TooltipContextType = {
7
7
  delay: number;
8
8
  scheduleDelayedOpen: () => void;
9
9
  cancelDelayedOpen: () => void;
10
+ tooltipId: string;
10
11
  };
11
12
  export type TooltipProps = {
12
13
  children: ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ui/tooltip/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EACJ,SAAS,GACT,SAAS,GACT,OAAO,GACP,OAAO,GACP,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,KAAK,GACL,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,iBAAiB,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;CAC1D,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/ui/tooltip/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClC,QAAQ,EAAE,eAAe,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,SAAS,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,SAAS,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EACJ,SAAS,GACT,SAAS,GACT,OAAO,GACP,OAAO,GACP,SAAS,GACT,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,KAAK,GACL,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,eAAe,GACf,gBAAgB,GAChB,cAAc,GACd,iBAAiB,GACjB,iBAAiB,GACjB,eAAe,GACf,iBAAiB,GACjB,eAAe,GACf,iBAAiB,CAAC;IACtB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;CAC1D,CAAC"}
@@ -1,34 +1,34 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var chunkWZKGRU3U_js = require('../chunk-WZKGRU3U.js');
4
+ var chunkMQZB5EPD_js = require('../chunk-MQZB5EPD.js');
5
5
  require('../chunk-UOZYPWDZ.js');
6
6
 
7
7
 
8
8
 
9
9
  Object.defineProperty(exports, "Tooltip", {
10
10
  enumerable: true,
11
- get: function () { return chunkWZKGRU3U_js.Tooltip; }
11
+ get: function () { return chunkMQZB5EPD_js.Tooltip; }
12
12
  });
13
13
  Object.defineProperty(exports, "TooltipContent", {
14
14
  enumerable: true,
15
- get: function () { return chunkWZKGRU3U_js.TooltipContent; }
15
+ get: function () { return chunkMQZB5EPD_js.TooltipContent; }
16
16
  });
17
17
  Object.defineProperty(exports, "TooltipContext", {
18
18
  enumerable: true,
19
- get: function () { return chunkWZKGRU3U_js.TooltipContext; }
19
+ get: function () { return chunkMQZB5EPD_js.TooltipContext; }
20
20
  });
21
21
  Object.defineProperty(exports, "TooltipTrigger", {
22
22
  enumerable: true,
23
- get: function () { return chunkWZKGRU3U_js.TooltipTrigger; }
23
+ get: function () { return chunkMQZB5EPD_js.TooltipTrigger; }
24
24
  });
25
25
  Object.defineProperty(exports, "tooltipVariants", {
26
26
  enumerable: true,
27
- get: function () { return chunkWZKGRU3U_js.tooltipVariants; }
27
+ get: function () { return chunkMQZB5EPD_js.tooltipVariants; }
28
28
  });
29
29
  Object.defineProperty(exports, "useTooltip", {
30
30
  enumerable: true,
31
- get: function () { return chunkWZKGRU3U_js.useTooltip; }
31
+ get: function () { return chunkMQZB5EPD_js.useTooltip; }
32
32
  });
33
33
  //# sourceMappingURL=tooltip.js.map
34
34
  //# sourceMappingURL=tooltip.js.map
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- export { Tooltip, TooltipContent, TooltipContext, TooltipTrigger, tooltipVariants, useTooltip } from '../chunk-YNCD6TKE.mjs';
2
+ export { Tooltip, TooltipContent, TooltipContext, TooltipTrigger, tooltipVariants, useTooltip } from '../chunk-Y4IFVO46.mjs';
3
3
  import '../chunk-DFEZH7TC.mjs';
4
4
  //# sourceMappingURL=tooltip.mjs.map
5
5
  //# sourceMappingURL=tooltip.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zentauri-ui/zentauri-components",
3
- "version": "1.4.61",
3
+ "version": "1.4.62",
4
4
  "description": "React + Tailwind UI kit with ESM/CJS builds, per-entry exports, and a zentauri-components / zentauri-ui CLI to vendor UI or hook source into your app",
5
5
  "license": "MIT",
6
6
  "files": ["dist", "src/ui", "src/lib", "src/hooks", "cli"],
@@ -42,4 +42,12 @@ describe("useFocusManagement", () => {
42
42
  fireEvent.keyDown(window, { key: "Escape" });
43
43
  expect(screen.queryByTestId("dialog")).not.toBeInTheDocument();
44
44
  });
45
+
46
+ it("should return focus inside the overlay when focus moves outside without Tab", () => {
47
+ render(<Modal initialOpen />);
48
+ const outsideButton = screen.getByTestId("after");
49
+ outsideButton.focus();
50
+ expect(outsideButton).not.toHaveFocus();
51
+ expect(screen.getByRole("button", { name: "first" })).toHaveFocus();
52
+ });
45
53
  });
@@ -1,39 +1,61 @@
1
1
  "use client";
2
2
 
3
3
  import type { RefObject } from "react";
4
- import { useEffect } from "react";
4
+ import { useEffect, useLayoutEffect, useRef } from "react";
5
5
  import { useBodyScrollLock } from "../useBodyScrollLock";
6
6
 
7
7
  const FOCUSABLE_SELECTOR =
8
- 'a[href], button:not([disabled]), textarea, input, select, [tabindex]:not([tabindex="-1"])';
8
+ [
9
+ 'a[href]',
10
+ 'button:not([disabled])',
11
+ 'textarea:not([disabled])',
12
+ 'input:not([disabled])',
13
+ 'select:not([disabled])',
14
+ '[tabindex]:not([tabindex="-1"])',
15
+ ].join(", ");
16
+
17
+ function getFocusableElements(
18
+ root: HTMLElement,
19
+ focusableSelector: string,
20
+ ): HTMLElement[] {
21
+ return Array.from(
22
+ root.querySelectorAll<HTMLElement>(focusableSelector),
23
+ ).filter((element) => {
24
+ if (element.getAttribute("aria-hidden") === "true") {
25
+ return false;
26
+ }
27
+ if (typeof window === "undefined") {
28
+ return true;
29
+ }
30
+ const style = getComputedStyle(element);
31
+ if (style.visibility === "hidden" || style.display === "none") {
32
+ return false;
33
+ }
34
+ return true;
35
+ });
36
+ }
9
37
 
10
38
  /**
11
- * Composes modal-like behavior for an open overlay: body scroll lock, Escape to close, and focus trapping.
12
- *
13
- * - Delegates scroll locking to {@link useBodyScrollLock} while `open` is true.
14
- * - Listens for `Escape` on `window` and calls `setOpen(false)`.
15
- * - When `open` becomes true, focuses the first visible focusable inside `contentRef`, or the container itself.
16
- * - Traps focus within `contentRef` via a capturing `focusin` listener on `document` that redirects focus back inside.
17
- * - On close/unmount of the open effect, restores focus to the element that was focused before the trap ran.
18
- *
19
- * @param params.open - Whether the overlay is visible.
20
- * @param params.setOpen - Setter used for Escape and cleanup paths.
21
- * @param params.contentRef - Root of the dialog/drawer content (must point at a focusable container or include focusables).
22
- * @param params.focusableSelector - Query selector for tabbable elements; defaults to a common interactive set.
39
+ * Composes modal-like behavior for an open overlay: body scroll lock, Escape to close, focus trapping with circular Tab cycling, and restoring focus after close.
23
40
  */
24
41
  export const useFocusManagement = ({
25
42
  open,
26
43
  setOpen,
27
44
  contentRef,
45
+ triggerRef,
28
46
  focusableSelector = FOCUSABLE_SELECTOR,
29
47
  }: {
30
48
  open: boolean;
31
49
  setOpen: (open: boolean) => void;
32
- contentRef: RefObject<HTMLDivElement | null>;
50
+ contentRef: RefObject<HTMLElement | null>;
51
+ /** Last modal trigger control; used when focus cannot be inferred at open time. */
52
+ triggerRef?: RefObject<HTMLElement | null>;
33
53
  focusableSelector?: string;
34
54
  }) => {
35
55
  useBodyScrollLock(open);
36
56
 
57
+ const previousFocusRef = useRef<HTMLElement | null>(null);
58
+
37
59
  useEffect(() => {
38
60
  if (!open) {
39
61
  return;
@@ -47,31 +69,138 @@ export const useFocusManagement = ({
47
69
  return () => window.removeEventListener("keydown", handleKeyDown);
48
70
  }, [open, setOpen]);
49
71
 
50
- useEffect(() => {
72
+ useLayoutEffect(() => {
51
73
  if (!open) {
52
74
  return;
53
75
  }
54
- const node = contentRef.current;
55
- if (!node) {
56
- return;
57
- }
58
- const focusables = Array.from(
59
- node.querySelectorAll<HTMLElement>(focusableSelector),
60
- ).filter((element) => element.offsetParent !== null || element === node);
61
- const target = focusables[0] ?? node;
62
- const previouslyFocused = document.activeElement as HTMLElement | null;
63
- target.focus();
76
+
77
+ let cancelled = false;
78
+ let rafId = 0;
79
+ let trapInstalled = false;
80
+
81
+ const detachTrap = () => {
82
+ if (!trapInstalled) {
83
+ return;
84
+ }
85
+ trapInstalled = false;
86
+ document.removeEventListener("focusin", handleFocusIn, true);
87
+ document.removeEventListener("keydown", handleTabKeyDown, true);
88
+ };
89
+
90
+ let trapRoot: HTMLElement | null = null;
64
91
 
65
92
  const handleFocusIn = (event: FocusEvent) => {
66
- if (!node.contains(event.target as Node)) {
67
- event.stopPropagation();
68
- target.focus();
93
+ const node = trapRoot;
94
+ if (!node) {
95
+ return;
96
+ }
97
+ const focused = event.target;
98
+ if (!(focused instanceof Node)) {
99
+ return;
69
100
  }
101
+ if (node.contains(focused)) {
102
+ return;
103
+ }
104
+ const list = getFocusableElements(node, focusableSelector);
105
+ const redirectTarget = list[0] ?? node;
106
+ redirectTarget.focus({ preventScroll: true });
70
107
  };
71
- document.addEventListener("focusin", handleFocusIn);
108
+
109
+ const handleTabKeyDown = (event: KeyboardEvent) => {
110
+ const node = trapRoot;
111
+ if (!node) {
112
+ return;
113
+ }
114
+ if (event.key !== "Tab") {
115
+ return;
116
+ }
117
+ const list = getFocusableElements(node, focusableSelector);
118
+ if (list.length === 0) {
119
+ event.preventDefault();
120
+ node.focus({ preventScroll: true });
121
+ return;
122
+ }
123
+ const first = list[0];
124
+ const last = list[list.length - 1];
125
+ if (!first || !last) {
126
+ return;
127
+ }
128
+ const activeElement = document.activeElement as HTMLElement | undefined;
129
+
130
+ if (!activeElement || !node.contains(activeElement)) {
131
+ event.preventDefault();
132
+ (event.shiftKey ? last : first).focus({ preventScroll: true });
133
+ return;
134
+ }
135
+
136
+ if (event.shiftKey && activeElement === first) {
137
+ event.preventDefault();
138
+ last.focus({ preventScroll: true });
139
+ return;
140
+ }
141
+ if (!event.shiftKey && activeElement === last) {
142
+ event.preventDefault();
143
+ first.focus({ preventScroll: true });
144
+ }
145
+ };
146
+
147
+ const installTrap = () => {
148
+ if (cancelled) {
149
+ return;
150
+ }
151
+ const node = contentRef.current;
152
+ if (!node) {
153
+ rafId = requestAnimationFrame(installTrap);
154
+ return;
155
+ }
156
+
157
+ trapRoot = node;
158
+
159
+ const active = document.activeElement;
160
+ if (
161
+ active instanceof HTMLElement &&
162
+ active !== document.body &&
163
+ !node.contains(active)
164
+ ) {
165
+ previousFocusRef.current = active;
166
+ } else {
167
+ previousFocusRef.current = triggerRef?.current ?? null;
168
+ }
169
+
170
+ const focusables = getFocusableElements(node, focusableSelector);
171
+ const initialFocus = focusables[0] ?? node;
172
+ initialFocus.focus({ preventScroll: true });
173
+
174
+ document.addEventListener("focusin", handleFocusIn, true);
175
+ document.addEventListener("keydown", handleTabKeyDown, true);
176
+ trapInstalled = true;
177
+ };
178
+
179
+ installTrap();
180
+
72
181
  return () => {
73
- document.removeEventListener("focusin", handleFocusIn);
74
- previouslyFocused?.focus?.();
182
+ cancelled = true;
183
+ cancelAnimationFrame(rafId);
184
+ detachTrap();
185
+ trapRoot = null;
186
+
187
+ const fallbackTrigger =
188
+ triggerRef?.current &&
189
+ document.body.contains(triggerRef.current) &&
190
+ typeof triggerRef.current.focus === "function"
191
+ ? triggerRef.current
192
+ : null;
193
+
194
+ const toRestore = previousFocusRef.current ?? fallbackTrigger;
195
+ previousFocusRef.current = null;
196
+
197
+ if (
198
+ toRestore &&
199
+ typeof toRestore.focus === "function" &&
200
+ document.body.contains(toRestore)
201
+ ) {
202
+ toRestore.focus({ preventScroll: true });
203
+ }
75
204
  };
76
- }, [contentRef, open]);
205
+ }, [open, contentRef, triggerRef, focusableSelector]);
77
206
  };
@@ -13,6 +13,7 @@ export function BadgeBase({
13
13
  size,
14
14
  shape,
15
15
  closable = false,
16
+ liveRegion = false,
16
17
  onClose,
17
18
  closeLabel = "Remove",
18
19
  children,
@@ -24,11 +25,13 @@ export function BadgeBase({
24
25
  const isDot = shape === "dot";
25
26
  const resolvedAriaLabel =
26
27
  ariaLabel ?? (isDot ? "Status indicator" : undefined);
28
+ const landmarkRole =
29
+ liveRegion === true || isDot ? ("status" as const) : undefined;
27
30
 
28
31
  return (
29
32
  <Wrapper
30
33
  ref={ref}
31
- role="status"
34
+ role={landmarkRole}
32
35
  data-slot="badge"
33
36
  aria-label={resolvedAriaLabel}
34
37
  className={cn(badgeVariants({ appearance, size, shape }), className)}
@@ -15,6 +15,7 @@ export interface BadgeBaseProps extends ComponentPropsWithRef<"span"> {
15
15
  size?: BadgeVariantProps["size"];
16
16
  shape?: BadgeVariantProps["shape"];
17
17
  closable?: boolean;
18
+ liveRegion?: boolean;
18
19
  onClose?: MouseEventHandler<HTMLButtonElement>;
19
20
  closeLabel?: string;
20
21
  children?: ReactNode;
@@ -7,19 +7,19 @@ import { cva } from "class-variance-authority";
7
7
  export const buttonLikeSolidAppearances = {
8
8
  default: "bg-slate-50 text-slate-950 shadow-[0_1px_2px_rgba(15,23,42,0.12)]",
9
9
  secondary: "bg-slate-800 text-slate-50",
10
- destructive: "bg-rose-600 text-white",
10
+ destructive: "bg-rose-700 text-white",
11
11
  outline: "border border-white/10 bg-white/5 text-slate-50",
12
12
  ghost: "bg-transparent text-slate-200",
13
13
  glass: "border border-white/15 bg-white/10 text-white backdrop-blur-md",
14
- emerald: "bg-emerald-600 text-white",
14
+ emerald: "bg-emerald-800 text-white",
15
15
  indigo: "bg-indigo-600 text-white",
16
16
  purple: "bg-purple-600 text-white",
17
17
  pink: "bg-pink-600 text-white",
18
- rose: "bg-rose-600 text-white",
19
- sky: "bg-sky-600 text-white",
20
- teal: "bg-teal-600 text-white",
21
- yellow: "bg-yellow-600 text-white",
22
- orange: "bg-orange-600 text-white",
18
+ rose: "bg-rose-700 text-white",
19
+ sky: "bg-sky-700 text-white",
20
+ teal: "bg-teal-700 text-white",
21
+ yellow: "bg-yellow-800 text-white",
22
+ orange: "bg-orange-800 text-white",
23
23
  "gradient-blue": "bg-gradient-to-r from-blue-600 to-purple-600 text-white",
24
24
  "gradient-green": "bg-gradient-to-r from-green-600 to-lime-600 text-white",
25
25
  "gradient-red": "bg-gradient-to-r from-red-600 to-pink-600 text-white",
@@ -129,7 +129,7 @@ describe("Button (component library)", () => {
129
129
  expect(
130
130
  root.className,
131
131
  "Destructive appearance must surface danger styling",
132
- ).toMatch(/bg-rose-600/);
132
+ ).toMatch(/bg-rose-700/);
133
133
  });
134
134
 
135
135
  it("should apply outline appearance when appearance='outline'", () => {
@@ -14,24 +14,24 @@ export const buttonVariants = cva(
14
14
  default:
15
15
  "bg-slate-50 text-slate-950 shadow-[0_1px_2px_rgba(15,23,42,0.12)] hover:bg-white",
16
16
  secondary: "bg-slate-800 text-slate-50 hover:bg-slate-700",
17
- destructive: "bg-rose-600 text-white hover:bg-rose-600",
17
+ destructive: "bg-rose-700 text-white hover:bg-rose-800",
18
18
  outline:
19
19
  "border border-white/10 bg-white/5 text-slate-50 hover:bg-white/10",
20
20
  ghost: "bg-transparent text-slate-200 hover:bg-white/5",
21
21
  link: "bg-transparent text-cyan-300 underline-offset-4 hover:underline",
22
22
  glass:
23
23
  "border border-white/15 bg-white/10 text-white backdrop-blur-md hover:bg-white/15",
24
- emerald: "bg-emerald-600 text-white hover:bg-emerald-600",
24
+ emerald: "bg-emerald-800 text-white hover:bg-emerald-900",
25
25
  indigo: "bg-indigo-600 text-white hover:bg-indigo-600",
26
26
  purple: "bg-purple-600 text-white hover:bg-purple-600",
27
27
  pink: "bg-pink-600 text-white hover:bg-pink-600",
28
28
  rose: "bg-rose-600 text-white hover:bg-rose-600",
29
- sky: "bg-sky-600 text-white hover:bg-sky-600",
30
- teal: "bg-teal-600 text-white hover:bg-teal-600",
31
- yellow: "bg-yellow-600 text-white hover:bg-yellow-600",
32
- orange: "bg-orange-600 text-white hover:bg-orange-600",
33
- gray: "bg-gray-600 text-white hover:bg-gray-600",
34
- amber: "bg-amber-600 text-white hover:bg-amber-600",
29
+ sky: "bg-sky-700 text-white hover:bg-sky-800",
30
+ teal: "bg-teal-700 text-white hover:bg-teal-800",
31
+ yellow: "bg-yellow-800 text-white hover:bg-yellow-900",
32
+ orange: "bg-orange-800 text-white hover:bg-orange-900",
33
+ gray: "bg-gray-700 text-white hover:bg-gray-800",
34
+ amber: "bg-amber-800 text-white hover:bg-amber-900",
35
35
  violet: "bg-violet-600 text-white hover:bg-violet-600",
36
36
  "gradient-blue":
37
37
  "bg-gradient-to-r from-blue-600 to-purple-600 text-white hover:from-blue-600 hover:to-purple-600",
@@ -26,7 +26,7 @@ export function DrawerContentAnimated({
26
26
  id,
27
27
  style,
28
28
  }: DrawerContentAnimatedProps) {
29
- const { open, setOpen, titleId, descriptionId, contentRef } =
29
+ const { open, setOpen, titleId, descriptionId, contentRef, triggerRef } =
30
30
  useDrawerContext("DrawerContent");
31
31
  const resolvedSide = side ?? "right";
32
32
  const reduceMotion = useReducedMotion();
@@ -39,6 +39,7 @@ export function DrawerContentAnimated({
39
39
  open,
40
40
  setOpen,
41
41
  contentRef,
42
+ triggerRef,
42
43
  });
43
44
 
44
45
  const portalTarget = typeof document !== "undefined" ? document.body : null;
@@ -50,10 +51,8 @@ export function DrawerContentAnimated({
50
51
  <AnimatePresence>
51
52
  {open ? (
52
53
  <div className="fixed inset-0 z-50" data-slot="drawer-portal">
53
- <motion.button
54
- type="button"
55
- aria-hidden
56
- tabIndex={-1}
54
+ <motion.div
55
+ role="presentation"
57
56
  data-slot="drawer-overlay"
58
57
  className={drawerOverlayVariants()}
59
58
  onClick={() => setOpen(false)}