@feugene/granularity 0.9.4 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/dist/chunks/{config-d386uO3O.js.map → config-58Mj2rGH.js.map} +1 -1
  2. package/dist/chunks/{config-D4s_QWVP.js.map → config-8f8624RN.js.map} +1 -1
  3. package/dist/chunks/{config-B_nSBc7W.js.map → config-A-iei0Ux.js.map} +1 -1
  4. package/dist/chunks/{config-CFf7xaG1.js → config-B0uUCaJW.js} +1 -1
  5. package/dist/chunks/{config-CFf7xaG1.js.map → config-B0uUCaJW.js.map} +1 -1
  6. package/dist/chunks/{config-Dcb7xK-C.js.map → config-B3dn-gdC.js.map} +1 -1
  7. package/dist/chunks/{config-D6Oe3blW2.js.map → config-BLa1TEGm2.js.map} +1 -1
  8. package/dist/chunks/{config-Dzd6BzIN2.js.map → config-BeBsN0c12.js.map} +1 -1
  9. package/dist/chunks/{config-BU0olrvr.js.map → config-Bh4NWWsQ.js.map} +1 -1
  10. package/dist/chunks/{config-BeQuykDk2.js.map → config-BuoIngj32.js.map} +1 -1
  11. package/dist/chunks/{config-BbKroFtR.js.map → config-C5-ujXCI.js.map} +1 -1
  12. package/dist/chunks/{config-BY81UKv0.js → config-C8MM2Dg0.js} +1 -1
  13. package/dist/chunks/{config-BY81UKv0.js.map → config-C8MM2Dg0.js.map} +1 -1
  14. package/dist/chunks/{config-DF_RlCIO.js.map → config-CPSdAjUi.js.map} +1 -1
  15. package/dist/chunks/{config-iuMz79Mg.js.map → config-CWTfyPNI.js.map} +1 -1
  16. package/dist/chunks/{config-Br_qI3Za.js → config-C_egzT_K.js} +2 -2
  17. package/dist/chunks/config-C_egzT_K.js.map +1 -0
  18. package/dist/chunks/{config-Ci9nXGUV.js.map → config-C_q_4FrU.js.map} +1 -1
  19. package/dist/chunks/{config-O1_FTqD3.js.map → config-CzgNEHKi.js.map} +1 -1
  20. package/dist/chunks/{config-Bcf-8XlK2.js.map → config-DDUPnue12.js.map} +1 -1
  21. package/dist/chunks/{config-DmjwIqx1.js.map → config-DDwBSoc_.js.map} +1 -1
  22. package/dist/chunks/{config-C5OwJM3-.js → config-DRpkoSvq.js} +1 -1
  23. package/dist/chunks/{config-C5OwJM3-.js.map → config-DRpkoSvq.js.map} +1 -1
  24. package/dist/chunks/{config-DaHI5bD_2.js.map → config-DZrlovR42.js.map} +1 -1
  25. package/dist/chunks/{config-72sW9Bag2.js.map → config-D_Pafsjq2.js.map} +1 -1
  26. package/dist/chunks/{config-B1kFmhpM.js.map → config-DhQc1TRY.js.map} +1 -1
  27. package/dist/chunks/{config-CetsgpaZ2.js.map → config-DkeLkzxj2.js.map} +1 -1
  28. package/dist/chunks/{config-BOdu-O_B.js.map → config-Dl5aZ5VR.js.map} +1 -1
  29. package/dist/chunks/{config-CvGdaXvH.js.map → config-Doa_gU40.js.map} +1 -1
  30. package/dist/chunks/{config-CdJpnjDj.js.map → config-DvDNney3.js.map} +1 -1
  31. package/dist/chunks/{config-CpMYmvVT.js.map → config-NkbzVFZo.js.map} +1 -1
  32. package/dist/chunks/{config-_3De4HFf.js.map → config-RjfJFv1Y.js.map} +1 -1
  33. package/dist/chunks/{config-DoBk_CzG.js.map → config-VJuoznpH.js.map} +1 -1
  34. package/dist/chunks/{config-BnWSHTEU.js.map → config-XspHtPsU.js.map} +1 -1
  35. package/dist/chunks/{config-B2YTEe_h.js.map → config-hSlCXHoG.js.map} +1 -1
  36. package/dist/chunks/{config-DSBlHQVa.js.map → config-lMDE_8A5.js.map} +1 -1
  37. package/dist/chunks/{config-Cp_XHsze.js.map → config-nrOj9p6I.js.map} +1 -1
  38. package/dist/chunks/{en-foQA8imU.js → en-B_fSdoTi.js} +9 -2
  39. package/dist/chunks/en-B_fSdoTi.js.map +1 -0
  40. package/dist/chunks/{es-Bx3Kuy6z.js → es-CISK11Nv.js} +3 -3
  41. package/dist/chunks/{es-Bx3Kuy6z.js.map → es-CISK11Nv.js.map} +1 -1
  42. package/dist/chunks/{es-DZFSojYL.js → es-DKP6fLir.js} +9 -2
  43. package/dist/chunks/es-DKP6fLir.js.map +1 -0
  44. package/dist/chunks/{grDropdownStyles-B41mVR1H.js → grDropdownStyles-Bqx9hOzU.js} +10 -7
  45. package/dist/chunks/grDropdownStyles-Bqx9hOzU.js.map +1 -0
  46. package/dist/chunks/{grModalStyles-DS1Vl6EW.js → grModalStyles-FgaKqx50.js} +1 -1
  47. package/dist/chunks/grModalStyles-FgaKqx50.js.map +1 -0
  48. package/dist/chunks/{grSelectStyles-pUt19VGy.js.map → grSelectStyles-AjWWl007.js.map} +1 -1
  49. package/dist/chunks/{grStyle-CUaTmpyW.js.map → grStyle-D-gPHdyW.js.map} +1 -1
  50. package/dist/chunks/{granularityI18n-LcJ88Vce.js → granularityI18n-D_7jowK2.js} +17 -2
  51. package/dist/chunks/granularityI18n-D_7jowK2.js.map +1 -0
  52. package/dist/chunks/{ru-LhkPpPIl.js → ru-S6VlnurJ.js} +9 -2
  53. package/dist/chunks/ru-S6VlnurJ.js.map +1 -0
  54. package/dist/chunks/{shared-BiqXd5MW.js → shared-DpjTvFno.js} +34 -34
  55. package/dist/chunks/{shared-BiqXd5MW.js.map → shared-DpjTvFno.js.map} +1 -1
  56. package/dist/chunks/useFloating-CLtbU7eD.js +1234 -0
  57. package/dist/chunks/useFloating-CLtbU7eD.js.map +1 -0
  58. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-Br6WJkLE.js → GrConfirmDialog-Bi2KLumL.js} +2 -2
  59. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-Br6WJkLE.js.map → GrConfirmDialog-Bi2KLumL.js.map} +1 -1
  60. package/dist/components/GrConfirmDialog/index.js +1 -1
  61. package/dist/components/GrDialog/chunks/{GrDialog-C7XLxp8e.js → GrDialog-CxK4Lj4F.js} +1 -1
  62. package/dist/components/GrDialog/chunks/{GrDialog-C7XLxp8e.js.map → GrDialog-CxK4Lj4F.js.map} +1 -1
  63. package/dist/components/GrDialog/index.js +1 -1
  64. package/dist/components/GrDropdown/chunks/{GrDropdown-DOvHKnih.js → GrDropdown-BGKeEfZ1.js} +13 -59
  65. package/dist/components/GrDropdown/chunks/GrDropdown-BGKeEfZ1.js.map +1 -0
  66. package/dist/components/GrDropdown/index.js +2 -2
  67. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-CLPwbiyG.js → GrDropdownMenu-CJom_-c2.js} +1 -1
  68. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-CLPwbiyG.js.map → GrDropdownMenu-CJom_-c2.js.map} +1 -1
  69. package/dist/components/GrDropdownMenu/index.js +2 -2
  70. package/dist/components/GrEmptyState/chunks/{GrEmptyState-Dj2V5GaX.js.map → GrEmptyState-yOuZW7-t.js.map} +1 -1
  71. package/dist/components/GrEmptyState/index.js +2 -2
  72. package/dist/components/GrFileUpload/chunks/{GrFileUpload-BEKNB1RM.js → GrFileUpload-CBKK3dgC.js} +1 -1
  73. package/dist/components/GrFileUpload/chunks/{GrFileUpload-BEKNB1RM.js.map → GrFileUpload-CBKK3dgC.js.map} +1 -1
  74. package/dist/components/GrFileUpload/index.js +2 -2
  75. package/dist/components/GrFormField/index.js +1 -1
  76. package/dist/components/GrFormFile/chunks/{GrFormFile-CIleXnfr.js.map → GrFormFile-CkR6cYqf.js.map} +1 -1
  77. package/dist/components/GrFormFile/index.js +2 -2
  78. package/dist/components/GrFormSection/chunks/{GrFormSection-DpGhY7MX.js.map → GrFormSection-dbyzqxYk.js.map} +1 -1
  79. package/dist/components/GrFormSection/index.js +2 -2
  80. package/dist/components/GrImageViewer/chunks/{GrImageViewer-CsvXQHM9.js.map → GrImageViewer-BG40DsHa.js.map} +1 -1
  81. package/dist/components/GrImageViewer/index.js +2 -2
  82. package/dist/components/GrInput/index.js +1 -1
  83. package/dist/components/GrInputTag/chunks/{GrInputTag-Dcj3F6rQ.js → GrInputTag-g-KdUI_Z.js} +1 -1
  84. package/dist/components/GrInputTag/chunks/{GrInputTag-Dcj3F6rQ.js.map → GrInputTag-g-KdUI_Z.js.map} +1 -1
  85. package/dist/components/GrInputTag/index.js +2 -2
  86. package/dist/components/GrLink/chunks/{GrLink-BMwn2iJ9.js → GrLink-KSTmk9Yq.js} +1 -1
  87. package/dist/components/GrLink/chunks/{GrLink-BMwn2iJ9.js.map → GrLink-KSTmk9Yq.js.map} +1 -1
  88. package/dist/components/GrLink/index.js +2 -2
  89. package/dist/components/GrList/chunks/{GrList-D8nM1FuV.js.map → GrList-CUW2sRm_.js.map} +1 -1
  90. package/dist/components/GrList/index.js +2 -2
  91. package/dist/components/GrLoading/index.js +1 -1
  92. package/dist/components/GrModal/chunks/{GrModal-lh0lOmoi.js → GrModal-CSOL3fHQ.js} +1 -1
  93. package/dist/components/GrModal/chunks/{GrModal-lh0lOmoi.js.map → GrModal-CSOL3fHQ.js.map} +1 -1
  94. package/dist/components/GrModal/index.js +3 -3
  95. package/dist/components/GrNavbar/chunks/{GrNavbar-BH7XiF9q.js → GrNavbar-CHxwtFIR.js} +1 -1
  96. package/dist/components/GrNavbar/chunks/{GrNavbar-BH7XiF9q.js.map → GrNavbar-CHxwtFIR.js.map} +1 -1
  97. package/dist/components/GrNavbar/index.js +2 -2
  98. package/dist/components/GrNumberInput/chunks/{GrNumberInput-YIWhV85S.js → GrNumberInput-ClPBwkxx.js} +1 -1
  99. package/dist/components/GrNumberInput/chunks/{GrNumberInput-YIWhV85S.js.map → GrNumberInput-ClPBwkxx.js.map} +1 -1
  100. package/dist/components/GrNumberInput/index.js +2 -2
  101. package/dist/components/GrPagination/chunks/{GrPagination-BNDEqM8_.js → GrPagination-D2GS0ShQ.js} +4 -4
  102. package/dist/components/GrPagination/chunks/GrPagination-D2GS0ShQ.js.map +1 -0
  103. package/dist/components/GrPagination/index.js +2 -2
  104. package/dist/components/GrProgressBar/chunks/{GrProgressBar-C2HdYjp4.js → GrProgressBar-BBSFpVEq.js} +1 -1
  105. package/dist/components/GrProgressBar/chunks/{GrProgressBar-C2HdYjp4.js.map → GrProgressBar-BBSFpVEq.js.map} +1 -1
  106. package/dist/components/GrProgressBar/index.js +2 -2
  107. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BV4EW3XO.js → GrPromptDialog-D_TFqKsF.js} +2 -2
  108. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BV4EW3XO.js.map → GrPromptDialog-D_TFqKsF.js.map} +1 -1
  109. package/dist/components/GrPromptDialog/index.js +2 -2
  110. package/dist/components/GrRadio/chunks/{GrRadio-IFU9Hiu2.js → GrRadio-CSbTnrom.js} +1 -1
  111. package/dist/components/GrRadio/chunks/{GrRadio-IFU9Hiu2.js.map → GrRadio-CSbTnrom.js.map} +1 -1
  112. package/dist/components/GrRadio/index.js +2 -2
  113. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-C8IcJuuF.js → GrRadioGroup-DsrnTygR.js} +1 -1
  114. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-C8IcJuuF.js.map → GrRadioGroup-DsrnTygR.js.map} +1 -1
  115. package/dist/components/GrRadioGroup/index.js +2 -2
  116. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BMvXREcv.js → GrResponseErrorBanner-K1uZ1mYD.js} +1 -1
  117. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BMvXREcv.js.map → GrResponseErrorBanner-K1uZ1mYD.js.map} +1 -1
  118. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CzdTh4gd.js → GrResponseErrorBanner-bM8FC_Bw.js} +1 -1
  119. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CzdTh4gd.js.map → GrResponseErrorBanner-bM8FC_Bw.js.map} +1 -1
  120. package/dist/components/GrResponseErrorBanner/index.js +2 -2
  121. package/dist/components/GrSegmented/chunks/{GrSegmented-BRmwBsEG.js → GrSegmented-DpZGs4VX.js} +1 -1
  122. package/dist/components/GrSegmented/chunks/{GrSegmented-BRmwBsEG.js.map → GrSegmented-DpZGs4VX.js.map} +1 -1
  123. package/dist/components/GrSegmented/index.js +2 -2
  124. package/dist/components/GrSelect/chunks/{GrSelect-CnHdbPlf.js → GrSelect-DSz7jvUb.js} +25 -51
  125. package/dist/components/GrSelect/chunks/GrSelect-DSz7jvUb.js.map +1 -0
  126. package/dist/components/GrSelect/index.js +2 -2
  127. package/dist/components/GrSidebar/chunks/{GrSidebar-BpBtAGBs.js.map → GrSidebar-BW8LRMZ-.js.map} +1 -1
  128. package/dist/components/GrSidebar/index.js +2 -2
  129. package/dist/components/GrSkeleton/chunks/{GrSkeleton-URyMkBqI.js.map → GrSkeleton-B05K0QKh.js.map} +1 -1
  130. package/dist/components/GrSkeleton/index.js +2 -2
  131. package/dist/components/GrSwitch/chunks/{GrSwitch-29h0QhMO.js → GrSwitch-CSRtcN5-.js} +1 -1
  132. package/dist/components/GrSwitch/chunks/{GrSwitch-29h0QhMO.js.map → GrSwitch-CSRtcN5-.js.map} +1 -1
  133. package/dist/components/GrSwitch/index.js +2 -2
  134. package/dist/components/GrTable/index.js +1 -1
  135. package/dist/components/GrTabs/chunks/{GrTabs-D3ntDdtg.js.map → GrTabs-BfeVNMFJ.js.map} +1 -1
  136. package/dist/components/GrTabs/index.js +2 -2
  137. package/dist/components/GrTextarea/chunks/{GrTextarea-Cv6r2GuC.js → GrTextarea-CBBzpF2S.js} +1 -1
  138. package/dist/components/GrTextarea/chunks/{GrTextarea-Cv6r2GuC.js.map → GrTextarea-CBBzpF2S.js.map} +1 -1
  139. package/dist/components/GrTextarea/index.js +2 -2
  140. package/dist/components/GrToaster/chunks/{GrToaster-DluJmR5D.js → GrToaster-C6_iHk2J.js} +4 -3
  141. package/dist/components/GrToaster/chunks/GrToaster-C6_iHk2J.js.map +1 -0
  142. package/dist/components/GrToaster/index.js +2 -2
  143. package/dist/components/GrTooltip/chunks/GrTooltip-BC-40SA5.js +109 -0
  144. package/dist/components/GrTooltip/chunks/GrTooltip-BC-40SA5.js.map +1 -0
  145. package/dist/components/GrTooltip/index.js +2 -2
  146. package/dist/components/GrTree/chunks/{GrTree-B2SMU5Py.js.map → GrTree-uZr5SyQI.js.map} +1 -1
  147. package/dist/components/GrTree/index.js +2 -2
  148. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-C1abr5uH.js → GrTreeSelect-CytivcCa.js} +9 -37
  149. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-CytivcCa.js.map +1 -0
  150. package/dist/components/GrTreeSelect/index.js +2 -2
  151. package/dist/granular-provider-node.js +2 -2
  152. package/dist/granular-provider.js +1 -1
  153. package/dist/i18n/all.js +1 -1
  154. package/dist/i18n/index.js +1 -1
  155. package/dist/index.js +67 -67
  156. package/dist/types/src/components/GrDropdown/grDropdownStyles.d.ts +3 -2
  157. package/dist/types/src/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +2 -2
  158. package/dist/types/src/components/GrDropdownMenu/GrDropdownMenuGroup.vue.d.ts +1 -1
  159. package/dist/types/src/components/GrDropdownMenu/GrDropdownMenuList.vue.d.ts +2 -2
  160. package/dist/types/src/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
  161. package/dist/types/src/components/GrLink/GrLink.vue.d.ts +1 -1
  162. package/dist/types/src/components/GrModal/grModalStyles.d.ts +1 -1
  163. package/dist/types/src/components/GrSegmented/GrSegmented.vue.d.ts +1 -1
  164. package/dist/types/src/components/GrSelect/GrSelect.vue.d.ts +6 -6
  165. package/dist/types/src/composables/internal/useFloating.d.ts +53 -0
  166. package/dist/types/src/i18n/messages/en.d.ts +12 -0
  167. package/dist/types/src/i18n/messages/es.d.ts +12 -0
  168. package/dist/types/src/i18n/messages/ru.d.ts +12 -0
  169. package/package.json +9 -1
  170. package/dist/chunks/config-Br_qI3Za.js.map +0 -1
  171. package/dist/chunks/en-foQA8imU.js.map +0 -1
  172. package/dist/chunks/es-DZFSojYL.js.map +0 -1
  173. package/dist/chunks/grDropdownStyles-B41mVR1H.js.map +0 -1
  174. package/dist/chunks/grModalStyles-DS1Vl6EW.js.map +0 -1
  175. package/dist/chunks/granularityI18n-LcJ88Vce.js.map +0 -1
  176. package/dist/chunks/ru-LhkPpPIl.js.map +0 -1
  177. package/dist/components/GrDropdown/chunks/GrDropdown-DOvHKnih.js.map +0 -1
  178. package/dist/components/GrPagination/chunks/GrPagination-BNDEqM8_.js.map +0 -1
  179. package/dist/components/GrSelect/chunks/GrSelect-CnHdbPlf.js.map +0 -1
  180. package/dist/components/GrToaster/chunks/GrToaster-DluJmR5D.js.map +0 -1
  181. package/dist/components/GrTooltip/chunks/GrTooltip-B7I1AVIC.js +0 -55
  182. package/dist/components/GrTooltip/chunks/GrTooltip-B7I1AVIC.js.map +0 -1
  183. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-C1abr5uH.js.map +0 -1
  184. /package/dist/chunks/{config-d386uO3O.js → config-58Mj2rGH.js} +0 -0
  185. /package/dist/chunks/{config-D4s_QWVP.js → config-8f8624RN.js} +0 -0
  186. /package/dist/chunks/{config-B_nSBc7W.js → config-A-iei0Ux.js} +0 -0
  187. /package/dist/chunks/{config-Dcb7xK-C.js → config-B3dn-gdC.js} +0 -0
  188. /package/dist/chunks/{config-D6Oe3blW2.js → config-BLa1TEGm2.js} +0 -0
  189. /package/dist/chunks/{config-Dzd6BzIN2.js → config-BeBsN0c12.js} +0 -0
  190. /package/dist/chunks/{config-BU0olrvr.js → config-Bh4NWWsQ.js} +0 -0
  191. /package/dist/chunks/{config-BeQuykDk2.js → config-BuoIngj32.js} +0 -0
  192. /package/dist/chunks/{config-BbKroFtR.js → config-C5-ujXCI.js} +0 -0
  193. /package/dist/chunks/{config-DF_RlCIO.js → config-CPSdAjUi.js} +0 -0
  194. /package/dist/chunks/{config-iuMz79Mg.js → config-CWTfyPNI.js} +0 -0
  195. /package/dist/chunks/{config-Ci9nXGUV.js → config-C_q_4FrU.js} +0 -0
  196. /package/dist/chunks/{config-O1_FTqD3.js → config-CzgNEHKi.js} +0 -0
  197. /package/dist/chunks/{config-Bcf-8XlK2.js → config-DDUPnue12.js} +0 -0
  198. /package/dist/chunks/{config-DmjwIqx1.js → config-DDwBSoc_.js} +0 -0
  199. /package/dist/chunks/{config-DaHI5bD_2.js → config-DZrlovR42.js} +0 -0
  200. /package/dist/chunks/{config-72sW9Bag2.js → config-D_Pafsjq2.js} +0 -0
  201. /package/dist/chunks/{config-B1kFmhpM.js → config-DhQc1TRY.js} +0 -0
  202. /package/dist/chunks/{config-CetsgpaZ2.js → config-DkeLkzxj2.js} +0 -0
  203. /package/dist/chunks/{config-BOdu-O_B.js → config-Dl5aZ5VR.js} +0 -0
  204. /package/dist/chunks/{config-CvGdaXvH.js → config-Doa_gU40.js} +0 -0
  205. /package/dist/chunks/{config-CdJpnjDj.js → config-DvDNney3.js} +0 -0
  206. /package/dist/chunks/{config-CpMYmvVT.js → config-NkbzVFZo.js} +0 -0
  207. /package/dist/chunks/{config-_3De4HFf.js → config-RjfJFv1Y.js} +0 -0
  208. /package/dist/chunks/{config-DoBk_CzG.js → config-VJuoznpH.js} +0 -0
  209. /package/dist/chunks/{config-BnWSHTEU.js → config-XspHtPsU.js} +0 -0
  210. /package/dist/chunks/{config-B2YTEe_h.js → config-hSlCXHoG.js} +0 -0
  211. /package/dist/chunks/{config-DSBlHQVa.js → config-lMDE_8A5.js} +0 -0
  212. /package/dist/chunks/{config-Cp_XHsze.js → config-nrOj9p6I.js} +0 -0
  213. /package/dist/chunks/{grSelectStyles-pUt19VGy.js → grSelectStyles-AjWWl007.js} +0 -0
  214. /package/dist/chunks/{grStyle-CUaTmpyW.js → grStyle-D-gPHdyW.js} +0 -0
  215. /package/dist/components/GrEmptyState/chunks/{GrEmptyState-Dj2V5GaX.js → GrEmptyState-yOuZW7-t.js} +0 -0
  216. /package/dist/components/GrFormFile/chunks/{GrFormFile-CIleXnfr.js → GrFormFile-CkR6cYqf.js} +0 -0
  217. /package/dist/components/GrFormSection/chunks/{GrFormSection-DpGhY7MX.js → GrFormSection-dbyzqxYk.js} +0 -0
  218. /package/dist/components/GrImageViewer/chunks/{GrImageViewer-CsvXQHM9.js → GrImageViewer-BG40DsHa.js} +0 -0
  219. /package/dist/components/GrList/chunks/{GrList-D8nM1FuV.js → GrList-CUW2sRm_.js} +0 -0
  220. /package/dist/components/GrSidebar/chunks/{GrSidebar-BpBtAGBs.js → GrSidebar-BW8LRMZ-.js} +0 -0
  221. /package/dist/components/GrSkeleton/chunks/{GrSkeleton-URyMkBqI.js → GrSkeleton-B05K0QKh.js} +0 -0
  222. /package/dist/components/GrTabs/chunks/{GrTabs-D3ntDdtg.js → GrTabs-BfeVNMFJ.js} +0 -0
  223. /package/dist/components/GrTree/chunks/{GrTree-B2SMU5Py.js → GrTree-uZr5SyQI.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrDropdown-BGKeEfZ1.js","names":[],"sources":["../../../../src/components/GrDropdown/GrDropdown.vue","../../../../src/components/GrDropdown/GrDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating } from '../../composables/internal/useFloating'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n grDropdownWidthClass,\n type GrDropdownAlign,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport interface GrDropdownProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownAlign\n /** Ширина панели (tailwind-токены `w-*` или `auto`). */\n width?: GrDropdownWidth\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /** Куда телепортировать панель (`body` по умолчанию). */\n teleportTo?: string | HTMLElement\n}\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: 'body',\n})\n\nconst open = ref(false)\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\n// `align='right'` — правый край панели совпадает с правым краем триггера (bottom-end);\n// `align='left'` — левые края (bottom-start); `align='center'` — floating-ui сам\n// центрирует панель под триггером при обычном `'bottom'` без суффикса.\nconst placementByAlign: Record<GrDropdownAlign, 'bottom-start' | 'bottom-end' | 'bottom'> = {\n left: 'bottom-start',\n right: 'bottom-end',\n center: 'bottom',\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n open,\n {\n placement: () => placementByAlign[props.align],\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\nfunction toggle(): void {\n open.value = !open.value\n}\n\nfunction close(): void {\n open.value = false\n}\n\nfunction closeOnEscape(e: KeyboardEvent): void {\n if (e.key === 'Escape') close()\n}\n\nwatch(\n open,\n (isOpen) => {\n if (typeof document === 'undefined') return\n\n document.removeEventListener('keydown', closeOnEscape)\n if (isOpen) document.addEventListener('keydown', closeOnEscape)\n },\n { immediate: true },\n)\n\nwatch(\n () => props.align,\n () => {\n if (open.value) updateFloatingPosition()\n },\n)\n\nonUnmounted(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', closeOnEscape)\n})\n\nconst widthClass = computed(() => grDropdownWidthClass(props.width))\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => {\n return [widthClass.value, grDropdownOriginClass(resolvedPlacement.value)].filter(Boolean)\n})\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n</script>\n\n<template>\n <div data-ds-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: open, exclude: clickOutsideExclude }\"\n data-ds-dropdown-trigger\n class=\"inline-block max-w-full\"\n @click=\"toggle\"\n >\n <slot name=\"trigger\" :open=\"open\" :toggle=\"toggle\" :close=\"close\" />\n </div>\n\n <teleport :to=\"teleportTo\">\n <transition\n enter-active-class=\"transition ease-out duration-150\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-ds-dropdown-panel\n :class=\"panelClasses\"\n :style=\"floatingStyle\"\n @click=\"onContentClick\"\n >\n <div data-ds-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating } from '../../composables/internal/useFloating'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n grDropdownWidthClass,\n type GrDropdownAlign,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport interface GrDropdownProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownAlign\n /** Ширина панели (tailwind-токены `w-*` или `auto`). */\n width?: GrDropdownWidth\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /** Куда телепортировать панель (`body` по умолчанию). */\n teleportTo?: string | HTMLElement\n}\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: 'body',\n})\n\nconst open = ref(false)\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\n// `align='right'` — правый край панели совпадает с правым краем триггера (bottom-end);\n// `align='left'` — левые края (bottom-start); `align='center'` — floating-ui сам\n// центрирует панель под триггером при обычном `'bottom'` без суффикса.\nconst placementByAlign: Record<GrDropdownAlign, 'bottom-start' | 'bottom-end' | 'bottom'> = {\n left: 'bottom-start',\n right: 'bottom-end',\n center: 'bottom',\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n open,\n {\n placement: () => placementByAlign[props.align],\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\nfunction toggle(): void {\n open.value = !open.value\n}\n\nfunction close(): void {\n open.value = false\n}\n\nfunction closeOnEscape(e: KeyboardEvent): void {\n if (e.key === 'Escape') close()\n}\n\nwatch(\n open,\n (isOpen) => {\n if (typeof document === 'undefined') return\n\n document.removeEventListener('keydown', closeOnEscape)\n if (isOpen) document.addEventListener('keydown', closeOnEscape)\n },\n { immediate: true },\n)\n\nwatch(\n () => props.align,\n () => {\n if (open.value) updateFloatingPosition()\n },\n)\n\nonUnmounted(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', closeOnEscape)\n})\n\nconst widthClass = computed(() => grDropdownWidthClass(props.width))\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => {\n return [widthClass.value, grDropdownOriginClass(resolvedPlacement.value)].filter(Boolean)\n})\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n</script>\n\n<template>\n <div data-ds-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: open, exclude: clickOutsideExclude }\"\n data-ds-dropdown-trigger\n class=\"inline-block max-w-full\"\n @click=\"toggle\"\n >\n <slot name=\"trigger\" :open=\"open\" :toggle=\"toggle\" :close=\"close\" />\n </div>\n\n <teleport :to=\"teleportTo\">\n <transition\n enter-active-class=\"transition ease-out duration-150\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-ds-dropdown-panel\n :class=\"panelClasses\"\n :style=\"floatingStyle\"\n @click=\"onContentClick\"\n >\n <div data-ds-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;EA0BA,MAAM,QAAQ;EAQd,MAAM,OAAO,IAAI,MAAK;EACtB,MAAM,SAAS,IAAwB,KAAI;EAC3C,MAAM,UAAU,IAAwB,KAAI;EAC5C,MAAM,sBAAsB,OAAO,QAAQ,MAAK;EAKhD,MAAM,mBAAsF;GAC1F,MAAM;GACN,OAAO;GACP,QAAQ;GACV;EAEA,MAAM,EAAE,eAAe,mBAAmB,QAAQ,2BAA2B,YAC3E,QACA,SACA,MACA;GACE,iBAAiB,iBAAiB,MAAM;GACxC,WAAW;GACZ,CACH;EAEA,SAAS,SAAe;AACtB,QAAK,QAAQ,CAAC,KAAK;;EAGrB,SAAS,QAAc;AACrB,QAAK,QAAQ;;EAGf,SAAS,cAAc,GAAwB;AAC7C,OAAI,EAAE,QAAQ,SAAU,QAAM;;AAGhC,QACE,OACC,WAAW;AACV,OAAI,OAAO,aAAa,YAAa;AAErC,YAAS,oBAAoB,WAAW,cAAa;AACrD,OAAI,OAAQ,UAAS,iBAAiB,WAAW,cAAa;KAEhE,EAAE,WAAW,MAAM,CACrB;AAEA,cACQ,MAAM,aACN;AACJ,OAAI,KAAK,MAAO,yBAAuB;IAE3C;AAEA,oBAAkB;AAChB,OAAI,OAAO,aAAa,YAAa;AACrC,YAAS,oBAAoB,WAAW,cAAa;IACtD;EAED,MAAM,aAAa,eAAe,qBAAqB,MAAM,MAAM,CAAA;EAEnE,MAAM,iBAAiB,eAAe,uBAAuB,MAAM,aAAa,CAAA;EAEhF,MAAM,eAAe,eAAe;AAClC,UAAO,CAAC,WAAW,OAAO,sBAAsB,kBAAkB,MAAM,CAAC,CAAC,OAAO,QAAO;IACzF;EAED,SAAS,iBAAuB;AAC9B,OAAI,MAAM,oBACR,QAAM;;;uBAMR,mBAkCM,OAlCN,YAkCM,CAAA,gBAAA,WAAA,EAjCJ,mBAQM,OAAA;aAPA;IAAJ,KAAI;IAEJ,4BAAA;IACA,OAAM;IACL,SAAO;OAER,WAAoE,KAAA,QAAA,WAAA;IAA9C,MAAM,KAAA;IAAe;IAAgB;;aAL/B;IAAK,SAAW,KAAA;IAAI,SAAW;IAAmB,CAAA,CAAA,CAAA,GAAA,WAAA,EAQhF,YAsBW,UAAA,EAtBA,IAAI,QAAA,YAAU,EAAA,CACvB,YAoBa,YAAA;IAnBX,sBAAmB;IACnB,oBAAiB;IACjB,kBAAe;IACf,sBAAmB;IACnB,oBAAiB;IACjB,kBAAe;;2BAaT,CAAA,eAXN,mBAWM,OAAA;cATA;KAAJ,KAAI;KACJ,0BAAA;KACC,OAAK,eAAE,aAAA,MAAY;KACnB,OAAK,eAAE,MAAA,cAAa,CAAA;KACpB,SAAO;QAER,mBAEM,OAAA;KAFD,4BAAA;KAA0B,OAAK,eAAE,eAAA,MAAc;QAClD,WAAsC,KAAA,QAAA,WAAA,EAAT,OAAK,CAAA,CAAA,EAAA,EAAA,CAAA,EAAA,EAAA,EAAA,CAAA,CAAA,OAR5B,KAAA,MAAI,CAAA,CAAA,CAAA,CAAA"}
