@feugene/granularity 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{adapter-K6zZTzBi.js.map → adapter-CRyH4YC8.js.map} +1 -1
- package/dist/chunks/{config-Cgk5ti-b.js.map → config-3SftO0uG.js.map} +1 -1
- package/dist/chunks/{config-BN-B2K4r.js.map → config-B44QVIge.js.map} +1 -1
- package/dist/chunks/{config-C-GVBa19.js.map → config-B8rC_K97.js.map} +1 -1
- package/dist/chunks/{config-DEv4m-ZP.js.map → config-BXffa3ta.js.map} +1 -1
- package/dist/chunks/{config-CUgvsjZx.js.map → config-BhvNm4Pp.js.map} +1 -1
- package/dist/chunks/{config-BNOf_qjD.js.map → config-C0b_3LJV.js.map} +1 -1
- package/dist/chunks/config-C0rHS1-l.js.map +1 -0
- package/dist/chunks/{config-fCcRwjIB.js.map → config-C4qAA0Sb.js.map} +1 -1
- package/dist/chunks/{config-XwI6t8cn.js.map → config-C5TN9J2Z.js.map} +1 -1
- package/dist/chunks/config-CVnluhKO.js.map +1 -0
- package/dist/chunks/{config-DUtUkSzc.js.map → config-CjEplP6D.js.map} +1 -1
- package/dist/chunks/{config-D19pyP4D.js.map → config-CtomKf-k.js.map} +1 -1
- package/dist/chunks/{config-BvuQUBtZ.js.map → config-CxCAfXZ1.js.map} +1 -1
- package/dist/chunks/{config-BDiLiqSk.js.map → config-D1DI3roo.js.map} +1 -1
- package/dist/chunks/{config-CgjOJ3aF.js.map → config-D27BL0H9.js.map} +1 -1
- package/dist/chunks/config-D32znLtV2.js.map +1 -0
- package/dist/chunks/{config-YSOeh6cy.js.map → config-D6Af6WZw.js.map} +1 -1
- package/dist/chunks/{config-BulF0Bf-.js.map → config-D98m8iyz.js.map} +1 -1
- package/dist/chunks/config-DDLoUczC.js.map +1 -0
- package/dist/chunks/{config-CFcv0hjb.js.map → config-DQOSlWvp.js.map} +1 -1
- package/dist/chunks/{config-ndXqsz5A.js.map → config-DbqFk-IW.js.map} +1 -1
- package/dist/chunks/{config-CdHY0Z7L.js.map → config-DnsISjD8.js.map} +1 -1
- package/dist/chunks/{config-BFZN9-vt.js.map → config-DudL02ag.js.map} +1 -1
- package/dist/chunks/{config-DgRJlF00.js.map → config-Dusr9jcE.js.map} +1 -1
- package/dist/chunks/{config-CWvHiaqr2.js.map → config-DxqMXzNV2.js.map} +1 -1
- package/dist/chunks/config-Mp9DJ9Mq2.js.map +1 -0
- package/dist/chunks/{config-R0jaXatX.js → config-XoANT5mU.js} +1 -1
- package/dist/chunks/{config-R0jaXatX.js.map → config-XoANT5mU.js.map} +1 -1
- package/dist/chunks/config-ZJVOVgqR.js +22 -0
- package/dist/chunks/config-ZJVOVgqR.js.map +1 -0
- package/dist/chunks/{config-CM7nbATU2.js.map → config-rxFL-6yF2.js.map} +1 -1
- package/dist/chunks/{config-bpQYM5O-.js.map → config-wo-ncgTH.js.map} +1 -1
- package/dist/chunks/{en-BeJa78lP.js → en-QNZhjmSJ.js} +18 -1
- package/dist/chunks/en-QNZhjmSJ.js.map +1 -0
- package/dist/chunks/{es-axYOwwWD.js → es-C1c5XsIK.js} +18 -1
- package/dist/chunks/es-C1c5XsIK.js.map +1 -0
- package/dist/chunks/{es-BPqm7rLm.js → es-CKLPuE0h.js} +3 -3
- package/dist/chunks/{es-BPqm7rLm.js.map → es-CKLPuE0h.js.map} +1 -1
- package/dist/chunks/{grSelectStyles-daEeDlBn.js.map → grSelectStyles-DTAYNzxn.js.map} +1 -1
- package/dist/chunks/grStyle-5EMYYctb.js +19 -0
- package/dist/chunks/grStyle-5EMYYctb.js.map +1 -0
- package/dist/chunks/granularityI18n-CXa_uN7f.js +46 -0
- package/dist/chunks/granularityI18n-CXa_uN7f.js.map +1 -0
- package/dist/chunks/{ru-Dqh-2C00.js → ru-DcF7ciz0.js} +18 -1
- package/dist/chunks/ru-DcF7ciz0.js.map +1 -0
- package/dist/chunks/{shared-CyCPkimZ.js → shared-BkIIEolF.js} +37 -30
- package/dist/chunks/shared-BkIIEolF.js.map +1 -0
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-u01j9S0t.js → GrFileUpload-DYRERhI2.js} +258 -37
- package/dist/components/GrFileUpload/chunks/GrFileUpload-DYRERhI2.js.map +1 -0
- package/dist/components/GrFileUpload/index.js +3 -3
- package/dist/components/GrFormField/chunks/{GrFormField-C6PfAs4u.js.map → GrFormField-C1oWTT_0.js.map} +1 -1
- package/dist/components/GrFormField/index.js +2 -2
- package/dist/components/GrFormFile/chunks/{GrFormFile-DdM8Bc2B.js.map → GrFormFile-deDPicM2.js.map} +1 -1
- package/dist/components/GrFormFile/index.js +2 -2
- package/dist/components/GrFormSection/chunks/{GrFormSection-5djEaQZQ.js.map → GrFormSection-CWBk2EUm.js.map} +1 -1
- package/dist/components/GrFormSection/index.js +2 -2
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-CjSnohW7.js.map → GrImageViewer-Cpj5zyZQ.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +2 -2
- package/dist/components/GrInput/chunks/{GrInput-ghxaTf6d.js.map → GrInput-CfO2RsM-.js.map} +1 -1
- package/dist/components/GrInput/index.js +2 -2
- package/dist/components/GrInputTag/chunks/{GrInputTag-B0x4U0Yk.js → GrInputTag-G_VYJPF9.js} +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-B0x4U0Yk.js.map → GrInputTag-G_VYJPF9.js.map} +1 -1
- package/dist/components/GrInputTag/index.js +2 -2
- package/dist/components/GrLink/chunks/{GrLink-DvvNkP0M.js → GrLink-BLPigqij.js} +1 -1
- package/dist/components/GrLink/chunks/{GrLink-DvvNkP0M.js.map → GrLink-BLPigqij.js.map} +1 -1
- package/dist/components/GrLink/index.js +2 -2
- package/dist/components/GrList/chunks/{GrList--Ib4zLNw.js.map → GrList-BPjQf-72.js.map} +1 -1
- package/dist/components/GrList/index.js +2 -2
- package/dist/components/GrLoading/index.js +1 -1
- package/dist/components/GrModal/index.js +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-nIyuiVj1.js → GrNavbar-BoVuSZ-V.js} +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-nIyuiVj1.js.map → GrNavbar-BoVuSZ-V.js.map} +1 -1
- package/dist/components/GrNavbar/index.js +2 -2
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-B0mPLjdv.js → GrNumberInput-ECtFCIKV.js} +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-B0mPLjdv.js.map → GrNumberInput-ECtFCIKV.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-C_rxGwfY.js → GrPagination-DW44c2-a.js} +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-C_rxGwfY.js.map → GrPagination-DW44c2-a.js.map} +1 -1
- package/dist/components/GrPagination/index.js +2 -2
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-MvMnzsJl.js → GrProgressBar-hQQK8cYh.js} +1 -1
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-MvMnzsJl.js.map → GrProgressBar-hQQK8cYh.js.map} +1 -1
- package/dist/components/GrProgressBar/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-DKhbN6ji.js → GrPromptDialog-CUMW6_58.js} +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-DKhbN6ji.js.map → GrPromptDialog-CUMW6_58.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +2 -2
- package/dist/components/GrRadio/chunks/{GrRadio-BxBs3WHq.js → GrRadio-B_t_ZNVl.js} +1 -1
- package/dist/components/GrRadio/chunks/{GrRadio-BxBs3WHq.js.map → GrRadio-B_t_ZNVl.js.map} +1 -1
- package/dist/components/GrRadio/index.js +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CEAfJQ6A.js → GrRadioGroup-CVlgpUBr.js} +1 -1
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CEAfJQ6A.js.map → GrRadioGroup-CVlgpUBr.js.map} +1 -1
- package/dist/components/GrRadioGroup/index.js +2 -2
- package/dist/components/GrSegmented/chunks/{GrSegmented-Bwn2qOY4.js → GrSegmented-BPl1koHc.js} +1 -1
- package/dist/components/GrSegmented/chunks/{GrSegmented-Bwn2qOY4.js.map → GrSegmented-BPl1koHc.js.map} +1 -1
- package/dist/components/GrSegmented/index.js +2 -2
- package/dist/components/GrSelect/chunks/{GrSelect-BMMT5MrT.js → GrSelect-C3NAfTqL.js} +2 -2
- package/dist/components/GrSelect/chunks/{GrSelect-BMMT5MrT.js.map → GrSelect-C3NAfTqL.js.map} +1 -1
- package/dist/components/GrSelect/index.js +2 -2
- package/dist/components/GrSidebar/chunks/{GrSidebar-CSZ3RpFB.js.map → GrSidebar-DVucgcfV.js.map} +1 -1
- package/dist/components/GrSidebar/index.js +2 -2
- package/dist/components/GrSkeleton/chunks/{GrSkeleton-DKXkqWDa.js.map → GrSkeleton-CDTvCSoH.js.map} +1 -1
- package/dist/components/GrSkeleton/index.js +2 -2
- package/dist/components/GrSwitch/chunks/{GrSwitch-CdBxwV3k.js → GrSwitch-Bnamgqb2.js} +1 -1
- package/dist/components/GrSwitch/chunks/{GrSwitch-CdBxwV3k.js.map → GrSwitch-Bnamgqb2.js.map} +1 -1
- package/dist/components/GrSwitch/index.js +2 -2
- package/dist/components/GrTable/index.js +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-BpF8AAUz.js.map → GrTabs-CiGmcmvm.js.map} +1 -1
- package/dist/components/GrTabs/index.js +2 -2
- package/dist/components/GrTextarea/chunks/{GrTextarea-DFS9ZkrA.js → GrTextarea-VBSc6A7D.js} +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-DFS9ZkrA.js.map → GrTextarea-VBSc6A7D.js.map} +1 -1
- package/dist/components/GrTextarea/index.js +2 -2
- package/dist/components/GrToaster/chunks/{GrToaster-3Mf0Moxt.js → GrToaster-I1e-zCpf.js} +1 -1
- package/dist/components/GrToaster/chunks/{GrToaster-3Mf0Moxt.js.map → GrToaster-I1e-zCpf.js.map} +1 -1
- package/dist/components/GrToaster/index.js +2 -2
- package/dist/components/GrTooltip/chunks/{GrTooltip-BvmsukLW.js.map → GrTooltip-CrV1gI_c.js.map} +1 -1
- package/dist/components/GrTooltip/index.js +2 -2
- package/dist/components/GrTree/chunks/{GrTree-C2kN-O4Q.js.map → GrTree-Dlev9oBd.js.map} +1 -1
- package/dist/components/GrTree/index.js +2 -2
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-N-oPAOFj.js → GrTreeSelect-DkAIksRW.js} +4 -4
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-N-oPAOFj.js.map → GrTreeSelect-DkAIksRW.js.map} +1 -1
- package/dist/components/GrTreeSelect/index.js +2 -2
- package/dist/directives/loading.js +15 -0
- package/dist/directives/loading.js.map +1 -1
- package/dist/granular-provider-node.js +2 -2
- package/dist/granular-provider.js +1 -1
- package/dist/i18n/all.js +1 -1
- package/dist/i18n/index.js +2 -2
- package/dist/index.js +1032 -58
- package/dist/index.js.map +1 -1
- package/dist/types/src/components/GrFileUpload/GrFileUpload.vue.d.ts +58 -5
- package/dist/types/src/components/GrFileUpload/index.d.ts +4 -0
- package/dist/types/src/components/GrFileUpload/uploadState.d.ts +38 -0
- package/dist/types/src/components/GrFileUpload/uploadViaXhr.d.ts +33 -0
- package/dist/types/src/components/GrImageViewer/GrImageViewer.vue.d.ts +1 -1
- package/dist/types/src/components/GrInput/GrInput.vue.d.ts +1 -1
- package/dist/types/src/components/GrNumberInput/GrNumberInput.vue.d.ts +1 -1
- package/dist/types/src/components/GrResponseErrorBanner/GrFormErrorBanner.vue.d.ts +70 -0
- package/dist/types/src/components/GrResponseErrorBanner/GrResponseErrorBanner.vue.d.ts +96 -0
- package/dist/types/src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue.d.ts +73 -0
- package/dist/types/src/components/GrResponseErrorBanner/config.d.ts +1 -0
- package/dist/types/src/components/GrResponseErrorBanner/index.d.ts +10 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/abortErrorParser.d.ts +15 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/createResponseErrorClassifier.d.ts +28 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/fileValidationParser.d.ts +12 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/httpStatusParser.d.ts +15 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/index.d.ts +11 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/jsonApiErrorParser.d.ts +17 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/laravelValidationParser.d.ts +15 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/networkErrorParser.d.ts +14 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/normalizeError.d.ts +19 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/plainMessageParser.d.ts +15 -0
- package/dist/types/src/components/GrResponseErrorBanner/parsers/problemDetailsParser.d.ts +17 -0
- package/dist/types/src/components/GrResponseErrorBanner/responseError.defaults.d.ts +18 -0
- package/dist/types/src/components/GrResponseErrorBanner/responseError.types.d.ts +115 -0
- package/dist/types/src/components/GrResponseErrorBanner/useResponseError.d.ts +62 -0
- package/dist/types/src/components/GrTextarea/GrTextarea.vue.d.ts +1 -1
- package/dist/types/src/components/GrToaster/GrToaster.vue.d.ts +1 -1
- package/dist/types/src/granular-provider/shared.d.ts +1 -0
- package/dist/types/src/i18n/messages/en.d.ts +32 -0
- package/dist/types/src/i18n/messages/es.d.ts +32 -0
- package/dist/types/src/i18n/messages/ru.d.ts +32 -0
- package/dist/types/src/index.d.ts +1 -0
- package/package.json +1 -1
- package/dist/chunks/config-BGmiXpR82.js.map +0 -1
- package/dist/chunks/config-CA9XwYnZ2.js.map +0 -1
- package/dist/chunks/config-CsMIhZfM.js.map +0 -1
- package/dist/chunks/config-CwLoozAz2.js.map +0 -1
- package/dist/chunks/config-DCQO6H6h.js.map +0 -1
- package/dist/chunks/config-Da90XGsi.js +0 -38
- package/dist/chunks/config-Da90XGsi.js.map +0 -1
- package/dist/chunks/en-BeJa78lP.js.map +0 -1
- package/dist/chunks/es-axYOwwWD.js.map +0 -1
- package/dist/chunks/granularityI18n-GCqUz_lo.js +0 -26
- package/dist/chunks/granularityI18n-GCqUz_lo.js.map +0 -1
- package/dist/chunks/ru-Dqh-2C00.js.map +0 -1
- package/dist/chunks/shared-CyCPkimZ.js.map +0 -1
- package/dist/components/GrFileUpload/chunks/GrFileUpload-u01j9S0t.js.map +0 -1
- /package/dist/chunks/{adapter-K6zZTzBi.js → adapter-CRyH4YC8.js} +0 -0
- /package/dist/chunks/{config-Cgk5ti-b.js → config-3SftO0uG.js} +0 -0
- /package/dist/chunks/{config-BN-B2K4r.js → config-B44QVIge.js} +0 -0
- /package/dist/chunks/{config-C-GVBa19.js → config-B8rC_K97.js} +0 -0
- /package/dist/chunks/{config-DEv4m-ZP.js → config-BXffa3ta.js} +0 -0
- /package/dist/chunks/{config-CUgvsjZx.js → config-BhvNm4Pp.js} +0 -0
- /package/dist/chunks/{config-BNOf_qjD.js → config-C0b_3LJV.js} +0 -0
- /package/dist/chunks/{config-CA9XwYnZ2.js → config-C0rHS1-l.js} +0 -0
- /package/dist/chunks/{config-fCcRwjIB.js → config-C4qAA0Sb.js} +0 -0
- /package/dist/chunks/{config-XwI6t8cn.js → config-C5TN9J2Z.js} +0 -0
- /package/dist/chunks/{config-BGmiXpR82.js → config-CVnluhKO.js} +0 -0
- /package/dist/chunks/{config-DUtUkSzc.js → config-CjEplP6D.js} +0 -0
- /package/dist/chunks/{config-D19pyP4D.js → config-CtomKf-k.js} +0 -0
- /package/dist/chunks/{config-BvuQUBtZ.js → config-CxCAfXZ1.js} +0 -0
- /package/dist/chunks/{config-BDiLiqSk.js → config-D1DI3roo.js} +0 -0
- /package/dist/chunks/{config-CgjOJ3aF.js → config-D27BL0H9.js} +0 -0
- /package/dist/chunks/{config-DCQO6H6h.js → config-D32znLtV2.js} +0 -0
- /package/dist/chunks/{config-YSOeh6cy.js → config-D6Af6WZw.js} +0 -0
- /package/dist/chunks/{config-BulF0Bf-.js → config-D98m8iyz.js} +0 -0
- /package/dist/chunks/{config-CwLoozAz2.js → config-DDLoUczC.js} +0 -0
- /package/dist/chunks/{config-CFcv0hjb.js → config-DQOSlWvp.js} +0 -0
- /package/dist/chunks/{config-ndXqsz5A.js → config-DbqFk-IW.js} +0 -0
- /package/dist/chunks/{config-CdHY0Z7L.js → config-DnsISjD8.js} +0 -0
- /package/dist/chunks/{config-BFZN9-vt.js → config-DudL02ag.js} +0 -0
- /package/dist/chunks/{config-DgRJlF00.js → config-Dusr9jcE.js} +0 -0
- /package/dist/chunks/{config-CWvHiaqr2.js → config-DxqMXzNV2.js} +0 -0
- /package/dist/chunks/{config-CsMIhZfM.js → config-Mp9DJ9Mq2.js} +0 -0
- /package/dist/chunks/{config-CM7nbATU2.js → config-rxFL-6yF2.js} +0 -0
- /package/dist/chunks/{config-bpQYM5O-.js → config-wo-ncgTH.js} +0 -0
- /package/dist/chunks/{grSelectStyles-daEeDlBn.js → grSelectStyles-DTAYNzxn.js} +0 -0
- /package/dist/components/GrFormField/chunks/{GrFormField-C6PfAs4u.js → GrFormField-C1oWTT_0.js} +0 -0
- /package/dist/components/GrFormFile/chunks/{GrFormFile-DdM8Bc2B.js → GrFormFile-deDPicM2.js} +0 -0
- /package/dist/components/GrFormSection/chunks/{GrFormSection-5djEaQZQ.js → GrFormSection-CWBk2EUm.js} +0 -0
- /package/dist/components/GrImageViewer/chunks/{GrImageViewer-CjSnohW7.js → GrImageViewer-Cpj5zyZQ.js} +0 -0
- /package/dist/components/GrInput/chunks/{GrInput-ghxaTf6d.js → GrInput-CfO2RsM-.js} +0 -0
- /package/dist/components/GrList/chunks/{GrList--Ib4zLNw.js → GrList-BPjQf-72.js} +0 -0
- /package/dist/components/GrSidebar/chunks/{GrSidebar-CSZ3RpFB.js → GrSidebar-DVucgcfV.js} +0 -0
- /package/dist/components/GrSkeleton/chunks/{GrSkeleton-DKXkqWDa.js → GrSkeleton-CDTvCSoH.js} +0 -0
- /package/dist/components/GrTabs/chunks/{GrTabs-BpF8AAUz.js → GrTabs-CiGmcmvm.js} +0 -0
- /package/dist/components/GrTooltip/chunks/{GrTooltip-BvmsukLW.js → GrTooltip-CrV1gI_c.js} +0 -0
- /package/dist/components/GrTree/chunks/{GrTree-C2kN-O4Q.js → GrTree-Dlev9oBd.js} +0 -0
package/dist/components/GrFileUpload/chunks/{GrFileUpload-u01j9S0t.js → GrFileUpload-DYRERhI2.js}
RENAMED
|
@@ -1,7 +1,116 @@
|
|
|
1
1
|
import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-BV7RBU_0.js";
|
|
2
2
|
import { t as arrow_up_default } from "../../../chunks/arrow-up-DNXrMoAI.js";
|
|
3
3
|
import { l as runFileValidators, u as FileValidationError } from "../../../chunks/fileValidation-CwJA8Vmn.js";
|
|
4
|
-
import {
|
|
4
|
+
import { t as GrProgressBar_default } from "../../GrProgressBar/chunks/GrProgressBar-hQQK8cYh.js";
|
|
5
|
+
import { Comment, Fragment, Text, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, openBlock, reactive, ref, renderList, renderSlot, toDisplayString, unref, useSlots, withCtx } from "vue";
|
|
6
|
+
//#region src/components/GrFileUpload/uploadViaXhr.ts
|
|
7
|
+
var GrUploadAbortError = class extends Error {
|
|
8
|
+
constructor(message = "Upload aborted") {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "GrUploadAbortError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var GrUploadHttpError = class extends Error {
|
|
14
|
+
status;
|
|
15
|
+
payload;
|
|
16
|
+
constructor(status, payload) {
|
|
17
|
+
super(`Upload failed with status ${status}`);
|
|
18
|
+
this.name = "GrUploadHttpError";
|
|
19
|
+
this.status = status;
|
|
20
|
+
this.payload = payload;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
function appendExtraFormData(body, extraData) {
|
|
24
|
+
if (!extraData) return;
|
|
25
|
+
for (const [key, value] of Object.entries(extraData)) {
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
for (const entry of value) body.append(key, entry);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
body.append(key, value);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function parseResponse(xhr) {
|
|
34
|
+
const contentType = xhr.getResponseHeader("content-type") ?? "";
|
|
35
|
+
const raw = xhr.responseText;
|
|
36
|
+
if (contentType.includes("application/json")) try {
|
|
37
|
+
return JSON.parse(raw);
|
|
38
|
+
} catch {
|
|
39
|
+
return raw;
|
|
40
|
+
}
|
|
41
|
+
return raw;
|
|
42
|
+
}
|
|
43
|
+
function uploadViaXhr(options) {
|
|
44
|
+
const { url, files, name, headers, withCredentials, extraData, signal, onProgress } = options;
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
if (signal.aborted) {
|
|
47
|
+
reject(new GrUploadAbortError());
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const body = new FormData();
|
|
51
|
+
for (const file of files) body.append(name, file);
|
|
52
|
+
appendExtraFormData(body, extraData);
|
|
53
|
+
const xhr = new XMLHttpRequest();
|
|
54
|
+
xhr.open("POST", url, true);
|
|
55
|
+
xhr.withCredentials = !!withCredentials;
|
|
56
|
+
if (headers) for (const [key, value] of Object.entries(headers)) xhr.setRequestHeader(key, value);
|
|
57
|
+
const onAbort = () => {
|
|
58
|
+
try {
|
|
59
|
+
xhr.abort();
|
|
60
|
+
} catch {}
|
|
61
|
+
};
|
|
62
|
+
signal.addEventListener("abort", onAbort);
|
|
63
|
+
const cleanup = () => {
|
|
64
|
+
signal.removeEventListener("abort", onAbort);
|
|
65
|
+
};
|
|
66
|
+
if (onProgress) xhr.upload.addEventListener("progress", (event) => {
|
|
67
|
+
const indeterminate = !event.lengthComputable;
|
|
68
|
+
const total = indeterminate ? 0 : event.total;
|
|
69
|
+
const loaded = indeterminate ? 0 : event.loaded;
|
|
70
|
+
onProgress({
|
|
71
|
+
percent: indeterminate || total === 0 ? 0 : Math.min(100, loaded / total * 100),
|
|
72
|
+
loaded,
|
|
73
|
+
total,
|
|
74
|
+
indeterminate
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
xhr.addEventListener("load", () => {
|
|
78
|
+
cleanup();
|
|
79
|
+
const payload = parseResponse(xhr);
|
|
80
|
+
const status = xhr.status;
|
|
81
|
+
if (status >= 200 && status < 300) {
|
|
82
|
+
if (onProgress) onProgress({
|
|
83
|
+
percent: 100,
|
|
84
|
+
loaded: 1,
|
|
85
|
+
total: 1,
|
|
86
|
+
indeterminate: false
|
|
87
|
+
});
|
|
88
|
+
resolve(payload);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
reject(new GrUploadHttpError(status, payload));
|
|
92
|
+
});
|
|
93
|
+
xhr.addEventListener("error", () => {
|
|
94
|
+
cleanup();
|
|
95
|
+
reject(/* @__PURE__ */ new Error("Network error during upload"));
|
|
96
|
+
});
|
|
97
|
+
xhr.addEventListener("abort", () => {
|
|
98
|
+
cleanup();
|
|
99
|
+
reject(new GrUploadAbortError());
|
|
100
|
+
});
|
|
101
|
+
xhr.send(body);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
//#region src/components/GrFileUpload/uploadState.ts
|
|
106
|
+
var GR_UPLOAD_STATE_IDLE = Object.freeze({
|
|
107
|
+
phase: "idle",
|
|
108
|
+
percent: 0,
|
|
109
|
+
indeterminate: false,
|
|
110
|
+
loaded: 0,
|
|
111
|
+
total: 0
|
|
112
|
+
});
|
|
113
|
+
//#endregion
|
|
5
114
|
//#region src/components/GrFileUpload/GrFileUpload.vue?vue&type=script&setup=true&lang.ts
|
|
6
115
|
var _hoisted_1 = [
|
|
7
116
|
"role",
|
|
@@ -43,6 +152,12 @@ var _hoisted_9 = {
|
|
|
43
152
|
};
|
|
44
153
|
var _hoisted_10 = { class: "font-600" };
|
|
45
154
|
var _hoisted_11 = { class: "text-[var(--muted-fg)]" };
|
|
155
|
+
var _hoisted_12 = ["aria-hidden"];
|
|
156
|
+
var _hoisted_13 = { class: "flex items-center gap-2" };
|
|
157
|
+
var _hoisted_14 = {
|
|
158
|
+
"data-ds-file-upload-progress-text": "",
|
|
159
|
+
class: "text-[12px] text-[var(--muted-fg)] tabular-nums min-w-[3ch] text-right"
|
|
160
|
+
};
|
|
46
161
|
//#endregion
|
|
47
162
|
//#region src/components/GrFileUpload/GrFileUpload.vue
|
|
48
163
|
var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
@@ -85,13 +200,21 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
85
200
|
type: Function,
|
|
86
201
|
default: void 0
|
|
87
202
|
},
|
|
88
|
-
placeholder: { default: "Drag files here or click to select" }
|
|
203
|
+
placeholder: { default: "Drag files here or click to select" },
|
|
204
|
+
showProgress: {
|
|
205
|
+
type: Boolean,
|
|
206
|
+
default: true
|
|
207
|
+
},
|
|
208
|
+
progressTone: { default: "primary" },
|
|
209
|
+
progressLabel: { default: "Upload progress" },
|
|
210
|
+
hideProgressOnSuccess: { default: 800 }
|
|
89
211
|
},
|
|
90
212
|
emits: [
|
|
91
213
|
"success",
|
|
92
214
|
"error",
|
|
93
215
|
"progress",
|
|
94
|
-
"change"
|
|
216
|
+
"change",
|
|
217
|
+
"state-change"
|
|
95
218
|
],
|
|
96
219
|
setup(__props, { expose: __expose, emit: __emit }) {
|
|
97
220
|
const props = __props;
|
|
@@ -128,7 +251,63 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
128
251
|
const isOver = ref(false);
|
|
129
252
|
let overCounter = 0;
|
|
130
253
|
const lastFiles = ref([]);
|
|
254
|
+
const state = reactive({ ...GR_UPLOAD_STATE_IDLE });
|
|
131
255
|
let activeController = null;
|
|
256
|
+
let hideSuccessTimer = null;
|
|
257
|
+
function clearHideSuccessTimer() {
|
|
258
|
+
if (hideSuccessTimer !== null) {
|
|
259
|
+
clearTimeout(hideSuccessTimer);
|
|
260
|
+
hideSuccessTimer = null;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function assignState(next) {
|
|
264
|
+
for (const key of Object.keys(state)) delete state[key];
|
|
265
|
+
Object.assign(state, next);
|
|
266
|
+
emit("state-change", state);
|
|
267
|
+
}
|
|
268
|
+
function setStateIdle() {
|
|
269
|
+
assignState({ ...GR_UPLOAD_STATE_IDLE });
|
|
270
|
+
}
|
|
271
|
+
function setStateUploading(info) {
|
|
272
|
+
assignState({
|
|
273
|
+
phase: "uploading",
|
|
274
|
+
percent: info?.percent ?? 0,
|
|
275
|
+
indeterminate: info?.indeterminate ?? true,
|
|
276
|
+
loaded: info?.loaded ?? 0,
|
|
277
|
+
total: info?.total ?? 0
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function setStateSuccess(info) {
|
|
281
|
+
assignState({
|
|
282
|
+
phase: "success",
|
|
283
|
+
percent: 100,
|
|
284
|
+
indeterminate: false,
|
|
285
|
+
loaded: info.loaded,
|
|
286
|
+
total: info.total
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
function setStateError(error) {
|
|
290
|
+
const prev = state;
|
|
291
|
+
assignState({
|
|
292
|
+
phase: "error",
|
|
293
|
+
percent: prev.phase === "uploading" ? prev.percent : 0,
|
|
294
|
+
indeterminate: false,
|
|
295
|
+
loaded: prev.phase === "uploading" ? prev.loaded : 0,
|
|
296
|
+
total: prev.phase === "uploading" ? prev.total : 0,
|
|
297
|
+
error
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
function handleProgress(info) {
|
|
301
|
+
if (state.phase !== "uploading") return;
|
|
302
|
+
assignState({
|
|
303
|
+
phase: "uploading",
|
|
304
|
+
percent: info.percent,
|
|
305
|
+
indeterminate: info.indeterminate,
|
|
306
|
+
loaded: info.loaded,
|
|
307
|
+
total: info.total
|
|
308
|
+
});
|
|
309
|
+
emit("progress", info.percent, info);
|
|
310
|
+
}
|
|
132
311
|
const tabIndex = computed(() => props.disabled ? -1 : 0);
|
|
133
312
|
const hiddenInputStyle = {
|
|
134
313
|
position: "fixed",
|
|
@@ -158,36 +337,18 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
158
337
|
if (limit <= 0) return void 0;
|
|
159
338
|
return Math.floor(limit);
|
|
160
339
|
}
|
|
161
|
-
function appendExtraFormData(body, extraData) {
|
|
162
|
-
if (!extraData) return;
|
|
163
|
-
for (const [key, value] of Object.entries(extraData)) {
|
|
164
|
-
if (Array.isArray(value)) {
|
|
165
|
-
for (const entry of value) body.append(key, entry);
|
|
166
|
-
continue;
|
|
167
|
-
}
|
|
168
|
-
body.append(key, value);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
340
|
async function uploadViaAction(files, signal, extraData) {
|
|
172
341
|
if (!props.action) throw new Error("GrFileUpload: either `action` or `request` must be provided");
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
method: "POST",
|
|
342
|
+
return uploadViaXhr({
|
|
343
|
+
url: props.action,
|
|
344
|
+
files,
|
|
345
|
+
name: props.name,
|
|
178
346
|
headers: props.headers,
|
|
179
|
-
|
|
347
|
+
withCredentials: props.withCredentials,
|
|
348
|
+
extraData,
|
|
180
349
|
signal,
|
|
181
|
-
|
|
350
|
+
onProgress: handleProgress
|
|
182
351
|
});
|
|
183
|
-
const payload = response.headers.get("content-type")?.includes("application/json") ? await response.json() : await response.text();
|
|
184
|
-
if (!response.ok) {
|
|
185
|
-
const error = /* @__PURE__ */ new Error(`Upload failed with status ${response.status}`);
|
|
186
|
-
error.payload = payload;
|
|
187
|
-
error.status = response.status;
|
|
188
|
-
throw error;
|
|
189
|
-
}
|
|
190
|
-
return payload;
|
|
191
352
|
}
|
|
192
353
|
async function runBeforeUpload(files) {
|
|
193
354
|
if (!props.beforeUpload) return "ok";
|
|
@@ -238,17 +399,42 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
238
399
|
return;
|
|
239
400
|
}
|
|
240
401
|
abort();
|
|
402
|
+
clearHideSuccessTimer();
|
|
241
403
|
const controller = new AbortController();
|
|
242
404
|
activeController = controller;
|
|
243
|
-
|
|
405
|
+
setStateUploading();
|
|
406
|
+
emit("progress", 0, {
|
|
407
|
+
percent: 0,
|
|
408
|
+
loaded: 0,
|
|
409
|
+
total: 0,
|
|
410
|
+
indeterminate: true
|
|
411
|
+
});
|
|
244
412
|
try {
|
|
245
|
-
|
|
413
|
+
const payload = props.request ? await props.request(valid, {
|
|
246
414
|
signal: controller.signal,
|
|
247
|
-
extraData
|
|
248
|
-
|
|
415
|
+
extraData,
|
|
416
|
+
onProgress: handleProgress
|
|
417
|
+
}) : await uploadViaAction(valid, controller.signal, extraData);
|
|
418
|
+
const finalLoaded = state.phase === "uploading" ? state.total || state.loaded : 0;
|
|
419
|
+
setStateSuccess({
|
|
420
|
+
loaded: finalLoaded,
|
|
421
|
+
total: finalLoaded
|
|
422
|
+
});
|
|
423
|
+
emit("success", payload);
|
|
249
424
|
emit("change", valid);
|
|
250
|
-
emit("progress", 100
|
|
425
|
+
emit("progress", 100, {
|
|
426
|
+
percent: 100,
|
|
427
|
+
loaded: finalLoaded,
|
|
428
|
+
total: finalLoaded,
|
|
429
|
+
indeterminate: false
|
|
430
|
+
});
|
|
431
|
+
if (props.hideProgressOnSuccess && props.hideProgressOnSuccess > 0) hideSuccessTimer = setTimeout(() => {
|
|
432
|
+
if (state.phase === "success") setStateIdle();
|
|
433
|
+
hideSuccessTimer = null;
|
|
434
|
+
}, props.hideProgressOnSuccess);
|
|
251
435
|
} catch (error) {
|
|
436
|
+
if (error instanceof GrUploadAbortError) setStateIdle();
|
|
437
|
+
else setStateError(error);
|
|
252
438
|
emit("error", error);
|
|
253
439
|
} finally {
|
|
254
440
|
if (activeController === controller) activeController = null;
|
|
@@ -306,10 +492,22 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
306
492
|
if (hasCustomUi.value) return;
|
|
307
493
|
onKeydown(event);
|
|
308
494
|
}
|
|
495
|
+
const effectiveProgressTone = computed(() => {
|
|
496
|
+
if (state.phase === "error") return "danger";
|
|
497
|
+
if (state.phase === "success") return "success";
|
|
498
|
+
return props.progressTone;
|
|
499
|
+
});
|
|
500
|
+
const progressVisible = computed(() => state.phase !== "idle");
|
|
501
|
+
const progressPercent = computed(() => state.phase === "uploading" && state.indeterminate ? 0 : state.percent);
|
|
502
|
+
const progressText = computed(() => {
|
|
503
|
+
if (state.phase === "uploading" && state.indeterminate) return "";
|
|
504
|
+
return `${Math.round(progressPercent.value)}%`;
|
|
505
|
+
});
|
|
309
506
|
__expose({
|
|
310
507
|
uploadFiles: handleFiles,
|
|
311
508
|
abort,
|
|
312
|
-
openDialog
|
|
509
|
+
openDialog,
|
|
510
|
+
state
|
|
313
511
|
});
|
|
314
512
|
return (_ctx, _cache) => {
|
|
315
513
|
return openBlock(), createElementBlock("div", {
|
|
@@ -346,7 +544,8 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
346
544
|
abort,
|
|
347
545
|
disabled: __props.disabled,
|
|
348
546
|
files: lastFiles.value,
|
|
349
|
-
isOver: isOver.value
|
|
547
|
+
isOver: isOver.value,
|
|
548
|
+
state
|
|
350
549
|
}) : (openBlock(), createElementBlock("div", _hoisted_3, [createElementVNode("div", _hoisted_4, [createVNode(GrIcon_default, { class: "h-6 w-6 text-[var(--muted-fg)]" }, {
|
|
351
550
|
default: withCtx(() => [createVNode(unref(arrow_up_default))]),
|
|
352
551
|
_: 1
|
|
@@ -359,10 +558,32 @@ var GrFileUpload_default = /* @__PURE__ */ defineComponent({
|
|
|
359
558
|
"data-ds-file-upload-item": "",
|
|
360
559
|
class: "text-[13px]"
|
|
361
560
|
}, [createElementVNode("span", _hoisted_10, toDisplayString(file.name), 1), createElementVNode("span", _hoisted_11, " · " + toDisplayString(Math.ceil(file.size / 1024)) + " KB", 1)]);
|
|
362
|
-
}), 128))])) : createCommentVNode("", true)
|
|
561
|
+
}), 128))])) : createCommentVNode("", true),
|
|
562
|
+
__props.showProgress || _ctx.$slots.progress ? renderSlot(_ctx.$slots, "progress", {
|
|
563
|
+
key: 3,
|
|
564
|
+
state,
|
|
565
|
+
percent: state.percent,
|
|
566
|
+
indeterminate: state.phase === "uploading" && state.indeterminate,
|
|
567
|
+
phase: state.phase,
|
|
568
|
+
files: lastFiles.value,
|
|
569
|
+
abort
|
|
570
|
+
}, () => [__props.showProgress ? (openBlock(), createElementBlock("div", {
|
|
571
|
+
key: 0,
|
|
572
|
+
"data-ds-file-upload-progress": "",
|
|
573
|
+
class: normalizeClass(["mt-3 transition-opacity duration-150", progressVisible.value ? "opacity-100" : "opacity-0 pointer-events-none"]),
|
|
574
|
+
"aria-hidden": !progressVisible.value
|
|
575
|
+
}, [createElementVNode("div", _hoisted_13, [createVNode(GrProgressBar_default, {
|
|
576
|
+
value: progressPercent.value,
|
|
577
|
+
tone: effectiveProgressTone.value,
|
|
578
|
+
"aria-label": __props.progressLabel
|
|
579
|
+
}, null, 8, [
|
|
580
|
+
"value",
|
|
581
|
+
"tone",
|
|
582
|
+
"aria-label"
|
|
583
|
+
]), createElementVNode("span", _hoisted_14, toDisplayString(progressText.value), 1)])], 10, _hoisted_12)) : createCommentVNode("", true)]) : createCommentVNode("", true)
|
|
363
584
|
])]))], 42, _hoisted_1);
|
|
364
585
|
};
|
|
365
586
|
}
|
|
366
587
|
});
|
|
367
588
|
//#endregion
|
|
368
|
-
export { GrFileUpload_default as t };
|
|
589
|
+
export { GrUploadHttpError as i, GR_UPLOAD_STATE_IDLE as n, GrUploadAbortError as r, GrFileUpload_default as t };
|
|
@@ -0,0 +1 @@
|
|
|
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,4 +1,4 @@
|
|
|
1
1
|
import { a as allowedExtensionsValidator, c as normalizeFiles, i as allowedMimeTypesValidator, l as runFileValidators, n as maxSizeMbValidator, o as acceptValidator, r as maxFileSizeBytesValidator, s as matchAccept, t as maxTotalSizeBytesValidator, u as FileValidationError } from "../../chunks/fileValidation-CwJA8Vmn.js";
|
|
2
|
-
import { t as GrFileUpload_default } from "./chunks/GrFileUpload-
|
|
3
|
-
import { t as grFileUploadConfig } from "../../chunks/config-
|
|
4
|
-
export { FileValidationError, GrFileUpload_default as GrFileUpload, GrFileUpload_default as default, acceptValidator, allowedExtensionsValidator, allowedMimeTypesValidator, grFileUploadConfig, matchAccept, maxFileSizeBytesValidator, maxSizeMbValidator, maxTotalSizeBytesValidator, normalizeFiles, runFileValidators };
|
|
2
|
+
import { i as GrUploadHttpError, n as GR_UPLOAD_STATE_IDLE, r as GrUploadAbortError, t as GrFileUpload_default } from "./chunks/GrFileUpload-DYRERhI2.js";
|
|
3
|
+
import { t as grFileUploadConfig } from "../../chunks/config-CVnluhKO.js";
|
|
4
|
+
export { FileValidationError, GR_UPLOAD_STATE_IDLE, GrFileUpload_default as GrFileUpload, GrFileUpload_default as default, GrUploadAbortError, GrUploadHttpError, acceptValidator, allowedExtensionsValidator, allowedMimeTypesValidator, grFileUploadConfig, matchAccept, maxFileSizeBytesValidator, maxSizeMbValidator, maxTotalSizeBytesValidator, normalizeFiles, runFileValidators };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrFormField-
|
|
1
|
+
{"version":3,"file":"GrFormField-C1oWTT_0.js","names":[],"sources":["../../../../src/components/GrFormField/GrFormField.vue","../../../../src/components/GrFormField/GrFormField.vue"],"sourcesContent":["<script setup lang=\"ts\">\ntype LabelClass = string | string[] | Record<string, boolean>\n\nconst props = withDefaults(\n defineProps<{\n label?: string\n forId?: string\n error?: string\n labelClass?: LabelClass\n }>(),\n {\n label: undefined,\n forId: undefined,\n error: undefined,\n labelClass: undefined,\n },\n)\n</script>\n\n<template>\n <div class=\"flex flex-col gap-2\">\n <label\n v-if=\"props.label\"\n :for=\"props.forId\"\n class=\"text-sm text-[var(--muted-fg)]\"\n :class=\"props.labelClass\"\n >\n {{ props.label }}\n </label>\n <slot />\n <div v-if=\"props.error\" class=\"text-sm text-[var(--ds-danger)]\">\n {{ props.error }}\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\ntype LabelClass = string | string[] | Record<string, boolean>\n\nconst props = withDefaults(\n defineProps<{\n label?: string\n forId?: string\n error?: string\n labelClass?: LabelClass\n }>(),\n {\n label: undefined,\n forId: undefined,\n error: undefined,\n labelClass: undefined,\n },\n)\n</script>\n\n<template>\n <div class=\"flex flex-col gap-2\">\n <label\n v-if=\"props.label\"\n :for=\"props.forId\"\n class=\"text-sm text-[var(--muted-fg)]\"\n :class=\"props.labelClass\"\n >\n {{ props.label }}\n </label>\n <slot />\n <div v-if=\"props.error\" class=\"text-sm text-[var(--ds-danger)]\">\n {{ props.error }}\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAGA,MAAM,QAAQ;;uBAiBZ,mBAaM,OAbN,YAaM;IAXI,MAAM,SAAA,WAAA,EADd,mBAOQ,SAAA;;KALL,KAAK,MAAM;KACZ,OAAK,eAAA,CAAC,kCACE,MAAM,WAAU,CAAA;uBAErB,MAAM,MAAK,EAAA,IAAA,WAAA,IAAA,mBAAA,IAAA,KAAA;IAEhB,WAAQ,KAAA,QAAA,UAAA;IACG,MAAM,SAAA,WAAA,EAAjB,mBAEM,OAFN,YAEM,gBADD,MAAM,MAAK,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrFormField_default } from "./chunks/GrFormField-
|
|
2
|
-
import { t as grFormFieldConfig } from "../../chunks/config-
|
|
1
|
+
import { t as GrFormField_default } from "./chunks/GrFormField-C1oWTT_0.js";
|
|
2
|
+
import { t as grFormFieldConfig } from "../../chunks/config-3SftO0uG.js";
|
|
3
3
|
export { GrFormField_default as GrFormField, GrFormField_default as default, grFormFieldConfig };
|