@techzyapp/ui-library 1.0.45 → 1.0.47

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 (392) hide show
  1. package/README.md +1 -1
  2. package/dist/AdminRoot-BRN_MlHp.cjs +2 -0
  3. package/dist/AdminRoot-BRN_MlHp.cjs.map +1 -0
  4. package/dist/AdminRoot-CtqPtYxo.js +107 -0
  5. package/dist/AdminRoot-CtqPtYxo.js.map +1 -0
  6. package/dist/{Alert-BU7GlQna.js → Alert-Bo_XgY-A.js} +3 -3
  7. package/dist/{Alert-BU7GlQna.js.map → Alert-Bo_XgY-A.js.map} +1 -1
  8. package/dist/{Alert-CVQOjuEq.cjs → Alert-QvfNBhlU.cjs} +2 -2
  9. package/dist/{Alert-CVQOjuEq.cjs.map → Alert-QvfNBhlU.cjs.map} +1 -1
  10. package/dist/AuthGuard-CAaQZ2y7.cjs +2 -0
  11. package/dist/AuthGuard-CAaQZ2y7.cjs.map +1 -0
  12. package/dist/AuthGuard-vqKf2PF9.js +102 -0
  13. package/dist/AuthGuard-vqKf2PF9.js.map +1 -0
  14. package/dist/{Breadcrumbs-BMz_YVPa.js → Breadcrumbs-BEv57tuJ.js} +3 -3
  15. package/dist/{Breadcrumbs-BMz_YVPa.js.map → Breadcrumbs-BEv57tuJ.js.map} +1 -1
  16. package/dist/{Breadcrumbs-BbC0o4JE.cjs → Breadcrumbs-CqGS32x5.cjs} +2 -2
  17. package/dist/{Breadcrumbs-BbC0o4JE.cjs.map → Breadcrumbs-CqGS32x5.cjs.map} +1 -1
  18. package/dist/{Button-mBZOvgyZ.cjs → Button-BtiFpRie.cjs} +2 -2
  19. package/dist/{Button-mBZOvgyZ.cjs.map → Button-BtiFpRie.cjs.map} +1 -1
  20. package/dist/{Button-C415LPw_.js → Button-DZWYeAno.js} +2 -2
  21. package/dist/{Button-C415LPw_.js.map → Button-DZWYeAno.js.map} +1 -1
  22. package/dist/{Calendar-B0f6h9-A.js → Calendar-7W9xNVBZ.js} +3 -3
  23. package/dist/{Calendar-B0f6h9-A.js.map → Calendar-7W9xNVBZ.js.map} +1 -1
  24. package/dist/{Calendar-hO051hfk.cjs → Calendar-Bgh_3Vk2.cjs} +2 -2
  25. package/dist/{Calendar-hO051hfk.cjs.map → Calendar-Bgh_3Vk2.cjs.map} +1 -1
  26. package/dist/{Card-BdNr5row.cjs → Card-KfmWG9Uz.cjs} +2 -2
  27. package/dist/{Card-BdNr5row.cjs.map → Card-KfmWG9Uz.cjs.map} +1 -1
  28. package/dist/{Card-ssUNaOF_.js → Card-ckOd617g.js} +3 -3
  29. package/dist/{Card-ssUNaOF_.js.map → Card-ckOd617g.js.map} +1 -1
  30. package/dist/{Chip-BpJN4rzY.cjs → Chip-BDUsue_R.cjs} +2 -2
  31. package/dist/{Chip-BpJN4rzY.cjs.map → Chip-BDUsue_R.cjs.map} +1 -1
  32. package/dist/{Chip-C0x-6g2h.js → Chip-Crzm7Eux.js} +2 -2
  33. package/dist/{Chip-C0x-6g2h.js.map → Chip-Crzm7Eux.js.map} +1 -1
  34. package/dist/{CodeBlock-DKnWINdV.js → CodeBlock-CX8_dMPD.js} +3 -3
  35. package/dist/{CodeBlock-DKnWINdV.js.map → CodeBlock-CX8_dMPD.js.map} +1 -1
  36. package/dist/{CodeBlock-DTrzN95i.cjs → CodeBlock-rnGAu2DQ.cjs} +2 -2
  37. package/dist/{CodeBlock-DTrzN95i.cjs.map → CodeBlock-rnGAu2DQ.cjs.map} +1 -1
  38. package/dist/{ColorPicker-Doaegll4.cjs → ColorPicker-BaAdcqR9.cjs} +2 -2
  39. package/dist/{ColorPicker-Doaegll4.cjs.map → ColorPicker-BaAdcqR9.cjs.map} +1 -1
  40. package/dist/{ColorPicker-Bidev2DJ.js → ColorPicker-CwLivdAt.js} +3 -3
  41. package/dist/{ColorPicker-Bidev2DJ.js.map → ColorPicker-CwLivdAt.js.map} +1 -1
  42. package/dist/{ColorPickerPanel-DThSuUoz.js → ColorPickerPanel-CkrSIf35.js} +2 -2
  43. package/dist/{ColorPickerPanel-DThSuUoz.js.map → ColorPickerPanel-CkrSIf35.js.map} +1 -1
  44. package/dist/{ColorPickerPanel-048Fj7wv.cjs → ColorPickerPanel-IOhJJF1R.cjs} +2 -2
  45. package/dist/{ColorPickerPanel-048Fj7wv.cjs.map → ColorPickerPanel-IOhJJF1R.cjs.map} +1 -1
  46. package/dist/{ColorRamp-CGw4D9bf.cjs → ColorRamp-BCy8a7ks.cjs} +2 -2
  47. package/dist/{ColorRamp-CGw4D9bf.cjs.map → ColorRamp-BCy8a7ks.cjs.map} +1 -1
  48. package/dist/{ColorRamp-Reb0q69d.js → ColorRamp-DbFOsspz.js} +2 -2
  49. package/dist/{ColorRamp-Reb0q69d.js.map → ColorRamp-DbFOsspz.js.map} +1 -1
  50. package/dist/ConfigProvider-CYSpuSMJ.cjs +2 -0
  51. package/dist/ConfigProvider-CYSpuSMJ.cjs.map +1 -0
  52. package/dist/ConfigProvider-DtyUlWk6.js +394 -0
  53. package/dist/ConfigProvider-DtyUlWk6.js.map +1 -0
  54. package/dist/{CopyButton-Cnab62vt.cjs → CopyButton-DUG5s3TM.cjs} +2 -2
  55. package/dist/{CopyButton-Cnab62vt.cjs.map → CopyButton-DUG5s3TM.cjs.map} +1 -1
  56. package/dist/{CopyButton-Dm8-V4ku.js → CopyButton-LURMuaYw.js} +3 -3
  57. package/dist/{CopyButton-Dm8-V4ku.js.map → CopyButton-LURMuaYw.js.map} +1 -1
  58. package/dist/{DatePicker-CaGeW_-j.cjs → DatePicker-Bw9gLB8o.cjs} +2 -2
  59. package/dist/{DatePicker-CaGeW_-j.cjs.map → DatePicker-Bw9gLB8o.cjs.map} +1 -1
  60. package/dist/{DatePicker-C4MTCmDn.js → DatePicker-CSIBYSZt.js} +4 -4
  61. package/dist/{DatePicker-C4MTCmDn.js.map → DatePicker-CSIBYSZt.js.map} +1 -1
  62. package/dist/{DateTimePicker-B0CjHKPV.js → DateTimePicker-C9F2yJMf.js} +7 -7
  63. package/dist/{DateTimePicker-B0CjHKPV.js.map → DateTimePicker-C9F2yJMf.js.map} +1 -1
  64. package/dist/{DateTimePicker-DXKaAYey.cjs → DateTimePicker-kikKdt0F.cjs} +2 -2
  65. package/dist/{DateTimePicker-DXKaAYey.cjs.map → DateTimePicker-kikKdt0F.cjs.map} +1 -1
  66. package/dist/{DescriptionList-BSDwobDc.cjs → DescriptionList-DnGkHdzT.cjs} +2 -2
  67. package/dist/{DescriptionList-BSDwobDc.cjs.map → DescriptionList-DnGkHdzT.cjs.map} +1 -1
  68. package/dist/{DescriptionList-BkUS5egS.js → DescriptionList-kfNXbf_D.js} +4 -4
  69. package/dist/{DescriptionList-BkUS5egS.js.map → DescriptionList-kfNXbf_D.js.map} +1 -1
  70. package/dist/{EmptyState-CkkFHKrh.cjs → EmptyState-BM5LrRLq.cjs} +2 -2
  71. package/dist/{EmptyState-CkkFHKrh.cjs.map → EmptyState-BM5LrRLq.cjs.map} +1 -1
  72. package/dist/{EmptyState-DXoaPC7o.js → EmptyState-DrSj2XV_.js} +2 -2
  73. package/dist/{EmptyState-DXoaPC7o.js.map → EmptyState-DrSj2XV_.js.map} +1 -1
  74. package/dist/{ErrorBoundary-CSP_Ctg6.js → ErrorBoundary-DsP4hO_V.js} +3 -3
  75. package/dist/{ErrorBoundary-CSP_Ctg6.js.map → ErrorBoundary-DsP4hO_V.js.map} +1 -1
  76. package/dist/{ErrorBoundary-tZjKtO28.cjs → ErrorBoundary-yz669VEu.cjs} +2 -2
  77. package/dist/{ErrorBoundary-tZjKtO28.cjs.map → ErrorBoundary-yz669VEu.cjs.map} +1 -1
  78. package/dist/{ErrorState-JH4JdrTI.cjs → ErrorState-BThPIYaM.cjs} +2 -2
  79. package/dist/{ErrorState-JH4JdrTI.cjs.map → ErrorState-BThPIYaM.cjs.map} +1 -1
  80. package/dist/{ErrorState-WYsly5-i.js → ErrorState-DEngucdq.js} +7 -7
  81. package/dist/{ErrorState-WYsly5-i.js.map → ErrorState-DEngucdq.js.map} +1 -1
  82. package/dist/{FileCard-D4TB3qGG.js → FileCard-CmCESTQd.js} +3 -3
  83. package/dist/{FileCard-D4TB3qGG.js.map → FileCard-CmCESTQd.js.map} +1 -1
  84. package/dist/{FileCard-BIfPqeek.cjs → FileCard-wxDT2rj9.cjs} +2 -2
  85. package/dist/{FileCard-BIfPqeek.cjs.map → FileCard-wxDT2rj9.cjs.map} +1 -1
  86. package/dist/{FileUploader-YE_DfTNC.cjs → FileUploader-DBNRp5eT.cjs} +2 -2
  87. package/dist/{FileUploader-YE_DfTNC.cjs.map → FileUploader-DBNRp5eT.cjs.map} +1 -1
  88. package/dist/{FileUploader-DPVF76Ha.js → FileUploader-Dp1r4Sxc.js} +29 -29
  89. package/dist/{FileUploader-DPVF76Ha.js.map → FileUploader-Dp1r4Sxc.js.map} +1 -1
  90. package/dist/{FullscreenToggle-ipX55Nj4.cjs → FullscreenToggle-DVdQriWB.cjs} +2 -2
  91. package/dist/{FullscreenToggle-ipX55Nj4.cjs.map → FullscreenToggle-DVdQriWB.cjs.map} +1 -1
  92. package/dist/{FullscreenToggle-CxwGPLdd.js → FullscreenToggle-WGsbE3Op.js} +3 -3
  93. package/dist/{FullscreenToggle-CxwGPLdd.js.map → FullscreenToggle-WGsbE3Op.js.map} +1 -1
  94. package/dist/{IconButton-U_sr2Ahy.cjs → IconButton-DSPdv-oI.cjs} +2 -2
  95. package/dist/{IconButton-U_sr2Ahy.cjs.map → IconButton-DSPdv-oI.cjs.map} +1 -1
  96. package/dist/{IconButton-re6xITGO.js → IconButton-iWbUJAz7.js} +2 -2
  97. package/dist/{IconButton-re6xITGO.js.map → IconButton-iWbUJAz7.js.map} +1 -1
  98. package/dist/{ImageEditor-BwrG1fk7.js → ImageEditor-BDNys8pq.js} +5 -5
  99. package/dist/{ImageEditor-BwrG1fk7.js.map → ImageEditor-BDNys8pq.js.map} +1 -1
  100. package/dist/{ImageEditor-1n50vo_v.cjs → ImageEditor-C40dp2-V.cjs} +2 -2
  101. package/dist/{ImageEditor-1n50vo_v.cjs.map → ImageEditor-C40dp2-V.cjs.map} +1 -1
  102. package/dist/{Loader-7v1QBvHY.js → Loader-DD1vfqmN.js} +2 -2
  103. package/dist/{Loader-7v1QBvHY.js.map → Loader-DD1vfqmN.js.map} +1 -1
  104. package/dist/{Loader-BE3SQr7W.cjs → Loader-RyFTP2X5.cjs} +2 -2
  105. package/dist/{Loader-BE3SQr7W.cjs.map → Loader-RyFTP2X5.cjs.map} +1 -1
  106. package/dist/{LocationPicker-CVJ4jVn2.cjs → LocationPicker-B594f0bz.cjs} +2 -2
  107. package/dist/{LocationPicker-CVJ4jVn2.cjs.map → LocationPicker-B594f0bz.cjs.map} +1 -1
  108. package/dist/{LocationPicker-BvKtZFq0.js → LocationPicker-DpmYaYyd.js} +6 -6
  109. package/dist/{LocationPicker-BvKtZFq0.js.map → LocationPicker-DpmYaYyd.js.map} +1 -1
  110. package/dist/{Modal-CxODxl81.cjs → Modal-7cCok6fV.cjs} +2 -2
  111. package/dist/{Modal-CxODxl81.cjs.map → Modal-7cCok6fV.cjs.map} +1 -1
  112. package/dist/{Modal-DpoiMMM3.js → Modal-DVGTD2Ck.js} +3 -3
  113. package/dist/{Modal-DpoiMMM3.js.map → Modal-DVGTD2Ck.js.map} +1 -1
  114. package/dist/{MultiSelect-B7KwEhL5.js → MultiSelect-D-X833xt.js} +4 -4
  115. package/dist/{MultiSelect-B7KwEhL5.js.map → MultiSelect-D-X833xt.js.map} +1 -1
  116. package/dist/{MultiSelect-2GouMRTl.cjs → MultiSelect-DTKNjUDH.cjs} +2 -2
  117. package/dist/{MultiSelect-2GouMRTl.cjs.map → MultiSelect-DTKNjUDH.cjs.map} +1 -1
  118. package/dist/{NumberField-ThojS4K3.js → NumberField-OPOl0Yph.js} +3 -3
  119. package/dist/{NumberField-ThojS4K3.js.map → NumberField-OPOl0Yph.js.map} +1 -1
  120. package/dist/{NumberField-o2z2QNK1.cjs → NumberField-Xz4yQMlm.cjs} +2 -2
  121. package/dist/{NumberField-o2z2QNK1.cjs.map → NumberField-Xz4yQMlm.cjs.map} +1 -1
  122. package/dist/{OtpField-C3MlMZ2F.js → OtpField-CLrDMNtS.js} +2 -2
  123. package/dist/{OtpField-C3MlMZ2F.js.map → OtpField-CLrDMNtS.js.map} +1 -1
  124. package/dist/{OtpField-BhZq44vV.cjs → OtpField-kd0YghZq.cjs} +2 -2
  125. package/dist/{OtpField-BhZq44vV.cjs.map → OtpField-kd0YghZq.cjs.map} +1 -1
  126. package/dist/{PageError-63Gk6fVC.js → PageError-BIiZDzey.js} +5 -5
  127. package/dist/{PageError-63Gk6fVC.js.map → PageError-BIiZDzey.js.map} +1 -1
  128. package/dist/{PageError-CCKWbrc5.cjs → PageError-v6MAH_OL.cjs} +2 -2
  129. package/dist/{PageError-CCKWbrc5.cjs.map → PageError-v6MAH_OL.cjs.map} +1 -1
  130. package/dist/{PageLayout-BekkDBtT.js → PageLayout-BjaPfXvb.js} +4 -4
  131. package/dist/{PageLayout-BekkDBtT.js.map → PageLayout-BjaPfXvb.js.map} +1 -1
  132. package/dist/{PageLayout-CDPUYu6A.cjs → PageLayout-DH3jochw.cjs} +2 -2
  133. package/dist/{PageLayout-CDPUYu6A.cjs.map → PageLayout-DH3jochw.cjs.map} +1 -1
  134. package/dist/{PageNotFound-BD3zX3cd.js → PageNotFound-C1oSsMG-.js} +5 -5
  135. package/dist/{PageNotFound-BD3zX3cd.js.map → PageNotFound-C1oSsMG-.js.map} +1 -1
  136. package/dist/{PageNotFound-CTR6htwa.cjs → PageNotFound-Cse4bROv.cjs} +2 -2
  137. package/dist/{PageNotFound-CTR6htwa.cjs.map → PageNotFound-Cse4bROv.cjs.map} +1 -1
  138. package/dist/{Pagination-qKjISBJ9.js → Pagination-BNJdqcu4.js} +2 -2
  139. package/dist/{Pagination-qKjISBJ9.js.map → Pagination-BNJdqcu4.js.map} +1 -1
  140. package/dist/{Pagination-BJvLUjQ0.cjs → Pagination-DkmfEmgK.cjs} +2 -2
  141. package/dist/{Pagination-BJvLUjQ0.cjs.map → Pagination-DkmfEmgK.cjs.map} +1 -1
  142. package/dist/{PaletteField-y8KpR4Ap.js → PaletteField-Cdky6Zka.js} +3 -3
  143. package/dist/{PaletteField-y8KpR4Ap.js.map → PaletteField-Cdky6Zka.js.map} +1 -1
  144. package/dist/{PaletteField-CDS9CJW9.cjs → PaletteField-DqZl1mK0.cjs} +2 -2
  145. package/dist/{PaletteField-CDS9CJW9.cjs.map → PaletteField-DqZl1mK0.cjs.map} +1 -1
  146. package/dist/{PhoneField-OjsuevPx.js → PhoneField-DmFaJJEa.js} +4 -4
  147. package/dist/{PhoneField-OjsuevPx.js.map → PhoneField-DmFaJJEa.js.map} +1 -1
  148. package/dist/{PhoneField-Df3J6Hhg.cjs → PhoneField-jq-3_i_b.cjs} +2 -2
  149. package/dist/{PhoneField-Df3J6Hhg.cjs.map → PhoneField-jq-3_i_b.cjs.map} +1 -1
  150. package/dist/{Popconfirm-aCyniPnH.js → Popconfirm-D-8ZG2WR.js} +3 -3
  151. package/dist/{Popconfirm-aCyniPnH.js.map → Popconfirm-D-8ZG2WR.js.map} +1 -1
  152. package/dist/{Popconfirm-BKzJ_EZy.cjs → Popconfirm-KOE9gGi6.cjs} +2 -2
  153. package/dist/{Popconfirm-BKzJ_EZy.cjs.map → Popconfirm-KOE9gGi6.cjs.map} +1 -1
  154. package/dist/{Progress-DWOoLd8u.cjs → Progress-7EyhPtnu.cjs} +2 -2
  155. package/dist/{Progress-DWOoLd8u.cjs.map → Progress-7EyhPtnu.cjs.map} +1 -1
  156. package/dist/{Progress-DzxbkcaD.js → Progress-CdX666FP.js} +2 -2
  157. package/dist/{Progress-DzxbkcaD.js.map → Progress-CdX666FP.js.map} +1 -1
  158. package/dist/{QrCode-C8uAPiHq.cjs → QrCode-ClIJjjvF.cjs} +2 -2
  159. package/dist/{QrCode-C8uAPiHq.cjs.map → QrCode-ClIJjjvF.cjs.map} +1 -1
  160. package/dist/{QrCode-DaJYqBc1.js → QrCode-D7ocSDi7.js} +2 -2
  161. package/dist/{QrCode-DaJYqBc1.js.map → QrCode-D7ocSDi7.js.map} +1 -1
  162. package/dist/{RemoveDialog-MhEU5Zl3.js → RemoveDialog-DTzRPLaT.js} +5 -5
  163. package/dist/{RemoveDialog-MhEU5Zl3.js.map → RemoveDialog-DTzRPLaT.js.map} +1 -1
  164. package/dist/{RemoveDialog-BnOtR6-q.cjs → RemoveDialog-UsSX5z8Y.cjs} +2 -2
  165. package/dist/{RemoveDialog-BnOtR6-q.cjs.map → RemoveDialog-UsSX5z8Y.cjs.map} +1 -1
  166. package/dist/{RichTextEditor-zkoxujnO.js → RichTextEditor-BMctlkVC.js} +7 -7
  167. package/dist/{RichTextEditor-zkoxujnO.js.map → RichTextEditor-BMctlkVC.js.map} +1 -1
  168. package/dist/{RichTextEditor-Cnrnvv1f.cjs → RichTextEditor-Bh0Q3dIW.cjs} +2 -2
  169. package/dist/{RichTextEditor-Cnrnvv1f.cjs.map → RichTextEditor-Bh0Q3dIW.cjs.map} +1 -1
  170. package/dist/{RootLayout-Z9PuRfsa.cjs → RootLayout-BztZetpk.cjs} +2 -2
  171. package/dist/{RootLayout-Z9PuRfsa.cjs.map → RootLayout-BztZetpk.cjs.map} +1 -1
  172. package/dist/{RootLayout-C4r9i5Go.js → RootLayout-CTkv4iQJ.js} +14 -14
  173. package/dist/{RootLayout-C4r9i5Go.js.map → RootLayout-CTkv4iQJ.js.map} +1 -1
  174. package/dist/{Select-CylqFHce.cjs → Select-BzVyK6Ne.cjs} +2 -2
  175. package/dist/{Select-CylqFHce.cjs.map → Select-BzVyK6Ne.cjs.map} +1 -1
  176. package/dist/{Select-jT94L1vq.js → Select-CmonDIIU.js} +3 -3
  177. package/dist/{Select-jT94L1vq.js.map → Select-CmonDIIU.js.map} +1 -1
  178. package/dist/{Sidebar-B1O2RsbR.js → Sidebar-CLr-DyQ_.js} +3 -3
  179. package/dist/{Sidebar-B1O2RsbR.js.map → Sidebar-CLr-DyQ_.js.map} +1 -1
  180. package/dist/{Sidebar-Bcm0fgVm.cjs → Sidebar-CM-jZfj5.cjs} +2 -2
  181. package/dist/{Sidebar-Bcm0fgVm.cjs.map → Sidebar-CM-jZfj5.cjs.map} +1 -1
  182. package/dist/{Slider-DC-ugZwT.js → Slider-C7Wb3q_F.js} +2 -2
  183. package/dist/{Slider-DC-ugZwT.js.map → Slider-C7Wb3q_F.js.map} +1 -1
  184. package/dist/{Slider-CV7ug0WF.cjs → Slider-Oe9VSAdy.cjs} +2 -2
  185. package/dist/{Slider-CV7ug0WF.cjs.map → Slider-Oe9VSAdy.cjs.map} +1 -1
  186. package/dist/{SpeedDial-C6yiMUe8.js → SpeedDial-CCGQlwn2.js} +2 -2
  187. package/dist/{SpeedDial-C6yiMUe8.js.map → SpeedDial-CCGQlwn2.js.map} +1 -1
  188. package/dist/{SpeedDial-DOgm2DDX.cjs → SpeedDial-DpIXoYHB.cjs} +2 -2
  189. package/dist/{SpeedDial-DOgm2DDX.cjs.map → SpeedDial-DpIXoYHB.cjs.map} +1 -1
  190. package/dist/{Stepper-BZdYGpBN.js → Stepper-D_WKS1RG.js} +2 -2
  191. package/dist/{Stepper-BZdYGpBN.js.map → Stepper-D_WKS1RG.js.map} +1 -1
  192. package/dist/{Stepper-DqM86TGV.cjs → Stepper-PBDU60G_.cjs} +2 -2
  193. package/dist/{Stepper-DqM86TGV.cjs.map → Stepper-PBDU60G_.cjs.map} +1 -1
  194. package/dist/{Table-BgaCwRDQ.cjs → Table-CZ4n4-TN.cjs} +2 -2
  195. package/dist/{Table-BgaCwRDQ.cjs.map → Table-CZ4n4-TN.cjs.map} +1 -1
  196. package/dist/{Table-FZlVWoYi.js → Table-DZQVa_PE.js} +16 -16
  197. package/dist/{Table-FZlVWoYi.js.map → Table-DZQVa_PE.js.map} +1 -1
  198. package/dist/{Tabs-BqQPkorY.js → Tabs-B063mP-v.js} +12 -12
  199. package/dist/{Tabs-BqQPkorY.js.map → Tabs-B063mP-v.js.map} +1 -1
  200. package/dist/{Tabs-kGeyFhJ6.cjs → Tabs-Byhqm-TE.cjs} +2 -2
  201. package/dist/{Tabs-kGeyFhJ6.cjs.map → Tabs-Byhqm-TE.cjs.map} +1 -1
  202. package/dist/{TagsField-B_sjp48X.cjs → TagsField-g_LtwYgz.cjs} +2 -2
  203. package/dist/{TagsField-B_sjp48X.cjs.map → TagsField-g_LtwYgz.cjs.map} +1 -1
  204. package/dist/{TagsField-ByTx9JXK.js → TagsField-hQFYyNcM.js} +4 -4
  205. package/dist/{TagsField-ByTx9JXK.js.map → TagsField-hQFYyNcM.js.map} +1 -1
  206. package/dist/{TextField-CBYJIfau.cjs → TextField-D4s2hGSd.cjs} +2 -2
  207. package/dist/{TextField-CBYJIfau.cjs.map → TextField-D4s2hGSd.cjs.map} +1 -1
  208. package/dist/{TextField-CyKIx-d-.js → TextField-Dfpk0jOg.js} +3 -3
  209. package/dist/{TextField-CyKIx-d-.js.map → TextField-Dfpk0jOg.js.map} +1 -1
  210. package/dist/{ThemeToggle-Dg6IishB.js → ThemeToggle-BQQ3eswr.js} +7 -7
  211. package/dist/{ThemeToggle-Dg6IishB.js.map → ThemeToggle-BQQ3eswr.js.map} +1 -1
  212. package/dist/{ThemeToggle-D2dIqiBa.cjs → ThemeToggle-BTTI7Jz0.cjs} +2 -2
  213. package/dist/{ThemeToggle-D2dIqiBa.cjs.map → ThemeToggle-BTTI7Jz0.cjs.map} +1 -1
  214. package/dist/{TimeColumns-Cx8J5qzW.js → TimeColumns-BpjhrNCq.js} +2 -2
  215. package/dist/{TimeColumns-Cx8J5qzW.js.map → TimeColumns-BpjhrNCq.js.map} +1 -1
  216. package/dist/{TimeColumns-DVmK_T_P.cjs → TimeColumns-DZYGWWG_.cjs} +2 -2
  217. package/dist/{TimeColumns-DVmK_T_P.cjs.map → TimeColumns-DZYGWWG_.cjs.map} +1 -1
  218. package/dist/{TimePicker-0nZOPRKp.cjs → TimePicker-DChtZgBs.cjs} +2 -2
  219. package/dist/{TimePicker-0nZOPRKp.cjs.map → TimePicker-DChtZgBs.cjs.map} +1 -1
  220. package/dist/{TimePicker-sAhtvqQ4.js → TimePicker-mzoMIlpq.js} +5 -5
  221. package/dist/{TimePicker-sAhtvqQ4.js.map → TimePicker-mzoMIlpq.js.map} +1 -1
  222. package/dist/{Toaster-BOW9rzLq.js → Toaster-79DvOW80.js} +8 -8
  223. package/dist/{Toaster-BOW9rzLq.js.map → Toaster-79DvOW80.js.map} +1 -1
  224. package/dist/{Toaster-DYGo92ke.cjs → Toaster-lonArt-H.cjs} +2 -2
  225. package/dist/{Toaster-DYGo92ke.cjs.map → Toaster-lonArt-H.cjs.map} +1 -1
  226. package/dist/{TranslatedFields-C_DuLotV.cjs → TranslatedFields-BYpMrYaw.cjs} +2 -2
  227. package/dist/{TranslatedFields-C_DuLotV.cjs.map → TranslatedFields-BYpMrYaw.cjs.map} +1 -1
  228. package/dist/{TranslatedFields-CcE0td9p.js → TranslatedFields-CHHtXO_n.js} +9 -9
  229. package/dist/{TranslatedFields-CcE0td9p.js.map → TranslatedFields-CHHtXO_n.js.map} +1 -1
  230. package/dist/{UserCard-DeONbaKj.js → UserCard-BJFNP_nl.js} +3 -3
  231. package/dist/{UserCard-DeONbaKj.js.map → UserCard-BJFNP_nl.js.map} +1 -1
  232. package/dist/{UserCard-DLVptkLr.cjs → UserCard-SlkCgZS9.cjs} +2 -2
  233. package/dist/{UserCard-DLVptkLr.cjs.map → UserCard-SlkCgZS9.cjs.map} +1 -1
  234. package/dist/app/AdminRoot.d.cts +9 -4
  235. package/dist/app/AdminRoot.d.ts +9 -4
  236. package/dist/auth/AuthGuard.d.cts +9 -3
  237. package/dist/auth/AuthGuard.d.ts +9 -3
  238. package/dist/auth/authLayoutRoute.d.cts +11 -3
  239. package/dist/auth/authLayoutRoute.d.ts +11 -3
  240. package/dist/auth/authRedirect.d.cts +64 -0
  241. package/dist/auth/authRedirect.d.ts +64 -0
  242. package/dist/authLayoutRoute-DCG9gCZ8.cjs +2 -0
  243. package/dist/authLayoutRoute-DCG9gCZ8.cjs.map +1 -0
  244. package/dist/authLayoutRoute-TuEqVizw.js +15 -0
  245. package/dist/authLayoutRoute-TuEqVizw.js.map +1 -0
  246. package/dist/components/Alert/index.cjs +1 -1
  247. package/dist/components/Alert/index.js +1 -1
  248. package/dist/components/Breadcrumbs/index.cjs +1 -1
  249. package/dist/components/Breadcrumbs/index.js +1 -1
  250. package/dist/components/Button/index.cjs +1 -1
  251. package/dist/components/Button/index.js +1 -1
  252. package/dist/components/Card/index.cjs +1 -1
  253. package/dist/components/Card/index.js +1 -1
  254. package/dist/components/Chip/index.cjs +1 -1
  255. package/dist/components/Chip/index.js +1 -1
  256. package/dist/components/CodeBlock/index.cjs +1 -1
  257. package/dist/components/CodeBlock/index.js +1 -1
  258. package/dist/components/ColorPicker/index.cjs +1 -1
  259. package/dist/components/ColorPicker/index.js +1 -1
  260. package/dist/components/ColorRamp/index.cjs +1 -1
  261. package/dist/components/ColorRamp/index.js +1 -1
  262. package/dist/components/CopyButton/index.cjs +1 -1
  263. package/dist/components/CopyButton/index.js +1 -1
  264. package/dist/components/DatePicker/index.cjs +1 -1
  265. package/dist/components/DatePicker/index.js +1 -1
  266. package/dist/components/DateTimePicker/index.cjs +1 -1
  267. package/dist/components/DateTimePicker/index.js +1 -1
  268. package/dist/components/DescriptionList/index.cjs +1 -1
  269. package/dist/components/DescriptionList/index.js +1 -1
  270. package/dist/components/EmptyState/index.cjs +1 -1
  271. package/dist/components/EmptyState/index.js +1 -1
  272. package/dist/components/ErrorState/index.cjs +1 -1
  273. package/dist/components/ErrorState/index.js +2 -2
  274. package/dist/components/FileCard/index.cjs +1 -1
  275. package/dist/components/FileCard/index.js +1 -1
  276. package/dist/components/FileUploader/index.cjs +1 -1
  277. package/dist/components/FileUploader/index.js +1 -1
  278. package/dist/components/FullscreenToggle/index.cjs +1 -1
  279. package/dist/components/FullscreenToggle/index.js +1 -1
  280. package/dist/components/IconButton/index.cjs +1 -1
  281. package/dist/components/IconButton/index.js +1 -1
  282. package/dist/components/ImageEditor/index.cjs +1 -1
  283. package/dist/components/ImageEditor/index.js +1 -1
  284. package/dist/components/Loader/index.cjs +1 -1
  285. package/dist/components/Loader/index.js +1 -1
  286. package/dist/components/LocationPicker/index.cjs +1 -1
  287. package/dist/components/LocationPicker/index.js +1 -1
  288. package/dist/components/Modal/index.cjs +1 -1
  289. package/dist/components/Modal/index.js +1 -1
  290. package/dist/components/MultiSelect/index.cjs +1 -1
  291. package/dist/components/MultiSelect/index.js +1 -1
  292. package/dist/components/NumberField/index.cjs +1 -1
  293. package/dist/components/NumberField/index.js +1 -1
  294. package/dist/components/OtpField/index.cjs +1 -1
  295. package/dist/components/OtpField/index.js +1 -1
  296. package/dist/components/PageError/index.cjs +1 -1
  297. package/dist/components/PageError/index.js +1 -1
  298. package/dist/components/PageLayout/index.cjs +1 -1
  299. package/dist/components/PageLayout/index.js +1 -1
  300. package/dist/components/PageNotFound/index.cjs +1 -1
  301. package/dist/components/PageNotFound/index.js +1 -1
  302. package/dist/components/Pagination/index.cjs +1 -1
  303. package/dist/components/Pagination/index.js +1 -1
  304. package/dist/components/PaletteField/index.cjs +1 -1
  305. package/dist/components/PaletteField/index.js +1 -1
  306. package/dist/components/PhoneField/index.cjs +1 -1
  307. package/dist/components/PhoneField/index.js +1 -1
  308. package/dist/components/Popconfirm/index.cjs +1 -1
  309. package/dist/components/Popconfirm/index.js +1 -1
  310. package/dist/components/Progress/index.cjs +1 -1
  311. package/dist/components/Progress/index.js +1 -1
  312. package/dist/components/QrCode/index.cjs +1 -1
  313. package/dist/components/QrCode/index.js +1 -1
  314. package/dist/components/RemoveDialog/index.cjs +1 -1
  315. package/dist/components/RemoveDialog/index.js +1 -1
  316. package/dist/components/RichTextEditor/index.cjs +1 -1
  317. package/dist/components/RichTextEditor/index.js +1 -1
  318. package/dist/components/RootLayout/index.cjs +1 -1
  319. package/dist/components/RootLayout/index.js +1 -1
  320. package/dist/components/Select/index.cjs +1 -1
  321. package/dist/components/Select/index.js +1 -1
  322. package/dist/components/Sidebar/index.cjs +1 -1
  323. package/dist/components/Sidebar/index.js +1 -1
  324. package/dist/components/Slider/index.cjs +1 -1
  325. package/dist/components/Slider/index.js +1 -1
  326. package/dist/components/SpeedDial/index.cjs +1 -1
  327. package/dist/components/SpeedDial/index.js +1 -1
  328. package/dist/components/Stepper/index.cjs +1 -1
  329. package/dist/components/Stepper/index.js +1 -1
  330. package/dist/components/Table/index.cjs +1 -1
  331. package/dist/components/Table/index.js +1 -1
  332. package/dist/components/Tabs/index.cjs +1 -1
  333. package/dist/components/Tabs/index.js +1 -1
  334. package/dist/components/TagsField/index.cjs +1 -1
  335. package/dist/components/TagsField/index.js +1 -1
  336. package/dist/components/TextField/index.cjs +1 -1
  337. package/dist/components/TextField/index.js +1 -1
  338. package/dist/components/ThemeToggle/index.cjs +1 -1
  339. package/dist/components/ThemeToggle/index.js +1 -1
  340. package/dist/components/TimePicker/index.cjs +1 -1
  341. package/dist/components/TimePicker/index.js +1 -1
  342. package/dist/components/Toast/index.cjs +1 -1
  343. package/dist/components/Toast/index.js +1 -1
  344. package/dist/components/TranslatedFields/index.cjs +1 -1
  345. package/dist/components/TranslatedFields/index.js +1 -1
  346. package/dist/components/UserCard/index.cjs +1 -1
  347. package/dist/components/UserCard/index.js +1 -1
  348. package/dist/entries/app.cjs +1 -1
  349. package/dist/entries/app.js +1 -1
  350. package/dist/entries/auth.cjs +1 -1
  351. package/dist/entries/auth.d.cts +1 -0
  352. package/dist/entries/auth.d.ts +1 -0
  353. package/dist/entries/auth.js +7 -4
  354. package/dist/entries/components.cjs +1 -1
  355. package/dist/entries/components.js +52 -52
  356. package/dist/entries/i18n.cjs +1 -1
  357. package/dist/entries/i18n.js +1 -1
  358. package/dist/entries/theme.cjs +1 -1
  359. package/dist/entries/theme.d.cts +1 -1
  360. package/dist/entries/theme.d.ts +1 -1
  361. package/dist/entries/theme.js +20 -18
  362. package/dist/index.cjs +1 -1
  363. package/dist/index.js +259 -254
  364. package/dist/theme/ConfigProvider.d.cts +17 -0
  365. package/dist/theme/ConfigProvider.d.ts +17 -0
  366. package/dist/theme/index.d.cts +1 -1
  367. package/dist/theme/index.d.ts +1 -1
  368. package/dist/{useHomeTo-BL3e8Sc6.js → useHomeTo-BLSvhJd5.js} +2 -2
  369. package/dist/{useHomeTo-BL3e8Sc6.js.map → useHomeTo-BLSvhJd5.js.map} +1 -1
  370. package/dist/{useHomeTo-W1PDW5CU.cjs → useHomeTo-cXCg1tf0.cjs} +2 -2
  371. package/dist/{useHomeTo-W1PDW5CU.cjs.map → useHomeTo-cXCg1tf0.cjs.map} +1 -1
  372. package/dist/{useOptionMenu-CVl7VHXl.cjs → useOptionMenu-6ZffgbYG.cjs} +2 -2
  373. package/dist/{useOptionMenu-CVl7VHXl.cjs.map → useOptionMenu-6ZffgbYG.cjs.map} +1 -1
  374. package/dist/{useOptionMenu-BkKiZ6Ax.js → useOptionMenu-CxM6FHXL.js} +3 -3
  375. package/dist/{useOptionMenu-BkKiZ6Ax.js.map → useOptionMenu-CxM6FHXL.js.map} +1 -1
  376. package/package.json +1 -1
  377. package/dist/AdminRoot-BZ1v5vN9.js +0 -101
  378. package/dist/AdminRoot-BZ1v5vN9.js.map +0 -1
  379. package/dist/AdminRoot-DJ4-UMAB.cjs +0 -2
  380. package/dist/AdminRoot-DJ4-UMAB.cjs.map +0 -1
  381. package/dist/AuthGuard-CVklwDbj.js +0 -7
  382. package/dist/AuthGuard-CVklwDbj.js.map +0 -1
  383. package/dist/AuthGuard-kfOZviar.cjs +0 -2
  384. package/dist/AuthGuard-kfOZviar.cjs.map +0 -1
  385. package/dist/ConfigProvider-DBU6rOIA.cjs +0 -2
  386. package/dist/ConfigProvider-DBU6rOIA.cjs.map +0 -1
  387. package/dist/ConfigProvider-DVDGtCUc.js +0 -386
  388. package/dist/ConfigProvider-DVDGtCUc.js.map +0 -1
  389. package/dist/authLayoutRoute-B10sXioW.js +0 -11
  390. package/dist/authLayoutRoute-B10sXioW.js.map +0 -1
  391. package/dist/authLayoutRoute-BVQ4LhuU.cjs +0 -2
  392. package/dist/authLayoutRoute-BVQ4LhuU.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"FileUploader-DPVF76Ha.js","sources":["../src/components/FileUploader/FileUploaderEditDialog.tsx","../src/components/FileUploader/FileUploaderPreview.tsx","../src/components/FileUploader/FileUploader.tsx"],"sourcesContent":["import { useState, type ChangeEvent } from 'react'\nimport { useT, type LocaleConfig } from '../../theme'\nimport { Button } from '../Button'\nimport { Modal } from '../Modal'\nimport { TextField } from '../TextField'\nimport styles from './FileUploaderEditDialog.module.css'\n\n/** What the dialog hands back on Save. */\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}\n\nexport interface FileUploaderEditDialogProps {\n /** Display name (the modal description). */\n name: 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 alt-text draft. */\n onSave: (result: EditDialogResult) => void\n}\n\n/**\n * The FileUploader per-item **alt text** modal — one `TextField` per locale (stacked, no tabs). Built on\n * the library's `Modal` + `TextField`. (Cropping lives in the image editor — the card's Edit button.)\n * Internal — not exported.\n */\nexport function FileUploaderEditDialog({\n name,\n editLocales,\n initialDraft,\n onClose,\n onSave,\n}: FileUploaderEditDialogProps) {\n const t = useT()\n const [draft, setDraft] = useState<Record<string, string>>(initialDraft)\n\n return (\n <Modal\n open\n onClose={onClose}\n size=\"sm\"\n icon=\"Text\"\n title={t('fileUploader.altTitle')}\n description={name}\n footer={\n <>\n <Button variant=\"text\" color=\"accent\" size=\"sm\" onClick={onClose}>\n {t('common.cancel')}\n </Button>\n <Button size=\"sm\" onClick={() => onSave({ draft })}>\n {t('common.save')}\n </Button>\n </>\n }\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 </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'\nimport { ImageEditor } from '../ImageEditor/ImageEditor'\nimport type { ImageEditorResult, ImageState } from '../ImageEditor/core/types'\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 (JPEG / PNG / WebP items — see `isEditableImageItem`) that opens the\n * fullscreen `ImageEditor` — crop / rotate / flip, filters, finetune, redact and resize. **Done** replaces the item's file with the rendered image (a\n * source item becomes a fresh pick). Edits are **non-destructive**: re-opening an edited file continues\n * from the original with every setting restored; reverting everything and pressing Done hands back\n * the original. Defaults to `true`.\n */\n allowEdit?: boolean\n /**\n * Show a per-card **alt text** button (image items) 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 (stacked fields,\n * no tabs), 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 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 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 `.entering` (a plain\n// fade-in), so here `add` is a no-op to avoid double-animating; auto-animate still animates the `remove`\n// (a plain fade-out, no movement) and the `remain` reflow (rows sliding over 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 = [{ opacity: 1 }, { opacity: 0 }]\n } else if (el.classList.contains(styles.entering) || el.classList.contains(styles.list)) {\n // never slide a card that is still fading in, nor the list itself: the list's `populated` gap appears /\n // goes in the same render as the first pick / last removal and would read as a 16px vertical jump\n duration = 0\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/**\n * The ImageEditor's non-destructive memory: an edited File → its original (a File or a source URL) + the\n * edit state, so re-opening continues from the original. Module-level so it survives a remount (a form\n * tab switch); a WeakMap, so it never keeps a removed file alive.\n */\nconst imageEdits = new WeakMap<File, { original: File | string; state: ImageState }>()\n\n/** Whether an edit state changes nothing (so Done can hand back the original untouched). */\nexport function isUntouchedEdit(\n s: ImageState,\n size: { width: number; height: number } | null,\n): boolean {\n const near = (a: number, b: number) => Math.abs(a - b) < 0.5\n return (\n !!size &&\n near(s.crop.x, 0) &&\n near(s.crop.y, 0) &&\n near(s.crop.width, size.width) &&\n near(s.crop.height, size.height) &&\n Math.abs(s.rotation) < 1e-6 &&\n !s.flipX &&\n !s.flipY &&\n Math.abs(s.scale - 1) < 1e-6 &&\n !s.colorMatrix &&\n !s.resize &&\n !(s.redact?.amount > 0) &&\n Object.values(s.finetune).every((v) => v === 0)\n )\n}\n\n/** Give a file name the extension of `type` (`photo.png` + JPEG → `photo.jpg`); a match is kept. */\nexport function renameForType(name: string, type: string): string {\n const ext = { 'image/jpeg': 'jpg', 'image/png': 'png', 'image/webp': 'webp' }[type]\n if (!ext) return name\n const m = /^(.*?)(\\.[^.]+)?$/.exec(name)\n const base = m?.[1] || 'image'\n const cur = (m?.[2] ?? '').slice(1).toLowerCase()\n if (cur === ext || (ext === 'jpg' && cur === 'jpeg')) return name\n return `${base}.${ext}`\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 **alt-text** editor (a video / PDF / doc has\n * nothing to describe; the image editor narrows it further, see `isEditableImageItem`). 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/** The formats the image editor opens — the raster ones it also saves back as the same format. */\nconst EDITABLE_IMAGE_TYPES = new Set(['image/jpeg', 'image/jpg', 'image/png', 'image/webp'])\nconst EDITABLE_IMAGE_EXT = /\\.(jpe?g|png|webp)(?:[?#]|$)/i\n\n/**\n * Whether an item gets the image editor (the Edit button): a JPEG / PNG / WebP. Not an SVG (a vector — it\n * would come out a small PNG), a GIF (its animation would be lost), HEIC / TIFF / BMP / ICO (not every\n * browser decodes them, or the result changes format) and no non-image file. An extensionless URL (a CDN\n * image) can't be told apart, so it counts — as in `isImageItem`. (Exported for unit tests.)\n */\nexport const isEditableImageItem = (item: FileUploaderItem): boolean => {\n if (item.file) {\n const type = item.file.type.toLowerCase()\n // some systems hand over no MIME type — go by the name then\n return type ? EDITABLE_IMAGE_TYPES.has(type) : EDITABLE_IMAGE_EXT.test(item.file.name)\n }\n const src = item.source\n if (!src) return false\n const data = /^data:([^;,]+)/i.exec(src)\n if (data) return EDITABLE_IMAGE_TYPES.has(data[1].toLowerCase())\n return EDITABLE_IMAGE_EXT.test(src) || !/\\.[a-z0-9]{1,8}(?:[?#]|$)/i.test(src)\n}\n\n/**\n * Whether an `accept` map lets in images only (every key an `image/…` type) — the dropzone then shows an\n * image icon instead of a document one. (Exported for unit tests.)\n */\nexport const acceptsOnlyImages = (accept: Accept | undefined): boolean => {\n const types = accept ? Object.keys(accept) : []\n return types.length > 0 && types.every((t) => t.toLowerCase().startsWith('image/'))\n}\n\n/** Whether an item is a video — its card shows a muted `<video>` thumbnail (no controls) instead of an `<img>`; the Eye lightbox plays it. */\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 onEdit?: () => void\n onAltText?: () => void\n onDownload?: () => void\n onView?: () => void\n onPreviewError?: () => void\n /** The field's label, shown above the name (a single-file uploader once its file is picked). */\n fieldLabel?: ReactNode\n}\n\nfunction Row({\n id,\n item,\n preview,\n sortable,\n entering,\n disabled,\n error,\n onRemove,\n onEdit,\n onAltText,\n onDownload,\n onView,\n onPreviewError,\n fieldLabel,\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 !preview && styles.tileFile, // no media to show → the light file-card look (no dark scrims)\n sortable && styles.grabbable,\n entering && styles.entering,\n isDragging && styles.dragging,\n error && styles.tileError,\n fieldLabel != null && styles.tileLabeled,\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 // a non-media file (or a failed preview): a file badge carrying the extension (\"PDF\", \"DOCX\")\n <span className={styles.tileFallback} aria-hidden=\"true\">\n <span className={styles.fileBadge}>\n <Icon name=\"Document\" size=\"lg\" />\n {ext && <span className={styles.fileExt}>{ext.slice(1)}</span>}\n </span>\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 {fieldLabel != null && <span className={styles.tileLabel}>{fieldLabel}</span>}\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: edit (Magicpen) + alt text (Text) + download on the left (edit/alt are image-only),\n the view (Eye) fullscreen-preview button pinned bottom-right */}\n {(onEdit || onAltText || onDownload || onView) && (\n <div className={styles.tileBottom}>\n {onEdit && (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.edit', { name: label })}\n onClick={onEdit}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Magicpen\" 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 centered dropzone panel sits above a grid of image cards (thumbnail, or a file badge\n * with the extension for non-media files, + name + size, with overlaid remove + action 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 allowEdit = 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 fade-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 // ── the alt-text dialog (opened from a card's Text button) ─────────────────────────────────────────\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 editPos = editId != null ? ids.indexOf(editId) : -1\n const editingItem = editPos !== -1 ? items[editPos] : null\n const openAltEditor = (index: number) => setEditId(ids[index] ?? null)\n const closeEditor = () => setEditId(null)\n\n // ── the image editor (Edit) — non-destructive: an edited File remembers its original + the edit state ──\n const [imageEditId, setImageEditId] = useState<string | null>(null)\n const imageEditPos = imageEditId != null ? ids.indexOf(imageEditId) : -1\n const imageEditItem = imageEditPos !== -1 ? items[imageEditPos] : null\n const imageEditRecord = imageEditItem?.file ? imageEdits.get(imageEditItem.file) : undefined\n const imageEditSrc =\n imageEditRecord?.original ?? imageEditItem?.file ?? imageEditItem?.source ?? null\n const imageEditSize = useRef<{ width: number; height: number } | null>(null)\n // the value as of the latest render — Done resolves after an async render, during which it may change\n const latestItems = useRef({ items, ids })\n latestItems.current = { items, ids }\n const saveImageEdit = ({ dest, imageState }: ImageEditorResult) => {\n const { items, ids } = latestItems.current\n const pos = imageEditId != null ? ids.indexOf(imageEditId) : -1\n if (pos === -1) return // the item went away under us\n const item = items[pos]\n const record = item.file ? imageEdits.get(item.file) : undefined\n const original = record?.original || item.file || item.source || null\n if (!original) return\n const untouched = isUntouchedEdit(imageState, imageEditSize.current)\n // opened and closed with Done but nothing changed (and never edited before) — leave the value alone,\n // so the form doesn't turn dirty for nothing\n if (untouched && !record) return\n let next: FileUploaderItem\n if (untouched) {\n // everything reverted → hand back the original (no re-encode)\n const { file: _drop, ...rest } = item // eslint-disable-line @typescript-eslint/no-unused-vars\n next =\n typeof original === 'string'\n ? { ...rest, source: original }\n : { ...rest, file: original, source: '' }\n } else {\n // the rendered image replaces the item (a source item becomes a fresh pick that uploads on save)\n const file = new File([dest], renameForType(labelOf(item), dest.type), {\n type: dest.type,\n lastModified: Date.now(),\n })\n imageEdits.set(file, { original, state: imageState })\n next = { ...item, file, source: '' }\n }\n commit(items.map((it, i) => (i === pos ? next : it)))\n }\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 }: 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 // rebuild altText from the draft (localized record / single string)\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 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 || imageEditId != 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 // the label + required mark — the dropzone's title, or the single card's once the dropzone is gone\n const fieldTitle =\n label != null ? (\n <>\n {label}\n {required && (\n <span className={clsx(fieldStyles.required, styles.dropRequired)} aria-hidden=\"true\">\n *\n </span>\n )}\n </>\n ) : undefined\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 {/* the label is the dropzone's title while it shows (below); once it's gone (a single-file\n uploader with its file picked) the card carries it, in the same place — nothing shifts */}\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={acceptsOnlyImages(accept) ? 'GalleryExport' : 'Upload'} size=\"lg\" />\n </span>\n <span className={styles.dropText}>\n {fieldTitle && <span className={styles.dropTitle}>{fieldTitle}</span>}\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 // the image editor only opens the raster formats it saves back as-is (no SVG / GIF / …);\n // alt text is for any image — a video / PDF / doc has nothing to describe\n onEdit={\n allowEdit && !disabled && isEditableImageItem(item)\n ? () => setImageEditId(ids[index] ?? null)\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 fieldLabel={!showDropzone ? fieldTitle : undefined}\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}\n name={labelOf(editingItem)}\n editLocales={editLocales}\n initialDraft={editInitialDraft}\n onClose={closeEditor}\n onSave={saveEdit}\n />\n )}\n\n <ImageEditor\n open={imageEditItem != null && imageEditSrc != null}\n src={imageEditSrc}\n initialState={imageEditRecord?.state}\n onLoad={(size) => (imageEditSize.current = size)}\n onProcess={saveImageEdit}\n onClose={() => setImageEditId(null)}\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","name","editLocales","initialDraft","onClose","onSave","t","useT","draft","setDraft","useState","jsx","Modal","jsxs","Fragment","Button","styles","l","TextField","e","d","FileUploaderPreview","url","isVideo","isSvg","Overlay","Icon","clsx","canMakeObjectUrl","ANIM_MS","listAnimation","el","action","oldCoords","newCoords","keyframes","duration","dx","dy","imageEdits","isUntouchedEdit","s","size","near","a","b","_a","v","renameForType","type","ext","m","base","cur","formatBytes","bytes","units","value","i","toBytes","match","fileKey","file","itemKey","item","labelOf","isImageItem","src","EDITABLE_IMAGE_TYPES","EDITABLE_IMAGE_EXT","isEditableImageItem","data","acceptsOnlyImages","accept","types","isVideoItem","triggerDownload","splitName","dot","Row","id","preview","sortable","entering","disabled","error","onRemove","onEdit","onAltText","onDownload","onView","onPreviewError","fieldLabel","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","label","mediaLoaded","setMediaLoaded","lastPreview","useRef","mediaRef","useEffect","img","onMediaError","meta","video","downloadBtn","Skeleton","FileUploader","forwardRef","multiple","allowDrop","allowReorder","allowDownload","allowPreview","allowEdit","allowAltText","altTextLocales","localizedAltText","allowDuplicates","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","setPreview","cache","liveFiles","it","liveSources","next","reindex","arr","commit","ordered","out","markTouched","configLocales","useLocales","altLocales","editId","setEditId","editPos","editingItem","openAltEditor","closeEditor","imageEditId","setImageEditId","imageEditPos","imageEditItem","imageEditRecord","imageEditSrc","imageEditSize","latestItems","saveImageEdit","dest","imageState","pos","record","original","untouched","_drop","rest","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","fieldTitle","fieldStyles","DndContext","closestCenter","SortableContext","rectSortingStrategy","Typography","ImageEditor"],"mappings":"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"}