@@ -1,3 +1,3 @@
1
- import { t as GrDropdown_default } from "./chunks/GrDropdown-DOvHKnih.js";
2
- import { n as grDropdownSafelist, t as grDropdownConfig } from "../../chunks/config-Br_qI3Za.js";
1
+ import { t as GrDropdown_default } from "./chunks/GrDropdown-BGKeEfZ1.js";
2
+ import { n as grDropdownSafelist, t as grDropdownConfig } from "../../chunks/config-C_egzT_K.js";
3
3
  export { GrDropdown_default as GrDropdown, GrDropdown_default as default, grDropdownConfig, grDropdownSafelist };
@@ -1,4 +1,4 @@
1
- import { t as GrDropdown_default } from "../../GrDropdown/chunks/GrDropdown-DOvHKnih.js";
1
+ import { t as GrDropdown_default } from "../../GrDropdown/chunks/GrDropdown-BGKeEfZ1.js";
2
2
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, guardReactiveProps, mergeProps, normalizeClass, normalizeProps, openBlock, renderSlot, resolveDynamicComponent, toDisplayString, unref, useAttrs, useSlots, withCtx } from "vue";
3
3
  //#endregion
4
4
  //#region src/components/GrDropdownMenu/GrDropdownMenuList.vue
@@ -1 +1 @@
1
- {"version":3,"file":"GrDropdownMenu-CLPwbiyG.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n props.borderTop ? 'border-t border-[var(--brd)]' : '',\n props.borderBottom ? 'border-b border-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-list :class=\"className\">\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n props.borderTop ? 'border-t border-[var(--brd)]' : '',\n props.borderBottom ? 'border-b border-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-list :class=\"className\">\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\n\nexport type GrDropdownMenuAlign = 'left' | 'right' | 'center'\nexport type GrDropdownMenuWidth = 'auto' | '20' | '48' | '60' | '64' | '80'\n\nexport interface GrDropdownMenuProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownMenuAlign\n /** Ширина панели. */\n width?: GrDropdownMenuWidth\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера; по умолчанию `p-0`. */\n contentClass?: string\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n // В `GrDropdown` есть `p-1`, поэтому здесь по умолчанию обнуляем padding,\n // чтобы пункты меню могли растягиваться до границ.\n contentClass: 'p-0',\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n})\n</script>\n\n<template>\n <GrDropdown\n data-ds-dropdown-menu\n :align=\"align\"\n :width=\"width\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\" />\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\n\nexport type GrDropdownMenuAlign = 'left' | 'right' | 'center'\nexport type GrDropdownMenuWidth = 'auto' | '20' | '48' | '60' | '64' | '80'\n\nexport interface GrDropdownMenuProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownMenuAlign\n /** Ширина панели. */\n width?: GrDropdownMenuWidth\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера; по умолчанию `p-0`. */\n contentClass?: string\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n // В `GrDropdown` есть `p-1`, поэтому здесь по умолчанию обнуляем padding,\n // чтобы пункты меню могли растягиваться до границ.\n contentClass: 'p-0',\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n})\n</script>\n\n<template>\n <GrDropdown\n data-ds-dropdown-menu\n :align=\"align\"\n :width=\"width\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\" />\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nexport type GrDropdownMenuColumnAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\nconst alignClass: Record<GrDropdownMenuColumnAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n}\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-column\n class=\"px-3 py-2 flex items-center\"\n :class=\"alignClass[align]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nexport type GrDropdownMenuColumnAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\nconst alignClass: Record<GrDropdownMenuColumnAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n}\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-column\n class=\"px-3 py-2 flex items-center\"\n :class=\"alignClass[align]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: 2 | 3 | 4\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\nconst colsClass = computed(() => {\n return {\n 2: 'grid-cols-2',\n 3: 'grid-cols-3',\n 4: 'grid-cols-4',\n }[props.cols]\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-columns\n class=\"w-full grid divide-x divide-[var(--brd)]\"\n :class=\"colsClass\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: 2 | 3 | 4\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\nconst colsClass = computed(() => {\n return {\n 2: 'grid-cols-2',\n 3: 'grid-cols-3',\n 4: 'grid-cols-4',\n }[props.cols]\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-columns\n class=\"w-full grid divide-x divide-[var(--brd)]\"\n :class=\"colsClass\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-divider\n role=\"separator\"\n class=\"border-t border-[var(--brd)]\"\n :class=\"inset ? 'mx-2' : ''\"\n />\n</template>\n","<script setup lang=\"ts\">\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-divider\n role=\"separator\"\n class=\"border-t border-[var(--brd)]\"\n :class=\"inset ? 'mx-2' : ''\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nexport type GrDropdownMenuHeaderAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\nconst titleAlignClass = computed(() => {\n const map: Record<GrDropdownMenuHeaderAlign, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n return map[props.align]\n})\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-ds-dropdown-menu-header\n class=\"px-4 py-2 text-[11px] tracking-wide text-[var(--muted-fg)]\"\n :class=\"[titleAlignClass, { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nexport type GrDropdownMenuHeaderAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\nconst titleAlignClass = computed(() => {\n const map: Record<GrDropdownMenuHeaderAlign, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n return map[props.align]\n})\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-ds-dropdown-menu-header\n class=\"px-4 py-2 text-[11px] tracking-wide text-[var(--muted-fg)]\"\n :class=\"[titleAlignClass, { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport type { GrDropdownMenuHeaderAlign } from './GrDropdownMenuHeader.vue'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst itemsClass = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-group class=\"w-full\">\n <GrDropdownMenuHeader\n v-if=\"title\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport type { GrDropdownMenuHeaderAlign } from './GrDropdownMenuHeader.vue'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst itemsClass = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-group class=\"w-full\">\n <GrDropdownMenuHeader\n v-if=\"title\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrDropdownMenuItemAlign = 'left' | 'center' | 'right'\nexport type GrDropdownMenuItemVariant = 'default' | 'danger'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n align: 'left',\n variant: 'default',\n})\n\nconst attrs = useAttrs()\n\nconst isNativeButton = computed(() => props.as === 'button' || props.as === undefined)\n\nconst alignClass = computed(() => {\n const map: Record<GrDropdownMenuItemAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n }\n\n return map[props.align]\n})\n\nconst variantClass = computed(() => {\n if (props.variant === 'danger')\n return 'text-[var(--ds-danger)]'\n\n return 'text-[var(--fg)]'\n})\n\nconst disabledClass = computed(() => {\n if (!props.disabled)\n return ''\n\n return 'cursor-not-allowed opacity-60 pointer-events-none'\n})\n\nconst interactiveClass = computed(() => {\n if (props.disabled)\n return ''\n\n return 'hover:bg-[var(--accent)] hover:text-[var(--accent-fg)]'\n})\n\nconst className = computed(() => {\n return [\n // block/flex + размеры\n 'w-full min-h-[40px] px-4 py-2.5',\n 'flex items-center gap-2',\n // типографика\n 'text-[13px]',\n // взаимодействие\n 'transition-colors duration-150',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',\n alignClass.value,\n variantClass.value,\n interactiveClass.value,\n disabledClass.value,\n ].filter(Boolean).join(' ')\n})\n\nfunction onClickCapture(e: MouseEvent) {\n if (!props.disabled)\n return\n\n e.preventDefault()\n e.stopPropagation()\n}\n</script>\n\n<template>\n <component\n :is=\"as\"\n v-bind=\"attrs\"\n data-ds-dropdown-menu-item\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :disabled=\"isNativeButton ? disabled : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : (attrs.tabindex as any)\"\n @click.capture=\"onClickCapture\"\n >\n <slot />\n </component>\n</template>","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrDropdownMenuItemAlign = 'left' | 'center' | 'right'\nexport type GrDropdownMenuItemVariant = 'default' | 'danger'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n align: 'left',\n variant: 'default',\n})\n\nconst attrs = useAttrs()\n\nconst isNativeButton = computed(() => props.as === 'button' || props.as === undefined)\n\nconst alignClass = computed(() => {\n const map: Record<GrDropdownMenuItemAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n }\n\n return map[props.align]\n})\n\nconst variantClass = computed(() => {\n if (props.variant === 'danger')\n return 'text-[var(--ds-danger)]'\n\n return 'text-[var(--fg)]'\n})\n\nconst disabledClass = computed(() => {\n if (!props.disabled)\n return ''\n\n return 'cursor-not-allowed opacity-60 pointer-events-none'\n})\n\nconst interactiveClass = computed(() => {\n if (props.disabled)\n return ''\n\n return 'hover:bg-[var(--accent)] hover:text-[var(--accent-fg)]'\n})\n\nconst className = computed(() => {\n return [\n // block/flex + размеры\n 'w-full min-h-[40px] px-4 py-2.5',\n 'flex items-center gap-2',\n // типографика\n 'text-[13px]',\n // взаимодействие\n 'transition-colors duration-150',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',\n alignClass.value,\n variantClass.value,\n interactiveClass.value,\n disabledClass.value,\n ].filter(Boolean).join(' ')\n})\n\nfunction onClickCapture(e: MouseEvent) {\n if (!props.disabled)\n return\n\n e.preventDefault()\n e.stopPropagation()\n}\n</script>\n\n<template>\n <component\n :is=\"as\"\n v-bind=\"attrs\"\n data-ds-dropdown-menu-item\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :disabled=\"isNativeButton ? disabled : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : (attrs.tabindex as any)\"\n @click.capture=\"onClickCapture\"\n >\n <slot />\n </component>\n</template>"],"mappings":";;;;;;;;;;;;;;;;;;;;;EASA,MAAM,QAAQ;EAMd,MAAM,YAAY,eAAe;AAC/B,UAAO;IACL;IACA,MAAM,WAAW,iCAAiC;IAClD,MAAM,YAAY,iCAAiC;IACnD,MAAM,eAAe,iCAAiC;IACvD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAG;IAC3B;;uBAIC,mBAEM,OAAA;IAFD,8BAAA;IAA4B,OAAK,eAAE,UAAA,MAAS;OAC/C,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBEiBV,YAqBa,oBAAA;IApBX,yBAAA;IACC,OAAO,QAAA;IACP,OAAO,QAAA;IACP,0BAAwB,QAAA;IACxB,iBAAe,QAAA;;IAEL,SAAO,SAAE,cAAS,CAC3B,WAA0C,KAAA,QAAA,WAAA,eAAA,mBAAb,UAAS,CAAA,CAAA,CAAA,CAAA;IAG7B,SAAO,SAAE,cAAS,CAC3B,YAOqB,4BAAA;KANlB,UAAU,QAAA;KACV,cAAY,QAAA;KACZ,iBAAe,QAAA;KACf,OAAK,eAAE,QAAA,UAAS;;4BAEU,CAA3B,WAA2B,KAAA,QAAA,WAAA,eAAA,mBAAb,UAAS,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;EEnD/B,MAAM,aAAwD;GAC5D,MAAM;GACN,QAAQ;GACR,OAAO;GACT;;uBAIE,mBAMM,OAAA;IALJ,gCAAA;IACA,OAAK,eAAA,CAAC,+BACE,WAAW,QAAA,OAAK,CAAA;OAExB,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,EAAA;;;;;;;;;;EEjBZ,MAAM,QAAQ;EAId,MAAM,YAAY,eAAe;AAC/B,UAAO;IACL,GAAG;IACH,GAAG;IACH,GAAG;IACJ,CAAC,MAAM;IACT;;uBAIC,mBAMM,OAAA;IALJ,iCAAA;IACA,OAAK,eAAA,CAAC,4CACE,UAAA,MAAS,CAAA;OAEjB,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,EAAA;;;;;;;;;;;;;;uBEfV,mBAKE,OAAA;IAJA,iCAAA;IACA,MAAK;IACL,OAAK,eAAA,CAAC,gCACE,QAAA,QAAK,SAAA,GAAA,CAAA;;;;;;;;;;;;;;;;;;EEJjB,MAAM,QAAQ;EAMd,MAAM,QAAQ,UAAS;EACvB,MAAM,YAAY,eAAe,QAAQ,MAAM,MAAM,IAAI,QAAQ,MAAM,QAAQ,CAAA;EAE/E,MAAM,kBAAkB,eAAe;AAMrC,UALuD;IACrD,MAAM;IACN,QAAQ;IACR,OAAO;IACT,CACW,MAAM;IAClB;;UAKS,UAAA,SAAA,WAAA,EADR,mBAOM,OAAA;;IALJ,gCAAA;IACA,OAAK,eAAA,CAAC,8DAA4D,CACzD,gBAAA,OAAe,EAAA,WAAI,QAAA,WAAS,CAAA,CAAA,CAAA;OAErC,WAAwB,KAAA,QAAA,WAAA,EAAA,QAAA,CAAA,gBAAA,gBAAf,QAAA,MAAK,EAAA,EAAA,CAAA,CAAA,CAAA,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;EExBlB,MAAM,QAAQ;EAOd,MAAM,aAAa,eAAe;AAChC,UAAO,CACL,UACA,MAAM,WAAW,iCAAiC,GACnD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAG;IAC3B;;uBAIC,mBAUM,OAVN,YAUM,CARI,QAAA,SAAA,WAAA,EADR,YAKE,8BAAA;;IAHC,OAAO,QAAA;IACP,OAAO,QAAA;IACP,WAAW,QAAA;;;;;uCAEd,mBAEM,OAAA,EAFA,OAAK,eAAE,WAAA,MAAU,EAAA,EAAA,CACrB,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,EAAA,CAAA,CAAA;;;;;;;;;;;;;;;;;;;EEnBd,MAAM,QAAQ;EAOd,MAAM,QAAQ,UAAS;EAEvB,MAAM,iBAAiB,eAAe,MAAM,OAAO,YAAY,MAAM,OAAO,KAAA,EAAS;EAErF,MAAM,aAAa,eAAe;AAOhC,UANqD;IACnD,MAAM;IACN,QAAQ;IACR,OAAO;IACT,CAEW,MAAM;IAClB;EAED,MAAM,eAAe,eAAe;AAClC,OAAI,MAAM,YAAY,SACpB,QAAO;AAET,UAAO;IACR;EAED,MAAM,gBAAgB,eAAe;AACnC,OAAI,CAAC,MAAM,SACT,QAAO;AAET,UAAO;IACR;EAED,MAAM,mBAAmB,eAAe;AACtC,OAAI,MAAM,SACR,QAAO;AAET,UAAO;IACR;EAED,MAAM,YAAY,eAAe;AAC/B,UAAO;IAEL;IACA;IAEA;IAEA;IACA;IACA,WAAW;IACX,aAAa;IACb,iBAAiB;IACjB,cAAc;IACf,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAG;IAC3B;EAED,SAAS,eAAe,GAAe;AACrC,OAAI,CAAC,MAAM,SACT;AAEF,KAAE,gBAAe;AACjB,KAAE,iBAAgB;;;uBAKlB,YAYY,wBAXL,QAAA,GAAE,EADT,WAEU,MAUE,MAVG,EAAA;IACb,8BAAA;IACC,OAAO,UAAA;IACP,MAAM,eAAA,QAAkB,MAAA,MAAK,CAAC,QAAI,WAAuB,KAAA;IACzD,UAAU,eAAA,QAAiB,QAAA,WAAW,KAAA;IACtC,iBAAe,QAAA,WAAQ,SAAY,KAAA;IACnC,UAAU,QAAA,WAAQ,KAAS,MAAA,MAAK,CAAC;IAClB;;2BAER,CAAR,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"GrDropdownMenu-CJom_-c2.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n props.borderTop ? 'border-t border-[var(--brd)]' : '',\n props.borderBottom ? 'border-b border-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-list :class=\"className\">\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n props.borderTop ? 'border-t border-[var(--brd)]' : '',\n props.borderBottom ? 'border-b border-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-list :class=\"className\">\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\n\nexport type GrDropdownMenuAlign = 'left' | 'right' | 'center'\nexport type GrDropdownMenuWidth = 'auto' | '20' | '48' | '60' | '64' | '80'\n\nexport interface GrDropdownMenuProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownMenuAlign\n /** Ширина панели. */\n width?: GrDropdownMenuWidth\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера; по умолчанию `p-0`. */\n contentClass?: string\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n // В `GrDropdown` есть `p-1`, поэтому здесь по умолчанию обнуляем padding,\n // чтобы пункты меню могли растягиваться до границ.\n contentClass: 'p-0',\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n})\n</script>\n\n<template>\n <GrDropdown\n data-ds-dropdown-menu\n :align=\"align\"\n :width=\"width\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\" />\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\n\nexport type GrDropdownMenuAlign = 'left' | 'right' | 'center'\nexport type GrDropdownMenuWidth = 'auto' | '20' | '48' | '60' | '64' | '80'\n\nexport interface GrDropdownMenuProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownMenuAlign\n /** Ширина панели. */\n width?: GrDropdownMenuWidth\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера; по умолчанию `p-0`. */\n contentClass?: string\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n // В `GrDropdown` есть `p-1`, поэтому здесь по умолчанию обнуляем padding,\n // чтобы пункты меню могли растягиваться до границ.\n contentClass: 'p-0',\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n})\n</script>\n\n<template>\n <GrDropdown\n data-ds-dropdown-menu\n :align=\"align\"\n :width=\"width\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\" />\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nexport type GrDropdownMenuColumnAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\nconst alignClass: Record<GrDropdownMenuColumnAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n}\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-column\n class=\"px-3 py-2 flex items-center\"\n :class=\"alignClass[align]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nexport type GrDropdownMenuColumnAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\nconst alignClass: Record<GrDropdownMenuColumnAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n}\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-column\n class=\"px-3 py-2 flex items-center\"\n :class=\"alignClass[align]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: 2 | 3 | 4\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\nconst colsClass = computed(() => {\n return {\n 2: 'grid-cols-2',\n 3: 'grid-cols-3',\n 4: 'grid-cols-4',\n }[props.cols]\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-columns\n class=\"w-full grid divide-x divide-[var(--brd)]\"\n :class=\"colsClass\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: 2 | 3 | 4\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\nconst colsClass = computed(() => {\n return {\n 2: 'grid-cols-2',\n 3: 'grid-cols-3',\n 4: 'grid-cols-4',\n }[props.cols]\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-columns\n class=\"w-full grid divide-x divide-[var(--brd)]\"\n :class=\"colsClass\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-divider\n role=\"separator\"\n class=\"border-t border-[var(--brd)]\"\n :class=\"inset ? 'mx-2' : ''\"\n />\n</template>\n","<script setup lang=\"ts\">\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-ds-dropdown-menu-divider\n role=\"separator\"\n class=\"border-t border-[var(--brd)]\"\n :class=\"inset ? 'mx-2' : ''\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nexport type GrDropdownMenuHeaderAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\nconst titleAlignClass = computed(() => {\n const map: Record<GrDropdownMenuHeaderAlign, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n return map[props.align]\n})\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-ds-dropdown-menu-header\n class=\"px-4 py-2 text-[11px] tracking-wide text-[var(--muted-fg)]\"\n :class=\"[titleAlignClass, { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nexport type GrDropdownMenuHeaderAlign = 'left' | 'center' | 'right'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\nconst titleAlignClass = computed(() => {\n const map: Record<GrDropdownMenuHeaderAlign, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n return map[props.align]\n})\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-ds-dropdown-menu-header\n class=\"px-4 py-2 text-[11px] tracking-wide text-[var(--muted-fg)]\"\n :class=\"[titleAlignClass, { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport type { GrDropdownMenuHeaderAlign } from './GrDropdownMenuHeader.vue'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst itemsClass = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-group class=\"w-full\">\n <GrDropdownMenuHeader\n v-if=\"title\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport type { GrDropdownMenuHeaderAlign } from './GrDropdownMenuHeader.vue'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst itemsClass = computed(() => {\n return [\n 'w-full',\n props.dividers ? 'divide-y divide-[var(--brd)]' : '',\n ].filter(Boolean).join(' ')\n})\n</script>\n\n<template>\n <div data-ds-dropdown-menu-group class=\"w-full\">\n <GrDropdownMenuHeader\n v-if=\"title\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrDropdownMenuItemAlign = 'left' | 'center' | 'right'\nexport type GrDropdownMenuItemVariant = 'default' | 'danger'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n align: 'left',\n variant: 'default',\n})\n\nconst attrs = useAttrs()\n\nconst isNativeButton = computed(() => props.as === 'button' || props.as === undefined)\n\nconst alignClass = computed(() => {\n const map: Record<GrDropdownMenuItemAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n }\n\n return map[props.align]\n})\n\nconst variantClass = computed(() => {\n if (props.variant === 'danger')\n return 'text-[var(--ds-danger)]'\n\n return 'text-[var(--fg)]'\n})\n\nconst disabledClass = computed(() => {\n if (!props.disabled)\n return ''\n\n return 'cursor-not-allowed opacity-60 pointer-events-none'\n})\n\nconst interactiveClass = computed(() => {\n if (props.disabled)\n return ''\n\n return 'hover:bg-[var(--accent)] hover:text-[var(--accent-fg)]'\n})\n\nconst className = computed(() => {\n return [\n // block/flex + размеры\n 'w-full min-h-[40px] px-4 py-2.5',\n 'flex items-center gap-2',\n // типографика\n 'text-[13px]',\n // взаимодействие\n 'transition-colors duration-150',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',\n alignClass.value,\n variantClass.value,\n interactiveClass.value,\n disabledClass.value,\n ].filter(Boolean).join(' ')\n})\n\nfunction onClickCapture(e: MouseEvent) {\n if (!props.disabled)\n return\n\n e.preventDefault()\n e.stopPropagation()\n}\n</script>\n\n<template>\n <component\n :is=\"as\"\n v-bind=\"attrs\"\n data-ds-dropdown-menu-item\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :disabled=\"isNativeButton ? disabled : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : (attrs.tabindex as any)\"\n @click.capture=\"onClickCapture\"\n >\n <slot />\n </component>\n</template>","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrDropdownMenuItemAlign = 'left' | 'center' | 'right'\nexport type GrDropdownMenuItemVariant = 'default' | 'danger'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n align: 'left',\n variant: 'default',\n})\n\nconst attrs = useAttrs()\n\nconst isNativeButton = computed(() => props.as === 'button' || props.as === undefined)\n\nconst alignClass = computed(() => {\n const map: Record<GrDropdownMenuItemAlign, string> = {\n left: 'justify-start text-left',\n center: 'justify-center text-center',\n right: 'justify-end text-right',\n }\n\n return map[props.align]\n})\n\nconst variantClass = computed(() => {\n if (props.variant === 'danger')\n return 'text-[var(--ds-danger)]'\n\n return 'text-[var(--fg)]'\n})\n\nconst disabledClass = computed(() => {\n if (!props.disabled)\n return ''\n\n return 'cursor-not-allowed opacity-60 pointer-events-none'\n})\n\nconst interactiveClass = computed(() => {\n if (props.disabled)\n return ''\n\n return 'hover:bg-[var(--accent)] hover:text-[var(--accent-fg)]'\n})\n\nconst className = computed(() => {\n return [\n // block/flex + размеры\n 'w-full min-h-[40px] px-4 py-2.5',\n 'flex items-center gap-2',\n // типографика\n 'text-[13px]',\n // взаимодействие\n 'transition-colors duration-150',\n 'focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]',\n alignClass.value,\n variantClass.value,\n interactiveClass.value,\n disabledClass.value,\n ].filter(Boolean).join(' ')\n})\n\nfunction onClickCapture(e: MouseEvent) {\n if (!props.disabled)\n return\n\n e.preventDefault()\n e.stopPropagation()\n}\n</script>\n\n<template>\n <component\n :is=\"as\"\n v-bind=\"attrs\"\n data-ds-dropdown-menu-item\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :disabled=\"isNativeButton ? disabled : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :tabindex=\"disabled ? -1 : (attrs.tabindex as any)\"\n @click.capture=\"onClickCapture\"\n >\n <slot />\n </component>\n</template>"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { a as GrDropdownMenuColumns_default, c as GrDropdownMenuList_default, i as GrDropdownMenuDivider_default, n as GrDropdownMenuGroup_default, o as GrDropdownMenuColumn_default, r as GrDropdownMenuHeader_default, s as GrDropdownMenu_default, t as GrDropdownMenuItem_default } from "./chunks/GrDropdownMenu-CLPwbiyG.js";
2
- import { t as grDropdownMenuConfig } from "../../chunks/config-DmjwIqx1.js";
1
+ import { a as GrDropdownMenuColumns_default, c as GrDropdownMenuList_default, i as GrDropdownMenuDivider_default, n as GrDropdownMenuGroup_default, o as GrDropdownMenuColumn_default, r as GrDropdownMenuHeader_default, s as GrDropdownMenu_default, t as GrDropdownMenuItem_default } from "./chunks/GrDropdownMenu-CJom_-c2.js";
2
+ import { t as grDropdownMenuConfig } from "../../chunks/config-DDwBSoc_.js";
3
3
  export { GrDropdownMenu_default as GrDropdownMenu, GrDropdownMenu_default as default, GrDropdownMenuColumn_default as GrDropdownMenuColumn, GrDropdownMenuColumns_default as GrDropdownMenuColumns, GrDropdownMenuDivider_default as GrDropdownMenuDivider, GrDropdownMenuGroup_default as GrDropdownMenuGroup, GrDropdownMenuHeader_default as GrDropdownMenuHeader, GrDropdownMenuItem_default as GrDropdownMenuItem, GrDropdownMenuList_default as GrDropdownMenuList, grDropdownMenuConfig };
