@feugene/granularity 0.9.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{config-d386uO3O.js.map → config-58Mj2rGH.js.map} +1 -1
- package/dist/chunks/{config-D4s_QWVP.js.map → config-8f8624RN.js.map} +1 -1
- package/dist/chunks/{config-B_nSBc7W.js.map → config-A-iei0Ux.js.map} +1 -1
- package/dist/chunks/{config-CFf7xaG1.js → config-B0uUCaJW.js} +1 -1
- package/dist/chunks/{config-CFf7xaG1.js.map → config-B0uUCaJW.js.map} +1 -1
- package/dist/chunks/{config-Dcb7xK-C.js.map → config-B3dn-gdC.js.map} +1 -1
- package/dist/chunks/{config-D6Oe3blW2.js.map → config-BLa1TEGm2.js.map} +1 -1
- package/dist/chunks/{config-Dzd6BzIN2.js.map → config-BeBsN0c12.js.map} +1 -1
- package/dist/chunks/{config-BU0olrvr.js.map → config-Bh4NWWsQ.js.map} +1 -1
- package/dist/chunks/{config-BeQuykDk2.js.map → config-BuoIngj32.js.map} +1 -1
- package/dist/chunks/{config-BbKroFtR.js.map → config-C5-ujXCI.js.map} +1 -1
- package/dist/chunks/{config-BY81UKv0.js → config-C8MM2Dg0.js} +1 -1
- package/dist/chunks/{config-BY81UKv0.js.map → config-C8MM2Dg0.js.map} +1 -1
- package/dist/chunks/{config-DF_RlCIO.js.map → config-CPSdAjUi.js.map} +1 -1
- package/dist/chunks/{config-iuMz79Mg.js.map → config-CWTfyPNI.js.map} +1 -1
- package/dist/chunks/{config-Br_qI3Za.js → config-C_egzT_K.js} +2 -2
- package/dist/chunks/config-C_egzT_K.js.map +1 -0
- package/dist/chunks/{config-Ci9nXGUV.js.map → config-C_q_4FrU.js.map} +1 -1
- package/dist/chunks/{config-O1_FTqD3.js.map → config-CzgNEHKi.js.map} +1 -1
- package/dist/chunks/{config-Bcf-8XlK2.js.map → config-DDUPnue12.js.map} +1 -1
- package/dist/chunks/{config-DmjwIqx1.js.map → config-DDwBSoc_.js.map} +1 -1
- package/dist/chunks/{config-C5OwJM3-.js → config-DRpkoSvq.js} +1 -1
- package/dist/chunks/{config-C5OwJM3-.js.map → config-DRpkoSvq.js.map} +1 -1
- package/dist/chunks/{config-DaHI5bD_2.js.map → config-DZrlovR42.js.map} +1 -1
- package/dist/chunks/{config-72sW9Bag2.js.map → config-D_Pafsjq2.js.map} +1 -1
- package/dist/chunks/{config-B1kFmhpM.js.map → config-DhQc1TRY.js.map} +1 -1
- package/dist/chunks/{config-CetsgpaZ2.js.map → config-DkeLkzxj2.js.map} +1 -1
- package/dist/chunks/{config-BOdu-O_B.js.map → config-Dl5aZ5VR.js.map} +1 -1
- package/dist/chunks/{config-CvGdaXvH.js.map → config-Doa_gU40.js.map} +1 -1
- package/dist/chunks/{config-CdJpnjDj.js.map → config-DvDNney3.js.map} +1 -1
- package/dist/chunks/{config-CpMYmvVT.js.map → config-NkbzVFZo.js.map} +1 -1
- package/dist/chunks/{config-_3De4HFf.js.map → config-RjfJFv1Y.js.map} +1 -1
- package/dist/chunks/{config-DoBk_CzG.js.map → config-VJuoznpH.js.map} +1 -1
- package/dist/chunks/{config-BnWSHTEU.js.map → config-XspHtPsU.js.map} +1 -1
- package/dist/chunks/{config-B2YTEe_h.js.map → config-hSlCXHoG.js.map} +1 -1
- package/dist/chunks/{config-DSBlHQVa.js.map → config-lMDE_8A5.js.map} +1 -1
- package/dist/chunks/{config-Cp_XHsze.js.map → config-nrOj9p6I.js.map} +1 -1
- package/dist/chunks/{en-foQA8imU.js → en-B_fSdoTi.js} +9 -2
- package/dist/chunks/en-B_fSdoTi.js.map +1 -0
- package/dist/chunks/{es-Bx3Kuy6z.js → es-CISK11Nv.js} +3 -3
- package/dist/chunks/{es-Bx3Kuy6z.js.map → es-CISK11Nv.js.map} +1 -1
- package/dist/chunks/{es-DZFSojYL.js → es-DKP6fLir.js} +9 -2
- package/dist/chunks/es-DKP6fLir.js.map +1 -0
- package/dist/chunks/{grDropdownStyles-B41mVR1H.js → grDropdownStyles-Bqx9hOzU.js} +10 -7
- package/dist/chunks/grDropdownStyles-Bqx9hOzU.js.map +1 -0
- package/dist/chunks/{grModalStyles-DS1Vl6EW.js → grModalStyles-FgaKqx50.js} +1 -1
- package/dist/chunks/grModalStyles-FgaKqx50.js.map +1 -0
- package/dist/chunks/{grSelectStyles-pUt19VGy.js.map → grSelectStyles-AjWWl007.js.map} +1 -1
- package/dist/chunks/{grStyle-CUaTmpyW.js.map → grStyle-D-gPHdyW.js.map} +1 -1
- package/dist/chunks/{granularityI18n-LcJ88Vce.js → granularityI18n-D_7jowK2.js} +17 -2
- package/dist/chunks/granularityI18n-D_7jowK2.js.map +1 -0
- package/dist/chunks/{ru-LhkPpPIl.js → ru-S6VlnurJ.js} +9 -2
- package/dist/chunks/ru-S6VlnurJ.js.map +1 -0
- package/dist/chunks/{shared-BiqXd5MW.js → shared-DpjTvFno.js} +34 -34
- package/dist/chunks/{shared-BiqXd5MW.js.map → shared-DpjTvFno.js.map} +1 -1
- package/dist/chunks/useFloating-CLtbU7eD.js +1234 -0
- package/dist/chunks/useFloating-CLtbU7eD.js.map +1 -0
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-Br6WJkLE.js → GrConfirmDialog-Bi2KLumL.js} +2 -2
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-Br6WJkLE.js.map → GrConfirmDialog-Bi2KLumL.js.map} +1 -1
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-C7XLxp8e.js → GrDialog-CxK4Lj4F.js} +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-C7XLxp8e.js.map → GrDialog-CxK4Lj4F.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-DOvHKnih.js → GrDropdown-BGKeEfZ1.js} +13 -59
- package/dist/components/GrDropdown/chunks/GrDropdown-BGKeEfZ1.js.map +1 -0
- package/dist/components/GrDropdown/index.js +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-CLPwbiyG.js → GrDropdownMenu-CJom_-c2.js} +1 -1
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-CLPwbiyG.js.map → GrDropdownMenu-CJom_-c2.js.map} +1 -1
- package/dist/components/GrDropdownMenu/index.js +2 -2
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-Dj2V5GaX.js.map → GrEmptyState-yOuZW7-t.js.map} +1 -1
- package/dist/components/GrEmptyState/index.js +2 -2
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-BEKNB1RM.js → GrFileUpload-CBKK3dgC.js} +1 -1
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-BEKNB1RM.js.map → GrFileUpload-CBKK3dgC.js.map} +1 -1
- package/dist/components/GrFileUpload/index.js +2 -2
- package/dist/components/GrFormField/index.js +1 -1
- package/dist/components/GrFormFile/chunks/{GrFormFile-CIleXnfr.js.map → GrFormFile-CkR6cYqf.js.map} +1 -1
- package/dist/components/GrFormFile/index.js +2 -2
- package/dist/components/GrFormSection/chunks/{GrFormSection-DpGhY7MX.js.map → GrFormSection-dbyzqxYk.js.map} +1 -1
- package/dist/components/GrFormSection/index.js +2 -2
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-CsvXQHM9.js.map → GrImageViewer-BG40DsHa.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +2 -2
- package/dist/components/GrInput/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-Dcj3F6rQ.js → GrInputTag-g-KdUI_Z.js} +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-Dcj3F6rQ.js.map → GrInputTag-g-KdUI_Z.js.map} +1 -1
- package/dist/components/GrInputTag/index.js +2 -2
- package/dist/components/GrLink/chunks/{GrLink-BMwn2iJ9.js → GrLink-KSTmk9Yq.js} +1 -1
- package/dist/components/GrLink/chunks/{GrLink-BMwn2iJ9.js.map → GrLink-KSTmk9Yq.js.map} +1 -1
- package/dist/components/GrLink/index.js +2 -2
- package/dist/components/GrList/chunks/{GrList-D8nM1FuV.js.map → GrList-CUW2sRm_.js.map} +1 -1
- package/dist/components/GrList/index.js +2 -2
- package/dist/components/GrLoading/index.js +1 -1
- package/dist/components/GrModal/chunks/{GrModal-lh0lOmoi.js → GrModal-CSOL3fHQ.js} +1 -1
- package/dist/components/GrModal/chunks/{GrModal-lh0lOmoi.js.map → GrModal-CSOL3fHQ.js.map} +1 -1
- package/dist/components/GrModal/index.js +3 -3
- package/dist/components/GrNavbar/chunks/{GrNavbar-BH7XiF9q.js → GrNavbar-CHxwtFIR.js} +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-BH7XiF9q.js.map → GrNavbar-CHxwtFIR.js.map} +1 -1
- package/dist/components/GrNavbar/index.js +2 -2
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-YIWhV85S.js → GrNumberInput-ClPBwkxx.js} +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-YIWhV85S.js.map → GrNumberInput-ClPBwkxx.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-BNDEqM8_.js → GrPagination-D2GS0ShQ.js} +4 -4
- package/dist/components/GrPagination/chunks/GrPagination-D2GS0ShQ.js.map +1 -0
- package/dist/components/GrPagination/index.js +2 -2
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-C2HdYjp4.js → GrProgressBar-BBSFpVEq.js} +1 -1
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-C2HdYjp4.js.map → GrProgressBar-BBSFpVEq.js.map} +1 -1
- package/dist/components/GrProgressBar/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BV4EW3XO.js → GrPromptDialog-D_TFqKsF.js} +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BV4EW3XO.js.map → GrPromptDialog-D_TFqKsF.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +2 -2
- package/dist/components/GrRadio/chunks/{GrRadio-IFU9Hiu2.js → GrRadio-CSbTnrom.js} +1 -1
- package/dist/components/GrRadio/chunks/{GrRadio-IFU9Hiu2.js.map → GrRadio-CSbTnrom.js.map} +1 -1
- package/dist/components/GrRadio/index.js +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-C8IcJuuF.js → GrRadioGroup-DsrnTygR.js} +1 -1
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-C8IcJuuF.js.map → GrRadioGroup-DsrnTygR.js.map} +1 -1
- package/dist/components/GrRadioGroup/index.js +2 -2
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BMvXREcv.js → GrResponseErrorBanner-K1uZ1mYD.js} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BMvXREcv.js.map → GrResponseErrorBanner-K1uZ1mYD.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CzdTh4gd.js → GrResponseErrorBanner-bM8FC_Bw.js} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CzdTh4gd.js.map → GrResponseErrorBanner-bM8FC_Bw.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/index.js +2 -2
- package/dist/components/GrSegmented/chunks/{GrSegmented-BRmwBsEG.js → GrSegmented-DpZGs4VX.js} +1 -1
- package/dist/components/GrSegmented/chunks/{GrSegmented-BRmwBsEG.js.map → GrSegmented-DpZGs4VX.js.map} +1 -1
- package/dist/components/GrSegmented/index.js +2 -2
- package/dist/components/GrSelect/chunks/{GrSelect-CnHdbPlf.js → GrSelect-DSz7jvUb.js} +25 -51
- package/dist/components/GrSelect/chunks/GrSelect-DSz7jvUb.js.map +1 -0
- package/dist/components/GrSelect/index.js +2 -2
- package/dist/components/GrSidebar/chunks/{GrSidebar-BpBtAGBs.js.map → GrSidebar-BW8LRMZ-.js.map} +1 -1
- package/dist/components/GrSidebar/index.js +2 -2
- package/dist/components/GrSkeleton/chunks/{GrSkeleton-URyMkBqI.js.map → GrSkeleton-B05K0QKh.js.map} +1 -1
- package/dist/components/GrSkeleton/index.js +2 -2
- package/dist/components/GrSwitch/chunks/{GrSwitch-29h0QhMO.js → GrSwitch-CSRtcN5-.js} +1 -1
- package/dist/components/GrSwitch/chunks/{GrSwitch-29h0QhMO.js.map → GrSwitch-CSRtcN5-.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-D3ntDdtg.js.map → GrTabs-BfeVNMFJ.js.map} +1 -1
- package/dist/components/GrTabs/index.js +2 -2
- package/dist/components/GrTextarea/chunks/{GrTextarea-Cv6r2GuC.js → GrTextarea-CBBzpF2S.js} +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-Cv6r2GuC.js.map → GrTextarea-CBBzpF2S.js.map} +1 -1
- package/dist/components/GrTextarea/index.js +2 -2
- package/dist/components/GrToaster/chunks/{GrToaster-DluJmR5D.js → GrToaster-C6_iHk2J.js} +4 -3
- package/dist/components/GrToaster/chunks/GrToaster-C6_iHk2J.js.map +1 -0
- package/dist/components/GrToaster/index.js +2 -2
- package/dist/components/GrTooltip/chunks/GrTooltip-BC-40SA5.js +109 -0
- package/dist/components/GrTooltip/chunks/GrTooltip-BC-40SA5.js.map +1 -0
- package/dist/components/GrTooltip/index.js +2 -2
- package/dist/components/GrTree/chunks/{GrTree-B2SMU5Py.js.map → GrTree-uZr5SyQI.js.map} +1 -1
- package/dist/components/GrTree/index.js +2 -2
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-C1abr5uH.js → GrTreeSelect-CytivcCa.js} +9 -37
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-CytivcCa.js.map +1 -0
- package/dist/components/GrTreeSelect/index.js +2 -2
- 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 +1 -1
- package/dist/index.js +67 -67
- package/dist/types/src/components/GrDropdown/grDropdownStyles.d.ts +3 -2
- package/dist/types/src/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +2 -2
- package/dist/types/src/components/GrDropdownMenu/GrDropdownMenuGroup.vue.d.ts +1 -1
- package/dist/types/src/components/GrDropdownMenu/GrDropdownMenuList.vue.d.ts +2 -2
- package/dist/types/src/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
- package/dist/types/src/components/GrLink/GrLink.vue.d.ts +1 -1
- package/dist/types/src/components/GrModal/grModalStyles.d.ts +1 -1
- package/dist/types/src/components/GrSegmented/GrSegmented.vue.d.ts +1 -1
- package/dist/types/src/components/GrSelect/GrSelect.vue.d.ts +6 -6
- package/dist/types/src/composables/internal/useFloating.d.ts +53 -0
- package/dist/types/src/i18n/messages/en.d.ts +12 -0
- package/dist/types/src/i18n/messages/es.d.ts +12 -0
- package/dist/types/src/i18n/messages/ru.d.ts +12 -0
- package/package.json +9 -1
- package/dist/chunks/config-Br_qI3Za.js.map +0 -1
- package/dist/chunks/en-foQA8imU.js.map +0 -1
- package/dist/chunks/es-DZFSojYL.js.map +0 -1
- package/dist/chunks/grDropdownStyles-B41mVR1H.js.map +0 -1
- package/dist/chunks/grModalStyles-DS1Vl6EW.js.map +0 -1
- package/dist/chunks/granularityI18n-LcJ88Vce.js.map +0 -1
- package/dist/chunks/ru-LhkPpPIl.js.map +0 -1
- package/dist/components/GrDropdown/chunks/GrDropdown-DOvHKnih.js.map +0 -1
- package/dist/components/GrPagination/chunks/GrPagination-BNDEqM8_.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-CnHdbPlf.js.map +0 -1
- package/dist/components/GrToaster/chunks/GrToaster-DluJmR5D.js.map +0 -1
- package/dist/components/GrTooltip/chunks/GrTooltip-B7I1AVIC.js +0 -55
- package/dist/components/GrTooltip/chunks/GrTooltip-B7I1AVIC.js.map +0 -1
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-C1abr5uH.js.map +0 -1
- /package/dist/chunks/{config-d386uO3O.js → config-58Mj2rGH.js} +0 -0
- /package/dist/chunks/{config-D4s_QWVP.js → config-8f8624RN.js} +0 -0
- /package/dist/chunks/{config-B_nSBc7W.js → config-A-iei0Ux.js} +0 -0
- /package/dist/chunks/{config-Dcb7xK-C.js → config-B3dn-gdC.js} +0 -0
- /package/dist/chunks/{config-D6Oe3blW2.js → config-BLa1TEGm2.js} +0 -0
- /package/dist/chunks/{config-Dzd6BzIN2.js → config-BeBsN0c12.js} +0 -0
- /package/dist/chunks/{config-BU0olrvr.js → config-Bh4NWWsQ.js} +0 -0
- /package/dist/chunks/{config-BeQuykDk2.js → config-BuoIngj32.js} +0 -0
- /package/dist/chunks/{config-BbKroFtR.js → config-C5-ujXCI.js} +0 -0
- /package/dist/chunks/{config-DF_RlCIO.js → config-CPSdAjUi.js} +0 -0
- /package/dist/chunks/{config-iuMz79Mg.js → config-CWTfyPNI.js} +0 -0
- /package/dist/chunks/{config-Ci9nXGUV.js → config-C_q_4FrU.js} +0 -0
- /package/dist/chunks/{config-O1_FTqD3.js → config-CzgNEHKi.js} +0 -0
- /package/dist/chunks/{config-Bcf-8XlK2.js → config-DDUPnue12.js} +0 -0
- /package/dist/chunks/{config-DmjwIqx1.js → config-DDwBSoc_.js} +0 -0
- /package/dist/chunks/{config-DaHI5bD_2.js → config-DZrlovR42.js} +0 -0
- /package/dist/chunks/{config-72sW9Bag2.js → config-D_Pafsjq2.js} +0 -0
- /package/dist/chunks/{config-B1kFmhpM.js → config-DhQc1TRY.js} +0 -0
- /package/dist/chunks/{config-CetsgpaZ2.js → config-DkeLkzxj2.js} +0 -0
- /package/dist/chunks/{config-BOdu-O_B.js → config-Dl5aZ5VR.js} +0 -0
- /package/dist/chunks/{config-CvGdaXvH.js → config-Doa_gU40.js} +0 -0
- /package/dist/chunks/{config-CdJpnjDj.js → config-DvDNney3.js} +0 -0
- /package/dist/chunks/{config-CpMYmvVT.js → config-NkbzVFZo.js} +0 -0
- /package/dist/chunks/{config-_3De4HFf.js → config-RjfJFv1Y.js} +0 -0
- /package/dist/chunks/{config-DoBk_CzG.js → config-VJuoznpH.js} +0 -0
- /package/dist/chunks/{config-BnWSHTEU.js → config-XspHtPsU.js} +0 -0
- /package/dist/chunks/{config-B2YTEe_h.js → config-hSlCXHoG.js} +0 -0
- /package/dist/chunks/{config-DSBlHQVa.js → config-lMDE_8A5.js} +0 -0
- /package/dist/chunks/{config-Cp_XHsze.js → config-nrOj9p6I.js} +0 -0
- /package/dist/chunks/{grSelectStyles-pUt19VGy.js → grSelectStyles-AjWWl007.js} +0 -0
- /package/dist/chunks/{grStyle-CUaTmpyW.js → grStyle-D-gPHdyW.js} +0 -0
- /package/dist/components/GrEmptyState/chunks/{GrEmptyState-Dj2V5GaX.js → GrEmptyState-yOuZW7-t.js} +0 -0
- /package/dist/components/GrFormFile/chunks/{GrFormFile-CIleXnfr.js → GrFormFile-CkR6cYqf.js} +0 -0
- /package/dist/components/GrFormSection/chunks/{GrFormSection-DpGhY7MX.js → GrFormSection-dbyzqxYk.js} +0 -0
- /package/dist/components/GrImageViewer/chunks/{GrImageViewer-CsvXQHM9.js → GrImageViewer-BG40DsHa.js} +0 -0
- /package/dist/components/GrList/chunks/{GrList-D8nM1FuV.js → GrList-CUW2sRm_.js} +0 -0
- /package/dist/components/GrSidebar/chunks/{GrSidebar-BpBtAGBs.js → GrSidebar-BW8LRMZ-.js} +0 -0
- /package/dist/components/GrSkeleton/chunks/{GrSkeleton-URyMkBqI.js → GrSkeleton-B05K0QKh.js} +0 -0
- /package/dist/components/GrTabs/chunks/{GrTabs-D3ntDdtg.js → GrTabs-BfeVNMFJ.js} +0 -0
- /package/dist/components/GrTree/chunks/{GrTree-B2SMU5Py.js → GrTree-uZr5SyQI.js} +0 -0
|
@@ -23,6 +23,10 @@ export declare const en: {
|
|
|
23
23
|
filterPlaceholder: string;
|
|
24
24
|
empty: string;
|
|
25
25
|
};
|
|
26
|
+
select: {
|
|
27
|
+
customValuePlaceholder: string;
|
|
28
|
+
addOption: string;
|
|
29
|
+
};
|
|
26
30
|
dialog: {
|
|
27
31
|
confirm: {
|
|
28
32
|
title: string;
|
|
@@ -34,9 +38,11 @@ export declare const en: {
|
|
|
34
38
|
};
|
|
35
39
|
};
|
|
36
40
|
pagination: {
|
|
41
|
+
label: string;
|
|
37
42
|
pageSize: string;
|
|
38
43
|
prev: string;
|
|
39
44
|
next: string;
|
|
45
|
+
page: string;
|
|
40
46
|
};
|
|
41
47
|
navbar: {
|
|
42
48
|
openMenu: string;
|
|
@@ -82,6 +88,10 @@ export declare const en: {
|
|
|
82
88
|
filterPlaceholder: string;
|
|
83
89
|
empty: string;
|
|
84
90
|
};
|
|
91
|
+
select: {
|
|
92
|
+
customValuePlaceholder: string;
|
|
93
|
+
addOption: string;
|
|
94
|
+
};
|
|
85
95
|
dialog: {
|
|
86
96
|
confirm: {
|
|
87
97
|
title: string;
|
|
@@ -93,9 +103,11 @@ export declare const en: {
|
|
|
93
103
|
};
|
|
94
104
|
};
|
|
95
105
|
pagination: {
|
|
106
|
+
label: string;
|
|
96
107
|
pageSize: string;
|
|
97
108
|
prev: string;
|
|
98
109
|
next: string;
|
|
110
|
+
page: string;
|
|
99
111
|
};
|
|
100
112
|
navbar: {
|
|
101
113
|
openMenu: string;
|
|
@@ -16,6 +16,10 @@ export declare const es: {
|
|
|
16
16
|
filterPlaceholder: string;
|
|
17
17
|
empty: string;
|
|
18
18
|
};
|
|
19
|
+
select: {
|
|
20
|
+
customValuePlaceholder: string;
|
|
21
|
+
addOption: string;
|
|
22
|
+
};
|
|
19
23
|
dialog: {
|
|
20
24
|
confirm: {
|
|
21
25
|
title: string;
|
|
@@ -27,9 +31,11 @@ export declare const es: {
|
|
|
27
31
|
};
|
|
28
32
|
};
|
|
29
33
|
pagination: {
|
|
34
|
+
label: string;
|
|
30
35
|
pageSize: string;
|
|
31
36
|
prev: string;
|
|
32
37
|
next: string;
|
|
38
|
+
page: string;
|
|
33
39
|
};
|
|
34
40
|
navbar: {
|
|
35
41
|
openMenu: string;
|
|
@@ -75,6 +81,10 @@ export declare const es: {
|
|
|
75
81
|
filterPlaceholder: string;
|
|
76
82
|
empty: string;
|
|
77
83
|
};
|
|
84
|
+
select: {
|
|
85
|
+
customValuePlaceholder: string;
|
|
86
|
+
addOption: string;
|
|
87
|
+
};
|
|
78
88
|
dialog: {
|
|
79
89
|
confirm: {
|
|
80
90
|
title: string;
|
|
@@ -86,9 +96,11 @@ export declare const es: {
|
|
|
86
96
|
};
|
|
87
97
|
};
|
|
88
98
|
pagination: {
|
|
99
|
+
label: string;
|
|
89
100
|
pageSize: string;
|
|
90
101
|
prev: string;
|
|
91
102
|
next: string;
|
|
103
|
+
page: string;
|
|
92
104
|
};
|
|
93
105
|
navbar: {
|
|
94
106
|
openMenu: string;
|
|
@@ -16,6 +16,10 @@ export declare const ru: {
|
|
|
16
16
|
filterPlaceholder: string;
|
|
17
17
|
empty: string;
|
|
18
18
|
};
|
|
19
|
+
select: {
|
|
20
|
+
customValuePlaceholder: string;
|
|
21
|
+
addOption: string;
|
|
22
|
+
};
|
|
19
23
|
dialog: {
|
|
20
24
|
confirm: {
|
|
21
25
|
title: string;
|
|
@@ -27,9 +31,11 @@ export declare const ru: {
|
|
|
27
31
|
};
|
|
28
32
|
};
|
|
29
33
|
pagination: {
|
|
34
|
+
label: string;
|
|
30
35
|
pageSize: string;
|
|
31
36
|
prev: string;
|
|
32
37
|
next: string;
|
|
38
|
+
page: string;
|
|
33
39
|
};
|
|
34
40
|
navbar: {
|
|
35
41
|
openMenu: string;
|
|
@@ -75,6 +81,10 @@ export declare const ru: {
|
|
|
75
81
|
filterPlaceholder: string;
|
|
76
82
|
empty: string;
|
|
77
83
|
};
|
|
84
|
+
select: {
|
|
85
|
+
customValuePlaceholder: string;
|
|
86
|
+
addOption: string;
|
|
87
|
+
};
|
|
78
88
|
dialog: {
|
|
79
89
|
confirm: {
|
|
80
90
|
title: string;
|
|
@@ -86,9 +96,11 @@ export declare const ru: {
|
|
|
86
96
|
};
|
|
87
97
|
};
|
|
88
98
|
pagination: {
|
|
99
|
+
label: string;
|
|
89
100
|
pageSize: string;
|
|
90
101
|
prev: string;
|
|
91
102
|
next: string;
|
|
103
|
+
page: string;
|
|
92
104
|
};
|
|
93
105
|
navbar: {
|
|
94
106
|
openMenu: string;
|
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.
|
|
4
|
+
"version": "0.10.0",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Evgeniy Fureev",
|
|
@@ -309,11 +309,18 @@
|
|
|
309
309
|
}
|
|
310
310
|
},
|
|
311
311
|
"peerDependencies": {
|
|
312
|
+
"@feugene/fint-i18n": "^0.3.0",
|
|
312
313
|
"@feugene/unocss-preset-granular": "^0.3.0",
|
|
313
314
|
"vue": "^3.5.32"
|
|
314
315
|
},
|
|
316
|
+
"peerDependenciesMeta": {
|
|
317
|
+
"@feugene/fint-i18n": {
|
|
318
|
+
"optional": true
|
|
319
|
+
}
|
|
320
|
+
},
|
|
315
321
|
"devDependencies": {
|
|
316
322
|
"@antfu/eslint-config": "^8.2.0",
|
|
323
|
+
"@feugene/fint-i18n": "^0.3.0",
|
|
317
324
|
"@feugene/unocss-preset-granular": "^0.3.0",
|
|
318
325
|
"@iconify-json/lucide": "^1.2.101",
|
|
319
326
|
"@types/node": "^25.5.2",
|
|
@@ -342,6 +349,7 @@
|
|
|
342
349
|
"test:run": "vitest run --config vitest.config.ts"
|
|
343
350
|
},
|
|
344
351
|
"dependencies": {
|
|
352
|
+
"@floating-ui/dom": "^1.6.0",
|
|
345
353
|
"@headlessui/vue": "^1.7.23"
|
|
346
354
|
}
|
|
347
355
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"config-Br_qI3Za.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":"en-foQA8imU.js","names":[],"sources":["../../src/i18n/locales/en.json"],"sourcesContent":["{\n \"common\": {\n \"confirm\": \"Confirm\",\n \"cancel\": \"Cancel\",\n \"add\": \"Add\",\n \"clear\": \"Clear\",\n \"close\": \"Close\"\n },\n \"loading\": {\n \"defaultText\": \"Loading...\"\n },\n \"treeSelect\": {\n \"filterPlaceholder\": \"Search…\",\n \"empty\": \"No data\"\n },\n \"dialog\": {\n \"confirm\": {\n \"title\": \"Confirm\"\n },\n \"prompt\": {\n \"title\": \"Prompt\",\n \"label\": \"Value\",\n \"required\": \"Enter a value.\"\n }\n },\n \"pagination\": {\n \"pageSize\": \"Page size\",\n \"prev\": \"Prev\",\n \"next\": \"Next\"\n },\n \"navbar\": {\n \"openMenu\": \"Open menu\"\n },\n \"responseError\": {\n \"networkTitle\": \"No connection to the server\",\n \"networkMessage\": \"Check your internet connection and try again.\",\n \"abortedTitle\": \"Request cancelled\",\n \"abortedMessage\": \"The request was cancelled.\",\n \"validationTitle\": \"Check the data\",\n \"validationMessage\": \"The server returned a validation error. Fix the fields and try again.\",\n \"clientTitle\": \"Request error\",\n \"clientMessage\": \"The server rejected the request.\",\n \"serverTitle\": \"Server error\",\n \"serverMessage\": \"A server error occurred. Please try again.\",\n \"unknownTitle\": \"Something went wrong\",\n \"unknownMessage\": \"The operation could not be completed. Please try again.\",\n \"retryLabel\": \"Retry\",\n \"dismissLabel\": \"Dismiss\"\n },\n \"colors\": {\n \"neutral\": \"Neutral\",\n \"success\": \"Success\",\n \"warning\": \"Warning\",\n \"danger\": \"Danger\",\n \"info\": \"Info\",\n \"primary\": \"Primary\",\n \"slate\": \"Slate\",\n \"azure\": \"Azure\"\n }\n}\n"],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"es-DZFSojYL.js","names":[],"sources":["../../src/i18n/locales/es.json"],"sourcesContent":["{\n \"common\": {\n \"confirm\": \"Confirmar\",\n \"cancel\": \"Cancelar\",\n \"add\": \"Añadir\",\n \"clear\": \"Limpiar\",\n \"close\": \"Cerrar\"\n },\n \"loading\": {\n \"defaultText\": \"Cargando...\"\n },\n \"treeSelect\": {\n \"filterPlaceholder\": \"Buscar…\",\n \"empty\": \"Sin datos\"\n },\n \"dialog\": {\n \"confirm\": {\n \"title\": \"Confirmar\"\n },\n \"prompt\": {\n \"title\": \"Aviso\",\n \"label\": \"Valor\",\n \"required\": \"Introduzca un valor.\"\n }\n },\n \"pagination\": {\n \"pageSize\": \"Tamaño de página\",\n \"prev\": \"Anterior\",\n \"next\": \"Siguiente\"\n },\n \"navbar\": {\n \"openMenu\": \"Abrir menú\"\n },\n \"responseError\": {\n \"networkTitle\": \"Sin conexión con el servidor\",\n \"networkMessage\": \"Compruebe su conexión a internet e inténtelo de nuevo.\",\n \"abortedTitle\": \"Solicitud cancelada\",\n \"abortedMessage\": \"La solicitud fue cancelada.\",\n \"validationTitle\": \"Compruebe los datos\",\n \"validationMessage\": \"El servidor devolvió un error de validación. Corrija los campos e inténtelo de nuevo.\",\n \"clientTitle\": \"Error de solicitud\",\n \"clientMessage\": \"El servidor rechazó la solicitud.\",\n \"serverTitle\": \"Error del servidor\",\n \"serverMessage\": \"Se produjo un error en el servidor. Inténtelo de nuevo.\",\n \"unknownTitle\": \"Algo salió mal\",\n \"unknownMessage\": \"No se pudo completar la operación. Inténtelo de nuevo.\",\n \"retryLabel\": \"Reintentar\",\n \"dismissLabel\": \"Descartar\"\n },\n \"colors\": {\n \"neutral\": \"Neutral\",\n \"success\": \"Éxito\",\n \"warning\": \"Advertencia\",\n \"danger\": \"Peligro\",\n \"info\": \"Info\",\n \"primary\": \"Primario\",\n \"slate\": \"Pizarra\",\n \"azure\": \"Azul celeste\"\n }\n}\n"],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"grDropdownStyles-B41mVR1H.js","names":[],"sources":["../../src/components/GrDropdown/grDropdownStyles.ts"],"sourcesContent":["export type GrDropdownAlign = 'left' | 'right' | 'center'\nexport type GrDropdownWidth = 'auto' | '20' | '48' | '60' | '64' | '80'\n\nexport const widthClassByWidth: Record<GrDropdownWidth, string> = {\n auto: '',\n 20: 'w-20',\n 48: 'w-48',\n 60: 'w-60',\n 64: 'w-64',\n 80: 'w-80',\n}\n\nexport const alignmentClassByAlign: Record<GrDropdownAlign, string> = {\n left: 'origin-top-left',\n right: 'origin-top-right -translate-x-full',\n center: 'origin-top -translate-x-1/2',\n}\n\nexport function grDropdownWidthClass(width: GrDropdownWidth): string {\n return widthClassByWidth[width]\n}\n\nexport function grDropdownAlignmentClass(align: GrDropdownAlign): string {\n return alignmentClassByAlign[align]\n}\n\nexport function grDropdownContentClass(contentClass?: string): string {\n return [\n 'rounded-[var(--ds-radius-xl)]',\n 'border border-[var(--brd)]',\n 'bg-[var(--card)] text-[var(--card-fg)]',\n 'shadow-[var(--ds-shadow-2)]',\n 'p-1',\n contentClass,\n ].filter(Boolean).join(' ')\n}\n"],"mappings":";AAGA,IAAa,oBAAqD;CAChE,MAAM;CACN,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACL;AAED,IAAa,wBAAyD;CACpE,MAAM;CACN,OAAO;CACP,QAAQ;CACT;AAED,SAAgB,qBAAqB,OAAgC;AACnE,QAAO,kBAAkB;;AAG3B,SAAgB,yBAAyB,OAAgC;AACvE,QAAO,sBAAsB;;AAG/B,SAAgB,uBAAuB,cAA+B;AACpE,QAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACD,CAAC,OAAO,QAAQ,CAAC,KAAK,IAAI"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"grModalStyles-DS1Vl6EW.js","names":[],"sources":["../../src/components/GrModal/grModalStyles.ts"],"sourcesContent":["export type GrModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'\n\n// Корневые утилитарные классы, используемые шаблоном `GrModal.vue`.\n// Они же являются единственным источником истины для safelist.\nexport const root = 'fixed inset-0 z-50'\nexport const shell = 'fixed inset-0 overflow-y-auto p-4 sm:p-6'\nexport const layout = 'min-h-full flex items-center justify-center'\nexport const overlay = 'fixed inset-0 z-0 bg-black/40'\n\n// Классы для `<TransitionChild :enter=\"...\" :enter-from=\"...\" ...>`.\n// Разбиты по фазам транзишна, чтобы не склеивать их в «мешок токенов».\nexport const overlayTransition = {\n enter: 'duration-200 ease-out',\n enterFrom: 'opacity-0',\n enterTo: 'opacity-100',\n leave: 'duration-150 ease-in',\n leaveFrom: 'opacity-100',\n leaveTo: 'opacity-0',\n} as const\n\nexport const panelTransition = {\n enter: 'duration-200 ease-out',\n enterFrom: 'opacity-0 translate-y-2 sm:translate-y-0 sm:scale-95',\n enterTo: 'opacity-100 translate-y-0 sm:scale-100',\n leave: 'duration-150 ease-in',\n leaveFrom: 'opacity-100 translate-y-0 sm:scale-100',\n leaveTo: 'opacity-0 translate-y-2 sm:translate-y-0 sm:scale-95',\n} as const\n\nexport const panelBase\n = 'w-full overflow-hidden relative z-10 border border-[var(--brd)] bg-[var(--card)] text-[var(--card-fg)] shadow-[var(--ds-shadow-2)] outline-none'\n\nexport const panelWidthBySize: Record<GrModalSize, string> = {\n sm: 'max-w-[420px]',\n md: 'max-w-[560px]',\n lg: 'max-w-[720px]',\n xl: 'max-w-[920px]',\n full: 'max-w-none',\n}\n\nexport const panelRadiusBySize: Record<GrModalSize, string> = {\n sm: 'rounded-[var(--ds-radius-xl)]',\n md: 'rounded-[var(--ds-radius-xl)]',\n lg: 'rounded-[var(--ds-radius-xl)]',\n xl: 'rounded-[var(--ds-radius-xl)]',\n full: 'rounded-none sm:rounded-[var(--ds-radius-xl)]',\n}\n\n// Для большинства размеров высота не задаётся — `Partial` + фильтрация пустых\n// значений в `getGrModalPanelClass` избавляют от двойных пробелов.\nexport const panelHeightBySize: Partial<Record<GrModalSize, string>> = {\n full: 'h-[100svh] sm:h-auto',\n}\n\nexport function getGrModalPanelClass(size: GrModalSize): string {\n return [\n panelBase,\n panelWidthBySize[size],\n panelHeightBySize[size],\n panelRadiusBySize[size],\n ]\n .filter(Boolean)\n .join(' ')\n}\n"],"mappings":";AAIA,IAAa,OAAO;AACpB,IAAa,QAAQ;AACrB,IAAa,SAAS;AACtB,IAAa,UAAU;AAIvB,IAAa,oBAAoB;CAC/B,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,WAAW;CACX,SAAS;CACV;AAED,IAAa,kBAAkB;CAC7B,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,WAAW;CACX,SAAS;CACV;AAED,IAAa,YACT;AAEJ,IAAa,mBAAgD;CAC3D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM;CACP;AAED,IAAa,oBAAiD;CAC5D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,MAAM;CACP;AAID,IAAa,oBAA0D,EACrE,MAAM,wBACP;AAED,SAAgB,qBAAqB,MAA2B;AAC9D,QAAO;EACL;EACA,iBAAiB;EACjB,kBAAkB;EAClB,kBAAkB;EACnB,CACE,OAAO,QAAQ,CACf,KAAK,IAAI"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"granularityI18n-LcJ88Vce.js","names":[],"sources":["../../src/internal/granularityI18n.ts"],"sourcesContent":["import { getCurrentInstance, inject, type AppContext } from 'vue'\n\nimport { GRANULARITY_I18N_KEY, type GranularityI18nAdapter } from '../i18n/adapter'\n\nexport type GranularityI18nLike = GranularityI18nAdapter\n\n/**\n * Ключ provide/inject из `@feugene/fint-i18n` (`Symbol.for(\"FintI18n\")`).\n *\n * Дублируем константу здесь, чтобы не делать `@feugene/fint-i18n` обязательной\n * runtime-зависимостью пакета: достаточно, чтобы приложение само установило\n * fint-i18n через `installI18n(app, i18n)` — символ глобальный (Symbol.for),\n * поэтому ключи будут совпадать без прямого импорта.\n */\nconst FINT_I18N_KEY: symbol = Symbol.for('FintI18n')\n\nfunction isGranularityI18nLike(value: unknown): value is GranularityI18nLike {\n return typeof (value as GranularityI18nLike | null)?.t === 'function'\n}\n\nexport function resolveGranularityI18n(context?: AppContext | GranularityI18nLike | null): GranularityI18nLike | null {\n if (isGranularityI18nLike(context)) {\n return context\n }\n\n const provides = context?.provides\n\n if (provides) {\n const fromGranularity = provides[GRANULARITY_I18N_KEY as symbol] as GranularityI18nLike | null | undefined\n if (isGranularityI18nLike(fromGranularity)) {\n return fromGranularity\n }\n\n const fromFint = provides[FINT_I18N_KEY] as GranularityI18nLike | null | undefined\n if (isGranularityI18nLike(fromFint)) {\n return fromFint\n }\n\n return null\n }\n\n if (!getCurrentInstance()) {\n return null\n }\n\n const fromGranularity = inject<GranularityI18nLike | null>(GRANULARITY_I18N_KEY, null)\n if (isGranularityI18nLike(fromGranularity)) {\n return fromGranularity\n }\n\n const fromFint = inject<GranularityI18nLike | null>(FINT_I18N_KEY, null)\n if (isGranularityI18nLike(fromFint)) {\n return fromFint\n }\n\n return null\n}\n\nexport function useGranularityTranslations(context?: AppContext | GranularityI18nLike | null) {\n const i18n = resolveGranularityI18n(context)\n\n const t = (key: string, fallback: string, params?: Record<string, any>): string => {\n if (!i18n) {\n return fallback\n }\n\n const result = i18n.t(key, params)\n return result === key ? fallback : result\n }\n\n return {\n i18n,\n t,\n }\n}"],"mappings":";;;;;;;;;;;AAcA,IAAM,gBAAwB,OAAO,IAAI,WAAW;AAEpD,SAAS,sBAAsB,OAA8C;AAC3E,QAAO,OAAQ,OAAsC,MAAM;;AAG7D,SAAgB,uBAAuB,SAA+E;AACpH,KAAI,sBAAsB,QAAQ,CAChC,QAAO;CAGT,MAAM,WAAW,SAAS;AAE1B,KAAI,UAAU;EACZ,MAAM,kBAAkB,SAAS;AACjC,MAAI,sBAAsB,gBAAgB,CACxC,QAAO;EAGT,MAAM,WAAW,SAAS;AAC1B,MAAI,sBAAsB,SAAS,CACjC,QAAO;AAGT,SAAO;;AAGT,KAAI,CAAC,oBAAoB,CACvB,QAAO;CAGT,MAAM,kBAAkB,OAAmC,sBAAsB,KAAK;AACtF,KAAI,sBAAsB,gBAAgB,CACxC,QAAO;CAGT,MAAM,WAAW,OAAmC,eAAe,KAAK;AACxE,KAAI,sBAAsB,SAAS,CACjC,QAAO;AAGT,QAAO;;AAGT,SAAgB,2BAA2B,SAAmD;CAC5F,MAAM,OAAO,uBAAuB,QAAQ;CAE5C,MAAM,KAAK,KAAa,UAAkB,WAAyC;AACjF,MAAI,CAAC,KACH,QAAO;EAGT,MAAM,SAAS,KAAK,EAAE,KAAK,OAAO;AAClC,SAAO,WAAW,MAAM,WAAW;;AAGrC,QAAO;EACL;EACA;EACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ru-LhkPpPIl.js","names":[],"sources":["../../src/i18n/locales/ru.json"],"sourcesContent":["{\n \"common\": {\n \"confirm\": \"Подтвердить\",\n \"cancel\": \"Отмена\",\n \"add\": \"Добавить\",\n \"clear\": \"Очистить\",\n \"close\": \"Закрыть\"\n },\n \"loading\": {\n \"defaultText\": \"Загрузка...\"\n },\n \"treeSelect\": {\n \"filterPlaceholder\": \"Поиск…\",\n \"empty\": \"Нет данных\"\n },\n \"dialog\": {\n \"confirm\": {\n \"title\": \"Подтверждение\"\n },\n \"prompt\": {\n \"title\": \"Введите значение\",\n \"label\": \"Значение\",\n \"required\": \"Введите значение.\"\n }\n },\n \"pagination\": {\n \"pageSize\": \"Размер страницы\",\n \"prev\": \"Назад\",\n \"next\": \"Вперёд\"\n },\n \"navbar\": {\n \"openMenu\": \"Открыть меню\"\n },\n \"responseError\": {\n \"networkTitle\": \"Нет связи с сервером\",\n \"networkMessage\": \"Проверьте подключение к интернету и попробуйте ещё раз.\",\n \"abortedTitle\": \"Запрос отменён\",\n \"abortedMessage\": \"Запрос был отменён.\",\n \"validationTitle\": \"Проверьте данные\",\n \"validationMessage\": \"Сервер вернул ошибку валидации. Исправьте поля и попробуйте снова.\",\n \"clientTitle\": \"Ошибка запроса\",\n \"clientMessage\": \"Сервер отклонил запрос.\",\n \"serverTitle\": \"Ошибка сервера\",\n \"serverMessage\": \"Произошла ошибка на сервере. Попробуйте ещё раз.\",\n \"unknownTitle\": \"Что-то пошло не так\",\n \"unknownMessage\": \"Не удалось выполнить операцию. Попробуйте ещё раз.\",\n \"retryLabel\": \"Повторить\",\n \"dismissLabel\": \"Скрыть\"\n },\n \"colors\": {\n \"neutral\": \"Нейтральный\",\n \"success\": \"Успех\",\n \"warning\": \"Предупреждение\",\n \"danger\": \"Опасность\",\n \"info\": \"Инфо\",\n \"primary\": \"Primary\",\n \"slate\": \"Сланцевый\",\n \"azure\": \"Лазурный\"\n }\n}\n"],"mappings":""}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrDropdown-DOvHKnih.js","names":[],"sources":["../../../../src/components/GrDropdown/GrDropdown.vue","../../../../src/components/GrDropdown/GrDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\nimport { vClickOutside } from '../../directives'\nimport {\n grDropdownAlignmentClass,\n grDropdownContentClass,\n grDropdownWidthClass,\n type GrDropdownAlign,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport interface GrDropdownProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownAlign\n /** Ширина панели (tailwind-токены `w-*` или `auto`). */\n width?: GrDropdownWidth\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /** Куда телепортировать панель (`body` по умолчанию). */\n teleportTo?: string | HTMLElement\n}\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: 'body',\n})\n\nconst open = ref(false)\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\nconst panelStyle = ref<Record<string, string>>({\n left: '0px',\n top: '0px',\n zIndex: '2147483647',\n})\nlet syncFrame = 0\n\nfunction cancelPanelPositionSync(): void {\n if (typeof window === 'undefined') return\n if (!syncFrame) return\n\n window.cancelAnimationFrame(syncFrame)\n syncFrame = 0\n}\n\nfunction syncPanelPosition(): void {\n if (typeof window === 'undefined') return\n\n const root = rootEl.value\n if (!root) return\n\n const rootRect = root.getBoundingClientRect()\n const left = (() => {\n if (props.align === 'right') return rootRect.right\n if (props.align === 'center') return rootRect.left + (rootRect.width / 2)\n return rootRect.left\n })()\n\n panelStyle.value = {\n left: `${left}px`,\n top: `${rootRect.bottom + 8}px`,\n zIndex: '2147483647',\n }\n}\n\nfunction schedulePanelPositionSync(): void {\n if (typeof window === 'undefined') return\n if (syncFrame) return\n\n syncFrame = window.requestAnimationFrame(() => {\n syncFrame = 0\n\n if (open.value) {\n syncPanelPosition()\n }\n })\n}\n\nfunction bindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.addEventListener('resize', schedulePanelPositionSync)\n window.addEventListener('scroll', schedulePanelPositionSync, true)\n}\n\nfunction unbindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.removeEventListener('resize', schedulePanelPositionSync)\n window.removeEventListener('scroll', schedulePanelPositionSync, true)\n}\n\nfunction toggle(): void {\n open.value = !open.value\n}\n\nfunction close(): void {\n open.value = false\n}\n\nfunction closeOnEscape(e: KeyboardEvent): void {\n if (e.key === 'Escape') close()\n}\n\nwatch(\n open,\n (isOpen) => {\n if (typeof document === 'undefined') return\n\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n cancelPanelPositionSync()\n if (isOpen) document.addEventListener('keydown', closeOnEscape)\n\n if (!isOpen) return\n\n bindPanelPositionListeners()\n syncPanelPosition()\n },\n { immediate: true },\n)\n\nwatch(\n () => props.align,\n () => {\n if (open.value) {\n schedulePanelPositionSync()\n }\n },\n)\n\nonUnmounted(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n cancelPanelPositionSync()\n})\n\nconst widthClass = computed(() => grDropdownWidthClass(props.width))\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => {\n return ['fixed z-50', widthClass.value, grDropdownAlignmentClass(props.align)].filter(Boolean)\n})\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n</script>\n\n<template>\n <div data-ds-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: open, exclude: clickOutsideExclude }\"\n data-ds-dropdown-trigger\n class=\"inline-block max-w-full\"\n @click=\"toggle\"\n >\n <slot name=\"trigger\" :open=\"open\" :toggle=\"toggle\" :close=\"close\" />\n </div>\n\n <teleport :to=\"teleportTo\">\n <transition\n enter-active-class=\"transition ease-out duration-150\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-ds-dropdown-panel\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n >\n <div data-ds-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onUnmounted, ref, watch } from 'vue'\n\nimport { vClickOutside } from '../../directives'\nimport {\n grDropdownAlignmentClass,\n grDropdownContentClass,\n grDropdownWidthClass,\n type GrDropdownAlign,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport interface GrDropdownProps {\n /** Выравнивание панели относительно триггера. */\n align?: GrDropdownAlign\n /** Ширина панели (tailwind-токены `w-*` или `auto`). */\n width?: GrDropdownWidth\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /** Куда телепортировать панель (`body` по умолчанию). */\n teleportTo?: string | HTMLElement\n}\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n align: 'right',\n width: '48',\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: 'body',\n})\n\nconst open = ref(false)\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\nconst panelStyle = ref<Record<string, string>>({\n left: '0px',\n top: '0px',\n zIndex: '2147483647',\n})\nlet syncFrame = 0\n\nfunction cancelPanelPositionSync(): void {\n if (typeof window === 'undefined') return\n if (!syncFrame) return\n\n window.cancelAnimationFrame(syncFrame)\n syncFrame = 0\n}\n\nfunction syncPanelPosition(): void {\n if (typeof window === 'undefined') return\n\n const root = rootEl.value\n if (!root) return\n\n const rootRect = root.getBoundingClientRect()\n const left = (() => {\n if (props.align === 'right') return rootRect.right\n if (props.align === 'center') return rootRect.left + (rootRect.width / 2)\n return rootRect.left\n })()\n\n panelStyle.value = {\n left: `${left}px`,\n top: `${rootRect.bottom + 8}px`,\n zIndex: '2147483647',\n }\n}\n\nfunction schedulePanelPositionSync(): void {\n if (typeof window === 'undefined') return\n if (syncFrame) return\n\n syncFrame = window.requestAnimationFrame(() => {\n syncFrame = 0\n\n if (open.value) {\n syncPanelPosition()\n }\n })\n}\n\nfunction bindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.addEventListener('resize', schedulePanelPositionSync)\n window.addEventListener('scroll', schedulePanelPositionSync, true)\n}\n\nfunction unbindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.removeEventListener('resize', schedulePanelPositionSync)\n window.removeEventListener('scroll', schedulePanelPositionSync, true)\n}\n\nfunction toggle(): void {\n open.value = !open.value\n}\n\nfunction close(): void {\n open.value = false\n}\n\nfunction closeOnEscape(e: KeyboardEvent): void {\n if (e.key === 'Escape') close()\n}\n\nwatch(\n open,\n (isOpen) => {\n if (typeof document === 'undefined') return\n\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n cancelPanelPositionSync()\n if (isOpen) document.addEventListener('keydown', closeOnEscape)\n\n if (!isOpen) return\n\n bindPanelPositionListeners()\n syncPanelPosition()\n },\n { immediate: true },\n)\n\nwatch(\n () => props.align,\n () => {\n if (open.value) {\n schedulePanelPositionSync()\n }\n },\n)\n\nonUnmounted(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n cancelPanelPositionSync()\n})\n\nconst widthClass = computed(() => grDropdownWidthClass(props.width))\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => {\n return ['fixed z-50', widthClass.value, grDropdownAlignmentClass(props.align)].filter(Boolean)\n})\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n</script>\n\n<template>\n <div data-ds-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: open, exclude: clickOutsideExclude }\"\n data-ds-dropdown-trigger\n class=\"inline-block max-w-full\"\n @click=\"toggle\"\n >\n <slot name=\"trigger\" :open=\"open\" :toggle=\"toggle\" :close=\"close\" />\n </div>\n\n <teleport :to=\"teleportTo\">\n <transition\n enter-active-class=\"transition ease-out duration-150\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-ds-dropdown-panel\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n >\n <div data-ds-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrPagination-BNDEqM8_.js","names":[],"sources":["../../../../src/components/GrPagination/GrPagination.vue","../../../../src/components/GrPagination/GrPagination.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrSelect from '../GrSelect/GrSelect.vue'\n\n/**\n * Пропы пагинации.\n *\n * `total` интерпретируется как общее количество элементов; число страниц\n * вычисляется из `total` и `pageSize`. Окно отображаемых номеров — 5.\n */\nexport interface GrPaginationProps {\n page: number\n pageSize: number\n total: number\n pageSizes?: number[]\n}\n\nconst { t } = useGranularityTranslations()\n\nconst props = withDefaults(defineProps<GrPaginationProps>(), {\n pageSizes: () => [10, 20, 50],\n})\n\nconst emit = defineEmits<{\n (e: 'update:page', value: number): void\n (e: 'update:pageSize', value: number): void\n}>()\n\nconst pageCount = computed(() => Math.max(1, Math.ceil(props.total / props.pageSize)))\n\nconst pageSizeModel = computed({\n get: () => String(props.pageSize),\n set: (value: string) => emit('update:pageSize', Number(value)),\n})\n\nconst pageSizeOptions = computed(() =>\n props.pageSizes.map(pageSize => ({\n value: String(pageSize),\n label: String(pageSize),\n })),\n)\n\nconst pages = computed(() => {\n const max = pageCount.value\n const current = props.page\n const windowSize = 5\n const half = Math.floor(windowSize / 2)\n\n let start = Math.max(1, current - half)\n const end = Math.min(max, start + windowSize - 1)\n start = Math.max(1, end - windowSize + 1)\n\n const list: number[] = []\n for (let page = start; page <= end; page += 1)\n list.push(page)\n\n return list\n})\n\nfunction goTo(page: number): void {\n emit('update:page', page)\n}\n\nfunction prev(): void {\n goTo(Math.max(1, props.page - 1))\n}\n\nfunction next(): void {\n goTo(Math.min(pageCount.value, props.page + 1))\n}\n</script>\n\n<template>\n <div\n class=\"flex flex-wrap items-center justify-end gap-3\"\n data-ds-pagination\n role=\"navigation\"\n :aria-label=\"t('gr.pagination.pageSize', 'Pagination')\"\n >\n <div class=\"min-w-[100px]\">\n <GrSelect\n v-model=\"pageSizeModel\"\n :options=\"pageSizeOptions\"\n :aria-label=\"t('gr.pagination.pageSize', 'Page size')\"\n />\n </div>\n\n <GrButton variant=\"ghost\" size=\"sm\" :disabled=\"page <= 1\" @click=\"prev\">\n {{ t('gr.pagination.prev', 'Prev') }}\n </GrButton>\n\n <div class=\"flex items-center gap-1\">\n <button\n v-for=\"pageNumber in pages\"\n :key=\"pageNumber\"\n type=\"button\"\n data-ds-pagination-page\n :aria-current=\"pageNumber === page ? 'page' : undefined\"\n :aria-label=\"`Page ${pageNumber}`\"\n class=\"h-8 min-w-8 px-2 rounded-md text-sm font-600 transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]\"\n :class=\"pageNumber === page ? 'bg-[var(--primary)] text-[var(--primary-fg)]' : 'text-[var(--muted-fg)] hover:bg-[var(--muted)] hover:text-[var(--fg)]'\"\n @click=\"goTo(pageNumber)\"\n >\n {{ pageNumber }}\n </button>\n </div>\n\n <GrButton variant=\"ghost\" size=\"sm\" :disabled=\"page >= pageCount\" @click=\"next\">\n {{ t('gr.pagination.next', 'Next') }}\n </GrButton>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrSelect from '../GrSelect/GrSelect.vue'\n\n/**\n * Пропы пагинации.\n *\n * `total` интерпретируется как общее количество элементов; число страниц\n * вычисляется из `total` и `pageSize`. Окно отображаемых номеров — 5.\n */\nexport interface GrPaginationProps {\n page: number\n pageSize: number\n total: number\n pageSizes?: number[]\n}\n\nconst { t } = useGranularityTranslations()\n\nconst props = withDefaults(defineProps<GrPaginationProps>(), {\n pageSizes: () => [10, 20, 50],\n})\n\nconst emit = defineEmits<{\n (e: 'update:page', value: number): void\n (e: 'update:pageSize', value: number): void\n}>()\n\nconst pageCount = computed(() => Math.max(1, Math.ceil(props.total / props.pageSize)))\n\nconst pageSizeModel = computed({\n get: () => String(props.pageSize),\n set: (value: string) => emit('update:pageSize', Number(value)),\n})\n\nconst pageSizeOptions = computed(() =>\n props.pageSizes.map(pageSize => ({\n value: String(pageSize),\n label: String(pageSize),\n })),\n)\n\nconst pages = computed(() => {\n const max = pageCount.value\n const current = props.page\n const windowSize = 5\n const half = Math.floor(windowSize / 2)\n\n let start = Math.max(1, current - half)\n const end = Math.min(max, start + windowSize - 1)\n start = Math.max(1, end - windowSize + 1)\n\n const list: number[] = []\n for (let page = start; page <= end; page += 1)\n list.push(page)\n\n return list\n})\n\nfunction goTo(page: number): void {\n emit('update:page', page)\n}\n\nfunction prev(): void {\n goTo(Math.max(1, props.page - 1))\n}\n\nfunction next(): void {\n goTo(Math.min(pageCount.value, props.page + 1))\n}\n</script>\n\n<template>\n <div\n class=\"flex flex-wrap items-center justify-end gap-3\"\n data-ds-pagination\n role=\"navigation\"\n :aria-label=\"t('gr.pagination.pageSize', 'Pagination')\"\n >\n <div class=\"min-w-[100px]\">\n <GrSelect\n v-model=\"pageSizeModel\"\n :options=\"pageSizeOptions\"\n :aria-label=\"t('gr.pagination.pageSize', 'Page size')\"\n />\n </div>\n\n <GrButton variant=\"ghost\" size=\"sm\" :disabled=\"page <= 1\" @click=\"prev\">\n {{ t('gr.pagination.prev', 'Prev') }}\n </GrButton>\n\n <div class=\"flex items-center gap-1\">\n <button\n v-for=\"pageNumber in pages\"\n :key=\"pageNumber\"\n type=\"button\"\n data-ds-pagination-page\n :aria-current=\"pageNumber === page ? 'page' : undefined\"\n :aria-label=\"`Page ${pageNumber}`\"\n class=\"h-8 min-w-8 px-2 rounded-md text-sm font-600 transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]\"\n :class=\"pageNumber === page ? 'bg-[var(--primary)] text-[var(--primary-fg)]' : 'text-[var(--muted-fg)] hover:bg-[var(--muted)] hover:text-[var(--fg)]'\"\n @click=\"goTo(pageNumber)\"\n >\n {{ pageNumber }}\n </button>\n </div>\n\n <GrButton variant=\"ghost\" size=\"sm\" :disabled=\"page >= pageCount\" @click=\"next\">\n {{ t('gr.pagination.next', 'Next') }}\n </GrButton>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoBA,MAAM,EAAE,MAAM,4BAA2B;EAEzC,MAAM,QAAQ;EAId,MAAM,OAAO;EAKb,MAAM,YAAY,eAAe,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,QAAQ,MAAM,SAAS,CAAC,CAAA;EAErF,MAAM,gBAAgB,SAAS;GAC7B,WAAW,OAAO,MAAM,SAAS;GACjC,MAAM,UAAkB,KAAK,mBAAmB,OAAO,MAAM,CAAC;GAC/D,CAAA;EAED,MAAM,kBAAkB,eACtB,MAAM,UAAU,KAAI,cAAa;GAC/B,OAAO,OAAO,SAAS;GACvB,OAAO,OAAO,SAAS;GACxB,EAAE,CACL;EAEA,MAAM,QAAQ,eAAe;GAC3B,MAAM,MAAM,UAAU;GACtB,MAAM,UAAU,MAAM;GACtB,MAAM,aAAa;GACnB,MAAM,OAAO,KAAK,MAAM,aAAa,EAAC;GAEtC,IAAI,QAAQ,KAAK,IAAI,GAAG,UAAU,KAAI;GACtC,MAAM,MAAM,KAAK,IAAI,KAAK,QAAQ,aAAa,EAAC;AAChD,WAAQ,KAAK,IAAI,GAAG,MAAM,aAAa,EAAC;GAExC,MAAM,OAAiB,EAAC;AACxB,QAAK,IAAI,OAAO,OAAO,QAAQ,KAAK,QAAQ,EAC1C,MAAK,KAAK,KAAI;AAEhB,UAAO;IACR;EAED,SAAS,KAAK,MAAoB;AAChC,QAAK,eAAe,KAAI;;EAG1B,SAAS,OAAa;AACpB,QAAK,KAAK,IAAI,GAAG,MAAM,OAAO,EAAE,CAAA;;EAGlC,SAAS,OAAa;AACpB,QAAK,KAAK,IAAI,UAAU,OAAO,MAAM,OAAO,EAAE,CAAA;;;uBAK9C,mBAqCM,OAAA;IApCJ,OAAM;IACN,sBAAA;IACA,MAAK;IACJ,cAAY,MAAA,EAAC,CAAA,0BAAA,aAAA;;IAEd,mBAMM,OANN,YAMM,CALJ,YAIE,kBAAA;iBAHS,cAAA;gFAAa,QAAA;KACrB,SAAS,gBAAA;KACT,cAAY,MAAA,EAAC,CAAA,0BAAA,YAAA;;;;;;IAIlB,YAEW,kBAAA;KAFD,SAAQ;KAAQ,MAAK;KAAM,UAAU,QAAA,QAAI;KAAQ,SAAO;;4BAC3B,CAAA,gBAAA,gBAAlC,MAAA,EAAC,CAAA,sBAAA,OAAA,CAAA,EAAA,EAAA,CAAA,CAAA;;;IAGN,mBAcM,OAdN,YAcM,EAAA,UAAA,KAAA,EAbJ,mBAYS,UAAA,MAAA,WAXc,MAAA,QAAd,eAAU;yBADnB,mBAYS,UAAA;MAVN,KAAK;MACN,MAAK;MACL,2BAAA;MACC,gBAAc,eAAe,QAAA,OAAI,SAAY,KAAA;MAC7C,cAAU,QAAU;MACrB,OAAK,eAAA,CAAC,wJACE,eAAe,QAAA,OAAI,iDAAA,wEAAA,CAAA;MAC1B,UAAK,WAAE,KAAK,WAAU;wBAEpB,WAAU,EAAA,IAAA,WAAA;;IAIjB,YAEW,kBAAA;KAFD,SAAQ;KAAQ,MAAK;KAAM,UAAU,QAAA,QAAQ,UAAA;KAAY,SAAO;;4BACnC,CAAA,gBAAA,gBAAlC,MAAA,EAAC,CAAA,sBAAA,OAAA,CAAA,EAAA,EAAA,CAAA,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrSelect-CnHdbPlf.js","names":[],"sources":["../../../../src/components/GrSelect/GrSelect.vue","../../../../src/components/GrSelect/GrSelect.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onUnmounted, ref, watch } from 'vue'\n\nimport GrInput from '../GrInput/GrInput.vue'\nimport { vClickOutside } from '../../directives'\n\nimport {\n defaultBaseClass,\n grSelectLinkNativeLabelClass,\n grSelectLinkNativeOverlayClass,\n grSelectNativeClass,\n grSelectPanelClasses,\n grSelectTriggerClass,\n linkBaseClass,\n type GrSelectModelValue,\n type GrSelectOption,\n type GrSelectOptionGroup,\n type GrSelectOptionOrGroup,\n type GrSelectOptionsView,\n type GrSelectSize,\n type GrSelectUnderline,\n type GrSelectVariant,\n type GrSelectView,\n} from './grSelectStyles'\n\nexport type {\n GrSelectModelValue,\n GrSelectOption,\n GrSelectOptionGroup,\n GrSelectOptionOrGroup,\n GrSelectOptionsView,\n GrSelectSize,\n GrSelectUnderline,\n GrSelectVariant,\n GrSelectView,\n} from './grSelectStyles'\n\n/**\n * Пропсы публичного DS-примитива «Select».\n */\nexport interface GrSelectProps {\n modelValue: GrSelectModelValue\n /** Список опций. Поддерживает плоский массив опций и группы опций (`{ label, options }`). */\n options?: GrSelectOptionOrGroup[]\n disabled?: boolean\n ariaLabel?: string\n view?: GrSelectView\n size?: GrSelectSize\n /** Placeholder (показывается, когда значение не выбрано). */\n placeholder?: string\n /** Multiple selection. */\n multiple?: boolean\n /** Как отображать список опций: нативный `<select>` или кастомная панель. */\n optionsView?: GrSelectOptionsView\n /** Разрешает ввод/выбор значения, которого нет в `options`. */\n allowCustomValue?: boolean\n /** Placeholder для инпута кастомного значения (только в `optionsView=\"panel\"`). */\n customValuePlaceholder?: string\n /** Максимальная высота панели (только в `optionsView=\"panel\"`). */\n dropdownMaxHeight?: number\n /** Закрывать панель после выбора (только в `optionsView=\"panel\"`). */\n closeOnSelect?: boolean\n /** Разрешает очистку выбранного значения. */\n clearable?: boolean\n /** i18n-label для кнопки очистки (`aria-label`). */\n clearLabel?: string\n /**\n * Цвет/вариант ссылки для `view=\"link\"` (аналогично `GrLink`).\n * В `view=\"default\"` не используется.\n */\n variant?: GrSelectVariant\n /**\n * Подчёркивание для `view=\"link\"` (аналогично `GrLink`).\n * В `view=\"default\"` не используется.\n */\n underline?: GrSelectUnderline\n}\n\nconst props = withDefaults(\n defineProps<GrSelectProps>(),\n {\n options: undefined,\n disabled: false,\n ariaLabel: undefined,\n view: 'default',\n size: 'md',\n\n placeholder: undefined,\n multiple: false,\n\n optionsView: 'native',\n allowCustomValue: false,\n customValuePlaceholder: 'Add value…',\n dropdownMaxHeight: 280,\n closeOnSelect: true,\n clearable: false,\n clearLabel: 'Clear',\n variant: 'primary',\n underline: 'auto',\n },\n)\n\nconst baseClassName = computed(() => props.view === 'link' ? linkBaseClass : defaultBaseClass)\n\nconst rootClass = computed(() => props.view === 'link' ? 'relative inline-block align-baseline' : 'relative w-full')\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: GrSelectModelValue): void\n}>()\n\nconst optionsResolved = computed<GrSelectOptionOrGroup[]>(() => props.options ?? [])\n\nfunction isOptionGroup(item: GrSelectOptionOrGroup): item is GrSelectOptionGroup {\n return Array.isArray((item as GrSelectOptionGroup).options)\n}\n\n/** Плоский список всех опций (группы «развёрнуты»). Используется для всех вычислений по значениям. */\nconst flatOptions = computed<GrSelectOption[]>(() => {\n const result: GrSelectOption[] = []\n for (const item of optionsResolved.value) {\n if (isOptionGroup(item)) result.push(...item.options)\n else result.push(item)\n }\n return result\n})\n\nfunction modelToArray(value: GrSelectModelValue): string[] {\n if (Array.isArray(value)) return value\n if (!value) return []\n return [value]\n}\n\nconst modelSingle = computed(() => {\n return Array.isArray(props.modelValue) ? (props.modelValue[0] ?? '') : props.modelValue\n})\n\nconst modelMultiple = computed(() => modelToArray(props.modelValue))\n\nconst selectedValues = computed(() => {\n return props.multiple ? modelMultiple.value : (modelSingle.value ? [modelSingle.value] : [])\n})\n\nconst hasSelection = computed(() => selectedValues.value.length > 0)\n\nconst selectedOptions = computed<GrSelectOption[]>(() => {\n const byValue = new Map(flatOptions.value.map(o => [o.value, o]))\n return selectedValues.value.map((v) => byValue.get(v) ?? { value: v, label: v })\n})\n\nconst hasModelInOptions = computed(() => {\n if (props.multiple) return false\n return flatOptions.value.some((o) => o.value === modelSingle.value)\n})\n\nconst displayLabel = computed(() => {\n if (props.multiple) {\n if (!selectedValues.value.length) return ''\n return selectedValues.value\n .map((v) => flatOptions.value.find((o) => o.value === v)?.label ?? v)\n .join(', ')\n }\n\n return flatOptions.value.find((o) => o.value === modelSingle.value)?.label ?? modelSingle.value\n})\n\nconst displayText = computed(() => {\n if (hasSelection.value) return displayLabel.value\n return props.placeholder ?? ''\n})\n\nconst nativeCustomOptionVisible = computed(() => {\n if (!props.allowCustomValue) return false\n if (props.optionsView !== 'native') return false\n if (props.multiple) return false\n if (!props.options) return false\n if (modelSingle.value === '') return false\n return !hasModelInOptions.value\n})\n\nconst customValue = ref('')\nconst open = ref(false)\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst customInputRef = ref<InstanceType<typeof GrInput> | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\nconst panelStyle = ref<Record<string, string>>({\n left: '0px',\n top: '0px',\n width: '0px',\n zIndex: '2147483647',\n})\n\nfunction syncPanelPosition(): void {\n if (typeof window === 'undefined') return\n\n const root = rootEl.value\n if (!root) return\n\n const rect = root.getBoundingClientRect()\n\n // Для `view='link'` ширина триггера = ширине выбранной опции (`inline-block w-auto`),\n // и без отдельной обработки панель тоже становилась шириной выбранной опции, из-за чего\n // её размер «прыгал» при выборе разных опций. Решение — отдать вычисление ширины браузеру:\n // `width: max-content` (по самому длинному ребёнку — `w-full`-кнопкам с `whitespace-nowrap`),\n // `min-width` равной ширине триггера (чтобы панель не была уже самого триггера).\n // Это чисто CSS-подход — без JS-замеров и ResizeObserver, максимально перформантный.\n if (props.view === 'link') {\n panelStyle.value = {\n left: `${rect.left}px`,\n top: `${rect.bottom + 8}px`,\n width: 'max-content',\n minWidth: `${rect.width}px`,\n zIndex: '2147483647',\n }\n return\n }\n\n panelStyle.value = {\n left: `${rect.left}px`,\n top: `${rect.bottom + 8}px`,\n width: `${rect.width}px`,\n zIndex: '2147483647',\n }\n}\n\nfunction bindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.addEventListener('resize', syncPanelPosition)\n window.addEventListener('scroll', syncPanelPosition, true)\n}\n\nfunction unbindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.removeEventListener('resize', syncPanelPosition)\n window.removeEventListener('scroll', syncPanelPosition, true)\n}\n\nfunction closeDropdown(): void {\n open.value = false\n}\n\nfunction toggleDropdown(): void {\n if (props.disabled) return\n open.value = !open.value\n}\n\nfunction closeOnEscape(e: KeyboardEvent): void {\n if (e.key === 'Escape') closeDropdown()\n}\n\nwatch(\n open,\n async (isOpen) => {\n if (typeof document === 'undefined') return\n\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n\n if (isOpen) document.addEventListener('keydown', closeOnEscape)\n\n if (!isOpen) {\n customValue.value = ''\n return\n }\n\n bindPanelPositionListeners()\n await nextTick()\n syncPanelPosition()\n\n if (props.allowCustomValue) {\n customInputRef.value?.focus()\n }\n },\n { immediate: true },\n)\n\nonUnmounted(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n})\n\nconst panelClasses = computed(() => {\n return grSelectPanelClasses\n})\n\nfunction matchesQuery(option: GrSelectOption, query: string): boolean {\n if (!query) return true\n return option.label.toLowerCase().includes(query) || option.value.toLowerCase().includes(query)\n}\n\n/**\n * Элемент рендера панели: либо заголовок группы, либо опция.\n * Группировка сохраняется, фильтрация по `customValue` скрывает пустые группы.\n */\ntype GrSelectPanelItem =\n | { kind: 'group', label: string, key: string }\n | { kind: 'option', option: GrSelectOption, key: string }\n\nconst panelItems = computed<GrSelectPanelItem[]>(() => {\n const q = props.allowCustomValue ? customValue.value.trim().toLowerCase() : ''\n const items: GrSelectPanelItem[] = []\n\n // Опция для кастомного значения, которого нет в options (single).\n if (props.allowCustomValue && !props.multiple && modelSingle.value !== '' && !hasModelInOptions.value) {\n const custom: GrSelectOption = { value: modelSingle.value, label: modelSingle.value }\n if (matchesQuery(custom, q)) {\n items.push({ kind: 'option', option: custom, key: `__custom__${custom.value}` })\n }\n }\n\n optionsResolved.value.forEach((item, index) => {\n if (isOptionGroup(item)) {\n const matched = item.options.filter((o) => matchesQuery(o, q))\n if (!matched.length) return\n items.push({ kind: 'group', label: item.label, key: `__group__${index}` })\n for (const option of matched) {\n items.push({ kind: 'option', option, key: option.value })\n }\n return\n }\n\n if (matchesQuery(item, q)) {\n items.push({ kind: 'option', option: item, key: item.value })\n }\n })\n\n return items\n})\n\nconst canAddCustom = computed(() => {\n if (!props.allowCustomValue) return false\n if (props.optionsView !== 'panel') return false\n const v = customValue.value.trim()\n if (!v) return false\n\n if (props.multiple) {\n if (selectedValues.value.includes(v)) return false\n return !flatOptions.value.some((o) => o.value === v)\n }\n\n if (v === modelSingle.value) return false\n return !flatOptions.value.some((o) => o.value === v)\n})\n\nfunction emitValue(value: GrSelectModelValue): void {\n emit('update:modelValue', value)\n}\n\nfunction isSelected(value: string): boolean {\n return selectedValues.value.includes(value)\n}\n\nfunction selectValue(value: string): void {\n emitValue(value)\n if (props.closeOnSelect) {\n closeDropdown()\n }\n}\n\nfunction toggleValue(value: string): void {\n if (!props.multiple) {\n selectValue(value)\n return\n }\n\n const next = selectedValues.value.slice()\n const idx = next.indexOf(value)\n if (idx >= 0) {\n next.splice(idx, 1)\n }\n else {\n next.push(value)\n }\n\n emitValue(next)\n if (props.closeOnSelect) {\n closeDropdown()\n }\n}\n\nfunction addCustom(): void {\n const v = customValue.value.trim()\n if (!v) return\n toggleValue(v)\n}\n\nconst showNativeChevron = computed(() => {\n return props.optionsView === 'native' && props.view !== 'link' && !props.multiple\n})\n\nconst nativeClearOptionVisible = computed(() => {\n if (!props.clearable) return false\n if (props.optionsView !== 'native') return false\n if (props.multiple) return false\n if (!props.options) return true\n return !flatOptions.value.some(o => o.value === '')\n})\n\nconst panelClearVisible = computed(() => {\n if (!props.clearable) return false\n if (props.optionsView !== 'panel') return false\n if (props.view === 'link') return false\n return hasSelection.value\n})\n\nconst nativeClassName = computed(() => {\n return grSelectNativeClass({\n view: props.view,\n size: props.size,\n disabled: props.disabled,\n variant: props.variant,\n underline: props.underline,\n showNativeChevron: showNativeChevron.value,\n })\n})\n\n/**\n * `view=\"link\"` в native-режиме: ширина обёртки должна определяться выбранной опцией,\n * а не самой длинной (как делает браузер по умолчанию). Поэтому рендерим прозрачный\n * `<select>`-overlay поверх видимого `<span>` с меткой — overlay принимает клики/клавиатуру,\n * span задаёт ширину компонента в закрытом состоянии.\n */\nconst isLinkNative = computed(() => props.view === 'link' && props.optionsView === 'native')\n\nconst linkNativeLabelClassName = computed(() => grSelectLinkNativeLabelClass({\n size: props.size,\n variant: props.variant,\n underline: props.underline,\n disabled: props.disabled,\n}))\n\nconst linkNativeDisplayText = computed(() => {\n return displayText.value || props.placeholder || '\\u00A0'\n})\n\nconst triggerClassName = computed(() => {\n return grSelectTriggerClass({\n view: props.view,\n optionsView: props.optionsView,\n size: props.size,\n disabled: props.disabled,\n variant: props.variant,\n underline: props.underline,\n })\n})\n\nfunction onChange(e: Event): void {\n const el = e.target as HTMLSelectElement\n\n if (props.multiple) {\n const values = Array.from(el.selectedOptions, o => o.value)\n emit('update:modelValue', values)\n return\n }\n\n emit('update:modelValue', el.value)\n}\n\nfunction clearSelection(): void {\n if (props.disabled) return\n emitValue(props.multiple ? [] : '')\n}\n</script>\n\n<template>\n <div\n v-if=\"optionsView === 'native'\"\n data-ds-select\n :class=\"rootClass\"\n >\n <select\n data-ds-select-native\n :value=\"multiple ? modelMultiple : modelSingle\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n :aria-label=\"ariaLabel\"\n :class=\"isLinkNative ? grSelectLinkNativeOverlayClass : [baseClassName, nativeClassName]\"\n @change=\"onChange\"\n >\n <option v-if=\"nativeClearOptionVisible\" value=\"\" />\n\n <slot>\n <option v-if=\"nativeCustomOptionVisible\" :value=\"modelSingle\">\n {{ modelSingle }}\n </option>\n <template v-for=\"(item, index) in optionsResolved\" :key=\"index\">\n <optgroup v-if=\"isOptionGroup(item)\" :label=\"item.label\">\n <option v-for=\"opt in item.options\" :key=\"opt.value\" :value=\"opt.value\">\n {{ opt.label }}\n </option>\n </optgroup>\n <option v-else :value=\"item.value\">\n {{ item.label }}\n </option>\n </template>\n </slot>\n </select>\n\n <span\n v-if=\"isLinkNative\"\n data-ds-select-link-label\n aria-hidden=\"true\"\n :class=\"linkNativeLabelClassName\"\n >{{ linkNativeDisplayText }}</span>\n\n <span\n v-if=\"showNativeChevron\"\n data-testid=\"ds-select-chevron\"\n class=\"absolute top-1/2 -translate-y-1/2 right-3 text-[var(--muted-fg)] pointer-events-none\"\n >\n <span class=\"i-lucide-chevron-down inline-block h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </div>\n\n <div\n v-else\n ref=\"rootEl\"\n v-click-outside=\"{ handler: closeDropdown, enabled: open, exclude: clickOutsideExclude }\"\n data-ds-select\n :class=\"rootClass\"\n >\n <button\n data-testid=\"ds-select-trigger\"\n data-ds-select-trigger\n type=\"button\"\n :disabled=\"disabled\"\n :aria-label=\"ariaLabel\"\n role=\"combobox\"\n aria-readonly=\"true\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :class=\"[baseClassName, triggerClassName]\"\n @click=\"toggleDropdown\"\n >\n <span class=\"min-w-0 flex-1\">\n <slot\n name=\"value\"\n :selected-options=\"selectedOptions\"\n :selected-values=\"selectedValues\"\n :display-label=\"displayLabel\"\n :placeholder=\"placeholder\"\n :has-selection=\"hasSelection\"\n >\n <span\n class=\"block truncate\"\n :class=\"!hasSelection ? 'text-[var(--muted-fg)]' : ''\"\n >\n {{ displayText }}\n </span>\n </slot>\n </span>\n\n <span\n v-if=\"panelClearVisible\"\n class=\"shrink-0 h-4 w-4\"\n aria-hidden=\"true\"\n />\n\n <span\n v-else\n data-testid=\"ds-select-chevron\"\n class=\"shrink-0 text-[var(--muted-fg)] pointer-events-none\"\n >\n <span class=\"i-lucide-chevron-down inline-block h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </button>\n\n <button\n v-if=\"panelClearVisible\"\n data-testid=\"ds-select-clear\"\n data-ds-select-clear\n type=\"button\"\n class=\"absolute top-1/2 -translate-y-1/2 right-3 h-6 w-6 inline-flex items-center justify-center rounded-md text-[var(--muted-fg)] hover:text-[var(--fg)] hover:bg-[color-mix(in_srgb,var(--muted)_25%,transparent)] disabled:opacity-50\"\n :disabled=\"disabled\"\n :aria-label=\"clearLabel\"\n @click.stop=\"clearSelection\"\n >\n <span class=\"i-lucide-x inline-block h-4 w-4\" aria-hidden=\"true\" />\n </button>\n\n <teleport to=\"body\">\n <transition\n enter-active-class=\"transition ease-out duration-150\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-testid=\"ds-select-panel\"\n data-ds-select-panel\n class=\"fixed w-full\"\n :style=\"panelStyle\"\n >\n <div :class=\"panelClasses\">\n <div v-if=\"allowCustomValue\" class=\"p-2 border-b border-[var(--brd)]\">\n <GrInput\n ref=\"customInputRef\"\n v-model=\"customValue\"\n data-testid=\"ds-select-custom-input\"\n type=\"text\"\n :placeholder=\"customValuePlaceholder\"\n size=\"sm\"\n @keydown.enter.prevent=\"addCustom\"\n />\n </div>\n\n <div\n data-ds-select-listbox\n class=\"p-1 overflow-auto\"\n :style=\"{ maxHeight: `${dropdownMaxHeight}px` }\"\n role=\"listbox\"\n :aria-multiselectable=\"multiple ? 'true' : undefined\"\n >\n <button\n v-if=\"canAddCustom\"\n data-testid=\"ds-select-add-option\"\n data-ds-select-add-option\n type=\"button\"\n class=\"rounded-[10px] px-3 py-2 text-left text-[13px] hover:bg-[color-mix(in_srgb,var(--muted)_30%,transparent)]\" :class=\"[\n view === 'link' ? 'block min-w-full w-max whitespace-nowrap' : 'w-full',\n ]\"\n @click=\"addCustom\"\n >\n Add “{{ customValue.trim() }}”\n </button>\n\n <template v-for=\"item in panelItems\" :key=\"item.key\">\n <div\n v-if=\"item.kind === 'group'\"\n data-ds-select-group-label\n role=\"presentation\"\n class=\"px-3 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-[var(--muted-fg)]\" :class=\"[\n view === 'link' ? 'block min-w-full w-max whitespace-nowrap' : '',\n ]\"\n >\n {{ item.label }}\n </div>\n\n <button\n v-else\n data-ds-select-option\n type=\"button\"\n role=\"option\"\n :aria-selected=\"isSelected(item.option.value) ? 'true' : 'false'\"\n class=\"rounded-[10px] px-3 py-2 text-left text-[13px] hover:bg-[color-mix(in_srgb,var(--muted)_30%,transparent)]\" :class=\"[\n view === 'link' ? 'block min-w-full w-max whitespace-nowrap' : 'w-full',\n ]\"\n @click=\"toggleValue(item.option.value)\"\n >\n <slot name=\"option\" :option=\"item.option\" :selected=\"isSelected(item.option.value)\">\n <span class=\"flex items-center gap-2 min-w-0\">\n <span\n class=\"inline-block h-4 w-4 shrink-0\"\n :class=\"isSelected(item.option.value) ? 'i-lucide-check text-[var(--primary)]' : ''\"\n aria-hidden=\"true\"\n />\n <span class=\"truncate\">{{ item.option.label }}</span>\n </span>\n </slot>\n </button>\n </template>\n </div>\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onUnmounted, ref, watch } from 'vue'\n\nimport GrInput from '../GrInput/GrInput.vue'\nimport { vClickOutside } from '../../directives'\n\nimport {\n defaultBaseClass,\n grSelectLinkNativeLabelClass,\n grSelectLinkNativeOverlayClass,\n grSelectNativeClass,\n grSelectPanelClasses,\n grSelectTriggerClass,\n linkBaseClass,\n type GrSelectModelValue,\n type GrSelectOption,\n type GrSelectOptionGroup,\n type GrSelectOptionOrGroup,\n type GrSelectOptionsView,\n type GrSelectSize,\n type GrSelectUnderline,\n type GrSelectVariant,\n type GrSelectView,\n} from './grSelectStyles'\n\nexport type {\n GrSelectModelValue,\n GrSelectOption,\n GrSelectOptionGroup,\n GrSelectOptionOrGroup,\n GrSelectOptionsView,\n GrSelectSize,\n GrSelectUnderline,\n GrSelectVariant,\n GrSelectView,\n} from './grSelectStyles'\n\n/**\n * Пропсы публичного DS-примитива «Select».\n */\nexport interface GrSelectProps {\n modelValue: GrSelectModelValue\n /** Список опций. Поддерживает плоский массив опций и группы опций (`{ label, options }`). */\n options?: GrSelectOptionOrGroup[]\n disabled?: boolean\n ariaLabel?: string\n view?: GrSelectView\n size?: GrSelectSize\n /** Placeholder (показывается, когда значение не выбрано). */\n placeholder?: string\n /** Multiple selection. */\n multiple?: boolean\n /** Как отображать список опций: нативный `<select>` или кастомная панель. */\n optionsView?: GrSelectOptionsView\n /** Разрешает ввод/выбор значения, которого нет в `options`. */\n allowCustomValue?: boolean\n /** Placeholder для инпута кастомного значения (только в `optionsView=\"panel\"`). */\n customValuePlaceholder?: string\n /** Максимальная высота панели (только в `optionsView=\"panel\"`). */\n dropdownMaxHeight?: number\n /** Закрывать панель после выбора (только в `optionsView=\"panel\"`). */\n closeOnSelect?: boolean\n /** Разрешает очистку выбранного значения. */\n clearable?: boolean\n /** i18n-label для кнопки очистки (`aria-label`). */\n clearLabel?: string\n /**\n * Цвет/вариант ссылки для `view=\"link\"` (аналогично `GrLink`).\n * В `view=\"default\"` не используется.\n */\n variant?: GrSelectVariant\n /**\n * Подчёркивание для `view=\"link\"` (аналогично `GrLink`).\n * В `view=\"default\"` не используется.\n */\n underline?: GrSelectUnderline\n}\n\nconst props = withDefaults(\n defineProps<GrSelectProps>(),\n {\n options: undefined,\n disabled: false,\n ariaLabel: undefined,\n view: 'default',\n size: 'md',\n\n placeholder: undefined,\n multiple: false,\n\n optionsView: 'native',\n allowCustomValue: false,\n customValuePlaceholder: 'Add value…',\n dropdownMaxHeight: 280,\n closeOnSelect: true,\n clearable: false,\n clearLabel: 'Clear',\n variant: 'primary',\n underline: 'auto',\n },\n)\n\nconst baseClassName = computed(() => props.view === 'link' ? linkBaseClass : defaultBaseClass)\n\nconst rootClass = computed(() => props.view === 'link' ? 'relative inline-block align-baseline' : 'relative w-full')\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: GrSelectModelValue): void\n}>()\n\nconst optionsResolved = computed<GrSelectOptionOrGroup[]>(() => props.options ?? [])\n\nfunction isOptionGroup(item: GrSelectOptionOrGroup): item is GrSelectOptionGroup {\n return Array.isArray((item as GrSelectOptionGroup).options)\n}\n\n/** Плоский список всех опций (группы «развёрнуты»). Используется для всех вычислений по значениям. */\nconst flatOptions = computed<GrSelectOption[]>(() => {\n const result: GrSelectOption[] = []\n for (const item of optionsResolved.value) {\n if (isOptionGroup(item)) result.push(...item.options)\n else result.push(item)\n }\n return result\n})\n\nfunction modelToArray(value: GrSelectModelValue): string[] {\n if (Array.isArray(value)) return value\n if (!value) return []\n return [value]\n}\n\nconst modelSingle = computed(() => {\n return Array.isArray(props.modelValue) ? (props.modelValue[0] ?? '') : props.modelValue\n})\n\nconst modelMultiple = computed(() => modelToArray(props.modelValue))\n\nconst selectedValues = computed(() => {\n return props.multiple ? modelMultiple.value : (modelSingle.value ? [modelSingle.value] : [])\n})\n\nconst hasSelection = computed(() => selectedValues.value.length > 0)\n\nconst selectedOptions = computed<GrSelectOption[]>(() => {\n const byValue = new Map(flatOptions.value.map(o => [o.value, o]))\n return selectedValues.value.map((v) => byValue.get(v) ?? { value: v, label: v })\n})\n\nconst hasModelInOptions = computed(() => {\n if (props.multiple) return false\n return flatOptions.value.some((o) => o.value === modelSingle.value)\n})\n\nconst displayLabel = computed(() => {\n if (props.multiple) {\n if (!selectedValues.value.length) return ''\n return selectedValues.value\n .map((v) => flatOptions.value.find((o) => o.value === v)?.label ?? v)\n .join(', ')\n }\n\n return flatOptions.value.find((o) => o.value === modelSingle.value)?.label ?? modelSingle.value\n})\n\nconst displayText = computed(() => {\n if (hasSelection.value) return displayLabel.value\n return props.placeholder ?? ''\n})\n\nconst nativeCustomOptionVisible = computed(() => {\n if (!props.allowCustomValue) return false\n if (props.optionsView !== 'native') return false\n if (props.multiple) return false\n if (!props.options) return false\n if (modelSingle.value === '') return false\n return !hasModelInOptions.value\n})\n\nconst customValue = ref('')\nconst open = ref(false)\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst customInputRef = ref<InstanceType<typeof GrInput> | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\nconst panelStyle = ref<Record<string, string>>({\n left: '0px',\n top: '0px',\n width: '0px',\n zIndex: '2147483647',\n})\n\nfunction syncPanelPosition(): void {\n if (typeof window === 'undefined') return\n\n const root = rootEl.value\n if (!root) return\n\n const rect = root.getBoundingClientRect()\n\n // Для `view='link'` ширина триггера = ширине выбранной опции (`inline-block w-auto`),\n // и без отдельной обработки панель тоже становилась шириной выбранной опции, из-за чего\n // её размер «прыгал» при выборе разных опций. Решение — отдать вычисление ширины браузеру:\n // `width: max-content` (по самому длинному ребёнку — `w-full`-кнопкам с `whitespace-nowrap`),\n // `min-width` равной ширине триггера (чтобы панель не была уже самого триггера).\n // Это чисто CSS-подход — без JS-замеров и ResizeObserver, максимально перформантный.\n if (props.view === 'link') {\n panelStyle.value = {\n left: `${rect.left}px`,\n top: `${rect.bottom + 8}px`,\n width: 'max-content',\n minWidth: `${rect.width}px`,\n zIndex: '2147483647',\n }\n return\n }\n\n panelStyle.value = {\n left: `${rect.left}px`,\n top: `${rect.bottom + 8}px`,\n width: `${rect.width}px`,\n zIndex: '2147483647',\n }\n}\n\nfunction bindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.addEventListener('resize', syncPanelPosition)\n window.addEventListener('scroll', syncPanelPosition, true)\n}\n\nfunction unbindPanelPositionListeners(): void {\n if (typeof window === 'undefined') return\n window.removeEventListener('resize', syncPanelPosition)\n window.removeEventListener('scroll', syncPanelPosition, true)\n}\n\nfunction closeDropdown(): void {\n open.value = false\n}\n\nfunction toggleDropdown(): void {\n if (props.disabled) return\n open.value = !open.value\n}\n\nfunction closeOnEscape(e: KeyboardEvent): void {\n if (e.key === 'Escape') closeDropdown()\n}\n\nwatch(\n open,\n async (isOpen) => {\n if (typeof document === 'undefined') return\n\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n\n if (isOpen) document.addEventListener('keydown', closeOnEscape)\n\n if (!isOpen) {\n customValue.value = ''\n return\n }\n\n bindPanelPositionListeners()\n await nextTick()\n syncPanelPosition()\n\n if (props.allowCustomValue) {\n customInputRef.value?.focus()\n }\n },\n { immediate: true },\n)\n\nonUnmounted(() => {\n if (typeof document === 'undefined') return\n document.removeEventListener('keydown', closeOnEscape)\n unbindPanelPositionListeners()\n})\n\nconst panelClasses = computed(() => {\n return grSelectPanelClasses\n})\n\nfunction matchesQuery(option: GrSelectOption, query: string): boolean {\n if (!query) return true\n return option.label.toLowerCase().includes(query) || option.value.toLowerCase().includes(query)\n}\n\n/**\n * Элемент рендера панели: либо заголовок группы, либо опция.\n * Группировка сохраняется, фильтрация по `customValue` скрывает пустые группы.\n */\ntype GrSelectPanelItem =\n | { kind: 'group', label: string, key: string }\n | { kind: 'option', option: GrSelectOption, key: string }\n\nconst panelItems = computed<GrSelectPanelItem[]>(() => {\n const q = props.allowCustomValue ? customValue.value.trim().toLowerCase() : ''\n const items: GrSelectPanelItem[] = []\n\n // Опция для кастомного значения, которого нет в options (single).\n if (props.allowCustomValue && !props.multiple && modelSingle.value !== '' && !hasModelInOptions.value) {\n const custom: GrSelectOption = { value: modelSingle.value, label: modelSingle.value }\n if (matchesQuery(custom, q)) {\n items.push({ kind: 'option', option: custom, key: `__custom__${custom.value}` })\n }\n }\n\n optionsResolved.value.forEach((item, index) => {\n if (isOptionGroup(item)) {\n const matched = item.options.filter((o) => matchesQuery(o, q))\n if (!matched.length) return\n items.push({ kind: 'group', label: item.label, key: `__group__${index}` })\n for (const option of matched) {\n items.push({ kind: 'option', option, key: option.value })\n }\n return\n }\n\n if (matchesQuery(item, q)) {\n items.push({ kind: 'option', option: item, key: item.value })\n }\n })\n\n return items\n})\n\nconst canAddCustom = computed(() => {\n if (!props.allowCustomValue) return false\n if (props.optionsView !== 'panel') return false\n const v = customValue.value.trim()\n if (!v) return false\n\n if (props.multiple) {\n if (selectedValues.value.includes(v)) return false\n return !flatOptions.value.some((o) => o.value === v)\n }\n\n if (v === modelSingle.value) return false\n return !flatOptions.value.some((o) => o.value === v)\n})\n\nfunction emitValue(value: GrSelectModelValue): void {\n emit('update:modelValue', value)\n}\n\nfunction isSelected(value: string): boolean {\n return selectedValues.value.includes(value)\n}\n\nfunction selectValue(value: string): void {\n emitValue(value)\n if (props.closeOnSelect) {\n closeDropdown()\n }\n}\n\nfunction toggleValue(value: string): void {\n if (!props.multiple) {\n selectValue(value)\n return\n }\n\n const next = selectedValues.value.slice()\n const idx = next.indexOf(value)\n if (idx >= 0) {\n next.splice(idx, 1)\n }\n else {\n next.push(value)\n }\n\n emitValue(next)\n if (props.closeOnSelect) {\n closeDropdown()\n }\n}\n\nfunction addCustom(): void {\n const v = customValue.value.trim()\n if (!v) return\n toggleValue(v)\n}\n\nconst showNativeChevron = computed(() => {\n return props.optionsView === 'native' && props.view !== 'link' && !props.multiple\n})\n\nconst nativeClearOptionVisible = computed(() => {\n if (!props.clearable) return false\n if (props.optionsView !== 'native') return false\n if (props.multiple) return false\n if (!props.options) return true\n return !flatOptions.value.some(o => o.value === '')\n})\n\nconst panelClearVisible = computed(() => {\n if (!props.clearable) return false\n if (props.optionsView !== 'panel') return false\n if (props.view === 'link') return false\n return hasSelection.value\n})\n\nconst nativeClassName = computed(() => {\n return grSelectNativeClass({\n view: props.view,\n size: props.size,\n disabled: props.disabled,\n variant: props.variant,\n underline: props.underline,\n showNativeChevron: showNativeChevron.value,\n })\n})\n\n/**\n * `view=\"link\"` в native-режиме: ширина обёртки должна определяться выбранной опцией,\n * а не самой длинной (как делает браузер по умолчанию). Поэтому рендерим прозрачный\n * `<select>`-overlay поверх видимого `<span>` с меткой — overlay принимает клики/клавиатуру,\n * span задаёт ширину компонента в закрытом состоянии.\n */\nconst isLinkNative = computed(() => props.view === 'link' && props.optionsView === 'native')\n\nconst linkNativeLabelClassName = computed(() => grSelectLinkNativeLabelClass({\n size: props.size,\n variant: props.variant,\n underline: props.underline,\n disabled: props.disabled,\n}))\n\nconst linkNativeDisplayText = computed(() => {\n return displayText.value || props.placeholder || '\\u00A0'\n})\n\nconst triggerClassName = computed(() => {\n return grSelectTriggerClass({\n view: props.view,\n optionsView: props.optionsView,\n size: props.size,\n disabled: props.disabled,\n variant: props.variant,\n underline: props.underline,\n })\n})\n\nfunction onChange(e: Event): void {\n const el = e.target as HTMLSelectElement\n\n if (props.multiple) {\n const values = Array.from(el.selectedOptions, o => o.value)\n emit('update:modelValue', values)\n return\n }\n\n emit('update:modelValue', el.value)\n}\n\nfunction clearSelection(): void {\n if (props.disabled) return\n emitValue(props.multiple ? [] : '')\n}\n</script>\n\n<template>\n <div\n v-if=\"optionsView === 'native'\"\n data-ds-select\n :class=\"rootClass\"\n >\n <select\n data-ds-select-native\n :value=\"multiple ? modelMultiple : modelSingle\"\n :multiple=\"multiple\"\n :disabled=\"disabled\"\n :aria-label=\"ariaLabel\"\n :class=\"isLinkNative ? grSelectLinkNativeOverlayClass : [baseClassName, nativeClassName]\"\n @change=\"onChange\"\n >\n <option v-if=\"nativeClearOptionVisible\" value=\"\" />\n\n <slot>\n <option v-if=\"nativeCustomOptionVisible\" :value=\"modelSingle\">\n {{ modelSingle }}\n </option>\n <template v-for=\"(item, index) in optionsResolved\" :key=\"index\">\n <optgroup v-if=\"isOptionGroup(item)\" :label=\"item.label\">\n <option v-for=\"opt in item.options\" :key=\"opt.value\" :value=\"opt.value\">\n {{ opt.label }}\n </option>\n </optgroup>\n <option v-else :value=\"item.value\">\n {{ item.label }}\n </option>\n </template>\n </slot>\n </select>\n\n <span\n v-if=\"isLinkNative\"\n data-ds-select-link-label\n aria-hidden=\"true\"\n :class=\"linkNativeLabelClassName\"\n >{{ linkNativeDisplayText }}</span>\n\n <span\n v-if=\"showNativeChevron\"\n data-testid=\"ds-select-chevron\"\n class=\"absolute top-1/2 -translate-y-1/2 right-3 text-[var(--muted-fg)] pointer-events-none\"\n >\n <span class=\"i-lucide-chevron-down inline-block h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </div>\n\n <div\n v-else\n ref=\"rootEl\"\n v-click-outside=\"{ handler: closeDropdown, enabled: open, exclude: clickOutsideExclude }\"\n data-ds-select\n :class=\"rootClass\"\n >\n <button\n data-testid=\"ds-select-trigger\"\n data-ds-select-trigger\n type=\"button\"\n :disabled=\"disabled\"\n :aria-label=\"ariaLabel\"\n role=\"combobox\"\n aria-readonly=\"true\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :class=\"[baseClassName, triggerClassName]\"\n @click=\"toggleDropdown\"\n >\n <span class=\"min-w-0 flex-1\">\n <slot\n name=\"value\"\n :selected-options=\"selectedOptions\"\n :selected-values=\"selectedValues\"\n :display-label=\"displayLabel\"\n :placeholder=\"placeholder\"\n :has-selection=\"hasSelection\"\n >\n <span\n class=\"block truncate\"\n :class=\"!hasSelection ? 'text-[var(--muted-fg)]' : ''\"\n >\n {{ displayText }}\n </span>\n </slot>\n </span>\n\n <span\n v-if=\"panelClearVisible\"\n class=\"shrink-0 h-4 w-4\"\n aria-hidden=\"true\"\n />\n\n <span\n v-else\n data-testid=\"ds-select-chevron\"\n class=\"shrink-0 text-[var(--muted-fg)] pointer-events-none\"\n >\n <span class=\"i-lucide-chevron-down inline-block h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </button>\n\n <button\n v-if=\"panelClearVisible\"\n data-testid=\"ds-select-clear\"\n data-ds-select-clear\n type=\"button\"\n class=\"absolute top-1/2 -translate-y-1/2 right-3 h-6 w-6 inline-flex items-center justify-center rounded-md text-[var(--muted-fg)] hover:text-[var(--fg)] hover:bg-[color-mix(in_srgb,var(--muted)_25%,transparent)] disabled:opacity-50\"\n :disabled=\"disabled\"\n :aria-label=\"clearLabel\"\n @click.stop=\"clearSelection\"\n >\n <span class=\"i-lucide-x inline-block h-4 w-4\" aria-hidden=\"true\" />\n </button>\n\n <teleport to=\"body\">\n <transition\n enter-active-class=\"transition ease-out duration-150\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-in duration-100\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-testid=\"ds-select-panel\"\n data-ds-select-panel\n class=\"fixed w-full\"\n :style=\"panelStyle\"\n >\n <div :class=\"panelClasses\">\n <div v-if=\"allowCustomValue\" class=\"p-2 border-b border-[var(--brd)]\">\n <GrInput\n ref=\"customInputRef\"\n v-model=\"customValue\"\n data-testid=\"ds-select-custom-input\"\n type=\"text\"\n :placeholder=\"customValuePlaceholder\"\n size=\"sm\"\n @keydown.enter.prevent=\"addCustom\"\n />\n </div>\n\n <div\n data-ds-select-listbox\n class=\"p-1 overflow-auto\"\n :style=\"{ maxHeight: `${dropdownMaxHeight}px` }\"\n role=\"listbox\"\n :aria-multiselectable=\"multiple ? 'true' : undefined\"\n >\n <button\n v-if=\"canAddCustom\"\n data-testid=\"ds-select-add-option\"\n data-ds-select-add-option\n type=\"button\"\n class=\"rounded-[10px] px-3 py-2 text-left text-[13px] hover:bg-[color-mix(in_srgb,var(--muted)_30%,transparent)]\" :class=\"[\n view === 'link' ? 'block min-w-full w-max whitespace-nowrap' : 'w-full',\n ]\"\n @click=\"addCustom\"\n >\n Add “{{ customValue.trim() }}”\n </button>\n\n <template v-for=\"item in panelItems\" :key=\"item.key\">\n <div\n v-if=\"item.kind === 'group'\"\n data-ds-select-group-label\n role=\"presentation\"\n class=\"px-3 pt-2 pb-1 text-[11px] font-semibold uppercase tracking-wide text-[var(--muted-fg)]\" :class=\"[\n view === 'link' ? 'block min-w-full w-max whitespace-nowrap' : '',\n ]\"\n >\n {{ item.label }}\n </div>\n\n <button\n v-else\n data-ds-select-option\n type=\"button\"\n role=\"option\"\n :aria-selected=\"isSelected(item.option.value) ? 'true' : 'false'\"\n class=\"rounded-[10px] px-3 py-2 text-left text-[13px] hover:bg-[color-mix(in_srgb,var(--muted)_30%,transparent)]\" :class=\"[\n view === 'link' ? 'block min-w-full w-max whitespace-nowrap' : 'w-full',\n ]\"\n @click=\"toggleValue(item.option.value)\"\n >\n <slot name=\"option\" :option=\"item.option\" :selected=\"isSelected(item.option.value)\">\n <span class=\"flex items-center gap-2 min-w-0\">\n <span\n class=\"inline-block h-4 w-4 shrink-0\"\n :class=\"isSelected(item.option.value) ? 'i-lucide-check text-[var(--primary)]' : ''\"\n aria-hidden=\"true\"\n />\n <span class=\"truncate\">{{ item.option.label }}</span>\n </span>\n </slot>\n </button>\n </template>\n </div>\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrToaster-DluJmR5D.js","names":[],"sources":["../../../../src/components/GrToaster/GrToaster.vue","../../../../src/components/GrToaster/GrToaster.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrToaster — DS-примитив области уведомлений (toast).\n *\n * Модель состояния берётся из `useToast` (модульный синглтон), поэтому\n * в приложении предполагается **один активный `GrToaster`** на корень.\n *\n * A11y:\n * - контейнер — `role=\"region\"` с `aria-label` (i18n-проп `regionLabel`);\n * - каждый toast — `role=\"status\"` + `aria-live=\"polite\"` для `info`/`success`\n * и `role=\"alert\"` + `aria-live=\"assertive\"` для `warning`/`danger`\n * (критичные сообщения должны прерывать скринридер).\n *\n * UX:\n * - появление/исчезновение анимируется `TransitionGroup`;\n * - `placement` настраивает угол экрана;\n * - `z-[60]` — выше, чем `GrModal` (`z-50`), чтобы уведомления не перекрывались диалогом.\n */\nimport {computed} from 'vue'\nimport type {Component} from 'vue'\n\nimport {useToast} from '../../composables/useToast'\nimport type {GrToastTone} from '../../composables/useToast'\nimport GrButton from '../GrButton'\nimport GrIcon from '../GrIcon'\nimport {PLACEMENT_CLASS, type GrToasterPlacement} from './grToasterStyles'\n\nimport IconCheck from '~icons/lucide/check-circle'\nimport IconWarning from '~icons/lucide/alert-triangle'\nimport IconError from '~icons/lucide/x-circle'\nimport IconInfo from '~icons/lucide/info'\nimport IconClose from '~icons/lucide/x'\n\nexport type {GrToasterPlacement}\n\ninterface ToneMeta {\n icon: Component\n color: string\n role: 'status' | 'alert'\n live: 'polite' | 'assertive'\n}\n\n// Единый маппинг по tone'у: иконка, цвет, a11y-роль и «напор» live-региона.\n// На уровне модуля — чтобы не пересоздавать объект на каждый рендер.\nconst TONE_META: Record<GrToastTone, ToneMeta> = {\n primary: {icon: IconInfo, color: 'var(--primary)', role: 'status', live: 'polite'},\n neutral: {icon: IconInfo, color: 'var(--muted-fg)', role: 'status', live: 'polite'},\n info: {icon: IconInfo, color: 'var(--ds-info)', role: 'status', live: 'polite'},\n success: {icon: IconCheck, color: 'var(--ds-success)', role: 'status', live: 'polite'},\n warning: {icon: IconWarning, color: 'var(--ds-warning)', role: 'alert', live: 'assertive'},\n danger: {icon: IconError, color: 'var(--ds-danger)', role: 'alert', live: 'assertive'},\n slate: {icon: IconInfo, color: 'var(--ds-slate)', role: 'status', live: 'polite'},\n azure: {icon: IconInfo, color: 'var(--ds-azure)', role: 'status', live: 'polite'},\n}\n\n\nexport interface GrToasterProps {\n /** Угол экрана для стека уведомлений. */\n placement?: GrToasterPlacement\n /** A11y-лейбл кнопки закрытия (i18n). */\n dismissLabel?: string\n /** A11y-лейбл контейнера-региона (i18n). */\n regionLabel?: string\n}\n\nconst props = withDefaults(defineProps<GrToasterProps>(), {\n placement: 'top-right',\n dismissLabel: 'Dismiss',\n regionLabel: 'Notifications',\n})\n\nconst {list, dismiss} = useToast()\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем `teleport`.\nconst isClient = typeof window !== 'undefined'\n\nfunction metaFor(tone: GrToastTone): ToneMeta {\n return TONE_META[tone] ?? TONE_META.info\n}\n\nconst containerClass = computed(() => PLACEMENT_CLASS[props.placement])\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <div\n data-ds-toaster\n role=\"region\"\n :aria-label=\"regionLabel\"\n class=\"fixed z-[60] grid w-[360px] max-w-[calc(100vw-2rem)] gap-3\"\n :class=\"containerClass\"\n >\n <TransitionGroup\n tag=\"div\"\n class=\"grid gap-3\"\n enter-active-class=\"transition duration-200 ease-out\"\n enter-from-class=\"opacity-0 translate-y-2\"\n enter-to-class=\"opacity-100 translate-y-0\"\n leave-active-class=\"transition duration-150 ease-in absolute\"\n leave-from-class=\"opacity-100 translate-y-0\"\n leave-to-class=\"opacity-0 translate-y-2\"\n move-class=\"transition-transform duration-200 ease-out\"\n >\n <div\n v-for=\"toast in list\"\n :key=\"toast.id\"\n data-ds-toast\n :data-tone=\"toast.tone\"\n :role=\"metaFor(toast.tone).role\"\n :aria-live=\"metaFor(toast.tone).live\"\n aria-atomic=\"true\"\n class=\"rounded-[var(--ds-radius-lg)] border border-[var(--brd)] bg-[var(--card)] px-4 py-3 shadow-[var(--ds-shadow-2)]\"\n >\n <div class=\"flex items-start gap-3\">\n <GrIcon size=\"md\" class=\"mt-0.5\" :style=\"{ color: metaFor(toast.tone).color }\" aria-hidden=\"true\">\n <component :is=\"metaFor(toast.tone).icon\" />\n </GrIcon>\n <div class=\"min-w-0 flex-1\">\n <div class=\"text-[13px] font-700\">\n {{ toast.title }}\n </div>\n <div v-if=\"toast.message\" class=\"mt-0.5 text-[13px] text-[var(--muted-fg)]\">\n {{ toast.message }}\n </div>\n </div>\n <GrButton\n variant=\"ghost\"\n size=\"sm\"\n square\n :aria-label=\"dismissLabel\"\n @click=\"dismiss(toast.id)\"\n >\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconClose />\n </GrIcon>\n </GrButton>\n </div>\n </div>\n </TransitionGroup>\n </div>\n </teleport>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrToaster — DS-примитив области уведомлений (toast).\n *\n * Модель состояния берётся из `useToast` (модульный синглтон), поэтому\n * в приложении предполагается **один активный `GrToaster`** на корень.\n *\n * A11y:\n * - контейнер — `role=\"region\"` с `aria-label` (i18n-проп `regionLabel`);\n * - каждый toast — `role=\"status\"` + `aria-live=\"polite\"` для `info`/`success`\n * и `role=\"alert\"` + `aria-live=\"assertive\"` для `warning`/`danger`\n * (критичные сообщения должны прерывать скринридер).\n *\n * UX:\n * - появление/исчезновение анимируется `TransitionGroup`;\n * - `placement` настраивает угол экрана;\n * - `z-[60]` — выше, чем `GrModal` (`z-50`), чтобы уведомления не перекрывались диалогом.\n */\nimport {computed} from 'vue'\nimport type {Component} from 'vue'\n\nimport {useToast} from '../../composables/useToast'\nimport type {GrToastTone} from '../../composables/useToast'\nimport GrButton from '../GrButton'\nimport GrIcon from '../GrIcon'\nimport {PLACEMENT_CLASS, type GrToasterPlacement} from './grToasterStyles'\n\nimport IconCheck from '~icons/lucide/check-circle'\nimport IconWarning from '~icons/lucide/alert-triangle'\nimport IconError from '~icons/lucide/x-circle'\nimport IconInfo from '~icons/lucide/info'\nimport IconClose from '~icons/lucide/x'\n\nexport type {GrToasterPlacement}\n\ninterface ToneMeta {\n icon: Component\n color: string\n role: 'status' | 'alert'\n live: 'polite' | 'assertive'\n}\n\n// Единый маппинг по tone'у: иконка, цвет, a11y-роль и «напор» live-региона.\n// На уровне модуля — чтобы не пересоздавать объект на каждый рендер.\nconst TONE_META: Record<GrToastTone, ToneMeta> = {\n primary: {icon: IconInfo, color: 'var(--primary)', role: 'status', live: 'polite'},\n neutral: {icon: IconInfo, color: 'var(--muted-fg)', role: 'status', live: 'polite'},\n info: {icon: IconInfo, color: 'var(--ds-info)', role: 'status', live: 'polite'},\n success: {icon: IconCheck, color: 'var(--ds-success)', role: 'status', live: 'polite'},\n warning: {icon: IconWarning, color: 'var(--ds-warning)', role: 'alert', live: 'assertive'},\n danger: {icon: IconError, color: 'var(--ds-danger)', role: 'alert', live: 'assertive'},\n slate: {icon: IconInfo, color: 'var(--ds-slate)', role: 'status', live: 'polite'},\n azure: {icon: IconInfo, color: 'var(--ds-azure)', role: 'status', live: 'polite'},\n}\n\n\nexport interface GrToasterProps {\n /** Угол экрана для стека уведомлений. */\n placement?: GrToasterPlacement\n /** A11y-лейбл кнопки закрытия (i18n). */\n dismissLabel?: string\n /** A11y-лейбл контейнера-региона (i18n). */\n regionLabel?: string\n}\n\nconst props = withDefaults(defineProps<GrToasterProps>(), {\n placement: 'top-right',\n dismissLabel: 'Dismiss',\n regionLabel: 'Notifications',\n})\n\nconst {list, dismiss} = useToast()\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем `teleport`.\nconst isClient = typeof window !== 'undefined'\n\nfunction metaFor(tone: GrToastTone): ToneMeta {\n return TONE_META[tone] ?? TONE_META.info\n}\n\nconst containerClass = computed(() => PLACEMENT_CLASS[props.placement])\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <div\n data-ds-toaster\n role=\"region\"\n :aria-label=\"regionLabel\"\n class=\"fixed z-[60] grid w-[360px] max-w-[calc(100vw-2rem)] gap-3\"\n :class=\"containerClass\"\n >\n <TransitionGroup\n tag=\"div\"\n class=\"grid gap-3\"\n enter-active-class=\"transition duration-200 ease-out\"\n enter-from-class=\"opacity-0 translate-y-2\"\n enter-to-class=\"opacity-100 translate-y-0\"\n leave-active-class=\"transition duration-150 ease-in absolute\"\n leave-from-class=\"opacity-100 translate-y-0\"\n leave-to-class=\"opacity-0 translate-y-2\"\n move-class=\"transition-transform duration-200 ease-out\"\n >\n <div\n v-for=\"toast in list\"\n :key=\"toast.id\"\n data-ds-toast\n :data-tone=\"toast.tone\"\n :role=\"metaFor(toast.tone).role\"\n :aria-live=\"metaFor(toast.tone).live\"\n aria-atomic=\"true\"\n class=\"rounded-[var(--ds-radius-lg)] border border-[var(--brd)] bg-[var(--card)] px-4 py-3 shadow-[var(--ds-shadow-2)]\"\n >\n <div class=\"flex items-start gap-3\">\n <GrIcon size=\"md\" class=\"mt-0.5\" :style=\"{ color: metaFor(toast.tone).color }\" aria-hidden=\"true\">\n <component :is=\"metaFor(toast.tone).icon\" />\n </GrIcon>\n <div class=\"min-w-0 flex-1\">\n <div class=\"text-[13px] font-700\">\n {{ toast.title }}\n </div>\n <div v-if=\"toast.message\" class=\"mt-0.5 text-[13px] text-[var(--muted-fg)]\">\n {{ toast.message }}\n </div>\n </div>\n <GrButton\n variant=\"ghost\"\n size=\"sm\"\n square\n :aria-label=\"dismissLabel\"\n @click=\"dismiss(toast.id)\"\n >\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconClose />\n </GrIcon>\n </GrButton>\n </div>\n </div>\n </TransitionGroup>\n </div>\n </teleport>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4CA,MAAM,YAA2C;GAC/C,SAAS;IAAC,MAAM;IAAU,OAAO;IAAkB,MAAM;IAAU,MAAM;IAAS;GAClF,SAAS;IAAC,MAAM;IAAU,OAAO;IAAmB,MAAM;IAAU,MAAM;IAAS;GACnF,MAAM;IAAC,MAAM;IAAU,OAAO;IAAkB,MAAM;IAAU,MAAM;IAAS;GAC/E,SAAS;IAAC,MAAM;IAAW,OAAO;IAAqB,MAAM;IAAU,MAAM;IAAS;GACtF,SAAS;IAAC,MAAM;IAAa,OAAO;IAAqB,MAAM;IAAS,MAAM;IAAY;GAC1F,QAAQ;IAAC,MAAM;IAAW,OAAO;IAAoB,MAAM;IAAS,MAAM;IAAY;GACtF,OAAO;IAAC,MAAM;IAAU,OAAO;IAAmB,MAAM;IAAU,MAAM;IAAS;GACjF,OAAO;IAAC,MAAM;IAAU,OAAO;IAAmB,MAAM;IAAU,MAAM;IAAS;GACnF;EAYA,MAAM,QAAQ;EAMd,MAAM,EAAC,MAAM,YAAW,UAAS;EAGjC,MAAM,WAAW,OAAO,WAAW;EAEnC,SAAS,QAAQ,MAA6B;AAC5C,UAAO,UAAU,SAAS,UAAU;;EAGtC,MAAM,iBAAiB,eAAe,gBAAgB,MAAM,WAAU;;uBAIpE,YAwDW,UAAA;IAxDD,IAAG;IAAQ,UAAQ,CAAG;OAC9B,mBAsDM,OAAA;IArDF,mBAAA;IACA,MAAK;IACJ,cAAY,QAAA;IACb,OAAK,eAAA,CAAC,8DACE,eAAA,MAAc,CAAA;OAExB,YA8CkB,iBAAA;IA7Cd,KAAI;IACJ,OAAM;IACN,sBAAmB;IACnB,oBAAiB;IACjB,kBAAe;IACf,sBAAmB;IACnB,oBAAiB;IACjB,kBAAe;IACf,cAAW;;2BAGY,EAAA,UAAA,KAAA,EADzB,mBAkCM,UAAA,MAAA,WAjCc,MAAA,KAAI,GAAb,UAAK;yBADhB,mBAkCM,OAAA;MAhCD,KAAK,MAAM;MACZ,iBAAA;MACC,aAAW,MAAM;MACjB,MAAM,QAAQ,MAAM,KAAI,CAAE;MAC1B,aAAW,QAAQ,MAAM,KAAI,CAAE;MAChC,eAAY;MACZ,OAAM;SAER,mBAuBM,OAvBN,YAuBM;MAtBJ,YAES,MAAA,eAAA,EAAA;OAFD,MAAK;OAAK,OAAM;OAAU,OAAK,eAAA,EAAA,OAAW,QAAQ,MAAM,KAAI,CAAE,OAAK,CAAA;OAAI,eAAY;;8BAC7C,EAAA,WAAA,EAA5C,YAA4C,wBAA5B,QAAQ,MAAM,KAAI,CAAE,KAAI,CAAA,EAAA,CAAA;;;MAE1C,mBAOM,OAPN,YAOM,CANJ,mBAEM,OAFN,YAEM,gBADD,MAAM,MAAK,EAAA,EAAA,EAEL,MAAM,WAAA,WAAA,EAAjB,mBAEM,OAFN,YAEM,gBADD,MAAM,QAAO,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA,CAAA,CAAA;MAGpB,YAUW,MAAA,iBAAA,EAAA;OATP,SAAQ;OACR,MAAK;OACL,QAAA;OACC,cAAY,QAAA;OACZ,UAAK,WAAE,MAAA,QAAO,CAAC,MAAM,GAAE;;8BAIjB,CAFT,YAES,MAAA,eAAA,EAAA;QAFD,MAAK;QAAK,eAAY;;+BACf,CAAb,YAAa,MAAA,UAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { t as info_default } from "../../../chunks/info-C0bHmdZq.js";
|
|
2
|
-
import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-BV7RBU_0.js";
|
|
3
|
-
import { computed, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeStyle, openBlock, renderSlot, toDisplayString, unref, useId, withCtx } from "vue";
|
|
4
|
-
//#region src/components/GrTooltip/GrTooltip.vue?vue&type=script&setup=true&lang.ts
|
|
5
|
-
var _hoisted_1 = {
|
|
6
|
-
"data-ds-tooltip": "",
|
|
7
|
-
class: "group relative inline-flex"
|
|
8
|
-
};
|
|
9
|
-
//#endregion
|
|
10
|
-
//#region src/components/GrTooltip/GrTooltip.vue
|
|
11
|
-
var GrTooltip_default = /* @__PURE__ */ defineComponent({
|
|
12
|
-
__name: "GrTooltip",
|
|
13
|
-
props: {
|
|
14
|
-
text: {},
|
|
15
|
-
iconColor: { default: "var(--muted-fg)" }
|
|
16
|
-
},
|
|
17
|
-
setup(__props) {
|
|
18
|
-
/**
|
|
19
|
-
* GrTooltip — DS-примитив инлайн-подсказки на hover/focus.
|
|
20
|
-
*
|
|
21
|
-
* По умолчанию триггер — иконка info; можно заменить через слот.
|
|
22
|
-
* A11y: `<span role="tooltip">` связывается с триггером через
|
|
23
|
-
* уникальный `aria-describedby`, чтобы скринридер озвучил подсказку
|
|
24
|
-
* при фокусе.
|
|
25
|
-
*
|
|
26
|
-
* Ограничения: без автопозиционирования/flip — подсказка всегда
|
|
27
|
-
* сверху по центру триггера.
|
|
28
|
-
*/
|
|
29
|
-
const props = __props;
|
|
30
|
-
const tooltipId = `ds-tooltip-${useId()}`;
|
|
31
|
-
const triggerStyle = computed(() => ({ color: props.iconColor }));
|
|
32
|
-
return (_ctx, _cache) => {
|
|
33
|
-
return openBlock(), createElementBlock("span", _hoisted_1, [createElementVNode("span", {
|
|
34
|
-
"data-ds-tooltip-trigger": "",
|
|
35
|
-
"data-testid": "ds-tooltip-trigger",
|
|
36
|
-
tabindex: "0",
|
|
37
|
-
"aria-describedby": tooltipId,
|
|
38
|
-
class: "inline-flex items-center justify-center focus:outline-none",
|
|
39
|
-
style: normalizeStyle(triggerStyle.value)
|
|
40
|
-
}, [renderSlot(_ctx.$slots, "default", {}, () => [createVNode(unref(GrIcon_default), {
|
|
41
|
-
size: "sm",
|
|
42
|
-
"aria-hidden": "true"
|
|
43
|
-
}, {
|
|
44
|
-
default: withCtx(() => [createVNode(unref(info_default))]),
|
|
45
|
-
_: 1
|
|
46
|
-
})])], 4), createElementVNode("span", {
|
|
47
|
-
id: tooltipId,
|
|
48
|
-
role: "tooltip",
|
|
49
|
-
class: "pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 z-10 -translate-x-1/2 whitespace-nowrap rounded-md border border-[var(--brd)] bg-[var(--popover)] px-2 py-1 text-[12px] text-[var(--popover-fg)] opacity-0 shadow-[var(--ds-shadow-1)] transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100"
|
|
50
|
-
}, toDisplayString(__props.text), 1)]);
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
//#endregion
|
|
55
|
-
export { GrTooltip_default as t };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GrTooltip-B7I1AVIC.js","names":[],"sources":["../../../../src/components/GrTooltip/GrTooltip.vue","../../../../src/components/GrTooltip/GrTooltip.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrTooltip — DS-примитив инлайн-подсказки на hover/focus.\n *\n * По умолчанию триггер — иконка info; можно заменить через слот.\n * A11y: `<span role=\"tooltip\">` связывается с триггером через\n * уникальный `aria-describedby`, чтобы скринридер озвучил подсказку\n * при фокусе.\n *\n * Ограничения: без автопозиционирования/flip — подсказка всегда\n * сверху по центру триггера.\n */\nimport { computed, useId } from 'vue'\n\nimport GrIcon from '../GrIcon'\n\nimport IconInfo from '~icons/lucide/info'\n\nexport interface GrTooltipProps {\n text: string\n /** Цвет триггер-иконки (CSS color). По умолчанию — `var(--muted-fg)`. */\n iconColor?: string\n}\n\nconst props = withDefaults(defineProps<GrTooltipProps>(), {\n iconColor: 'var(--muted-fg)',\n})\n\nconst tooltipId = `ds-tooltip-${useId()}`\n\nconst triggerStyle = computed(() => ({ color: props.iconColor }))\n</script>\n\n<template>\n <span data-ds-tooltip class=\"group relative inline-flex\">\n <span\n data-ds-tooltip-trigger\n data-testid=\"ds-tooltip-trigger\"\n tabindex=\"0\"\n :aria-describedby=\"tooltipId\"\n class=\"inline-flex items-center justify-center focus:outline-none\"\n :style=\"triggerStyle\"\n >\n <slot>\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconInfo />\n </GrIcon>\n </slot>\n </span>\n <span\n :id=\"tooltipId\"\n role=\"tooltip\"\n class=\"pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 z-10 -translate-x-1/2 whitespace-nowrap rounded-md border border-[var(--brd)] bg-[var(--popover)] px-2 py-1 text-[12px] text-[var(--popover-fg)] opacity-0 shadow-[var(--ds-shadow-1)] transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100\"\n >\n {{ text }}\n </span>\n </span>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrTooltip — DS-примитив инлайн-подсказки на hover/focus.\n *\n * По умолчанию триггер — иконка info; можно заменить через слот.\n * A11y: `<span role=\"tooltip\">` связывается с триггером через\n * уникальный `aria-describedby`, чтобы скринридер озвучил подсказку\n * при фокусе.\n *\n * Ограничения: без автопозиционирования/flip — подсказка всегда\n * сверху по центру триггера.\n */\nimport { computed, useId } from 'vue'\n\nimport GrIcon from '../GrIcon'\n\nimport IconInfo from '~icons/lucide/info'\n\nexport interface GrTooltipProps {\n text: string\n /** Цвет триггер-иконки (CSS color). По умолчанию — `var(--muted-fg)`. */\n iconColor?: string\n}\n\nconst props = withDefaults(defineProps<GrTooltipProps>(), {\n iconColor: 'var(--muted-fg)',\n})\n\nconst tooltipId = `ds-tooltip-${useId()}`\n\nconst triggerStyle = computed(() => ({ color: props.iconColor }))\n</script>\n\n<template>\n <span data-ds-tooltip class=\"group relative inline-flex\">\n <span\n data-ds-tooltip-trigger\n data-testid=\"ds-tooltip-trigger\"\n tabindex=\"0\"\n :aria-describedby=\"tooltipId\"\n class=\"inline-flex items-center justify-center focus:outline-none\"\n :style=\"triggerStyle\"\n >\n <slot>\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconInfo />\n </GrIcon>\n </slot>\n </span>\n <span\n :id=\"tooltipId\"\n role=\"tooltip\"\n class=\"pointer-events-none absolute bottom-[calc(100%+8px)] left-1/2 z-10 -translate-x-1/2 whitespace-nowrap rounded-md border border-[var(--brd)] bg-[var(--popover)] px-2 py-1 text-[12px] text-[var(--popover-fg)] opacity-0 shadow-[var(--ds-shadow-1)] transition-opacity duration-150 group-hover:opacity-100 group-focus-within:opacity-100\"\n >\n {{ text }}\n </span>\n </span>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwBA,MAAM,QAAQ;EAId,MAAM,YAAY,cAAc,OAAO;EAEvC,MAAM,eAAe,gBAAgB,EAAE,OAAO,MAAM,WAAW,EAAC;;uBAI9D,mBAsBO,QAtBP,YAsBO,CArBL,mBAaO,QAAA;IAZL,2BAAA;IACA,eAAY;IACZ,UAAS;IACR,oBAAkB;IACnB,OAAM;IACL,OAAK,eAAE,aAAA,MAAY;OAEpB,WAIO,KAAA,QAAA,WAAA,EAAA,QAAA,CAHL,YAES,MAAA,eAAA,EAAA;IAFD,MAAK;IAAK,eAAY;;2BAChB,CAAZ,YAAY,MAAA,aAAA,CAAA,CAAA,CAAA;;cAIlB,mBAMO,QAAA;IALJ,IAAI;IACL,MAAK;IACL,OAAM;sBAEH,QAAA,KAAI,EAAA,EAAA,CAAA,CAAA"}
|