@feugene/granularity 0.8.0 → 0.9.1

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 (268) hide show
  1. package/dist/chunks/{adapter-CRyH4YC8.js.map → adapter-BqqjEZGU.js.map} +1 -1
  2. package/dist/chunks/arrow-up-DZdIrpaF.js.map +1 -0
  3. package/dist/chunks/config-72sW9Bag2.js.map +1 -0
  4. package/dist/chunks/{config-B8rC_K97.js.map → config-B1kFmhpM.js.map} +1 -1
  5. package/dist/chunks/{config-BhvNm4Pp.js.map → config-B2YTEe_h.js.map} +1 -1
  6. package/dist/chunks/{config-C0rHS1-l.js.map → config-BOdu-O_B.js.map} +1 -1
  7. package/dist/chunks/{config-D27BL0H9.js.map → config-BU0olrvr.js.map} +1 -1
  8. package/dist/chunks/{config-XoANT5mU.js → config-BY81UKv0.js} +1 -1
  9. package/dist/chunks/{config-XoANT5mU.js.map → config-BY81UKv0.js.map} +1 -1
  10. package/dist/chunks/config-B_nSBc7W.js.map +1 -0
  11. package/dist/chunks/{config-DbqFk-IW.js.map → config-BbKroFtR.js.map} +1 -1
  12. package/dist/chunks/config-Bcf-8XlK2.js.map +1 -0
  13. package/dist/chunks/config-BduXEXjt.js.map +1 -0
  14. package/dist/chunks/config-BeQuykDk2.js.map +1 -0
  15. package/dist/chunks/{config-Dusr9jcE.js.map → config-BnWSHTEU.js.map} +1 -1
  16. package/dist/chunks/{config-C4AlNm912.js → config-Br_qI3Za.js} +1 -1
  17. package/dist/chunks/config-Br_qI3Za.js.map +1 -0
  18. package/dist/chunks/{config-C5TN9J2Z.js → config-C5OwJM3-.js} +1 -1
  19. package/dist/chunks/{config-C5TN9J2Z.js.map → config-C5OwJM3-.js.map} +1 -1
  20. package/dist/chunks/config-C6zT56Jc2.js.map +1 -0
  21. package/dist/chunks/{config-ZJVOVgqR.js → config-CFf7xaG1.js} +1 -1
  22. package/dist/chunks/{config-ZJVOVgqR.js.map → config-CFf7xaG1.js.map} +1 -1
  23. package/dist/chunks/{config-wo-ncgTH.js.map → config-CdJpnjDj.js.map} +1 -1
  24. package/dist/chunks/config-CetsgpaZ2.js.map +1 -0
  25. package/dist/chunks/{config-D1DI3roo.js.map → config-Ci9nXGUV.js.map} +1 -1
  26. package/dist/chunks/{config-CjEplP6D.js.map → config-CpMYmvVT.js.map} +1 -1
  27. package/dist/chunks/{config-DZAQpfz0.js.map → config-Cp_XHsze.js.map} +1 -1
  28. package/dist/chunks/{config-D98m8iyz.js.map → config-CvGdaXvH.js.map} +1 -1
  29. package/dist/chunks/{config-CtomKf-k.js.map → config-D4s_QWVP.js.map} +1 -1
  30. package/dist/chunks/{config-D32znLtV2.js.map → config-D6Oe3blW2.js.map} +1 -1
  31. package/dist/chunks/{config-CVnluhKO.js.map → config-DF_RlCIO.js.map} +1 -1
  32. package/dist/chunks/{config-C4qAA0Sb.js.map → config-DSBlHQVa.js.map} +1 -1
  33. package/dist/chunks/{config-Mp9DJ9Mq2.js.map → config-DaHI5bD_2.js.map} +1 -1
  34. package/dist/chunks/{config-3SftO0uG.js.map → config-Dcb7xK-C.js.map} +1 -1
  35. package/dist/chunks/config-DmjwIqx1.js.map +1 -0
  36. package/dist/chunks/{config-D6Af6WZw.js.map → config-DoBk_CzG.js.map} +1 -1
  37. package/dist/chunks/config-Dzd6BzIN2.js.map +1 -0
  38. package/dist/chunks/{config-Db4BEG8Y.js.map → config-O1_FTqD3.js.map} +1 -1
  39. package/dist/chunks/config-_3De4HFf.js.map +1 -0
  40. package/dist/chunks/{config-B44QVIge.js → config-d386uO3O.js} +1 -1
  41. package/dist/chunks/{config-B44QVIge.js.map → config-d386uO3O.js.map} +1 -1
  42. package/dist/chunks/{config-DudL02ag.js.map → config-iuMz79Mg.js.map} +1 -1
  43. package/dist/chunks/config-vcDVCYXo.js.map +1 -0
  44. package/dist/chunks/{en-QNZhjmSJ.js.map → en-foQA8imU.js.map} +1 -1
  45. package/dist/chunks/{es-CKLPuE0h.js → es-Bx3Kuy6z.js} +3 -3
  46. package/dist/chunks/{es-CKLPuE0h.js.map → es-Bx3Kuy6z.js.map} +1 -1
  47. package/dist/chunks/{es-C1c5XsIK.js.map → es-DZFSojYL.js.map} +1 -1
  48. package/dist/chunks/{fileValidation-CwJA8Vmn.js.map → fileValidation-c_iBg74s.js.map} +1 -1
  49. package/dist/chunks/{grDropdownStyles-DMp7RrI9.js.map → grDropdownStyles-B41mVR1H.js.map} +1 -1
  50. package/dist/chunks/{grLoadingStyles-CrxZHFL0.js.map → grLoadingStyles-DmI-SJ3i.js.map} +1 -1
  51. package/dist/chunks/{grModalStyles-Dv2NXBKi.js.map → grModalStyles-DS1Vl6EW.js.map} +1 -1
  52. package/dist/chunks/{grSelectStyles-DTAYNzxn.js.map → grSelectStyles-pUt19VGy.js.map} +1 -1
  53. package/dist/chunks/{grStyle-5EMYYctb.js.map → grStyle-CUaTmpyW.js.map} +1 -1
  54. package/dist/chunks/{granularityI18n-CXa_uN7f.js → granularityI18n-LcJ88Vce.js} +1 -1
  55. package/dist/chunks/{granularityI18n-CXa_uN7f.js.map → granularityI18n-LcJ88Vce.js.map} +1 -1
  56. package/dist/chunks/{ru-DcF7ciz0.js.map → ru-LhkPpPIl.js.map} +1 -1
  57. package/dist/chunks/safelist-_UVzJrgE2.js.map +1 -0
  58. package/dist/chunks/{shared-D7q-upeJ.js → shared-BiqXd5MW.js} +37 -37
  59. package/dist/chunks/{shared-D7q-upeJ.js.map → shared-BiqXd5MW.js.map} +1 -1
  60. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-DE-d77Us.js → GrConfirmDialog-DuUQA7nv.js} +31 -8
  61. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DuUQA7nv.js.map +1 -0
  62. package/dist/components/GrConfirmDialog/index.js +2 -2
  63. package/dist/components/GrDataTable/chunks/{GrDataTable-QDOJWmdY.js → GrDataTable-ClcYiyc8.js} +2 -2
  64. package/dist/components/GrDataTable/chunks/{GrDataTable-QDOJWmdY.js.map → GrDataTable-ClcYiyc8.js.map} +1 -1
  65. package/dist/components/GrDataTable/index.js +2 -2
  66. package/dist/components/GrDialog/chunks/{GrDialog-Ba3Ojcsq.js → GrDialog-SYcF-4op.js} +1 -1
  67. package/dist/components/GrDialog/chunks/{GrDialog-Ba3Ojcsq.js.map → GrDialog-SYcF-4op.js.map} +1 -1
  68. package/dist/components/GrDialog/index.js +2 -2
  69. package/dist/components/GrDrawer/chunks/{GrDrawer-h33X403E.js → GrDrawer-BW3wtI7h.js} +1 -1
  70. package/dist/components/GrDrawer/chunks/{GrDrawer-h33X403E.js.map → GrDrawer-BW3wtI7h.js.map} +1 -1
  71. package/dist/components/GrDrawer/index.js +2 -2
  72. package/dist/components/GrDropdown/chunks/{GrDropdown-BkACCXdp.js → GrDropdown-DOvHKnih.js} +1 -1
  73. package/dist/components/GrDropdown/chunks/{GrDropdown-BkACCXdp.js.map → GrDropdown-DOvHKnih.js.map} +1 -1
  74. package/dist/components/GrDropdown/index.js +2 -2
  75. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BEenXrJw.js → GrDropdownMenu-CLPwbiyG.js} +1 -1
  76. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BEenXrJw.js.map → GrDropdownMenu-CLPwbiyG.js.map} +1 -1
  77. package/dist/components/GrDropdownMenu/index.js +2 -2
  78. package/dist/components/GrEmptyState/chunks/{GrEmptyState-BLbMJFW-.js.map → GrEmptyState-Dj2V5GaX.js.map} +1 -1
  79. package/dist/components/GrEmptyState/index.js +2 -2
  80. package/dist/components/GrFileUpload/chunks/{GrFileUpload-DYRERhI2.js → GrFileUpload-BEKNB1RM.js} +5 -5
  81. package/dist/components/GrFileUpload/chunks/GrFileUpload-BEKNB1RM.js.map +1 -0
  82. package/dist/components/GrFileUpload/index.js +3 -3
  83. package/dist/components/GrFormField/chunks/{GrFormField-C1oWTT_0.js.map → GrFormField-U7c_aDPJ.js.map} +1 -1
  84. package/dist/components/GrFormField/index.js +2 -2
  85. package/dist/components/GrFormFile/chunks/{GrFormFile-WqF-dPTB.js → GrFormFile-CIleXnfr.js} +1 -1
  86. package/dist/components/GrFormFile/chunks/{GrFormFile-WqF-dPTB.js.map → GrFormFile-CIleXnfr.js.map} +1 -1
  87. package/dist/components/GrFormFile/index.js +2 -2
  88. package/dist/components/GrFormSection/chunks/{GrFormSection-CWBk2EUm.js.map → GrFormSection-DpGhY7MX.js.map} +1 -1
  89. package/dist/components/GrFormSection/index.js +2 -2
  90. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Cpj5zyZQ.js.map → GrImageViewer-Cn1X-sWS.js.map} +1 -1
  91. package/dist/components/GrImageViewer/index.js +2 -2
  92. package/dist/components/GrInput/chunks/{GrInput-CfO2RsM-.js.map → GrInput-gwFQ1sk4.js.map} +1 -1
  93. package/dist/components/GrInput/index.js +2 -2
  94. package/dist/components/GrInputTag/chunks/{GrInputTag-CeEy0IwD.js → GrInputTag-Dcj3F6rQ.js} +1 -1
  95. package/dist/components/GrInputTag/chunks/{GrInputTag-CeEy0IwD.js.map → GrInputTag-Dcj3F6rQ.js.map} +1 -1
  96. package/dist/components/GrInputTag/index.js +2 -2
  97. package/dist/components/GrLink/chunks/{GrLink-BLPigqij.js → GrLink-BMwn2iJ9.js} +1 -1
  98. package/dist/components/GrLink/chunks/{GrLink-BLPigqij.js.map → GrLink-BMwn2iJ9.js.map} +1 -1
  99. package/dist/components/GrLink/index.js +2 -2
  100. package/dist/components/GrList/chunks/{GrList-C2GpK56-.js.map → GrList-D8nM1FuV.js.map} +1 -1
  101. package/dist/components/GrList/index.js +2 -2
  102. package/dist/components/GrLoading/chunks/{GrLoading-CxNgHgNw.js → GrLoading-mfyfghxs.js} +1 -1
  103. package/dist/components/GrLoading/chunks/{GrLoading-CxNgHgNw.js.map → GrLoading-mfyfghxs.js.map} +1 -1
  104. package/dist/components/GrLoading/index.js +2 -2
  105. package/dist/components/GrModal/chunks/{GrModal-gvfvlp7k.js → GrModal-2ALC3kwy.js} +73 -7
  106. package/dist/components/GrModal/chunks/GrModal-2ALC3kwy.js.map +1 -0
  107. package/dist/components/GrModal/index.js +3 -3
  108. package/dist/components/GrNavbar/chunks/{GrNavbar-CxHwBvSG.js → GrNavbar-BH7XiF9q.js} +1 -1
  109. package/dist/components/GrNavbar/chunks/{GrNavbar-CxHwBvSG.js.map → GrNavbar-BH7XiF9q.js.map} +1 -1
  110. package/dist/components/GrNavbar/index.js +2 -2
  111. package/dist/components/GrNumberInput/chunks/{GrNumberInput-ECtFCIKV.js → GrNumberInput-YIWhV85S.js} +1 -1
  112. package/dist/components/GrNumberInput/chunks/{GrNumberInput-ECtFCIKV.js.map → GrNumberInput-YIWhV85S.js.map} +1 -1
  113. package/dist/components/GrNumberInput/index.js +2 -2
  114. package/dist/components/GrPagination/chunks/{GrPagination-dMXZz120.js → GrPagination-cD6rFO9W.js} +2 -2
  115. package/dist/components/GrPagination/chunks/{GrPagination-dMXZz120.js.map → GrPagination-cD6rFO9W.js.map} +1 -1
  116. package/dist/components/GrPagination/index.js +2 -2
  117. package/dist/components/GrProgressBar/chunks/{GrProgressBar-hQQK8cYh.js → GrProgressBar-C2HdYjp4.js} +1 -1
  118. package/dist/components/GrProgressBar/chunks/{GrProgressBar-hQQK8cYh.js.map → GrProgressBar-C2HdYjp4.js.map} +1 -1
  119. package/dist/components/GrProgressBar/index.js +2 -2
  120. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-CfKf4tPx.js → GrPromptDialog-23x2nZvv.js} +54 -28
  121. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-23x2nZvv.js.map +1 -0
  122. package/dist/components/GrPromptDialog/index.js +2 -2
  123. package/dist/components/GrRadio/chunks/{GrRadio-CQ3w3Bj6.js → GrRadio-IFU9Hiu2.js} +1 -1
  124. package/dist/components/GrRadio/chunks/{GrRadio-CQ3w3Bj6.js.map → GrRadio-IFU9Hiu2.js.map} +1 -1
  125. package/dist/components/GrRadio/index.js +2 -2
  126. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-DAaVzlPx.js → GrRadioGroup-C8IcJuuF.js} +1 -1
  127. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-DAaVzlPx.js.map → GrRadioGroup-C8IcJuuF.js.map} +1 -1
  128. package/dist/components/GrRadioGroup/index.js +2 -2
  129. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-BMvXREcv.js +221 -0
  130. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-BMvXREcv.js.map +1 -0
  131. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-CzdTh4gd.js +782 -0
  132. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-CzdTh4gd.js.map +1 -0
  133. package/dist/components/GrResponseErrorBanner/index.js +3 -0
  134. package/dist/components/GrSegmented/chunks/{GrSegmented-BPl1koHc.js → GrSegmented-BRmwBsEG.js} +1 -1
  135. package/dist/components/GrSegmented/chunks/{GrSegmented-BPl1koHc.js.map → GrSegmented-BRmwBsEG.js.map} +1 -1
  136. package/dist/components/GrSegmented/index.js +2 -2
  137. package/dist/components/GrSelect/chunks/{GrSelect-C3NAfTqL.js → GrSelect-W9lbAjRZ.js} +2 -2
  138. package/dist/components/GrSelect/chunks/{GrSelect-C3NAfTqL.js.map → GrSelect-W9lbAjRZ.js.map} +1 -1
  139. package/dist/components/GrSelect/index.js +2 -2
  140. package/dist/components/GrSidebar/chunks/{GrSidebar-DVucgcfV.js.map → GrSidebar-BpBtAGBs.js.map} +1 -1
  141. package/dist/components/GrSidebar/index.js +2 -2
  142. package/dist/components/GrSkeleton/chunks/{GrSkeleton-CDTvCSoH.js.map → GrSkeleton-URyMkBqI.js.map} +1 -1
  143. package/dist/components/GrSkeleton/index.js +2 -2
  144. package/dist/components/GrSwitch/chunks/{GrSwitch-Bnamgqb2.js → GrSwitch-29h0QhMO.js} +1 -1
  145. package/dist/components/GrSwitch/chunks/{GrSwitch-Bnamgqb2.js.map → GrSwitch-29h0QhMO.js.map} +1 -1
  146. package/dist/components/GrSwitch/index.js +2 -2
  147. package/dist/components/GrTable/chunks/{GrTable-CyQ9uw8A.js.map → GrTable-dTWUxzRm.js.map} +1 -1
  148. package/dist/components/GrTable/index.js +2 -2
  149. package/dist/components/GrTabs/chunks/{GrTabs-CiGmcmvm.js.map → GrTabs-D3ntDdtg.js.map} +1 -1
  150. package/dist/components/GrTabs/index.js +2 -2
  151. package/dist/components/GrTextarea/chunks/{GrTextarea-VBSc6A7D.js → GrTextarea-Cv6r2GuC.js} +1 -1
  152. package/dist/components/GrTextarea/chunks/{GrTextarea-VBSc6A7D.js.map → GrTextarea-Cv6r2GuC.js.map} +1 -1
  153. package/dist/components/GrTextarea/index.js +2 -2
  154. package/dist/components/GrToaster/chunks/{GrToaster-BGNNmnr9.js → GrToaster-DluJmR5D.js} +1 -1
  155. package/dist/components/GrToaster/chunks/{GrToaster-BGNNmnr9.js.map → GrToaster-DluJmR5D.js.map} +1 -1
  156. package/dist/components/GrToaster/index.js +2 -2
  157. package/dist/components/GrTooltip/chunks/{GrTooltip-CrV1gI_c.js.map → GrTooltip-B7I1AVIC.js.map} +1 -1
  158. package/dist/components/GrTooltip/index.js +2 -2
  159. package/dist/components/GrTree/chunks/{GrTree-mYa3COxG.js.map → GrTree-B2SMU5Py.js.map} +1 -1
  160. package/dist/components/GrTree/index.js +2 -2
  161. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-BEdtrjwX.js → GrTreeSelect-C1abr5uH.js} +4 -4
  162. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-BEdtrjwX.js.map → GrTreeSelect-C1abr5uH.js.map} +1 -1
  163. package/dist/components/GrTreeSelect/index.js +2 -2
  164. package/dist/directives/dropzone.js +1 -1
  165. package/dist/directives/loading.js +1 -1
  166. package/dist/fileValidation/index.js +1 -1
  167. package/dist/granular-provider-node.js +2 -2
  168. package/dist/granular-provider.js +1 -1
  169. package/dist/i18n/all.js +1 -1
  170. package/dist/i18n/index.js +2 -2
  171. package/dist/index.js +474 -1015
  172. package/dist/index.js.map +1 -1
  173. package/dist/types/src/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +36 -3
  174. package/dist/types/src/components/GrDialogService/GrDialogServiceHost.vue.d.ts +3 -0
  175. package/dist/types/src/components/GrDialogService/config.d.ts +1 -0
  176. package/dist/types/src/components/GrDialogService/index.d.ts +4 -0
  177. package/dist/types/src/components/GrDialogService/store.d.ts +22 -0
  178. package/dist/types/src/components/GrDialogService/types.d.ts +141 -0
  179. package/dist/types/src/components/GrDialogService/useDialogService.d.ts +13 -0
  180. package/dist/types/src/components/GrFileUpload/GrFileUpload.vue.d.ts +3 -3
  181. package/dist/types/src/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
  182. package/dist/types/src/components/GrInput/GrInput.vue.d.ts +2 -2
  183. package/dist/types/src/components/GrInputTag/GrInputTag.vue.d.ts +1 -1
  184. package/dist/types/src/components/GrModal/grModalEscStack.d.ts +30 -0
  185. package/dist/types/src/components/GrNumberInput/GrNumberInput.vue.d.ts +4 -4
  186. package/dist/types/src/components/GrPromptDialog/GrPromptDialog.vue.d.ts +42 -3
  187. package/dist/types/src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue.d.ts +1 -1
  188. package/dist/types/src/components/GrResponseErrorBanner/index.d.ts +2 -2
  189. package/dist/types/src/components/GrResponseErrorBanner/parsers/createResponseErrorClassifier.d.ts +27 -0
  190. package/dist/types/src/components/GrResponseErrorBanner/parsers/index.d.ts +2 -2
  191. package/dist/types/src/components/GrSelect/GrSelect.vue.d.ts +1 -1
  192. package/dist/types/src/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
  193. package/dist/types/src/components/GrToaster/GrToaster.vue.d.ts +1 -1
  194. package/dist/types/src/index.d.ts +1 -0
  195. package/package.json +5 -1
  196. package/dist/chunks/arrow-up-DNXrMoAI.js.map +0 -1
  197. package/dist/chunks/config-C0b_3LJV.js.map +0 -1
  198. package/dist/chunks/config-C4AlNm912.js.map +0 -1
  199. package/dist/chunks/config-CxCAfXZ1.js.map +0 -1
  200. package/dist/chunks/config-DDEWvph-2.js.map +0 -1
  201. package/dist/chunks/config-DDLoUczC.js.map +0 -1
  202. package/dist/chunks/config-DK2NpdyX2.js.map +0 -1
  203. package/dist/chunks/config-DQOSlWvp.js.map +0 -1
  204. package/dist/chunks/config-DnsISjD8.js.map +0 -1
  205. package/dist/chunks/config-DxqMXzNV2.js.map +0 -1
  206. package/dist/chunks/config-DxqpV-KM.js.map +0 -1
  207. package/dist/chunks/config-iDTkWUdh2.js.map +0 -1
  208. package/dist/chunks/config-rxFL-6yF2.js.map +0 -1
  209. package/dist/chunks/safelist-BF822K15.js.map +0 -1
  210. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DE-d77Us.js.map +0 -1
  211. package/dist/components/GrFileUpload/chunks/GrFileUpload-DYRERhI2.js.map +0 -1
  212. package/dist/components/GrModal/chunks/GrModal-gvfvlp7k.js.map +0 -1
  213. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-CfKf4tPx.js.map +0 -1
  214. /package/dist/chunks/{adapter-CRyH4YC8.js → adapter-BqqjEZGU.js} +0 -0
  215. /package/dist/chunks/{arrow-up-DNXrMoAI.js → arrow-up-DZdIrpaF.js} +0 -0
  216. /package/dist/chunks/{config-C0b_3LJV.js → config-72sW9Bag2.js} +0 -0
  217. /package/dist/chunks/{config-B8rC_K97.js → config-B1kFmhpM.js} +0 -0
  218. /package/dist/chunks/{config-BhvNm4Pp.js → config-B2YTEe_h.js} +0 -0
  219. /package/dist/chunks/{config-C0rHS1-l.js → config-BOdu-O_B.js} +0 -0
  220. /package/dist/chunks/{config-D27BL0H9.js → config-BU0olrvr.js} +0 -0
  221. /package/dist/chunks/{config-DxqMXzNV2.js → config-B_nSBc7W.js} +0 -0
  222. /package/dist/chunks/{config-DbqFk-IW.js → config-BbKroFtR.js} +0 -0
  223. /package/dist/chunks/{config-DQOSlWvp.js → config-Bcf-8XlK2.js} +0 -0
  224. /package/dist/chunks/{config-iDTkWUdh2.js → config-BduXEXjt.js} +0 -0
  225. /package/dist/chunks/{config-DnsISjD8.js → config-BeQuykDk2.js} +0 -0
  226. /package/dist/chunks/{config-Dusr9jcE.js → config-BnWSHTEU.js} +0 -0
  227. /package/dist/chunks/{config-DxqpV-KM.js → config-C6zT56Jc2.js} +0 -0
  228. /package/dist/chunks/{config-wo-ncgTH.js → config-CdJpnjDj.js} +0 -0
  229. /package/dist/chunks/{config-CxCAfXZ1.js → config-CetsgpaZ2.js} +0 -0
  230. /package/dist/chunks/{config-D1DI3roo.js → config-Ci9nXGUV.js} +0 -0
  231. /package/dist/chunks/{config-CjEplP6D.js → config-CpMYmvVT.js} +0 -0
  232. /package/dist/chunks/{config-DZAQpfz0.js → config-Cp_XHsze.js} +0 -0
  233. /package/dist/chunks/{config-D98m8iyz.js → config-CvGdaXvH.js} +0 -0
  234. /package/dist/chunks/{config-CtomKf-k.js → config-D4s_QWVP.js} +0 -0
  235. /package/dist/chunks/{config-D32znLtV2.js → config-D6Oe3blW2.js} +0 -0
  236. /package/dist/chunks/{config-CVnluhKO.js → config-DF_RlCIO.js} +0 -0
  237. /package/dist/chunks/{config-C4qAA0Sb.js → config-DSBlHQVa.js} +0 -0
  238. /package/dist/chunks/{config-Mp9DJ9Mq2.js → config-DaHI5bD_2.js} +0 -0
  239. /package/dist/chunks/{config-3SftO0uG.js → config-Dcb7xK-C.js} +0 -0
  240. /package/dist/chunks/{config-DDEWvph-2.js → config-DmjwIqx1.js} +0 -0
  241. /package/dist/chunks/{config-D6Af6WZw.js → config-DoBk_CzG.js} +0 -0
  242. /package/dist/chunks/{config-DDLoUczC.js → config-Dzd6BzIN2.js} +0 -0
  243. /package/dist/chunks/{config-Db4BEG8Y.js → config-O1_FTqD3.js} +0 -0
  244. /package/dist/chunks/{config-rxFL-6yF2.js → config-_3De4HFf.js} +0 -0
  245. /package/dist/chunks/{config-DudL02ag.js → config-iuMz79Mg.js} +0 -0
  246. /package/dist/chunks/{config-DK2NpdyX2.js → config-vcDVCYXo.js} +0 -0
  247. /package/dist/chunks/{en-QNZhjmSJ.js → en-foQA8imU.js} +0 -0
  248. /package/dist/chunks/{es-C1c5XsIK.js → es-DZFSojYL.js} +0 -0
  249. /package/dist/chunks/{fileValidation-CwJA8Vmn.js → fileValidation-c_iBg74s.js} +0 -0
  250. /package/dist/chunks/{grDropdownStyles-DMp7RrI9.js → grDropdownStyles-B41mVR1H.js} +0 -0
  251. /package/dist/chunks/{grLoadingStyles-CrxZHFL0.js → grLoadingStyles-DmI-SJ3i.js} +0 -0
  252. /package/dist/chunks/{grModalStyles-Dv2NXBKi.js → grModalStyles-DS1Vl6EW.js} +0 -0
  253. /package/dist/chunks/{grSelectStyles-DTAYNzxn.js → grSelectStyles-pUt19VGy.js} +0 -0
  254. /package/dist/chunks/{grStyle-5EMYYctb.js → grStyle-CUaTmpyW.js} +0 -0
  255. /package/dist/chunks/{ru-DcF7ciz0.js → ru-LhkPpPIl.js} +0 -0
  256. /package/dist/chunks/{safelist-BF822K15.js → safelist-_UVzJrgE2.js} +0 -0
  257. /package/dist/components/GrEmptyState/chunks/{GrEmptyState-BLbMJFW-.js → GrEmptyState-Dj2V5GaX.js} +0 -0
  258. /package/dist/components/GrFormField/chunks/{GrFormField-C1oWTT_0.js → GrFormField-U7c_aDPJ.js} +0 -0
  259. /package/dist/components/GrFormSection/chunks/{GrFormSection-CWBk2EUm.js → GrFormSection-DpGhY7MX.js} +0 -0
  260. /package/dist/components/GrImageViewer/chunks/{GrImageViewer-Cpj5zyZQ.js → GrImageViewer-Cn1X-sWS.js} +0 -0
  261. /package/dist/components/GrInput/chunks/{GrInput-CfO2RsM-.js → GrInput-gwFQ1sk4.js} +0 -0
  262. /package/dist/components/GrList/chunks/{GrList-C2GpK56-.js → GrList-D8nM1FuV.js} +0 -0
  263. /package/dist/components/GrSidebar/chunks/{GrSidebar-DVucgcfV.js → GrSidebar-BpBtAGBs.js} +0 -0
  264. /package/dist/components/GrSkeleton/chunks/{GrSkeleton-CDTvCSoH.js → GrSkeleton-URyMkBqI.js} +0 -0
  265. /package/dist/components/GrTable/chunks/{GrTable-CyQ9uw8A.js → GrTable-dTWUxzRm.js} +0 -0
  266. /package/dist/components/GrTabs/chunks/{GrTabs-CiGmcmvm.js → GrTabs-D3ntDdtg.js} +0 -0
  267. /package/dist/components/GrTooltip/chunks/{GrTooltip-CrV1gI_c.js → GrTooltip-B7I1AVIC.js} +0 -0
  268. /package/dist/components/GrTree/chunks/{GrTree-mYa3COxG.js → GrTree-B2SMU5Py.js} +0 -0
