@techzyapp/ui-library 1.0.40 → 1.0.42

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 (546) hide show
  1. package/README.md +14 -8
  2. package/dist/AdminRoot-DufZpgdm.js +100 -0
  3. package/dist/AdminRoot-DufZpgdm.js.map +1 -0
  4. package/dist/AdminRoot-DwJ5jdXr.cjs +2 -0
  5. package/dist/AdminRoot-DwJ5jdXr.cjs.map +1 -0
  6. package/dist/Alert-C8BBxL_7.cjs +2 -0
  7. package/dist/Alert-C8BBxL_7.cjs.map +1 -0
  8. package/dist/Alert-D6oBxBdP.js +70 -0
  9. package/dist/Alert-D6oBxBdP.js.map +1 -0
  10. package/dist/AuthLayout-exuNQicH.cjs.map +1 -1
  11. package/dist/AuthLayout-q8pbCGdt.js.map +1 -1
  12. package/dist/{Breadcrumbs-hi6dJhfN.cjs → Breadcrumbs-B-olYVdw.cjs} +2 -2
  13. package/dist/Breadcrumbs-B-olYVdw.cjs.map +1 -0
  14. package/dist/{Breadcrumbs-Dqhk-dY2.js → Breadcrumbs-cXET6OM5.js} +3 -3
  15. package/dist/Breadcrumbs-cXET6OM5.js.map +1 -0
  16. package/dist/{Button-Bst_NtPJ.js → Button-0ZgdNjX-.js} +2 -2
  17. package/dist/{Button-Bst_NtPJ.js.map → Button-0ZgdNjX-.js.map} +1 -1
  18. package/dist/{Button-CYZoF18-.cjs → Button-CwrDiZek.cjs} +2 -2
  19. package/dist/{Button-CYZoF18-.cjs.map → Button-CwrDiZek.cjs.map} +1 -1
  20. package/dist/{Calendar-OYXsfuWz.js → Calendar-CxzdnzdK.js} +3 -3
  21. package/dist/{Calendar-OYXsfuWz.js.map → Calendar-CxzdnzdK.js.map} +1 -1
  22. package/dist/{Calendar-CMNBHtvY.cjs → Calendar-d3CX5UJp.cjs} +2 -2
  23. package/dist/{Calendar-CMNBHtvY.cjs.map → Calendar-d3CX5UJp.cjs.map} +1 -1
  24. package/dist/Card-CjqStov5.js +129 -0
  25. package/dist/Card-CjqStov5.js.map +1 -0
  26. package/dist/Card-CxnUoWsi.cjs +2 -0
  27. package/dist/Card-CxnUoWsi.cjs.map +1 -0
  28. package/dist/{Chip-B7cAHjlx.cjs → Chip-BkU3yx6G.cjs} +2 -2
  29. package/dist/Chip-BkU3yx6G.cjs.map +1 -0
  30. package/dist/{Chip-D5ZZs3QH.js → Chip-CzJjbaKx.js} +2 -2
  31. package/dist/Chip-CzJjbaKx.js.map +1 -0
  32. package/dist/ChoiceCardGroup-C7Eengyd.cjs +2 -0
  33. package/dist/ChoiceCardGroup-C7Eengyd.cjs.map +1 -0
  34. package/dist/ChoiceCardGroup-q0yN-TeQ.js +180 -0
  35. package/dist/{ChoiceCardGroup-143hR0v_.cjs.map → ChoiceCardGroup-q0yN-TeQ.js.map} +1 -1
  36. package/dist/{CodeBlock-DrWRSRmO.js → CodeBlock-BHcvQrs9.js} +3 -3
  37. package/dist/CodeBlock-BHcvQrs9.js.map +1 -0
  38. package/dist/{CodeBlock-C3mG_seZ.cjs → CodeBlock-DRBQ_S5t.cjs} +2 -2
  39. package/dist/CodeBlock-DRBQ_S5t.cjs.map +1 -0
  40. package/dist/{ColorPicker-w7NdprlW.js → ColorPicker-BQKFdTNr.js} +51 -51
  41. package/dist/{ColorPicker-w7NdprlW.js.map → ColorPicker-BQKFdTNr.js.map} +1 -1
  42. package/dist/ColorPicker-BzCEMN7B.cjs +2 -0
  43. package/dist/{ColorPicker-C1pDI4su.cjs.map → ColorPicker-BzCEMN7B.cjs.map} +1 -1
  44. package/dist/{ColorPickerPanel-CKMd-dqd.js → ColorPickerPanel-DKTKC9KH.js} +2 -2
  45. package/dist/{ColorPickerPanel-CKMd-dqd.js.map → ColorPickerPanel-DKTKC9KH.js.map} +1 -1
  46. package/dist/{ColorPickerPanel-BbgujQ3X.cjs → ColorPickerPanel-kl2jUix-.cjs} +2 -2
  47. package/dist/{ColorPickerPanel-BbgujQ3X.cjs.map → ColorPickerPanel-kl2jUix-.cjs.map} +1 -1
  48. package/dist/{ColorRamp-D9_5JULy.cjs → ColorRamp-n7muILK3.cjs} +2 -2
  49. package/dist/{ColorRamp-D9_5JULy.cjs.map → ColorRamp-n7muILK3.cjs.map} +1 -1
  50. package/dist/{ColorRamp-Mp_ddhmb.js → ColorRamp-yfMyJCyx.js} +2 -2
  51. package/dist/{ColorRamp-Mp_ddhmb.js.map → ColorRamp-yfMyJCyx.js.map} +1 -1
  52. package/dist/ConfigProvider-BaiTKZKC.cjs +2 -0
  53. package/dist/ConfigProvider-BaiTKZKC.cjs.map +1 -0
  54. package/dist/ConfigProvider-D61cpCz-.js +379 -0
  55. package/dist/ConfigProvider-D61cpCz-.js.map +1 -0
  56. package/dist/{CopyButton-DZeYcG68.cjs → CopyButton-DlSi82gv.cjs} +2 -2
  57. package/dist/{CopyButton-DZeYcG68.cjs.map → CopyButton-DlSi82gv.cjs.map} +1 -1
  58. package/dist/{CopyButton-Yg5ZVTiX.js → CopyButton-ecxn-ghi.js} +3 -3
  59. package/dist/{CopyButton-Yg5ZVTiX.js.map → CopyButton-ecxn-ghi.js.map} +1 -1
  60. package/dist/DatePicker-BjZ_P21i.cjs +2 -0
  61. package/dist/{DatePicker-CXRsT-lt.cjs.map → DatePicker-BjZ_P21i.cjs.map} +1 -1
  62. package/dist/{DatePicker-BMJlfCKB.js → DatePicker-CAGpJbDi.js} +42 -42
  63. package/dist/{DatePicker-BMJlfCKB.js.map → DatePicker-CAGpJbDi.js.map} +1 -1
  64. package/dist/{DateTimePicker-B-Jjejzm.js → DateTimePicker-BJmF0Su6.js} +50 -50
  65. package/dist/DateTimePicker-BJmF0Su6.js.map +1 -0
  66. package/dist/DateTimePicker-DZqWQeUL.cjs +2 -0
  67. package/dist/DateTimePicker-DZqWQeUL.cjs.map +1 -0
  68. package/dist/{DescriptionList-S9C6Tp90.cjs → DescriptionList-CvPDn-kh.cjs} +2 -2
  69. package/dist/DescriptionList-CvPDn-kh.cjs.map +1 -0
  70. package/dist/{DescriptionList-CG08_qwT.js → DescriptionList-Knq5eCiY.js} +4 -4
  71. package/dist/DescriptionList-Knq5eCiY.js.map +1 -0
  72. package/dist/{Dropdown-DYYhzKSo.cjs → Dropdown-CMjURWYd.cjs} +2 -2
  73. package/dist/{Dropdown-DYYhzKSo.cjs.map → Dropdown-CMjURWYd.cjs.map} +1 -1
  74. package/dist/{Dropdown-CcC-Hwx4.js → Dropdown-CnDBlB02.js} +2 -2
  75. package/dist/{Dropdown-CcC-Hwx4.js.map → Dropdown-CnDBlB02.js.map} +1 -1
  76. package/dist/{EmptyState-DnGds1ch.cjs → EmptyState-CX1g47y_.cjs} +2 -2
  77. package/dist/{EmptyState-DnGds1ch.cjs.map → EmptyState-CX1g47y_.cjs.map} +1 -1
  78. package/dist/{EmptyState-BCoPw8jf.js → EmptyState-Dqtpmtje.js} +2 -2
  79. package/dist/{EmptyState-BCoPw8jf.js.map → EmptyState-Dqtpmtje.js.map} +1 -1
  80. package/dist/{ErrorBoundary-JCNa0_Ys.cjs → ErrorBoundary-B8KwWXXp.cjs} +2 -2
  81. package/dist/{ErrorBoundary-JCNa0_Ys.cjs.map → ErrorBoundary-B8KwWXXp.cjs.map} +1 -1
  82. package/dist/{ErrorBoundary-BILk_3fM.js → ErrorBoundary-Dos7VLb-.js} +3 -3
  83. package/dist/{ErrorBoundary-BILk_3fM.js.map → ErrorBoundary-Dos7VLb-.js.map} +1 -1
  84. package/dist/{ErrorState-MQBeyF2n.cjs → ErrorState-CwCqd2PU.cjs} +2 -2
  85. package/dist/{ErrorState-MQBeyF2n.cjs.map → ErrorState-CwCqd2PU.cjs.map} +1 -1
  86. package/dist/{ErrorState-DI28ZCJN.js → ErrorState-KhzrGIJ-.js} +7 -7
  87. package/dist/{ErrorState-DI28ZCJN.js.map → ErrorState-KhzrGIJ-.js.map} +1 -1
  88. package/dist/{FileCard-Cl88Gu6L.cjs → FileCard-DEc10T2G.cjs} +2 -2
  89. package/dist/FileCard-DEc10T2G.cjs.map +1 -0
  90. package/dist/{FileCard-5QvVkO1-.js → FileCard-SSuFS13E.js} +3 -3
  91. package/dist/FileCard-SSuFS13E.js.map +1 -0
  92. package/dist/{FileUploader-FMVbj7rz.cjs → FileUploader-D58_6kDA.cjs} +2 -2
  93. package/dist/FileUploader-D58_6kDA.cjs.map +1 -0
  94. package/dist/{FileUploader-DwAl3UXI.js → FileUploader-DfYOBFa4.js} +5 -5
  95. package/dist/FileUploader-DfYOBFa4.js.map +1 -0
  96. package/dist/{Flag-Do7x-AhS.cjs → Flag-B1ZvZVXi.cjs} +2 -2
  97. package/dist/{Flag-Do7x-AhS.cjs.map → Flag-B1ZvZVXi.cjs.map} +1 -1
  98. package/dist/{Flag-DfA2t0yd.js → Flag-BEIqYQZg.js} +2 -2
  99. package/dist/{Flag-DfA2t0yd.js.map → Flag-BEIqYQZg.js.map} +1 -1
  100. package/dist/FloatingPanel-C5c_eMQ0.js.map +1 -1
  101. package/dist/FloatingPanel-tGCG2nhA.cjs.map +1 -1
  102. package/dist/{FullscreenToggle-DM6wWZ1a.js → FullscreenToggle-I_In47BB.js} +3 -3
  103. package/dist/{FullscreenToggle-DM6wWZ1a.js.map → FullscreenToggle-I_In47BB.js.map} +1 -1
  104. package/dist/{FullscreenToggle-Bbb_z2xj.cjs → FullscreenToggle-Po769CoC.cjs} +2 -2
  105. package/dist/{FullscreenToggle-Bbb_z2xj.cjs.map → FullscreenToggle-Po769CoC.cjs.map} +1 -1
  106. package/dist/{IconButton-CQ25TtBc.cjs → IconButton-CxSXEYce.cjs} +2 -2
  107. package/dist/{IconButton-CQ25TtBc.cjs.map → IconButton-CxSXEYce.cjs.map} +1 -1
  108. package/dist/{IconButton-06pmftMo.js → IconButton-D9MCwRK_.js} +2 -2
  109. package/dist/{IconButton-06pmftMo.js.map → IconButton-D9MCwRK_.js.map} +1 -1
  110. package/dist/{List-CwuAJDTi.js → List-2Y3ktTcF.js} +2 -2
  111. package/dist/{List-CwuAJDTi.js.map → List-2Y3ktTcF.js.map} +1 -1
  112. package/dist/{List-B5Ppe9R1.cjs → List-CKoNx21F.cjs} +2 -2
  113. package/dist/{List-B5Ppe9R1.cjs.map → List-CKoNx21F.cjs.map} +1 -1
  114. package/dist/{ListItem-BWNIbyTh.js → ListItem-2Lr5_NRY.js} +15 -15
  115. package/dist/{ListItem-BWNIbyTh.js.map → ListItem-2Lr5_NRY.js.map} +1 -1
  116. package/dist/ListItem-DkCYXucd.cjs +2 -0
  117. package/dist/{ListItem-Qo1Tt6Fi.cjs.map → ListItem-DkCYXucd.cjs.map} +1 -1
  118. package/dist/{Loader-B5Pm8AaT.cjs → Loader-5zp2MPm5.cjs} +2 -2
  119. package/dist/{Loader-B5Pm8AaT.cjs.map → Loader-5zp2MPm5.cjs.map} +1 -1
  120. package/dist/{Loader-Bj5uwVR9.js → Loader-Bluu6z0-.js} +2 -2
  121. package/dist/{Loader-Bj5uwVR9.js.map → Loader-Bluu6z0-.js.map} +1 -1
  122. package/dist/{LocationPicker-D-sT4rSe.cjs → LocationPicker-CGHXTIml.cjs} +2 -2
  123. package/dist/{LocationPicker-D-sT4rSe.cjs.map → LocationPicker-CGHXTIml.cjs.map} +1 -1
  124. package/dist/{LocationPicker-Ce8aLubZ.js → LocationPicker-hULpHBVG.js} +7 -7
  125. package/dist/{LocationPicker-Ce8aLubZ.js.map → LocationPicker-hULpHBVG.js.map} +1 -1
  126. package/dist/{Modal-DTnB_mGg.js → Modal-C6Zgwz_6.js} +3 -3
  127. package/dist/Modal-C6Zgwz_6.js.map +1 -0
  128. package/dist/{Modal-DjSOhZqd.cjs → Modal-D9_OG53G.cjs} +2 -2
  129. package/dist/Modal-D9_OG53G.cjs.map +1 -0
  130. package/dist/{MultiSelect-C4RvohFY.cjs → MultiSelect-BdPvjiTj.cjs} +2 -2
  131. package/dist/{MultiSelect-C4RvohFY.cjs.map → MultiSelect-BdPvjiTj.cjs.map} +1 -1
  132. package/dist/{MultiSelect-Dn8l5z52.js → MultiSelect-CHLMpim4.js} +4 -4
  133. package/dist/{MultiSelect-Dn8l5z52.js.map → MultiSelect-CHLMpim4.js.map} +1 -1
  134. package/dist/{NumberField-DvQ5UP1R.js → NumberField-BlpFmetF.js} +3 -3
  135. package/dist/{NumberField-DvQ5UP1R.js.map → NumberField-BlpFmetF.js.map} +1 -1
  136. package/dist/{NumberField-C3TLdAgT.cjs → NumberField-C-FZ-uRI.cjs} +2 -2
  137. package/dist/{NumberField-C3TLdAgT.cjs.map → NumberField-C-FZ-uRI.cjs.map} +1 -1
  138. package/dist/OtpField-D4-r7I0A.js +174 -0
  139. package/dist/OtpField-D4-r7I0A.js.map +1 -0
  140. package/dist/OtpField-Drjy2wwq.cjs +2 -0
  141. package/dist/OtpField-Drjy2wwq.cjs.map +1 -0
  142. package/dist/{PageError-aUV0vUfB.cjs → PageError-DXUOkE14.cjs} +2 -2
  143. package/dist/{PageError-aUV0vUfB.cjs.map → PageError-DXUOkE14.cjs.map} +1 -1
  144. package/dist/{PageError-BORFaxGW.js → PageError-DyDj1wQZ.js} +5 -5
  145. package/dist/{PageError-BORFaxGW.js.map → PageError-DyDj1wQZ.js.map} +1 -1
  146. package/dist/{PageLayout-rtEl8uqS.cjs → PageLayout-CoG0AaUs.cjs} +2 -2
  147. package/dist/PageLayout-CoG0AaUs.cjs.map +1 -0
  148. package/dist/{PageLayout-ojiBEcxI.js → PageLayout-nsJa8CbT.js} +4 -4
  149. package/dist/PageLayout-nsJa8CbT.js.map +1 -0
  150. package/dist/{PageNotFound-D536Tshv.js → PageNotFound-BNNwMkwE.js} +5 -5
  151. package/dist/{PageNotFound-D536Tshv.js.map → PageNotFound-BNNwMkwE.js.map} +1 -1
  152. package/dist/{PageNotFound-f-dxrnol.cjs → PageNotFound-CGSxT_n9.cjs} +2 -2
  153. package/dist/{PageNotFound-f-dxrnol.cjs.map → PageNotFound-CGSxT_n9.cjs.map} +1 -1
  154. package/dist/Pagination-CZtewveA.cjs +2 -0
  155. package/dist/Pagination-CZtewveA.cjs.map +1 -0
  156. package/dist/Pagination-tuWRnGwR.js +139 -0
  157. package/dist/Pagination-tuWRnGwR.js.map +1 -0
  158. package/dist/PaletteField-CTPl3D43.js +56 -0
  159. package/dist/PaletteField-CTPl3D43.js.map +1 -0
  160. package/dist/PaletteField-PDcu2vUp.cjs +2 -0
  161. package/dist/PaletteField-PDcu2vUp.cjs.map +1 -0
  162. package/dist/{PhoneField-DzLTXJcw.cjs → PhoneField-BPYg5ZHW.cjs} +2 -2
  163. package/dist/{PhoneField-DzLTXJcw.cjs.map → PhoneField-BPYg5ZHW.cjs.map} +1 -1
  164. package/dist/{PhoneField-CjYw-Unw.js → PhoneField-pdWDCszb.js} +4 -4
  165. package/dist/{PhoneField-CjYw-Unw.js.map → PhoneField-pdWDCszb.js.map} +1 -1
  166. package/dist/{Popconfirm-B3GhhrRM.js → Popconfirm-CMVzLaC_.js} +3 -3
  167. package/dist/{Popconfirm-B3GhhrRM.js.map → Popconfirm-CMVzLaC_.js.map} +1 -1
  168. package/dist/{Popconfirm-CYc8ywDI.cjs → Popconfirm-cNpJmkuR.cjs} +2 -2
  169. package/dist/{Popconfirm-CYc8ywDI.cjs.map → Popconfirm-cNpJmkuR.cjs.map} +1 -1
  170. package/dist/Popover-DsYUT23r.cjs.map +1 -1
  171. package/dist/Popover-WaVH3jsN.js.map +1 -1
  172. package/dist/{Progress-ZNQrxw_Q.js → Progress-BNEFGn-O.js} +2 -2
  173. package/dist/{Progress-ZNQrxw_Q.js.map → Progress-BNEFGn-O.js.map} +1 -1
  174. package/dist/{Progress-BABBBG2y.cjs → Progress-x12Rkh06.cjs} +2 -2
  175. package/dist/{Progress-BABBBG2y.cjs.map → Progress-x12Rkh06.cjs.map} +1 -1
  176. package/dist/QrCode-CrNJZV_8.js +81 -0
  177. package/dist/QrCode-CrNJZV_8.js.map +1 -0
  178. package/dist/QrCode-TcQQE0h7.cjs +2 -0
  179. package/dist/QrCode-TcQQE0h7.cjs.map +1 -0
  180. package/dist/{RemoveDialog-ayAfGXpB.js → RemoveDialog-ARFp1UJM.js} +5 -5
  181. package/dist/{RemoveDialog-ayAfGXpB.js.map → RemoveDialog-ARFp1UJM.js.map} +1 -1
  182. package/dist/{RemoveDialog-B_Y18MeJ.cjs → RemoveDialog-IWOAQFNK.cjs} +2 -2
  183. package/dist/{RemoveDialog-B_Y18MeJ.cjs.map → RemoveDialog-IWOAQFNK.cjs.map} +1 -1
  184. package/dist/RichTextEditor-C9jT2cLl.cjs +2 -0
  185. package/dist/RichTextEditor-C9jT2cLl.cjs.map +1 -0
  186. package/dist/{RichTextEditor-itYD1PfE.js → RichTextEditor-DrwJUEYz.js} +148 -148
  187. package/dist/RichTextEditor-DrwJUEYz.js.map +1 -0
  188. package/dist/RootLayout-CZ2GQ8XA.js +647 -0
  189. package/dist/RootLayout-CZ2GQ8XA.js.map +1 -0
  190. package/dist/RootLayout-DStUP263.cjs +2 -0
  191. package/dist/RootLayout-DStUP263.cjs.map +1 -0
  192. package/dist/{Select-1FWkryTK.cjs → Select-C2DIfuoB.cjs} +2 -2
  193. package/dist/{Select-1FWkryTK.cjs.map → Select-C2DIfuoB.cjs.map} +1 -1
  194. package/dist/{Select-K0a_7ROf.js → Select-KGsA8PbI.js} +3 -3
  195. package/dist/{Select-K0a_7ROf.js.map → Select-KGsA8PbI.js.map} +1 -1
  196. package/dist/{Sidebar-Dg15hPpM.js → Sidebar-_pcwxdd8.js} +133 -131
  197. package/dist/{Sidebar-Dg15hPpM.js.map → Sidebar-_pcwxdd8.js.map} +1 -1
  198. package/dist/Sidebar-wK1_xaY_.cjs +2 -0
  199. package/dist/{Sidebar-C3-u3Agj.cjs.map → Sidebar-wK1_xaY_.cjs.map} +1 -1
  200. package/dist/Slider-CXAz9SUY.cjs +2 -0
  201. package/dist/Slider-CXAz9SUY.cjs.map +1 -0
  202. package/dist/Slider-Cpc5_dPl.js +185 -0
  203. package/dist/Slider-Cpc5_dPl.js.map +1 -0
  204. package/dist/{SpeedDial-D6me6w_m.cjs → SpeedDial-BT_boD06.cjs} +2 -2
  205. package/dist/{SpeedDial-D6me6w_m.cjs.map → SpeedDial-BT_boD06.cjs.map} +1 -1
  206. package/dist/{SpeedDial-CEBAWIYo.js → SpeedDial-SMMfes9f.js} +2 -2
  207. package/dist/{SpeedDial-CEBAWIYo.js.map → SpeedDial-SMMfes9f.js.map} +1 -1
  208. package/dist/{Stepper-wPPs57uZ.cjs → Stepper-BmA_DjTS.cjs} +2 -2
  209. package/dist/Stepper-BmA_DjTS.cjs.map +1 -0
  210. package/dist/{Stepper-BN0GsRZW.js → Stepper-CR0Mlkq7.js} +2 -2
  211. package/dist/Stepper-CR0Mlkq7.js.map +1 -0
  212. package/dist/{Table-CFl3OYlo.cjs → Table-BkjY1Lwt.cjs} +2 -2
  213. package/dist/Table-BkjY1Lwt.cjs.map +1 -0
  214. package/dist/{Table-DChIfjqj.js → Table-D-F68lcm.js} +18 -18
  215. package/dist/Table-D-F68lcm.js.map +1 -0
  216. package/dist/{Tabs-BAKPWO4g.cjs → Tabs-Cgp6D1WP.cjs} +2 -2
  217. package/dist/{Tabs-BAKPWO4g.cjs.map → Tabs-Cgp6D1WP.cjs.map} +1 -1
  218. package/dist/{Tabs-DfVFgOfs.js → Tabs-DP0aZ5TB.js} +2 -2
  219. package/dist/{Tabs-DfVFgOfs.js.map → Tabs-DP0aZ5TB.js.map} +1 -1
  220. package/dist/TagsField-9nKu6ZW4.cjs +2 -0
  221. package/dist/TagsField-9nKu6ZW4.cjs.map +1 -0
  222. package/dist/{TagsField-CoBRqcjW.js → TagsField-CcY9MTMw.js} +64 -64
  223. package/dist/TagsField-CcY9MTMw.js.map +1 -0
  224. package/dist/{TextField-0gFvIFs8.js → TextField-0WvJsHhA.js} +3 -3
  225. package/dist/{TextField-0gFvIFs8.js.map → TextField-0WvJsHhA.js.map} +1 -1
  226. package/dist/{TextField-BL6OAJcP.cjs → TextField-C5MgCQIV.cjs} +2 -2
  227. package/dist/{TextField-BL6OAJcP.cjs.map → TextField-C5MgCQIV.cjs.map} +1 -1
  228. package/dist/{ThemeToggle-BgKfcb02.cjs → ThemeToggle-BvcCxRpF.cjs} +2 -2
  229. package/dist/{ThemeToggle-BgKfcb02.cjs.map → ThemeToggle-BvcCxRpF.cjs.map} +1 -1
  230. package/dist/ThemeToggle-DmCePuTy.js +28 -0
  231. package/dist/{ThemeToggle-_SUmLxmU.js.map → ThemeToggle-DmCePuTy.js.map} +1 -1
  232. package/dist/{TimeColumns-DkJsIu1w.cjs → TimeColumns-Q-vsHFZU.cjs} +2 -2
  233. package/dist/{TimeColumns-DkJsIu1w.cjs.map → TimeColumns-Q-vsHFZU.cjs.map} +1 -1
  234. package/dist/{TimeColumns-BE1sLoRV.js → TimeColumns-WJRHQuFv.js} +2 -2
  235. package/dist/{TimeColumns-BE1sLoRV.js.map → TimeColumns-WJRHQuFv.js.map} +1 -1
  236. package/dist/TimePicker-CvbQFzBf.cjs +2 -0
  237. package/dist/{TimePicker-6nHQx0P5.cjs.map → TimePicker-CvbQFzBf.cjs.map} +1 -1
  238. package/dist/{TimePicker-Bv2qIFf9.js → TimePicker-DJDuSxAg.js} +54 -54
  239. package/dist/{TimePicker-Bv2qIFf9.js.map → TimePicker-DJDuSxAg.js.map} +1 -1
  240. package/dist/{Toaster-Fq6-ImDJ.js → Toaster-Bb5YEN5j.js} +2 -2
  241. package/dist/{Toaster-Fq6-ImDJ.js.map → Toaster-Bb5YEN5j.js.map} +1 -1
  242. package/dist/{Toaster-Brcspf7v.cjs → Toaster-Dy1AonLa.cjs} +2 -2
  243. package/dist/{Toaster-Brcspf7v.cjs.map → Toaster-Dy1AonLa.cjs.map} +1 -1
  244. package/dist/TranslatedFields-CuK5KKzE.cjs +2 -0
  245. package/dist/TranslatedFields-CuK5KKzE.cjs.map +1 -0
  246. package/dist/TranslatedFields-DKXznBtD.js +86 -0
  247. package/dist/TranslatedFields-DKXznBtD.js.map +1 -0
  248. package/dist/{UserCard-1ubnvBV6.cjs → UserCard-DbudGMvG.cjs} +2 -2
  249. package/dist/UserCard-DbudGMvG.cjs.map +1 -0
  250. package/dist/{UserCard-DcTLEHFu.js → UserCard-UG_Cwe-Y.js} +3 -3
  251. package/dist/UserCard-UG_Cwe-Y.js.map +1 -0
  252. package/dist/app/AdminRoot.d.cts +13 -3
  253. package/dist/app/AdminRoot.d.ts +13 -3
  254. package/dist/components/Alert/Alert.d.cts +1 -1
  255. package/dist/components/Alert/Alert.d.ts +1 -1
  256. package/dist/components/Alert/index.cjs +1 -1
  257. package/dist/components/Alert/index.js +1 -1
  258. package/dist/components/AuthLayout/AuthLayout.d.cts +2 -2
  259. package/dist/components/AuthLayout/AuthLayout.d.ts +2 -2
  260. package/dist/components/Breadcrumbs/Breadcrumbs.d.cts +2 -1
  261. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +2 -1
  262. package/dist/components/Breadcrumbs/index.cjs +1 -1
  263. package/dist/components/Breadcrumbs/index.js +1 -1
  264. package/dist/components/Button/index.cjs +1 -1
  265. package/dist/components/Button/index.js +1 -1
  266. package/dist/components/Card/Card.d.cts +1 -1
  267. package/dist/components/Card/Card.d.ts +1 -1
  268. package/dist/components/Card/index.cjs +1 -1
  269. package/dist/components/Card/index.js +1 -1
  270. package/dist/components/Chip/Chip.d.cts +1 -1
  271. package/dist/components/Chip/Chip.d.ts +1 -1
  272. package/dist/components/Chip/index.cjs +1 -1
  273. package/dist/components/Chip/index.js +1 -1
  274. package/dist/components/ChoiceCard/ChoiceCard.d.cts +1 -1
  275. package/dist/components/ChoiceCard/ChoiceCard.d.ts +1 -1
  276. package/dist/components/ChoiceCard/index.cjs +1 -1
  277. package/dist/components/ChoiceCard/index.js +1 -1
  278. package/dist/components/CodeBlock/CodeBlock.d.cts +1 -1
  279. package/dist/components/CodeBlock/CodeBlock.d.ts +1 -1
  280. package/dist/components/CodeBlock/index.cjs +1 -1
  281. package/dist/components/CodeBlock/index.js +1 -1
  282. package/dist/components/ColorPicker/index.cjs +1 -1
  283. package/dist/components/ColorPicker/index.js +1 -1
  284. package/dist/components/ColorRamp/index.cjs +1 -1
  285. package/dist/components/ColorRamp/index.js +1 -1
  286. package/dist/components/CopyButton/index.cjs +1 -1
  287. package/dist/components/CopyButton/index.js +1 -1
  288. package/dist/components/DatePicker/index.cjs +1 -1
  289. package/dist/components/DatePicker/index.js +1 -1
  290. package/dist/components/DateTimePicker/DateTimePicker.d.cts +2 -2
  291. package/dist/components/DateTimePicker/DateTimePicker.d.ts +2 -2
  292. package/dist/components/DateTimePicker/index.cjs +1 -1
  293. package/dist/components/DateTimePicker/index.js +1 -1
  294. package/dist/components/DescriptionList/DescriptionList.d.cts +1 -1
  295. package/dist/components/DescriptionList/DescriptionList.d.ts +1 -1
  296. package/dist/components/DescriptionList/index.cjs +1 -1
  297. package/dist/components/DescriptionList/index.js +1 -1
  298. package/dist/components/Dropdown/index.cjs +1 -1
  299. package/dist/components/Dropdown/index.js +1 -1
  300. package/dist/components/EmptyState/index.cjs +1 -1
  301. package/dist/components/EmptyState/index.js +1 -1
  302. package/dist/components/ErrorState/index.cjs +1 -1
  303. package/dist/components/ErrorState/index.js +2 -2
  304. package/dist/components/FileCard/FileCard.d.cts +5 -2
  305. package/dist/components/FileCard/FileCard.d.ts +5 -2
  306. package/dist/components/FileCard/index.cjs +1 -1
  307. package/dist/components/FileCard/index.js +1 -1
  308. package/dist/components/FileUploader/FileUploader.d.cts +5 -5
  309. package/dist/components/FileUploader/FileUploader.d.ts +5 -5
  310. package/dist/components/FileUploader/index.cjs +1 -1
  311. package/dist/components/FileUploader/index.js +1 -1
  312. package/dist/components/Flag/index.cjs +1 -1
  313. package/dist/components/Flag/index.js +1 -1
  314. package/dist/components/FloatingPanel/FloatingPanel.d.cts +6 -5
  315. package/dist/components/FloatingPanel/FloatingPanel.d.ts +6 -5
  316. package/dist/components/FullscreenToggle/index.cjs +1 -1
  317. package/dist/components/FullscreenToggle/index.js +1 -1
  318. package/dist/components/IconButton/index.cjs +1 -1
  319. package/dist/components/IconButton/index.js +1 -1
  320. package/dist/components/List/index.cjs +1 -1
  321. package/dist/components/List/index.js +2 -2
  322. package/dist/components/Loader/Loader.d.cts +1 -1
  323. package/dist/components/Loader/Loader.d.ts +1 -1
  324. package/dist/components/Loader/index.cjs +1 -1
  325. package/dist/components/Loader/index.js +1 -1
  326. package/dist/components/LocationPicker/index.cjs +1 -1
  327. package/dist/components/LocationPicker/index.js +1 -1
  328. package/dist/components/Modal/Modal.d.cts +1 -1
  329. package/dist/components/Modal/Modal.d.ts +1 -1
  330. package/dist/components/Modal/index.cjs +1 -1
  331. package/dist/components/Modal/index.js +1 -1
  332. package/dist/components/MultiSelect/index.cjs +1 -1
  333. package/dist/components/MultiSelect/index.js +1 -1
  334. package/dist/components/NumberField/index.cjs +1 -1
  335. package/dist/components/NumberField/index.js +1 -1
  336. package/dist/components/OtpField/OtpField.d.cts +1 -1
  337. package/dist/components/OtpField/OtpField.d.ts +1 -1
  338. package/dist/components/OtpField/index.cjs +1 -1
  339. package/dist/components/OtpField/index.js +1 -1
  340. package/dist/components/PageError/index.cjs +1 -1
  341. package/dist/components/PageError/index.js +1 -1
  342. package/dist/components/PageLayout/PageLayout.d.cts +2 -2
  343. package/dist/components/PageLayout/PageLayout.d.ts +2 -2
  344. package/dist/components/PageLayout/index.cjs +1 -1
  345. package/dist/components/PageLayout/index.js +1 -1
  346. package/dist/components/PageNotFound/index.cjs +1 -1
  347. package/dist/components/PageNotFound/index.js +1 -1
  348. package/dist/components/Pagination/index.cjs +1 -1
  349. package/dist/components/Pagination/index.js +1 -1
  350. package/dist/components/PaletteField/PaletteField.d.cts +8 -2
  351. package/dist/components/PaletteField/PaletteField.d.ts +8 -2
  352. package/dist/components/PaletteField/index.cjs +1 -1
  353. package/dist/components/PaletteField/index.js +1 -1
  354. package/dist/components/PhoneField/index.cjs +1 -1
  355. package/dist/components/PhoneField/index.js +1 -1
  356. package/dist/components/Popconfirm/index.cjs +1 -1
  357. package/dist/components/Popconfirm/index.js +1 -1
  358. package/dist/components/Popover/Popover.d.cts +1 -1
  359. package/dist/components/Popover/Popover.d.ts +1 -1
  360. package/dist/components/Progress/index.cjs +1 -1
  361. package/dist/components/Progress/index.js +1 -1
  362. package/dist/components/QrCode/QrCode.d.cts +5 -2
  363. package/dist/components/QrCode/QrCode.d.ts +5 -2
  364. package/dist/components/QrCode/index.cjs +1 -1
  365. package/dist/components/QrCode/index.js +1 -1
  366. package/dist/components/RemoveDialog/index.cjs +1 -1
  367. package/dist/components/RemoveDialog/index.js +1 -1
  368. package/dist/components/RichTextEditor/RichTextEditor.d.cts +1 -1
  369. package/dist/components/RichTextEditor/RichTextEditor.d.ts +1 -1
  370. package/dist/components/RichTextEditor/index.cjs +1 -1
  371. package/dist/components/RichTextEditor/index.js +1 -1
  372. package/dist/components/RootLayout/RootLayout.d.cts +26 -6
  373. package/dist/components/RootLayout/RootLayout.d.ts +26 -6
  374. package/dist/components/RootLayout/SettingsDrawer.d.cts +8 -2
  375. package/dist/components/RootLayout/SettingsDrawer.d.ts +8 -2
  376. package/dist/components/RootLayout/index.cjs +1 -1
  377. package/dist/components/RootLayout/index.d.cts +1 -1
  378. package/dist/components/RootLayout/index.d.ts +1 -1
  379. package/dist/components/RootLayout/index.js +1 -1
  380. package/dist/components/Select/index.cjs +1 -1
  381. package/dist/components/Select/index.js +1 -1
  382. package/dist/components/Sidebar/index.cjs +1 -1
  383. package/dist/components/Sidebar/index.js +1 -1
  384. package/dist/components/Slider/Slider.d.cts +2 -2
  385. package/dist/components/Slider/Slider.d.ts +2 -2
  386. package/dist/components/Slider/index.cjs +1 -1
  387. package/dist/components/Slider/index.js +1 -1
  388. package/dist/components/SpeedDial/index.cjs +1 -1
  389. package/dist/components/SpeedDial/index.js +1 -1
  390. package/dist/components/Stepper/Stepper.d.cts +2 -2
  391. package/dist/components/Stepper/Stepper.d.ts +2 -2
  392. package/dist/components/Stepper/index.cjs +1 -1
  393. package/dist/components/Stepper/index.js +1 -1
  394. package/dist/components/Table/Table.d.cts +1 -1
  395. package/dist/components/Table/Table.d.ts +1 -1
  396. package/dist/components/Table/index.cjs +1 -1
  397. package/dist/components/Table/index.js +1 -1
  398. package/dist/components/Tabs/index.cjs +1 -1
  399. package/dist/components/Tabs/index.js +1 -1
  400. package/dist/components/TagsField/TagsField.d.cts +1 -1
  401. package/dist/components/TagsField/TagsField.d.ts +1 -1
  402. package/dist/components/TagsField/index.cjs +1 -1
  403. package/dist/components/TagsField/index.js +1 -1
  404. package/dist/components/TextField/index.cjs +1 -1
  405. package/dist/components/TextField/index.js +1 -1
  406. package/dist/components/ThemeToggle/index.cjs +1 -1
  407. package/dist/components/ThemeToggle/index.js +1 -1
  408. package/dist/components/TimePicker/index.cjs +1 -1
  409. package/dist/components/TimePicker/index.js +1 -1
  410. package/dist/components/Toast/index.cjs +1 -1
  411. package/dist/components/Toast/index.js +1 -1
  412. package/dist/components/TranslatedFields/TranslatedFields.d.cts +1 -1
  413. package/dist/components/TranslatedFields/TranslatedFields.d.ts +1 -1
  414. package/dist/components/TranslatedFields/index.cjs +1 -1
  415. package/dist/components/TranslatedFields/index.js +1 -1
  416. package/dist/components/UserCard/UserCard.d.cts +6 -5
  417. package/dist/components/UserCard/UserCard.d.ts +6 -5
  418. package/dist/components/UserCard/index.cjs +1 -1
  419. package/dist/components/UserCard/index.js +1 -1
  420. package/dist/entries/app.cjs +1 -1
  421. package/dist/entries/app.js +1 -1
  422. package/dist/entries/components.cjs +1 -1
  423. package/dist/entries/components.js +56 -56
  424. package/dist/entries/i18n.cjs +1 -1
  425. package/dist/entries/i18n.js +2 -2
  426. package/dist/entries/theme.cjs +1 -1
  427. package/dist/entries/theme.d.cts +2 -2
  428. package/dist/entries/theme.d.ts +2 -2
  429. package/dist/entries/theme.js +12 -11
  430. package/dist/form/useForm.d.cts +1 -1
  431. package/dist/form/useForm.d.ts +1 -1
  432. package/dist/hooks/useMediaQuery.d.cts +3 -3
  433. package/dist/hooks/useMediaQuery.d.ts +3 -3
  434. package/dist/i18n/messages.d.cts +26 -0
  435. package/dist/i18n/messages.d.ts +26 -0
  436. package/dist/index.cjs +1 -1
  437. package/dist/index.css +3 -3
  438. package/dist/index.js +232 -231
  439. package/dist/{messages-CMgYU5p6.js → messages-BiRLMy1E.js} +228 -46
  440. package/dist/messages-BiRLMy1E.js.map +1 -0
  441. package/dist/messages-C_fRRCg6.cjs +36 -0
  442. package/dist/messages-C_fRRCg6.cjs.map +1 -0
  443. package/dist/theme/ConfigProvider.d.cts +47 -7
  444. package/dist/theme/ConfigProvider.d.ts +47 -7
  445. package/dist/theme/index.d.cts +2 -2
  446. package/dist/theme/index.d.ts +2 -2
  447. package/dist/useForm-CGbJ44Gp.js.map +1 -1
  448. package/dist/useForm-CSw6r1n1.cjs.map +1 -1
  449. package/dist/{useHomeTo-MfvJxziQ.cjs → useHomeTo-BaM7kBDh.cjs} +2 -2
  450. package/dist/{useHomeTo-MfvJxziQ.cjs.map → useHomeTo-BaM7kBDh.cjs.map} +1 -1
  451. package/dist/{useHomeTo-Ckq7scIY.js → useHomeTo-DQj9tVZI.js} +2 -2
  452. package/dist/{useHomeTo-Ckq7scIY.js.map → useHomeTo-DQj9tVZI.js.map} +1 -1
  453. package/dist/useMediaQuery-CHMrI6Dy.cjs.map +1 -1
  454. package/dist/useMediaQuery-DrDUrkmJ.js.map +1 -1
  455. package/dist/{useOptionMenu-3YlvxPAM.cjs → useOptionMenu-BKC1y6oj.cjs} +2 -2
  456. package/dist/{useOptionMenu-3YlvxPAM.cjs.map → useOptionMenu-BKC1y6oj.cjs.map} +1 -1
  457. package/dist/{useOptionMenu-BBsyUow1.js → useOptionMenu-Dom1-bqm.js} +5 -5
  458. package/dist/{useOptionMenu-BBsyUow1.js.map → useOptionMenu-Dom1-bqm.js.map} +1 -1
  459. package/package.json +1 -1
  460. package/dist/AdminRoot-CRTBGUxq.cjs +0 -2
  461. package/dist/AdminRoot-CRTBGUxq.cjs.map +0 -1
  462. package/dist/AdminRoot-JOgiNkJA.js +0 -107
  463. package/dist/AdminRoot-JOgiNkJA.js.map +0 -1
  464. package/dist/Alert-CY8iU1zd.cjs +0 -2
  465. package/dist/Alert-CY8iU1zd.cjs.map +0 -1
  466. package/dist/Alert-CtUr-0s8.js +0 -70
  467. package/dist/Alert-CtUr-0s8.js.map +0 -1
  468. package/dist/Breadcrumbs-Dqhk-dY2.js.map +0 -1
  469. package/dist/Breadcrumbs-hi6dJhfN.cjs.map +0 -1
  470. package/dist/Card-B91LGIzF.js +0 -128
  471. package/dist/Card-B91LGIzF.js.map +0 -1
  472. package/dist/Card-CkZtVNyV.cjs +0 -2
  473. package/dist/Card-CkZtVNyV.cjs.map +0 -1
  474. package/dist/Chip-B7cAHjlx.cjs.map +0 -1
  475. package/dist/Chip-D5ZZs3QH.js.map +0 -1
  476. package/dist/ChoiceCardGroup-143hR0v_.cjs +0 -2
  477. package/dist/ChoiceCardGroup-Cx8CtmPl.js +0 -180
  478. package/dist/ChoiceCardGroup-Cx8CtmPl.js.map +0 -1
  479. package/dist/CodeBlock-C3mG_seZ.cjs.map +0 -1
  480. package/dist/CodeBlock-DrWRSRmO.js.map +0 -1
  481. package/dist/ColorPicker-C1pDI4su.cjs +0 -2
  482. package/dist/ConfigProvider-B_Bb6pk1.cjs +0 -2
  483. package/dist/ConfigProvider-B_Bb6pk1.cjs.map +0 -1
  484. package/dist/ConfigProvider-DeMASTVo.js +0 -347
  485. package/dist/ConfigProvider-DeMASTVo.js.map +0 -1
  486. package/dist/DatePicker-CXRsT-lt.cjs +0 -2
  487. package/dist/DateTimePicker-B-Jjejzm.js.map +0 -1
  488. package/dist/DateTimePicker-BuTIRTUX.cjs +0 -2
  489. package/dist/DateTimePicker-BuTIRTUX.cjs.map +0 -1
  490. package/dist/DescriptionList-CG08_qwT.js.map +0 -1
  491. package/dist/DescriptionList-S9C6Tp90.cjs.map +0 -1
  492. package/dist/FileCard-5QvVkO1-.js.map +0 -1
  493. package/dist/FileCard-Cl88Gu6L.cjs.map +0 -1
  494. package/dist/FileUploader-DwAl3UXI.js.map +0 -1
  495. package/dist/FileUploader-FMVbj7rz.cjs.map +0 -1
  496. package/dist/ListItem-Qo1Tt6Fi.cjs +0 -2
  497. package/dist/Modal-DTnB_mGg.js.map +0 -1
  498. package/dist/Modal-DjSOhZqd.cjs.map +0 -1
  499. package/dist/OtpField-Dy4O1MeD.js +0 -174
  500. package/dist/OtpField-Dy4O1MeD.js.map +0 -1
  501. package/dist/OtpField-OdkuKKcV.cjs +0 -2
  502. package/dist/OtpField-OdkuKKcV.cjs.map +0 -1
  503. package/dist/PageLayout-ojiBEcxI.js.map +0 -1
  504. package/dist/PageLayout-rtEl8uqS.cjs.map +0 -1
  505. package/dist/Pagination-DoDGKGpQ.js +0 -139
  506. package/dist/Pagination-DoDGKGpQ.js.map +0 -1
  507. package/dist/Pagination-Ffv6IFIU.cjs +0 -2
  508. package/dist/Pagination-Ffv6IFIU.cjs.map +0 -1
  509. package/dist/PaletteField-ChG2VQtS.js +0 -54
  510. package/dist/PaletteField-ChG2VQtS.js.map +0 -1
  511. package/dist/PaletteField-DQ1OvXqe.cjs +0 -2
  512. package/dist/PaletteField-DQ1OvXqe.cjs.map +0 -1
  513. package/dist/QrCode-B9YbQNVc.js +0 -80
  514. package/dist/QrCode-B9YbQNVc.js.map +0 -1
  515. package/dist/QrCode-CNVYpz9j.cjs +0 -2
  516. package/dist/QrCode-CNVYpz9j.cjs.map +0 -1
  517. package/dist/RichTextEditor-DSvSaszc.cjs +0 -2
  518. package/dist/RichTextEditor-DSvSaszc.cjs.map +0 -1
  519. package/dist/RichTextEditor-itYD1PfE.js.map +0 -1
  520. package/dist/RootLayout-BlYjYAYk.js +0 -582
  521. package/dist/RootLayout-BlYjYAYk.js.map +0 -1
  522. package/dist/RootLayout-D5nlzYlH.cjs +0 -2
  523. package/dist/RootLayout-D5nlzYlH.cjs.map +0 -1
  524. package/dist/Sidebar-C3-u3Agj.cjs +0 -2
  525. package/dist/Slider-0joKXhPo.cjs +0 -2
  526. package/dist/Slider-0joKXhPo.cjs.map +0 -1
  527. package/dist/Slider-CwZYxDO0.js +0 -184
  528. package/dist/Slider-CwZYxDO0.js.map +0 -1
  529. package/dist/Stepper-BN0GsRZW.js.map +0 -1
  530. package/dist/Stepper-wPPs57uZ.cjs.map +0 -1
  531. package/dist/Table-CFl3OYlo.cjs.map +0 -1
  532. package/dist/Table-DChIfjqj.js.map +0 -1
  533. package/dist/TagsField-5mbyaFQZ.cjs +0 -2
  534. package/dist/TagsField-5mbyaFQZ.cjs.map +0 -1
  535. package/dist/TagsField-CoBRqcjW.js.map +0 -1
  536. package/dist/ThemeToggle-_SUmLxmU.js +0 -28
  537. package/dist/TimePicker-6nHQx0P5.cjs +0 -2
  538. package/dist/TranslatedFields-CVc0NvXa.cjs +0 -2
  539. package/dist/TranslatedFields-CVc0NvXa.cjs.map +0 -1
  540. package/dist/TranslatedFields-CmRhRGC_.js +0 -86
  541. package/dist/TranslatedFields-CmRhRGC_.js.map +0 -1
  542. package/dist/UserCard-1ubnvBV6.cjs.map +0 -1
  543. package/dist/UserCard-DcTLEHFu.js.map +0 -1
  544. package/dist/messages-CMgYU5p6.js.map +0 -1
  545. package/dist/messages-h22vS9zn.cjs +0 -36
  546. package/dist/messages-h22vS9zn.cjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileUploader-DwAl3UXI.js","sources":["../src/components/FileUploader/FileUploaderEditDialog.tsx","../src/components/FileUploader/FileUploaderPreview.tsx","../src/components/FileUploader/FileUploader.tsx"],"sourcesContent":["import { useRef, useState, type ChangeEvent } from 'react'\nimport ReactCrop, { type Crop, type PercentCrop, type PixelCrop } from 'react-image-crop'\nimport 'react-image-crop/dist/ReactCrop.css'\nimport { useT, type LocaleConfig } from '../../theme'\nimport { Button } from '../Button'\nimport { Modal } from '../Modal'\nimport { TextField } from '../TextField'\nimport { Typography } from '../Typography'\nimport styles from './FileUploaderEditDialog.module.css'\n\n/** What a dialog hands back on Save: the alt-text draft (alt-text mode) or a cropped File (crop mode). */\nexport interface EditDialogResult {\n /** Alt-text values keyed by locale code (or the single `''` key in non-localized mode). */\n draft?: Record<string, string>\n /** A freshly-cropped File (native-resolution, lossless). */\n croppedFile?: File\n}\n\nexport interface FileUploaderEditDialogProps {\n /** Which editor to show — the **crop** stage or the **alt text** fields (each is its own modal). */\n mode: 'crop' | 'altText'\n /** Display name (modal description + the cropped File's name). */\n name: string\n /** Image URL for crop mode (object URL for a File, or the source URL). */\n imageUrl: string | null\n /** MIME type for the cropped output — keeps the original (PNG ⇒ lossless). */\n mimeType: string\n /** Locales for the alt-text editor (one field each); a single `{ code: '' }` ⇒ one plain field. */\n editLocales: LocaleConfig[]\n /** The alt-text draft to seed from the item's current value. */\n initialDraft: Record<string, string>\n /** Close without saving. */\n onClose: () => void\n /** Commit the result (alt-text draft or cropped File). */\n onSave: (result: EditDialogResult) => void\n}\n\n/** The crop selection in the image's NATIVE pixels — what actually gets exported (no resample / resize). */\ninterface NaturalCrop {\n x: number\n y: number\n width: number\n height: number\n}\n\n/**\n * The FileUploader per-item edit modal. Two separate modes (each opened from its own card button):\n * **`crop`** — a draggable selection over the image, exported at the image's native resolution (lossless,\n * dimensions shown live); **`altText`** — one `TextField` per locale (stacked, no tabs). Built on the\n * library's `Modal` + `TextField` and **`react-image-crop`** (an optional peer). Internal — not exported.\n */\nexport function FileUploaderEditDialog({\n mode,\n name,\n imageUrl,\n mimeType,\n editLocales,\n initialDraft,\n onClose,\n onSave,\n}: FileUploaderEditDialogProps) {\n const t = useT()\n const imgRef = useRef<HTMLImageElement>(null)\n const [crop, setCrop] = useState<Crop>()\n // store the crop in NATIVE coords (computed on every drag) so the export never depends on display size\n const [naturalCrop, setNaturalCrop] = useState<NaturalCrop | null>(null)\n // the image's intrinsic size (captured on load) — shown as the readout until a crop is selected\n const [naturalSize, setNaturalSize] = useState<{ w: number; h: number } | null>(null)\n const [draft, setDraft] = useState<Record<string, string>>(initialDraft)\n const [cropError, setCropError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n\n const onCropChange = (px: PixelCrop, percent: PercentCrop) => {\n setCrop(percent)\n const img = imgRef.current\n if (img && img.width > 0 && px.width >= 1 && px.height >= 1) {\n const sx = img.naturalWidth / img.width\n const sy = img.naturalHeight / img.height\n setNaturalCrop({\n x: Math.round(px.x * sx),\n y: Math.round(px.y * sy),\n width: Math.round(px.width * sx),\n height: Math.round(px.height * sy),\n })\n } else {\n setNaturalCrop(null)\n }\n }\n\n // Crop at native resolution: copy the selected region 1:1 (no resample → no quality loss, no resize).\n const buildCroppedFile = async (): Promise<File | undefined> => {\n const image = imgRef.current\n if (!image || !naturalCrop || naturalCrop.width < 1 || naturalCrop.height < 1) return undefined\n const canvas = document.createElement('canvas')\n canvas.width = naturalCrop.width\n canvas.height = naturalCrop.height\n const ctx = canvas.getContext('2d')\n if (!ctx) return undefined\n ctx.imageSmoothingEnabled = false // 1:1 native-pixel copy — no resampling\n ctx.drawImage(\n image,\n naturalCrop.x,\n naturalCrop.y,\n naturalCrop.width,\n naturalCrop.height,\n 0,\n 0,\n naturalCrop.width,\n naturalCrop.height,\n )\n // toBlob throws on a cross-origin-tainted canvas — let handleSave catch it\n const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, mimeType, 1))\n // a null blob is a failed export too (not just tainted) — throw so it surfaces as a crop error\n // instead of silently resolving to `undefined` and discarding the crop with no feedback\n if (!blob) throw new Error('canvas.toBlob returned null')\n return new File([blob], name, { type: mimeType, lastModified: Date.now() })\n }\n\n const handleSave = async () => {\n if (mode === 'altText') {\n onSave({ draft })\n return\n }\n setBusy(true)\n try {\n const croppedFile =\n naturalCrop && naturalCrop.width >= 1 && naturalCrop.height >= 1\n ? await buildCroppedFile()\n : undefined\n onSave({ croppedFile }) // parent commits + closes (this dialog unmounts)\n } catch {\n setCropError(t('fileUploader.cropError'))\n setBusy(false)\n }\n }\n\n return (\n <Modal\n open\n onClose={onClose}\n size={mode === 'crop' ? 'lg' : 'sm'}\n icon={mode === 'crop' ? 'Crop' : 'Text'}\n title={mode === 'crop' ? t('fileUploader.cropTitle') : t('fileUploader.altTitle')}\n description={name}\n footer={\n <>\n <Button variant=\"text\" color=\"accent\" size=\"sm\" onClick={onClose} disabled={busy}>\n {t('common.cancel')}\n </Button>\n <Button size=\"sm\" onClick={handleSave} loading={busy}>\n {t('common.save')}\n </Button>\n </>\n }\n >\n {mode === 'crop' ? (\n <div className={styles.cropSection}>\n <div className={styles.cropHead}>\n <Typography variant=\"bodySmall\" color=\"muted\">\n {t('fileUploader.cropHint')}\n </Typography>\n <Typography variant=\"bodySmall\" color={naturalCrop ? 'text' : 'muted'}>\n {naturalCrop\n ? `${naturalCrop.width} × ${naturalCrop.height} px`\n : naturalSize\n ? `${naturalSize.w} × ${naturalSize.h} px`\n : ''}\n </Typography>\n </div>\n <div className={styles.cropStage}>\n <ReactCrop crop={crop} onChange={onCropChange} className={styles.crop}>\n <img\n ref={imgRef}\n src={imageUrl ?? undefined}\n alt=\"\"\n className={styles.cropImg}\n onLoad={(e) =>\n setNaturalSize({\n w: e.currentTarget.naturalWidth,\n h: e.currentTarget.naturalHeight,\n })\n }\n />\n </ReactCrop>\n </div>\n {cropError && (\n <Typography variant=\"bodySmall\" color=\"error\">\n {cropError}\n </Typography>\n )}\n </div>\n ) : (\n <div className={styles.altFields}>\n {editLocales.map((l) => (\n <TextField\n key={l.code}\n label={l.label ?? (l.code || t('fileUploader.altTitle'))}\n placeholder={t('fileUploader.altPlaceholder')}\n value={draft[l.code] ?? ''}\n onChange={(e: ChangeEvent<HTMLInputElement>) =>\n setDraft((d) => ({ ...d, [l.code]: e.target.value }))\n }\n />\n ))}\n </div>\n )}\n </Modal>\n )\n}\n","import { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Icon } from '../Icon'\nimport { Overlay } from '../Overlay/Overlay'\nimport styles from './FileUploaderPreview.module.css'\n\nexport interface FileUploaderPreviewProps {\n /** The media URL (a File's object URL or a source URL). */\n url: string\n /** Render a `<video controls>` instead of an `<img>`. */\n isVideo: boolean\n /**\n * The image is an SVG — a vector has no reliable pixel size (a viewBox-only icon shows tiny, a sizeless\n * one collapses to nothing), so when set the image is given a floored box (`min-*` + `object-fit:\n * contain`): a small SVG scales up to a visible minimum while a larger one keeps its real size.\n */\n isSvg?: boolean\n /** Accessible name / image alt. */\n name: string\n /** Dismiss the overlay. */\n onClose: () => void\n}\n\n/**\n * A fullscreen media lightbox for the FileUploader — a dark backdrop with the image (or a `<video>` with\n * controls) centered. Built on the shared `<Overlay>` (portal to `<body>`, scroll-lock, fade-in, backdrop\n * / Escape dismissal); a darker scrim (`dim={0.85}`) than a Modal since media reads over black. Opened\n * from a card's **Eye** button (image + video items only). Internal — not exported.\n */\nexport function FileUploaderPreview({\n url,\n isVideo,\n isSvg,\n name,\n onClose,\n}: FileUploaderPreviewProps) {\n const t = useT()\n return (\n <Overlay\n open\n onClose={onClose}\n dim={0.85}\n className={styles.backdrop}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={t('fileUploader.preview', { name })}\n >\n <button\n type=\"button\"\n className={styles.close}\n aria-label={t('fileUploader.closePreview')}\n onClick={onClose}\n autoFocus\n >\n <Icon name=\"Close\" size=\"lg\" />\n </button>\n {isVideo ? (\n <video src={url} className={styles.media} controls playsInline />\n ) : (\n // an SVG's natural size is unreliable, so it always gets the floored box (`.mediaSvg`); a raster\n // keeps its natural size, only capped to the viewport (`.media`)\n <img src={url} alt={name} className={clsx(styles.media, isSvg && styles.mediaSvg)} />\n )}\n </Overlay>\n )\n}\n","import {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type HTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport {\n DndContext,\n KeyboardSensor,\n PointerSensor,\n closestCenter,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from '@dnd-kit/core'\nimport {\n SortableContext,\n arrayMove,\n useSortable,\n sortableKeyboardCoordinates,\n rectSortingStrategy,\n} from '@dnd-kit/sortable'\nimport { CSS } from '@dnd-kit/utilities'\nimport type { AutoAnimationPlugin } from '@formkit/auto-animate'\nimport { useAutoAnimate } from '@formkit/auto-animate/react'\nimport { useDropzone, type Accept, type FileRejection } from 'react-dropzone'\nimport { useFormContext } from '../../form/formContext'\nimport { useLocales, useT, type LocaleConfig } from '../../theme'\nimport { toast } from '../Toast/toastStore'\nimport { Icon } from '../Icon'\nimport { Skeleton } from '../Skeleton'\nimport { Typography } from '../Typography'\nimport { FileUploaderEditDialog, type EditDialogResult } from './FileUploaderEditDialog'\nimport { FileUploaderPreview } from './FileUploaderPreview'\n// shared field chrome (wrapper / label / required / helper) — the Slider precedent\nimport fieldStyles from '../TextField/TextField.module.css'\nimport styles from './FileUploader.module.css'\n\n/**\n * A single file entry. A freshly-picked file carries its binary in `file`; an already-uploaded one\n * (a backend response, edit mode) carries only its URL in `source` — then `file` is absent.\n */\nexport interface FileUploaderItem {\n /** The picked binary — present for a newly-selected file, absent for an already-uploaded one. */\n file?: File\n /** Server URL of an already-uploaded file (edit mode); `''` for a fresh pick. */\n source?: string\n /** Position in the list (0-based) — kept in sync with the visual order on every change. */\n sortIndex: number\n /**\n * Optional alt text, edited per card via the `allowAltText` modal. **Per-locale by default** —\n * `Record<localeCode, string>` (e.g. `{ 'en-US': 'A red car', 'ka-GE': '…' }`); with\n * **`localizedAltText={false}`** it's a single **`string`**. Absent until something is typed.\n */\n altText?: Record<string, string> | string\n}\n\n/** Single mode → one item (or `null`); `multiple` mode → an array. */\nexport type FileUploaderValue = FileUploaderItem | FileUploaderItem[] | null\n\nexport interface FileUploaderProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** Accept more than one file — the value becomes an array. Defaults to `false`. */\n multiple?: boolean\n /** Allow dropping files onto the dropzone (drag from the OS). Defaults to `true`. */\n allowDrop?: boolean\n /** Allow drag + keyboard reordering of the rows (only meaningful with `multiple`). Defaults to `true`. */\n allowReorder?: boolean\n /** Show a download button on each item (downloads the File / source). Defaults to `true`. */\n allowDownload?: boolean\n /**\n * Show a per-card **preview** (Eye) button — opens a fullscreen lightbox of the image / video. Defaults\n * to `true`. Only rendered for **image + video** items (a PDF / doc has nothing to preview).\n */\n allowPreview?: boolean\n /**\n * Show a per-card **edit** button that opens a modal for editing the item's `altText`. Defaults to\n * `true` — pass `false` to hide it. The modal renders one input per content locale (a tab strip when\n * there are several), so the edited value lands in `item.altText` keyed by locale code (or a single\n * string with `localizedAltText={false}`).\n */\n allowAltText?: boolean\n /**\n * Locales for the `allowAltText` editor (one input/tab each). Defaults to the app's `ConfigProvider`\n * locales (`useLocales()`); pass this to override — mirrors `<TranslatedFields locales>`. Ignored when\n * `localizedAltText` is `false`.\n */\n altTextLocales?: LocaleConfig[]\n /**\n * Whether the `allowAltText` editor is **per-locale**. Defaults to `true` — `altText` is a\n * `Record<localeCode, string>` with one input/tab per locale. Pass **`false`** for a single plain input\n * (no locales), so `altText` is just a **`string`**.\n */\n localizedAltText?: boolean\n /**\n * Allow the same file to be added more than once. By default (`false`) a pick that matches an\n * already-present item by content (a File by name + size + last-modified, a source by URL) is skipped\n * and a notice is shown. Only meaningful with `multiple` (single mode replaces, so it can't stack).\n */\n allowDuplicates?: boolean\n /** Disables the whole control — no adding, removing, reordering, or downloading; dimmed + inert. */\n disabled?: boolean\n /**\n * Accepted file types (react-dropzone's format: a MIME type → file-extensions map) — restricts the file\n * picker and rejects non-matching picks/drops (a rejection raises a `toast.error`). E.g. `{ 'image/*': [] }`\n * or `{ 'image/*': [], 'application/pdf': ['.pdf'] }`. Omit to accept any type.\n */\n accept?: Accept\n /** Maximum number of files (only meaningful with `multiple`). Picks beyond it are rejected with a notice. */\n maxFiles?: number\n /**\n * Maximum size per file — a bytes `number`, or a human string like `\"5MB\"` / `\"500KB\"`. A picked file\n * over the limit is **rejected** (not added) and raises a **`toast.error`** (so a `<Toaster>` — mounted\n * by `RootLayout` by default — must be present to see it). A file supplied via `value`/`defaultValue`\n * that exceeds the limit is still rendered but flagged in an error state (red ring + `\"Exceeds … limit\"`).\n */\n maxFileSize?: number | string\n /** Where a newly added file lands in the list (`multiple` only): `'start'` (top) or `'end'` (bottom). Defaults to `'end'`. */\n itemInsertLocation?: 'start' | 'end'\n /** Controlled value — one item (or `null`) when single, an array when `multiple`. */\n value?: FileUploaderValue\n /** Initial value for uncontrolled use. */\n defaultValue?: FileUploaderValue\n /** Fires with the next value whenever files are added, removed, or reordered. */\n onChange?: (value: FileUploaderValue) => void\n /** Label rendered above the control. */\n label?: ReactNode\n /** Marks the field invalid: red dropzone border + the `helperText` in the error color. */\n error?: boolean\n /** Helper / validation text under the control. Adopts the error color while `error`. */\n helperText?: ReactNode\n /** Adds a red asterisk after the label. */\n required?: boolean\n /** Stretches the control to fill its container width. Defaults to `true`. */\n fullWidth?: boolean\n /**\n * Binds the field to a surrounding `<Form>` — the form value is the item / array, validated with e.g.\n * `z.array(fileItemSchema).min(1)`. Reads the raw `form.values[name]` and writes via `setValue`;\n * error/touched come from the form, and the form's scroll-to-error can focus the field.\n */\n name?: string\n}\n\nconst canMakeObjectUrl = (): boolean =>\n typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function'\n\n// auto-animate plugin: the ENTER (add) is handled by a CSS mount animation on `.row` (a reliable, visible\n// drop-in), so here `add` is a no-op to avoid double-animating; auto-animate still smoothly animates the\n// `remove` (lift + fade) and the `remain` reflow (rows sliding up to fill a gap).\nconst ANIM_MS = 300\nconst listAnimation: AutoAnimationPlugin = (el, action, oldCoords, newCoords) => {\n let keyframes: Keyframe[] = [{}, {}]\n let duration = ANIM_MS\n if (action === 'add') {\n duration = 0\n } else if (action === 'remove') {\n keyframes = [\n { opacity: 1, transform: 'translateY(0)' },\n { opacity: 0, transform: 'translateY(-8px)' },\n ]\n } else if (oldCoords && newCoords) {\n const dx = oldCoords.left - newCoords.left\n const dy = oldCoords.top - newCoords.top\n keyframes = [{ transform: `translate(${dx}px, ${dy}px)` }, { transform: 'translate(0, 0)' }]\n }\n return new KeyframeEffect(el, keyframes, { duration, easing: 'ease-out' })\n}\n\n/** Human-readable byte size, e.g. `2.4 MB`. (Exported for unit tests; not part of the public surface.) */\nexport const formatBytes = (bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`\n const units = ['KB', 'MB', 'GB', 'TB']\n let value = bytes / 1024\n let i = 0\n while (value >= 1024 && i < units.length - 1) {\n value /= 1024\n i += 1\n }\n return `${value.toFixed(value < 10 ? 1 : 0)} ${units[i]}`\n}\n\n/** Coerce a `maxFileSize` (a bytes number, or a human string like `\"5MB\"` / `\"500 KB\"`) to bytes. */\nexport const toBytes = (size: number | string): number | undefined => {\n if (typeof size === 'number') return size\n const match = /^\\s*([\\d.]+)\\s*(b|kb|mb|gb|tb)?\\s*$/i.exec(size)\n if (!match) return undefined\n const units: Record<string, number> = {\n b: 1,\n kb: 1024,\n mb: 1024 ** 2,\n gb: 1024 ** 3,\n tb: 1024 ** 4,\n }\n return parseFloat(match[1]) * (units[(match[2] || 'b').toLowerCase()] ?? 1)\n}\n\n/**\n * A content-identity key for de-duplication. The same file picked twice arrives as two distinct `File`\n * objects (so a `WeakMap`/reference check can't catch it), but its name + size + last-modified match.\n */\nexport const fileKey = (file: File): string => `f:${file.name}:${file.size}:${file.lastModified}`\n/** The dedup key for an existing item — a File by its content, an already-uploaded one by its URL. */\nexport const itemKey = (item: FileUploaderItem): string =>\n item.file ? fileKey(item.file) : `s:${item.source ?? ''}`\n\n/** Display name — the File's name or the last path segment of a source URL. */\nexport const labelOf = (item: FileUploaderItem): string => {\n if (item.file) return item.file.name\n if (item.source) {\n if (/^(data|blob):/i.test(item.source)) return 'File'\n return item.source.split(/[?#]/)[0].split('/').pop() || 'File'\n }\n return 'File'\n}\n\n/**\n * Whether an item is an image — the only kind that gets the **crop** + **alt-text** editors (a video / PDF\n * / doc has nothing to crop or describe). A File is judged by its MIME `type`; a source URL by a known\n * image extension or a `data:image/…` URI, defaulting to `true` when it carries no recognizable extension\n * (the image-first assumption — e.g. extensionless CDN URLs).\n */\nexport const isImageItem = (item: FileUploaderItem): boolean => {\n if (item.file) return item.file.type.startsWith('image/')\n const src = item.source\n if (!src) return false\n if (/^data:image\\//i.test(src)) return true\n if (/^data:/i.test(src)) return false // a non-image data URI\n return (\n /\\.(png|jpe?g|gif|webp|avif|svg|bmp|ico|heic|heif)(?:[?#]|$)/i.test(src) ||\n !/\\.[a-z0-9]{1,8}(?:[?#]|$)/i.test(src)\n )\n}\n\n/** Whether an item is a video — rendered as a playable `<video controls>` preview instead of an `<img>`. */\nexport const isVideoItem = (item: FileUploaderItem): boolean => {\n if (item.file) return item.file.type.startsWith('video/')\n const src = item.source\n if (!src) return false\n return /^data:video\\//i.test(src) || /\\.(mp4|webm|ogg|ogv|mov|m4v|avi|mkv)(?:[?#]|$)/i.test(src)\n}\n\n/** Download an item — a File via a fresh object URL, a source URL via a download link. */\nconst triggerDownload = (item: FileUploaderItem) => {\n if (typeof document === 'undefined') return\n const a = document.createElement('a')\n a.style.display = 'none'\n if (item.file) {\n if (!canMakeObjectUrl()) return\n const url = URL.createObjectURL(item.file)\n a.href = url\n a.download = item.file.name\n document.body.appendChild(a)\n a.click()\n a.remove()\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n } else if (item.source) {\n a.href = item.source\n a.download = labelOf(item)\n a.target = '_blank'\n a.rel = 'noopener'\n document.body.appendChild(a)\n a.click()\n a.remove()\n }\n}\n\n/**\n * Split a name into the part that may truncate and a short trailing extension that should always stay\n * visible — so a long name middle-ellipses as `name….ext` instead of overflowing or losing the type.\n */\nexport const splitName = (name: string): { base: string; ext: string } => {\n const dot = name.lastIndexOf('.')\n // only peel off a real, short extension (\".png\", \".jpeg\") — not a dot buried in a long hash\n return dot > 0 && name.length - dot <= 7\n ? { base: name.slice(0, dot), ext: name.slice(dot) }\n : { base: name, ext: '' }\n}\n\n// ── one row ─────────────────────────────────────────────────────────────────────────────────────\n\ninterface RowProps {\n id: string\n item: FileUploaderItem\n preview: string | null\n sortable: boolean\n entering: boolean\n disabled?: boolean\n error?: string\n onRemove: () => void\n onCrop?: () => void\n onAltText?: () => void\n onDownload?: () => void\n onView?: () => void\n onPreviewError?: () => void\n}\n\nfunction Row({\n id,\n item,\n preview,\n sortable,\n entering,\n disabled,\n error,\n onRemove,\n onCrop,\n onAltText,\n onDownload,\n onView,\n onPreviewError,\n}: RowProps) {\n // the whole tile is the drag handle (no separate grip — matches the image-card visual)\n const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({\n id,\n disabled: !sortable,\n })\n const style: CSSProperties = {\n transform: CSS.Transform.toString(transform),\n transition,\n }\n const t = useT()\n const label = labelOf(item)\n const { base, ext } = splitName(label)\n // a remote preview shows a skeleton until it arrives; a local `blob:` preview is instant, so no flash\n const [mediaLoaded, setMediaLoaded] = useState(() => !preview || preview.startsWith('blob:'))\n const lastPreview = useRef(preview)\n if (lastPreview.current !== preview) {\n lastPreview.current = preview\n setMediaLoaded(!preview || preview.startsWith('blob:'))\n }\n const mediaRef = useRef<HTMLImageElement>(null)\n useEffect(() => {\n const img = mediaRef.current\n if (img?.complete && img.naturalWidth > 0) setMediaLoaded(true)\n }, [preview])\n const onMediaError = () => {\n setMediaLoaded(true)\n onPreviewError?.()\n }\n const meta = item.file ? formatBytes(item.file.size) : t('fileUploader.uploaded')\n const video = isVideoItem(item)\n\n const downloadBtn = onDownload ? (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.download', { name: label })}\n onClick={onDownload}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"DocumentDownload\" size=\"sm\" />\n </button>\n ) : null\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n className={clsx(\n styles.tile,\n sortable && styles.grabbable,\n entering && styles.entering,\n isDragging && styles.dragging,\n error && styles.tileError,\n )}\n {...attributes}\n {...listeners}\n >\n {preview && !mediaLoaded && (\n <Skeleton variant=\"rect\" width=\"100%\" height=\"100%\" className={styles.tileSkeleton} />\n )}\n {preview ? (\n video ? (\n <>\n {/* first-frame thumbnail (no controls) + a centred play badge so it reads as a video */}\n <video\n src={preview}\n className={styles.tileImg}\n muted\n playsInline\n preload=\"metadata\"\n draggable={false}\n onLoadedData={() => setMediaLoaded(true)}\n onError={onMediaError}\n />\n <span className={styles.tilePlay} aria-hidden=\"true\">\n <Icon name=\"Play\" size=\"lg\" />\n </span>\n </>\n ) : (\n <img\n ref={mediaRef}\n src={preview}\n alt=\"\"\n className={clsx(styles.tileImg, !mediaLoaded && styles.tileImgPending)}\n draggable={false}\n onLoad={() => setMediaLoaded(true)}\n onError={onMediaError}\n />\n )\n ) : (\n <span className={styles.tileFallback} aria-hidden=\"true\">\n <Icon name=\"Document\" size=\"lg\" />\n </span>\n )}\n\n {/* top scrim: name/meta on the left, the remove × pinned top-right */}\n <div className={styles.tileTop}>\n <span className={styles.tileText}>\n <span className={styles.name} title={label}>\n <span className={styles.nameBase}>{base}</span>\n {ext && <span className={styles.nameExt}>{ext}</span>}\n </span>\n <span className={clsx(styles.tileMeta, error && styles.metaError)}>{error ?? meta}</span>\n </span>\n {!disabled && (\n <button\n type=\"button\"\n className={styles.tileRemove}\n aria-label={t('fileUploader.remove', { name: label })}\n onClick={onRemove}\n onPointerDown={(e) => e.stopPropagation()} // don't start a drag from the remove button\n >\n <Icon name=\"Close\" size=\"sm\" />\n </button>\n )}\n </div>\n\n {/* bottom scrim: crop (Crop) + alt text (Text) + download on the left (crop/alt are image-only),\n the view (Eye) fullscreen-preview button pinned bottom-right */}\n {(onCrop || onAltText || onDownload || onView) && (\n <div className={styles.tileBottom}>\n {onCrop && (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.crop', { name: label })}\n onClick={onCrop}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Crop\" size=\"sm\" />\n </button>\n )}\n {onAltText && (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.editAlt', { name: label })}\n onClick={onAltText}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Text\" size=\"sm\" />\n </button>\n )}\n {downloadBtn}\n {onView && (\n <button\n type=\"button\"\n className={clsx(styles.tileAction, styles.tileActionEnd)}\n aria-label={t('fileUploader.preview', { name: label })}\n onClick={onView}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Eye\" size=\"sm\" />\n </button>\n )}\n </div>\n )}\n </div>\n )\n}\n\n// ── the field ───────────────────────────────────────────────────────────────────────────────────\n\n/**\n * A small, clean file field that **collects** files for the consumer to upload on save — it never\n * uploads itself. New picks carry their binary in `file`; already-uploaded files arrive with a\n * `source` URL. A soft dropzone panel sits above a grid of image cards (thumbnail/file-icon + name +\n * size, with overlaid remove + download buttons). `allowDrop` enables drag-from-OS (via\n * `react-dropzone`); `allowReorder` enables drag + keyboard reordering (via `@dnd-kit`); cards animate\n * in/out (via `@formkit/auto-animate`). Controlled (`value` + `onChange`) or uncontrolled\n * (`defaultValue`); binds to a `<Form>` by `name`. The forwarded ref points at the root.\n */\nexport const FileUploader = forwardRef<HTMLDivElement, FileUploaderProps>(function FileUploader(\n {\n multiple = false,\n allowDrop = true,\n allowReorder = true,\n allowDownload = true,\n allowPreview = true,\n allowAltText = true,\n altTextLocales,\n localizedAltText = true,\n allowDuplicates = false,\n disabled = false,\n accept,\n maxFiles,\n maxFileSize,\n itemInsertLocation = 'end',\n value,\n defaultValue,\n onChange,\n label,\n error,\n helperText,\n required = false,\n fullWidth = true,\n name,\n id: idProp,\n onBlur,\n className,\n style,\n ...props\n },\n ref,\n) {\n const reactId = useId()\n const id = idProp ?? reactId\n const helperId = `${id}-helper`\n\n const maxBytes = maxFileSize != null ? toBytes(maxFileSize) : undefined\n const [notice, setNotice] = useState<string | null>(null)\n // the rejection notice auto-dismisses so it doesn't linger forever\n useEffect(() => {\n if (!notice) return\n const timer = window.setTimeout(() => setNotice(null), 4000)\n return () => window.clearTimeout(timer)\n }, [notice])\n\n // Auto-bind to a surrounding <Form> by `name`. The value is a typed object/array, so read it RAW from\n // values[name] (never field().value, which String-coerces); error/touched come from field().\n const form = useFormContext()\n const isFormBound = Boolean(form && name)\n const bound = form && name ? form.field(name) : undefined\n\n const fallback: FileUploaderValue = multiple ? [] : null\n const externalValue: FileUploaderValue | undefined =\n value !== undefined\n ? value\n : isFormBound\n ? ((form!.values[name!] as FileUploaderValue | undefined) ?? fallback)\n : undefined\n const isControlled = externalValue !== undefined\n const [internal, setInternal] = useState<FileUploaderValue>(defaultValue ?? fallback)\n const current = isControlled ? externalValue! : internal\n const items: FileUploaderItem[] =\n current == null ? [] : Array.isArray(current) ? current : [current]\n\n const resolvedError = error ?? bound?.error ?? false\n const resolvedHelperText = helperText ?? bound?.helperText\n const shownHelper = notice ?? resolvedHelperText\n const helperIsError = Boolean(notice) || resolvedError\n\n const reorderEnabled = allowReorder && multiple && !disabled\n\n // Stable ids per item so a row keeps its identity (and focus) across reorders.\n const fileIds = useRef(new WeakMap<File, string>())\n const seed = useRef(0)\n const idOf = (item: FileUploaderItem, index: number): string => {\n if (item.file) {\n let id = fileIds.current.get(item.file)\n if (!id) {\n seed.current += 1\n id = `f${seed.current}`\n fileIds.current.set(item.file, id)\n }\n return id\n }\n return item.source ? `s:${item.source}` : `i:${index}`\n }\n const ids = items.map((item, i) => idOf(item, i))\n\n // Ids that have already animated in, so only genuinely new rows get the entrance animation — a reorder\n // re-inserts the moved/shifted nodes, which would otherwise restart the CSS drop-in on them.\n const enteredIds = useRef<Set<string>>(new Set())\n const enteringIds = new Set(ids.filter((id) => !enteredIds.current.has(id)))\n useEffect(() => {\n enteredIds.current = new Set(ids)\n })\n\n // Source URLs that failed to load as an image (so we fall back to the file icon).\n const [failedSources, setFailedSources] = useState<ReadonlySet<string>>(() => new Set())\n const markSourceFailed = (src: string) =>\n setFailedSources((prev) => (prev.has(src) ? prev : new Set(prev).add(src)))\n\n // Files whose object-URL preview failed to load (a corrupt/undecodable image) — same fallback.\n const [failedFiles, setFailedFiles] = useState<ReadonlySet<File>>(() => new Set())\n const markFileFailed = (file: File) =>\n setFailedFiles((prev) => (prev.has(file) ? prev : new Set(prev).add(file)))\n\n // Object URLs for image/video File previews, revoked when the File leaves the value / on unmount.\n const objectUrls = useRef(new Map<File, string>())\n const previewOf = (item: FileUploaderItem): string | null => {\n if (item.file) {\n const type = item.file.type\n if (\n (!type.startsWith('image/') && !type.startsWith('video/')) ||\n !canMakeObjectUrl() ||\n failedFiles.has(item.file)\n )\n return null\n let url = objectUrls.current.get(item.file)\n if (!url) {\n url = URL.createObjectURL(item.file)\n objectUrls.current.set(item.file, url)\n }\n return url\n }\n // an already-uploaded item is assumed to be a previewable image/video (image-first uploader); a\n // non-media URL just falls the row back to the file icon via the <img> onError handler\n if (item.source && !failedSources.has(item.source)) return item.source\n return null\n }\n // fullscreen preview (Eye) — snapshot the media so the lightbox is self-contained. Declared above\n // the object-URL cleanup effect below so that effect can spare the URL the lightbox is showing.\n const [preview, setPreview] = useState<{\n url: string\n isVideo: boolean\n isSvg: boolean\n name: string\n } | null>(null)\n useEffect(() => {\n const cache = objectUrls.current\n const liveFiles = new Set(items.map((it) => it.file).filter(Boolean) as File[])\n const liveSources = new Set(items.filter((it) => !it.file && it.source).map((it) => it.source!))\n for (const [file, url] of cache) {\n // don't revoke the URL the open lightbox is showing — a controlled value swap that removes the\n // item would otherwise break the media mid-display; the deferred revoke runs once it closes\n // (this effect re-runs on `preview` change) or on unmount\n if (!liveFiles.has(file) && url !== preview?.url) {\n URL.revokeObjectURL(url)\n cache.delete(file)\n }\n }\n setFailedSources((prev) => {\n if (prev.size === 0) return prev\n const next = new Set([...prev].filter((s) => liveSources.has(s)))\n return next.size === prev.size ? prev : next\n })\n }, [current, preview]) // eslint-disable-line react-hooks/exhaustive-deps -- `current` is the value identity\n useEffect(() => {\n const cache = objectUrls.current\n return () => {\n for (const url of cache.values()) URL.revokeObjectURL(url)\n cache.clear()\n }\n }, [])\n\n const reindex = (arr: FileUploaderItem[]): FileUploaderItem[] =>\n arr.map((it, i) => (it.sortIndex === i ? it : { ...it, sortIndex: i }))\n\n const commit = (next: FileUploaderItem[]) => {\n const ordered = reindex(next)\n const out: FileUploaderValue = multiple ? ordered : (ordered[0] ?? null)\n if (!isControlled) setInternal(out)\n if (isFormBound) form!.setValue(name!, out)\n onChange?.(out)\n }\n\n // mark the bound form field touched (the impl ignores the event — it just flips the touched flag)\n const markTouched = () => bound?.onBlur({} as FocusEvent<HTMLInputElement>)\n\n const t = useT()\n // ── edit dialogs (separate Crop and Alt-text modals, opened from a card's two buttons) ────────────\n const configLocales = useLocales()\n const altLocales = altTextLocales ?? configLocales\n // per-locale (default): one field per locale (falling back to a single field if none configured);\n // non-localized: always a single field, keyed under '' (the value is a plain string)\n const editLocales = localizedAltText && altLocales.length > 0 ? altLocales : [{ code: '' }]\n // track the edited item by its STABLE id (not its index) so an external value change while a dialog is\n // open — reorder/remove/refetch — can't retarget the save onto the wrong item\n const [editId, setEditId] = useState<string | null>(null)\n const [editMode, setEditMode] = useState<'crop' | 'altText'>('altText')\n const editPos = editId != null ? ids.indexOf(editId) : -1\n const editingItem = editPos !== -1 ? items[editPos] : null\n const openCropEditor = (index: number) => {\n setEditMode('crop')\n setEditId(ids[index] ?? null)\n }\n const openAltEditor = (index: number) => {\n setEditMode('altText')\n setEditId(ids[index] ?? null)\n }\n const closeEditor = () => setEditId(null)\n\n const openPreview = (item: FileUploaderItem) => {\n const url = previewOf(item)\n if (!url) return\n // SVGs need an explicit box in the lightbox (they often lack an intrinsic pixel size)\n const isSvg = item.file\n ? item.file.type === 'image/svg+xml'\n : /^data:image\\/svg/i.test(item.source ?? '') || /\\.svg(?:[?#]|$)/i.test(item.source ?? '')\n setPreview({ url, isVideo: isVideoItem(item), isSvg, name: labelOf(item) })\n }\n // seed the alt-text dialog's draft from the item's current value (record vs single string)\n const editInitialDraft: Record<string, string> = editingItem\n ? localizedAltText\n ? editingItem.altText && typeof editingItem.altText === 'object'\n ? { ...editingItem.altText }\n : {}\n : { '': typeof editingItem.altText === 'string' ? editingItem.altText : '' }\n : {}\n const saveEdit = ({ draft, croppedFile }: EditDialogResult) => {\n if (editPos === -1) return closeEditor() // the item went away under us — bail\n commit(\n items.map((it, i) => {\n if (ids[i] !== editId) return it\n const next: FileUploaderItem = { ...it }\n // alt-text dialog → rebuild altText from the draft (localized record / single string)\n if (draft !== undefined) {\n if (localizedAltText) {\n // prune empty/whitespace entries so the model isn't littered with blank locales\n const cleaned = Object.fromEntries(\n Object.entries(draft)\n .map(([code, text]) => [code, text.trim()] as [string, string])\n .filter(([, text]) => text !== ''),\n )\n next.altText = Object.keys(cleaned).length > 0 ? cleaned : undefined\n } else {\n next.altText = (draft[''] ?? '').trim() || undefined\n }\n }\n // crop dialog → replace the image with the cropped File (native-res, lossless); a source item\n // becomes a fresh pick (the cropped version uploads on save)\n if (croppedFile) {\n next.file = croppedFile\n next.source = ''\n }\n return next\n }),\n )\n closeEditor()\n }\n\n const addFiles = (accepted: File[], rejections: FileRejection[] = []) => {\n // Hard rejections (the file is invalid: wrong type, or over `maxFileSize` — react-dropzone rejects\n // both, so they never reach `accepted`) surface as a Toast error and are not added.\n const wrongType = rejections.filter((r) => r.errors.some((e) => e.code === 'file-invalid-type'))\n const tooLarge = rejections.filter((r) => r.errors.some((e) => e.code === 'file-too-large'))\n if (wrongType.length > 0)\n toast.error(\n wrongType.length === 1\n ? t('fileUploader.wrongTypeOne', { name: wrongType[0].file.name })\n : t('fileUploader.wrongTypeMany', { count: wrongType.length }),\n )\n if (tooLarge.length > 0 && maxBytes != null)\n toast.error(\n tooLarge.length === 1\n ? t('fileUploader.tooLargeOne', {\n name: tooLarge[0].file.name,\n size: formatBytes(maxBytes),\n })\n : t('fileUploader.tooLargeMany', { count: tooLarge.length, size: formatBytes(maxBytes) }),\n )\n\n // Soft notices (the file is valid, just not added now) stay in the inline helper slot + auto-dismiss.\n const reasons: string[] = []\n let taken = accepted\n // drop files already present (same content) + intra-batch dupes, unless explicitly allowed\n if (multiple && !allowDuplicates) {\n const seen = new Set(items.map(itemKey))\n const unique: File[] = []\n for (const file of taken) {\n const key = fileKey(file)\n if (seen.has(key)) continue\n seen.add(key)\n unique.push(file)\n }\n if (unique.length < taken.length) reasons.push(t('fileUploader.duplicate'))\n taken = unique\n }\n if (multiple && maxFiles != null) {\n const room = Math.max(0, maxFiles - items.length)\n if (taken.length > room) {\n taken = taken.slice(0, room)\n reasons.push(\n maxFiles === 1\n ? t('fileUploader.hintUpToOne', { count: maxFiles })\n : t('fileUploader.hintUpToMany', { count: maxFiles }),\n )\n }\n }\n\n setNotice(reasons.length > 0 ? reasons.join(' · ') : null)\n if (taken.length === 0) return\n const picked = taken.map<FileUploaderItem>((file) => ({ file, source: '', sortIndex: 0 }))\n if (!multiple) {\n commit([picked[0]])\n return\n }\n commit(itemInsertLocation === 'start' ? [...picked, ...items] : [...items, ...picked])\n }\n const removeAt = (index: number) => {\n setNotice(null)\n commit(items.filter((_, i) => i !== index))\n // removing is an explicit interaction — mark touched so an emptied required field reveals its error\n markTouched()\n }\n\n // auto-animate handles add / remove / shift on the list; it's paused during a dnd-kit drag so the two\n // don't both animate the reorder (dnd-kit owns the drag visuals, auto-animate owns enter/exit).\n const [listRef, enableAnimations] = useAutoAnimate(listAnimation)\n const reEnableAnimations = () => {\n if (typeof requestAnimationFrame === 'function')\n requestAnimationFrame(() => enableAnimations(true))\n else enableAnimations(true)\n }\n const handleDragStart = () => enableAnimations(false)\n const handleDragCancel = () => reEnableAnimations()\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event\n if (over && active.id !== over.id) {\n const from = ids.indexOf(String(active.id))\n const to = ids.indexOf(String(over.id))\n if (from !== -1 && to !== -1) commit(arrayMove(items, from, to))\n }\n reEnableAnimations() // after the reorder DOM settles, so the move isn't double-animated\n }\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),\n )\n\n // opening the native file dialog blurs the window, which would otherwise mark the field touched and flash\n // a \"required\" error before the user picks anything; suppress that one blur and only mark touched when the\n // dialog is *canceled* with no selection (the real \"engaged, added nothing\" signal)\n const fileDialogOpen = useRef(false)\n\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\n multiple,\n accept,\n // reject oversized picks here so they never get added; the rejection surfaces as a Toast in addFiles\n maxSize: maxBytes,\n disabled,\n noKeyboard: false,\n noDrag: !allowDrop,\n onFileDialogOpen: () => {\n fileDialogOpen.current = true\n },\n onFileDialogCancel: () => {\n fileDialogOpen.current = false\n markTouched()\n },\n onDrop: (accepted, rejections) => {\n fileDialogOpen.current = false\n addFiles(accepted, rejections)\n },\n })\n\n const showDropzone = multiple || items.length === 0\n\n // static constraint hint shown inside the dropzone (e.g. \"Up to 5 files · Max 5 MB each\")\n const hintParts: string[] = []\n if (multiple && maxFiles != null)\n hintParts.push(\n maxFiles === 1\n ? t('fileUploader.hintUpToOne', { count: maxFiles })\n : t('fileUploader.hintUpToMany', { count: maxFiles }),\n )\n if (maxBytes != null) hintParts.push(t('fileUploader.hintMax', { size: formatBytes(maxBytes) }))\n const hint = hintParts.join(' · ')\n\n const prompt: ReactNode = allowDrop ? (\n <>\n <span className={styles.accent}>{t('fileUploader.choose')}</span>{' '}\n {t('fileUploader.dropSuffix')}\n </>\n ) : (\n <span className={styles.accent}>{t('fileUploader.choose')}</span>\n )\n\n // mark the field touched once focus leaves the whole widget (so blurThenLive errors reveal on blur)\n const onRootBlur = (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event)\n if (event.currentTarget.contains(event.relatedTarget as Node | null)) return\n // opening the alt-text editor moves focus into the body-portaled Modal (outside the root); that's not\n // focus leaving the widget, so don't mark touched (mirrors Select's portaled-popover guard)\n if (editId != null) return\n // the native file-dialog blur isn't \"leaving the widget\" either — consume it (touched is set instead on\n // dialog cancel); only a genuine blur-away marks touched\n if (fileDialogOpen.current) {\n fileDialogOpen.current = false\n return\n }\n markTouched()\n }\n\n return (\n <div\n ref={ref}\n id={id}\n className={clsx(\n styles.root,\n fullWidth && styles.fullWidth,\n resolvedError && styles.error,\n disabled && styles.disabled,\n className,\n )}\n style={style}\n aria-invalid={resolvedError || undefined}\n aria-describedby={shownHelper != null ? helperId : undefined}\n onBlur={onRootBlur}\n {...props}\n // name + tabIndex are load-bearing for the form's scroll-to-error → spread last so props can't clobber\n {...(name ? { name, tabIndex: -1 } : {})}\n >\n {label != null && (\n <label className={fieldStyles.label}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {label}\n </Typography>\n {required && (\n <span className={fieldStyles.required} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n {showDropzone && (\n <div\n {...getRootProps({ className: clsx(styles.dropzone, isDragActive && styles.dropping) })}\n >\n <input {...getInputProps()} />\n <span className={styles.dropIcon} aria-hidden=\"true\">\n <Icon name=\"DocumentUpload\" size=\"lg\" />\n </span>\n <span className={styles.dropText}>\n <span className={styles.prompt}>{prompt}</span>\n {hint && <span className={styles.hint}>{hint}</span>}\n </span>\n </div>\n )}\n\n {/* always rendered (even when empty) so auto-animate can animate the last card out on removal */}\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragStart={reorderEnabled ? handleDragStart : undefined}\n onDragEnd={reorderEnabled ? handleDragEnd : undefined}\n onDragCancel={reorderEnabled ? handleDragCancel : undefined}\n >\n <SortableContext items={ids} strategy={rectSortingStrategy}>\n <div\n ref={listRef}\n className={clsx(styles.list, showDropzone && items.length > 0 && styles.populated)}\n >\n {items.map((item, index) => (\n <Row\n key={ids[index]}\n id={ids[index]}\n item={item}\n preview={previewOf(item)}\n sortable={reorderEnabled && items.length > 1}\n entering={enteringIds.has(ids[index])}\n disabled={disabled}\n error={\n item.file && maxBytes != null && item.file.size > maxBytes\n ? t('fileUploader.exceedsLimit', { size: formatBytes(maxBytes) })\n : undefined\n }\n onRemove={() => removeAt(index)}\n // crop + alt text are image-only — a video / PDF / doc has nothing to crop or describe\n onCrop={\n allowAltText && !disabled && isImageItem(item)\n ? () => openCropEditor(index)\n : undefined\n }\n onAltText={\n allowAltText && !disabled && isImageItem(item)\n ? () => openAltEditor(index)\n : undefined\n }\n onDownload={allowDownload && !disabled ? () => triggerDownload(item) : undefined}\n // fullscreen preview — image + video only (a PDF / doc has nothing to preview)\n onView={\n allowPreview &&\n !disabled &&\n previewOf(item) != null &&\n (isImageItem(item) || isVideoItem(item))\n ? () => openPreview(item)\n : undefined\n }\n onPreviewError={\n item.file\n ? () => markFileFailed(item.file!)\n : item.source\n ? () => markSourceFailed(item.source!)\n : undefined\n }\n />\n ))}\n </div>\n </SortableContext>\n </DndContext>\n\n {shownHelper != null && (\n <Typography\n as=\"span\"\n id={helperId}\n variant=\"bodySmall\"\n color={helperIsError ? 'error' : 'muted'}\n className={fieldStyles.helper}\n role=\"status\"\n aria-live=\"polite\"\n >\n {shownHelper}\n </Typography>\n )}\n\n {editingItem && (\n <FileUploaderEditDialog\n key={`${editId}:${editMode}`}\n mode={editMode}\n name={labelOf(editingItem)}\n imageUrl={previewOf(editingItem)}\n mimeType={editingItem.file?.type || 'image/png'}\n editLocales={editLocales}\n initialDraft={editInitialDraft}\n onClose={closeEditor}\n onSave={saveEdit}\n />\n )}\n\n {preview && (\n <FileUploaderPreview\n url={preview.url}\n isVideo={preview.isVideo}\n isSvg={preview.isSvg}\n name={preview.name}\n onClose={() => setPreview(null)}\n />\n )}\n </div>\n )\n})\n"],"names":["FileUploaderEditDialog","mode","name","imageUrl","mimeType","editLocales","initialDraft","onClose","onSave","t","useT","imgRef","useRef","crop","setCrop","useState","naturalCrop","setNaturalCrop","naturalSize","setNaturalSize","draft","setDraft","cropError","setCropError","busy","setBusy","onCropChange","px","percent","img","sx","sy","buildCroppedFile","image","canvas","ctx","blob","resolve","handleSave","croppedFile","jsx","Modal","jsxs","Fragment","Button","styles","Typography","ReactCrop","e","l","TextField","d","FileUploaderPreview","url","isVideo","isSvg","Overlay","Icon","clsx","canMakeObjectUrl","ANIM_MS","listAnimation","el","action","oldCoords","newCoords","keyframes","duration","dx","dy","formatBytes","bytes","units","value","i","toBytes","size","match","fileKey","file","itemKey","item","labelOf","isImageItem","src","isVideoItem","triggerDownload","a","splitName","dot","Row","id","preview","sortable","entering","disabled","error","onRemove","onCrop","onAltText","onDownload","onView","onPreviewError","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","label","base","ext","mediaLoaded","setMediaLoaded","lastPreview","mediaRef","useEffect","onMediaError","meta","video","downloadBtn","Skeleton","FileUploader","forwardRef","multiple","allowDrop","allowReorder","allowDownload","allowPreview","allowAltText","altTextLocales","localizedAltText","allowDuplicates","accept","maxFiles","maxFileSize","itemInsertLocation","defaultValue","onChange","helperText","required","fullWidth","idProp","onBlur","className","props","ref","reactId","useId","helperId","maxBytes","notice","setNotice","timer","form","useFormContext","isFormBound","bound","fallback","externalValue","isControlled","internal","setInternal","current","items","resolvedError","resolvedHelperText","shownHelper","helperIsError","reorderEnabled","fileIds","seed","idOf","index","ids","enteredIds","enteringIds","failedSources","setFailedSources","markSourceFailed","prev","failedFiles","setFailedFiles","markFileFailed","objectUrls","previewOf","type","setPreview","cache","liveFiles","it","liveSources","next","s","reindex","arr","commit","ordered","out","markTouched","configLocales","useLocales","altLocales","editId","setEditId","editMode","setEditMode","editPos","editingItem","openCropEditor","openAltEditor","closeEditor","openPreview","editInitialDraft","saveEdit","cleaned","code","text","addFiles","accepted","rejections","wrongType","r","tooLarge","toast","reasons","taken","seen","unique","key","room","picked","removeAt","_","listRef","enableAnimations","useAutoAnimate","reEnableAnimations","handleDragStart","handleDragCancel","handleDragEnd","event","active","over","from","to","arrayMove","sensors","useSensors","useSensor","PointerSensor","KeyboardSensor","sortableKeyboardCoordinates","fileDialogOpen","getRootProps","getInputProps","isDragActive","useDropzone","showDropzone","hintParts","hint","prompt","onRootBlur","fieldStyles","DndContext","closestCenter","SortableContext","rectSortingStrategy","_a"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"FileUploader-FMVbj7rz.cjs","sources":["../src/components/FileUploader/FileUploaderEditDialog.tsx","../src/components/FileUploader/FileUploaderPreview.tsx","../src/components/FileUploader/FileUploader.tsx"],"sourcesContent":["import { useRef, useState, type ChangeEvent } from 'react'\nimport ReactCrop, { type Crop, type PercentCrop, type PixelCrop } from 'react-image-crop'\nimport 'react-image-crop/dist/ReactCrop.css'\nimport { useT, type LocaleConfig } from '../../theme'\nimport { Button } from '../Button'\nimport { Modal } from '../Modal'\nimport { TextField } from '../TextField'\nimport { Typography } from '../Typography'\nimport styles from './FileUploaderEditDialog.module.css'\n\n/** What a dialog hands back on Save: the alt-text draft (alt-text mode) or a cropped File (crop mode). */\nexport interface EditDialogResult {\n /** Alt-text values keyed by locale code (or the single `''` key in non-localized mode). */\n draft?: Record<string, string>\n /** A freshly-cropped File (native-resolution, lossless). */\n croppedFile?: File\n}\n\nexport interface FileUploaderEditDialogProps {\n /** Which editor to show — the **crop** stage or the **alt text** fields (each is its own modal). */\n mode: 'crop' | 'altText'\n /** Display name (modal description + the cropped File's name). */\n name: string\n /** Image URL for crop mode (object URL for a File, or the source URL). */\n imageUrl: string | null\n /** MIME type for the cropped output — keeps the original (PNG ⇒ lossless). */\n mimeType: string\n /** Locales for the alt-text editor (one field each); a single `{ code: '' }` ⇒ one plain field. */\n editLocales: LocaleConfig[]\n /** The alt-text draft to seed from the item's current value. */\n initialDraft: Record<string, string>\n /** Close without saving. */\n onClose: () => void\n /** Commit the result (alt-text draft or cropped File). */\n onSave: (result: EditDialogResult) => void\n}\n\n/** The crop selection in the image's NATIVE pixels — what actually gets exported (no resample / resize). */\ninterface NaturalCrop {\n x: number\n y: number\n width: number\n height: number\n}\n\n/**\n * The FileUploader per-item edit modal. Two separate modes (each opened from its own card button):\n * **`crop`** — a draggable selection over the image, exported at the image's native resolution (lossless,\n * dimensions shown live); **`altText`** — one `TextField` per locale (stacked, no tabs). Built on the\n * library's `Modal` + `TextField` and **`react-image-crop`** (an optional peer). Internal — not exported.\n */\nexport function FileUploaderEditDialog({\n mode,\n name,\n imageUrl,\n mimeType,\n editLocales,\n initialDraft,\n onClose,\n onSave,\n}: FileUploaderEditDialogProps) {\n const t = useT()\n const imgRef = useRef<HTMLImageElement>(null)\n const [crop, setCrop] = useState<Crop>()\n // store the crop in NATIVE coords (computed on every drag) so the export never depends on display size\n const [naturalCrop, setNaturalCrop] = useState<NaturalCrop | null>(null)\n // the image's intrinsic size (captured on load) — shown as the readout until a crop is selected\n const [naturalSize, setNaturalSize] = useState<{ w: number; h: number } | null>(null)\n const [draft, setDraft] = useState<Record<string, string>>(initialDraft)\n const [cropError, setCropError] = useState<string | null>(null)\n const [busy, setBusy] = useState(false)\n\n const onCropChange = (px: PixelCrop, percent: PercentCrop) => {\n setCrop(percent)\n const img = imgRef.current\n if (img && img.width > 0 && px.width >= 1 && px.height >= 1) {\n const sx = img.naturalWidth / img.width\n const sy = img.naturalHeight / img.height\n setNaturalCrop({\n x: Math.round(px.x * sx),\n y: Math.round(px.y * sy),\n width: Math.round(px.width * sx),\n height: Math.round(px.height * sy),\n })\n } else {\n setNaturalCrop(null)\n }\n }\n\n // Crop at native resolution: copy the selected region 1:1 (no resample → no quality loss, no resize).\n const buildCroppedFile = async (): Promise<File | undefined> => {\n const image = imgRef.current\n if (!image || !naturalCrop || naturalCrop.width < 1 || naturalCrop.height < 1) return undefined\n const canvas = document.createElement('canvas')\n canvas.width = naturalCrop.width\n canvas.height = naturalCrop.height\n const ctx = canvas.getContext('2d')\n if (!ctx) return undefined\n ctx.imageSmoothingEnabled = false // 1:1 native-pixel copy — no resampling\n ctx.drawImage(\n image,\n naturalCrop.x,\n naturalCrop.y,\n naturalCrop.width,\n naturalCrop.height,\n 0,\n 0,\n naturalCrop.width,\n naturalCrop.height,\n )\n // toBlob throws on a cross-origin-tainted canvas — let handleSave catch it\n const blob = await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, mimeType, 1))\n // a null blob is a failed export too (not just tainted) — throw so it surfaces as a crop error\n // instead of silently resolving to `undefined` and discarding the crop with no feedback\n if (!blob) throw new Error('canvas.toBlob returned null')\n return new File([blob], name, { type: mimeType, lastModified: Date.now() })\n }\n\n const handleSave = async () => {\n if (mode === 'altText') {\n onSave({ draft })\n return\n }\n setBusy(true)\n try {\n const croppedFile =\n naturalCrop && naturalCrop.width >= 1 && naturalCrop.height >= 1\n ? await buildCroppedFile()\n : undefined\n onSave({ croppedFile }) // parent commits + closes (this dialog unmounts)\n } catch {\n setCropError(t('fileUploader.cropError'))\n setBusy(false)\n }\n }\n\n return (\n <Modal\n open\n onClose={onClose}\n size={mode === 'crop' ? 'lg' : 'sm'}\n icon={mode === 'crop' ? 'Crop' : 'Text'}\n title={mode === 'crop' ? t('fileUploader.cropTitle') : t('fileUploader.altTitle')}\n description={name}\n footer={\n <>\n <Button variant=\"text\" color=\"accent\" size=\"sm\" onClick={onClose} disabled={busy}>\n {t('common.cancel')}\n </Button>\n <Button size=\"sm\" onClick={handleSave} loading={busy}>\n {t('common.save')}\n </Button>\n </>\n }\n >\n {mode === 'crop' ? (\n <div className={styles.cropSection}>\n <div className={styles.cropHead}>\n <Typography variant=\"bodySmall\" color=\"muted\">\n {t('fileUploader.cropHint')}\n </Typography>\n <Typography variant=\"bodySmall\" color={naturalCrop ? 'text' : 'muted'}>\n {naturalCrop\n ? `${naturalCrop.width} × ${naturalCrop.height} px`\n : naturalSize\n ? `${naturalSize.w} × ${naturalSize.h} px`\n : ''}\n </Typography>\n </div>\n <div className={styles.cropStage}>\n <ReactCrop crop={crop} onChange={onCropChange} className={styles.crop}>\n <img\n ref={imgRef}\n src={imageUrl ?? undefined}\n alt=\"\"\n className={styles.cropImg}\n onLoad={(e) =>\n setNaturalSize({\n w: e.currentTarget.naturalWidth,\n h: e.currentTarget.naturalHeight,\n })\n }\n />\n </ReactCrop>\n </div>\n {cropError && (\n <Typography variant=\"bodySmall\" color=\"error\">\n {cropError}\n </Typography>\n )}\n </div>\n ) : (\n <div className={styles.altFields}>\n {editLocales.map((l) => (\n <TextField\n key={l.code}\n label={l.label ?? (l.code || t('fileUploader.altTitle'))}\n placeholder={t('fileUploader.altPlaceholder')}\n value={draft[l.code] ?? ''}\n onChange={(e: ChangeEvent<HTMLInputElement>) =>\n setDraft((d) => ({ ...d, [l.code]: e.target.value }))\n }\n />\n ))}\n </div>\n )}\n </Modal>\n )\n}\n","import { clsx } from 'clsx'\nimport { useT } from '../../theme'\nimport { Icon } from '../Icon'\nimport { Overlay } from '../Overlay/Overlay'\nimport styles from './FileUploaderPreview.module.css'\n\nexport interface FileUploaderPreviewProps {\n /** The media URL (a File's object URL or a source URL). */\n url: string\n /** Render a `<video controls>` instead of an `<img>`. */\n isVideo: boolean\n /**\n * The image is an SVG — a vector has no reliable pixel size (a viewBox-only icon shows tiny, a sizeless\n * one collapses to nothing), so when set the image is given a floored box (`min-*` + `object-fit:\n * contain`): a small SVG scales up to a visible minimum while a larger one keeps its real size.\n */\n isSvg?: boolean\n /** Accessible name / image alt. */\n name: string\n /** Dismiss the overlay. */\n onClose: () => void\n}\n\n/**\n * A fullscreen media lightbox for the FileUploader — a dark backdrop with the image (or a `<video>` with\n * controls) centered. Built on the shared `<Overlay>` (portal to `<body>`, scroll-lock, fade-in, backdrop\n * / Escape dismissal); a darker scrim (`dim={0.85}`) than a Modal since media reads over black. Opened\n * from a card's **Eye** button (image + video items only). Internal — not exported.\n */\nexport function FileUploaderPreview({\n url,\n isVideo,\n isSvg,\n name,\n onClose,\n}: FileUploaderPreviewProps) {\n const t = useT()\n return (\n <Overlay\n open\n onClose={onClose}\n dim={0.85}\n className={styles.backdrop}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={t('fileUploader.preview', { name })}\n >\n <button\n type=\"button\"\n className={styles.close}\n aria-label={t('fileUploader.closePreview')}\n onClick={onClose}\n autoFocus\n >\n <Icon name=\"Close\" size=\"lg\" />\n </button>\n {isVideo ? (\n <video src={url} className={styles.media} controls playsInline />\n ) : (\n // an SVG's natural size is unreliable, so it always gets the floored box (`.mediaSvg`); a raster\n // keeps its natural size, only capped to the viewport (`.media`)\n <img src={url} alt={name} className={clsx(styles.media, isSvg && styles.mediaSvg)} />\n )}\n </Overlay>\n )\n}\n","import {\n forwardRef,\n useEffect,\n useId,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type HTMLAttributes,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport {\n DndContext,\n KeyboardSensor,\n PointerSensor,\n closestCenter,\n useSensor,\n useSensors,\n type DragEndEvent,\n} from '@dnd-kit/core'\nimport {\n SortableContext,\n arrayMove,\n useSortable,\n sortableKeyboardCoordinates,\n rectSortingStrategy,\n} from '@dnd-kit/sortable'\nimport { CSS } from '@dnd-kit/utilities'\nimport type { AutoAnimationPlugin } from '@formkit/auto-animate'\nimport { useAutoAnimate } from '@formkit/auto-animate/react'\nimport { useDropzone, type Accept, type FileRejection } from 'react-dropzone'\nimport { useFormContext } from '../../form/formContext'\nimport { useLocales, useT, type LocaleConfig } from '../../theme'\nimport { toast } from '../Toast/toastStore'\nimport { Icon } from '../Icon'\nimport { Skeleton } from '../Skeleton'\nimport { Typography } from '../Typography'\nimport { FileUploaderEditDialog, type EditDialogResult } from './FileUploaderEditDialog'\nimport { FileUploaderPreview } from './FileUploaderPreview'\n// shared field chrome (wrapper / label / required / helper) — the Slider precedent\nimport fieldStyles from '../TextField/TextField.module.css'\nimport styles from './FileUploader.module.css'\n\n/**\n * A single file entry. A freshly-picked file carries its binary in `file`; an already-uploaded one\n * (a backend response, edit mode) carries only its URL in `source` — then `file` is absent.\n */\nexport interface FileUploaderItem {\n /** The picked binary — present for a newly-selected file, absent for an already-uploaded one. */\n file?: File\n /** Server URL of an already-uploaded file (edit mode); `''` for a fresh pick. */\n source?: string\n /** Position in the list (0-based) — kept in sync with the visual order on every change. */\n sortIndex: number\n /**\n * Optional alt text, edited per card via the `allowAltText` modal. **Per-locale by default** —\n * `Record<localeCode, string>` (e.g. `{ 'en-US': 'A red car', 'ka-GE': '…' }`); with\n * **`localizedAltText={false}`** it's a single **`string`**. Absent until something is typed.\n */\n altText?: Record<string, string> | string\n}\n\n/** Single mode → one item (or `null`); `multiple` mode → an array. */\nexport type FileUploaderValue = FileUploaderItem | FileUploaderItem[] | null\n\nexport interface FileUploaderProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue'\n> {\n /** Accept more than one file — the value becomes an array. Defaults to `false`. */\n multiple?: boolean\n /** Allow dropping files onto the dropzone (drag from the OS). Defaults to `true`. */\n allowDrop?: boolean\n /** Allow drag + keyboard reordering of the rows (only meaningful with `multiple`). Defaults to `true`. */\n allowReorder?: boolean\n /** Show a download button on each item (downloads the File / source). Defaults to `true`. */\n allowDownload?: boolean\n /**\n * Show a per-card **preview** (Eye) button — opens a fullscreen lightbox of the image / video. Defaults\n * to `true`. Only rendered for **image + video** items (a PDF / doc has nothing to preview).\n */\n allowPreview?: boolean\n /**\n * Show a per-card **edit** button that opens a modal for editing the item's `altText`. Defaults to\n * `true` — pass `false` to hide it. The modal renders one input per content locale (a tab strip when\n * there are several), so the edited value lands in `item.altText` keyed by locale code (or a single\n * string with `localizedAltText={false}`).\n */\n allowAltText?: boolean\n /**\n * Locales for the `allowAltText` editor (one input/tab each). Defaults to the app's `ConfigProvider`\n * locales (`useLocales()`); pass this to override — mirrors `<TranslatedFields locales>`. Ignored when\n * `localizedAltText` is `false`.\n */\n altTextLocales?: LocaleConfig[]\n /**\n * Whether the `allowAltText` editor is **per-locale**. Defaults to `true` — `altText` is a\n * `Record<localeCode, string>` with one input/tab per locale. Pass **`false`** for a single plain input\n * (no locales), so `altText` is just a **`string`**.\n */\n localizedAltText?: boolean\n /**\n * Allow the same file to be added more than once. By default (`false`) a pick that matches an\n * already-present item by content (a File by name + size + last-modified, a source by URL) is skipped\n * and a notice is shown. Only meaningful with `multiple` (single mode replaces, so it can't stack).\n */\n allowDuplicates?: boolean\n /** Disables the whole control — no adding, removing, reordering, or downloading; dimmed + inert. */\n disabled?: boolean\n /**\n * Accepted file types (react-dropzone's format: a MIME type → file-extensions map) — restricts the file\n * picker and rejects non-matching picks/drops (a rejection raises a `toast.error`). E.g. `{ 'image/*': [] }`\n * or `{ 'image/*': [], 'application/pdf': ['.pdf'] }`. Omit to accept any type.\n */\n accept?: Accept\n /** Maximum number of files (only meaningful with `multiple`). Picks beyond it are rejected with a notice. */\n maxFiles?: number\n /**\n * Maximum size per file — a bytes `number`, or a human string like `\"5MB\"` / `\"500KB\"`. A picked file\n * over the limit is **rejected** (not added) and raises a **`toast.error`** (so a `<Toaster>` — mounted\n * by `RootLayout` by default — must be present to see it). A file supplied via `value`/`defaultValue`\n * that exceeds the limit is still rendered but flagged in an error state (red ring + `\"Exceeds … limit\"`).\n */\n maxFileSize?: number | string\n /** Where a newly added file lands in the list (`multiple` only): `'start'` (top) or `'end'` (bottom). Defaults to `'end'`. */\n itemInsertLocation?: 'start' | 'end'\n /** Controlled value — one item (or `null`) when single, an array when `multiple`. */\n value?: FileUploaderValue\n /** Initial value for uncontrolled use. */\n defaultValue?: FileUploaderValue\n /** Fires with the next value whenever files are added, removed, or reordered. */\n onChange?: (value: FileUploaderValue) => void\n /** Label rendered above the control. */\n label?: ReactNode\n /** Marks the field invalid: red dropzone border + the `helperText` in the error color. */\n error?: boolean\n /** Helper / validation text under the control. Adopts the error color while `error`. */\n helperText?: ReactNode\n /** Adds a red asterisk after the label. */\n required?: boolean\n /** Stretches the control to fill its container width. Defaults to `true`. */\n fullWidth?: boolean\n /**\n * Binds the field to a surrounding `<Form>` — the form value is the item / array, validated with e.g.\n * `z.array(fileItemSchema).min(1)`. Reads the raw `form.values[name]` and writes via `setValue`;\n * error/touched come from the form, and the form's scroll-to-error can focus the field.\n */\n name?: string\n}\n\nconst canMakeObjectUrl = (): boolean =>\n typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function'\n\n// auto-animate plugin: the ENTER (add) is handled by a CSS mount animation on `.row` (a reliable, visible\n// drop-in), so here `add` is a no-op to avoid double-animating; auto-animate still smoothly animates the\n// `remove` (lift + fade) and the `remain` reflow (rows sliding up to fill a gap).\nconst ANIM_MS = 300\nconst listAnimation: AutoAnimationPlugin = (el, action, oldCoords, newCoords) => {\n let keyframes: Keyframe[] = [{}, {}]\n let duration = ANIM_MS\n if (action === 'add') {\n duration = 0\n } else if (action === 'remove') {\n keyframes = [\n { opacity: 1, transform: 'translateY(0)' },\n { opacity: 0, transform: 'translateY(-8px)' },\n ]\n } else if (oldCoords && newCoords) {\n const dx = oldCoords.left - newCoords.left\n const dy = oldCoords.top - newCoords.top\n keyframes = [{ transform: `translate(${dx}px, ${dy}px)` }, { transform: 'translate(0, 0)' }]\n }\n return new KeyframeEffect(el, keyframes, { duration, easing: 'ease-out' })\n}\n\n/** Human-readable byte size, e.g. `2.4 MB`. (Exported for unit tests; not part of the public surface.) */\nexport const formatBytes = (bytes: number): string => {\n if (bytes < 1024) return `${bytes} B`\n const units = ['KB', 'MB', 'GB', 'TB']\n let value = bytes / 1024\n let i = 0\n while (value >= 1024 && i < units.length - 1) {\n value /= 1024\n i += 1\n }\n return `${value.toFixed(value < 10 ? 1 : 0)} ${units[i]}`\n}\n\n/** Coerce a `maxFileSize` (a bytes number, or a human string like `\"5MB\"` / `\"500 KB\"`) to bytes. */\nexport const toBytes = (size: number | string): number | undefined => {\n if (typeof size === 'number') return size\n const match = /^\\s*([\\d.]+)\\s*(b|kb|mb|gb|tb)?\\s*$/i.exec(size)\n if (!match) return undefined\n const units: Record<string, number> = {\n b: 1,\n kb: 1024,\n mb: 1024 ** 2,\n gb: 1024 ** 3,\n tb: 1024 ** 4,\n }\n return parseFloat(match[1]) * (units[(match[2] || 'b').toLowerCase()] ?? 1)\n}\n\n/**\n * A content-identity key for de-duplication. The same file picked twice arrives as two distinct `File`\n * objects (so a `WeakMap`/reference check can't catch it), but its name + size + last-modified match.\n */\nexport const fileKey = (file: File): string => `f:${file.name}:${file.size}:${file.lastModified}`\n/** The dedup key for an existing item — a File by its content, an already-uploaded one by its URL. */\nexport const itemKey = (item: FileUploaderItem): string =>\n item.file ? fileKey(item.file) : `s:${item.source ?? ''}`\n\n/** Display name — the File's name or the last path segment of a source URL. */\nexport const labelOf = (item: FileUploaderItem): string => {\n if (item.file) return item.file.name\n if (item.source) {\n if (/^(data|blob):/i.test(item.source)) return 'File'\n return item.source.split(/[?#]/)[0].split('/').pop() || 'File'\n }\n return 'File'\n}\n\n/**\n * Whether an item is an image — the only kind that gets the **crop** + **alt-text** editors (a video / PDF\n * / doc has nothing to crop or describe). A File is judged by its MIME `type`; a source URL by a known\n * image extension or a `data:image/…` URI, defaulting to `true` when it carries no recognizable extension\n * (the image-first assumption — e.g. extensionless CDN URLs).\n */\nexport const isImageItem = (item: FileUploaderItem): boolean => {\n if (item.file) return item.file.type.startsWith('image/')\n const src = item.source\n if (!src) return false\n if (/^data:image\\//i.test(src)) return true\n if (/^data:/i.test(src)) return false // a non-image data URI\n return (\n /\\.(png|jpe?g|gif|webp|avif|svg|bmp|ico|heic|heif)(?:[?#]|$)/i.test(src) ||\n !/\\.[a-z0-9]{1,8}(?:[?#]|$)/i.test(src)\n )\n}\n\n/** Whether an item is a video — rendered as a playable `<video controls>` preview instead of an `<img>`. */\nexport const isVideoItem = (item: FileUploaderItem): boolean => {\n if (item.file) return item.file.type.startsWith('video/')\n const src = item.source\n if (!src) return false\n return /^data:video\\//i.test(src) || /\\.(mp4|webm|ogg|ogv|mov|m4v|avi|mkv)(?:[?#]|$)/i.test(src)\n}\n\n/** Download an item — a File via a fresh object URL, a source URL via a download link. */\nconst triggerDownload = (item: FileUploaderItem) => {\n if (typeof document === 'undefined') return\n const a = document.createElement('a')\n a.style.display = 'none'\n if (item.file) {\n if (!canMakeObjectUrl()) return\n const url = URL.createObjectURL(item.file)\n a.href = url\n a.download = item.file.name\n document.body.appendChild(a)\n a.click()\n a.remove()\n setTimeout(() => URL.revokeObjectURL(url), 1000)\n } else if (item.source) {\n a.href = item.source\n a.download = labelOf(item)\n a.target = '_blank'\n a.rel = 'noopener'\n document.body.appendChild(a)\n a.click()\n a.remove()\n }\n}\n\n/**\n * Split a name into the part that may truncate and a short trailing extension that should always stay\n * visible — so a long name middle-ellipses as `name….ext` instead of overflowing or losing the type.\n */\nexport const splitName = (name: string): { base: string; ext: string } => {\n const dot = name.lastIndexOf('.')\n // only peel off a real, short extension (\".png\", \".jpeg\") — not a dot buried in a long hash\n return dot > 0 && name.length - dot <= 7\n ? { base: name.slice(0, dot), ext: name.slice(dot) }\n : { base: name, ext: '' }\n}\n\n// ── one row ─────────────────────────────────────────────────────────────────────────────────────\n\ninterface RowProps {\n id: string\n item: FileUploaderItem\n preview: string | null\n sortable: boolean\n entering: boolean\n disabled?: boolean\n error?: string\n onRemove: () => void\n onCrop?: () => void\n onAltText?: () => void\n onDownload?: () => void\n onView?: () => void\n onPreviewError?: () => void\n}\n\nfunction Row({\n id,\n item,\n preview,\n sortable,\n entering,\n disabled,\n error,\n onRemove,\n onCrop,\n onAltText,\n onDownload,\n onView,\n onPreviewError,\n}: RowProps) {\n // the whole tile is the drag handle (no separate grip — matches the image-card visual)\n const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({\n id,\n disabled: !sortable,\n })\n const style: CSSProperties = {\n transform: CSS.Transform.toString(transform),\n transition,\n }\n const t = useT()\n const label = labelOf(item)\n const { base, ext } = splitName(label)\n // a remote preview shows a skeleton until it arrives; a local `blob:` preview is instant, so no flash\n const [mediaLoaded, setMediaLoaded] = useState(() => !preview || preview.startsWith('blob:'))\n const lastPreview = useRef(preview)\n if (lastPreview.current !== preview) {\n lastPreview.current = preview\n setMediaLoaded(!preview || preview.startsWith('blob:'))\n }\n const mediaRef = useRef<HTMLImageElement>(null)\n useEffect(() => {\n const img = mediaRef.current\n if (img?.complete && img.naturalWidth > 0) setMediaLoaded(true)\n }, [preview])\n const onMediaError = () => {\n setMediaLoaded(true)\n onPreviewError?.()\n }\n const meta = item.file ? formatBytes(item.file.size) : t('fileUploader.uploaded')\n const video = isVideoItem(item)\n\n const downloadBtn = onDownload ? (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.download', { name: label })}\n onClick={onDownload}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"DocumentDownload\" size=\"sm\" />\n </button>\n ) : null\n\n return (\n <div\n ref={setNodeRef}\n style={style}\n className={clsx(\n styles.tile,\n sortable && styles.grabbable,\n entering && styles.entering,\n isDragging && styles.dragging,\n error && styles.tileError,\n )}\n {...attributes}\n {...listeners}\n >\n {preview && !mediaLoaded && (\n <Skeleton variant=\"rect\" width=\"100%\" height=\"100%\" className={styles.tileSkeleton} />\n )}\n {preview ? (\n video ? (\n <>\n {/* first-frame thumbnail (no controls) + a centred play badge so it reads as a video */}\n <video\n src={preview}\n className={styles.tileImg}\n muted\n playsInline\n preload=\"metadata\"\n draggable={false}\n onLoadedData={() => setMediaLoaded(true)}\n onError={onMediaError}\n />\n <span className={styles.tilePlay} aria-hidden=\"true\">\n <Icon name=\"Play\" size=\"lg\" />\n </span>\n </>\n ) : (\n <img\n ref={mediaRef}\n src={preview}\n alt=\"\"\n className={clsx(styles.tileImg, !mediaLoaded && styles.tileImgPending)}\n draggable={false}\n onLoad={() => setMediaLoaded(true)}\n onError={onMediaError}\n />\n )\n ) : (\n <span className={styles.tileFallback} aria-hidden=\"true\">\n <Icon name=\"Document\" size=\"lg\" />\n </span>\n )}\n\n {/* top scrim: name/meta on the left, the remove × pinned top-right */}\n <div className={styles.tileTop}>\n <span className={styles.tileText}>\n <span className={styles.name} title={label}>\n <span className={styles.nameBase}>{base}</span>\n {ext && <span className={styles.nameExt}>{ext}</span>}\n </span>\n <span className={clsx(styles.tileMeta, error && styles.metaError)}>{error ?? meta}</span>\n </span>\n {!disabled && (\n <button\n type=\"button\"\n className={styles.tileRemove}\n aria-label={t('fileUploader.remove', { name: label })}\n onClick={onRemove}\n onPointerDown={(e) => e.stopPropagation()} // don't start a drag from the remove button\n >\n <Icon name=\"Close\" size=\"sm\" />\n </button>\n )}\n </div>\n\n {/* bottom scrim: crop (Crop) + alt text (Text) + download on the left (crop/alt are image-only),\n the view (Eye) fullscreen-preview button pinned bottom-right */}\n {(onCrop || onAltText || onDownload || onView) && (\n <div className={styles.tileBottom}>\n {onCrop && (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.crop', { name: label })}\n onClick={onCrop}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Crop\" size=\"sm\" />\n </button>\n )}\n {onAltText && (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.editAlt', { name: label })}\n onClick={onAltText}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Text\" size=\"sm\" />\n </button>\n )}\n {downloadBtn}\n {onView && (\n <button\n type=\"button\"\n className={clsx(styles.tileAction, styles.tileActionEnd)}\n aria-label={t('fileUploader.preview', { name: label })}\n onClick={onView}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Eye\" size=\"sm\" />\n </button>\n )}\n </div>\n )}\n </div>\n )\n}\n\n// ── the field ───────────────────────────────────────────────────────────────────────────────────\n\n/**\n * A small, clean file field that **collects** files for the consumer to upload on save — it never\n * uploads itself. New picks carry their binary in `file`; already-uploaded files arrive with a\n * `source` URL. A soft dropzone panel sits above a grid of image cards (thumbnail/file-icon + name +\n * size, with overlaid remove + download buttons). `allowDrop` enables drag-from-OS (via\n * `react-dropzone`); `allowReorder` enables drag + keyboard reordering (via `@dnd-kit`); cards animate\n * in/out (via `@formkit/auto-animate`). Controlled (`value` + `onChange`) or uncontrolled\n * (`defaultValue`); binds to a `<Form>` by `name`. The forwarded ref points at the root.\n */\nexport const FileUploader = forwardRef<HTMLDivElement, FileUploaderProps>(function FileUploader(\n {\n multiple = false,\n allowDrop = true,\n allowReorder = true,\n allowDownload = true,\n allowPreview = true,\n allowAltText = true,\n altTextLocales,\n localizedAltText = true,\n allowDuplicates = false,\n disabled = false,\n accept,\n maxFiles,\n maxFileSize,\n itemInsertLocation = 'end',\n value,\n defaultValue,\n onChange,\n label,\n error,\n helperText,\n required = false,\n fullWidth = true,\n name,\n id: idProp,\n onBlur,\n className,\n style,\n ...props\n },\n ref,\n) {\n const reactId = useId()\n const id = idProp ?? reactId\n const helperId = `${id}-helper`\n\n const maxBytes = maxFileSize != null ? toBytes(maxFileSize) : undefined\n const [notice, setNotice] = useState<string | null>(null)\n // the rejection notice auto-dismisses so it doesn't linger forever\n useEffect(() => {\n if (!notice) return\n const timer = window.setTimeout(() => setNotice(null), 4000)\n return () => window.clearTimeout(timer)\n }, [notice])\n\n // Auto-bind to a surrounding <Form> by `name`. The value is a typed object/array, so read it RAW from\n // values[name] (never field().value, which String-coerces); error/touched come from field().\n const form = useFormContext()\n const isFormBound = Boolean(form && name)\n const bound = form && name ? form.field(name) : undefined\n\n const fallback: FileUploaderValue = multiple ? [] : null\n const externalValue: FileUploaderValue | undefined =\n value !== undefined\n ? value\n : isFormBound\n ? ((form!.values[name!] as FileUploaderValue | undefined) ?? fallback)\n : undefined\n const isControlled = externalValue !== undefined\n const [internal, setInternal] = useState<FileUploaderValue>(defaultValue ?? fallback)\n const current = isControlled ? externalValue! : internal\n const items: FileUploaderItem[] =\n current == null ? [] : Array.isArray(current) ? current : [current]\n\n const resolvedError = error ?? bound?.error ?? false\n const resolvedHelperText = helperText ?? bound?.helperText\n const shownHelper = notice ?? resolvedHelperText\n const helperIsError = Boolean(notice) || resolvedError\n\n const reorderEnabled = allowReorder && multiple && !disabled\n\n // Stable ids per item so a row keeps its identity (and focus) across reorders.\n const fileIds = useRef(new WeakMap<File, string>())\n const seed = useRef(0)\n const idOf = (item: FileUploaderItem, index: number): string => {\n if (item.file) {\n let id = fileIds.current.get(item.file)\n if (!id) {\n seed.current += 1\n id = `f${seed.current}`\n fileIds.current.set(item.file, id)\n }\n return id\n }\n return item.source ? `s:${item.source}` : `i:${index}`\n }\n const ids = items.map((item, i) => idOf(item, i))\n\n // Ids that have already animated in, so only genuinely new rows get the entrance animation — a reorder\n // re-inserts the moved/shifted nodes, which would otherwise restart the CSS drop-in on them.\n const enteredIds = useRef<Set<string>>(new Set())\n const enteringIds = new Set(ids.filter((id) => !enteredIds.current.has(id)))\n useEffect(() => {\n enteredIds.current = new Set(ids)\n })\n\n // Source URLs that failed to load as an image (so we fall back to the file icon).\n const [failedSources, setFailedSources] = useState<ReadonlySet<string>>(() => new Set())\n const markSourceFailed = (src: string) =>\n setFailedSources((prev) => (prev.has(src) ? prev : new Set(prev).add(src)))\n\n // Files whose object-URL preview failed to load (a corrupt/undecodable image) — same fallback.\n const [failedFiles, setFailedFiles] = useState<ReadonlySet<File>>(() => new Set())\n const markFileFailed = (file: File) =>\n setFailedFiles((prev) => (prev.has(file) ? prev : new Set(prev).add(file)))\n\n // Object URLs for image/video File previews, revoked when the File leaves the value / on unmount.\n const objectUrls = useRef(new Map<File, string>())\n const previewOf = (item: FileUploaderItem): string | null => {\n if (item.file) {\n const type = item.file.type\n if (\n (!type.startsWith('image/') && !type.startsWith('video/')) ||\n !canMakeObjectUrl() ||\n failedFiles.has(item.file)\n )\n return null\n let url = objectUrls.current.get(item.file)\n if (!url) {\n url = URL.createObjectURL(item.file)\n objectUrls.current.set(item.file, url)\n }\n return url\n }\n // an already-uploaded item is assumed to be a previewable image/video (image-first uploader); a\n // non-media URL just falls the row back to the file icon via the <img> onError handler\n if (item.source && !failedSources.has(item.source)) return item.source\n return null\n }\n // fullscreen preview (Eye) — snapshot the media so the lightbox is self-contained. Declared above\n // the object-URL cleanup effect below so that effect can spare the URL the lightbox is showing.\n const [preview, setPreview] = useState<{\n url: string\n isVideo: boolean\n isSvg: boolean\n name: string\n } | null>(null)\n useEffect(() => {\n const cache = objectUrls.current\n const liveFiles = new Set(items.map((it) => it.file).filter(Boolean) as File[])\n const liveSources = new Set(items.filter((it) => !it.file && it.source).map((it) => it.source!))\n for (const [file, url] of cache) {\n // don't revoke the URL the open lightbox is showing — a controlled value swap that removes the\n // item would otherwise break the media mid-display; the deferred revoke runs once it closes\n // (this effect re-runs on `preview` change) or on unmount\n if (!liveFiles.has(file) && url !== preview?.url) {\n URL.revokeObjectURL(url)\n cache.delete(file)\n }\n }\n setFailedSources((prev) => {\n if (prev.size === 0) return prev\n const next = new Set([...prev].filter((s) => liveSources.has(s)))\n return next.size === prev.size ? prev : next\n })\n }, [current, preview]) // eslint-disable-line react-hooks/exhaustive-deps -- `current` is the value identity\n useEffect(() => {\n const cache = objectUrls.current\n return () => {\n for (const url of cache.values()) URL.revokeObjectURL(url)\n cache.clear()\n }\n }, [])\n\n const reindex = (arr: FileUploaderItem[]): FileUploaderItem[] =>\n arr.map((it, i) => (it.sortIndex === i ? it : { ...it, sortIndex: i }))\n\n const commit = (next: FileUploaderItem[]) => {\n const ordered = reindex(next)\n const out: FileUploaderValue = multiple ? ordered : (ordered[0] ?? null)\n if (!isControlled) setInternal(out)\n if (isFormBound) form!.setValue(name!, out)\n onChange?.(out)\n }\n\n // mark the bound form field touched (the impl ignores the event — it just flips the touched flag)\n const markTouched = () => bound?.onBlur({} as FocusEvent<HTMLInputElement>)\n\n const t = useT()\n // ── edit dialogs (separate Crop and Alt-text modals, opened from a card's two buttons) ────────────\n const configLocales = useLocales()\n const altLocales = altTextLocales ?? configLocales\n // per-locale (default): one field per locale (falling back to a single field if none configured);\n // non-localized: always a single field, keyed under '' (the value is a plain string)\n const editLocales = localizedAltText && altLocales.length > 0 ? altLocales : [{ code: '' }]\n // track the edited item by its STABLE id (not its index) so an external value change while a dialog is\n // open — reorder/remove/refetch — can't retarget the save onto the wrong item\n const [editId, setEditId] = useState<string | null>(null)\n const [editMode, setEditMode] = useState<'crop' | 'altText'>('altText')\n const editPos = editId != null ? ids.indexOf(editId) : -1\n const editingItem = editPos !== -1 ? items[editPos] : null\n const openCropEditor = (index: number) => {\n setEditMode('crop')\n setEditId(ids[index] ?? null)\n }\n const openAltEditor = (index: number) => {\n setEditMode('altText')\n setEditId(ids[index] ?? null)\n }\n const closeEditor = () => setEditId(null)\n\n const openPreview = (item: FileUploaderItem) => {\n const url = previewOf(item)\n if (!url) return\n // SVGs need an explicit box in the lightbox (they often lack an intrinsic pixel size)\n const isSvg = item.file\n ? item.file.type === 'image/svg+xml'\n : /^data:image\\/svg/i.test(item.source ?? '') || /\\.svg(?:[?#]|$)/i.test(item.source ?? '')\n setPreview({ url, isVideo: isVideoItem(item), isSvg, name: labelOf(item) })\n }\n // seed the alt-text dialog's draft from the item's current value (record vs single string)\n const editInitialDraft: Record<string, string> = editingItem\n ? localizedAltText\n ? editingItem.altText && typeof editingItem.altText === 'object'\n ? { ...editingItem.altText }\n : {}\n : { '': typeof editingItem.altText === 'string' ? editingItem.altText : '' }\n : {}\n const saveEdit = ({ draft, croppedFile }: EditDialogResult) => {\n if (editPos === -1) return closeEditor() // the item went away under us — bail\n commit(\n items.map((it, i) => {\n if (ids[i] !== editId) return it\n const next: FileUploaderItem = { ...it }\n // alt-text dialog → rebuild altText from the draft (localized record / single string)\n if (draft !== undefined) {\n if (localizedAltText) {\n // prune empty/whitespace entries so the model isn't littered with blank locales\n const cleaned = Object.fromEntries(\n Object.entries(draft)\n .map(([code, text]) => [code, text.trim()] as [string, string])\n .filter(([, text]) => text !== ''),\n )\n next.altText = Object.keys(cleaned).length > 0 ? cleaned : undefined\n } else {\n next.altText = (draft[''] ?? '').trim() || undefined\n }\n }\n // crop dialog → replace the image with the cropped File (native-res, lossless); a source item\n // becomes a fresh pick (the cropped version uploads on save)\n if (croppedFile) {\n next.file = croppedFile\n next.source = ''\n }\n return next\n }),\n )\n closeEditor()\n }\n\n const addFiles = (accepted: File[], rejections: FileRejection[] = []) => {\n // Hard rejections (the file is invalid: wrong type, or over `maxFileSize` — react-dropzone rejects\n // both, so they never reach `accepted`) surface as a Toast error and are not added.\n const wrongType = rejections.filter((r) => r.errors.some((e) => e.code === 'file-invalid-type'))\n const tooLarge = rejections.filter((r) => r.errors.some((e) => e.code === 'file-too-large'))\n if (wrongType.length > 0)\n toast.error(\n wrongType.length === 1\n ? t('fileUploader.wrongTypeOne', { name: wrongType[0].file.name })\n : t('fileUploader.wrongTypeMany', { count: wrongType.length }),\n )\n if (tooLarge.length > 0 && maxBytes != null)\n toast.error(\n tooLarge.length === 1\n ? t('fileUploader.tooLargeOne', {\n name: tooLarge[0].file.name,\n size: formatBytes(maxBytes),\n })\n : t('fileUploader.tooLargeMany', { count: tooLarge.length, size: formatBytes(maxBytes) }),\n )\n\n // Soft notices (the file is valid, just not added now) stay in the inline helper slot + auto-dismiss.\n const reasons: string[] = []\n let taken = accepted\n // drop files already present (same content) + intra-batch dupes, unless explicitly allowed\n if (multiple && !allowDuplicates) {\n const seen = new Set(items.map(itemKey))\n const unique: File[] = []\n for (const file of taken) {\n const key = fileKey(file)\n if (seen.has(key)) continue\n seen.add(key)\n unique.push(file)\n }\n if (unique.length < taken.length) reasons.push(t('fileUploader.duplicate'))\n taken = unique\n }\n if (multiple && maxFiles != null) {\n const room = Math.max(0, maxFiles - items.length)\n if (taken.length > room) {\n taken = taken.slice(0, room)\n reasons.push(\n maxFiles === 1\n ? t('fileUploader.hintUpToOne', { count: maxFiles })\n : t('fileUploader.hintUpToMany', { count: maxFiles }),\n )\n }\n }\n\n setNotice(reasons.length > 0 ? reasons.join(' · ') : null)\n if (taken.length === 0) return\n const picked = taken.map<FileUploaderItem>((file) => ({ file, source: '', sortIndex: 0 }))\n if (!multiple) {\n commit([picked[0]])\n return\n }\n commit(itemInsertLocation === 'start' ? [...picked, ...items] : [...items, ...picked])\n }\n const removeAt = (index: number) => {\n setNotice(null)\n commit(items.filter((_, i) => i !== index))\n // removing is an explicit interaction — mark touched so an emptied required field reveals its error\n markTouched()\n }\n\n // auto-animate handles add / remove / shift on the list; it's paused during a dnd-kit drag so the two\n // don't both animate the reorder (dnd-kit owns the drag visuals, auto-animate owns enter/exit).\n const [listRef, enableAnimations] = useAutoAnimate(listAnimation)\n const reEnableAnimations = () => {\n if (typeof requestAnimationFrame === 'function')\n requestAnimationFrame(() => enableAnimations(true))\n else enableAnimations(true)\n }\n const handleDragStart = () => enableAnimations(false)\n const handleDragCancel = () => reEnableAnimations()\n const handleDragEnd = (event: DragEndEvent) => {\n const { active, over } = event\n if (over && active.id !== over.id) {\n const from = ids.indexOf(String(active.id))\n const to = ids.indexOf(String(over.id))\n if (from !== -1 && to !== -1) commit(arrayMove(items, from, to))\n }\n reEnableAnimations() // after the reorder DOM settles, so the move isn't double-animated\n }\n\n const sensors = useSensors(\n useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),\n useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),\n )\n\n // opening the native file dialog blurs the window, which would otherwise mark the field touched and flash\n // a \"required\" error before the user picks anything; suppress that one blur and only mark touched when the\n // dialog is *canceled* with no selection (the real \"engaged, added nothing\" signal)\n const fileDialogOpen = useRef(false)\n\n const { getRootProps, getInputProps, isDragActive } = useDropzone({\n multiple,\n accept,\n // reject oversized picks here so they never get added; the rejection surfaces as a Toast in addFiles\n maxSize: maxBytes,\n disabled,\n noKeyboard: false,\n noDrag: !allowDrop,\n onFileDialogOpen: () => {\n fileDialogOpen.current = true\n },\n onFileDialogCancel: () => {\n fileDialogOpen.current = false\n markTouched()\n },\n onDrop: (accepted, rejections) => {\n fileDialogOpen.current = false\n addFiles(accepted, rejections)\n },\n })\n\n const showDropzone = multiple || items.length === 0\n\n // static constraint hint shown inside the dropzone (e.g. \"Up to 5 files · Max 5 MB each\")\n const hintParts: string[] = []\n if (multiple && maxFiles != null)\n hintParts.push(\n maxFiles === 1\n ? t('fileUploader.hintUpToOne', { count: maxFiles })\n : t('fileUploader.hintUpToMany', { count: maxFiles }),\n )\n if (maxBytes != null) hintParts.push(t('fileUploader.hintMax', { size: formatBytes(maxBytes) }))\n const hint = hintParts.join(' · ')\n\n const prompt: ReactNode = allowDrop ? (\n <>\n <span className={styles.accent}>{t('fileUploader.choose')}</span>{' '}\n {t('fileUploader.dropSuffix')}\n </>\n ) : (\n <span className={styles.accent}>{t('fileUploader.choose')}</span>\n )\n\n // mark the field touched once focus leaves the whole widget (so blurThenLive errors reveal on blur)\n const onRootBlur = (event: FocusEvent<HTMLDivElement>) => {\n onBlur?.(event)\n if (event.currentTarget.contains(event.relatedTarget as Node | null)) return\n // opening the alt-text editor moves focus into the body-portaled Modal (outside the root); that's not\n // focus leaving the widget, so don't mark touched (mirrors Select's portaled-popover guard)\n if (editId != null) return\n // the native file-dialog blur isn't \"leaving the widget\" either — consume it (touched is set instead on\n // dialog cancel); only a genuine blur-away marks touched\n if (fileDialogOpen.current) {\n fileDialogOpen.current = false\n return\n }\n markTouched()\n }\n\n return (\n <div\n ref={ref}\n id={id}\n className={clsx(\n styles.root,\n fullWidth && styles.fullWidth,\n resolvedError && styles.error,\n disabled && styles.disabled,\n className,\n )}\n style={style}\n aria-invalid={resolvedError || undefined}\n aria-describedby={shownHelper != null ? helperId : undefined}\n onBlur={onRootBlur}\n {...props}\n // name + tabIndex are load-bearing for the form's scroll-to-error → spread last so props can't clobber\n {...(name ? { name, tabIndex: -1 } : {})}\n >\n {label != null && (\n <label className={fieldStyles.label}>\n <Typography as=\"span\" variant=\"bodySmall\" color=\"muted\">\n {label}\n </Typography>\n {required && (\n <span className={fieldStyles.required} aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n )}\n\n {showDropzone && (\n <div\n {...getRootProps({ className: clsx(styles.dropzone, isDragActive && styles.dropping) })}\n >\n <input {...getInputProps()} />\n <span className={styles.dropIcon} aria-hidden=\"true\">\n <Icon name=\"DocumentUpload\" size=\"lg\" />\n </span>\n <span className={styles.dropText}>\n <span className={styles.prompt}>{prompt}</span>\n {hint && <span className={styles.hint}>{hint}</span>}\n </span>\n </div>\n )}\n\n {/* always rendered (even when empty) so auto-animate can animate the last card out on removal */}\n <DndContext\n sensors={sensors}\n collisionDetection={closestCenter}\n onDragStart={reorderEnabled ? handleDragStart : undefined}\n onDragEnd={reorderEnabled ? handleDragEnd : undefined}\n onDragCancel={reorderEnabled ? handleDragCancel : undefined}\n >\n <SortableContext items={ids} strategy={rectSortingStrategy}>\n <div\n ref={listRef}\n className={clsx(styles.list, showDropzone && items.length > 0 && styles.populated)}\n >\n {items.map((item, index) => (\n <Row\n key={ids[index]}\n id={ids[index]}\n item={item}\n preview={previewOf(item)}\n sortable={reorderEnabled && items.length > 1}\n entering={enteringIds.has(ids[index])}\n disabled={disabled}\n error={\n item.file && maxBytes != null && item.file.size > maxBytes\n ? t('fileUploader.exceedsLimit', { size: formatBytes(maxBytes) })\n : undefined\n }\n onRemove={() => removeAt(index)}\n // crop + alt text are image-only — a video / PDF / doc has nothing to crop or describe\n onCrop={\n allowAltText && !disabled && isImageItem(item)\n ? () => openCropEditor(index)\n : undefined\n }\n onAltText={\n allowAltText && !disabled && isImageItem(item)\n ? () => openAltEditor(index)\n : undefined\n }\n onDownload={allowDownload && !disabled ? () => triggerDownload(item) : undefined}\n // fullscreen preview — image + video only (a PDF / doc has nothing to preview)\n onView={\n allowPreview &&\n !disabled &&\n previewOf(item) != null &&\n (isImageItem(item) || isVideoItem(item))\n ? () => openPreview(item)\n : undefined\n }\n onPreviewError={\n item.file\n ? () => markFileFailed(item.file!)\n : item.source\n ? () => markSourceFailed(item.source!)\n : undefined\n }\n />\n ))}\n </div>\n </SortableContext>\n </DndContext>\n\n {shownHelper != null && (\n <Typography\n as=\"span\"\n id={helperId}\n variant=\"bodySmall\"\n color={helperIsError ? 'error' : 'muted'}\n className={fieldStyles.helper}\n role=\"status\"\n aria-live=\"polite\"\n >\n {shownHelper}\n </Typography>\n )}\n\n {editingItem && (\n <FileUploaderEditDialog\n key={`${editId}:${editMode}`}\n mode={editMode}\n name={labelOf(editingItem)}\n imageUrl={previewOf(editingItem)}\n mimeType={editingItem.file?.type || 'image/png'}\n editLocales={editLocales}\n initialDraft={editInitialDraft}\n onClose={closeEditor}\n onSave={saveEdit}\n />\n )}\n\n {preview && (\n <FileUploaderPreview\n url={preview.url}\n isVideo={preview.isVideo}\n isSvg={preview.isSvg}\n name={preview.name}\n onClose={() => setPreview(null)}\n />\n )}\n </div>\n )\n})\n"],"names":["FileUploaderEditDialog","mode","name","imageUrl","mimeType","editLocales","initialDraft","onClose","onSave","t","useT","imgRef","useRef","crop","setCrop","useState","naturalCrop","setNaturalCrop","naturalSize","setNaturalSize","draft","setDraft","cropError","setCropError","busy","setBusy","onCropChange","px","percent","img","sx","sy","buildCroppedFile","image","canvas","ctx","blob","resolve","handleSave","croppedFile","jsx","Modal","jsxs","Fragment","Button","styles","Typography","ReactCrop","e","l","TextField","d","FileUploaderPreview","url","isVideo","isSvg","Overlay","Icon","clsx","canMakeObjectUrl","ANIM_MS","listAnimation","el","action","oldCoords","newCoords","keyframes","duration","dx","dy","formatBytes","bytes","units","value","i","toBytes","size","match","fileKey","file","itemKey","item","labelOf","isImageItem","src","isVideoItem","triggerDownload","a","splitName","dot","Row","id","preview","sortable","entering","disabled","error","onRemove","onCrop","onAltText","onDownload","onView","onPreviewError","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","label","base","ext","mediaLoaded","setMediaLoaded","lastPreview","mediaRef","useEffect","onMediaError","meta","video","downloadBtn","Skeleton","FileUploader","forwardRef","multiple","allowDrop","allowReorder","allowDownload","allowPreview","allowAltText","altTextLocales","localizedAltText","allowDuplicates","accept","maxFiles","maxFileSize","itemInsertLocation","defaultValue","onChange","helperText","required","fullWidth","idProp","onBlur","className","props","ref","reactId","useId","helperId","maxBytes","notice","setNotice","timer","form","useFormContext","isFormBound","bound","fallback","externalValue","isControlled","internal","setInternal","current","items","resolvedError","resolvedHelperText","shownHelper","helperIsError","reorderEnabled","fileIds","seed","idOf","index","ids","enteredIds","enteringIds","failedSources","setFailedSources","markSourceFailed","prev","failedFiles","setFailedFiles","markFileFailed","objectUrls","previewOf","type","setPreview","cache","liveFiles","it","liveSources","next","s","reindex","arr","commit","ordered","out","markTouched","configLocales","useLocales","altLocales","editId","setEditId","editMode","setEditMode","editPos","editingItem","openCropEditor","openAltEditor","closeEditor","openPreview","editInitialDraft","saveEdit","cleaned","code","text","addFiles","accepted","rejections","wrongType","r","tooLarge","toast","reasons","taken","seen","unique","key","room","picked","removeAt","_","listRef","enableAnimations","useAutoAnimate","reEnableAnimations","handleDragStart","handleDragCancel","handleDragEnd","event","active","over","from","to","arrayMove","sensors","useSensors","useSensor","PointerSensor","KeyboardSensor","sortableKeyboardCoordinates","fileDialogOpen","getRootProps","getInputProps","isDragActive","useDropzone","showDropzone","hintParts","hint","prompt","onRootBlur","fieldStyles","DndContext","closestCenter","SortableContext","rectSortingStrategy","_a"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";const e=require("react/jsx-runtime"),_=require("react"),y=require("clsx"),b=require("./Icon-B6lz-V0A.cjs"),h=_.createContext({}),E=()=>_.useContext(h),O="_item_16twt_3",q="_sm_16twt_25",S="_md_16twt_31",D="_lg_16twt_36",A="_flush_16twt_43",M="_itemIcon_16twt_49",R="_itemText_16twt_57",B="_itemLabel_16twt_65",Z="_itemDescription_16twt_72",$="_itemTrailing_16twt_82",F="_clickable_16twt_92",G="_selected_16twt_109",H="_disabled_16twt_130",t={item:O,sm:q,md:S,lg:D,flush:A,itemIcon:M,itemText:R,itemLabel:B,itemDescription:Z,itemTrailing:$,clickable:F,selected:G,disabled:H},J=new Set(b.ICON_NAMES),P={sm:"sm",md:"md",lg:"md"},Q=_.forwardRef(function({icon:s,description:o,trailing:u,selected:d=!1,clickable:m=!1,disabled:n=!1,size:w,flush:p,color:g="primary",as:i,className:C,style:N,children:a,onClick:L,onKeyDown:l,...T},j){const x=E(),f=w??x.size??"md",k=p??x.flush??!1,z=i??"div",r=m&&!(i==="a"||i==="button"||typeof i=="function"||typeof i=="object"),I=s==null?null:typeof s=="string"&&J.has(s)?e.jsx(b.Icon,{name:s,size:P[f]}):s,v=c=>{r&&!n&&(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),c.currentTarget.click()),l==null||l(c)};return e.jsxs(z,{ref:j,className:y.clsx(t.item,t[f],k&&t.flush,d&&t.selected,m&&t.clickable,n&&t.disabled,C),style:{"--tz-btn-rgb":`var(--tz-color-${g}-rgb)`,...N},role:r?"button":void 0,tabIndex:r?n?-1:0:void 0,"aria-disabled":n||void 0,"aria-current":d||void 0,onClick:n?void 0:L,onKeyDown:m?v:l,...T,children:[I!=null&&e.jsx("span",{className:t.itemIcon,children:I}),(a!=null||o!=null)&&e.jsxs("span",{className:t.itemText,children:[a!=null&&e.jsx("span",{className:t.itemLabel,children:a}),o!=null&&e.jsx("span",{className:t.itemDescription,children:o})]}),u!=null&&e.jsx("span",{className:t.itemTrailing,children:u})]})});exports.ListContext=h;exports.ListItem=Q;
2
- //# sourceMappingURL=ListItem-Qo1Tt6Fi.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Modal-DTnB_mGg.js","sources":["../src/components/Overlay/Overlay.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { clsx } from 'clsx'\nimport { useLockBodyScroll } from '../../hooks/useLockBodyScroll'\nimport styles from './Overlay.module.css'\n\nexport interface OverlayProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the overlay is mounted + shown — gates the portal and drives the fade-in. */\n open: boolean\n /** Requested dismiss — fired on a backdrop click (`closeOnBackdrop`) or Escape (`closeOnEscape`). */\n onClose?: () => void\n /** Close when the scrim itself (outside the content) is clicked. Defaults to `true`. */\n closeOnBackdrop?: boolean\n /** Close when Escape is pressed while focus is within the overlay. Defaults to `true`. */\n closeOnEscape?: boolean\n /** Lock page scroll while open. Defaults to `true`. */\n lockScroll?: boolean\n /** Scrim darkness — the black backdrop's alpha (0–1). Defaults to `0.45`. */\n dim?: number\n /** Overlay content — typically a centered dialog / box / media. */\n children?: ReactNode\n}\n\n/**\n * The shared backdrop primitive behind every dimmed, page-blocking surface (`Modal`, the FileUploader\n * lightbox). Portals a fixed full-viewport scrim to `<body>`, locks page scroll, fades in (opacity keyed\n * off a rAF `visible` flag → `data-open`), and dismisses on **backdrop-click** (gated on the pointer-down\n * AND click both landing on the scrim, so a text-selection drag ending on it doesn't close) / **Escape**\n * (swallowed via `stopPropagation` so it can't reach a React-tree ancestor overlay). Centers its children\n * by default; consumers layer their own padding / scroll / placement via `className` + `data-*` and read\n * the shared `data-open` on the scrim for their own box's enter transform. A consumer `onKeyDown` still\n * fires (after the Escape handling) so it can add e.g. a Tab focus-trap. Internal — no `index.ts`, so it's\n * never exposed as a package subpath; import it via `../Overlay/Overlay`. The ref points at the scrim div.\n */\nexport const Overlay = forwardRef<HTMLDivElement, OverlayProps>(function Overlay(\n {\n open,\n onClose,\n closeOnBackdrop = true,\n closeOnEscape = true,\n lockScroll = true,\n dim,\n className,\n style,\n children,\n onKeyDown,\n onMouseDown,\n onClick,\n ...props\n },\n ref,\n) {\n const mouseDownTarget = useRef<EventTarget | null>(null)\n const [visible, setVisible] = useState(false)\n\n useLockBodyScroll(open && lockScroll)\n\n // enter animation: flip `visible` on the frame after mount so the opacity transition runs\n useEffect(() => {\n if (!open) {\n setVisible(false)\n return\n }\n const raf = requestAnimationFrame(() => setVisible(true))\n return () => cancelAnimationFrame(raf)\n }, [open])\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n // the overlay owns the page — swallow Escape so it can't reach a React-tree ancestor overlay (e.g.\n // an outer Modal) even when this one isn't Escape-dismissible\n event.stopPropagation()\n if (closeOnEscape) onClose?.()\n }\n onKeyDown?.(event)\n }\n // remember where the pointer went down so the click handler can tell a scrim click from a drag that\n // started inside the content and ended on the scrim (a text-selection drag)\n const handleMouseDown = (event: MouseEvent<HTMLDivElement>) => {\n mouseDownTarget.current = event.target\n onMouseDown?.(event)\n }\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n if (\n closeOnBackdrop &&\n event.target === event.currentTarget &&\n mouseDownTarget.current === event.currentTarget\n ) {\n onClose?.()\n }\n onClick?.(event)\n }\n\n if (!open || typeof document === 'undefined') return null\n\n return createPortal(\n <div\n ref={ref}\n className={clsx(styles.overlay, className)}\n data-open={visible ? 'true' : 'false'}\n style={dim != null ? ({ '--tz-overlay-dim': dim, ...style } as CSSProperties) : style}\n onKeyDown={handleKeyDown}\n onMouseDown={handleMouseDown}\n onClick={handleClick}\n {...props}\n >\n {children}\n </div>,\n document.body,\n )\n})\n","import {\n forwardRef,\n useEffect,\n useId,\n useRef,\n type CSSProperties,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Icon } from '../Icon'\nimport { IconButton } from '../IconButton'\nimport { Overlay } from '../Overlay/Overlay'\nimport styles from './Modal.module.css'\n\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'fullScreen'\nexport type ModalScrollBehavior = 'inside' | 'outside'\nexport type ModalPlacement = 'center' | 'left' | 'right'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/** Focusable descendants used by the focus trap + initial focus. */\n// every clause excludes tabindex=\"-1\" so decorative/programmatic-only nodes (e.g. the header's\n// `nonClickable aria-hidden` IconButton) don't count as trap boundaries or initial-focus targets\nconst FOCUSABLE =\n 'a[href]:not([tabindex=\"-1\"]), button:not(:disabled):not([tabindex=\"-1\"]), textarea:not(:disabled):not([tabindex=\"-1\"]), input:not(:disabled):not([tabindex=\"-1\"]), select:not(:disabled):not([tabindex=\"-1\"]), [tabindex]:not([tabindex=\"-1\"])'\n\n/** Body FIELDS — where a form modal's initial focus lands (buttons / links in content don't count). */\nconst FIELD =\n 'input:not([type=\"hidden\"]):not(:disabled):not([tabindex=\"-1\"]), textarea:not(:disabled):not([tabindex=\"-1\"]), select:not(:disabled):not([tabindex=\"-1\"]), [contenteditable]:not([contenteditable=\"false\"]):not([tabindex=\"-1\"])'\n\n/**\n * Focus the first candidate that actually takes focus (a field inside a hidden tab panel won't). A radio\n * lands on its group's checked option, as Tab would.\n */\nfunction focusFirst(candidates: ArrayLike<HTMLElement>): boolean {\n const list = Array.from(candidates)\n for (const candidate of list) {\n const el =\n candidate instanceof HTMLInputElement && candidate.type === 'radio' && !candidate.checked\n ? (list.find(\n (other) =>\n other instanceof HTMLInputElement &&\n other.type === 'radio' &&\n other.name === candidate.name &&\n other.checked,\n ) ?? candidate)\n : candidate\n el.focus({ preventScroll: true })\n if (document.activeElement === el) return true\n }\n return false\n}\n\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'color'> {\n /** Whether the modal is open — gates the portal and drives the enter animation. */\n open: boolean\n /** Called when a dismiss is requested (close button, backdrop click, or Escape). */\n onClose: () => void\n /** Preset width: `sm` 360 · `md` 620 · `lg` 900 px, or `fullScreen` (fills the viewport). Defaults to `md`. */\n size?: ModalSize\n /**\n * Where overflow scrolls when the content is taller than the viewport: `outside` (default — the\n * whole dialog grows and the overlay/page scrolls) or `inside` (the body scrolls while the header +\n * footer stay pinned). Ignored for side-drawer placements (`left`/`right`), which always scroll inside.\n */\n scrollBehavior?: ModalScrollBehavior\n /**\n * Where the dialog sits: `center` (default — the standard centered modal), or `left` / `right` to\n * make it a **full-height side drawer** (sheet) that slides in from that edge. A drawer takes its\n * width from `size`, fills the viewport height, and always scrolls its body inside (header + footer\n * stay pinned).\n */\n placement?: ModalPlacement\n /** Header title. When set, labels the dialog (`aria-labelledby`). */\n title?: ReactNode\n /** Muted description line under the title (e.g. a confirm prompt). */\n description?: ReactNode\n /** Leading header icon shown in a tinted box (like `Card`) — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Theme color that tints the leading icon box. Defaults to `accent`. */\n color?: ThemeColor\n /** Footer slot — right-aligned actions over a top divider (e.g. Cancel / Confirm buttons). */\n footer?: ReactNode\n /** Extra class on the scrollable body element — to tune its padding / layout (e.g. a compact confirm). */\n bodyClassName?: string\n /** Show the header × close button. Defaults to `true`. */\n showCloseButton?: boolean\n /** Close when the backdrop (outside the dialog) is clicked. Defaults to `true`. */\n closeOnBackdrop?: boolean\n /** Close when Escape is pressed. Defaults to `true`. */\n closeOnEscape?: boolean\n /** Accessible label — used when there's no `title`. */\n ariaLabel?: string\n /** Dialog body. */\n children?: ReactNode\n}\n\n/**\n * A centered, backdrop-dimmed overlay dialog. Portaled to `<body>`, it locks page scroll while open,\n * traps Tab focus inside, restores focus to the previously-focused element on close, and dismisses on\n * close button / backdrop click / Escape (each toggleable). Sizes are `sm`/`md`/`lg` (max-width caps)\n * or `fullScreen`; `scrollBehavior` picks inside-body vs. whole-dialog scrolling. `placement` turns it\n * into a full-height side drawer (`left`/`right`) that slides in from the edge. The header mirrors\n * `Card` — an optional tinted `icon` box + `title` + `description`. Controlled by `open` + `onClose`.\n * The forwarded ref points at the dialog element.\n *\n * @example\n * const { isOpen, open, close } = useDisclosure()\n * <Modal open={isOpen} onClose={close} title=\"Edit\" footer={<Button onClick={close}>Done</Button>}>\n * …\n * </Modal>\n */\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\n {\n open,\n onClose,\n size = 'md',\n scrollBehavior = 'outside',\n placement = 'center',\n title,\n description,\n icon,\n color = 'accent',\n footer,\n bodyClassName,\n showCloseButton = true,\n closeOnBackdrop = true,\n closeOnEscape = true,\n ariaLabel,\n className,\n style,\n children,\n ...props\n },\n forwardedRef,\n) {\n const t = useT()\n const panelRef = useRef<HTMLDivElement | null>(null)\n const bodyRef = useRef<HTMLDivElement | null>(null)\n const footerRef = useRef<HTMLDivElement | null>(null)\n const titleId = useId()\n const descId = useId()\n\n // portal + scrim + scroll-lock + fade-in + backdrop-dismiss are handled by the shared `<Overlay>`\n\n // the element focused before opening — read during the render that opens the modal, because an\n // `autoFocus` element inside moves focus on mount, before any effect could see the opener\n const openerRef = useRef<HTMLElement | null>(null)\n const wasOpenRef = useRef(false)\n if (open !== wasOpenRef.current) {\n wasOpenRef.current = open\n if (open && typeof document !== 'undefined') {\n openerRef.current = document.activeElement as HTMLElement | null\n }\n }\n\n // focus management on open — an explicit `autoFocus` inside wins; else the first body FIELD (form\n // modals land on their first input), else the first footer action (a confirm dialog lands on\n // Cancel/Confirm, a sheet on its Close), else the dialog panel itself. Never \"any control in the\n // body\": a copy / icon / link button deep in content isn't where focus should start (it would also\n // pop that button's tooltip). The Tab trap still reaches every control. Restore on close.\n useEffect(() => {\n if (!open) return\n const panel = panelRef.current\n const opener = openerRef.current\n if (!panel?.contains(document.activeElement)) {\n // preventScroll so opening an `outside`-scroll modal doesn't jump the overlay to a below-fold control\n const placed =\n focusFirst(bodyRef.current?.querySelectorAll<HTMLElement>(FIELD) ?? []) ||\n focusFirst(footerRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [])\n if (!placed) panel?.focus({ preventScroll: true })\n }\n // only restore if the element is still mounted (it may have unmounted while the modal was open)\n return () => {\n if (opener?.isConnected) opener.focus?.()\n }\n }, [open])\n\n // merge the panel ref (positioning/focus) with the forwarded ref (consumer access)\n const setPanelRef = (node: HTMLDivElement | null) => {\n panelRef.current = node\n if (typeof forwardedRef === 'function') forwardedRef(node)\n else if (forwardedRef) forwardedRef.current = node\n }\n\n // trap Tab within the dialog so focus can't strand on the locked page behind it (Escape + backdrop\n // dismissal live in `<Overlay>`; this fires after the overlay's own handler)\n const handleTabTrap = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== 'Tab') return\n const panel = panelRef.current\n if (!panel) return\n const focusables = [...panel.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (el) => el.offsetParent !== null || el === document.activeElement,\n )\n if (focusables.length === 0) {\n event.preventDefault()\n panel.focus()\n return\n }\n const first = focusables[0]\n const last = focusables[focusables.length - 1]\n const active = document.activeElement\n if (event.shiftKey && (active === first || active === panel)) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first.focus()\n }\n }\n\n if (!open) return null\n\n // a side drawer (left/right) is always full-height with the body scrolling inside (header/footer pinned)\n const isDrawer = placement !== 'center'\n\n const renderedIcon =\n icon == null ? null : typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} />\n ) : (\n icon\n )\n\n const hasHeader = title != null || description != null || renderedIcon != null || showCloseButton\n // a divider sets the header apart from the body/footer, like Card\n const headerDivided = children != null || footer != null\n\n return (\n <Overlay\n open={open}\n onClose={onClose}\n closeOnBackdrop={closeOnBackdrop}\n closeOnEscape={closeOnEscape}\n onKeyDown={handleTabTrap}\n className={styles.overlay}\n data-size={size}\n data-placement={placement}\n data-scroll={isDrawer ? 'inside' : scrollBehavior}\n >\n <div\n ref={setPanelRef}\n className={clsx(styles.modal, styles[size], className)}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title != null ? titleId : undefined}\n aria-label={title == null ? ariaLabel : undefined}\n aria-describedby={description != null ? descId : undefined}\n tabIndex={-1}\n style={style as CSSProperties}\n {...props}\n >\n {hasHeader && (\n <div className={clsx(styles.header, headerDivided && styles.headerDivided)}>\n <div className={styles.headerMain}>\n {renderedIcon != null && (\n <IconButton\n variant=\"filled\"\n size=\"sm\"\n color={color}\n nonClickable\n aria-hidden\n className={styles.icon}\n >\n {renderedIcon}\n </IconButton>\n )}\n {(title != null || description != null) && (\n <div className={styles.headerText}>\n {title != null && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n {description != null && (\n <div id={descId} className={styles.subtitle}>\n {description}\n </div>\n )}\n </div>\n )}\n </div>\n {showCloseButton && (\n <IconButton\n variant=\"filled\"\n color=\"primary\"\n size=\"sm\"\n className={styles.close}\n aria-label={t('common.close')}\n onClick={onClose}\n >\n <Icon name=\"Close\" />\n </IconButton>\n )}\n </div>\n )}\n {children != null && (\n <div ref={bodyRef} className={clsx(styles.body, bodyClassName)}>\n {children}\n </div>\n )}\n {footer != null && (\n <div ref={footerRef} className={styles.footer}>\n {footer}\n </div>\n )}\n </div>\n </Overlay>\n )\n})\n"],"names":["Overlay","forwardRef","open","onClose","closeOnBackdrop","closeOnEscape","lockScroll","dim","className","style","children","onKeyDown","onMouseDown","onClick","props","ref","mouseDownTarget","useRef","visible","setVisible","useState","useLockBodyScroll","useEffect","raf","handleKeyDown","event","handleMouseDown","handleClick","createPortal","jsx","clsx","styles","ICON_NAME_SET","ICON_NAMES","FOCUSABLE","FIELD","focusFirst","candidates","list","candidate","el","other","Modal","size","scrollBehavior","placement","title","description","icon","color","footer","bodyClassName","showCloseButton","ariaLabel","forwardedRef","t","useT","panelRef","bodyRef","footerRef","titleId","useId","descId","openerRef","wasOpenRef","panel","opener","_a","_b","setPanelRef","node","handleTabTrap","focusables","first","last","active","isDrawer","renderedIcon","Icon","hasHeader","headerDivided","jsxs","IconButton"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"Modal-DjSOhZqd.cjs","sources":["../src/components/Overlay/Overlay.tsx","../src/components/Modal/Modal.tsx"],"sourcesContent":["import {\n forwardRef,\n useEffect,\n useRef,\n useState,\n type CSSProperties,\n type HTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\nimport { clsx } from 'clsx'\nimport { useLockBodyScroll } from '../../hooks/useLockBodyScroll'\nimport styles from './Overlay.module.css'\n\nexport interface OverlayProps extends HTMLAttributes<HTMLDivElement> {\n /** Whether the overlay is mounted + shown — gates the portal and drives the fade-in. */\n open: boolean\n /** Requested dismiss — fired on a backdrop click (`closeOnBackdrop`) or Escape (`closeOnEscape`). */\n onClose?: () => void\n /** Close when the scrim itself (outside the content) is clicked. Defaults to `true`. */\n closeOnBackdrop?: boolean\n /** Close when Escape is pressed while focus is within the overlay. Defaults to `true`. */\n closeOnEscape?: boolean\n /** Lock page scroll while open. Defaults to `true`. */\n lockScroll?: boolean\n /** Scrim darkness — the black backdrop's alpha (0–1). Defaults to `0.45`. */\n dim?: number\n /** Overlay content — typically a centered dialog / box / media. */\n children?: ReactNode\n}\n\n/**\n * The shared backdrop primitive behind every dimmed, page-blocking surface (`Modal`, the FileUploader\n * lightbox). Portals a fixed full-viewport scrim to `<body>`, locks page scroll, fades in (opacity keyed\n * off a rAF `visible` flag → `data-open`), and dismisses on **backdrop-click** (gated on the pointer-down\n * AND click both landing on the scrim, so a text-selection drag ending on it doesn't close) / **Escape**\n * (swallowed via `stopPropagation` so it can't reach a React-tree ancestor overlay). Centers its children\n * by default; consumers layer their own padding / scroll / placement via `className` + `data-*` and read\n * the shared `data-open` on the scrim for their own box's enter transform. A consumer `onKeyDown` still\n * fires (after the Escape handling) so it can add e.g. a Tab focus-trap. Internal — no `index.ts`, so it's\n * never exposed as a package subpath; import it via `../Overlay/Overlay`. The ref points at the scrim div.\n */\nexport const Overlay = forwardRef<HTMLDivElement, OverlayProps>(function Overlay(\n {\n open,\n onClose,\n closeOnBackdrop = true,\n closeOnEscape = true,\n lockScroll = true,\n dim,\n className,\n style,\n children,\n onKeyDown,\n onMouseDown,\n onClick,\n ...props\n },\n ref,\n) {\n const mouseDownTarget = useRef<EventTarget | null>(null)\n const [visible, setVisible] = useState(false)\n\n useLockBodyScroll(open && lockScroll)\n\n // enter animation: flip `visible` on the frame after mount so the opacity transition runs\n useEffect(() => {\n if (!open) {\n setVisible(false)\n return\n }\n const raf = requestAnimationFrame(() => setVisible(true))\n return () => cancelAnimationFrame(raf)\n }, [open])\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Escape') {\n // the overlay owns the page — swallow Escape so it can't reach a React-tree ancestor overlay (e.g.\n // an outer Modal) even when this one isn't Escape-dismissible\n event.stopPropagation()\n if (closeOnEscape) onClose?.()\n }\n onKeyDown?.(event)\n }\n // remember where the pointer went down so the click handler can tell a scrim click from a drag that\n // started inside the content and ended on the scrim (a text-selection drag)\n const handleMouseDown = (event: MouseEvent<HTMLDivElement>) => {\n mouseDownTarget.current = event.target\n onMouseDown?.(event)\n }\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n if (\n closeOnBackdrop &&\n event.target === event.currentTarget &&\n mouseDownTarget.current === event.currentTarget\n ) {\n onClose?.()\n }\n onClick?.(event)\n }\n\n if (!open || typeof document === 'undefined') return null\n\n return createPortal(\n <div\n ref={ref}\n className={clsx(styles.overlay, className)}\n data-open={visible ? 'true' : 'false'}\n style={dim != null ? ({ '--tz-overlay-dim': dim, ...style } as CSSProperties) : style}\n onKeyDown={handleKeyDown}\n onMouseDown={handleMouseDown}\n onClick={handleClick}\n {...props}\n >\n {children}\n </div>,\n document.body,\n )\n})\n","import {\n forwardRef,\n useEffect,\n useId,\n useRef,\n type CSSProperties,\n type HTMLAttributes,\n type KeyboardEvent,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport { ICON_NAMES, type IconName } from '../../icons/names'\nimport { useT, type ThemeColor } from '../../theme'\nimport { Icon } from '../Icon'\nimport { IconButton } from '../IconButton'\nimport { Overlay } from '../Overlay/Overlay'\nimport styles from './Modal.module.css'\n\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'fullScreen'\nexport type ModalScrollBehavior = 'inside' | 'outside'\nexport type ModalPlacement = 'center' | 'left' | 'right'\n\nconst ICON_NAME_SET = new Set<string>(ICON_NAMES)\n\n/** Focusable descendants used by the focus trap + initial focus. */\n// every clause excludes tabindex=\"-1\" so decorative/programmatic-only nodes (e.g. the header's\n// `nonClickable aria-hidden` IconButton) don't count as trap boundaries or initial-focus targets\nconst FOCUSABLE =\n 'a[href]:not([tabindex=\"-1\"]), button:not(:disabled):not([tabindex=\"-1\"]), textarea:not(:disabled):not([tabindex=\"-1\"]), input:not(:disabled):not([tabindex=\"-1\"]), select:not(:disabled):not([tabindex=\"-1\"]), [tabindex]:not([tabindex=\"-1\"])'\n\n/** Body FIELDS — where a form modal's initial focus lands (buttons / links in content don't count). */\nconst FIELD =\n 'input:not([type=\"hidden\"]):not(:disabled):not([tabindex=\"-1\"]), textarea:not(:disabled):not([tabindex=\"-1\"]), select:not(:disabled):not([tabindex=\"-1\"]), [contenteditable]:not([contenteditable=\"false\"]):not([tabindex=\"-1\"])'\n\n/**\n * Focus the first candidate that actually takes focus (a field inside a hidden tab panel won't). A radio\n * lands on its group's checked option, as Tab would.\n */\nfunction focusFirst(candidates: ArrayLike<HTMLElement>): boolean {\n const list = Array.from(candidates)\n for (const candidate of list) {\n const el =\n candidate instanceof HTMLInputElement && candidate.type === 'radio' && !candidate.checked\n ? (list.find(\n (other) =>\n other instanceof HTMLInputElement &&\n other.type === 'radio' &&\n other.name === candidate.name &&\n other.checked,\n ) ?? candidate)\n : candidate\n el.focus({ preventScroll: true })\n if (document.activeElement === el) return true\n }\n return false\n}\n\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title' | 'color'> {\n /** Whether the modal is open — gates the portal and drives the enter animation. */\n open: boolean\n /** Called when a dismiss is requested (close button, backdrop click, or Escape). */\n onClose: () => void\n /** Preset width: `sm` 360 · `md` 620 · `lg` 900 px, or `fullScreen` (fills the viewport). Defaults to `md`. */\n size?: ModalSize\n /**\n * Where overflow scrolls when the content is taller than the viewport: `outside` (default — the\n * whole dialog grows and the overlay/page scrolls) or `inside` (the body scrolls while the header +\n * footer stay pinned). Ignored for side-drawer placements (`left`/`right`), which always scroll inside.\n */\n scrollBehavior?: ModalScrollBehavior\n /**\n * Where the dialog sits: `center` (default — the standard centered modal), or `left` / `right` to\n * make it a **full-height side drawer** (sheet) that slides in from that edge. A drawer takes its\n * width from `size`, fills the viewport height, and always scrolls its body inside (header + footer\n * stay pinned).\n */\n placement?: ModalPlacement\n /** Header title. When set, labels the dialog (`aria-labelledby`). */\n title?: ReactNode\n /** Muted description line under the title (e.g. a confirm prompt). */\n description?: ReactNode\n /** Leading header icon shown in a tinted box (like `Card`) — a known `IconName` or any node. */\n icon?: IconName | ReactNode\n /** Theme color that tints the leading icon box. Defaults to `accent`. */\n color?: ThemeColor\n /** Footer slot — right-aligned actions over a top divider (e.g. Cancel / Confirm buttons). */\n footer?: ReactNode\n /** Extra class on the scrollable body element — to tune its padding / layout (e.g. a compact confirm). */\n bodyClassName?: string\n /** Show the header × close button. Defaults to `true`. */\n showCloseButton?: boolean\n /** Close when the backdrop (outside the dialog) is clicked. Defaults to `true`. */\n closeOnBackdrop?: boolean\n /** Close when Escape is pressed. Defaults to `true`. */\n closeOnEscape?: boolean\n /** Accessible label — used when there's no `title`. */\n ariaLabel?: string\n /** Dialog body. */\n children?: ReactNode\n}\n\n/**\n * A centered, backdrop-dimmed overlay dialog. Portaled to `<body>`, it locks page scroll while open,\n * traps Tab focus inside, restores focus to the previously-focused element on close, and dismisses on\n * close button / backdrop click / Escape (each toggleable). Sizes are `sm`/`md`/`lg` (max-width caps)\n * or `fullScreen`; `scrollBehavior` picks inside-body vs. whole-dialog scrolling. `placement` turns it\n * into a full-height side drawer (`left`/`right`) that slides in from the edge. The header mirrors\n * `Card` — an optional tinted `icon` box + `title` + `description`. Controlled by `open` + `onClose`.\n * The forwarded ref points at the dialog element.\n *\n * @example\n * const { isOpen, open, close } = useDisclosure()\n * <Modal open={isOpen} onClose={close} title=\"Edit\" footer={<Button onClick={close}>Done</Button>}>\n * …\n * </Modal>\n */\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\n {\n open,\n onClose,\n size = 'md',\n scrollBehavior = 'outside',\n placement = 'center',\n title,\n description,\n icon,\n color = 'accent',\n footer,\n bodyClassName,\n showCloseButton = true,\n closeOnBackdrop = true,\n closeOnEscape = true,\n ariaLabel,\n className,\n style,\n children,\n ...props\n },\n forwardedRef,\n) {\n const t = useT()\n const panelRef = useRef<HTMLDivElement | null>(null)\n const bodyRef = useRef<HTMLDivElement | null>(null)\n const footerRef = useRef<HTMLDivElement | null>(null)\n const titleId = useId()\n const descId = useId()\n\n // portal + scrim + scroll-lock + fade-in + backdrop-dismiss are handled by the shared `<Overlay>`\n\n // the element focused before opening — read during the render that opens the modal, because an\n // `autoFocus` element inside moves focus on mount, before any effect could see the opener\n const openerRef = useRef<HTMLElement | null>(null)\n const wasOpenRef = useRef(false)\n if (open !== wasOpenRef.current) {\n wasOpenRef.current = open\n if (open && typeof document !== 'undefined') {\n openerRef.current = document.activeElement as HTMLElement | null\n }\n }\n\n // focus management on open — an explicit `autoFocus` inside wins; else the first body FIELD (form\n // modals land on their first input), else the first footer action (a confirm dialog lands on\n // Cancel/Confirm, a sheet on its Close), else the dialog panel itself. Never \"any control in the\n // body\": a copy / icon / link button deep in content isn't where focus should start (it would also\n // pop that button's tooltip). The Tab trap still reaches every control. Restore on close.\n useEffect(() => {\n if (!open) return\n const panel = panelRef.current\n const opener = openerRef.current\n if (!panel?.contains(document.activeElement)) {\n // preventScroll so opening an `outside`-scroll modal doesn't jump the overlay to a below-fold control\n const placed =\n focusFirst(bodyRef.current?.querySelectorAll<HTMLElement>(FIELD) ?? []) ||\n focusFirst(footerRef.current?.querySelectorAll<HTMLElement>(FOCUSABLE) ?? [])\n if (!placed) panel?.focus({ preventScroll: true })\n }\n // only restore if the element is still mounted (it may have unmounted while the modal was open)\n return () => {\n if (opener?.isConnected) opener.focus?.()\n }\n }, [open])\n\n // merge the panel ref (positioning/focus) with the forwarded ref (consumer access)\n const setPanelRef = (node: HTMLDivElement | null) => {\n panelRef.current = node\n if (typeof forwardedRef === 'function') forwardedRef(node)\n else if (forwardedRef) forwardedRef.current = node\n }\n\n // trap Tab within the dialog so focus can't strand on the locked page behind it (Escape + backdrop\n // dismissal live in `<Overlay>`; this fires after the overlay's own handler)\n const handleTabTrap = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== 'Tab') return\n const panel = panelRef.current\n if (!panel) return\n const focusables = [...panel.querySelectorAll<HTMLElement>(FOCUSABLE)].filter(\n (el) => el.offsetParent !== null || el === document.activeElement,\n )\n if (focusables.length === 0) {\n event.preventDefault()\n panel.focus()\n return\n }\n const first = focusables[0]\n const last = focusables[focusables.length - 1]\n const active = document.activeElement\n if (event.shiftKey && (active === first || active === panel)) {\n event.preventDefault()\n last.focus()\n } else if (!event.shiftKey && active === last) {\n event.preventDefault()\n first.focus()\n }\n }\n\n if (!open) return null\n\n // a side drawer (left/right) is always full-height with the body scrolling inside (header/footer pinned)\n const isDrawer = placement !== 'center'\n\n const renderedIcon =\n icon == null ? null : typeof icon === 'string' && ICON_NAME_SET.has(icon) ? (\n <Icon name={icon as IconName} />\n ) : (\n icon\n )\n\n const hasHeader = title != null || description != null || renderedIcon != null || showCloseButton\n // a divider sets the header apart from the body/footer, like Card\n const headerDivided = children != null || footer != null\n\n return (\n <Overlay\n open={open}\n onClose={onClose}\n closeOnBackdrop={closeOnBackdrop}\n closeOnEscape={closeOnEscape}\n onKeyDown={handleTabTrap}\n className={styles.overlay}\n data-size={size}\n data-placement={placement}\n data-scroll={isDrawer ? 'inside' : scrollBehavior}\n >\n <div\n ref={setPanelRef}\n className={clsx(styles.modal, styles[size], className)}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={title != null ? titleId : undefined}\n aria-label={title == null ? ariaLabel : undefined}\n aria-describedby={description != null ? descId : undefined}\n tabIndex={-1}\n style={style as CSSProperties}\n {...props}\n >\n {hasHeader && (\n <div className={clsx(styles.header, headerDivided && styles.headerDivided)}>\n <div className={styles.headerMain}>\n {renderedIcon != null && (\n <IconButton\n variant=\"filled\"\n size=\"sm\"\n color={color}\n nonClickable\n aria-hidden\n className={styles.icon}\n >\n {renderedIcon}\n </IconButton>\n )}\n {(title != null || description != null) && (\n <div className={styles.headerText}>\n {title != null && (\n <div id={titleId} className={styles.title}>\n {title}\n </div>\n )}\n {description != null && (\n <div id={descId} className={styles.subtitle}>\n {description}\n </div>\n )}\n </div>\n )}\n </div>\n {showCloseButton && (\n <IconButton\n variant=\"filled\"\n color=\"primary\"\n size=\"sm\"\n className={styles.close}\n aria-label={t('common.close')}\n onClick={onClose}\n >\n <Icon name=\"Close\" />\n </IconButton>\n )}\n </div>\n )}\n {children != null && (\n <div ref={bodyRef} className={clsx(styles.body, bodyClassName)}>\n {children}\n </div>\n )}\n {footer != null && (\n <div ref={footerRef} className={styles.footer}>\n {footer}\n </div>\n )}\n </div>\n </Overlay>\n )\n})\n"],"names":["Overlay","forwardRef","open","onClose","closeOnBackdrop","closeOnEscape","lockScroll","dim","className","style","children","onKeyDown","onMouseDown","onClick","props","ref","mouseDownTarget","useRef","visible","setVisible","useState","useLockBodyScroll","useEffect","raf","handleKeyDown","event","handleMouseDown","handleClick","createPortal","jsx","clsx","styles","ICON_NAME_SET","ICON_NAMES","FOCUSABLE","FIELD","focusFirst","candidates","list","candidate","el","other","Modal","size","scrollBehavior","placement","title","description","icon","color","footer","bodyClassName","showCloseButton","ariaLabel","forwardedRef","t","useT","panelRef","bodyRef","footerRef","titleId","useId","descId","openerRef","wasOpenRef","panel","opener","_a","_b","setPanelRef","node","handleTabTrap","focusables","first","last","active","isDrawer","renderedIcon","Icon","hasHeader","headerDivided","jsxs","IconButton"],"mappings":"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"}