@@ -1 +1 @@
1
- {"version":3,"file":"GrEmptyState-Dj2V5GaX.js","names":["$slots"],"sources":["../../../../src/components/GrEmptyState/GrEmptyState.vue","../../../../src/components/GrEmptyState/GrEmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport IconInbox from '~icons/lucide/inbox'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\n\n/**\n * GrEmptyState — карточка пустого состояния с иконкой, заголовком,\n * опциональным описанием и CTA-слотом.\n *\n * - Иконка по умолчанию — `lucide/inbox`, кастомизируется через слот `#icon`.\n * - Default-слот рендерится как контейнер для действий (центрирован).\n */\nexport interface GrEmptyStateProps {\n title: string\n description?: string\n}\n\nwithDefaults(defineProps<GrEmptyStateProps>(), {\n description: undefined,\n})\n</script>\n\n<template>\n <div\n data-ds-empty-state\n class=\"rounded-[var(--ds-radius-lg)] border border-[var(--brd)] bg-[var(--card)] p-6 text-center\"\n >\n <div class=\"flex justify-center\">\n <div class=\"h-12 w-12 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center text-[var(--muted-fg)]\">\n <slot name=\"icon\">\n <GrIcon :size=\"24\">\n <IconInbox aria-hidden=\"true\" />\n </GrIcon>\n </slot>\n </div>\n </div>\n\n <div class=\"mt-4 text-[14px] font-700\">\n {{ title }}\n </div>\n\n <div v-if=\"description\" class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n {{ description }}\n </div>\n\n <div v-if=\"$slots.default\" class=\"mt-4 flex justify-center\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport IconInbox from '~icons/lucide/inbox'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\n\n/**\n * GrEmptyState — карточка пустого состояния с иконкой, заголовком,\n * опциональным описанием и CTA-слотом.\n *\n * - Иконка по умолчанию — `lucide/inbox`, кастомизируется через слот `#icon`.\n * - Default-слот рендерится как контейнер для действий (центрирован).\n */\nexport interface GrEmptyStateProps {\n title: string\n description?: string\n}\n\nwithDefaults(defineProps<GrEmptyStateProps>(), {\n description: undefined,\n})\n</script>\n\n<template>\n <div\n data-ds-empty-state\n class=\"rounded-[var(--ds-radius-lg)] border border-[var(--brd)] bg-[var(--card)] p-6 text-center\"\n >\n <div class=\"flex justify-center\">\n <div class=\"h-12 w-12 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center text-[var(--muted-fg)]\">\n <slot name=\"icon\">\n <GrIcon :size=\"24\">\n <IconInbox aria-hidden=\"true\" />\n </GrIcon>\n </slot>\n </div>\n </div>\n\n <div class=\"mt-4 text-[14px] font-700\">\n {{ title }}\n </div>\n\n <div v-if=\"description\" class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n {{ description }}\n </div>\n\n <div v-if=\"$slots.default\" class=\"mt-4 flex justify-center\">\n <slot />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAuBE,mBAyBM,OAzBN,YAyBM;IArBJ,mBAQM,OARN,YAQM,CAPJ,mBAMM,OANN,YAMM,CALJ,WAIO,KAAA,QAAA,QAAA,EAAA,QAAA,CAHL,YAES,gBAAA,EAFA,MAAM,IAAE,EAAA;4BACiB,CAAhC,YAAgC,MAAA,cAAA,EAAA,EAArB,eAAY,QAAM,CAAA,CAAA,CAAA;;;IAMrC,mBAEM,OAFN,YAEM,gBADD,QAAA,MAAK,EAAA,EAAA;IAGC,QAAA,eAAA,WAAA,EAAX,mBAEM,OAFN,YAEM,gBADD,QAAA,YAAW,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;IAGLA,KAAAA,OAAO,WAAA,WAAA,EAAlB,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA"}
1
+ {"version":3,"file":"GrEmptyState-yOuZW7-t.js","names":["$slots"],"sources":["../../../../src/components/GrEmptyState/GrEmptyState.vue","../../../../src/components/GrEmptyState/GrEmptyState.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport IconInbox from '~icons/lucide/inbox'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\n\n/**\n * GrEmptyState — карточка пустого состояния с иконкой, заголовком,\n * опциональным описанием и CTA-слотом.\n *\n * - Иконка по умолчанию — `lucide/inbox`, кастомизируется через слот `#icon`.\n * - Default-слот рендерится как контейнер для действий (центрирован).\n */\nexport interface GrEmptyStateProps {\n title: string\n description?: string\n}\n\nwithDefaults(defineProps<GrEmptyStateProps>(), {\n description: undefined,\n})\n</script>\n\n<template>\n <div\n data-ds-empty-state\n class=\"rounded-[var(--ds-radius-lg)] border border-[var(--brd)] bg-[var(--card)] p-6 text-center\"\n >\n <div class=\"flex justify-center\">\n <div class=\"h-12 w-12 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center text-[var(--muted-fg)]\">\n <slot name=\"icon\">\n <GrIcon :size=\"24\">\n <IconInbox aria-hidden=\"true\" />\n </GrIcon>\n </slot>\n </div>\n </div>\n\n <div class=\"mt-4 text-[14px] font-700\">\n {{ title }}\n </div>\n\n <div v-if=\"description\" class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n {{ description }}\n </div>\n\n <div v-if=\"$slots.default\" class=\"mt-4 flex justify-center\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport IconInbox from '~icons/lucide/inbox'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\n\n/**\n * GrEmptyState — карточка пустого состояния с иконкой, заголовком,\n * опциональным описанием и CTA-слотом.\n *\n * - Иконка по умолчанию — `lucide/inbox`, кастомизируется через слот `#icon`.\n * - Default-слот рендерится как контейнер для действий (центрирован).\n */\nexport interface GrEmptyStateProps {\n title: string\n description?: string\n}\n\nwithDefaults(defineProps<GrEmptyStateProps>(), {\n description: undefined,\n})\n</script>\n\n<template>\n <div\n data-ds-empty-state\n class=\"rounded-[var(--ds-radius-lg)] border border-[var(--brd)] bg-[var(--card)] p-6 text-center\"\n >\n <div class=\"flex justify-center\">\n <div class=\"h-12 w-12 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center text-[var(--muted-fg)]\">\n <slot name=\"icon\">\n <GrIcon :size=\"24\">\n <IconInbox aria-hidden=\"true\" />\n </GrIcon>\n </slot>\n </div>\n </div>\n\n <div class=\"mt-4 text-[14px] font-700\">\n {{ title }}\n </div>\n\n <div v-if=\"description\" class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n {{ description }}\n </div>\n\n <div v-if=\"$slots.default\" class=\"mt-4 flex justify-center\">\n <slot />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAuBE,mBAyBM,OAzBN,YAyBM;IArBJ,mBAQM,OARN,YAQM,CAPJ,mBAMM,OANN,YAMM,CALJ,WAIO,KAAA,QAAA,QAAA,EAAA,QAAA,CAHL,YAES,gBAAA,EAFA,MAAM,IAAE,EAAA;4BACiB,CAAhC,YAAgC,MAAA,cAAA,EAAA,EAArB,eAAY,QAAM,CAAA,CAAA,CAAA;;;IAMrC,mBAEM,OAFN,YAEM,gBADD,QAAA,MAAK,EAAA,EAAA;IAGC,QAAA,eAAA,WAAA,EAAX,mBAEM,OAFN,YAEM,gBADD,QAAA,YAAW,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;IAGLA,KAAAA,OAAO,WAAA,WAAA,EAAlB,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA"}
@@ -1,3 +1,3 @@
1
- import { t as GrEmptyState_default } from "./chunks/GrEmptyState-Dj2V5GaX.js";
2
- import { t as grEmptyStateConfig } from "../../chunks/config-O1_FTqD3.js";
1
+ import { t as GrEmptyState_default } from "./chunks/GrEmptyState-yOuZW7-t.js";
2
+ import { t as grEmptyStateConfig } from "../../chunks/config-CzgNEHKi.js";
3
3
  export { GrEmptyState_default as GrEmptyState, GrEmptyState_default as default, grEmptyStateConfig };
@@ -1,7 +1,7 @@
1
1
  import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-BV7RBU_0.js";
2
2
  import { t as arrow_up_default } from "../../../chunks/arrow-up-DZdIrpaF.js";
3
3
  import { l as runFileValidators, u as FileValidationError } from "../../../chunks/fileValidation-c_iBg74s.js";
4
- import { t as GrProgressBar_default } from "../../GrProgressBar/chunks/GrProgressBar-C2HdYjp4.js";
4
+ import { t as GrProgressBar_default } from "../../GrProgressBar/chunks/GrProgressBar-BBSFpVEq.js";
5
5
  import { Comment, Fragment, Text, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, reactive, ref, renderList, renderSlot, toDisplayString, unref, useSlots, withCtx } from "vue";
6
6
  //#region src/components/GrFileUpload/uploadViaXhr.ts
7
7
  var GrUploadAbortError = class extends Error {
@@ -1 +1 @@
1
- {"version":3,"file":"GrFileUpload-BEKNB1RM.js","names":["$slots"],"sources":["../../../../src/components/GrFileUpload/uploadViaXhr.ts","../../../../src/components/GrFileUpload/uploadState.ts","../../../../src/components/GrFileUpload/GrFileUpload.vue","../../../../src/components/GrFileUpload/GrFileUpload.vue"],"sourcesContent":["/**\n * Загрузка файлов через `XMLHttpRequest` с поддержкой прогресса аплоада и\n * отмены по `AbortSignal`. Используется в `GrFileUpload` для ветки `action`,\n * а также может применяться пользователем напрямую в `request`-загрузчике.\n */\n\nexport type GrUploadExtraDataValue = string | Blob\n\nexport type GrUploadExtraData = Record<string, GrUploadExtraDataValue | GrUploadExtraDataValue[]>\n\nexport interface GrUploadProgressInfo {\n /** Процент `0..100`. Для запросов без `lengthComputable` значение `0` и `indeterminate = true`. */\n percent: number\n loaded: number\n total: number\n indeterminate: boolean\n}\n\nexport interface UploadViaXhrOptions {\n url: string\n files: File[]\n name: string\n headers?: Record<string, string>\n withCredentials?: boolean\n extraData?: GrUploadExtraData\n signal: AbortSignal\n onProgress?: (info: GrUploadProgressInfo) => void\n}\n\nexport class GrUploadAbortError extends Error {\n constructor(message = 'Upload aborted') {\n super(message)\n this.name = 'GrUploadAbortError'\n }\n}\n\nexport class GrUploadHttpError extends Error {\n status: number\n payload: unknown\n\n constructor(status: number, payload: unknown) {\n super(`Upload failed with status ${status}`)\n this.name = 'GrUploadHttpError'\n this.status = status\n this.payload = payload\n }\n}\n\nfunction appendExtraFormData(body: FormData, extraData: GrUploadExtraData | undefined) {\n if (!extraData) return\n\n for (const [key, value] of Object.entries(extraData)) {\n if (Array.isArray(value)) {\n for (const entry of value) body.append(key, entry)\n continue\n }\n\n body.append(key, value)\n }\n}\n\nfunction parseResponse(xhr: XMLHttpRequest): unknown {\n const contentType = xhr.getResponseHeader('content-type') ?? ''\n const raw = xhr.responseText\n\n if (contentType.includes('application/json')) {\n try {\n return JSON.parse(raw)\n } catch {\n return raw\n }\n }\n\n return raw\n}\n\nexport function uploadViaXhr(options: UploadViaXhrOptions): Promise<unknown> {\n const { url, files, name, headers, withCredentials, extraData, signal, onProgress } = options\n\n return new Promise<unknown>((resolve, reject) => {\n if (signal.aborted) {\n reject(new GrUploadAbortError())\n return\n }\n\n const body = new FormData()\n for (const file of files) body.append(name, file)\n appendExtraFormData(body, extraData)\n\n const xhr = new XMLHttpRequest()\n xhr.open('POST', url, true)\n xhr.withCredentials = !!withCredentials\n\n if (headers) {\n for (const [key, value] of Object.entries(headers))\n xhr.setRequestHeader(key, value)\n }\n\n const onAbort = () => {\n try {\n xhr.abort()\n } catch {\n /* ignore */\n }\n }\n\n signal.addEventListener('abort', onAbort)\n\n const cleanup = () => {\n signal.removeEventListener('abort', onAbort)\n }\n\n if (onProgress) {\n xhr.upload.addEventListener('progress', (event) => {\n const indeterminate = !event.lengthComputable\n const total = indeterminate ? 0 : event.total\n const loaded = indeterminate ? 0 : event.loaded\n const percent = indeterminate || total === 0 ? 0 : Math.min(100, (loaded / total) * 100)\n onProgress({ percent, loaded, total, indeterminate })\n })\n }\n\n xhr.addEventListener('load', () => {\n cleanup()\n const payload = parseResponse(xhr)\n const status = xhr.status\n\n if (status >= 200 && status < 300) {\n if (onProgress) onProgress({ percent: 100, loaded: 1, total: 1, indeterminate: false })\n resolve(payload)\n return\n }\n\n reject(new GrUploadHttpError(status, payload))\n })\n\n xhr.addEventListener('error', () => {\n cleanup()\n reject(new Error('Network error during upload'))\n })\n\n xhr.addEventListener('abort', () => {\n cleanup()\n reject(new GrUploadAbortError())\n })\n\n xhr.send(body)\n })\n}\n","/**\n * Состояние процесса загрузки в `GrFileUpload`.\n *\n * Используется как для внутреннего управления UI, так и пробрасывается наружу\n * через scoped-слоты (`progress`, `default`) и `defineExpose`.\n */\n\nexport type GrUploadPhase = 'idle' | 'uploading' | 'success' | 'error'\n\nexport interface GrUploadStateIdle {\n phase: 'idle'\n percent: 0\n indeterminate: false\n loaded: 0\n total: 0\n}\n\nexport interface GrUploadStateUploading {\n phase: 'uploading'\n percent: number\n indeterminate: boolean\n loaded: number\n total: number\n}\n\nexport interface GrUploadStateSuccess {\n phase: 'success'\n percent: 100\n indeterminate: false\n loaded: number\n total: number\n}\n\nexport interface GrUploadStateError {\n phase: 'error'\n percent: number\n indeterminate: false\n loaded: number\n total: number\n error: unknown\n}\n\nexport type GrUploadState =\n | GrUploadStateIdle\n | GrUploadStateUploading\n | GrUploadStateSuccess\n | GrUploadStateError\n\nexport const GR_UPLOAD_STATE_IDLE: GrUploadStateIdle = Object.freeze({\n phase: 'idle',\n percent: 0,\n indeterminate: false,\n loaded: 0,\n total: 0,\n})\n","<script setup lang=\"ts\">\nimport { Comment, computed, Fragment, nextTick, reactive, ref, Text, useSlots, type VNode } from 'vue'\n\nimport IconArrowUp from '~icons/lucide/arrow-up'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport GrProgressBar from '../GrProgressBar/GrProgressBar.vue'\nimport type { GrProgressBarTone } from '../GrProgressBar/grStyle'\nimport type { FileValidator, FileValidatorSource } from '../../fileValidation'\nimport type { GrUploadProgressInfo } from './uploadViaXhr'\nimport type { GrUploadState } from './uploadState'\n\nimport { FileValidationError, runFileValidators } from '../../fileValidation'\nimport { GrUploadAbortError, uploadViaXhr } from './uploadViaXhr'\nimport { GR_UPLOAD_STATE_IDLE } from './uploadState'\n\nexport type GrFileUploadExtraDataValue = string | Blob\n\nexport type GrFileUploadExtraData = Record<string, GrFileUploadExtraDataValue | GrFileUploadExtraDataValue[]>\n\nexport type GrFileUploadRequestCtx = {\n signal: AbortSignal\n extraData?: GrFileUploadExtraData\n /**\n * Колбэк прогресса аплоада. Пользовательский `request` (например, axios)\n * должен вызывать его из `onUploadProgress`, чтобы `GrFileUpload` отображал\n * прогресс через слот `progress` / дефолтный `GrProgressBar`.\n */\n onProgress?: (info: GrUploadProgressInfo) => void\n}\n\nexport type GrFileUploadRequest = (files: File[], ctx: GrFileUploadRequestCtx) => Promise<any>\n\n/**\n * Пропы `GrFileUpload`.\n *\n * Либо `action` (URL для POST multipart/form-data), либо `request` — кастомный\n * загрузчик (например, через axios). Если переданы оба — приоритет у `request`.\n *\n * `placeholder` — надпись в дефолтном UI-варианте (без слота default).\n */\nexport interface GrFileUploadProps {\n action?: string\n request?: GrFileUploadRequest\n name?: string\n multiple?: boolean\n limit?: number\n onExceed?: (files: File[], limit: number) => void\n beforeUpload?: (file: File) => boolean | Promise<unknown>\n validators?: FileValidator[]\n disabled?: boolean\n headers?: Record<string, string>\n withCredentials?: boolean\n showFileList?: boolean\n uploadExtraData?: (files: File[]) => GrFileUploadExtraData | undefined\n /** i18n: надпись-подсказка в дефолтном UI. */\n placeholder?: string\n /** Показывать дефолтный прогресс-бар (если не используется слот `progress`). */\n showProgress?: boolean\n /** Цветовой тон полосы прогресса в фазе `uploading`. */\n progressTone?: GrProgressBarTone\n /** aria-label для прогресс-бара. */\n progressLabel?: string\n /** Через сколько мс после `success` скрыть прогресс-бар. `0` — не скрывать. */\n hideProgressOnSuccess?: number\n}\n\nconst props = withDefaults(\n defineProps<GrFileUploadProps>(),\n {\n action: undefined,\n request: undefined,\n name: 'file',\n multiple: false,\n limit: undefined,\n onExceed: undefined,\n beforeUpload: undefined,\n validators: undefined,\n disabled: false,\n headers: undefined,\n withCredentials: false,\n showFileList: false,\n uploadExtraData: undefined,\n placeholder: 'Drag files here or click to select',\n showProgress: true,\n progressTone: 'primary',\n progressLabel: 'Upload progress',\n hideProgressOnSuccess: 800,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'success', payload: any): void\n (e: 'error', error: unknown): void\n (e: 'progress', percent: number, info?: GrUploadProgressInfo): void\n (e: 'change', files: File[]): void\n (e: 'stateChange', state: GrUploadState): void\n}>()\n\nconst slots = useSlots()\n\nfunction flattenSlotNodes(nodes: VNode[]): VNode[] {\n const out: VNode[] = []\n\n for (const node of nodes) {\n if (node.type === Fragment && Array.isArray(node.children)) {\n out.push(...flattenSlotNodes(node.children as VNode[]))\n continue\n }\n\n out.push(node)\n }\n\n return out\n}\n\nfunction isWhitespaceTextNode(node: VNode): boolean {\n if (node.type !== Text) return false\n return typeof node.children === 'string' && node.children.trim().length === 0\n}\n\nfunction slotIsTextOnly(nodes: VNode[]): boolean {\n const flat = flattenSlotNodes(nodes)\n const meaningful = flat.filter(node => node.type !== Comment && !isWhitespaceTextNode(node))\n\n if (meaningful.length === 0) return true\n\n for (const node of meaningful) {\n if (node.type !== Text) return false\n }\n\n return true\n}\n\nconst defaultSlotNodes = computed(() => {\n return slots.default ? flattenSlotNodes(slots.default({} as any)) : []\n})\n\nconst hasCustomUi = computed(() => {\n return !!slots.default && !slotIsTextOnly(defaultSlotNodes.value)\n})\n\nconst inputRef = ref<HTMLInputElement | null>(null)\nconst isOver = ref(false)\nlet overCounter = 0\n\nconst lastFiles = ref<File[]>([])\n\nconst state = reactive<GrUploadState>({ ...GR_UPLOAD_STATE_IDLE }) as GrUploadState\n\nlet activeController: AbortController | null = null\nlet hideSuccessTimer: ReturnType<typeof setTimeout> | null = null\n\nfunction clearHideSuccessTimer() {\n if (hideSuccessTimer !== null) {\n clearTimeout(hideSuccessTimer)\n hideSuccessTimer = null\n }\n}\n\nfunction assignState(next: GrUploadState) {\n // мутируем через Object.assign, чтобы сохранить reactive ссылку\n for (const key of Object.keys(state) as (keyof GrUploadState)[])\n delete (state as any)[key]\n Object.assign(state, next)\n emit('stateChange', state as GrUploadState)\n}\n\nfunction setStateIdle() {\n assignState({ ...GR_UPLOAD_STATE_IDLE })\n}\n\nfunction setStateUploading(info?: GrUploadProgressInfo) {\n assignState({\n phase: 'uploading',\n percent: info?.percent ?? 0,\n indeterminate: info?.indeterminate ?? true,\n loaded: info?.loaded ?? 0,\n total: info?.total ?? 0,\n })\n}\n\nfunction setStateSuccess(info: { loaded: number, total: number }) {\n assignState({\n phase: 'success',\n percent: 100,\n indeterminate: false,\n loaded: info.loaded,\n total: info.total,\n })\n}\n\nfunction setStateError(error: unknown) {\n const prev = state\n assignState({\n phase: 'error',\n percent: prev.phase === 'uploading' ? prev.percent : 0,\n indeterminate: false,\n loaded: prev.phase === 'uploading' ? prev.loaded : 0,\n total: prev.phase === 'uploading' ? prev.total : 0,\n error,\n })\n}\n\nfunction handleProgress(info: GrUploadProgressInfo) {\n if (state.phase !== 'uploading') return\n assignState({\n phase: 'uploading',\n percent: info.percent,\n indeterminate: info.indeterminate,\n loaded: info.loaded,\n total: info.total,\n })\n emit('progress', info.percent, info)\n}\n\nconst tabIndex = computed(() => (props.disabled ? -1 : 0))\n\nconst hiddenInputStyle = {\n position: 'fixed',\n top: '-9999px',\n left: '-9999px',\n width: '1px',\n height: '1px',\n opacity: '0',\n overflow: 'hidden',\n pointerEvents: 'none',\n} as const satisfies Record<string, string>\n\nfunction setOver(next: boolean) {\n if (isOver.value === next) return\n isOver.value = next\n}\n\nfunction openDialog() {\n if (props.disabled) return\n inputRef.value?.click()\n}\n\nfunction abort() {\n activeController?.abort()\n activeController = null\n}\n\nfunction normalizeLimit(limit: number | undefined): number | undefined {\n if (typeof limit !== 'number') return undefined\n if (!Number.isFinite(limit)) return undefined\n if (limit <= 0) return undefined\n return Math.floor(limit)\n}\n\n\nasync function uploadViaAction(files: File[], signal: AbortSignal, extraData: GrFileUploadExtraData | undefined) {\n if (!props.action) throw new Error('GrFileUpload: either `action` or `request` must be provided')\n\n return uploadViaXhr({\n url: props.action,\n files,\n name: props.name,\n headers: props.headers,\n withCredentials: props.withCredentials,\n extraData,\n signal,\n onProgress: handleProgress,\n })\n}\n\nasync function runBeforeUpload(files: File[]): Promise<'ok' | { aborted: true; reason: unknown }> {\n if (!props.beforeUpload) return 'ok'\n\n for (const file of files) {\n try {\n const result = props.beforeUpload(file)\n\n if (result === false) {\n return { aborted: true, reason: new Error('Upload aborted by beforeUpload') }\n }\n\n if (result && typeof (result as any).then === 'function')\n await result\n } catch (error) {\n return { aborted: true, reason: error }\n }\n }\n\n return 'ok'\n}\n\nasync function handleFiles(files: File[], source: FileValidatorSource = 'input') {\n if (props.disabled) return\n if (!files.length) return\n\n const normalizedLimit = normalizeLimit(props.limit)\n if (props.multiple && normalizedLimit && files.length > normalizedLimit) {\n props.onExceed?.(files, normalizedLimit)\n emit('error', new Error(`Too many files selected, limit=${normalizedLimit}`))\n return\n }\n\n const { files: valid, issues } = await runFileValidators(files, props.validators ?? [], {\n source,\n multiple: props.multiple,\n })\n\n if (issues.length > 0) {\n emit('error', new FileValidationError(issues, valid))\n return\n }\n\n if (!valid.length) return\n\n lastFiles.value = valid\n\n const before = await runBeforeUpload(valid)\n if (before !== 'ok') {\n emit('error', before.reason)\n return\n }\n\n let extraData: GrFileUploadExtraData | undefined\n try {\n extraData = props.uploadExtraData?.(valid)\n } catch (error) {\n emit('error', error)\n return\n }\n\n abort()\n clearHideSuccessTimer()\n\n const controller = new AbortController()\n activeController = controller\n\n setStateUploading()\n emit('progress', 0, { percent: 0, loaded: 0, total: 0, indeterminate: true })\n\n try {\n const payload = props.request\n ? await props.request(valid, { signal: controller.signal, extraData, onProgress: handleProgress })\n : await uploadViaAction(valid, controller.signal, extraData)\n\n const finalLoaded = state.phase === 'uploading' ? state.total || state.loaded : 0\n setStateSuccess({ loaded: finalLoaded, total: finalLoaded })\n emit('success', payload)\n emit('change', valid)\n emit('progress', 100, { percent: 100, loaded: finalLoaded, total: finalLoaded, indeterminate: false })\n\n if (props.hideProgressOnSuccess && props.hideProgressOnSuccess > 0) {\n hideSuccessTimer = setTimeout(() => {\n if (state.phase === 'success') setStateIdle()\n hideSuccessTimer = null\n }, props.hideProgressOnSuccess)\n }\n } catch (error) {\n if (error instanceof GrUploadAbortError) {\n setStateIdle()\n } else {\n setStateError(error)\n }\n emit('error', error)\n } finally {\n if (activeController === controller) activeController = null\n }\n}\n\nfunction onDragEnter(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter += 1\n setOver(true)\n}\n\nfunction onDragOver(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy'\n}\n\nfunction onDragLeave(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = Math.max(0, overCounter - 1)\n if (overCounter === 0) setOver(false)\n}\n\nfunction onDrop(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = 0\n setOver(false)\n\n const files = event.dataTransfer?.files ? Array.prototype.slice.call(event.dataTransfer.files) as File[] : []\n void handleFiles(files, 'drop')\n}\n\nasync function onInputChange(event: Event) {\n if (props.disabled) return\n\n const target = event.target as HTMLInputElement | null\n const files = target?.files ? Array.prototype.slice.call(target.files) as File[] : []\n\n if (target) target.value = ''\n\n await nextTick()\n await handleFiles(files, 'input')\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n openDialog()\n }\n}\n\nfunction onRootClick() {\n if (hasCustomUi.value) return\n openDialog()\n}\n\nfunction onRootKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n onKeydown(event)\n}\n\nconst effectiveProgressTone = computed<GrProgressBarTone>(() => {\n if (state.phase === 'error') return 'danger'\n if (state.phase === 'success') return 'success'\n return props.progressTone\n})\n\nconst progressVisible = computed(() => state.phase !== 'idle')\nconst progressPercent = computed(() => (state.phase === 'uploading' && state.indeterminate ? 0 : state.percent))\nconst progressText = computed(() => {\n if (state.phase === 'uploading' && state.indeterminate) return ''\n return `${Math.round(progressPercent.value)}%`\n})\n\ndefineExpose({\n uploadFiles: handleFiles,\n abort,\n openDialog,\n state,\n})\n</script>\n\n<template>\n <div\n data-ds-file-upload\n :role=\"hasCustomUi ? undefined : 'button'\"\n :tabindex=\"hasCustomUi ? undefined : tabIndex\"\n :aria-disabled=\"hasCustomUi ? undefined : disabled ? 'true' : 'false'\"\n :class=\"\n hasCustomUi\n ? 'inline-block'\n : [\n 'relative w-full rounded-[var(--ds-radius-lg)] border border-dashed border-[var(--brd)] bg-[var(--card)] px-5 py-6 outline-none transition',\n disabled\n ? 'opacity-60 cursor-not-allowed'\n : 'cursor-pointer hover:bg-[var(--muted)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg)]',\n isOver && !disabled ? 'border-[var(--ring)] bg-[var(--muted)]' : '',\n ]\n \"\n @click=\"onRootClick\"\n @keydown=\"onRootKeydown\"\n @dragenter=\"onDragEnter\"\n @dragover=\"onDragOver\"\n @dragleave=\"onDragLeave\"\n @drop=\"onDrop\"\n >\n <input\n ref=\"inputRef\"\n data-ds-file-upload-input\n :style=\"hiddenInputStyle\"\n type=\"file\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :name=\"name\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n @change=\"onInputChange\"\n >\n\n <slot\n v-if=\"hasCustomUi\"\n :open-dialog=\"openDialog\"\n :abort=\"abort\"\n :disabled=\"disabled\"\n :files=\"lastFiles\"\n :is-over=\"isOver\"\n :state=\"state\"\n />\n\n <div v-else class=\"flex items-start gap-4\">\n <div\n data-ds-file-upload-icon\n class=\"h-12 w-12 shrink-0 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <GrIcon class=\"h-6 w-6 text-[var(--muted-fg)]\">\n <IconArrowUp />\n </GrIcon>\n </div>\n\n <div class=\"min-w-0\">\n <div data-ds-file-upload-label class=\"text-[14px] font-700\">\n <slot name=\"label\">\n <slot>\n {{ placeholder }}\n </slot>\n </slot>\n </div>\n\n <div v-if=\"$slots.tip\" data-ds-file-upload-tip class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n <slot name=\"tip\" />\n </div>\n <div v-else class=\"mt-1 text-[13px] text-[var(--muted-fg)]\" />\n\n <ul v-if=\"showFileList && lastFiles.length\" data-ds-file-upload-list class=\"mt-3 space-y-1\">\n <li\n v-for=\"file in lastFiles\"\n :key=\"file.name\"\n data-ds-file-upload-item\n class=\"text-[13px]\"\n >\n <span class=\"font-600\">{{ file.name }}</span>\n <span class=\"text-[var(--muted-fg)]\"> · {{ Math.ceil(file.size / 1024) }} KB</span>\n </li>\n </ul>\n\n <slot\n v-if=\"showProgress || $slots.progress\"\n name=\"progress\"\n :state=\"state\"\n :percent=\"state.percent\"\n :indeterminate=\"state.phase === 'uploading' && state.indeterminate\"\n :phase=\"state.phase\"\n :files=\"lastFiles\"\n :abort=\"abort\"\n >\n <div\n v-if=\"showProgress\"\n data-ds-file-upload-progress\n class=\"mt-3 transition-opacity duration-150\"\n :class=\"progressVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'\"\n :aria-hidden=\"!progressVisible\"\n >\n <div class=\"flex items-center gap-2\">\n <GrProgressBar\n :value=\"progressPercent\"\n :tone=\"effectiveProgressTone\"\n :aria-label=\"progressLabel\"\n />\n <span\n data-ds-file-upload-progress-text\n class=\"text-[12px] text-[var(--muted-fg)] tabular-nums min-w-[3ch] text-right\"\n >{{ progressText }}</span>\n </div>\n </div>\n </slot>\n </div>\n </div>\n </div>\n</template>","<script setup lang=\"ts\">\nimport { Comment, computed, Fragment, nextTick, reactive, ref, Text, useSlots, type VNode } from 'vue'\n\nimport IconArrowUp from '~icons/lucide/arrow-up'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport GrProgressBar from '../GrProgressBar/GrProgressBar.vue'\nimport type { GrProgressBarTone } from '../GrProgressBar/grStyle'\nimport type { FileValidator, FileValidatorSource } from '../../fileValidation'\nimport type { GrUploadProgressInfo } from './uploadViaXhr'\nimport type { GrUploadState } from './uploadState'\n\nimport { FileValidationError, runFileValidators } from '../../fileValidation'\nimport { GrUploadAbortError, uploadViaXhr } from './uploadViaXhr'\nimport { GR_UPLOAD_STATE_IDLE } from './uploadState'\n\nexport type GrFileUploadExtraDataValue = string | Blob\n\nexport type GrFileUploadExtraData = Record<string, GrFileUploadExtraDataValue | GrFileUploadExtraDataValue[]>\n\nexport type GrFileUploadRequestCtx = {\n signal: AbortSignal\n extraData?: GrFileUploadExtraData\n /**\n * Колбэк прогресса аплоада. Пользовательский `request` (например, axios)\n * должен вызывать его из `onUploadProgress`, чтобы `GrFileUpload` отображал\n * прогресс через слот `progress` / дефолтный `GrProgressBar`.\n */\n onProgress?: (info: GrUploadProgressInfo) => void\n}\n\nexport type GrFileUploadRequest = (files: File[], ctx: GrFileUploadRequestCtx) => Promise<any>\n\n/**\n * Пропы `GrFileUpload`.\n *\n * Либо `action` (URL для POST multipart/form-data), либо `request` — кастомный\n * загрузчик (например, через axios). Если переданы оба — приоритет у `request`.\n *\n * `placeholder` — надпись в дефолтном UI-варианте (без слота default).\n */\nexport interface GrFileUploadProps {\n action?: string\n request?: GrFileUploadRequest\n name?: string\n multiple?: boolean\n limit?: number\n onExceed?: (files: File[], limit: number) => void\n beforeUpload?: (file: File) => boolean | Promise<unknown>\n validators?: FileValidator[]\n disabled?: boolean\n headers?: Record<string, string>\n withCredentials?: boolean\n showFileList?: boolean\n uploadExtraData?: (files: File[]) => GrFileUploadExtraData | undefined\n /** i18n: надпись-подсказка в дефолтном UI. */\n placeholder?: string\n /** Показывать дефолтный прогресс-бар (если не используется слот `progress`). */\n showProgress?: boolean\n /** Цветовой тон полосы прогресса в фазе `uploading`. */\n progressTone?: GrProgressBarTone\n /** aria-label для прогресс-бара. */\n progressLabel?: string\n /** Через сколько мс после `success` скрыть прогресс-бар. `0` — не скрывать. */\n hideProgressOnSuccess?: number\n}\n\nconst props = withDefaults(\n defineProps<GrFileUploadProps>(),\n {\n action: undefined,\n request: undefined,\n name: 'file',\n multiple: false,\n limit: undefined,\n onExceed: undefined,\n beforeUpload: undefined,\n validators: undefined,\n disabled: false,\n headers: undefined,\n withCredentials: false,\n showFileList: false,\n uploadExtraData: undefined,\n placeholder: 'Drag files here or click to select',\n showProgress: true,\n progressTone: 'primary',\n progressLabel: 'Upload progress',\n hideProgressOnSuccess: 800,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'success', payload: any): void\n (e: 'error', error: unknown): void\n (e: 'progress', percent: number, info?: GrUploadProgressInfo): void\n (e: 'change', files: File[]): void\n (e: 'stateChange', state: GrUploadState): void\n}>()\n\nconst slots = useSlots()\n\nfunction flattenSlotNodes(nodes: VNode[]): VNode[] {\n const out: VNode[] = []\n\n for (const node of nodes) {\n if (node.type === Fragment && Array.isArray(node.children)) {\n out.push(...flattenSlotNodes(node.children as VNode[]))\n continue\n }\n\n out.push(node)\n }\n\n return out\n}\n\nfunction isWhitespaceTextNode(node: VNode): boolean {\n if (node.type !== Text) return false\n return typeof node.children === 'string' && node.children.trim().length === 0\n}\n\nfunction slotIsTextOnly(nodes: VNode[]): boolean {\n const flat = flattenSlotNodes(nodes)\n const meaningful = flat.filter(node => node.type !== Comment && !isWhitespaceTextNode(node))\n\n if (meaningful.length === 0) return true\n\n for (const node of meaningful) {\n if (node.type !== Text) return false\n }\n\n return true\n}\n\nconst defaultSlotNodes = computed(() => {\n return slots.default ? flattenSlotNodes(slots.default({} as any)) : []\n})\n\nconst hasCustomUi = computed(() => {\n return !!slots.default && !slotIsTextOnly(defaultSlotNodes.value)\n})\n\nconst inputRef = ref<HTMLInputElement | null>(null)\nconst isOver = ref(false)\nlet overCounter = 0\n\nconst lastFiles = ref<File[]>([])\n\nconst state = reactive<GrUploadState>({ ...GR_UPLOAD_STATE_IDLE }) as GrUploadState\n\nlet activeController: AbortController | null = null\nlet hideSuccessTimer: ReturnType<typeof setTimeout> | null = null\n\nfunction clearHideSuccessTimer() {\n if (hideSuccessTimer !== null) {\n clearTimeout(hideSuccessTimer)\n hideSuccessTimer = null\n }\n}\n\nfunction assignState(next: GrUploadState) {\n // мутируем через Object.assign, чтобы сохранить reactive ссылку\n for (const key of Object.keys(state) as (keyof GrUploadState)[])\n delete (state as any)[key]\n Object.assign(state, next)\n emit('stateChange', state as GrUploadState)\n}\n\nfunction setStateIdle() {\n assignState({ ...GR_UPLOAD_STATE_IDLE })\n}\n\nfunction setStateUploading(info?: GrUploadProgressInfo) {\n assignState({\n phase: 'uploading',\n percent: info?.percent ?? 0,\n indeterminate: info?.indeterminate ?? true,\n loaded: info?.loaded ?? 0,\n total: info?.total ?? 0,\n })\n}\n\nfunction setStateSuccess(info: { loaded: number, total: number }) {\n assignState({\n phase: 'success',\n percent: 100,\n indeterminate: false,\n loaded: info.loaded,\n total: info.total,\n })\n}\n\nfunction setStateError(error: unknown) {\n const prev = state\n assignState({\n phase: 'error',\n percent: prev.phase === 'uploading' ? prev.percent : 0,\n indeterminate: false,\n loaded: prev.phase === 'uploading' ? prev.loaded : 0,\n total: prev.phase === 'uploading' ? prev.total : 0,\n error,\n })\n}\n\nfunction handleProgress(info: GrUploadProgressInfo) {\n if (state.phase !== 'uploading') return\n assignState({\n phase: 'uploading',\n percent: info.percent,\n indeterminate: info.indeterminate,\n loaded: info.loaded,\n total: info.total,\n })\n emit('progress', info.percent, info)\n}\n\nconst tabIndex = computed(() => (props.disabled ? -1 : 0))\n\nconst hiddenInputStyle = {\n position: 'fixed',\n top: '-9999px',\n left: '-9999px',\n width: '1px',\n height: '1px',\n opacity: '0',\n overflow: 'hidden',\n pointerEvents: 'none',\n} as const satisfies Record<string, string>\n\nfunction setOver(next: boolean) {\n if (isOver.value === next) return\n isOver.value = next\n}\n\nfunction openDialog() {\n if (props.disabled) return\n inputRef.value?.click()\n}\n\nfunction abort() {\n activeController?.abort()\n activeController = null\n}\n\nfunction normalizeLimit(limit: number | undefined): number | undefined {\n if (typeof limit !== 'number') return undefined\n if (!Number.isFinite(limit)) return undefined\n if (limit <= 0) return undefined\n return Math.floor(limit)\n}\n\n\nasync function uploadViaAction(files: File[], signal: AbortSignal, extraData: GrFileUploadExtraData | undefined) {\n if (!props.action) throw new Error('GrFileUpload: either `action` or `request` must be provided')\n\n return uploadViaXhr({\n url: props.action,\n files,\n name: props.name,\n headers: props.headers,\n withCredentials: props.withCredentials,\n extraData,\n signal,\n onProgress: handleProgress,\n })\n}\n\nasync function runBeforeUpload(files: File[]): Promise<'ok' | { aborted: true; reason: unknown }> {\n if (!props.beforeUpload) return 'ok'\n\n for (const file of files) {\n try {\n const result = props.beforeUpload(file)\n\n if (result === false) {\n return { aborted: true, reason: new Error('Upload aborted by beforeUpload') }\n }\n\n if (result && typeof (result as any).then === 'function')\n await result\n } catch (error) {\n return { aborted: true, reason: error }\n }\n }\n\n return 'ok'\n}\n\nasync function handleFiles(files: File[], source: FileValidatorSource = 'input') {\n if (props.disabled) return\n if (!files.length) return\n\n const normalizedLimit = normalizeLimit(props.limit)\n if (props.multiple && normalizedLimit && files.length > normalizedLimit) {\n props.onExceed?.(files, normalizedLimit)\n emit('error', new Error(`Too many files selected, limit=${normalizedLimit}`))\n return\n }\n\n const { files: valid, issues } = await runFileValidators(files, props.validators ?? [], {\n source,\n multiple: props.multiple,\n })\n\n if (issues.length > 0) {\n emit('error', new FileValidationError(issues, valid))\n return\n }\n\n if (!valid.length) return\n\n lastFiles.value = valid\n\n const before = await runBeforeUpload(valid)\n if (before !== 'ok') {\n emit('error', before.reason)\n return\n }\n\n let extraData: GrFileUploadExtraData | undefined\n try {\n extraData = props.uploadExtraData?.(valid)\n } catch (error) {\n emit('error', error)\n return\n }\n\n abort()\n clearHideSuccessTimer()\n\n const controller = new AbortController()\n activeController = controller\n\n setStateUploading()\n emit('progress', 0, { percent: 0, loaded: 0, total: 0, indeterminate: true })\n\n try {\n const payload = props.request\n ? await props.request(valid, { signal: controller.signal, extraData, onProgress: handleProgress })\n : await uploadViaAction(valid, controller.signal, extraData)\n\n const finalLoaded = state.phase === 'uploading' ? state.total || state.loaded : 0\n setStateSuccess({ loaded: finalLoaded, total: finalLoaded })\n emit('success', payload)\n emit('change', valid)\n emit('progress', 100, { percent: 100, loaded: finalLoaded, total: finalLoaded, indeterminate: false })\n\n if (props.hideProgressOnSuccess && props.hideProgressOnSuccess > 0) {\n hideSuccessTimer = setTimeout(() => {\n if (state.phase === 'success') setStateIdle()\n hideSuccessTimer = null\n }, props.hideProgressOnSuccess)\n }\n } catch (error) {\n if (error instanceof GrUploadAbortError) {\n setStateIdle()\n } else {\n setStateError(error)\n }\n emit('error', error)\n } finally {\n if (activeController === controller) activeController = null\n }\n}\n\nfunction onDragEnter(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter += 1\n setOver(true)\n}\n\nfunction onDragOver(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy'\n}\n\nfunction onDragLeave(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = Math.max(0, overCounter - 1)\n if (overCounter === 0) setOver(false)\n}\n\nfunction onDrop(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = 0\n setOver(false)\n\n const files = event.dataTransfer?.files ? Array.prototype.slice.call(event.dataTransfer.files) as File[] : []\n void handleFiles(files, 'drop')\n}\n\nasync function onInputChange(event: Event) {\n if (props.disabled) return\n\n const target = event.target as HTMLInputElement | null\n const files = target?.files ? Array.prototype.slice.call(target.files) as File[] : []\n\n if (target) target.value = ''\n\n await nextTick()\n await handleFiles(files, 'input')\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n openDialog()\n }\n}\n\nfunction onRootClick() {\n if (hasCustomUi.value) return\n openDialog()\n}\n\nfunction onRootKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n onKeydown(event)\n}\n\nconst effectiveProgressTone = computed<GrProgressBarTone>(() => {\n if (state.phase === 'error') return 'danger'\n if (state.phase === 'success') return 'success'\n return props.progressTone\n})\n\nconst progressVisible = computed(() => state.phase !== 'idle')\nconst progressPercent = computed(() => (state.phase === 'uploading' && state.indeterminate ? 0 : state.percent))\nconst progressText = computed(() => {\n if (state.phase === 'uploading' && state.indeterminate) return ''\n return `${Math.round(progressPercent.value)}%`\n})\n\ndefineExpose({\n uploadFiles: handleFiles,\n abort,\n openDialog,\n state,\n})\n</script>\n\n<template>\n <div\n data-ds-file-upload\n :role=\"hasCustomUi ? undefined : 'button'\"\n :tabindex=\"hasCustomUi ? undefined : tabIndex\"\n :aria-disabled=\"hasCustomUi ? undefined : disabled ? 'true' : 'false'\"\n :class=\"\n hasCustomUi\n ? 'inline-block'\n : [\n 'relative w-full rounded-[var(--ds-radius-lg)] border border-dashed border-[var(--brd)] bg-[var(--card)] px-5 py-6 outline-none transition',\n disabled\n ? 'opacity-60 cursor-not-allowed'\n : 'cursor-pointer hover:bg-[var(--muted)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg)]',\n isOver && !disabled ? 'border-[var(--ring)] bg-[var(--muted)]' : '',\n ]\n \"\n @click=\"onRootClick\"\n @keydown=\"onRootKeydown\"\n @dragenter=\"onDragEnter\"\n @dragover=\"onDragOver\"\n @dragleave=\"onDragLeave\"\n @drop=\"onDrop\"\n >\n <input\n ref=\"inputRef\"\n data-ds-file-upload-input\n :style=\"hiddenInputStyle\"\n type=\"file\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :name=\"name\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n @change=\"onInputChange\"\n >\n\n <slot\n v-if=\"hasCustomUi\"\n :open-dialog=\"openDialog\"\n :abort=\"abort\"\n :disabled=\"disabled\"\n :files=\"lastFiles\"\n :is-over=\"isOver\"\n :state=\"state\"\n />\n\n <div v-else class=\"flex items-start gap-4\">\n <div\n data-ds-file-upload-icon\n class=\"h-12 w-12 shrink-0 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <GrIcon class=\"h-6 w-6 text-[var(--muted-fg)]\">\n <IconArrowUp />\n </GrIcon>\n </div>\n\n <div class=\"min-w-0\">\n <div data-ds-file-upload-label class=\"text-[14px] font-700\">\n <slot name=\"label\">\n <slot>\n {{ placeholder }}\n </slot>\n </slot>\n </div>\n\n <div v-if=\"$slots.tip\" data-ds-file-upload-tip class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n <slot name=\"tip\" />\n </div>\n <div v-else class=\"mt-1 text-[13px] text-[var(--muted-fg)]\" />\n\n <ul v-if=\"showFileList && lastFiles.length\" data-ds-file-upload-list class=\"mt-3 space-y-1\">\n <li\n v-for=\"file in lastFiles\"\n :key=\"file.name\"\n data-ds-file-upload-item\n class=\"text-[13px]\"\n >\n <span class=\"font-600\">{{ file.name }}</span>\n <span class=\"text-[var(--muted-fg)]\"> · {{ Math.ceil(file.size / 1024) }} KB</span>\n </li>\n </ul>\n\n <slot\n v-if=\"showProgress || $slots.progress\"\n name=\"progress\"\n :state=\"state\"\n :percent=\"state.percent\"\n :indeterminate=\"state.phase === 'uploading' && state.indeterminate\"\n :phase=\"state.phase\"\n :files=\"lastFiles\"\n :abort=\"abort\"\n >\n <div\n v-if=\"showProgress\"\n data-ds-file-upload-progress\n class=\"mt-3 transition-opacity duration-150\"\n :class=\"progressVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'\"\n :aria-hidden=\"!progressVisible\"\n >\n <div class=\"flex items-center gap-2\">\n <GrProgressBar\n :value=\"progressPercent\"\n :tone=\"effectiveProgressTone\"\n :aria-label=\"progressLabel\"\n />\n <span\n data-ds-file-upload-progress-text\n class=\"text-[12px] text-[var(--muted-fg)] tabular-nums min-w-[3ch] text-right\"\n >{{ progressText }}</span>\n </div>\n </div>\n </slot>\n </div>\n </div>\n </div>\n</template>"],"mappings":"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"}
1
+ {"version":3,"file":"GrFileUpload-CBKK3dgC.js","names":["$slots"],"sources":["../../../../src/components/GrFileUpload/uploadViaXhr.ts","../../../../src/components/GrFileUpload/uploadState.ts","../../../../src/components/GrFileUpload/GrFileUpload.vue","../../../../src/components/GrFileUpload/GrFileUpload.vue"],"sourcesContent":["/**\n * Загрузка файлов через `XMLHttpRequest` с поддержкой прогресса аплоада и\n * отмены по `AbortSignal`. Используется в `GrFileUpload` для ветки `action`,\n * а также может применяться пользователем напрямую в `request`-загрузчике.\n */\n\nexport type GrUploadExtraDataValue = string | Blob\n\nexport type GrUploadExtraData = Record<string, GrUploadExtraDataValue | GrUploadExtraDataValue[]>\n\nexport interface GrUploadProgressInfo {\n /** Процент `0..100`. Для запросов без `lengthComputable` значение `0` и `indeterminate = true`. */\n percent: number\n loaded: number\n total: number\n indeterminate: boolean\n}\n\nexport interface UploadViaXhrOptions {\n url: string\n files: File[]\n name: string\n headers?: Record<string, string>\n withCredentials?: boolean\n extraData?: GrUploadExtraData\n signal: AbortSignal\n onProgress?: (info: GrUploadProgressInfo) => void\n}\n\nexport class GrUploadAbortError extends Error {\n constructor(message = 'Upload aborted') {\n super(message)\n this.name = 'GrUploadAbortError'\n }\n}\n\nexport class GrUploadHttpError extends Error {\n status: number\n payload: unknown\n\n constructor(status: number, payload: unknown) {\n super(`Upload failed with status ${status}`)\n this.name = 'GrUploadHttpError'\n this.status = status\n this.payload = payload\n }\n}\n\nfunction appendExtraFormData(body: FormData, extraData: GrUploadExtraData | undefined) {\n if (!extraData) return\n\n for (const [key, value] of Object.entries(extraData)) {\n if (Array.isArray(value)) {\n for (const entry of value) body.append(key, entry)\n continue\n }\n\n body.append(key, value)\n }\n}\n\nfunction parseResponse(xhr: XMLHttpRequest): unknown {\n const contentType = xhr.getResponseHeader('content-type') ?? ''\n const raw = xhr.responseText\n\n if (contentType.includes('application/json')) {\n try {\n return JSON.parse(raw)\n } catch {\n return raw\n }\n }\n\n return raw\n}\n\nexport function uploadViaXhr(options: UploadViaXhrOptions): Promise<unknown> {\n const { url, files, name, headers, withCredentials, extraData, signal, onProgress } = options\n\n return new Promise<unknown>((resolve, reject) => {\n if (signal.aborted) {\n reject(new GrUploadAbortError())\n return\n }\n\n const body = new FormData()\n for (const file of files) body.append(name, file)\n appendExtraFormData(body, extraData)\n\n const xhr = new XMLHttpRequest()\n xhr.open('POST', url, true)\n xhr.withCredentials = !!withCredentials\n\n if (headers) {\n for (const [key, value] of Object.entries(headers))\n xhr.setRequestHeader(key, value)\n }\n\n const onAbort = () => {\n try {\n xhr.abort()\n } catch {\n /* ignore */\n }\n }\n\n signal.addEventListener('abort', onAbort)\n\n const cleanup = () => {\n signal.removeEventListener('abort', onAbort)\n }\n\n if (onProgress) {\n xhr.upload.addEventListener('progress', (event) => {\n const indeterminate = !event.lengthComputable\n const total = indeterminate ? 0 : event.total\n const loaded = indeterminate ? 0 : event.loaded\n const percent = indeterminate || total === 0 ? 0 : Math.min(100, (loaded / total) * 100)\n onProgress({ percent, loaded, total, indeterminate })\n })\n }\n\n xhr.addEventListener('load', () => {\n cleanup()\n const payload = parseResponse(xhr)\n const status = xhr.status\n\n if (status >= 200 && status < 300) {\n if (onProgress) onProgress({ percent: 100, loaded: 1, total: 1, indeterminate: false })\n resolve(payload)\n return\n }\n\n reject(new GrUploadHttpError(status, payload))\n })\n\n xhr.addEventListener('error', () => {\n cleanup()\n reject(new Error('Network error during upload'))\n })\n\n xhr.addEventListener('abort', () => {\n cleanup()\n reject(new GrUploadAbortError())\n })\n\n xhr.send(body)\n })\n}\n","/**\n * Состояние процесса загрузки в `GrFileUpload`.\n *\n * Используется как для внутреннего управления UI, так и пробрасывается наружу\n * через scoped-слоты (`progress`, `default`) и `defineExpose`.\n */\n\nexport type GrUploadPhase = 'idle' | 'uploading' | 'success' | 'error'\n\nexport interface GrUploadStateIdle {\n phase: 'idle'\n percent: 0\n indeterminate: false\n loaded: 0\n total: 0\n}\n\nexport interface GrUploadStateUploading {\n phase: 'uploading'\n percent: number\n indeterminate: boolean\n loaded: number\n total: number\n}\n\nexport interface GrUploadStateSuccess {\n phase: 'success'\n percent: 100\n indeterminate: false\n loaded: number\n total: number\n}\n\nexport interface GrUploadStateError {\n phase: 'error'\n percent: number\n indeterminate: false\n loaded: number\n total: number\n error: unknown\n}\n\nexport type GrUploadState =\n | GrUploadStateIdle\n | GrUploadStateUploading\n | GrUploadStateSuccess\n | GrUploadStateError\n\nexport const GR_UPLOAD_STATE_IDLE: GrUploadStateIdle = Object.freeze({\n phase: 'idle',\n percent: 0,\n indeterminate: false,\n loaded: 0,\n total: 0,\n})\n","<script setup lang=\"ts\">\nimport { Comment, computed, Fragment, nextTick, reactive, ref, Text, useSlots, type VNode } from 'vue'\n\nimport IconArrowUp from '~icons/lucide/arrow-up'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport GrProgressBar from '../GrProgressBar/GrProgressBar.vue'\nimport type { GrProgressBarTone } from '../GrProgressBar/grStyle'\nimport type { FileValidator, FileValidatorSource } from '../../fileValidation'\nimport type { GrUploadProgressInfo } from './uploadViaXhr'\nimport type { GrUploadState } from './uploadState'\n\nimport { FileValidationError, runFileValidators } from '../../fileValidation'\nimport { GrUploadAbortError, uploadViaXhr } from './uploadViaXhr'\nimport { GR_UPLOAD_STATE_IDLE } from './uploadState'\n\nexport type GrFileUploadExtraDataValue = string | Blob\n\nexport type GrFileUploadExtraData = Record<string, GrFileUploadExtraDataValue | GrFileUploadExtraDataValue[]>\n\nexport type GrFileUploadRequestCtx = {\n signal: AbortSignal\n extraData?: GrFileUploadExtraData\n /**\n * Колбэк прогресса аплоада. Пользовательский `request` (например, axios)\n * должен вызывать его из `onUploadProgress`, чтобы `GrFileUpload` отображал\n * прогресс через слот `progress` / дефолтный `GrProgressBar`.\n */\n onProgress?: (info: GrUploadProgressInfo) => void\n}\n\nexport type GrFileUploadRequest = (files: File[], ctx: GrFileUploadRequestCtx) => Promise<any>\n\n/**\n * Пропы `GrFileUpload`.\n *\n * Либо `action` (URL для POST multipart/form-data), либо `request` — кастомный\n * загрузчик (например, через axios). Если переданы оба — приоритет у `request`.\n *\n * `placeholder` — надпись в дефолтном UI-варианте (без слота default).\n */\nexport interface GrFileUploadProps {\n action?: string\n request?: GrFileUploadRequest\n name?: string\n multiple?: boolean\n limit?: number\n onExceed?: (files: File[], limit: number) => void\n beforeUpload?: (file: File) => boolean | Promise<unknown>\n validators?: FileValidator[]\n disabled?: boolean\n headers?: Record<string, string>\n withCredentials?: boolean\n showFileList?: boolean\n uploadExtraData?: (files: File[]) => GrFileUploadExtraData | undefined\n /** i18n: надпись-подсказка в дефолтном UI. */\n placeholder?: string\n /** Показывать дефолтный прогресс-бар (если не используется слот `progress`). */\n showProgress?: boolean\n /** Цветовой тон полосы прогресса в фазе `uploading`. */\n progressTone?: GrProgressBarTone\n /** aria-label для прогресс-бара. */\n progressLabel?: string\n /** Через сколько мс после `success` скрыть прогресс-бар. `0` — не скрывать. */\n hideProgressOnSuccess?: number\n}\n\nconst props = withDefaults(\n defineProps<GrFileUploadProps>(),\n {\n action: undefined,\n request: undefined,\n name: 'file',\n multiple: false,\n limit: undefined,\n onExceed: undefined,\n beforeUpload: undefined,\n validators: undefined,\n disabled: false,\n headers: undefined,\n withCredentials: false,\n showFileList: false,\n uploadExtraData: undefined,\n placeholder: 'Drag files here or click to select',\n showProgress: true,\n progressTone: 'primary',\n progressLabel: 'Upload progress',\n hideProgressOnSuccess: 800,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'success', payload: any): void\n (e: 'error', error: unknown): void\n (e: 'progress', percent: number, info?: GrUploadProgressInfo): void\n (e: 'change', files: File[]): void\n (e: 'stateChange', state: GrUploadState): void\n}>()\n\nconst slots = useSlots()\n\nfunction flattenSlotNodes(nodes: VNode[]): VNode[] {\n const out: VNode[] = []\n\n for (const node of nodes) {\n if (node.type === Fragment && Array.isArray(node.children)) {\n out.push(...flattenSlotNodes(node.children as VNode[]))\n continue\n }\n\n out.push(node)\n }\n\n return out\n}\n\nfunction isWhitespaceTextNode(node: VNode): boolean {\n if (node.type !== Text) return false\n return typeof node.children === 'string' && node.children.trim().length === 0\n}\n\nfunction slotIsTextOnly(nodes: VNode[]): boolean {\n const flat = flattenSlotNodes(nodes)\n const meaningful = flat.filter(node => node.type !== Comment && !isWhitespaceTextNode(node))\n\n if (meaningful.length === 0) return true\n\n for (const node of meaningful) {\n if (node.type !== Text) return false\n }\n\n return true\n}\n\nconst defaultSlotNodes = computed(() => {\n return slots.default ? flattenSlotNodes(slots.default({} as any)) : []\n})\n\nconst hasCustomUi = computed(() => {\n return !!slots.default && !slotIsTextOnly(defaultSlotNodes.value)\n})\n\nconst inputRef = ref<HTMLInputElement | null>(null)\nconst isOver = ref(false)\nlet overCounter = 0\n\nconst lastFiles = ref<File[]>([])\n\nconst state = reactive<GrUploadState>({ ...GR_UPLOAD_STATE_IDLE }) as GrUploadState\n\nlet activeController: AbortController | null = null\nlet hideSuccessTimer: ReturnType<typeof setTimeout> | null = null\n\nfunction clearHideSuccessTimer() {\n if (hideSuccessTimer !== null) {\n clearTimeout(hideSuccessTimer)\n hideSuccessTimer = null\n }\n}\n\nfunction assignState(next: GrUploadState) {\n // мутируем через Object.assign, чтобы сохранить reactive ссылку\n for (const key of Object.keys(state) as (keyof GrUploadState)[])\n delete (state as any)[key]\n Object.assign(state, next)\n emit('stateChange', state as GrUploadState)\n}\n\nfunction setStateIdle() {\n assignState({ ...GR_UPLOAD_STATE_IDLE })\n}\n\nfunction setStateUploading(info?: GrUploadProgressInfo) {\n assignState({\n phase: 'uploading',\n percent: info?.percent ?? 0,\n indeterminate: info?.indeterminate ?? true,\n loaded: info?.loaded ?? 0,\n total: info?.total ?? 0,\n })\n}\n\nfunction setStateSuccess(info: { loaded: number, total: number }) {\n assignState({\n phase: 'success',\n percent: 100,\n indeterminate: false,\n loaded: info.loaded,\n total: info.total,\n })\n}\n\nfunction setStateError(error: unknown) {\n const prev = state\n assignState({\n phase: 'error',\n percent: prev.phase === 'uploading' ? prev.percent : 0,\n indeterminate: false,\n loaded: prev.phase === 'uploading' ? prev.loaded : 0,\n total: prev.phase === 'uploading' ? prev.total : 0,\n error,\n })\n}\n\nfunction handleProgress(info: GrUploadProgressInfo) {\n if (state.phase !== 'uploading') return\n assignState({\n phase: 'uploading',\n percent: info.percent,\n indeterminate: info.indeterminate,\n loaded: info.loaded,\n total: info.total,\n })\n emit('progress', info.percent, info)\n}\n\nconst tabIndex = computed(() => (props.disabled ? -1 : 0))\n\nconst hiddenInputStyle = {\n position: 'fixed',\n top: '-9999px',\n left: '-9999px',\n width: '1px',\n height: '1px',\n opacity: '0',\n overflow: 'hidden',\n pointerEvents: 'none',\n} as const satisfies Record<string, string>\n\nfunction setOver(next: boolean) {\n if (isOver.value === next) return\n isOver.value = next\n}\n\nfunction openDialog() {\n if (props.disabled) return\n inputRef.value?.click()\n}\n\nfunction abort() {\n activeController?.abort()\n activeController = null\n}\n\nfunction normalizeLimit(limit: number | undefined): number | undefined {\n if (typeof limit !== 'number') return undefined\n if (!Number.isFinite(limit)) return undefined\n if (limit <= 0) return undefined\n return Math.floor(limit)\n}\n\n\nasync function uploadViaAction(files: File[], signal: AbortSignal, extraData: GrFileUploadExtraData | undefined) {\n if (!props.action) throw new Error('GrFileUpload: either `action` or `request` must be provided')\n\n return uploadViaXhr({\n url: props.action,\n files,\n name: props.name,\n headers: props.headers,\n withCredentials: props.withCredentials,\n extraData,\n signal,\n onProgress: handleProgress,\n })\n}\n\nasync function runBeforeUpload(files: File[]): Promise<'ok' | { aborted: true; reason: unknown }> {\n if (!props.beforeUpload) return 'ok'\n\n for (const file of files) {\n try {\n const result = props.beforeUpload(file)\n\n if (result === false) {\n return { aborted: true, reason: new Error('Upload aborted by beforeUpload') }\n }\n\n if (result && typeof (result as any).then === 'function')\n await result\n } catch (error) {\n return { aborted: true, reason: error }\n }\n }\n\n return 'ok'\n}\n\nasync function handleFiles(files: File[], source: FileValidatorSource = 'input') {\n if (props.disabled) return\n if (!files.length) return\n\n const normalizedLimit = normalizeLimit(props.limit)\n if (props.multiple && normalizedLimit && files.length > normalizedLimit) {\n props.onExceed?.(files, normalizedLimit)\n emit('error', new Error(`Too many files selected, limit=${normalizedLimit}`))\n return\n }\n\n const { files: valid, issues } = await runFileValidators(files, props.validators ?? [], {\n source,\n multiple: props.multiple,\n })\n\n if (issues.length > 0) {\n emit('error', new FileValidationError(issues, valid))\n return\n }\n\n if (!valid.length) return\n\n lastFiles.value = valid\n\n const before = await runBeforeUpload(valid)\n if (before !== 'ok') {\n emit('error', before.reason)\n return\n }\n\n let extraData: GrFileUploadExtraData | undefined\n try {\n extraData = props.uploadExtraData?.(valid)\n } catch (error) {\n emit('error', error)\n return\n }\n\n abort()\n clearHideSuccessTimer()\n\n const controller = new AbortController()\n activeController = controller\n\n setStateUploading()\n emit('progress', 0, { percent: 0, loaded: 0, total: 0, indeterminate: true })\n\n try {\n const payload = props.request\n ? await props.request(valid, { signal: controller.signal, extraData, onProgress: handleProgress })\n : await uploadViaAction(valid, controller.signal, extraData)\n\n const finalLoaded = state.phase === 'uploading' ? state.total || state.loaded : 0\n setStateSuccess({ loaded: finalLoaded, total: finalLoaded })\n emit('success', payload)\n emit('change', valid)\n emit('progress', 100, { percent: 100, loaded: finalLoaded, total: finalLoaded, indeterminate: false })\n\n if (props.hideProgressOnSuccess && props.hideProgressOnSuccess > 0) {\n hideSuccessTimer = setTimeout(() => {\n if (state.phase === 'success') setStateIdle()\n hideSuccessTimer = null\n }, props.hideProgressOnSuccess)\n }\n } catch (error) {\n if (error instanceof GrUploadAbortError) {\n setStateIdle()\n } else {\n setStateError(error)\n }\n emit('error', error)\n } finally {\n if (activeController === controller) activeController = null\n }\n}\n\nfunction onDragEnter(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter += 1\n setOver(true)\n}\n\nfunction onDragOver(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy'\n}\n\nfunction onDragLeave(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = Math.max(0, overCounter - 1)\n if (overCounter === 0) setOver(false)\n}\n\nfunction onDrop(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = 0\n setOver(false)\n\n const files = event.dataTransfer?.files ? Array.prototype.slice.call(event.dataTransfer.files) as File[] : []\n void handleFiles(files, 'drop')\n}\n\nasync function onInputChange(event: Event) {\n if (props.disabled) return\n\n const target = event.target as HTMLInputElement | null\n const files = target?.files ? Array.prototype.slice.call(target.files) as File[] : []\n\n if (target) target.value = ''\n\n await nextTick()\n await handleFiles(files, 'input')\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n openDialog()\n }\n}\n\nfunction onRootClick() {\n if (hasCustomUi.value) return\n openDialog()\n}\n\nfunction onRootKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n onKeydown(event)\n}\n\nconst effectiveProgressTone = computed<GrProgressBarTone>(() => {\n if (state.phase === 'error') return 'danger'\n if (state.phase === 'success') return 'success'\n return props.progressTone\n})\n\nconst progressVisible = computed(() => state.phase !== 'idle')\nconst progressPercent = computed(() => (state.phase === 'uploading' && state.indeterminate ? 0 : state.percent))\nconst progressText = computed(() => {\n if (state.phase === 'uploading' && state.indeterminate) return ''\n return `${Math.round(progressPercent.value)}%`\n})\n\ndefineExpose({\n uploadFiles: handleFiles,\n abort,\n openDialog,\n state,\n})\n</script>\n\n<template>\n <div\n data-ds-file-upload\n :role=\"hasCustomUi ? undefined : 'button'\"\n :tabindex=\"hasCustomUi ? undefined : tabIndex\"\n :aria-disabled=\"hasCustomUi ? undefined : disabled ? 'true' : 'false'\"\n :class=\"\n hasCustomUi\n ? 'inline-block'\n : [\n 'relative w-full rounded-[var(--ds-radius-lg)] border border-dashed border-[var(--brd)] bg-[var(--card)] px-5 py-6 outline-none transition',\n disabled\n ? 'opacity-60 cursor-not-allowed'\n : 'cursor-pointer hover:bg-[var(--muted)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg)]',\n isOver && !disabled ? 'border-[var(--ring)] bg-[var(--muted)]' : '',\n ]\n \"\n @click=\"onRootClick\"\n @keydown=\"onRootKeydown\"\n @dragenter=\"onDragEnter\"\n @dragover=\"onDragOver\"\n @dragleave=\"onDragLeave\"\n @drop=\"onDrop\"\n >\n <input\n ref=\"inputRef\"\n data-ds-file-upload-input\n :style=\"hiddenInputStyle\"\n type=\"file\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :name=\"name\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n @change=\"onInputChange\"\n >\n\n <slot\n v-if=\"hasCustomUi\"\n :open-dialog=\"openDialog\"\n :abort=\"abort\"\n :disabled=\"disabled\"\n :files=\"lastFiles\"\n :is-over=\"isOver\"\n :state=\"state\"\n />\n\n <div v-else class=\"flex items-start gap-4\">\n <div\n data-ds-file-upload-icon\n class=\"h-12 w-12 shrink-0 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <GrIcon class=\"h-6 w-6 text-[var(--muted-fg)]\">\n <IconArrowUp />\n </GrIcon>\n </div>\n\n <div class=\"min-w-0\">\n <div data-ds-file-upload-label class=\"text-[14px] font-700\">\n <slot name=\"label\">\n <slot>\n {{ placeholder }}\n </slot>\n </slot>\n </div>\n\n <div v-if=\"$slots.tip\" data-ds-file-upload-tip class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n <slot name=\"tip\" />\n </div>\n <div v-else class=\"mt-1 text-[13px] text-[var(--muted-fg)]\" />\n\n <ul v-if=\"showFileList && lastFiles.length\" data-ds-file-upload-list class=\"mt-3 space-y-1\">\n <li\n v-for=\"file in lastFiles\"\n :key=\"file.name\"\n data-ds-file-upload-item\n class=\"text-[13px]\"\n >\n <span class=\"font-600\">{{ file.name }}</span>\n <span class=\"text-[var(--muted-fg)]\"> · {{ Math.ceil(file.size / 1024) }} KB</span>\n </li>\n </ul>\n\n <slot\n v-if=\"showProgress || $slots.progress\"\n name=\"progress\"\n :state=\"state\"\n :percent=\"state.percent\"\n :indeterminate=\"state.phase === 'uploading' && state.indeterminate\"\n :phase=\"state.phase\"\n :files=\"lastFiles\"\n :abort=\"abort\"\n >\n <div\n v-if=\"showProgress\"\n data-ds-file-upload-progress\n class=\"mt-3 transition-opacity duration-150\"\n :class=\"progressVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'\"\n :aria-hidden=\"!progressVisible\"\n >\n <div class=\"flex items-center gap-2\">\n <GrProgressBar\n :value=\"progressPercent\"\n :tone=\"effectiveProgressTone\"\n :aria-label=\"progressLabel\"\n />\n <span\n data-ds-file-upload-progress-text\n class=\"text-[12px] text-[var(--muted-fg)] tabular-nums min-w-[3ch] text-right\"\n >{{ progressText }}</span>\n </div>\n </div>\n </slot>\n </div>\n </div>\n </div>\n</template>","<script setup lang=\"ts\">\nimport { Comment, computed, Fragment, nextTick, reactive, ref, Text, useSlots, type VNode } from 'vue'\n\nimport IconArrowUp from '~icons/lucide/arrow-up'\n\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport GrProgressBar from '../GrProgressBar/GrProgressBar.vue'\nimport type { GrProgressBarTone } from '../GrProgressBar/grStyle'\nimport type { FileValidator, FileValidatorSource } from '../../fileValidation'\nimport type { GrUploadProgressInfo } from './uploadViaXhr'\nimport type { GrUploadState } from './uploadState'\n\nimport { FileValidationError, runFileValidators } from '../../fileValidation'\nimport { GrUploadAbortError, uploadViaXhr } from './uploadViaXhr'\nimport { GR_UPLOAD_STATE_IDLE } from './uploadState'\n\nexport type GrFileUploadExtraDataValue = string | Blob\n\nexport type GrFileUploadExtraData = Record<string, GrFileUploadExtraDataValue | GrFileUploadExtraDataValue[]>\n\nexport type GrFileUploadRequestCtx = {\n signal: AbortSignal\n extraData?: GrFileUploadExtraData\n /**\n * Колбэк прогресса аплоада. Пользовательский `request` (например, axios)\n * должен вызывать его из `onUploadProgress`, чтобы `GrFileUpload` отображал\n * прогресс через слот `progress` / дефолтный `GrProgressBar`.\n */\n onProgress?: (info: GrUploadProgressInfo) => void\n}\n\nexport type GrFileUploadRequest = (files: File[], ctx: GrFileUploadRequestCtx) => Promise<any>\n\n/**\n * Пропы `GrFileUpload`.\n *\n * Либо `action` (URL для POST multipart/form-data), либо `request` — кастомный\n * загрузчик (например, через axios). Если переданы оба — приоритет у `request`.\n *\n * `placeholder` — надпись в дефолтном UI-варианте (без слота default).\n */\nexport interface GrFileUploadProps {\n action?: string\n request?: GrFileUploadRequest\n name?: string\n multiple?: boolean\n limit?: number\n onExceed?: (files: File[], limit: number) => void\n beforeUpload?: (file: File) => boolean | Promise<unknown>\n validators?: FileValidator[]\n disabled?: boolean\n headers?: Record<string, string>\n withCredentials?: boolean\n showFileList?: boolean\n uploadExtraData?: (files: File[]) => GrFileUploadExtraData | undefined\n /** i18n: надпись-подсказка в дефолтном UI. */\n placeholder?: string\n /** Показывать дефолтный прогресс-бар (если не используется слот `progress`). */\n showProgress?: boolean\n /** Цветовой тон полосы прогресса в фазе `uploading`. */\n progressTone?: GrProgressBarTone\n /** aria-label для прогресс-бара. */\n progressLabel?: string\n /** Через сколько мс после `success` скрыть прогресс-бар. `0` — не скрывать. */\n hideProgressOnSuccess?: number\n}\n\nconst props = withDefaults(\n defineProps<GrFileUploadProps>(),\n {\n action: undefined,\n request: undefined,\n name: 'file',\n multiple: false,\n limit: undefined,\n onExceed: undefined,\n beforeUpload: undefined,\n validators: undefined,\n disabled: false,\n headers: undefined,\n withCredentials: false,\n showFileList: false,\n uploadExtraData: undefined,\n placeholder: 'Drag files here or click to select',\n showProgress: true,\n progressTone: 'primary',\n progressLabel: 'Upload progress',\n hideProgressOnSuccess: 800,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'success', payload: any): void\n (e: 'error', error: unknown): void\n (e: 'progress', percent: number, info?: GrUploadProgressInfo): void\n (e: 'change', files: File[]): void\n (e: 'stateChange', state: GrUploadState): void\n}>()\n\nconst slots = useSlots()\n\nfunction flattenSlotNodes(nodes: VNode[]): VNode[] {\n const out: VNode[] = []\n\n for (const node of nodes) {\n if (node.type === Fragment && Array.isArray(node.children)) {\n out.push(...flattenSlotNodes(node.children as VNode[]))\n continue\n }\n\n out.push(node)\n }\n\n return out\n}\n\nfunction isWhitespaceTextNode(node: VNode): boolean {\n if (node.type !== Text) return false\n return typeof node.children === 'string' && node.children.trim().length === 0\n}\n\nfunction slotIsTextOnly(nodes: VNode[]): boolean {\n const flat = flattenSlotNodes(nodes)\n const meaningful = flat.filter(node => node.type !== Comment && !isWhitespaceTextNode(node))\n\n if (meaningful.length === 0) return true\n\n for (const node of meaningful) {\n if (node.type !== Text) return false\n }\n\n return true\n}\n\nconst defaultSlotNodes = computed(() => {\n return slots.default ? flattenSlotNodes(slots.default({} as any)) : []\n})\n\nconst hasCustomUi = computed(() => {\n return !!slots.default && !slotIsTextOnly(defaultSlotNodes.value)\n})\n\nconst inputRef = ref<HTMLInputElement | null>(null)\nconst isOver = ref(false)\nlet overCounter = 0\n\nconst lastFiles = ref<File[]>([])\n\nconst state = reactive<GrUploadState>({ ...GR_UPLOAD_STATE_IDLE }) as GrUploadState\n\nlet activeController: AbortController | null = null\nlet hideSuccessTimer: ReturnType<typeof setTimeout> | null = null\n\nfunction clearHideSuccessTimer() {\n if (hideSuccessTimer !== null) {\n clearTimeout(hideSuccessTimer)\n hideSuccessTimer = null\n }\n}\n\nfunction assignState(next: GrUploadState) {\n // мутируем через Object.assign, чтобы сохранить reactive ссылку\n for (const key of Object.keys(state) as (keyof GrUploadState)[])\n delete (state as any)[key]\n Object.assign(state, next)\n emit('stateChange', state as GrUploadState)\n}\n\nfunction setStateIdle() {\n assignState({ ...GR_UPLOAD_STATE_IDLE })\n}\n\nfunction setStateUploading(info?: GrUploadProgressInfo) {\n assignState({\n phase: 'uploading',\n percent: info?.percent ?? 0,\n indeterminate: info?.indeterminate ?? true,\n loaded: info?.loaded ?? 0,\n total: info?.total ?? 0,\n })\n}\n\nfunction setStateSuccess(info: { loaded: number, total: number }) {\n assignState({\n phase: 'success',\n percent: 100,\n indeterminate: false,\n loaded: info.loaded,\n total: info.total,\n })\n}\n\nfunction setStateError(error: unknown) {\n const prev = state\n assignState({\n phase: 'error',\n percent: prev.phase === 'uploading' ? prev.percent : 0,\n indeterminate: false,\n loaded: prev.phase === 'uploading' ? prev.loaded : 0,\n total: prev.phase === 'uploading' ? prev.total : 0,\n error,\n })\n}\n\nfunction handleProgress(info: GrUploadProgressInfo) {\n if (state.phase !== 'uploading') return\n assignState({\n phase: 'uploading',\n percent: info.percent,\n indeterminate: info.indeterminate,\n loaded: info.loaded,\n total: info.total,\n })\n emit('progress', info.percent, info)\n}\n\nconst tabIndex = computed(() => (props.disabled ? -1 : 0))\n\nconst hiddenInputStyle = {\n position: 'fixed',\n top: '-9999px',\n left: '-9999px',\n width: '1px',\n height: '1px',\n opacity: '0',\n overflow: 'hidden',\n pointerEvents: 'none',\n} as const satisfies Record<string, string>\n\nfunction setOver(next: boolean) {\n if (isOver.value === next) return\n isOver.value = next\n}\n\nfunction openDialog() {\n if (props.disabled) return\n inputRef.value?.click()\n}\n\nfunction abort() {\n activeController?.abort()\n activeController = null\n}\n\nfunction normalizeLimit(limit: number | undefined): number | undefined {\n if (typeof limit !== 'number') return undefined\n if (!Number.isFinite(limit)) return undefined\n if (limit <= 0) return undefined\n return Math.floor(limit)\n}\n\n\nasync function uploadViaAction(files: File[], signal: AbortSignal, extraData: GrFileUploadExtraData | undefined) {\n if (!props.action) throw new Error('GrFileUpload: either `action` or `request` must be provided')\n\n return uploadViaXhr({\n url: props.action,\n files,\n name: props.name,\n headers: props.headers,\n withCredentials: props.withCredentials,\n extraData,\n signal,\n onProgress: handleProgress,\n })\n}\n\nasync function runBeforeUpload(files: File[]): Promise<'ok' | { aborted: true; reason: unknown }> {\n if (!props.beforeUpload) return 'ok'\n\n for (const file of files) {\n try {\n const result = props.beforeUpload(file)\n\n if (result === false) {\n return { aborted: true, reason: new Error('Upload aborted by beforeUpload') }\n }\n\n if (result && typeof (result as any).then === 'function')\n await result\n } catch (error) {\n return { aborted: true, reason: error }\n }\n }\n\n return 'ok'\n}\n\nasync function handleFiles(files: File[], source: FileValidatorSource = 'input') {\n if (props.disabled) return\n if (!files.length) return\n\n const normalizedLimit = normalizeLimit(props.limit)\n if (props.multiple && normalizedLimit && files.length > normalizedLimit) {\n props.onExceed?.(files, normalizedLimit)\n emit('error', new Error(`Too many files selected, limit=${normalizedLimit}`))\n return\n }\n\n const { files: valid, issues } = await runFileValidators(files, props.validators ?? [], {\n source,\n multiple: props.multiple,\n })\n\n if (issues.length > 0) {\n emit('error', new FileValidationError(issues, valid))\n return\n }\n\n if (!valid.length) return\n\n lastFiles.value = valid\n\n const before = await runBeforeUpload(valid)\n if (before !== 'ok') {\n emit('error', before.reason)\n return\n }\n\n let extraData: GrFileUploadExtraData | undefined\n try {\n extraData = props.uploadExtraData?.(valid)\n } catch (error) {\n emit('error', error)\n return\n }\n\n abort()\n clearHideSuccessTimer()\n\n const controller = new AbortController()\n activeController = controller\n\n setStateUploading()\n emit('progress', 0, { percent: 0, loaded: 0, total: 0, indeterminate: true })\n\n try {\n const payload = props.request\n ? await props.request(valid, { signal: controller.signal, extraData, onProgress: handleProgress })\n : await uploadViaAction(valid, controller.signal, extraData)\n\n const finalLoaded = state.phase === 'uploading' ? state.total || state.loaded : 0\n setStateSuccess({ loaded: finalLoaded, total: finalLoaded })\n emit('success', payload)\n emit('change', valid)\n emit('progress', 100, { percent: 100, loaded: finalLoaded, total: finalLoaded, indeterminate: false })\n\n if (props.hideProgressOnSuccess && props.hideProgressOnSuccess > 0) {\n hideSuccessTimer = setTimeout(() => {\n if (state.phase === 'success') setStateIdle()\n hideSuccessTimer = null\n }, props.hideProgressOnSuccess)\n }\n } catch (error) {\n if (error instanceof GrUploadAbortError) {\n setStateIdle()\n } else {\n setStateError(error)\n }\n emit('error', error)\n } finally {\n if (activeController === controller) activeController = null\n }\n}\n\nfunction onDragEnter(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter += 1\n setOver(true)\n}\n\nfunction onDragOver(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy'\n}\n\nfunction onDragLeave(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = Math.max(0, overCounter - 1)\n if (overCounter === 0) setOver(false)\n}\n\nfunction onDrop(event: DragEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n event.preventDefault()\n overCounter = 0\n setOver(false)\n\n const files = event.dataTransfer?.files ? Array.prototype.slice.call(event.dataTransfer.files) as File[] : []\n void handleFiles(files, 'drop')\n}\n\nasync function onInputChange(event: Event) {\n if (props.disabled) return\n\n const target = event.target as HTMLInputElement | null\n const files = target?.files ? Array.prototype.slice.call(target.files) as File[] : []\n\n if (target) target.value = ''\n\n await nextTick()\n await handleFiles(files, 'input')\n}\n\nfunction onKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n if (props.disabled) return\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n openDialog()\n }\n}\n\nfunction onRootClick() {\n if (hasCustomUi.value) return\n openDialog()\n}\n\nfunction onRootKeydown(event: KeyboardEvent) {\n if (hasCustomUi.value) return\n onKeydown(event)\n}\n\nconst effectiveProgressTone = computed<GrProgressBarTone>(() => {\n if (state.phase === 'error') return 'danger'\n if (state.phase === 'success') return 'success'\n return props.progressTone\n})\n\nconst progressVisible = computed(() => state.phase !== 'idle')\nconst progressPercent = computed(() => (state.phase === 'uploading' && state.indeterminate ? 0 : state.percent))\nconst progressText = computed(() => {\n if (state.phase === 'uploading' && state.indeterminate) return ''\n return `${Math.round(progressPercent.value)}%`\n})\n\ndefineExpose({\n uploadFiles: handleFiles,\n abort,\n openDialog,\n state,\n})\n</script>\n\n<template>\n <div\n data-ds-file-upload\n :role=\"hasCustomUi ? undefined : 'button'\"\n :tabindex=\"hasCustomUi ? undefined : tabIndex\"\n :aria-disabled=\"hasCustomUi ? undefined : disabled ? 'true' : 'false'\"\n :class=\"\n hasCustomUi\n ? 'inline-block'\n : [\n 'relative w-full rounded-[var(--ds-radius-lg)] border border-dashed border-[var(--brd)] bg-[var(--card)] px-5 py-6 outline-none transition',\n disabled\n ? 'opacity-60 cursor-not-allowed'\n : 'cursor-pointer hover:bg-[var(--muted)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--bg)]',\n isOver && !disabled ? 'border-[var(--ring)] bg-[var(--muted)]' : '',\n ]\n \"\n @click=\"onRootClick\"\n @keydown=\"onRootKeydown\"\n @dragenter=\"onDragEnter\"\n @dragover=\"onDragOver\"\n @dragleave=\"onDragLeave\"\n @drop=\"onDrop\"\n >\n <input\n ref=\"inputRef\"\n data-ds-file-upload-input\n :style=\"hiddenInputStyle\"\n type=\"file\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :name=\"name\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n @change=\"onInputChange\"\n >\n\n <slot\n v-if=\"hasCustomUi\"\n :open-dialog=\"openDialog\"\n :abort=\"abort\"\n :disabled=\"disabled\"\n :files=\"lastFiles\"\n :is-over=\"isOver\"\n :state=\"state\"\n />\n\n <div v-else class=\"flex items-start gap-4\">\n <div\n data-ds-file-upload-icon\n class=\"h-12 w-12 shrink-0 rounded-[12px] bg-[var(--muted)] border border-[var(--brd)] flex items-center justify-center\"\n aria-hidden=\"true\"\n >\n <GrIcon class=\"h-6 w-6 text-[var(--muted-fg)]\">\n <IconArrowUp />\n </GrIcon>\n </div>\n\n <div class=\"min-w-0\">\n <div data-ds-file-upload-label class=\"text-[14px] font-700\">\n <slot name=\"label\">\n <slot>\n {{ placeholder }}\n </slot>\n </slot>\n </div>\n\n <div v-if=\"$slots.tip\" data-ds-file-upload-tip class=\"mt-1 text-[13px] text-[var(--muted-fg)]\">\n <slot name=\"tip\" />\n </div>\n <div v-else class=\"mt-1 text-[13px] text-[var(--muted-fg)]\" />\n\n <ul v-if=\"showFileList && lastFiles.length\" data-ds-file-upload-list class=\"mt-3 space-y-1\">\n <li\n v-for=\"file in lastFiles\"\n :key=\"file.name\"\n data-ds-file-upload-item\n class=\"text-[13px]\"\n >\n <span class=\"font-600\">{{ file.name }}</span>\n <span class=\"text-[var(--muted-fg)]\"> · {{ Math.ceil(file.size / 1024) }} KB</span>\n </li>\n </ul>\n\n <slot\n v-if=\"showProgress || $slots.progress\"\n name=\"progress\"\n :state=\"state\"\n :percent=\"state.percent\"\n :indeterminate=\"state.phase === 'uploading' && state.indeterminate\"\n :phase=\"state.phase\"\n :files=\"lastFiles\"\n :abort=\"abort\"\n >\n <div\n v-if=\"showProgress\"\n data-ds-file-upload-progress\n class=\"mt-3 transition-opacity duration-150\"\n :class=\"progressVisible ? 'opacity-100' : 'opacity-0 pointer-events-none'\"\n :aria-hidden=\"!progressVisible\"\n >\n <div class=\"flex items-center gap-2\">\n <GrProgressBar\n :value=\"progressPercent\"\n :tone=\"effectiveProgressTone\"\n :aria-label=\"progressLabel\"\n />\n <span\n data-ds-file-upload-progress-text\n class=\"text-[12px] text-[var(--muted-fg)] tabular-nums min-w-[3ch] text-right\"\n >{{ progressText }}</span>\n </div>\n </div>\n </slot>\n </div>\n </div>\n </div>\n</template>"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  import { a as allowedExtensionsValidator, c as normalizeFiles, i as allowedMimeTypesValidator, l as runFileValidators, n as maxSizeMbValidator, o as acceptValidator, r as maxFileSizeBytesValidator, s as matchAccept, t as maxTotalSizeBytesValidator, u as FileValidationError } from "../../chunks/fileValidation-c_iBg74s.js";
2
- import { i as GrUploadHttpError, n as GR_UPLOAD_STATE_IDLE, r as GrUploadAbortError, t as GrFileUpload_default } from "./chunks/GrFileUpload-BEKNB1RM.js";
3
- import { t as grFileUploadConfig } from "../../chunks/config-DF_RlCIO.js";
2
+ import { i as GrUploadHttpError, n as GR_UPLOAD_STATE_IDLE, r as GrUploadAbortError, t as GrFileUpload_default } from "./chunks/GrFileUpload-CBKK3dgC.js";
3
+ import { t as grFileUploadConfig } from "../../chunks/config-CPSdAjUi.js";
4
4
  export { FileValidationError, GR_UPLOAD_STATE_IDLE, GrFileUpload_default as GrFileUpload, GrFileUpload_default as default, GrUploadAbortError, GrUploadHttpError, acceptValidator, allowedExtensionsValidator, allowedMimeTypesValidator, grFileUploadConfig, matchAccept, maxFileSizeBytesValidator, maxSizeMbValidator, maxTotalSizeBytesValidator, normalizeFiles, runFileValidators };
@@ -1,3 +1,3 @@
1
1
  import { t as GrFormField_default } from "./chunks/GrFormField-U7c_aDPJ.js";
2
- import { t as grFormFieldConfig } from "../../chunks/config-Dcb7xK-C.js";
2
+ import { t as grFormFieldConfig } from "../../chunks/config-B3dn-gdC.js";
3
3
  export { GrFormField_default as GrFormField, GrFormField_default as default, grFormFieldConfig };