@@ -90,8 +90,8 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
90
90
  readonly: boolean;
91
91
  size: GrInputTagSize;
92
92
  disabled: boolean;
93
- max: number;
94
93
  invalid: boolean;
94
+ max: number;
95
95
  placeholder: string;
96
96
  state: GrInputTagState;
97
97
  separators: string[];
@@ -0,0 +1,30 @@
1
+ /**
2
+ * grModalEscStack — общий стек открытых `GrModal` для корректной обработки Esc.
3
+ *
4
+ * Зачем нужен:
5
+ * HeadlessUI вешает обработчик Escape на `window` у каждого открытого `<Dialog>`.
6
+ * Когда модалки рендерятся в разных деревьях приложения (например, диалоги
7
+ * `useDialogService` монтируются отдельным `render()` в `document.body`), их
8
+ * HeadlessUI-стек не общий, и каждый `<Dialog>` считает себя верхним. В итоге
9
+ * Esc перехватывает обработчик той модалки, что смонтирована раньше (нижней),
10
+ * а реально верхнее окно (последнее открытое) остаётся.
11
+ *
12
+ * Решение: единый capture-обработчик на `window`, который срабатывает раньше
13
+ * обработчиков HeadlessUI, гасит событие (`stopImmediatePropagation`) и
14
+ * закрывает только верхнюю (последнюю зарегистрированную) модалку. Так Esc
15
+ * всегда адресуется верхнему окну независимо от дерева рендера.
16
+ */
17
+ export interface GrModalEscEntry {
18
+ /** Уникальный id зарегистрированной модалки. */
19
+ id: number;
20
+ /** Должна ли модалка закрываться по Esc (реактивный геттер `closeOnEsc`). */
21
+ shouldClose: () => boolean;
22
+ /** Закрыть модалку (эмит `update:modelValue=false`). */
23
+ close: () => void;
24
+ }
25
+ /** Регистрирует открытую модалку как верхнюю и возвращает её id. */
26
+ export declare function pushGrModalEsc(entry: Omit<GrModalEscEntry, 'id'>): number;
27
+ /** Снимает модалку со стека (при закрытии или размонтировании). */
28
+ export declare function removeGrModalEsc(id: number): void;
29
+ /** Тестовая/служебная очистка стека. */
30
+ export declare function resetGrModalEscStack(): void;
@@ -99,18 +99,18 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
99
99
  disabled: boolean;