1
+ {"version":3,"file":"FileUploader-Dp1r4Sxc.js","sources":["../src/components/FileUploader/FileUploaderEditDialog.tsx","../src/components/FileUploader/FileUploaderPreview.tsx","../src/components/FileUploader/FileUploader.tsx"],"sourcesContent":["import { useState, type ChangeEvent } from 'react'\nimport { useT, type LocaleConfig } from '../../theme'\nimport { Button } from '../Button'\nimport { Modal } from '../Modal'\nimport { TextField } from '../TextField'\nimport styles from './FileUploaderEditDialog.module.css'\n\n/** What the dialog hands back on Save. */\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}\n\nexport interface FileUploaderEditDialogProps {\n /** Display name (the modal description). */\n name: 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 alt-text draft. */\n onSave: (result: EditDialogResult) => void\n}\n\n/**\n * The FileUploader per-item **alt text** modal — one `TextField` per locale (stacked, no tabs). Built on\n * the library's `Modal` + `TextField`. (Cropping lives in the image editor — the card's Edit button.)\n * Internal — not exported.\n */\nexport function FileUploaderEditDialog({\n name,\n editLocales,\n initialDraft,\n onClose,\n onSave,\n}: FileUploaderEditDialogProps) {\n const t = useT()\n const [draft, setDraft] = useState<Record<string, string>>(initialDraft)\n\n return (\n <Modal\n open\n onClose={onClose}\n size=\"sm\"\n icon=\"Text\"\n title={t('fileUploader.altTitle')}\n description={name}\n footer={\n <>\n <Button variant=\"text\" color=\"accent\" size=\"sm\" onClick={onClose}>\n {t('common.cancel')}\n </Button>\n <Button size=\"sm\" onClick={() => onSave({ draft })}>\n {t('common.save')}\n </Button>\n </>\n }\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 </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'\nimport { ImageEditor } from '../ImageEditor/ImageEditor'\nimport type { ImageEditorResult, ImageState } from '../ImageEditor/core/types'\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 (JPEG / PNG / WebP items — see `isEditableImageItem`) that opens the\n * fullscreen `ImageEditor` — crop / rotate / flip, filters, finetune, redact and resize. **Done** replaces the item's file with the rendered image (a\n * source item becomes a fresh pick). Edits are **non-destructive**: re-opening an edited file continues\n * from the original with every setting restored; reverting everything and pressing Done hands back\n * the original. Defaults to `true`.\n */\n allowEdit?: boolean\n /**\n * Show a per-card **alt text** button (image items) 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 (stacked fields,\n * no tabs), 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 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 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 `.entering` (a plain\n// fade-in), so here `add` is a no-op to avoid double-animating; auto-animate still animates the `remove`\n// (a plain fade-out, no movement) and the `remain` reflow (rows sliding over 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 = [{ opacity: 1 }, { opacity: 0 }]\n } else if (el.classList.contains(styles.entering) || el.classList.contains(styles.list)) {\n // never slide a card that is still fading in, nor the list itself: the list's `populated` gap appears /\n // goes in the same render as the first pick / last removal and would read as a 16px vertical jump\n duration = 0\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/**\n * The ImageEditor's non-destructive memory: an edited File → its original (a File or a source URL) + the\n * edit state, so re-opening continues from the original. Module-level so it survives a remount (a form\n * tab switch); a WeakMap, so it never keeps a removed file alive.\n */\nconst imageEdits = new WeakMap<File, { original: File | string; state: ImageState }>()\n\n/** Whether an edit state changes nothing (so Done can hand back the original untouched). */\nexport function isUntouchedEdit(\n s: ImageState,\n size: { width: number; height: number } | null,\n): boolean {\n const near = (a: number, b: number) => Math.abs(a - b) < 0.5\n return (\n !!size &&\n near(s.crop.x, 0) &&\n near(s.crop.y, 0) &&\n near(s.crop.width, size.width) &&\n near(s.crop.height, size.height) &&\n Math.abs(s.rotation) < 1e-6 &&\n !s.flipX &&\n !s.flipY &&\n Math.abs(s.scale - 1) < 1e-6 &&\n !s.colorMatrix &&\n !s.resize &&\n !(s.redact?.amount > 0) &&\n Object.values(s.finetune).every((v) => v === 0)\n )\n}\n\n/** Give a file name the extension of `type` (`photo.png` + JPEG → `photo.jpg`); a match is kept. */\nexport function renameForType(name: string, type: string): string {\n const ext = { 'image/jpeg': 'jpg', 'image/png': 'png', 'image/webp': 'webp' }[type]\n if (!ext) return name\n const m = /^(.*?)(\\.[^.]+)?$/.exec(name)\n const base = m?.[1] || 'image'\n const cur = (m?.[2] ?? '').slice(1).toLowerCase()\n if (cur === ext || (ext === 'jpg' && cur === 'jpeg')) return name\n return `${base}.${ext}`\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 **alt-text** editor (a video / PDF / doc has\n * nothing to describe; the image editor narrows it further, see `isEditableImageItem`). 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/** The formats the image editor opens — the raster ones it also saves back as the same format. */\nconst EDITABLE_IMAGE_TYPES = new Set(['image/jpeg', 'image/jpg', 'image/png', 'image/webp'])\nconst EDITABLE_IMAGE_EXT = /\\.(jpe?g|png|webp)(?:[?#]|$)/i\n\n/**\n * Whether an item gets the image editor (the Edit button): a JPEG / PNG / WebP. Not an SVG (a vector — it\n * would come out a small PNG), a GIF (its animation would be lost), HEIC / TIFF / BMP / ICO (not every\n * browser decodes them, or the result changes format) and no non-image file. An extensionless URL (a CDN\n * image) can't be told apart, so it counts — as in `isImageItem`. (Exported for unit tests.)\n */\nexport const isEditableImageItem = (item: FileUploaderItem): boolean => {\n if (item.file) {\n const type = item.file.type.toLowerCase()\n // some systems hand over no MIME type — go by the name then\n return type ? EDITABLE_IMAGE_TYPES.has(type) : EDITABLE_IMAGE_EXT.test(item.file.name)\n }\n const src = item.source\n if (!src) return false\n const data = /^data:([^;,]+)/i.exec(src)\n if (data) return EDITABLE_IMAGE_TYPES.has(data[1].toLowerCase())\n return EDITABLE_IMAGE_EXT.test(src) || !/\\.[a-z0-9]{1,8}(?:[?#]|$)/i.test(src)\n}\n\n/**\n * Whether an `accept` map lets in images only (every key an `image/…` type) — the dropzone then shows an\n * image icon instead of a document one. (Exported for unit tests.)\n */\nexport const acceptsOnlyImages = (accept: Accept | undefined): boolean => {\n const types = accept ? Object.keys(accept) : []\n return types.length > 0 && types.every((t) => t.toLowerCase().startsWith('image/'))\n}\n\n/** Whether an item is a video — its card shows a muted `<video>` thumbnail (no controls) instead of an `<img>`; the Eye lightbox plays it. */\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 onEdit?: () => void\n onAltText?: () => void\n onDownload?: () => void\n onView?: () => void\n onPreviewError?: () => void\n /** The field's label, shown above the name (a single-file uploader once its file is picked). */\n fieldLabel?: ReactNode\n}\n\nfunction Row({\n id,\n item,\n preview,\n sortable,\n entering,\n disabled,\n error,\n onRemove,\n onEdit,\n onAltText,\n onDownload,\n onView,\n onPreviewError,\n fieldLabel,\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 !preview && styles.tileFile, // no media to show → the light file-card look (no dark scrims)\n sortable && styles.grabbable,\n entering && styles.entering,\n isDragging && styles.dragging,\n error && styles.tileError,\n fieldLabel != null && styles.tileLabeled,\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 // a non-media file (or a failed preview): a file badge carrying the extension (\"PDF\", \"DOCX\")\n <span className={styles.tileFallback} aria-hidden=\"true\">\n <span className={styles.fileBadge}>\n <Icon name=\"Document\" size=\"lg\" />\n {ext && <span className={styles.fileExt}>{ext.slice(1)}</span>}\n </span>\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 {fieldLabel != null && <span className={styles.tileLabel}>{fieldLabel}</span>}\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: edit (Magicpen) + alt text (Text) + download on the left (edit/alt are image-only),\n the view (Eye) fullscreen-preview button pinned bottom-right */}\n {(onEdit || onAltText || onDownload || onView) && (\n <div className={styles.tileBottom}>\n {onEdit && (\n <button\n type=\"button\"\n className={styles.tileAction}\n aria-label={t('fileUploader.edit', { name: label })}\n onClick={onEdit}\n onPointerDown={(e) => e.stopPropagation()}\n >\n <Icon name=\"Magicpen\" 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 centered dropzone panel sits above a grid of image cards (thumbnail, or a file badge\n * with the extension for non-media files, + name + size, with overlaid remove + action 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 allowEdit = 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 fade-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 // ── the alt-text dialog (opened from a card's Text button) ─────────────────────────────────────────\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 editPos = editId != null ? ids.indexOf(editId) : -1\n const editingItem = editPos !== -1 ? items[editPos] : null\n const openAltEditor = (index: number) => setEditId(ids[index] ?? null)\n const closeEditor = () => setEditId(null)\n\n // ── the image editor (Edit) — non-destructive: an edited File remembers its original + the edit state ──\n const [imageEditId, setImageEditId] = useState<string | null>(null)\n const imageEditPos = imageEditId != null ? ids.indexOf(imageEditId) : -1\n const imageEditItem = imageEditPos !== -1 ? items[imageEditPos] : null\n const imageEditRecord = imageEditItem?.file ? imageEdits.get(imageEditItem.file) : undefined\n const imageEditSrc =\n imageEditRecord?.original ?? imageEditItem?.file ?? imageEditItem?.source ?? null\n const imageEditSize = useRef<{ width: number; height: number } | null>(null)\n // the value as of the latest render — Done resolves after an async render, during which it may change\n const latestItems = useRef({ items, ids })\n latestItems.current = { items, ids }\n const saveImageEdit = ({ dest, imageState }: ImageEditorResult) => {\n const { items, ids } = latestItems.current\n const pos = imageEditId != null ? ids.indexOf(imageEditId) : -1\n if (pos === -1) return // the item went away under us\n const item = items[pos]\n const record = item.file ? imageEdits.get(item.file) : undefined\n const original = record?.original || item.file || item.source || null\n if (!original) return\n const untouched = isUntouchedEdit(imageState, imageEditSize.current)\n // opened and closed with Done but nothing changed (and never edited before) — leave the value alone,\n // so the form doesn't turn dirty for nothing\n if (untouched && !record) return\n let next: FileUploaderItem\n if (untouched) {\n // everything reverted → hand back the original (no re-encode)\n const { file: _drop, ...rest } = item // eslint-disable-line @typescript-eslint/no-unused-vars\n next =\n typeof original === 'string'\n ? { ...rest, source: original }\n : { ...rest, file: original, source: '' }\n } else {\n // the rendered image replaces the item (a source item becomes a fresh pick that uploads on save)\n const file = new File([dest], renameForType(labelOf(item), dest.type), {\n type: dest.type,\n lastModified: Date.now(),\n })\n imageEdits.set(file, { original, state: imageState })\n next = { ...item, file, source: '' }\n }\n commit(items.map((it, i) => (i === pos ? next : it)))\n }\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 }: 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 // rebuild altText from the draft (localized record / single string)\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 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 || imageEditId != 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 // the label + required mark — the dropzone's title, or the single card's once the dropzone is gone\n const fieldTitle =\n label != null ? (\n <>\n {label}\n {required && (\n <span className={clsx(fieldStyles.required, styles.dropRequired)} aria-hidden=\"true\">\n *\n </span>\n )}\n </>\n ) : undefined\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 {/* the label is the dropzone's title while it shows (below); once it's gone (a single-file\n uploader with its file picked) the card carries it, in the same place — nothing shifts */}\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={acceptsOnlyImages(accept) ? 'GalleryExport' : 'Upload'} size=\"lg\" />\n </span>\n <span className={styles.dropText}>\n {fieldTitle && <span className={styles.dropTitle}>{fieldTitle}</span>}\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 // the image editor only opens the raster formats it saves back as-is (no SVG / GIF / …);\n // alt text is for any image — a video / PDF / doc has nothing to describe\n onEdit={\n allowEdit && !disabled && isEditableImageItem(item)\n ? () => setImageEditId(ids[index] ?? null)\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 fieldLabel={!showDropzone ? fieldTitle : undefined}\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}\n name={labelOf(editingItem)}\n editLocales={editLocales}\n initialDraft={editInitialDraft}\n onClose={closeEditor}\n onSave={saveEdit}\n />\n )}\n\n <ImageEditor\n open={imageEditItem != null && imageEditSrc != null}\n src={imageEditSrc}\n initialState={imageEditRecord?.state}\n onLoad={(size) => (imageEditSize.current = size)}\n onProcess={saveImageEdit}\n onClose={() => setImageEditId(null)}\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","name","editLocales","initialDraft","onClose","onSave","t","useT","draft","setDraft","useState","jsx","Modal","jsxs","Fragment","Button","styles","l","TextField","e","d","FileUploaderPreview","url","isVideo","isSvg","Overlay","Icon","clsx","canMakeObjectUrl","ANIM_MS","listAnimation","el","action","oldCoords","newCoords","keyframes","duration","dx","dy","imageEdits","isUntouchedEdit","s","size","near","a","b","_a","v","renameForType","type","ext","m","base","cur","formatBytes","bytes","units","value","i","toBytes","match","fileKey","file","itemKey","item","labelOf","isImageItem","src","EDITABLE_IMAGE_TYPES","EDITABLE_IMAGE_EXT","isEditableImageItem","data","acceptsOnlyImages","accept","types","isVideoItem","triggerDownload","splitName","dot","Row","id","preview","sortable","entering","disabled","error","onRemove","onEdit","onAltText","onDownload","onView","onPreviewError","fieldLabel","attributes","listeners","setNodeRef","transform","transition","isDragging","useSortable","style","CSS","label","mediaLoaded","setMediaLoaded","lastPreview","useRef","mediaRef","useEffect","img","onMediaError","meta","video","downloadBtn","Skeleton","FileUploader","forwardRef","multiple","allowDrop","allowReorder","allowDownload","allowPreview","allowEdit","allowAltText","altTextLocales","localizedAltText","allowDuplicates","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","setPreview","cache","liveFiles","it","liveSources","next","reindex","arr","commit","ordered","out","markTouched","configLocales","useLocales","altLocales","editId","setEditId","editPos","editingItem","openAltEditor","closeEditor","imageEditId","setImageEditId","imageEditPos","imageEditItem","imageEditRecord","imageEditSrc","imageEditSize","latestItems","saveImageEdit","dest","imageState","pos","record","original","untouched","_drop","rest","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","fieldTitle","fieldStyles","DndContext","closestCenter","SortableContext","rectSortingStrategy","Typography","ImageEditor"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";const s=require("react/jsx-runtime"),c=require("react"),F=require("./Icon-CBg21lKA.cjs"),h=require("./IconButton-U_sr2Ahy.cjs"),q=require("./ConfigProvider-DBU6rOIA.cjs"),E=c.forwardRef(function({variant:i="outlined",...t},d){const[a]=c.useState(()=>typeof document<"u"&&typeof document.documentElement.requestFullscreen=="function"),[l,f]=c.useState(!1),m=q.useT();if(c.useEffect(()=>{const e=()=>f(document.fullscreenElement!=null);return e(),document.addEventListener("fullscreenchange",e),()=>document.removeEventListener("fullscreenchange",e)},[]),!a)return null;const g=()=>{var e,n,u,o,r;document.fullscreenElement?(n=(e=document.exitFullscreen)==null?void 0:e.call(document))==null||n.catch(()=>{}):(r=(o=(u=document.documentElement).requestFullscreen)==null?void 0:o.call(u))==null||r.catch(()=>{})};return s.jsx(h.IconButton,{ref:d,variant:i,role:"switch","aria-checked":l,"aria-label":m("fullscreenToggle.label"),...t,onClick:e=>{var n;(n=t.onClick)==null||n.call(t,e),g()},children:s.jsx(F.Icon,{name:"Maximize3",style:l?{transform:"rotate(180deg)"}:void 0})})});exports.FullscreenToggle=E;
2
- //# sourceMappingURL=FullscreenToggle-ipX55Nj4.cjs.map
1
+ "use strict";const s=require("react/jsx-runtime"),c=require("react"),F=require("./Icon-CBg21lKA.cjs"),h=require("./IconButton-DSPdv-oI.cjs"),q=require("./ConfigProvider-CYSpuSMJ.cjs"),E=c.forwardRef(function({variant:i="outlined",...t},d){const[a]=c.useState(()=>typeof document<"u"&&typeof document.documentElement.requestFullscreen=="function"),[l,f]=c.useState(!1),m=q.useT();if(c.useEffect(()=>{const e=()=>f(document.fullscreenElement!=null);return e(),document.addEventListener("fullscreenchange",e),()=>document.removeEventListener("fullscreenchange",e)},[]),!a)return null;const g=()=>{var e,n,u,o,r;document.fullscreenElement?(n=(e=document.exitFullscreen)==null?void 0:e.call(document))==null||n.catch(()=>{}):(r=(o=(u=document.documentElement).requestFullscreen)==null?void 0:o.call(u))==null||r.catch(()=>{})};return s.jsx(h.IconButton,{ref:d,variant:i,role:"switch","aria-checked":l,"aria-label":m("fullscreenToggle.label"),...t,onClick:e=>{var n;(n=t.onClick)==null||n.call(t,e),g()},children:s.jsx(F.Icon,{name:"Maximize3",style:l?{transform:"rotate(180deg)"}:void 0})})});exports.FullscreenToggle=E;
2
+ //# sourceMappingURL=FullscreenToggle-DVdQriWB.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"FullscreenToggle-ipX55Nj4.cjs","sources":["../src/components/FullscreenToggle/FullscreenToggle.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState } from 'react'\nimport { useT } from '../../theme'\nimport { Icon } from '../Icon'\nimport { IconButton, type IconButtonProps } from '../IconButton'\n\n/** Inherits `IconButton`'s look (variant, color, size); the icon and toggle behavior are built in. */\nexport type FullscreenToggleProps = Omit<IconButtonProps, 'children'>\n\n/**\n * A one-tap browser fullscreen switch. Renders an `IconButton` that calls the Fullscreen API —\n * `requestFullscreen` to maximize, `exitFullscreen` to restore — and flips its `Maximize3` icon 180°\n * while fullscreen (so it reads as \"minimize\"), keeping state in sync via the `fullscreenchange`\n * event. Renders **nothing** where the Fullscreen API is unavailable (e.g. iOS Safari on iPhone), so\n * it auto-hides on devices that can't go fullscreen. Styling comes from `IconButton`, so `variant`,\n * `color` and `size` pass through.\n */\nexport const FullscreenToggle = forwardRef<HTMLButtonElement, FullscreenToggleProps>(\n function FullscreenToggle({ variant = 'outlined', ...props }, ref) {\n // The Fullscreen API is absent on some devices (notably iOS Safari on iPhone); hide the control\n // there, since tapping it could never do anything.\n const [supported] = useState(\n () =>\n typeof document !== 'undefined' &&\n typeof document.documentElement.requestFullscreen === 'function',\n )\n const [isFullscreen, setIsFullscreen] = useState(false)\n const t = useT()\n\n useEffect(() => {\n const sync = () => setIsFullscreen(document.fullscreenElement != null)\n sync() // pick up a session that's already fullscreen on mount\n document.addEventListener('fullscreenchange', sync)\n return () => document.removeEventListener('fullscreenchange', sync)\n }, [])\n\n if (!supported) return null\n\n const toggle = () => {\n // `?.` guards environments without the Fullscreen API; `.catch` swallows a blocked request\n if (document.fullscreenElement) {\n document.exitFullscreen?.()?.catch(() => {})\n } else {\n document.documentElement.requestFullscreen?.()?.catch(() => {})\n }\n }\n\n return (\n <IconButton\n ref={ref}\n variant={variant}\n role=\"switch\"\n aria-checked={isFullscreen}\n aria-label={t('fullscreenToggle.label')}\n {...props}\n onClick={(event) => {\n props.onClick?.(event) // preserve a caller-supplied handler, then toggle\n toggle()\n }}\n >\n <Icon name=\"Maximize3\" style={isFullscreen ? { transform: 'rotate(180deg)' } : undefined} />\n </IconButton>\n )\n },\n)\n"],"names":["FullscreenToggle","forwardRef","variant","props","ref","supported","useState","isFullscreen","setIsFullscreen","t","useT","useEffect","sync","toggle","_b","_a","_e","_d","_c","jsx","IconButton","event","Icon"],"mappings":"wLAgBaA,EAAmBC,EAAAA,WAC9B,SAA0B,CAAE,QAAAC,EAAU,WAAY,GAAGC,CAAA,EAASC,EAAK,CAGjE,KAAM,CAACC,CAAS,EAAIC,EAAAA,SAClB,IACE,OAAO,SAAa,KACpB,OAAO,SAAS,gBAAgB,mBAAsB,UAAA,EAEpD,CAACC,EAAcC,CAAe,EAAIF,EAAAA,SAAS,EAAK,EAChDG,EAAIC,EAAAA,KAAA,EASV,GAPAC,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAO,IAAMJ,EAAgB,SAAS,mBAAqB,IAAI,EACrE,OAAAI,EAAA,EACA,SAAS,iBAAiB,mBAAoBA,CAAI,EAC3C,IAAM,SAAS,oBAAoB,mBAAoBA,CAAI,CACpE,EAAG,CAAA,CAAE,EAED,CAACP,EAAW,OAAO,KAEvB,MAAMQ,EAAS,IAAM,eAEf,SAAS,mBACXC,GAAAC,EAAA,SAAS,iBAAT,YAAAA,EAAA,uBAAAD,EAA6B,MAAM,IAAM,CAAC,IAE1CE,GAAAC,GAAAC,EAAA,SAAS,iBAAgB,oBAAzB,YAAAD,EAAA,KAAAC,KAAA,MAAAF,EAAgD,MAAM,IAAM,CAAC,EAEjE,EAEA,OACEG,EAAAA,IAACC,EAAAA,WAAA,CACC,IAAAhB,EACA,QAAAF,EACA,KAAK,SACL,eAAcK,EACd,aAAYE,EAAE,wBAAwB,EACrC,GAAGN,EACJ,QAAUkB,GAAU,QAClBN,EAAAZ,EAAM,UAAN,MAAAY,EAAA,KAAAZ,EAAgBkB,GAChBR,EAAA,CACF,EAEA,SAAAM,EAAAA,IAACG,OAAA,CAAK,KAAK,YAAY,MAAOf,EAAe,CAAE,UAAW,gBAAA,EAAqB,MAAA,CAAW,CAAA,CAAA,CAGhG,CACF"}
1
+ {"version":3,"file":"FullscreenToggle-DVdQriWB.cjs","sources":["../src/components/FullscreenToggle/FullscreenToggle.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState } from 'react'\nimport { useT } from '../../theme'\nimport { Icon } from '../Icon'\nimport { IconButton, type IconButtonProps } from '../IconButton'\n\n/** Inherits `IconButton`'s look (variant, color, size); the icon and toggle behavior are built in. */\nexport type FullscreenToggleProps = Omit<IconButtonProps, 'children'>\n\n/**\n * A one-tap browser fullscreen switch. Renders an `IconButton` that calls the Fullscreen API —\n * `requestFullscreen` to maximize, `exitFullscreen` to restore — and flips its `Maximize3` icon 180°\n * while fullscreen (so it reads as \"minimize\"), keeping state in sync via the `fullscreenchange`\n * event. Renders **nothing** where the Fullscreen API is unavailable (e.g. iOS Safari on iPhone), so\n * it auto-hides on devices that can't go fullscreen. Styling comes from `IconButton`, so `variant`,\n * `color` and `size` pass through.\n */\nexport const FullscreenToggle = forwardRef<HTMLButtonElement, FullscreenToggleProps>(\n function FullscreenToggle({ variant = 'outlined', ...props }, ref) {\n // The Fullscreen API is absent on some devices (notably iOS Safari on iPhone); hide the control\n // there, since tapping it could never do anything.\n const [supported] = useState(\n () =>\n typeof document !== 'undefined' &&\n typeof document.documentElement.requestFullscreen === 'function',\n )\n const [isFullscreen, setIsFullscreen] = useState(false)\n const t = useT()\n\n useEffect(() => {\n const sync = () => setIsFullscreen(document.fullscreenElement != null)\n sync() // pick up a session that's already fullscreen on mount\n document.addEventListener('fullscreenchange', sync)\n return () => document.removeEventListener('fullscreenchange', sync)\n }, [])\n\n if (!supported) return null\n\n const toggle = () => {\n // `?.` guards environments without the Fullscreen API; `.catch` swallows a blocked request\n if (document.fullscreenElement) {\n document.exitFullscreen?.()?.catch(() => {})\n } else {\n document.documentElement.requestFullscreen?.()?.catch(() => {})\n }\n }\n\n return (\n <IconButton\n ref={ref}\n variant={variant}\n role=\"switch\"\n aria-checked={isFullscreen}\n aria-label={t('fullscreenToggle.label')}\n {...props}\n onClick={(event) => {\n props.onClick?.(event) // preserve a caller-supplied handler, then toggle\n toggle()\n }}\n >\n <Icon name=\"Maximize3\" style={isFullscreen ? { transform: 'rotate(180deg)' } : undefined} />\n </IconButton>\n )\n },\n)\n"],"names":["FullscreenToggle","forwardRef","variant","props","ref","supported","useState","isFullscreen","setIsFullscreen","t","useT","useEffect","sync","toggle","_b","_a","_e","_d","_c","jsx","IconButton","event","Icon"],"mappings":"wLAgBaA,EAAmBC,EAAAA,WAC9B,SAA0B,CAAE,QAAAC,EAAU,WAAY,GAAGC,CAAA,EAASC,EAAK,CAGjE,KAAM,CAACC,CAAS,EAAIC,EAAAA,SAClB,IACE,OAAO,SAAa,KACpB,OAAO,SAAS,gBAAgB,mBAAsB,UAAA,EAEpD,CAACC,EAAcC,CAAe,EAAIF,EAAAA,SAAS,EAAK,EAChDG,EAAIC,EAAAA,KAAA,EASV,GAPAC,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAO,IAAMJ,EAAgB,SAAS,mBAAqB,IAAI,EACrE,OAAAI,EAAA,EACA,SAAS,iBAAiB,mBAAoBA,CAAI,EAC3C,IAAM,SAAS,oBAAoB,mBAAoBA,CAAI,CACpE,EAAG,CAAA,CAAE,EAED,CAACP,EAAW,OAAO,KAEvB,MAAMQ,EAAS,IAAM,eAEf,SAAS,mBACXC,GAAAC,EAAA,SAAS,iBAAT,YAAAA,EAAA,uBAAAD,EAA6B,MAAM,IAAM,CAAC,IAE1CE,GAAAC,GAAAC,EAAA,SAAS,iBAAgB,oBAAzB,YAAAD,EAAA,KAAAC,KAAA,MAAAF,EAAgD,MAAM,IAAM,CAAC,EAEjE,EAEA,OACEG,EAAAA,IAACC,EAAAA,WAAA,CACC,IAAAhB,EACA,QAAAF,EACA,KAAK,SACL,eAAcK,EACd,aAAYE,EAAE,wBAAwB,EACrC,GAAGN,EACJ,QAAUkB,GAAU,QAClBN,EAAAZ,EAAM,UAAN,MAAAY,EAAA,KAAAZ,EAAgBkB,GAChBR,EAAA,CACF,EAEA,SAAAM,EAAAA,IAACG,OAAA,CAAK,KAAK,YAAY,MAAOf,EAAe,CAAE,UAAW,gBAAA,EAAqB,MAAA,CAAW,CAAA,CAAA,CAGhG,CACF"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as u } from "react/jsx-runtime";
2
2
  import { forwardRef as F, useState as s, useEffect as h } from "react";
3
3
  import { b as E } from "./Icon-B7DJn8Tw.js";
4
- import { I as v } from "./IconButton-re6xITGO.js";
5
- import { a as x } from "./ConfigProvider-DVDGtCUc.js";
4
+ import { I as v } from "./IconButton-iWbUJAz7.js";
5
+ import { a as x } from "./ConfigProvider-DtyUlWk6.js";
6
6
  const w = F(
7
7
  function({ variant: m = "outlined", ...t }, i) {
8
8
  const [a] = s(
@@ -39,4 +39,4 @@ const w = F(
39
39
  export {
40
40
  w as F
41
41
  };
42
- //# sourceMappingURL=FullscreenToggle-CxwGPLdd.js.map
42
+ //# sourceMappingURL=FullscreenToggle-WGsbE3Op.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FullscreenToggle-CxwGPLdd.js","sources":["../src/components/FullscreenToggle/FullscreenToggle.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState } from 'react'\nimport { useT } from '../../theme'\nimport { Icon } from '../Icon'\nimport { IconButton, type IconButtonProps } from '../IconButton'\n\n/** Inherits `IconButton`'s look (variant, color, size); the icon and toggle behavior are built in. */\nexport type FullscreenToggleProps = Omit<IconButtonProps, 'children'>\n\n/**\n * A one-tap browser fullscreen switch. Renders an `IconButton` that calls the Fullscreen API —\n * `requestFullscreen` to maximize, `exitFullscreen` to restore — and flips its `Maximize3` icon 180°\n * while fullscreen (so it reads as \"minimize\"), keeping state in sync via the `fullscreenchange`\n * event. Renders **nothing** where the Fullscreen API is unavailable (e.g. iOS Safari on iPhone), so\n * it auto-hides on devices that can't go fullscreen. Styling comes from `IconButton`, so `variant`,\n * `color` and `size` pass through.\n */\nexport const FullscreenToggle = forwardRef<HTMLButtonElement, FullscreenToggleProps>(\n function FullscreenToggle({ variant = 'outlined', ...props }, ref) {\n // The Fullscreen API is absent on some devices (notably iOS Safari on iPhone); hide the control\n // there, since tapping it could never do anything.\n const [supported] = useState(\n () =>\n typeof document !== 'undefined' &&\n typeof document.documentElement.requestFullscreen === 'function',\n )\n const [isFullscreen, setIsFullscreen] = useState(false)\n const t = useT()\n\n useEffect(() => {\n const sync = () => setIsFullscreen(document.fullscreenElement != null)\n sync() // pick up a session that's already fullscreen on mount\n document.addEventListener('fullscreenchange', sync)\n return () => document.removeEventListener('fullscreenchange', sync)\n }, [])\n\n if (!supported) return null\n\n const toggle = () => {\n // `?.` guards environments without the Fullscreen API; `.catch` swallows a blocked request\n if (document.fullscreenElement) {\n document.exitFullscreen?.()?.catch(() => {})\n } else {\n document.documentElement.requestFullscreen?.()?.catch(() => {})\n }\n }\n\n return (\n <IconButton\n ref={ref}\n variant={variant}\n role=\"switch\"\n aria-checked={isFullscreen}\n aria-label={t('fullscreenToggle.label')}\n {...props}\n onClick={(event) => {\n props.onClick?.(event) // preserve a caller-supplied handler, then toggle\n toggle()\n }}\n >\n <Icon name=\"Maximize3\" style={isFullscreen ? { transform: 'rotate(180deg)' } : undefined} />\n </IconButton>\n )\n },\n)\n"],"names":["FullscreenToggle","forwardRef","variant","props","ref","supported","useState","isFullscreen","setIsFullscreen","t","useT","useEffect","sync","toggle","_b","_a","_e","_d","_c","jsx","IconButton","event","Icon"],"mappings":";;;;;AAgBO,MAAMA,IAAmBC;AAAA,EAC9B,SAA0B,EAAE,SAAAC,IAAU,YAAY,GAAGC,EAAA,GAASC,GAAK;AAGjE,UAAM,CAACC,CAAS,IAAIC;AAAA,MAClB,MACE,OAAO,WAAa,OACpB,OAAO,SAAS,gBAAgB,qBAAsB;AAAA,IAAA,GAEpD,CAACC,GAAcC,CAAe,IAAIF,EAAS,EAAK,GAChDG,IAAIC,EAAA;AASV,QAPAC,EAAU,MAAM;AACd,YAAMC,IAAO,MAAMJ,EAAgB,SAAS,qBAAqB,IAAI;AACrE,aAAAI,EAAA,GACA,SAAS,iBAAiB,oBAAoBA,CAAI,GAC3C,MAAM,SAAS,oBAAoB,oBAAoBA,CAAI;AAAA,IACpE,GAAG,CAAA,CAAE,GAED,CAACP,EAAW,QAAO;AAEvB,UAAMQ,IAAS,MAAM;;AAEnB,MAAI,SAAS,qBACXC,KAAAC,IAAA,SAAS,mBAAT,gBAAAA,EAAA,2BAAAD,EAA6B,MAAM,MAAM;AAAA,MAAC,MAE1CE,KAAAC,KAAAC,IAAA,SAAS,iBAAgB,sBAAzB,gBAAAD,EAAA,KAAAC,OAAA,QAAAF,EAAgD,MAAM,MAAM;AAAA,MAAC;AAAA,IAEjE;AAEA,WACE,gBAAAG;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,KAAAhB;AAAA,QACA,SAAAF;AAAA,QACA,MAAK;AAAA,QACL,gBAAcK;AAAA,QACd,cAAYE,EAAE,wBAAwB;AAAA,QACrC,GAAGN;AAAA,QACJ,SAAS,CAACkB,MAAU;;AAClB,WAAAN,IAAAZ,EAAM,YAAN,QAAAY,EAAA,KAAAZ,GAAgBkB,IAChBR,EAAA;AAAA,QACF;AAAA,QAEA,UAAA,gBAAAM,EAACG,GAAA,EAAK,MAAK,aAAY,OAAOf,IAAe,EAAE,WAAW,iBAAA,IAAqB,OAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,EAGhG;AACF;"}
1
+ {"version":3,"file":"FullscreenToggle-WGsbE3Op.js","sources":["../src/components/FullscreenToggle/FullscreenToggle.tsx"],"sourcesContent":["import { forwardRef, useEffect, useState } from 'react'\nimport { useT } from '../../theme'\nimport { Icon } from '../Icon'\nimport { IconButton, type IconButtonProps } from '../IconButton'\n\n/** Inherits `IconButton`'s look (variant, color, size); the icon and toggle behavior are built in. */\nexport type FullscreenToggleProps = Omit<IconButtonProps, 'children'>\n\n/**\n * A one-tap browser fullscreen switch. Renders an `IconButton` that calls the Fullscreen API —\n * `requestFullscreen` to maximize, `exitFullscreen` to restore — and flips its `Maximize3` icon 180°\n * while fullscreen (so it reads as \"minimize\"), keeping state in sync via the `fullscreenchange`\n * event. Renders **nothing** where the Fullscreen API is unavailable (e.g. iOS Safari on iPhone), so\n * it auto-hides on devices that can't go fullscreen. Styling comes from `IconButton`, so `variant`,\n * `color` and `size` pass through.\n */\nexport const FullscreenToggle = forwardRef<HTMLButtonElement, FullscreenToggleProps>(\n function FullscreenToggle({ variant = 'outlined', ...props }, ref) {\n // The Fullscreen API is absent on some devices (notably iOS Safari on iPhone); hide the control\n // there, since tapping it could never do anything.\n const [supported] = useState(\n () =>\n typeof document !== 'undefined' &&\n typeof document.documentElement.requestFullscreen === 'function',\n )\n const [isFullscreen, setIsFullscreen] = useState(false)\n const t = useT()\n\n useEffect(() => {\n const sync = () => setIsFullscreen(document.fullscreenElement != null)\n sync() // pick up a session that's already fullscreen on mount\n document.addEventListener('fullscreenchange', sync)\n return () => document.removeEventListener('fullscreenchange', sync)\n }, [])\n\n if (!supported) return null\n\n const toggle = () => {\n // `?.` guards environments without the Fullscreen API; `.catch` swallows a blocked request\n if (document.fullscreenElement) {\n document.exitFullscreen?.()?.catch(() => {})\n } else {\n document.documentElement.requestFullscreen?.()?.catch(() => {})\n }\n }\n\n return (\n <IconButton\n ref={ref}\n variant={variant}\n role=\"switch\"\n aria-checked={isFullscreen}\n aria-label={t('fullscreenToggle.label')}\n {...props}\n onClick={(event) => {\n props.onClick?.(event) // preserve a caller-supplied handler, then toggle\n toggle()\n }}\n >\n <Icon name=\"Maximize3\" style={isFullscreen ? { transform: 'rotate(180deg)' } : undefined} />\n </IconButton>\n )\n },\n)\n"],"names":["FullscreenToggle","forwardRef","variant","props","ref","supported","useState","isFullscreen","setIsFullscreen","t","useT","useEffect","sync","toggle","_b","_a","_e","_d","_c","jsx","IconButton","event","Icon"],"mappings":";;;;;AAgBO,MAAMA,IAAmBC;AAAA,EAC9B,SAA0B,EAAE,SAAAC,IAAU,YAAY,GAAGC,EAAA,GAASC,GAAK;AAGjE,UAAM,CAACC,CAAS,IAAIC;AAAA,MAClB,MACE,OAAO,WAAa,OACpB,OAAO,SAAS,gBAAgB,qBAAsB;AAAA,IAAA,GAEpD,CAACC,GAAcC,CAAe,IAAIF,EAAS,EAAK,GAChDG,IAAIC,EAAA;AASV,QAPAC,EAAU,MAAM;AACd,YAAMC,IAAO,MAAMJ,EAAgB,SAAS,qBAAqB,IAAI;AACrE,aAAAI,EAAA,GACA,SAAS,iBAAiB,oBAAoBA,CAAI,GAC3C,MAAM,SAAS,oBAAoB,oBAAoBA,CAAI;AAAA,IACpE,GAAG,CAAA,CAAE,GAED,CAACP,EAAW,QAAO;AAEvB,UAAMQ,IAAS,MAAM;;AAEnB,MAAI,SAAS,qBACXC,KAAAC,IAAA,SAAS,mBAAT,gBAAAA,EAAA,2BAAAD,EAA6B,MAAM,MAAM;AAAA,MAAC,MAE1CE,KAAAC,KAAAC,IAAA,SAAS,iBAAgB,sBAAzB,gBAAAD,EAAA,KAAAC,OAAA,QAAAF,EAAgD,MAAM,MAAM;AAAA,MAAC;AAAA,IAEjE;AAEA,WACE,gBAAAG;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,KAAAhB;AAAA,QACA,SAAAF;AAAA,QACA,MAAK;AAAA,QACL,gBAAcK;AAAA,QACd,cAAYE,EAAE,wBAAwB;AAAA,QACrC,GAAGN;AAAA,QACJ,SAAS,CAACkB,MAAU;;AAClB,WAAAN,IAAAZ,EAAM,YAAN,QAAAY,EAAA,KAAAZ,GAAgBkB,IAChBR,EAAA;AAAA,QACF;AAAA,QAEA,UAAA,gBAAAM,EAACG,GAAA,EAAK,MAAK,aAAY,OAAOf,IAAe,EAAE,WAAW,iBAAA,IAAqB,OAAA,CAAW;AAAA,MAAA;AAAA,IAAA;AAAA,EAGhG;AACF;"}
@@ -1,2 +1,2 @@
1
- "use strict";const _=require("react/jsx-runtime"),l=require("react"),x=require("clsx"),B=require("./Loader-BE3SQr7W.cjs"),g="_iconButton_1lspy_1",q="_sm_1lspy_22",v="_md_1lspy_27",z="_lg_1lspy_32",I="_contained_1lspy_38",j="_filled_1lspy_50",k="_outlined_1lspy_61",C="_text_1lspy_74",E="_rounded_1lspy_86",L="_disabled_1lspy_94",R="_loading_1lspy_98",$="_nonClickable_1lspy_103",t={iconButton:g,sm:q,md:v,lg:z,contained:I,filled:j,outlined:k,text:C,rounded:E,disabled:L,loading:R,nonClickable:$},w=l.forwardRef(function({variant:i="contained",color:c="accent",size:s="md",loading:n=!1,rounded:a=!1,disabled:d=!1,nonClickable:e=!1,className:r,style:u,type:b="button",tabIndex:y,children:o,...p},f){const m=l.isValidElement(o)&&!n?l.cloneElement(o,{size:o.props.size??s}):o;return _.jsx("button",{ref:f,type:b,disabled:d||n,"aria-busy":n||void 0,"aria-disabled":e||void 0,tabIndex:e?-1:y,className:x.clsx(t.iconButton,t[i],t[s],a&&t.rounded,n&&t.loading,d&&t.disabled,e&&t.nonClickable,r),style:{"--tz-btn-rgb":`var(--tz-color-${c}-rgb)`,"--tz-btn-on":`var(--tz-color-${c}-contrast, #fff)`,...u},...p,children:n?_.jsx(B.Loader,{size:s,"aria-hidden":"true"}):m})});exports.IconButton=w;
2
- //# sourceMappingURL=IconButton-U_sr2Ahy.cjs.map
1
+ "use strict";const _=require("react/jsx-runtime"),l=require("react"),x=require("clsx"),B=require("./Loader-RyFTP2X5.cjs"),g="_iconButton_1lspy_1",q="_sm_1lspy_22",v="_md_1lspy_27",z="_lg_1lspy_32",I="_contained_1lspy_38",j="_filled_1lspy_50",k="_outlined_1lspy_61",C="_text_1lspy_74",E="_rounded_1lspy_86",L="_disabled_1lspy_94",R="_loading_1lspy_98",$="_nonClickable_1lspy_103",t={iconButton:g,sm:q,md:v,lg:z,contained:I,filled:j,outlined:k,text:C,rounded:E,disabled:L,loading:R,nonClickable:$},w=l.forwardRef(function({variant:i="contained",color:c="accent",size:s="md",loading:n=!1,rounded:a=!1,disabled:d=!1,nonClickable:e=!1,className:r,style:u,type:b="button",tabIndex:y,children:o,...p},f){const m=l.isValidElement(o)&&!n?l.cloneElement(o,{size:o.props.size??s}):o;return _.jsx("button",{ref:f,type:b,disabled:d||n,"aria-busy":n||void 0,"aria-disabled":e||void 0,tabIndex:e?-1:y,className:x.clsx(t.iconButton,t[i],t[s],a&&t.rounded,n&&t.loading,d&&t.disabled,e&&t.nonClickable,r),style:{"--tz-btn-rgb":`var(--tz-color-${c}-rgb)`,"--tz-btn-on":`var(--tz-color-${c}-contrast, #fff)`,...u},...p,children:n?_.jsx(B.Loader,{size:s,"aria-hidden":"true"}):m})});exports.IconButton=w;
2
+ //# sourceMappingURL=IconButton-DSPdv-oI.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"IconButton-U_sr2Ahy.cjs","sources":["../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Loader } from '../Loader'\nimport styles from './IconButton.module.css'\n\nexport type IconButtonVariant = 'contained' | 'filled' | 'outlined' | 'text'\nexport type IconButtonSize = 'sm' | 'md' | 'lg'\n\nexport interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'> {\n /** Visual style. `contained` solid · `filled` soft tint · `outlined` border · `text` bare. */\n variant?: IconButtonVariant\n /** Theme palette token that tints the button. Defaults to `accent`. */\n color?: ThemeColor\n /** Preset size — square: width === height === `--tz-control-height-*` (matches `Button` heights). */\n size?: IconButtonSize\n /** Shows the loader in the icon's place and blocks interaction (also sets the native `disabled`). */\n loading?: boolean\n /** Circular shape instead of the default rounded square. */\n rounded?: boolean\n /** Ignores all interaction (no clicks, hover or focus) while keeping the normal look — unlike `disabled`, it's not dimmed. */\n nonClickable?: boolean\n /** The icon to render — typically an `<Icon />`. Swapped for the loader while `loading`. */\n children?: ReactNode\n}\n\n/**\n * A square, text-less button for a single icon. Shares `Button`'s variants,\n * colors and sizing, but its width equals its height (the matching\n * `--tz-control-height-*`). Pass an `<Icon />` (or any node) as the child;\n * while `loading` it's replaced by the `Loader`. Provide an `aria-label` since\n * there's no visible text.\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(\n {\n variant = 'contained',\n color = 'accent',\n size = 'md',\n loading = false,\n rounded = false,\n disabled = false,\n nonClickable = false,\n className,\n style,\n type = 'button',\n tabIndex,\n children,\n ...props\n },\n ref,\n) {\n // size the icon child to match the button (an explicit icon `size` still wins)\n const icon =\n isValidElement(children) && !loading\n ? cloneElement(children as ReactElement<{ size?: IconButtonSize }>, {\n size: (children.props as { size?: IconButtonSize }).size ?? size,\n })\n : children\n\n return (\n <button\n ref={ref}\n type={type}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n aria-disabled={nonClickable || undefined}\n tabIndex={nonClickable ? -1 : tabIndex}\n className={clsx(\n styles.iconButton,\n styles[variant],\n styles[size],\n rounded && styles.rounded,\n loading && styles.loading,\n disabled && styles.disabled,\n nonClickable && styles.nonClickable,\n className,\n )}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${color}-contrast, #fff)`,\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {loading ? <Loader size={size} aria-hidden=\"true\" /> : icon}\n </button>\n )\n})\n"],"names":["IconButton","forwardRef","variant","color","size","loading","rounded","disabled","nonClickable","className","style","type","tabIndex","children","props","ref","icon","isValidElement","cloneElement","jsx","clsx","styles","Loader"],"mappings":"gfAyCaA,EAAaC,EAAAA,WAA+C,SACvE,CACE,QAAAC,EAAU,YACV,MAAAC,EAAQ,SACR,KAAAC,EAAO,KACP,QAAAC,EAAU,GACV,QAAAC,EAAU,GACV,SAAAC,EAAW,GACX,aAAAC,EAAe,GACf,UAAAC,EACA,MAAAC,EACA,KAAAC,EAAO,SACP,SAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CAEA,MAAMC,EACJC,EAAAA,eAAeJ,CAAQ,GAAK,CAACR,EACzBa,EAAAA,aAAaL,EAAqD,CAChE,KAAOA,EAAS,MAAoC,MAAQT,CAAA,CAC7D,EACDS,EAEN,OACEM,EAAAA,IAAC,SAAA,CACC,IAAAJ,EACA,KAAAJ,EACA,SAAUJ,GAAYF,EACtB,YAAWA,GAAW,OACtB,gBAAeG,GAAgB,OAC/B,SAAUA,EAAe,GAAKI,EAC9B,UAAWQ,EAAAA,KACTC,EAAO,WACPA,EAAOnB,CAAO,EACdmB,EAAOjB,CAAI,EACXE,GAAWe,EAAO,QAClBhB,GAAWgB,EAAO,QAClBd,GAAYc,EAAO,SACnBb,GAAgBa,EAAO,aACvBZ,CAAA,EAEF,MACE,CACE,eAAgB,kBAAkBN,CAAK,QACvC,cAAe,kBAAkBA,CAAK,mBACtC,GAAGO,CAAA,EAGN,GAAGI,EAEH,WAAUK,EAAAA,IAACG,EAAAA,OAAA,CAAO,KAAAlB,EAAY,cAAY,OAAO,EAAKY,CAAA,CAAA,CAG7D,CAAC"}
1
+ {"version":3,"file":"IconButton-DSPdv-oI.cjs","sources":["../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Loader } from '../Loader'\nimport styles from './IconButton.module.css'\n\nexport type IconButtonVariant = 'contained' | 'filled' | 'outlined' | 'text'\nexport type IconButtonSize = 'sm' | 'md' | 'lg'\n\nexport interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'> {\n /** Visual style. `contained` solid · `filled` soft tint · `outlined` border · `text` bare. */\n variant?: IconButtonVariant\n /** Theme palette token that tints the button. Defaults to `accent`. */\n color?: ThemeColor\n /** Preset size — square: width === height === `--tz-control-height-*` (matches `Button` heights). */\n size?: IconButtonSize\n /** Shows the loader in the icon's place and blocks interaction (also sets the native `disabled`). */\n loading?: boolean\n /** Circular shape instead of the default rounded square. */\n rounded?: boolean\n /** Ignores all interaction (no clicks, hover or focus) while keeping the normal look — unlike `disabled`, it's not dimmed. */\n nonClickable?: boolean\n /** The icon to render — typically an `<Icon />`. Swapped for the loader while `loading`. */\n children?: ReactNode\n}\n\n/**\n * A square, text-less button for a single icon. Shares `Button`'s variants,\n * colors and sizing, but its width equals its height (the matching\n * `--tz-control-height-*`). Pass an `<Icon />` (or any node) as the child;\n * while `loading` it's replaced by the `Loader`. Provide an `aria-label` since\n * there's no visible text.\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(\n {\n variant = 'contained',\n color = 'accent',\n size = 'md',\n loading = false,\n rounded = false,\n disabled = false,\n nonClickable = false,\n className,\n style,\n type = 'button',\n tabIndex,\n children,\n ...props\n },\n ref,\n) {\n // size the icon child to match the button (an explicit icon `size` still wins)\n const icon =\n isValidElement(children) && !loading\n ? cloneElement(children as ReactElement<{ size?: IconButtonSize }>, {\n size: (children.props as { size?: IconButtonSize }).size ?? size,\n })\n : children\n\n return (\n <button\n ref={ref}\n type={type}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n aria-disabled={nonClickable || undefined}\n tabIndex={nonClickable ? -1 : tabIndex}\n className={clsx(\n styles.iconButton,\n styles[variant],\n styles[size],\n rounded && styles.rounded,\n loading && styles.loading,\n disabled && styles.disabled,\n nonClickable && styles.nonClickable,\n className,\n )}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${color}-contrast, #fff)`,\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {loading ? <Loader size={size} aria-hidden=\"true\" /> : icon}\n </button>\n )\n})\n"],"names":["IconButton","forwardRef","variant","color","size","loading","rounded","disabled","nonClickable","className","style","type","tabIndex","children","props","ref","icon","isValidElement","cloneElement","jsx","clsx","styles","Loader"],"mappings":"gfAyCaA,EAAaC,EAAAA,WAA+C,SACvE,CACE,QAAAC,EAAU,YACV,MAAAC,EAAQ,SACR,KAAAC,EAAO,KACP,QAAAC,EAAU,GACV,QAAAC,EAAU,GACV,SAAAC,EAAW,GACX,aAAAC,EAAe,GACf,UAAAC,EACA,MAAAC,EACA,KAAAC,EAAO,SACP,SAAAC,EACA,SAAAC,EACA,GAAGC,CACL,EACAC,EACA,CAEA,MAAMC,EACJC,EAAAA,eAAeJ,CAAQ,GAAK,CAACR,EACzBa,EAAAA,aAAaL,EAAqD,CAChE,KAAOA,EAAS,MAAoC,MAAQT,CAAA,CAC7D,EACDS,EAEN,OACEM,EAAAA,IAAC,SAAA,CACC,IAAAJ,EACA,KAAAJ,EACA,SAAUJ,GAAYF,EACtB,YAAWA,GAAW,OACtB,gBAAeG,GAAgB,OAC/B,SAAUA,EAAe,GAAKI,EAC9B,UAAWQ,EAAAA,KACTC,EAAO,WACPA,EAAOnB,CAAO,EACdmB,EAAOjB,CAAI,EACXE,GAAWe,EAAO,QAClBhB,GAAWgB,EAAO,QAClBd,GAAYc,EAAO,SACnBb,GAAgBa,EAAO,aACvBZ,CAAA,EAEF,MACE,CACE,eAAgB,kBAAkBN,CAAK,QACvC,cAAe,kBAAkBA,CAAK,mBACtC,GAAGO,CAAA,EAGN,GAAGI,EAEH,WAAUK,EAAAA,IAACG,EAAAA,OAAA,CAAO,KAAAlB,EAAY,cAAY,OAAO,EAAKY,CAAA,CAAA,CAG7D,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _ } from "react/jsx-runtime";
2
2
  import { forwardRef as y, isValidElement as x, cloneElement as B } from "react";
3
3
  import { clsx as g } from "clsx";
4
- import { L as v } from "./Loader-7v1QBvHY.js";
4
+ import { L as v } from "./Loader-DD1vfqmN.js";
5
5
  const z = "_iconButton_1lspy_1", I = "_sm_1lspy_22", k = "_md_1lspy_27", C = "_lg_1lspy_32", E = "_contained_1lspy_38", L = "_filled_1lspy_50", $ = "_outlined_1lspy_61", j = "_text_1lspy_74", w = "_rounded_1lspy_86", N = "_disabled_1lspy_94", R = "_loading_1lspy_98", V = "_nonClickable_1lspy_103", t = {
6
6
  iconButton: z,
7
7
  sm: I,
@@ -65,4 +65,4 @@ const z = "_iconButton_1lspy_1", I = "_sm_1lspy_22", k = "_md_1lspy_27", C = "_l
65
65
  export {
66
66
  H as I
67
67
  };
68
- //# sourceMappingURL=IconButton-re6xITGO.js.map
68
+ //# sourceMappingURL=IconButton-iWbUJAz7.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"IconButton-re6xITGO.js","sources":["../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Loader } from '../Loader'\nimport styles from './IconButton.module.css'\n\nexport type IconButtonVariant = 'contained' | 'filled' | 'outlined' | 'text'\nexport type IconButtonSize = 'sm' | 'md' | 'lg'\n\nexport interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'> {\n /** Visual style. `contained` solid · `filled` soft tint · `outlined` border · `text` bare. */\n variant?: IconButtonVariant\n /** Theme palette token that tints the button. Defaults to `accent`. */\n color?: ThemeColor\n /** Preset size — square: width === height === `--tz-control-height-*` (matches `Button` heights). */\n size?: IconButtonSize\n /** Shows the loader in the icon's place and blocks interaction (also sets the native `disabled`). */\n loading?: boolean\n /** Circular shape instead of the default rounded square. */\n rounded?: boolean\n /** Ignores all interaction (no clicks, hover or focus) while keeping the normal look — unlike `disabled`, it's not dimmed. */\n nonClickable?: boolean\n /** The icon to render — typically an `<Icon />`. Swapped for the loader while `loading`. */\n children?: ReactNode\n}\n\n/**\n * A square, text-less button for a single icon. Shares `Button`'s variants,\n * colors and sizing, but its width equals its height (the matching\n * `--tz-control-height-*`). Pass an `<Icon />` (or any node) as the child;\n * while `loading` it's replaced by the `Loader`. Provide an `aria-label` since\n * there's no visible text.\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(\n {\n variant = 'contained',\n color = 'accent',\n size = 'md',\n loading = false,\n rounded = false,\n disabled = false,\n nonClickable = false,\n className,\n style,\n type = 'button',\n tabIndex,\n children,\n ...props\n },\n ref,\n) {\n // size the icon child to match the button (an explicit icon `size` still wins)\n const icon =\n isValidElement(children) && !loading\n ? cloneElement(children as ReactElement<{ size?: IconButtonSize }>, {\n size: (children.props as { size?: IconButtonSize }).size ?? size,\n })\n : children\n\n return (\n <button\n ref={ref}\n type={type}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n aria-disabled={nonClickable || undefined}\n tabIndex={nonClickable ? -1 : tabIndex}\n className={clsx(\n styles.iconButton,\n styles[variant],\n styles[size],\n rounded && styles.rounded,\n loading && styles.loading,\n disabled && styles.disabled,\n nonClickable && styles.nonClickable,\n className,\n )}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${color}-contrast, #fff)`,\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {loading ? <Loader size={size} aria-hidden=\"true\" /> : icon}\n </button>\n )\n})\n"],"names":["IconButton","forwardRef","variant","color","size","loading","rounded","disabled","nonClickable","className","style","type","tabIndex","children","props","ref","icon","isValidElement","cloneElement","jsx","clsx","styles","Loader"],"mappings":";;;;;;;;;;;;;;;;;GAyCaA,IAAaC,EAA+C,SACvE;AAAA,EACE,SAAAC,IAAU;AAAA,EACV,OAAAC,IAAQ;AAAA,EACR,MAAAC,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,SAAAC,IAAU;AAAA,EACV,UAAAC,IAAW;AAAA,EACX,cAAAC,IAAe;AAAA,EACf,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AAEA,QAAMC,IACJC,EAAeJ,CAAQ,KAAK,CAACR,IACzBa,EAAaL,GAAqD;AAAA,IAChE,MAAOA,EAAS,MAAoC,QAAQT;AAAA,EAAA,CAC7D,IACDS;AAEN,SACE,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAJ;AAAA,MACA,MAAAJ;AAAA,MACA,UAAUJ,KAAYF;AAAA,MACtB,aAAWA,KAAW;AAAA,MACtB,iBAAeG,KAAgB;AAAA,MAC/B,UAAUA,IAAe,KAAKI;AAAA,MAC9B,WAAWQ;AAAA,QACTC,EAAO;AAAA,QACPA,EAAOnB,CAAO;AAAA,QACdmB,EAAOjB,CAAI;AAAA,QACXE,KAAWe,EAAO;AAAA,QAClBhB,KAAWgB,EAAO;AAAA,QAClBd,KAAYc,EAAO;AAAA,QACnBb,KAAgBa,EAAO;AAAA,QACvBZ;AAAA,MAAA;AAAA,MAEF,OACE;AAAA,QACE,gBAAgB,kBAAkBN,CAAK;AAAA,QACvC,eAAe,kBAAkBA,CAAK;AAAA,QACtC,GAAGO;AAAA,MAAA;AAAA,MAGN,GAAGI;AAAA,MAEH,cAAU,gBAAAK,EAACG,GAAA,EAAO,MAAAlB,GAAY,eAAY,QAAO,IAAKY;AAAA,IAAA;AAAA,EAAA;AAG7D,CAAC;"}
1
+ {"version":3,"file":"IconButton-iWbUJAz7.js","sources":["../src/components/IconButton/IconButton.tsx"],"sourcesContent":["import {\n cloneElement,\n forwardRef,\n isValidElement,\n type ButtonHTMLAttributes,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from 'react'\nimport { clsx } from 'clsx'\nimport type { ThemeColor } from '../../theme'\nimport { Loader } from '../Loader'\nimport styles from './IconButton.module.css'\n\nexport type IconButtonVariant = 'contained' | 'filled' | 'outlined' | 'text'\nexport type IconButtonSize = 'sm' | 'md' | 'lg'\n\nexport interface IconButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'color'> {\n /** Visual style. `contained` solid · `filled` soft tint · `outlined` border · `text` bare. */\n variant?: IconButtonVariant\n /** Theme palette token that tints the button. Defaults to `accent`. */\n color?: ThemeColor\n /** Preset size — square: width === height === `--tz-control-height-*` (matches `Button` heights). */\n size?: IconButtonSize\n /** Shows the loader in the icon's place and blocks interaction (also sets the native `disabled`). */\n loading?: boolean\n /** Circular shape instead of the default rounded square. */\n rounded?: boolean\n /** Ignores all interaction (no clicks, hover or focus) while keeping the normal look — unlike `disabled`, it's not dimmed. */\n nonClickable?: boolean\n /** The icon to render — typically an `<Icon />`. Swapped for the loader while `loading`. */\n children?: ReactNode\n}\n\n/**\n * A square, text-less button for a single icon. Shares `Button`'s variants,\n * colors and sizing, but its width equals its height (the matching\n * `--tz-control-height-*`). Pass an `<Icon />` (or any node) as the child;\n * while `loading` it's replaced by the `Loader`. Provide an `aria-label` since\n * there's no visible text.\n */\nexport const IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(function IconButton(\n {\n variant = 'contained',\n color = 'accent',\n size = 'md',\n loading = false,\n rounded = false,\n disabled = false,\n nonClickable = false,\n className,\n style,\n type = 'button',\n tabIndex,\n children,\n ...props\n },\n ref,\n) {\n // size the icon child to match the button (an explicit icon `size` still wins)\n const icon =\n isValidElement(children) && !loading\n ? cloneElement(children as ReactElement<{ size?: IconButtonSize }>, {\n size: (children.props as { size?: IconButtonSize }).size ?? size,\n })\n : children\n\n return (\n <button\n ref={ref}\n type={type}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n aria-disabled={nonClickable || undefined}\n tabIndex={nonClickable ? -1 : tabIndex}\n className={clsx(\n styles.iconButton,\n styles[variant],\n styles[size],\n rounded && styles.rounded,\n loading && styles.loading,\n disabled && styles.disabled,\n nonClickable && styles.nonClickable,\n className,\n )}\n style={\n {\n '--tz-btn-rgb': `var(--tz-color-${color}-rgb)`,\n '--tz-btn-on': `var(--tz-color-${color}-contrast, #fff)`,\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {loading ? <Loader size={size} aria-hidden=\"true\" /> : icon}\n </button>\n )\n})\n"],"names":["IconButton","forwardRef","variant","color","size","loading","rounded","disabled","nonClickable","className","style","type","tabIndex","children","props","ref","icon","isValidElement","cloneElement","jsx","clsx","styles","Loader"],"mappings":";;;;;;;;;;;;;;;;;GAyCaA,IAAaC,EAA+C,SACvE;AAAA,EACE,SAAAC,IAAU;AAAA,EACV,OAAAC,IAAQ;AAAA,EACR,MAAAC,IAAO;AAAA,EACP,SAAAC,IAAU;AAAA,EACV,SAAAC,IAAU;AAAA,EACV,UAAAC,IAAW;AAAA,EACX,cAAAC,IAAe;AAAA,EACf,WAAAC;AAAA,EACA,OAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,UAAAC;AAAA,EACA,UAAAC;AAAA,EACA,GAAGC;AACL,GACAC,GACA;AAEA,QAAMC,IACJC,EAAeJ,CAAQ,KAAK,CAACR,IACzBa,EAAaL,GAAqD;AAAA,IAChE,MAAOA,EAAS,MAAoC,QAAQT;AAAA,EAAA,CAC7D,IACDS;AAEN,SACE,gBAAAM;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAJ;AAAA,MACA,MAAAJ;AAAA,MACA,UAAUJ,KAAYF;AAAA,MACtB,aAAWA,KAAW;AAAA,MACtB,iBAAeG,KAAgB;AAAA,MAC/B,UAAUA,IAAe,KAAKI;AAAA,MAC9B,WAAWQ;AAAA,QACTC,EAAO;AAAA,QACPA,EAAOnB,CAAO;AAAA,QACdmB,EAAOjB,CAAI;AAAA,QACXE,KAAWe,EAAO;AAAA,QAClBhB,KAAWgB,EAAO;AAAA,QAClBd,KAAYc,EAAO;AAAA,QACnBb,KAAgBa,EAAO;AAAA,QACvBZ;AAAA,MAAA;AAAA,MAEF,OACE;AAAA,QACE,gBAAgB,kBAAkBN,CAAK;AAAA,QACvC,eAAe,kBAAkBA,CAAK;AAAA,QACtC,GAAGO;AAAA,MAAA;AAAA,MAGN,GAAGI;AAAA,MAEH,cAAU,gBAAAK,EAACG,GAAA,EAAO,MAAAlB,GAAY,eAAY,QAAO,IAAKY;AAAA,IAAA;AAAA,EAAA;AAG7D,CAAC;"}