100
100
  name: string;
101
101
  id: string;
102
- max: number;
103
102
  invalid: boolean;
104
- min: number;
105
- placeholder: string;
106
- state: GrNumberInputState;
103
+ max: number;
107
104
  inputmode: "text" | "search" | "none" | "email" | "tel" | "url" | "numeric" | "decimal";
105
+ placeholder: string;
108
106
  autocomplete: string;
107
+ state: GrNumberInputState;
109
108
  textAlign: GrNumberInputTextAlign;
110
109
  prefixMinWidth: string;
111
110
  prefixMaxWidth: string;
112
111
  suffixMinWidth: string;
113
112
  suffixMaxWidth: string;
113
+ min: number;
114
114
  decimalSeparator: string;
115
115
  step: number;
116
116
  precision: number;
@@ -1,5 +1,6 @@
1
1
  import type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton';
2
2
  import type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog';
3
+ import type { ResponseErrorInfo } from '../GrResponseErrorBanner';
3
4
  export interface GrPromptDialogProps {
4
5
  modelValue: boolean;
5
6
  value: string;
@@ -25,12 +26,35 @@ export interface GrPromptDialogProps {
25
26
  confirmVariant?: GrButtonVariant;
26
27
  confirmTone?: GrButtonTone;
27
28
  required?: boolean;
29
+ /**
30
+ * Структура ошибки ответа сервера для показа общим блоком в теле диалога
31
+ * (через `GrResponseErrorBanner`). `null` — блок скрыт.
32
+ */
33
+ error?: ResponseErrorInfo | null;
34
+ /**
35
+ * Внешняя ошибка поля ввода (например, серверная валидация). Имеет приоритет
36
+ * над встроенной проверкой `required`. `null`/`undefined` — нет внешней ошибки.
37
+ */
38
+ fieldError?: string | null;
39
+ /** Состояние загрузки кнопки Confirm (async-`onConfirm` in-flight). */
40
+ confirmLoading?: boolean;
41
+ /** Принудительно дизейблит кнопку Confirm. */
42
+ confirmDisabled?: boolean;
43
+ /**
44
+ * Закрывать ли диалог автоматически по клику Confirm. По умолчанию `true`.
45
+ * `false` — отдаёт управление закрытием наружу (нужно `useDialogService`).
46
+ */
47
+ closeOnConfirm?: boolean;
28
48
  }
29
- declare var __VLS_8: {}, __VLS_26: {};
49
+ declare var __VLS_8: {}, __VLS_25: {
50
+ error: ResponseErrorInfo | null;
51
+ }, __VLS_33: {};
30
52
  type __VLS_Slots = {} & {
31
53
  default?: (props: typeof __VLS_8) => any;
32
54
  } & {
33
- footer?: (props: typeof __VLS_26) => any;
55
+ error?: (props: typeof __VLS_25) => any;
56
+ } & {
57
+ footer?: (props: typeof __VLS_33) => any;
34
58
  };
35
59
  declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrPromptDialogProps>, {
36
60
  title: string;
@@ -53,6 +77,11 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
53
77
  confirmVariant: string;
54
78
  confirmTone: string;
55
79
  required: boolean;
80
+ error: null;
81
+ fieldError: null;
82
+ confirmLoading: boolean;
83
+ confirmDisabled: boolean;
84
+ closeOnConfirm: boolean;
56
85
  }>>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
57
86
  "update:modelValue": (value: boolean) => void;
58
87
  "update:value": (value: string) => void;
@@ -79,16 +108,22 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
79
108
  confirmVariant: string;
80
109
  confirmTone: string;
81
110
  required: boolean;
111
+ error: null;
112
+ fieldError: null;
113
+ confirmLoading: boolean;
114
+ confirmDisabled: boolean;
115
+ closeOnConfirm: boolean;
82
116
  }>>> & Readonly<{
83
117
  "onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
84
- onConfirm?: ((value: string) => any) | undefined;
85
118
  onCancel?: (() => any) | undefined;
119
+ onConfirm?: ((value: string) => any) | undefined;
86
120
  "onUpdate:value"?: ((value: string) => any) | undefined;
87
121
  }>, {
88
122
  title: string;
89
123
  label: string;
90
124
  size: GrDialogSize;
91
125
  required: boolean;
126
+ error: ResponseErrorInfo | null;
92
127
  closeOnBackdrop: boolean;
93
128
  closeOnEsc: boolean;
94
129
  description: string;
@@ -103,8 +138,12 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
103
138
  cancelText: string;
104
139
  confirmVariant: GrButtonVariant;
105
140
  confirmTone: GrButtonTone;
141
+ confirmLoading: boolean;
142
+ confirmDisabled: boolean;
143
+ closeOnConfirm: boolean;
106
144
  placeholder: string;
107
145
  requiredErrorText: string;
146
+ fieldError: string | null;
108
147
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
109
148
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
110
149
  declare const _default: typeof __VLS_export;
@@ -43,13 +43,13 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
43
43
  onDismiss?: (() => any) | undefined;
44
44
  }>, {
45
45
  tone: ResponseErrorTone;
46
- files: File[];
47
46
  texts: Partial<ResponseErrorTexts>;
48
47
  toneByKind: Partial<Record<ResponseErrorKind, ResponseErrorTone>>;
49
48
  canRetry: boolean;
50
49
  canDismiss: boolean;
51
50
  autoHideKinds: ResponseErrorKind[];
52
51
  testIdPrefix: string;
52
+ files: File[];
53
53
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
54
54
  declare const _default: typeof __VLS_export;
55
55
  export default _default;
@@ -5,6 +5,6 @@ export { default as GrFormErrorBanner } from './GrFormErrorBanner.vue';
5
5
  export { DEFAULT_RESPONSE_ERROR_TEXTS, useResponseError, } from './useResponseError';
6
6
  export type { UseResponseErrorOptions, UseResponseErrorReturn, } from './useResponseError';
7
7
  export { DEFAULT_AUTO_HIDE_KINDS, DEFAULT_TONE_BY_KIND, } from './responseError.defaults';
8
- export { abortErrorParser, createResponseErrorClassifier, defaultResponseErrorParsers, extendDefaultParsers, fileValidationParser, httpStatusParser, jsonApiErrorParser, laravelValidationParser, networkErrorParser, normalizeError, plainMessageParser, problemDetailsParser, resolveResponseErrorTitle, } from './parsers';
9
- export type { CreateResponseErrorClassifierOptions } from './parsers';
8
+ export { abortErrorParser, coreResponseErrorParsers, createResponseErrorClassifier, defaultResponseErrorParsers, extendDefaultParsers, fileValidationParser, httpStatusParser, jsonApiErrorParser, laravelValidationParser, networkErrorParser, normalizeError, plainMessageParser, problemDetailsParser, resolveResponseErrorTitle, responseErrorParserPresets, } from './parsers';
9
+ export type { CreateResponseErrorClassifierOptions, ResponseErrorParserPresets, } from './parsers';
10
10
  export type { NormalizedRawError, ResponseErrorContext, ResponseErrorFieldError, ResponseErrorInfo, ResponseErrorKind, ResponseErrorParser, ResponseErrorParserResult, ResponseErrorTexts, ResponseErrorTone, } from './responseError.types';
@@ -8,6 +8,33 @@ import type { ResponseErrorInfo, ResponseErrorKind, ResponseErrorParser, Respons
8
8
  * - `plainMessage` всегда последний — добывает хоть какое-то сообщение.
9
9
  */
10
10
  export declare const defaultResponseErrorParsers: ResponseErrorParser[];
11
+ /**
12
+ * Универсальное «ядро» парсеров — транспортно-независимый набор, безопасный
13
+ * для любого бэкенда (Laravel / Symfony / Go / …). Не делает формат-специфичных
14
+ * допущений: разбирает только отмену, сетевые ошибки, HTTP-статус и «плоское»
15
+ * сообщение из тела. Используется как дефолт в `useDialogService`.
16
+ *
17
+ * Порядок: `abort → network → httpStatus → plainMessage`.
18
+ */
19
+ export declare const coreResponseErrorParsers: ResponseErrorParser[];
20
+ /**
21
+ * Именованные пресеты-строительные блоки для удобной композиции цепочки
22
+ * парсеров без ручного импорта каждого из них.
23
+ *
24
+ * - `core` — универсальное ядро (см. `coreResponseErrorParsers`).
25
+ * - `all` — полная дефолтная цепочка (`defaultResponseErrorParsers`).
26
+ * - остальные — серверо-специфичные парсеры, подключаемые осознанно.
27
+ */
28
+ export type ResponseErrorParserPresets = {
29
+ core: ResponseErrorParser[];
30
+ all: ResponseErrorParser[];
31
+ laravel: ResponseErrorParser;
32
+ problemDetails: ResponseErrorParser;
33
+ jsonApi: ResponseErrorParser;
34
+ fileValidation: ResponseErrorParser;
35
+ };
36
+ /** Объект пресетов, передаётся builder-функции `errorParsers`. */
37
+ export declare const responseErrorParserPresets: ResponseErrorParserPresets;
11
38
  /** Добавляет пользовательские парсеры в начало дефолтной цепочки. */
12
39
  export declare function extendDefaultParsers(extra: ResponseErrorParser[]): ResponseErrorParser[];
13
40
  export type CreateResponseErrorClassifierOptions = {
@@ -7,5 +7,5 @@ export { networkErrorParser } from './networkErrorParser';
7
7
  export { plainMessageParser } from './plainMessageParser';
8
8
  export { problemDetailsParser } from './problemDetailsParser';
9
9
  export { normalizeError } from './normalizeError';
10
- export { createResponseErrorClassifier, defaultResponseErrorParsers, extendDefaultParsers, resolveResponseErrorTitle, } from './createResponseErrorClassifier';
11
- export type { CreateResponseErrorClassifierOptions } from './createResponseErrorClassifier';
10
+ export { coreResponseErrorParsers, createResponseErrorClassifier, defaultResponseErrorParsers, extendDefaultParsers, resolveResponseErrorTitle, responseErrorParserPresets, } from './createResponseErrorClassifier';
11
+ export type { CreateResponseErrorClassifierOptions, ResponseErrorParserPresets, } from './createResponseErrorClassifier';
@@ -100,9 +100,9 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
100
100
  size: GrSelectSize;
101
101
  disabled: boolean;
102
102
  ariaLabel: string;
103
+ placeholder: string;
103
104
  options: GrSelectOption[];
104
105
  multiple: boolean;
105
- placeholder: string;
106
106
  underline: GrSelectUnderline;
107
107
  optionsView: GrSelectOptionsView;
108
108
  allowCustomValue: boolean;
@@ -52,11 +52,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
52
52
  disabled: boolean;
53
53
  name: string;
54
54
  id: string;
55
- rows: number;
56
55
  invalid: boolean;
56
+ rows: number;
57
57
  placeholder: string;
58
- state: GrTextareaState;
59
58
  autocomplete: string;
59
+ state: GrTextareaState;
60
60
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
61
61
  declare const _default: typeof __VLS_export;
62
62
  export default _default;
@@ -17,8 +17,8 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
17
17
  dismissLabel: string;
18
18
  regionLabel: string;
19
19
  }>>> & Readonly<{}>, {
20
- regionLabel: string;
21
20
  dismissLabel: string;
21
+ regionLabel: string;
22
22
  placement: GrToasterPlacement;
23
23
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
24
24
  declare const _default: typeof __VLS_export;
@@ -11,6 +11,7 @@ export * from './components/GrCollapse';
11
11
  export * from './components/GrConfirmDialog';
12
12
  export * from './components/GrDataTable';
13
13
  export * from './components/GrDialog';
14
+ export * from './components/GrDialogService';
14
15
  export * from './components/GrDrawer';
15
16
  export * from './components/GrDropdown';
16
17
  export * from './components/GrDropdownMenu';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@feugene/granularity",
3
3
  "description": "Granularity design system package with Vue 3 components, consumed via the `@feugene/unocss-preset-granular` preset.",
4
- "version": "0.8.0",
4
+ "version": "0.9.1",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": {
7
7
  "name": "Evgeniy Fureev",
@@ -193,6 +193,10 @@
193
193
  "types": "./dist/types/src/components/GrRadioGroup/index.d.ts",
194
194
  "import": "./dist/components/GrRadioGroup/index.js"
195
195
  },
196
+ "./components/GrResponseErrorBanner": {
197
+ "types": "./dist/types/src/components/GrResponseErrorBanner/index.d.ts",
198
+ "import": "./dist/components/GrResponseErrorBanner/index.js"
199
+ },
196
200
  "./components/GrSegmented": {
197
201
  "types": "./dist/types/src/components/GrSegmented/index.d.ts",
198
202
  "import": "./dist/components/GrSegmented/index.js"
@@ -1 +0,0 @@
1
- {"version":3,"file":"arrow-up-DNXrMoAI.js","names":[],"sources":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-C0b_3LJV.js","names":[],"sources":["../../src/components/GrTreeSelect/grTreeSelectStyles.ts","../../src/components/GrTreeSelect/safelist.ts","../../src/components/GrTreeSelect/config.ts"],"sourcesContent":["import type { GrInputSize } from '../GrInput'\n\nexport type GrTreeSelectState = 'default' | 'success' | 'warning' | 'danger'\n\nexport const sizeClassBySize: Record<GrInputSize, string> = {\n xs: 'h-7 px-2.5 text-[12px]',\n sm: 'h-8 px-3 text-[13px]',\n md: 'h-10 px-3 text-[14px]',\n lg: 'h-11 px-4 text-[16px]',\n}\n\nexport const borderClassByState: Record<GrTreeSelectState, string> = {\n default: 'border-[var(--brd)]',\n success: 'border-[var(--ds-success)] focus-visible:ring-[var(--ds-success)]',\n warning: 'border-[var(--ds-warning)] focus-visible:ring-[var(--ds-warning)]',\n danger: 'border-[var(--ds-danger)] focus-visible:ring-[var(--ds-danger)]',\n}\n\nexport function grTreeSelectClass(options: { size: GrInputSize, state: GrTreeSelectState, invalid: boolean }): string {\n return [\n sizeClassBySize[options.size],\n 'pr-9',\n options.invalid ? borderClassByState.danger : borderClassByState[options.state],\n ].join(' ')\n}\n\nexport const grTreeSelectPanelClass = 'rounded-[var(--ds-radius-xl)] border border-[var(--brd)] bg-[var(--card)] text-[var(--card-fg)] shadow-[var(--ds-shadow-2)] overflow-hidden'\n","import { splitClassTokens } from '../shared/classTokens'\nimport { borderClassByState, grTreeSelectPanelClass, sizeClassBySize } from './grTreeSelectStyles'\n\nexport const grTreeSelectSafelist = [...new Set([\n ...Object.values(sizeClassBySize).flatMap(splitClassTokens),\n ...Object.values(borderClassByState).flatMap(splitClassTokens),\n 'pr-9',\n ...splitClassTokens(grTreeSelectPanelClass),\n])]\n","import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nimport { grTreeSelectSafelist } from './safelist'\n\nexport const grTreeSelectConfig = defineGranularComponent(import.meta.url, {\n name: 'GrTreeSelect',\n safelist: grTreeSelectSafelist,\n dependencies: ['GrInput', 'GrTree'],\n})"],"mappings":";;;AAIA,IAAa,kBAA+C;CAC1D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,IAAa,qBAAwD;CACnE,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACT;AAED,SAAgB,kBAAkB,SAAoF;AACpH,QAAO;EACL,gBAAgB,QAAQ;EACxB;EACA,QAAQ,UAAU,mBAAmB,SAAS,mBAAmB,QAAQ;EAC1E,CAAC,KAAK,IAAI;;AAGb,IAAa,yBAAyB;;;ACvBtC,IAAa,uBAAuB,CAAC,GAAG,IAAI,IAAI;CAC9C,GAAG,OAAO,OAAO,gBAAgB,CAAC,QAAQ,iBAAiB;CAC3D,GAAG,OAAO,OAAO,mBAAmB,CAAC,QAAQ,iBAAiB;CAC9D;CACA,GAAG,iBAAiB,uBAAuB;CAC5C,CAAC,CAAC;;;ACJH,IAAa,qBAAqB,wBAAwB,OAAO,KAAK,KAAK;CACzE,MAAM;CACN,UAAU;CACV,cAAc,CAAC,WAAW,SAAS;CACpC,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-C4AlNm912.js","names":[],"sources":["../../src/components/GrDropdown/safelist.ts","../../src/components/GrDropdown/config.ts"],"sourcesContent":["import { splitClassTokens } from '../shared/classTokens'\nimport {\n alignmentClassByAlign,\n widthClassByWidth,\n} from './grDropdownStyles'\n\n// В safelist кладём только динамические токены, выбираемые по ключам в рантайме\n// (`width`/`align`). Литералы content-класса (`rounded-*`, `border`, `bg-*` и пр.)\n// прописаны статически в исходнике `grDropdownStyles.ts` и находятся UnoCSS'ом сканом.\nexport const grDropdownSafelist = [...new Set([\n ...Object.values(widthClassByWidth).flatMap(splitClassTokens),\n ...Object.values(alignmentClassByAlign).flatMap(splitClassTokens),\n])]\n","import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nimport { grDropdownSafelist } from './safelist'\n\nexport const grDropdownConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDropdown',\n safelist: grDropdownSafelist,\n})"],"mappings":";;;;AASA,IAAa,qBAAqB,CAAC,GAAG,IAAI,IAAI,CAC5C,GAAG,OAAO,OAAO,kBAAkB,CAAC,QAAQ,iBAAiB,EAC7D,GAAG,OAAO,OAAO,sBAAsB,CAAC,QAAQ,iBAAiB,CAClE,CAAC,CAAC;;;ACRH,IAAa,mBAAmB,wBAAwB,OAAO,KAAK,KAAK;CACvE,MAAM;CACN,UAAU;CACX,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-CxCAfXZ1.js","names":[],"sources":["../../src/components/GrToaster/grToasterStyles.ts","../../src/components/GrToaster/safelist.ts","../../src/components/GrToaster/config.ts"],"sourcesContent":["export type GrToasterPlacement = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left'\n\n// Классы позиционирования контейнера по углам экрана.\n// Вынесены в отдельный модуль, чтобы быть единственным источником истины\n// для шаблона `GrToaster.vue` и для safelist.\nexport const PLACEMENT_CLASS: Record<GrToasterPlacement, string> = {\n 'top-right': 'right-4 top-4',\n 'top-left': 'left-4 top-4',\n 'bottom-right': 'right-4 bottom-4',\n 'bottom-left': 'left-4 bottom-4',\n}\n","import { splitClassTokens } from '../shared/classTokens'\nimport { PLACEMENT_CLASS } from './grToasterStyles'\n\n// В safelist попадают только те классы, которые приходят в шаблон динамически\n// (через `:class`/`PLACEMENT_CLASS`). Литералы из шаблона (`class=\"...\"`)\n// UnoCSS находит статическим сканом и дублировать их здесь не нужно.\nexport const grToasterSafelist = [...new Set(\n Object.values(PLACEMENT_CLASS).flatMap(splitClassTokens),\n)]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grToasterSafelist } from './safelist'\n\nexport const grToasterConfig = defineGranularComponent(import.meta.url, {\n name: 'GrToaster',\n dependencies: ['GrButton', 'GrIcon'],\n safelist: grToasterSafelist,\n})\n"],"mappings":";;;AAKA,IAAa,kBAAsD;CACjE,aAAa;CACb,YAAY;CACZ,gBAAgB;CAChB,eAAe;CAChB;;;ACJD,IAAa,oBAAoB,CAAC,GAAG,IAAI,IACvC,OAAO,OAAO,gBAAgB,CAAC,QAAQ,iBAAiB,CACzD,CAAC;;;ACJF,IAAa,kBAAkB,wBAAwB,OAAO,KAAK,KAAK;CACtE,MAAM;CACN,cAAc,CAAC,YAAY,SAAS;CACpC,UAAU;CACX,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DDEWvph-2.js","names":[],"sources":["../../src/components/GrDropdownMenu/config.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grDropdownMenuConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDropdownMenu',\n dependencies: ['GrDropdown'],\n})\n"],"mappings":";;AAEA,IAAa,uBAAuB,wBAAwB,OAAO,KAAK,KAAK;CAC3E,MAAM;CACN,cAAc,CAAC,aAAa;CAC7B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DDLoUczC.js","names":[],"sources":["../../src/components/GrTabs/config.ts"],"sourcesContent":["import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nexport const grTabsConfig = defineGranularComponent(import.meta.url, {\n name: 'GrTabs',\n})\n"],"mappings":";;AAEA,IAAa,eAAe,wBAAwB,OAAO,KAAK,KAAK,EACjE,MAAM,UACT,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DK2NpdyX2.js","names":[],"sources":["../../src/components/GrDataTable/config.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grDataTableConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDataTable',\n dependencies: ['GrTable', 'GrIcon'],\n})\n"],"mappings":";;AAEA,IAAa,oBAAoB,wBAAwB,OAAO,KAAK,KAAK;CACxE,MAAM;CACN,cAAc,CAAC,WAAW,SAAS;CACpC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DQOSlWvp.js","names":[],"sources":["../../src/components/GrTable/config.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\n// Все классы GrTable — статические литералы в шаблоне, UnoCSS найдёт их сканом.\nexport const grTableConfig = defineGranularComponent(import.meta.url, {\n name: 'GrTable',\n})\n"],"mappings":";;AAGA,IAAa,gBAAgB,wBAAwB,OAAO,KAAK,KAAK,EACpE,MAAM,WACP,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DnsISjD8.js","names":[],"sources":["../../src/components/GrSidebar/config.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grSidebarConfig = defineGranularComponent(import.meta.url, {\n name: 'GrSidebar',\n})\n"],"mappings":";;AAEA,IAAa,kBAAkB,wBAAwB,OAAO,KAAK,KAAK,EACtE,MAAM,aACP,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DxqMXzNV2.js","names":[],"sources":["../../src/components/GrTextarea/grTextareaStyles.ts","../../src/components/GrTextarea/safelist.ts","../../src/components/GrTextarea/config.ts"],"sourcesContent":["export type GrTextareaState = 'default' | 'success' | 'warning' | 'danger'\n\nexport const borderClassByState: Record<GrTextareaState, string> = {\n default: 'border-[var(--brd)]',\n success: 'border-[var(--ds-success)] focus-visible:ring-[var(--ds-success)]',\n warning: 'border-[var(--ds-warning)] focus-visible:ring-[var(--ds-warning)]',\n danger: 'border-[var(--ds-danger)] focus-visible:ring-[var(--ds-danger)]',\n}\n\nexport function grTextareaClass(options: { state: GrTextareaState, invalid: boolean }): string {\n return options.invalid ? borderClassByState.danger : borderClassByState[options.state]\n}\n","import { splitClassTokens } from '../shared/classTokens'\nimport { borderClassByState } from './grTextareaStyles'\n\nexport const grTextareaSafelist = [...new Set([\n ...Object.values(borderClassByState).flatMap(splitClassTokens),\n])]\n","import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nimport { grTextareaSafelist } from './safelist'\n\nexport const grTextareaConfig = defineGranularComponent(import.meta.url, {\n name: 'GrTextarea',\n safelist: grTextareaSafelist,\n})"],"mappings":";;;AAEA,IAAa,qBAAsD;CACjE,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACT;AAED,SAAgB,gBAAgB,SAA+D;AAC7F,QAAO,QAAQ,UAAU,mBAAmB,SAAS,mBAAmB,QAAQ;;;;ACPlF,IAAa,qBAAqB,CAAC,GAAG,IAAI,IAAI,CAC5C,GAAG,OAAO,OAAO,mBAAmB,CAAC,QAAQ,iBAAiB,CAC/D,CAAC,CAAC;;;ACDH,IAAa,mBAAmB,wBAAwB,OAAO,KAAK,KAAK;CACvE,MAAM;CACN,UAAU;CACX,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-DxqpV-KM.js","names":[],"sources":["../../src/components/GrDrawer/grDrawerStyles.ts","../../src/components/GrDrawer/safelist.ts","../../src/components/GrDrawer/config.ts"],"sourcesContent":["export type GrDrawerSide = 'left' | 'right'\nexport type GrDrawerSize = 'sm' | 'md' | 'lg' | 'full'\n\nexport const panelWidthBySize: Record<GrDrawerSize, string> = {\n sm: 'w-[360px] max-w-[90vw]',\n md: 'w-[420px] max-w-[92vw]',\n lg: 'w-[560px] max-w-[94vw]',\n full: 'w-[100vw]',\n}\n\nexport const panelSideClass: Record<GrDrawerSide, string> = {\n left: 'left-0 border-r',\n right: 'right-0 border-l',\n}\n\nexport const panelTransitionClass: Record<GrDrawerSide, string> = {\n left: '-translate-x-full',\n right: 'translate-x-full',\n}\n\nexport function grDrawerPanelClass(options: { side: GrDrawerSide, size: GrDrawerSize }): string {\n return [\n panelSideClass[options.side],\n panelWidthBySize[options.size],\n 'border-[var(--brd)]',\n 'bg-[var(--card)] text-[var(--card-fg)]',\n 'shadow-[var(--ds-shadow-2)] outline-none',\n ].join(' ')\n}\n\nexport function grDrawerPanelEnterFrom(side: GrDrawerSide): string {\n return panelTransitionClass[side]\n}\n","import { splitClassTokens } from '../shared/classTokens'\nimport {\n panelSideClass,\n panelTransitionClass,\n panelWidthBySize,\n} from './grDrawerStyles'\n\n// Safelist содержит только динамические токены, выбираемые в рантайме через\n// ключи (`side`/`size`). Литералы, прописанные статически в шаблоне и в функции\n// `grDrawerPanelClass`, UnoCSS находит сканом и здесь не дублируются.\nexport const grDrawerSafelist = [...new Set([\n ...Object.values(panelSideClass).flatMap(splitClassTokens),\n ...Object.values(panelWidthBySize).flatMap(splitClassTokens),\n ...Object.values(panelTransitionClass).flatMap(splitClassTokens),\n])]\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\nimport { grDrawerSafelist } from './safelist'\n\nexport const grDrawerConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDrawer',\n dependencies: ['GrButton', 'GrIcon'],\n safelist: grDrawerSafelist,\n})\n"],"mappings":";;;AAGA,IAAa,mBAAiD;CAC5D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM;CACP;AAED,IAAa,iBAA+C;CAC1D,MAAM;CACN,OAAO;CACR;AAED,IAAa,uBAAqD;CAChE,MAAM;CACN,OAAO;CACR;AAED,SAAgB,mBAAmB,SAA6D;AAC9F,QAAO;EACL,eAAe,QAAQ;EACvB,iBAAiB,QAAQ;EACzB;EACA;EACA;EACD,CAAC,KAAK,IAAI;;AAGb,SAAgB,uBAAuB,MAA4B;AACjE,QAAO,qBAAqB;;;;ACrB9B,IAAa,mBAAmB,CAAC,GAAG,IAAI,IAAI;CAC1C,GAAG,OAAO,OAAO,eAAe,CAAC,QAAQ,iBAAiB;CAC1D,GAAG,OAAO,OAAO,iBAAiB,CAAC,QAAQ,iBAAiB;CAC5D,GAAG,OAAO,OAAO,qBAAqB,CAAC,QAAQ,iBAAiB;CACjE,CAAC,CAAC;;;ACXH,IAAa,iBAAiB,wBAAwB,OAAO,KAAK,KAAK;CACrE,MAAM;CACN,cAAc,CAAC,YAAY,SAAS;CACpC,UAAU;CACX,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-iDTkWUdh2.js","names":[],"sources":["../../src/components/GrConfirmDialog/config.ts"],"sourcesContent":["import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nexport const grConfirmDialogConfig = defineGranularComponent(import.meta.url, {\n name: 'GrConfirmDialog',\n dependencies: ['GrButton', 'GrDialog'],\n})"],"mappings":";;AAEA,IAAa,wBAAwB,wBAAwB,OAAO,KAAK,KAAK;CAC1E,MAAM;CACN,cAAc,CAAC,YAAY,WAAW;CACzC,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"config-rxFL-6yF2.js","names":[],"sources":["../../src/components/GrSwitch/grSwitchStyles.ts","../../src/components/GrSwitch/safelist.ts","../../src/components/GrSwitch/config.ts"],"sourcesContent":["export type GrSwitchSize = 'sm' | 'md' | 'lg'\n\ntype GrSwitchThumbClassOptions = {\n checked: boolean\n size: GrSwitchSize\n}\n\nexport const trackBase =\n 'relative inline-flex items-center rounded-full border border-[var(--ds-switch-track-brd)] transition-colors duration-150'\n\nexport const trackSizes: Record<GrSwitchSize, string> = {\n sm: 'h-5 w-9',\n md: 'h-6 w-11',\n lg: 'h-7 w-14',\n}\n\nexport const thumbBase =\n 'inline-block rounded-full bg-[var(--card)] shadow-[var(--ds-shadow-1)] transition-transform duration-150'\n\nexport const thumbSizes: Record<GrSwitchSize, string> = {\n sm: 'h-4 w-4',\n md: 'h-5 w-5',\n lg: 'h-6 w-6',\n}\n\nexport const thumbTranslations: Record<GrSwitchSize, { checked: string, unchecked: string }> = {\n sm: {\n checked: 'translate-x-[17px]',\n unchecked: 'translate-x-[2px]',\n },\n md: {\n checked: 'translate-x-5',\n unchecked: 'translate-x-[2px]',\n },\n lg: {\n checked: 'translate-x-[28px]',\n unchecked: 'translate-x-[3px]',\n },\n}\n\nexport const labelBase = 'text-[var(--muted-fg)]'\n\nexport const labelSizes: Record<GrSwitchSize, string> = {\n sm: 'text-sm',\n md: 'text-sm',\n lg: 'text-base',\n}\n\nexport function grSwitchTrackClass(size: GrSwitchSize): string {\n return [trackBase, trackSizes[size]].join(' ')\n}\n\nexport function grSwitchThumbClass(options: GrSwitchThumbClassOptions): string {\n return [\n thumbBase,\n thumbSizes[options.size],\n thumbTranslations[options.size][options.checked ? 'checked' : 'unchecked'],\n ].join(' ')\n}\n\nexport function grSwitchLabelClass(size: GrSwitchSize): string {\n return [labelBase, labelSizes[size]].join(' ')\n}\n","import { splitClassTokens } from '../shared/classTokens'\nimport {\n labelBase,\n labelSizes,\n thumbBase,\n thumbSizes,\n thumbTranslations,\n trackBase,\n trackSizes,\n} from './grSwitchStyles'\n\nexport const grSwitchClassTokens = {\n trackBase: splitClassTokens(trackBase),\n trackSizes: Object.values(trackSizes).flatMap(splitClassTokens),\n thumbBase: splitClassTokens(thumbBase),\n thumbSizes: Object.values(thumbSizes).flatMap(splitClassTokens),\n thumbTranslations: Object.values(thumbTranslations).flatMap(({checked, unchecked}) => {\n return [...splitClassTokens(checked), ...splitClassTokens(unchecked)]\n }),\n labelBase: splitClassTokens(labelBase),\n labelSizes: Object.values(labelSizes).flatMap(splitClassTokens),\n} as const\n\nexport const grSwitchSafelist = [...new Set([\n ...grSwitchClassTokens.trackBase,\n ...grSwitchClassTokens.trackSizes,\n ...grSwitchClassTokens.thumbBase,\n ...grSwitchClassTokens.thumbSizes,\n ...grSwitchClassTokens.thumbTranslations,\n ...grSwitchClassTokens.labelBase,\n ...grSwitchClassTokens.labelSizes,\n])]\n","import {defineGranularComponent} from '@feugene/unocss-preset-granular/contract'\n\nimport { grSwitchSafelist } from './safelist'\n\nexport const grSwitchConfig = defineGranularComponent(import.meta.url, {\n name: 'GrSwitch',\n safelist: grSwitchSafelist,\n})"],"mappings":";;;AAOA,IAAa,YACT;AAEJ,IAAa,aAA2C;CACpD,IAAI;CACJ,IAAI;CACJ,IAAI;CACP;AAED,IAAa,YACT;AAEJ,IAAa,aAA2C;CACpD,IAAI;CACJ,IAAI;CACJ,IAAI;CACP;AAED,IAAa,oBAAkF;CAC3F,IAAI;EACA,SAAS;EACT,WAAW;EACd;CACD,IAAI;EACA,SAAS;EACT,WAAW;EACd;CACD,IAAI;EACA,SAAS;EACT,WAAW;EACd;CACJ;AAED,IAAa,YAAY;AAEzB,IAAa,aAA2C;CACpD,IAAI;CACJ,IAAI;CACJ,IAAI;CACP;AAED,SAAgB,mBAAmB,MAA4B;AAC3D,QAAO,CAAC,WAAW,WAAW,MAAM,CAAC,KAAK,IAAI;;AAGlD,SAAgB,mBAAmB,SAA4C;AAC3E,QAAO;EACH;EACA,WAAW,QAAQ;EACnB,kBAAkB,QAAQ,MAAM,QAAQ,UAAU,YAAY;EACjE,CAAC,KAAK,IAAI;;AAGf,SAAgB,mBAAmB,MAA4B;AAC3D,QAAO,CAAC,WAAW,WAAW,MAAM,CAAC,KAAK,IAAI;;;;AClDlD,IAAa,sBAAsB;CAC/B,WAAW,iBAAiB,UAAU;CACtC,YAAY,OAAO,OAAO,WAAW,CAAC,QAAQ,iBAAiB;CAC/D,WAAW,iBAAiB,UAAU;CACtC,YAAY,OAAO,OAAO,WAAW,CAAC,QAAQ,iBAAiB;CAC/D,mBAAmB,OAAO,OAAO,kBAAkB,CAAC,SAAS,EAAC,SAAS,gBAAe;AAClF,SAAO,CAAC,GAAG,iBAAiB,QAAQ,EAAE,GAAG,iBAAiB,UAAU,CAAC;GACvE;CACF,WAAW,iBAAiB,UAAU;CACtC,YAAY,OAAO,OAAO,WAAW,CAAC,QAAQ,iBAAiB;CAClE;AAED,IAAa,mBAAmB,CAAC,GAAG,IAAI,IAAI;CACxC,GAAG,oBAAoB;CACvB,GAAG,oBAAoB;CACvB,GAAG,oBAAoB;CACvB,GAAG,oBAAoB;CACvB,GAAG,oBAAoB;CACvB,GAAG,oBAAoB;CACvB,GAAG,oBAAoB;CAC1B,CAAC,CAAC;;;AC3BH,IAAa,iBAAiB,wBAAwB,OAAO,KAAK,KAAK;CACrE,MAAM;CACN,UAAU;CACX,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"safelist-BF822K15.js","names":[],"sources":["../../src/components/GrDialog/safelist.ts"],"sourcesContent":["import { splitClassTokens } from '../shared/classTokens'\nimport {\n DEFAULT_GR_DIALOG_BODY_CONFIG,\n DEFAULT_GR_DIALOG_FOOTER_CONFIG,\n DEFAULT_GR_DIALOG_HEADER_CONFIG,\n} from './dialogShared'\n\n// В safelist попадают ТОЛЬКО токены, которые нельзя обнаружить статическим\n// сканом шаблонов: значения из дефолтных конфигов секций (`paddingX`/`paddingY`),\n// которые используются через `:class` и могут переопределяться консьюмером.\n//\n// Все литералы, прописанные напрямую в шаблонах (`class=\"...\"` или\n// статические строки в `:class=\"[...]\"` внутри .vue), UnoCSS найдёт сам —\n// дублировать их здесь не нужно.\nfunction configTokens(config: { paddingX: string, paddingY: string }): string[] {\n return [\n ...splitClassTokens(config.paddingX),\n ...splitClassTokens(config.paddingY),\n ]\n}\n\nexport const grDialogSafelist = [...new Set([\n ...configTokens(DEFAULT_GR_DIALOG_HEADER_CONFIG),\n ...configTokens(DEFAULT_GR_DIALOG_FOOTER_CONFIG),\n ...configTokens(DEFAULT_GR_DIALOG_BODY_CONFIG),\n])]\n"],"mappings":";;;AAcA,SAAS,aAAa,QAA0D;AAC9E,QAAO,CACL,GAAG,iBAAiB,OAAO,SAAS,EACpC,GAAG,iBAAiB,OAAO,SAAS,CACrC;;AAGH,IAAa,mBAAmB,CAAC,GAAG,IAAI,IAAI;CAC1C,GAAG,aAAa,gCAAgC;CAChD,GAAG,aAAa,gCAAgC;CAChD,GAAG,aAAa,8BAA8B;CAC/C,CAAC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrConfirmDialog-DE-d77Us.js","names":[],"sources":["../../../../src/components/GrConfirmDialog/GrConfirmDialog.vue","../../../../src/components/GrConfirmDialog/GrConfirmDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrConfirmDialog — DS-примитив диалога подтверждения поверх `GrDialog`.\n *\n * Синхронизирован с `GrDialog`/`GrPromptDialog` по набору проп-проксирования:\n * `size`, `closeOnBackdrop`, `closeOnEsc`, `showHeader`, `showCloseButton`,\n * `headerConfig`, `footerConfig`, `bodyConfig`, `closeLabel`.\n *\n * Клик по «Confirm»/«Cancel» эмитит одноимённое событие и закрывает диалог\n * через `update:modelValue`.\n */\nimport { computed } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrDialog from '../GrDialog/GrDialog.vue'\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton'\nimport type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog'\n\nexport interface GrConfirmDialogProps {\n modelValue: boolean\n title?: string\n description?: string\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n showHeader?: boolean\n showCloseButton?: boolean\n size?: GrDialogSize\n headerConfig?: GrDialogSectionConfig\n footerConfig?: GrDialogSectionConfig\n bodyConfig?: GrDialogSectionConfig\n /** A11y-лейбл кнопки закрытия (i18n). */\n closeLabel?: string\n buttonSize?: GrButtonSize\n confirmText?: string\n cancelText?: string\n confirmVariant?: GrButtonVariant\n confirmTone?: GrButtonTone\n}\n\nconst props = withDefaults(defineProps<GrConfirmDialogProps>(), {\n title: 'Confirm',\n description: undefined,\n closeOnBackdrop: true,\n closeOnEsc: true,\n showHeader: true,\n showCloseButton: true,\n size: 'md',\n headerConfig: undefined,\n footerConfig: undefined,\n bodyConfig: undefined,\n closeLabel: 'Close',\n buttonSize: undefined,\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n confirmVariant: 'primary',\n confirmTone: 'primary',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'confirm'): void\n (e: 'cancel'): void\n}>()\n\nconst open = computed({\n get: () => props.modelValue,\n set: (value: boolean) => emit('update:modelValue', value),\n})\n\nfunction onCancel(): void {\n emit('cancel')\n emit('update:modelValue', false)\n}\n\nfunction onConfirm(): void {\n emit('confirm')\n emit('update:modelValue', false)\n}\n</script>\n\n<template>\n <GrDialog\n v-model=\"open\"\n :title=\"title\"\n :size=\"size\"\n :close-on-backdrop=\"closeOnBackdrop\"\n :close-on-esc=\"closeOnEsc\"\n :show-header=\"showHeader\"\n :show-close-button=\"showCloseButton\"\n :header-config=\"headerConfig\"\n :footer-config=\"footerConfig\"\n :body-config=\"bodyConfig\"\n :close-label=\"closeLabel\"\n >\n <slot>\n <div v-if=\"description\" class=\"text-[14px] text-[var(--muted-fg)]\">\n {{ description }}\n </div>\n </slot>\n\n <template #footer>\n <slot name=\"footer\">\n <div class=\"flex items-center justify-end gap-3\">\n <GrButton data-testid=\"ds-confirm-cancel\" variant=\"outline\" :size=\"buttonSize\" @click=\"onCancel\">\n {{ cancelText }}\n </GrButton>\n <GrButton\n data-testid=\"ds-confirm-confirm\"\n :variant=\"confirmVariant\"\n :tone=\"confirmTone\"\n :size=\"buttonSize\"\n @click=\"onConfirm\"\n >\n {{ confirmText }}\n </GrButton>\n </div>\n </slot>\n </template>\n </GrDialog>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrConfirmDialog — DS-примитив диалога подтверждения поверх `GrDialog`.\n *\n * Синхронизирован с `GrDialog`/`GrPromptDialog` по набору проп-проксирования:\n * `size`, `closeOnBackdrop`, `closeOnEsc`, `showHeader`, `showCloseButton`,\n * `headerConfig`, `footerConfig`, `bodyConfig`, `closeLabel`.\n *\n * Клик по «Confirm»/«Cancel» эмитит одноимённое событие и закрывает диалог\n * через `update:modelValue`.\n */\nimport { computed } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrDialog from '../GrDialog/GrDialog.vue'\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton'\nimport type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog'\n\nexport interface GrConfirmDialogProps {\n modelValue: boolean\n title?: string\n description?: string\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n showHeader?: boolean\n showCloseButton?: boolean\n size?: GrDialogSize\n headerConfig?: GrDialogSectionConfig\n footerConfig?: GrDialogSectionConfig\n bodyConfig?: GrDialogSectionConfig\n /** A11y-лейбл кнопки закрытия (i18n). */\n closeLabel?: string\n buttonSize?: GrButtonSize\n confirmText?: string\n cancelText?: string\n confirmVariant?: GrButtonVariant\n confirmTone?: GrButtonTone\n}\n\nconst props = withDefaults(defineProps<GrConfirmDialogProps>(), {\n title: 'Confirm',\n description: undefined,\n closeOnBackdrop: true,\n closeOnEsc: true,\n showHeader: true,\n showCloseButton: true,\n size: 'md',\n headerConfig: undefined,\n footerConfig: undefined,\n bodyConfig: undefined,\n closeLabel: 'Close',\n buttonSize: undefined,\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n confirmVariant: 'primary',\n confirmTone: 'primary',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'confirm'): void\n (e: 'cancel'): void\n}>()\n\nconst open = computed({\n get: () => props.modelValue,\n set: (value: boolean) => emit('update:modelValue', value),\n})\n\nfunction onCancel(): void {\n emit('cancel')\n emit('update:modelValue', false)\n}\n\nfunction onConfirm(): void {\n emit('confirm')\n emit('update:modelValue', false)\n}\n</script>\n\n<template>\n <GrDialog\n v-model=\"open\"\n :title=\"title\"\n :size=\"size\"\n :close-on-backdrop=\"closeOnBackdrop\"\n :close-on-esc=\"closeOnEsc\"\n :show-header=\"showHeader\"\n :show-close-button=\"showCloseButton\"\n :header-config=\"headerConfig\"\n :footer-config=\"footerConfig\"\n :body-config=\"bodyConfig\"\n :close-label=\"closeLabel\"\n >\n <slot>\n <div v-if=\"description\" class=\"text-[14px] text-[var(--muted-fg)]\">\n {{ description }}\n </div>\n </slot>\n\n <template #footer>\n <slot name=\"footer\">\n <div class=\"flex items-center justify-end gap-3\">\n <GrButton data-testid=\"ds-confirm-cancel\" variant=\"outline\" :size=\"buttonSize\" @click=\"onCancel\">\n {{ cancelText }}\n </GrButton>\n <GrButton\n data-testid=\"ds-confirm-confirm\"\n :variant=\"confirmVariant\"\n :tone=\"confirmTone\"\n :size=\"buttonSize\"\n @click=\"onConfirm\"\n >\n {{ confirmText }}\n </GrButton>\n </div>\n </slot>\n </template>\n </GrDialog>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuCA,MAAM,QAAQ;EAmBd,MAAM,OAAO;EAMb,MAAM,OAAO,SAAS;GACpB,WAAW,MAAM;GACjB,MAAM,UAAmB,KAAK,qBAAqB,MAAM;GAC1D,CAAA;EAED,SAAS,WAAiB;AACxB,QAAK,SAAQ;AACb,QAAK,qBAAqB,MAAK;;EAGjC,SAAS,YAAkB;AACzB,QAAK,UAAS;AACd,QAAK,qBAAqB,MAAK;;;uBAK/B,YAqCW,kBAAA;gBApCA,KAAA;sEAAI,QAAA;IACZ,OAAO,QAAA;IACP,MAAM,QAAA;IACN,qBAAmB,QAAA;IACnB,gBAAc,QAAA;IACd,eAAa,QAAA;IACb,qBAAmB,QAAA;IACnB,iBAAe,QAAA;IACf,iBAAe,QAAA;IACf,eAAa,QAAA;IACb,eAAa,QAAA;;IAQH,QAAM,cAgBR,CAfP,WAeO,KAAA,QAAA,UAAA,EAAA,QAAA,CAdL,mBAaM,OAbN,YAaM,CAZJ,YAEW,kBAAA;KAFD,eAAY;KAAoB,SAAQ;KAAW,MAAM,QAAA;KAAa,SAAO;;4BACrE,CAAA,gBAAA,gBAAb,QAAA,WAAU,EAAA,EAAA,CAAA,CAAA;;qBAEf,YAQW,kBAAA;KAPT,eAAY;KACX,SAAS,QAAA;KACT,MAAM,QAAA;KACN,MAAM,QAAA;KACN,SAAO;;4BAES,CAAA,gBAAA,gBAAd,QAAA,YAAW,EAAA,EAAA,CAAA,CAAA;;;;;;;2BAff,CAJP,WAIO,KAAA,QAAA,WAAA,EAAA,QAAA,CAHM,QAAA,eAAA,WAAA,EAAX,mBAEM,OAFN,YAEM,gBADD,QAAA,YAAW,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA,CAAA,CAAA,CAAA,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrFileUpload-DYRERhI2.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: 'state-change', 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('state-change', 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: 'state-change', 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('state-change', 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 +0,0 @@
1
- {"version":3,"file":"GrModal-gvfvlp7k.js","names":["$slots"],"sources":["../../../../src/components/GrModal/GrModal.vue","../../../../src/components/GrModal/GrModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrModal — DS-примитив модального окна на базе `@headlessui/vue`.\n *\n * Публичный API:\n * - `modelValue` (v-model) — открыто/закрыто;\n * - `size` — размер панели (`sm | md | lg | xl | full`);\n * - `closeOnBackdrop` (default: true) — закрывать при клике по оверлею;\n * - `closeOnEsc` (default: true) — закрывать по Esc;\n * - слоты `#title` / `#description` — если переданы, оборачиваются в\n * `DialogTitle` / `DialogDescription` (связь через `aria-labelledby` /\n * `aria-describedby` ставится HeadlessUI автоматически).\n *\n * Esc обрабатывается штатно через событие `@close` у HeadlessUI `<Dialog>`,\n * чтобы не конфликтовать с его внутренней логикой. Источник закрытия\n * различается через ref `closeReasonRef`.\n */\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\nimport {\n type GrModalSize,\n getGrModalPanelClass,\n layout,\n overlay as overlayClass,\n overlayTransition,\n panelTransition,\n root as rootClass,\n shell,\n} from './grModalStyles'\n\nexport interface GrModalProps {\n modelValue: boolean\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n size?: GrModalSize\n}\n\nconst props = withDefaults(defineProps<GrModalProps>(), {\n closeOnBackdrop: true,\n closeOnEsc: true,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n}>()\n\nconst panelClass = computed(() => getGrModalPanelClass(props.size))\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем teleport,\n// а в клиенте включаем после маунта.\nconst isClient = typeof window !== 'undefined'\n\n// Источник закрытия от HeadlessUI `<Dialog>` — либо Esc, либо клик по оверлею.\n// Различаем их, чтобы `closeOnBackdrop` и `closeOnEsc` работали независимо.\nconst closeReason = ref<'backdrop' | 'esc' | null>(null)\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction onDialogClose(): void {\n const reason = closeReason.value\n closeReason.value = null\n\n if (reason === 'esc') {\n if (props.closeOnEsc) close()\n return\n }\n\n // По умолчанию (клик по оверлею или программный вызов `@close`)\n // уважаем `closeOnBackdrop`.\n if (props.closeOnBackdrop) close()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') closeReason.value = 'esc'\n}\n\nfunction onOverlayPointerDown(): void {\n closeReason.value = 'backdrop'\n}\n\n// ————— Scroll lock на `<body>` на время открытия.\n// HeadlessUI Vue этого не делает автоматически, а фон скроллится —\n// для DS-примитива это мешающий UX.\nlet savedBodyOverflow: string | null = null\n\nfunction lockBodyScroll(): void {\n if (!isClient) return\n if (savedBodyOverflow !== null) return\n savedBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n}\n\nfunction unlockBodyScroll(): void {\n if (!isClient) return\n if (savedBodyOverflow === null) return\n document.body.style.overflow = savedBodyOverflow\n savedBodyOverflow = null\n}\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (value) lockBodyScroll()\n else unlockBodyScroll()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(unlockBodyScroll)\n\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <TransitionRoot :show=\"modelValue\" as=\"template\">\n <Dialog\n as=\"div\"\n :class=\"rootClass\"\n @close=\"onDialogClose\"\n @keydown.capture=\"onRootKeydown\"\n >\n <div :class=\"shell\">\n <div :class=\"layout\">\n <TransitionChild\n as=\"template\"\n :enter=\"overlayTransition.enter\"\n :enter-from=\"overlayTransition.enterFrom\"\n :enter-to=\"overlayTransition.enterTo\"\n :leave=\"overlayTransition.leave\"\n :leave-from=\"overlayTransition.leaveFrom\"\n :leave-to=\"overlayTransition.leaveTo\"\n >\n <div\n data-ds-modal-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n @pointerdown=\"onOverlayPointerDown\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n :enter=\"panelTransition.enter\"\n :enter-from=\"panelTransition.enterFrom\"\n :enter-to=\"panelTransition.enterTo\"\n :leave=\"panelTransition.leave\"\n :leave-from=\"panelTransition.leaveFrom\"\n :leave-to=\"panelTransition.leaveTo\"\n >\n <DialogPanel\n data-ds-modal-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n >\n <DialogTitle v-if=\"$slots.title\" as=\"div\" data-ds-modal-title>\n <slot name=\"title\" />\n </DialogTitle>\n <DialogDescription v-if=\"$slots.description\" as=\"div\" data-ds-modal-description>\n <slot name=\"description\" />\n </DialogDescription>\n <slot />\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrModal — DS-примитив модального окна на базе `@headlessui/vue`.\n *\n * Публичный API:\n * - `modelValue` (v-model) — открыто/закрыто;\n * - `size` — размер панели (`sm | md | lg | xl | full`);\n * - `closeOnBackdrop` (default: true) — закрывать при клике по оверлею;\n * - `closeOnEsc` (default: true) — закрывать по Esc;\n * - слоты `#title` / `#description` — если переданы, оборачиваются в\n * `DialogTitle` / `DialogDescription` (связь через `aria-labelledby` /\n * `aria-describedby` ставится HeadlessUI автоматически).\n *\n * Esc обрабатывается штатно через событие `@close` у HeadlessUI `<Dialog>`,\n * чтобы не конфликтовать с его внутренней логикой. Источник закрытия\n * различается через ref `closeReasonRef`.\n */\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\nimport {\n type GrModalSize,\n getGrModalPanelClass,\n layout,\n overlay as overlayClass,\n overlayTransition,\n panelTransition,\n root as rootClass,\n shell,\n} from './grModalStyles'\n\nexport interface GrModalProps {\n modelValue: boolean\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n size?: GrModalSize\n}\n\nconst props = withDefaults(defineProps<GrModalProps>(), {\n closeOnBackdrop: true,\n closeOnEsc: true,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n}>()\n\nconst panelClass = computed(() => getGrModalPanelClass(props.size))\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем teleport,\n// а в клиенте включаем после маунта.\nconst isClient = typeof window !== 'undefined'\n\n// Источник закрытия от HeadlessUI `<Dialog>` — либо Esc, либо клик по оверлею.\n// Различаем их, чтобы `closeOnBackdrop` и `closeOnEsc` работали независимо.\nconst closeReason = ref<'backdrop' | 'esc' | null>(null)\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction onDialogClose(): void {\n const reason = closeReason.value\n closeReason.value = null\n\n if (reason === 'esc') {\n if (props.closeOnEsc) close()\n return\n }\n\n // По умолчанию (клик по оверлею или программный вызов `@close`)\n // уважаем `closeOnBackdrop`.\n if (props.closeOnBackdrop) close()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') closeReason.value = 'esc'\n}\n\nfunction onOverlayPointerDown(): void {\n closeReason.value = 'backdrop'\n}\n\n// ————— Scroll lock на `<body>` на время открытия.\n// HeadlessUI Vue этого не делает автоматически, а фон скроллится —\n// для DS-примитива это мешающий UX.\nlet savedBodyOverflow: string | null = null\n\nfunction lockBodyScroll(): void {\n if (!isClient) return\n if (savedBodyOverflow !== null) return\n savedBodyOverflow = document.body.style.overflow\n document.body.style.overflow = 'hidden'\n}\n\nfunction unlockBodyScroll(): void {\n if (!isClient) return\n if (savedBodyOverflow === null) return\n document.body.style.overflow = savedBodyOverflow\n savedBodyOverflow = null\n}\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (value) lockBodyScroll()\n else unlockBodyScroll()\n },\n { immediate: true },\n)\n\nonBeforeUnmount(unlockBodyScroll)\n\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <TransitionRoot :show=\"modelValue\" as=\"template\">\n <Dialog\n as=\"div\"\n :class=\"rootClass\"\n @close=\"onDialogClose\"\n @keydown.capture=\"onRootKeydown\"\n >\n <div :class=\"shell\">\n <div :class=\"layout\">\n <TransitionChild\n as=\"template\"\n :enter=\"overlayTransition.enter\"\n :enter-from=\"overlayTransition.enterFrom\"\n :enter-to=\"overlayTransition.enterTo\"\n :leave=\"overlayTransition.leave\"\n :leave-from=\"overlayTransition.leaveFrom\"\n :leave-to=\"overlayTransition.leaveTo\"\n >\n <div\n data-ds-modal-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n @pointerdown=\"onOverlayPointerDown\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n :enter=\"panelTransition.enter\"\n :enter-from=\"panelTransition.enterFrom\"\n :enter-to=\"panelTransition.enterTo\"\n :leave=\"panelTransition.leave\"\n :leave-from=\"panelTransition.leaveFrom\"\n :leave-to=\"panelTransition.leaveTo\"\n >\n <DialogPanel\n data-ds-modal-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n >\n <DialogTitle v-if=\"$slots.title\" as=\"div\" data-ds-modal-title>\n <slot name=\"title\" />\n </DialogTitle>\n <DialogDescription v-if=\"$slots.description\" as=\"div\" data-ds-modal-description>\n <slot name=\"description\" />\n </DialogDescription>\n <slot />\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsCA,MAAM,QAAQ;EAMd,MAAM,OAAO;EAIb,MAAM,aAAa,eAAe,qBAAqB,MAAM,KAAK,CAAA;EAIlE,MAAM,WAAW,OAAO,WAAW;EAInC,MAAM,cAAc,IAA+B,KAAI;EAEvD,SAAS,QAAc;AACrB,QAAK,qBAAqB,MAAK;;EAGjC,SAAS,gBAAsB;GAC7B,MAAM,SAAS,YAAY;AAC3B,eAAY,QAAQ;AAEpB,OAAI,WAAW,OAAO;AACpB,QAAI,MAAM,WAAY,QAAM;AAC5B;;AAKF,OAAI,MAAM,gBAAiB,QAAM;;EAGnC,SAAS,cAAc,OAA4B;AACjD,OAAI,MAAM,QAAQ,SAAU,aAAY,QAAQ;;EAGlD,SAAS,uBAA6B;AACpC,eAAY,QAAQ;;EAMtB,IAAI,oBAAmC;EAEvC,SAAS,iBAAuB;AAC9B,OAAI,CAAC,SAAU;AACf,OAAI,sBAAsB,KAAM;AAChC,uBAAoB,SAAS,KAAK,MAAM;AACxC,YAAS,KAAK,MAAM,WAAW;;EAGjC,SAAS,mBAAyB;AAChC,OAAI,CAAC,SAAU;AACf,OAAI,sBAAsB,KAAM;AAChC,YAAS,KAAK,MAAM,WAAW;AAC/B,uBAAoB;;AAGtB,cACQ,MAAM,aACX,UAAU;AACT,OAAI,MAAO,iBAAe;OACrB,mBAAiB;KAExB,EAAE,WAAW,MAAM,CACrB;AAEA,kBAAgB,iBAAgB;;uBAK9B,YAsDW,UAAA;IAtDD,IAAG;IAAQ,UAAQ,CAAG;OAC9B,YAoDiB,MAAA,GAAA,EAAA;IApDA,MAAM,QAAA;IAAY,IAAG;;2BAmD3B,CAlDT,YAkDS,MAAA,GAAA,EAAA;KAjDP,IAAG;KACF,OAAK,eAAE,MAAA,KAAS,CAAA;KAChB,SAAO;uBACU;;4BA6CZ,CA3CN,mBA2CM,OAAA,EA3CA,OAAK,eAAE,MAAA,MAAK,CAAA,EAAA,EAAA,CAChB,mBAyCM,OAAA,EAzCA,OAAK,eAAE,MAAA,OAAM,CAAA,EAAA,EAAA,CACjB,YAekB,MAAA,GAAA,EAAA;MAdhB,IAAG;MACF,OAAO,MAAA,kBAAiB,CAAC;MACzB,cAAY,MAAA,kBAAiB,CAAC;MAC9B,YAAU,MAAA,kBAAiB,CAAC;MAC5B,OAAO,MAAA,kBAAiB,CAAC;MACzB,cAAY,MAAA,kBAAiB,CAAC;MAC9B,YAAU,MAAA,kBAAiB,CAAC;;6BAO3B,CALF,mBAKE,OAAA;OAJA,yBAAA;OACC,OAAK,eAAE,MAAA,QAAY,CAAA;OACpB,eAAY;OACX,eAAa;;;;;;;;;;SAIlB,YAsBkB,MAAA,GAAA,EAAA;MArBhB,IAAG;MACF,OAAO,MAAA,gBAAe,CAAC;MACvB,cAAY,MAAA,gBAAe,CAAC;MAC5B,YAAU,MAAA,gBAAe,CAAC;MAC1B,OAAO,MAAA,gBAAe,CAAC;MACvB,cAAY,MAAA,gBAAe,CAAC;MAC5B,YAAU,MAAA,gBAAe,CAAC;;6BAcb,CAZd,YAYc,MAAA,GAAA,EAAA;OAXZ,uBAAA;OACA,UAAS;OACR,OAAK,eAAE,WAAA,MAAU;;8BAIJ;QAFKA,KAAAA,OAAO,SAAA,WAAA,EAA1B,YAEc,MAAA,GAAA,EAAA;;SAFmB,IAAG;SAAM,uBAAA;;gCACnB,CAArB,WAAqB,KAAA,QAAA,QAAA,CAAA,CAAA;;;QAEEA,KAAAA,OAAO,eAAA,WAAA,EAAhC,YAEoB,MAAA,GAAA,EAAA;;SAFyB,IAAG;SAAM,6BAAA;;gCACzB,CAA3B,WAA2B,KAAA,QAAA,cAAA,CAAA,CAAA;;;QAE7B,WAAQ,KAAA,QAAA,UAAA"}