@feugene/granularity 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/{adapter-C7fKeUa4.js → adapter-K6zZTzBi.js} +0 -2
- package/dist/chunks/{adapter-C7fKeUa4.js.map → adapter-K6zZTzBi.js.map} +1 -1
- package/dist/chunks/arrow-up-DNXrMoAI.js +0 -2
- package/dist/chunks/classTokens-BPeBXNzu.js +0 -2
- package/dist/chunks/{config-BUGfFjmC.js → config-1I95Zy4V.js} +0 -2
- package/dist/chunks/{config-BUGfFjmC.js.map → config-1I95Zy4V.js.map} +1 -1
- package/dist/chunks/config-2wgwWaAB.js +0 -2
- package/dist/chunks/{config-DBYCntwl.js → config-BA0BWYzs.js} +0 -2
- package/dist/chunks/{config-DBYCntwl.js.map → config-BA0BWYzs.js.map} +1 -1
- package/dist/chunks/{config-dD6Po-Cq.js → config-BCPyma1I.js} +0 -2
- package/dist/chunks/{config-dD6Po-Cq.js.map → config-BCPyma1I.js.map} +1 -1
- package/dist/chunks/{config-CYPU3ztl.js → config-BDlh6iNz.js} +1 -3
- package/dist/chunks/{config-CYPU3ztl.js.map → config-BDlh6iNz.js.map} +1 -1
- package/dist/chunks/config-BKRmlivc.js +0 -2
- package/dist/chunks/{config-CcmeMlic.js → config-BN-B2K4r.js} +1 -3
- package/dist/chunks/{config-CcmeMlic.js.map → config-BN-B2K4r.js.map} +1 -1
- package/dist/chunks/{config-C0b_3LJV.js → config-BNOf_qjD.js} +0 -2
- package/dist/chunks/{config-C0b_3LJV.js.map → config-BNOf_qjD.js.map} +1 -1
- package/dist/chunks/config-BaMO9dQh.js +0 -2
- package/dist/chunks/config-Bv2G0OU6.js +0 -2
- package/dist/chunks/{config-CxCAfXZ1.js → config-BvuQUBtZ.js} +0 -2
- package/dist/chunks/{config-CxCAfXZ1.js.map → config-BvuQUBtZ.js.map} +1 -1
- package/dist/chunks/config-BzZGpWsj.js +0 -2
- package/dist/chunks/{config-KGTIAFD92.js → config-C0j836dC.js} +0 -2
- package/dist/chunks/config-C0j836dC.js.map +1 -0
- package/dist/chunks/{config-D7iuXJbl.js → config-C2iI7_QX.js} +0 -2
- package/dist/chunks/{config-D7iuXJbl.js.map → config-C2iI7_QX.js.map} +1 -1
- package/dist/chunks/{config-BcFOkUhh.js → config-C4AlNm912.js} +1 -3
- package/dist/chunks/config-C4AlNm912.js.map +1 -0
- package/dist/chunks/{config-rFwazRKi.js → config-C5SJXHQ4.js} +0 -2
- package/dist/chunks/{config-rFwazRKi.js.map → config-C5SJXHQ4.js.map} +1 -1
- package/dist/chunks/config-C6SBJxcH.js +0 -2
- package/dist/chunks/{config-BzQ4S4Hb.js → config-CByfsV-z2.js} +0 -2
- package/dist/chunks/config-CByfsV-z2.js.map +1 -0
- package/dist/chunks/{config-rxFL-6yF2.js → config-CM7nbATU2.js} +0 -2
- package/dist/chunks/{config-rxFL-6yF2.js.map → config-CM7nbATU2.js.map} +1 -1
- package/dist/chunks/config-CMZE2fu0.js +0 -2
- package/dist/chunks/config-CU_CBd0k.js +0 -2
- package/dist/chunks/{config-BhvNm4Pp.js → config-CUgvsjZx.js} +0 -2
- package/dist/chunks/{config-BhvNm4Pp.js.map → config-CUgvsjZx.js.map} +1 -1
- package/dist/chunks/{config-DxqMXzNV2.js → config-CWvHiaqr2.js} +0 -2
- package/dist/chunks/{config-DxqMXzNV2.js.map → config-CWvHiaqr2.js.map} +1 -1
- package/dist/chunks/{config-CdAx6ify2.js → config-CgAY2WP9.js} +0 -2
- package/dist/chunks/config-CgAY2WP9.js.map +1 -0
- package/dist/chunks/{config-D1gSaT52.js → config-Cgc-D1K4.js} +0 -2
- package/dist/chunks/{config-D1gSaT52.js.map → config-Cgc-D1K4.js.map} +1 -1
- package/dist/chunks/{config-cn6knwud.js → config-D19pyP4D.js} +0 -2
- package/dist/chunks/{config-cn6knwud.js.map → config-D19pyP4D.js.map} +1 -1
- package/dist/chunks/{config-ug8O8epd.js → config-DCQO6H6h.js} +0 -2
- package/dist/chunks/{config-ug8O8epd.js.map → config-DCQO6H6h.js.map} +1 -1
- package/dist/chunks/{config-BXffa3ta.js → config-DEv4m-ZP.js} +0 -2
- package/dist/chunks/{config-BXffa3ta.js.map → config-DEv4m-ZP.js.map} +1 -1
- package/dist/chunks/config-DFRYOcrP.js +0 -2
- package/dist/chunks/{config-DlLE49_I.js → config-DTpwUHgF.js} +0 -2
- package/dist/chunks/{config-DlLE49_I.js.map → config-DTpwUHgF.js.map} +1 -1
- package/dist/chunks/{config-C2JKq8-2.js → config-DUtUkSzc.js} +1 -2
- package/dist/chunks/config-DUtUkSzc.js.map +1 -0
- package/dist/chunks/config-DW_RqmUp.js +0 -2
- package/dist/chunks/{config-CJeyaUTp.js → config-Da90XGsi.js} +0 -2
- package/dist/chunks/{config-CJeyaUTp.js.map → config-Da90XGsi.js.map} +1 -1
- package/dist/chunks/{config-CJbjLC5X.js → config-DgRJlF00.js} +0 -2
- package/dist/chunks/{config-CJbjLC5X.js.map → config-DgRJlF00.js.map} +1 -1
- package/dist/chunks/config-Dkq0HeLe.js +0 -2
- package/dist/chunks/{config-DwB5-qdP2.js → config-DmI1IQvI2.js} +0 -2
- package/dist/chunks/{config-DwB5-qdP2.js.map → config-DmI1IQvI2.js.map} +1 -1
- package/dist/chunks/{config-BRU5PR8_.js → config-Dnu4VuO0.js} +0 -2
- package/dist/chunks/{config-BRU5PR8_.js.map → config-Dnu4VuO0.js.map} +1 -1
- package/dist/chunks/config-DxqpV-KM.js +0 -2
- package/dist/chunks/config-TyzU6gLf.js +0 -2
- package/dist/chunks/{config-Bv5Dok4j.js → config-XwI6t8cn.js} +0 -2
- package/dist/chunks/{config-Bv5Dok4j.js.map → config-XwI6t8cn.js.map} +1 -1
- package/dist/chunks/{config-DvTUDLT1.js → config-bpQYM5O-.js} +0 -2
- package/dist/chunks/{config-DvTUDLT1.js.map → config-bpQYM5O-.js.map} +1 -1
- package/dist/chunks/{config-BbtK511H.js → config-etXh7Bsr2.js} +0 -2
- package/dist/chunks/config-etXh7Bsr2.js.map +1 -0
- package/dist/chunks/{config-BhubOeci.js → config-fCcRwjIB.js} +0 -2
- package/dist/chunks/{config-BhubOeci.js.map → config-fCcRwjIB.js.map} +1 -1
- package/dist/chunks/{config-D7tRu8u3.js → config-nfOMJXVs.js} +0 -2
- package/dist/chunks/{config-D7tRu8u3.js.map → config-nfOMJXVs.js.map} +1 -1
- package/dist/chunks/{config-BcpRsZTe.js → config-qJXIIY1E.js} +0 -2
- package/dist/chunks/{config-BcpRsZTe.js.map → config-qJXIIY1E.js.map} +1 -1
- package/dist/chunks/{config-Dzz9P-GV2.js → config-r6hzn2Bn2.js} +0 -2
- package/dist/chunks/{config-Dzz9P-GV2.js.map → config-r6hzn2Bn2.js.map} +1 -1
- package/dist/chunks/config-rQlbnEKn.js +0 -2
- package/dist/chunks/dialogShared-BtXUk6Zc.js +0 -2
- package/dist/chunks/{en-BMjJZttK.js → en-BeJa78lP.js} +0 -2
- package/dist/chunks/{en-BMjJZttK.js.map → en-BeJa78lP.js.map} +1 -1
- package/dist/chunks/{es-Cu_RlgIr.js → es-BPqm7rLm.js} +3 -5
- package/dist/chunks/{es-Cu_RlgIr.js.map → es-BPqm7rLm.js.map} +1 -1
- package/dist/chunks/{es-EYCf8G_1.js → es-axYOwwWD.js} +0 -2
- package/dist/chunks/{es-EYCf8G_1.js.map → es-axYOwwWD.js.map} +1 -1
- package/dist/chunks/{fileValidation-CgjTGoUx.js → fileValidation-CwJA8Vmn.js} +0 -2
- package/dist/chunks/{fileValidation-CgjTGoUx.js.map → fileValidation-CwJA8Vmn.js.map} +1 -1
- package/dist/chunks/grBadgeStyles-pqqbVgLk.js +0 -2
- package/dist/chunks/grButtonStyles-BxZW2x0-.js +0 -2
- package/dist/chunks/{grDropdownStyles-DQfLh-bp.js → grDropdownStyles-DMp7RrI9.js} +0 -2
- package/dist/chunks/{grDropdownStyles-DQfLh-bp.js.map → grDropdownStyles-DMp7RrI9.js.map} +1 -1
- package/dist/chunks/{grLoadingStyles-CERsxyk9.js → grLoadingStyles-CrxZHFL0.js} +0 -2
- package/dist/chunks/{grLoadingStyles-CERsxyk9.js.map → grLoadingStyles-CrxZHFL0.js.map} +1 -1
- package/dist/chunks/grModalStyles-Dv2NXBKi.js +0 -2
- package/dist/chunks/{grSelectStyles-C1zNEkV7.js → grSelectStyles-B7doeAQp.js} +0 -2
- package/dist/chunks/{grSelectStyles-C1zNEkV7.js.map → grSelectStyles-B7doeAQp.js.map} +1 -1
- package/dist/chunks/{granularityI18n-BEWP9aJs.js → granularityI18n-GCqUz_lo.js} +1 -3
- package/dist/chunks/{granularityI18n-BEWP9aJs.js.map → granularityI18n-GCqUz_lo.js.map} +1 -1
- package/dist/chunks/info-C0bHmdZq.js +0 -2
- package/dist/chunks/loader-circle-B2rWDk5u.js +0 -2
- package/dist/chunks/{ru-DKswMSdd.js → ru-Dqh-2C00.js} +0 -2
- package/dist/chunks/{ru-DKswMSdd.js.map → ru-Dqh-2C00.js.map} +1 -1
- package/dist/chunks/safelist-BF822K15.js +0 -2
- package/dist/chunks/safelist-BY7z8fOl.js +0 -2
- package/dist/chunks/{shared-Bvjkhhm2.js → shared-buYOkZSv.js} +33 -35
- package/dist/chunks/{shared-Bvjkhhm2.js.map → shared-buYOkZSv.js.map} +1 -1
- package/dist/chunks/transition-mJ3PZCHH.js +0 -2
- package/dist/chunks/x-Pa6C2hwi.js +0 -2
- package/dist/chunks/x-circle-DQSlBLmX.js +0 -2
- package/dist/components/GrAlert/chunks/GrAlert-BjerGcU8.js +0 -2
- package/dist/components/GrAvatar/chunks/GrAvatar-BjnPKNAL.js +0 -2
- package/dist/components/GrBadge/chunks/GrBadge-wuIb4_2K.js +0 -2
- package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-CxtamOZ-.js +0 -2
- package/dist/components/GrBottomNav/chunks/GrBottomNav-CsmQ7mTJ.js +0 -2
- package/dist/components/GrButton/chunks/GrButton-BmGdp8-4.js +0 -2
- package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CBj4tpms.js +0 -2
- package/dist/components/GrCard/chunks/GrCard-xtDcXBr7.js +0 -2
- package/dist/components/GrCheckbox/chunks/GrCheckbox-Bt3d7ckE.js +0 -2
- package/dist/components/GrCollapse/chunks/GrCollapse-HU20VTVn.js +0 -2
- package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DjGOX9Hd.js +0 -2
- package/dist/components/GrDataTable/chunks/GrDataTable-QDOJWmdY.js +0 -2
- package/dist/components/GrDialog/chunks/GrDialog-gObmaVEl.js +0 -2
- package/dist/components/GrDrawer/chunks/GrDrawer-BJL_gTxI.js +0 -2
- package/dist/components/GrDropdown/chunks/{GrDropdown-DVTU32T_.js → GrDropdown-BkACCXdp.js} +2 -4
- package/dist/components/GrDropdown/chunks/{GrDropdown-DVTU32T_.js.map → GrDropdown-BkACCXdp.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-fePQRcgh.js → GrDropdownMenu-BEenXrJw.js} +1 -3
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-fePQRcgh.js.map → GrDropdownMenu-BEenXrJw.js.map} +1 -1
- package/dist/components/GrDropdownMenu/index.js +2 -2
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-Bs8d3tgb.js → GrEmptyState-BLbMJFW-.js} +0 -2
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-Bs8d3tgb.js.map → GrEmptyState-BLbMJFW-.js.map} +1 -1
- package/dist/components/GrEmptyState/index.js +2 -2
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-DVv8yXpl.js → GrFileUpload-u01j9S0t.js} +1 -3
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-DVv8yXpl.js.map → GrFileUpload-u01j9S0t.js.map} +1 -1
- package/dist/components/GrFileUpload/index.js +3 -3
- package/dist/components/GrFormField/chunks/{GrFormField-BzezYcS8.js → GrFormField-C6PfAs4u.js} +0 -2
- package/dist/components/GrFormField/chunks/{GrFormField-BzezYcS8.js.map → GrFormField-C6PfAs4u.js.map} +1 -1
- package/dist/components/GrFormField/index.js +2 -2
- package/dist/components/GrFormFile/chunks/{GrFormFile-DtZOypJW.js → GrFormFile-DdM8Bc2B.js} +2 -4
- package/dist/components/GrFormFile/chunks/{GrFormFile-DtZOypJW.js.map → GrFormFile-DdM8Bc2B.js.map} +1 -1
- package/dist/components/GrFormFile/index.js +2 -2
- package/dist/components/GrFormSection/chunks/{GrFormSection-BIPB1RIk.js → GrFormSection-5djEaQZQ.js} +0 -2
- package/dist/components/GrFormSection/chunks/{GrFormSection-BIPB1RIk.js.map → GrFormSection-5djEaQZQ.js.map} +1 -1
- package/dist/components/GrFormSection/index.js +2 -2
- package/dist/components/GrIcon/chunks/GrIcon-BV7RBU_0.js +0 -2
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-fn8ilJTA.js → GrImageViewer-CjSnohW7.js} +0 -2
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-fn8ilJTA.js.map → GrImageViewer-CjSnohW7.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +2 -2
- package/dist/components/GrInput/chunks/{GrInput-DLLRrH1A.js → GrInput-ghxaTf6d.js} +0 -2
- package/dist/components/GrInput/chunks/{GrInput-DLLRrH1A.js.map → GrInput-ghxaTf6d.js.map} +1 -1
- package/dist/components/GrInput/index.js +2 -2
- package/dist/components/GrInputTag/chunks/{GrInputTag-CzrrBxgU.js → GrInputTag-B0x4U0Yk.js} +1 -3
- package/dist/components/GrInputTag/chunks/{GrInputTag-CzrrBxgU.js.map → GrInputTag-B0x4U0Yk.js.map} +1 -1
- package/dist/components/GrInputTag/index.js +2 -2
- package/dist/components/GrLink/chunks/{GrLink-Dhkid3Mp.js → GrLink-BbN7R3iP.js} +1 -3
- package/dist/components/GrLink/chunks/{GrLink-Dhkid3Mp.js.map → GrLink-BbN7R3iP.js.map} +1 -1
- package/dist/components/GrLink/index.js +2 -2
- package/dist/components/GrList/chunks/{GrList-CjgeVjhY.js → GrList--Ib4zLNw.js} +0 -2
- package/dist/components/GrList/chunks/{GrList-CjgeVjhY.js.map → GrList--Ib4zLNw.js.map} +1 -1
- package/dist/components/GrList/index.js +2 -2
- package/dist/components/GrLoading/chunks/{GrLoading-DihGX3ol.js → GrLoading-C3QZKwE-.js} +1 -3
- package/dist/components/GrLoading/chunks/{GrLoading-DihGX3ol.js.map → GrLoading-C3QZKwE-.js.map} +1 -1
- package/dist/components/GrLoading/index.js +2 -2
- package/dist/components/GrModal/chunks/GrModal-gvfvlp7k.js +0 -2
- package/dist/components/GrModal/index.js +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-CQOAfO6y.js → GrNavbar-nIyuiVj1.js} +1 -3
- package/dist/components/GrNavbar/chunks/{GrNavbar-CQOAfO6y.js.map → GrNavbar-nIyuiVj1.js.map} +1 -1
- package/dist/components/GrNavbar/index.js +2 -2
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-CyHgUotG.js → GrNumberInput-B0mPLjdv.js} +1 -3
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-CyHgUotG.js.map → GrNumberInput-B0mPLjdv.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-C5cxRJsF.js → GrPagination-BSTO6flk.js} +2 -4
- package/dist/components/GrPagination/chunks/{GrPagination-C5cxRJsF.js.map → GrPagination-BSTO6flk.js.map} +1 -1
- package/dist/components/GrPagination/index.js +2 -2
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-C9wAAFxR.js → GrProgressBar-MvMnzsJl.js} +1 -3
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-C9wAAFxR.js.map → GrProgressBar-MvMnzsJl.js.map} +1 -1
- package/dist/components/GrProgressBar/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-Cfq9bvL3.js → GrPromptDialog-DKhbN6ji.js} +2 -4
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-Cfq9bvL3.js.map → GrPromptDialog-DKhbN6ji.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +2 -2
- package/dist/components/GrRadio/chunks/{GrRadio-B_t_ZNVl.js → GrRadio-BxBs3WHq.js} +1 -3
- package/dist/components/GrRadio/chunks/{GrRadio-B_t_ZNVl.js.map → GrRadio-BxBs3WHq.js.map} +1 -1
- package/dist/components/GrRadio/index.js +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CVlgpUBr.js → GrRadioGroup-CEAfJQ6A.js} +1 -3
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CVlgpUBr.js.map → GrRadioGroup-CEAfJQ6A.js.map} +1 -1
- package/dist/components/GrRadioGroup/index.js +2 -2
- package/dist/components/GrSegmented/chunks/{GrSegmented-BPl1koHc.js → GrSegmented-Bwn2qOY4.js} +1 -3
- package/dist/components/GrSegmented/chunks/{GrSegmented-BPl1koHc.js.map → GrSegmented-Bwn2qOY4.js.map} +1 -1
- package/dist/components/GrSegmented/index.js +2 -2
- package/dist/components/GrSelect/chunks/{GrSelect-aVqUL-1F.js → GrSelect-9wRWAu2R.js} +3 -5
- package/dist/components/GrSelect/chunks/{GrSelect-aVqUL-1F.js.map → GrSelect-9wRWAu2R.js.map} +1 -1
- package/dist/components/GrSelect/index.js +2 -2
- package/dist/components/GrSidebar/chunks/{GrSidebar-DVucgcfV.js → GrSidebar-CSZ3RpFB.js} +0 -2
- package/dist/components/GrSidebar/chunks/{GrSidebar-DVucgcfV.js.map → GrSidebar-CSZ3RpFB.js.map} +1 -1
- package/dist/components/GrSidebar/index.js +2 -2
- package/dist/components/GrSkeleton/chunks/{GrSkeleton-CDTvCSoH.js → GrSkeleton-DKXkqWDa.js} +0 -2
- package/dist/components/GrSkeleton/chunks/{GrSkeleton-CDTvCSoH.js.map → GrSkeleton-DKXkqWDa.js.map} +1 -1
- package/dist/components/GrSkeleton/index.js +2 -2
- package/dist/components/GrSwitch/chunks/{GrSwitch-Bnamgqb2.js → GrSwitch-CdBxwV3k.js} +1 -3
- package/dist/components/GrSwitch/chunks/{GrSwitch-Bnamgqb2.js.map → GrSwitch-CdBxwV3k.js.map} +1 -1
- package/dist/components/GrSwitch/index.js +2 -2
- package/dist/components/GrTable/chunks/GrTable-CyQ9uw8A.js +0 -2
- package/dist/components/GrTable/index.js +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-CiGmcmvm.js → GrTabs-BpF8AAUz.js} +0 -2
- package/dist/components/GrTabs/chunks/{GrTabs-CiGmcmvm.js.map → GrTabs-BpF8AAUz.js.map} +1 -1
- package/dist/components/GrTabs/index.js +2 -2
- package/dist/components/GrTextarea/chunks/{GrTextarea-VBSc6A7D.js → GrTextarea-DFS9ZkrA.js} +1 -3
- package/dist/components/GrTextarea/chunks/{GrTextarea-VBSc6A7D.js.map → GrTextarea-DFS9ZkrA.js.map} +1 -1
- package/dist/components/GrTextarea/index.js +2 -2
- package/dist/components/GrToaster/chunks/{GrToaster-I1e-zCpf.js → GrToaster-3Mf0Moxt.js} +1 -3
- package/dist/components/GrToaster/chunks/{GrToaster-I1e-zCpf.js.map → GrToaster-3Mf0Moxt.js.map} +1 -1
- package/dist/components/GrToaster/index.js +2 -2
- package/dist/components/GrTooltip/chunks/{GrTooltip-CrV1gI_c.js → GrTooltip-BvmsukLW.js} +0 -2
- package/dist/components/GrTooltip/chunks/{GrTooltip-CrV1gI_c.js.map → GrTooltip-BvmsukLW.js.map} +1 -1
- package/dist/components/GrTooltip/index.js +2 -2
- package/dist/components/GrTree/chunks/{GrTree-Dlev9oBd.js → GrTree-C2kN-O4Q.js} +0 -2
- package/dist/components/GrTree/chunks/{GrTree-Dlev9oBd.js.map → GrTree-C2kN-O4Q.js.map} +1 -1
- package/dist/components/GrTree/index.js +2 -2
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DN6XFjOD.js → GrTreeSelect-Da-CpRqm.js} +5 -7
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DN6XFjOD.js.map → GrTreeSelect-Da-CpRqm.js.map} +1 -1
- package/dist/components/GrTreeSelect/index.js +2 -2
- package/dist/composables/useTheme.js +0 -2
- package/dist/composables/useToast.js +0 -2
- package/dist/directives/autofocus.js +55 -0
- package/dist/directives/autofocus.js.map +1 -0
- package/dist/directives/autosize.js +117 -0
- package/dist/directives/autosize.js.map +1 -0
- package/dist/directives/clickOutside.js +96 -0
- package/dist/directives/clickOutside.js.map +1 -0
- package/dist/directives/dropzone.js +164 -0
- package/dist/directives/dropzone.js.map +1 -0
- package/dist/directives/hotkey.js +138 -0
- package/dist/directives/hotkey.js.map +1 -0
- package/dist/directives/index.js +6 -1
- package/dist/directives/loading.js +163 -0
- package/dist/directives/loading.js.map +1 -0
- package/dist/fileValidation/index.js +1 -1
- package/dist/granular-provider-node.js +2 -4
- package/dist/granular-provider.js +1 -3
- package/dist/i18n/all.js +1 -3
- package/dist/i18n/index.js +2 -2
- package/dist/index.js +71 -66
- package/dist/types/src/components/GrLink/grLinkStyles.d.ts +1 -1
- package/dist/vue/index.js +0 -2
- package/package.json +25 -1
- package/dist/chunks/config-BbtK511H.js.map +0 -1
- package/dist/chunks/config-BcFOkUhh.js.map +0 -1
- package/dist/chunks/config-BzQ4S4Hb.js.map +0 -1
- package/dist/chunks/config-C2JKq8-2.js.map +0 -1
- package/dist/chunks/config-CdAx6ify2.js.map +0 -1
- package/dist/chunks/config-KGTIAFD92.js.map +0 -1
- package/dist/chunks/directives-Cuib0yOO.js +0 -728
- package/dist/chunks/directives-Cuib0yOO.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrImageViewer-fn8ilJTA.js","names":["$slots"],"sources":["../../../../src/components/GrImageViewer/GrImageViewer.vue","../../../../src/components/GrImageViewer/GrImageViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\n/**\n * Usage:\n *\n * <GrImageViewer\n * v-model=\"open\"\n * :url-list=\"images\"\n * :initial-index=\"0\"\n * show-progress\n * hide-on-click-modal\n * />\n */\nconst props = withDefaults(\n defineProps<{\n modelValue: boolean\n urlList: string[]\n initialIndex?: number\n zoomRate?: number\n minScale?: number\n maxScale?: number\n hideOnClickModal?: boolean\n closeOnPressEscape?: boolean\n showProgress?: boolean\n showZoomValue?: boolean\n zIndex?: number\n /** i18n: aria-label кнопки закрытия. */\n closeLabel?: string\n /** i18n: aria-label кнопки «предыдущее изображение». */\n prevLabel?: string\n /** i18n: aria-label кнопки «следующее изображение». */\n nextLabel?: string\n /** i18n: aria-label кнопки «увеличить». */\n zoomInLabel?: string\n /** i18n: aria-label кнопки «уменьшить». */\n zoomOutLabel?: string\n /** i18n: aria-label кнопки «сбросить масштаб». */\n resetZoomLabel?: string\n /** i18n: aria-label кнопки «повернуть влево». */\n rotateLeftLabel?: string\n /** i18n: aria-label кнопки «повернуть вправо». */\n rotateRightLabel?: string\n /** i18n: текст в пустом состоянии (нет изображений). */\n emptyText?: string\n }>(),\n {\n initialIndex: 0,\n zoomRate: 1.2,\n minScale: 0.5,\n maxScale: 5,\n hideOnClickModal: false,\n closeOnPressEscape: true,\n showProgress: false,\n showZoomValue: true,\n zIndex: undefined,\n closeLabel: 'Close image viewer',\n prevLabel: 'Previous image',\n nextLabel: 'Next image',\n zoomInLabel: 'Zoom in',\n zoomOutLabel: 'Zoom out',\n resetZoomLabel: 'Reset zoom',\n rotateLeftLabel: 'Rotate left',\n rotateRightLabel: 'Rotate right',\n emptyText: 'No image',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'close'): void\n (e: 'switch', newIndex: number): void\n (e: 'rotate', deg: number): void\n}>()\n\ntype GrImageViewerToolbarActions = {\n close: () => void\n prev: () => void\n next: () => void\n zoomIn: () => void\n zoomOut: () => void\n reset: () => void\n rotateLeft: () => void\n rotateRight: () => void\n}\n\nconst DEFAULT_Z_INDEX = 2000\nconst TRAILING_ZERO_DECIMAL_RE = /\\.0$/\n\nconst open = computed(() => props.modelValue)\nconst total = computed(() => props.urlList.length)\nconst hasImages = computed(() => total.value > 0)\n\nconst currentIndex = ref(0)\nconst scale = ref(1)\nconst rotation = ref(0)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\n\nconst currentUrl = computed(() => {\n if (!hasImages.value) {\n return undefined\n }\n\n return props.urlList[currentIndex.value]\n})\n\nconst displayIndex = computed(() => {\n if (!hasImages.value) {\n return 0\n }\n\n return currentIndex.value + 1\n})\n\nconst viewerStyle = computed(() => ({\n zIndex: String(Number.isFinite(props.zIndex) ? props.zIndex : DEFAULT_Z_INDEX),\n}))\n\nconst imageStyle = computed(() => ({\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value}) rotate(${rotation.value}deg)`,\n}))\n\nconst zoomValueText = computed(() => {\n const zoomPercent = scale.value * 100\n\n if (Number.isInteger(zoomPercent)) {\n return String(zoomPercent)\n }\n\n return zoomPercent.toFixed(1).replace(TRAILING_ZERO_DECIMAL_RE, '')\n})\n\nfunction normalizeIndex(value: number): number {\n if (!hasImages.value) {\n return 0\n }\n\n const normalized = Number.isFinite(value) ? Math.trunc(value) : 0\n\n return ((normalized % total.value) + total.value) % total.value\n}\n\nfunction resetTransform(): void {\n scale.value = 1\n rotation.value = 0\n offsetX.value = 0\n offsetY.value = 0\n}\n\nfunction setIndex(nextIndex: number, options?: { emitSwitch?: boolean }): void {\n const normalizedIndex = normalizeIndex(nextIndex)\n\n if (normalizedIndex === currentIndex.value) {\n return\n }\n\n currentIndex.value = normalizedIndex\n resetTransform()\n\n if (options?.emitSwitch !== false) {\n emit('switch', normalizedIndex)\n }\n}\n\nfunction syncIndexFromInitial(): void {\n if (!hasImages.value) {\n currentIndex.value = 0\n return\n }\n\n currentIndex.value = normalizeIndex(props.initialIndex)\n resetTransform()\n}\n\nfunction preloadAt(index: number): void {\n const url = props.urlList[index]\n\n if (!url) {\n return\n }\n\n const image = new Image()\n image.decoding = 'async'\n image.src = url\n}\n\nfunction closeViewer(): void {\n emit('update:modelValue', false)\n emit('close')\n}\n\nfunction prev(): void {\n setIndex(currentIndex.value - 1)\n}\n\nfunction next(): void {\n setIndex(currentIndex.value + 1)\n}\n\nfunction zoomIn(): void {\n scale.value = Math.min(props.maxScale, Number((scale.value * props.zoomRate).toFixed(4)))\n}\n\nfunction zoomOut(): void {\n scale.value = Math.max(props.minScale, Number((scale.value / props.zoomRate).toFixed(4)))\n}\n\nfunction rotateLeft(): void {\n rotation.value -= 90\n emit('rotate', rotation.value)\n}\n\nfunction rotateRight(): void {\n rotation.value += 90\n emit('rotate', rotation.value)\n}\n\nconst toolbarActions: GrImageViewerToolbarActions = {\n close: closeViewer,\n prev,\n next,\n zoomIn,\n zoomOut,\n reset: resetTransform,\n rotateLeft,\n rotateRight,\n}\n\nfunction onBackdropClick(): void {\n if (!props.hideOnClickModal) {\n return\n }\n\n closeViewer()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'Escape':\n if (!props.closeOnPressEscape) {\n return\n }\n\n event.preventDefault()\n closeViewer()\n return\n\n case 'ArrowLeft':\n event.preventDefault()\n prev()\n return\n\n case 'ArrowRight':\n event.preventDefault()\n next()\n return\n\n case '+':\n case '=':\n case 'Add':\n event.preventDefault()\n zoomIn()\n return\n\n case '-':\n case '_':\n case 'Subtract':\n event.preventDefault()\n zoomOut()\n return\n\n case '0':\n event.preventDefault()\n resetTransform()\n break\n\n default:\n }\n}\n\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (!isOpen) {\n return\n }\n\n syncIndexFromInitial()\n },\n { immediate: true },\n)\n\nwatch(\n () => props.initialIndex,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n)\n\nwatch(\n () => props.urlList,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n { deep: true },\n)\n\nwatch(\n currentIndex,\n (index) => {\n if (!hasImages.value || total.value < 2) {\n return\n }\n\n preloadAt(normalizeIndex(index - 1))\n preloadAt(normalizeIndex(index + 1))\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <teleport to=\"body\">\n <TransitionRoot :show=\"open\" as=\"template\">\n <Dialog\n as=\"div\"\n class=\"fixed inset-0\"\n :style=\"viewerStyle\"\n role=\"dialog\"\n aria-modal=\"true\"\n :static=\"true\"\n @keydown=\"onKeydown\"\n >\n <div class=\"fixed inset-0 overflow-hidden\">\n <TransitionChild\n as=\"template\"\n enter=\"duration-150 ease-out\"\n enter-from=\"opacity-0\"\n enter-to=\"opacity-100\"\n leave=\"duration-120 ease-in\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n data-ds-image-viewer-overlay\n class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\"\n aria-hidden=\"true\"\n @click=\"onBackdropClick\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n enter=\"duration-180 ease-out\"\n enter-from=\"opacity-0 scale-98\"\n enter-to=\"opacity-100 scale-100\"\n leave=\"duration-130 ease-in\"\n leave-from=\"opacity-100 scale-100\"\n leave-to=\"opacity-0 scale-98\"\n >\n <DialogPanel\n data-ds-image-viewer-panel\n class=\"relative z-10 h-full w-full outline-none\"\n tabindex=\"-1\"\n >\n <div class=\"pointer-events-none absolute inset-x-0 top-0 z-30 px-3 py-3 sm:px-6\">\n <div class=\"pointer-events-auto flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-2\">\n <div\n v-if=\"showProgress\"\n data-ds-image-viewer-progress\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-600 text-white/95 sm:text-sm\"\n >\n {{ displayIndex }} / {{ total }}\n </div>\n\n <div\n v-if=\"showZoomValue\"\n data-ds-image-viewer-zoom-value\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-700 text-white/95 sm:text-sm\"\n >\n {{ zoomValueText }}%\n </div>\n </div>\n\n <button\n type=\"button\"\n data-ds-image-viewer-close\n :aria-label=\"closeLabel\"\n class=\"h-11 w-11 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"closeViewer\"\n >\n <span aria-hidden=\"true\" class=\"text-lg leading-none\">✕</span>\n </button>\n </div>\n </div>\n\n <div class=\"relative z-10 h-full w-full flex items-center justify-center px-16 py-16 sm:px-24 sm:py-20\">\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-prev\n :aria-label=\"prevLabel\"\n class=\"absolute left-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:left-6\"\n @click=\"prev\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">‹</span>\n </button>\n\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-next\n :aria-label=\"nextLabel\"\n class=\"absolute right-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:right-6\"\n @click=\"next\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">›</span>\n </button>\n\n <div class=\"h-full w-full flex items-center justify-center\">\n <img\n v-if=\"currentUrl\"\n data-ds-image-viewer-image\n :src=\"currentUrl\"\n alt=\"\"\n draggable=\"false\"\n class=\"max-h-full max-w-full select-none object-contain will-change-transform transition-transform duration-150 ease-out\"\n :style=\"imageStyle\"\n >\n\n <div\n v-else\n class=\"rounded-[var(--ds-radius-xl)] border border-white/20 bg-black/25 px-4 py-3 text-sm text-white/80\"\n >\n {{ emptyText }}\n </div>\n </div>\n </div>\n\n <div class=\"pointer-events-none absolute inset-x-0 bottom-0 z-30 px-3 pb-3 sm:px-6 sm:pb-6\">\n <div class=\"pointer-events-auto mx-auto w-full max-w-max\">\n <slot\n name=\"toolbar\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n >\n <div class=\"rounded-full border border-white/20 bg-black/35 p-1 backdrop-blur-sm flex items-center gap-1\">\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-out\n :aria-label=\"zoomOutLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomOut\"\n >\n −\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-reset\n :aria-label=\"resetZoomLabel\"\n class=\"h-11 min-w-11 px-3 flex items-center justify-center rounded-full text-xs font-700 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"resetTransform\"\n >\n 100%\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-in\n :aria-label=\"zoomInLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomIn\"\n >\n +\n </button>\n\n <template v-if=\"$slots['toolbar-actions']\">\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <slot\n name=\"toolbar-actions\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n />\n\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n </template>\n\n <div v-else class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-left\n :aria-label=\"rotateLeftLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateLeft\"\n >\n ↺\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-right\n :aria-label=\"rotateRightLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateRight\"\n >\n ↻\n </button>\n </div>\n </slot>\n </div>\n </div>\n </DialogPanel>\n </TransitionChild>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\n/**\n * Usage:\n *\n * <GrImageViewer\n * v-model=\"open\"\n * :url-list=\"images\"\n * :initial-index=\"0\"\n * show-progress\n * hide-on-click-modal\n * />\n */\nconst props = withDefaults(\n defineProps<{\n modelValue: boolean\n urlList: string[]\n initialIndex?: number\n zoomRate?: number\n minScale?: number\n maxScale?: number\n hideOnClickModal?: boolean\n closeOnPressEscape?: boolean\n showProgress?: boolean\n showZoomValue?: boolean\n zIndex?: number\n /** i18n: aria-label кнопки закрытия. */\n closeLabel?: string\n /** i18n: aria-label кнопки «предыдущее изображение». */\n prevLabel?: string\n /** i18n: aria-label кнопки «следующее изображение». */\n nextLabel?: string\n /** i18n: aria-label кнопки «увеличить». */\n zoomInLabel?: string\n /** i18n: aria-label кнопки «уменьшить». */\n zoomOutLabel?: string\n /** i18n: aria-label кнопки «сбросить масштаб». */\n resetZoomLabel?: string\n /** i18n: aria-label кнопки «повернуть влево». */\n rotateLeftLabel?: string\n /** i18n: aria-label кнопки «повернуть вправо». */\n rotateRightLabel?: string\n /** i18n: текст в пустом состоянии (нет изображений). */\n emptyText?: string\n }>(),\n {\n initialIndex: 0,\n zoomRate: 1.2,\n minScale: 0.5,\n maxScale: 5,\n hideOnClickModal: false,\n closeOnPressEscape: true,\n showProgress: false,\n showZoomValue: true,\n zIndex: undefined,\n closeLabel: 'Close image viewer',\n prevLabel: 'Previous image',\n nextLabel: 'Next image',\n zoomInLabel: 'Zoom in',\n zoomOutLabel: 'Zoom out',\n resetZoomLabel: 'Reset zoom',\n rotateLeftLabel: 'Rotate left',\n rotateRightLabel: 'Rotate right',\n emptyText: 'No image',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'close'): void\n (e: 'switch', newIndex: number): void\n (e: 'rotate', deg: number): void\n}>()\n\ntype GrImageViewerToolbarActions = {\n close: () => void\n prev: () => void\n next: () => void\n zoomIn: () => void\n zoomOut: () => void\n reset: () => void\n rotateLeft: () => void\n rotateRight: () => void\n}\n\nconst DEFAULT_Z_INDEX = 2000\nconst TRAILING_ZERO_DECIMAL_RE = /\\.0$/\n\nconst open = computed(() => props.modelValue)\nconst total = computed(() => props.urlList.length)\nconst hasImages = computed(() => total.value > 0)\n\nconst currentIndex = ref(0)\nconst scale = ref(1)\nconst rotation = ref(0)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\n\nconst currentUrl = computed(() => {\n if (!hasImages.value) {\n return undefined\n }\n\n return props.urlList[currentIndex.value]\n})\n\nconst displayIndex = computed(() => {\n if (!hasImages.value) {\n return 0\n }\n\n return currentIndex.value + 1\n})\n\nconst viewerStyle = computed(() => ({\n zIndex: String(Number.isFinite(props.zIndex) ? props.zIndex : DEFAULT_Z_INDEX),\n}))\n\nconst imageStyle = computed(() => ({\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value}) rotate(${rotation.value}deg)`,\n}))\n\nconst zoomValueText = computed(() => {\n const zoomPercent = scale.value * 100\n\n if (Number.isInteger(zoomPercent)) {\n return String(zoomPercent)\n }\n\n return zoomPercent.toFixed(1).replace(TRAILING_ZERO_DECIMAL_RE, '')\n})\n\nfunction normalizeIndex(value: number): number {\n if (!hasImages.value) {\n return 0\n }\n\n const normalized = Number.isFinite(value) ? Math.trunc(value) : 0\n\n return ((normalized % total.value) + total.value) % total.value\n}\n\nfunction resetTransform(): void {\n scale.value = 1\n rotation.value = 0\n offsetX.value = 0\n offsetY.value = 0\n}\n\nfunction setIndex(nextIndex: number, options?: { emitSwitch?: boolean }): void {\n const normalizedIndex = normalizeIndex(nextIndex)\n\n if (normalizedIndex === currentIndex.value) {\n return\n }\n\n currentIndex.value = normalizedIndex\n resetTransform()\n\n if (options?.emitSwitch !== false) {\n emit('switch', normalizedIndex)\n }\n}\n\nfunction syncIndexFromInitial(): void {\n if (!hasImages.value) {\n currentIndex.value = 0\n return\n }\n\n currentIndex.value = normalizeIndex(props.initialIndex)\n resetTransform()\n}\n\nfunction preloadAt(index: number): void {\n const url = props.urlList[index]\n\n if (!url) {\n return\n }\n\n const image = new Image()\n image.decoding = 'async'\n image.src = url\n}\n\nfunction closeViewer(): void {\n emit('update:modelValue', false)\n emit('close')\n}\n\nfunction prev(): void {\n setIndex(currentIndex.value - 1)\n}\n\nfunction next(): void {\n setIndex(currentIndex.value + 1)\n}\n\nfunction zoomIn(): void {\n scale.value = Math.min(props.maxScale, Number((scale.value * props.zoomRate).toFixed(4)))\n}\n\nfunction zoomOut(): void {\n scale.value = Math.max(props.minScale, Number((scale.value / props.zoomRate).toFixed(4)))\n}\n\nfunction rotateLeft(): void {\n rotation.value -= 90\n emit('rotate', rotation.value)\n}\n\nfunction rotateRight(): void {\n rotation.value += 90\n emit('rotate', rotation.value)\n}\n\nconst toolbarActions: GrImageViewerToolbarActions = {\n close: closeViewer,\n prev,\n next,\n zoomIn,\n zoomOut,\n reset: resetTransform,\n rotateLeft,\n rotateRight,\n}\n\nfunction onBackdropClick(): void {\n if (!props.hideOnClickModal) {\n return\n }\n\n closeViewer()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'Escape':\n if (!props.closeOnPressEscape) {\n return\n }\n\n event.preventDefault()\n closeViewer()\n return\n\n case 'ArrowLeft':\n event.preventDefault()\n prev()\n return\n\n case 'ArrowRight':\n event.preventDefault()\n next()\n return\n\n case '+':\n case '=':\n case 'Add':\n event.preventDefault()\n zoomIn()\n return\n\n case '-':\n case '_':\n case 'Subtract':\n event.preventDefault()\n zoomOut()\n return\n\n case '0':\n event.preventDefault()\n resetTransform()\n break\n\n default:\n }\n}\n\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (!isOpen) {\n return\n }\n\n syncIndexFromInitial()\n },\n { immediate: true },\n)\n\nwatch(\n () => props.initialIndex,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n)\n\nwatch(\n () => props.urlList,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n { deep: true },\n)\n\nwatch(\n currentIndex,\n (index) => {\n if (!hasImages.value || total.value < 2) {\n return\n }\n\n preloadAt(normalizeIndex(index - 1))\n preloadAt(normalizeIndex(index + 1))\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <teleport to=\"body\">\n <TransitionRoot :show=\"open\" as=\"template\">\n <Dialog\n as=\"div\"\n class=\"fixed inset-0\"\n :style=\"viewerStyle\"\n role=\"dialog\"\n aria-modal=\"true\"\n :static=\"true\"\n @keydown=\"onKeydown\"\n >\n <div class=\"fixed inset-0 overflow-hidden\">\n <TransitionChild\n as=\"template\"\n enter=\"duration-150 ease-out\"\n enter-from=\"opacity-0\"\n enter-to=\"opacity-100\"\n leave=\"duration-120 ease-in\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n data-ds-image-viewer-overlay\n class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\"\n aria-hidden=\"true\"\n @click=\"onBackdropClick\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n enter=\"duration-180 ease-out\"\n enter-from=\"opacity-0 scale-98\"\n enter-to=\"opacity-100 scale-100\"\n leave=\"duration-130 ease-in\"\n leave-from=\"opacity-100 scale-100\"\n leave-to=\"opacity-0 scale-98\"\n >\n <DialogPanel\n data-ds-image-viewer-panel\n class=\"relative z-10 h-full w-full outline-none\"\n tabindex=\"-1\"\n >\n <div class=\"pointer-events-none absolute inset-x-0 top-0 z-30 px-3 py-3 sm:px-6\">\n <div class=\"pointer-events-auto flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-2\">\n <div\n v-if=\"showProgress\"\n data-ds-image-viewer-progress\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-600 text-white/95 sm:text-sm\"\n >\n {{ displayIndex }} / {{ total }}\n </div>\n\n <div\n v-if=\"showZoomValue\"\n data-ds-image-viewer-zoom-value\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-700 text-white/95 sm:text-sm\"\n >\n {{ zoomValueText }}%\n </div>\n </div>\n\n <button\n type=\"button\"\n data-ds-image-viewer-close\n :aria-label=\"closeLabel\"\n class=\"h-11 w-11 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"closeViewer\"\n >\n <span aria-hidden=\"true\" class=\"text-lg leading-none\">✕</span>\n </button>\n </div>\n </div>\n\n <div class=\"relative z-10 h-full w-full flex items-center justify-center px-16 py-16 sm:px-24 sm:py-20\">\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-prev\n :aria-label=\"prevLabel\"\n class=\"absolute left-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:left-6\"\n @click=\"prev\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">‹</span>\n </button>\n\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-next\n :aria-label=\"nextLabel\"\n class=\"absolute right-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:right-6\"\n @click=\"next\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">›</span>\n </button>\n\n <div class=\"h-full w-full flex items-center justify-center\">\n <img\n v-if=\"currentUrl\"\n data-ds-image-viewer-image\n :src=\"currentUrl\"\n alt=\"\"\n draggable=\"false\"\n class=\"max-h-full max-w-full select-none object-contain will-change-transform transition-transform duration-150 ease-out\"\n :style=\"imageStyle\"\n >\n\n <div\n v-else\n class=\"rounded-[var(--ds-radius-xl)] border border-white/20 bg-black/25 px-4 py-3 text-sm text-white/80\"\n >\n {{ emptyText }}\n </div>\n </div>\n </div>\n\n <div class=\"pointer-events-none absolute inset-x-0 bottom-0 z-30 px-3 pb-3 sm:px-6 sm:pb-6\">\n <div class=\"pointer-events-auto mx-auto w-full max-w-max\">\n <slot\n name=\"toolbar\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n >\n <div class=\"rounded-full border border-white/20 bg-black/35 p-1 backdrop-blur-sm flex items-center gap-1\">\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-out\n :aria-label=\"zoomOutLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomOut\"\n >\n −\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-reset\n :aria-label=\"resetZoomLabel\"\n class=\"h-11 min-w-11 px-3 flex items-center justify-center rounded-full text-xs font-700 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"resetTransform\"\n >\n 100%\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-in\n :aria-label=\"zoomInLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomIn\"\n >\n +\n </button>\n\n <template v-if=\"$slots['toolbar-actions']\">\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <slot\n name=\"toolbar-actions\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n />\n\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n </template>\n\n <div v-else class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-left\n :aria-label=\"rotateLeftLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateLeft\"\n >\n ↺\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-right\n :aria-label=\"rotateRightLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateRight\"\n >\n ↻\n </button>\n </div>\n </slot>\n </div>\n </div>\n </DialogPanel>\n </TransitionChild>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrImageViewer-CjSnohW7.js","names":["$slots"],"sources":["../../../../src/components/GrImageViewer/GrImageViewer.vue","../../../../src/components/GrImageViewer/GrImageViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\n/**\n * Usage:\n *\n * <GrImageViewer\n * v-model=\"open\"\n * :url-list=\"images\"\n * :initial-index=\"0\"\n * show-progress\n * hide-on-click-modal\n * />\n */\nconst props = withDefaults(\n defineProps<{\n modelValue: boolean\n urlList: string[]\n initialIndex?: number\n zoomRate?: number\n minScale?: number\n maxScale?: number\n hideOnClickModal?: boolean\n closeOnPressEscape?: boolean\n showProgress?: boolean\n showZoomValue?: boolean\n zIndex?: number\n /** i18n: aria-label кнопки закрытия. */\n closeLabel?: string\n /** i18n: aria-label кнопки «предыдущее изображение». */\n prevLabel?: string\n /** i18n: aria-label кнопки «следующее изображение». */\n nextLabel?: string\n /** i18n: aria-label кнопки «увеличить». */\n zoomInLabel?: string\n /** i18n: aria-label кнопки «уменьшить». */\n zoomOutLabel?: string\n /** i18n: aria-label кнопки «сбросить масштаб». */\n resetZoomLabel?: string\n /** i18n: aria-label кнопки «повернуть влево». */\n rotateLeftLabel?: string\n /** i18n: aria-label кнопки «повернуть вправо». */\n rotateRightLabel?: string\n /** i18n: текст в пустом состоянии (нет изображений). */\n emptyText?: string\n }>(),\n {\n initialIndex: 0,\n zoomRate: 1.2,\n minScale: 0.5,\n maxScale: 5,\n hideOnClickModal: false,\n closeOnPressEscape: true,\n showProgress: false,\n showZoomValue: true,\n zIndex: undefined,\n closeLabel: 'Close image viewer',\n prevLabel: 'Previous image',\n nextLabel: 'Next image',\n zoomInLabel: 'Zoom in',\n zoomOutLabel: 'Zoom out',\n resetZoomLabel: 'Reset zoom',\n rotateLeftLabel: 'Rotate left',\n rotateRightLabel: 'Rotate right',\n emptyText: 'No image',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'close'): void\n (e: 'switch', newIndex: number): void\n (e: 'rotate', deg: number): void\n}>()\n\ntype GrImageViewerToolbarActions = {\n close: () => void\n prev: () => void\n next: () => void\n zoomIn: () => void\n zoomOut: () => void\n reset: () => void\n rotateLeft: () => void\n rotateRight: () => void\n}\n\nconst DEFAULT_Z_INDEX = 2000\nconst TRAILING_ZERO_DECIMAL_RE = /\\.0$/\n\nconst open = computed(() => props.modelValue)\nconst total = computed(() => props.urlList.length)\nconst hasImages = computed(() => total.value > 0)\n\nconst currentIndex = ref(0)\nconst scale = ref(1)\nconst rotation = ref(0)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\n\nconst currentUrl = computed(() => {\n if (!hasImages.value) {\n return undefined\n }\n\n return props.urlList[currentIndex.value]\n})\n\nconst displayIndex = computed(() => {\n if (!hasImages.value) {\n return 0\n }\n\n return currentIndex.value + 1\n})\n\nconst viewerStyle = computed(() => ({\n zIndex: String(Number.isFinite(props.zIndex) ? props.zIndex : DEFAULT_Z_INDEX),\n}))\n\nconst imageStyle = computed(() => ({\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value}) rotate(${rotation.value}deg)`,\n}))\n\nconst zoomValueText = computed(() => {\n const zoomPercent = scale.value * 100\n\n if (Number.isInteger(zoomPercent)) {\n return String(zoomPercent)\n }\n\n return zoomPercent.toFixed(1).replace(TRAILING_ZERO_DECIMAL_RE, '')\n})\n\nfunction normalizeIndex(value: number): number {\n if (!hasImages.value) {\n return 0\n }\n\n const normalized = Number.isFinite(value) ? Math.trunc(value) : 0\n\n return ((normalized % total.value) + total.value) % total.value\n}\n\nfunction resetTransform(): void {\n scale.value = 1\n rotation.value = 0\n offsetX.value = 0\n offsetY.value = 0\n}\n\nfunction setIndex(nextIndex: number, options?: { emitSwitch?: boolean }): void {\n const normalizedIndex = normalizeIndex(nextIndex)\n\n if (normalizedIndex === currentIndex.value) {\n return\n }\n\n currentIndex.value = normalizedIndex\n resetTransform()\n\n if (options?.emitSwitch !== false) {\n emit('switch', normalizedIndex)\n }\n}\n\nfunction syncIndexFromInitial(): void {\n if (!hasImages.value) {\n currentIndex.value = 0\n return\n }\n\n currentIndex.value = normalizeIndex(props.initialIndex)\n resetTransform()\n}\n\nfunction preloadAt(index: number): void {\n const url = props.urlList[index]\n\n if (!url) {\n return\n }\n\n const image = new Image()\n image.decoding = 'async'\n image.src = url\n}\n\nfunction closeViewer(): void {\n emit('update:modelValue', false)\n emit('close')\n}\n\nfunction prev(): void {\n setIndex(currentIndex.value - 1)\n}\n\nfunction next(): void {\n setIndex(currentIndex.value + 1)\n}\n\nfunction zoomIn(): void {\n scale.value = Math.min(props.maxScale, Number((scale.value * props.zoomRate).toFixed(4)))\n}\n\nfunction zoomOut(): void {\n scale.value = Math.max(props.minScale, Number((scale.value / props.zoomRate).toFixed(4)))\n}\n\nfunction rotateLeft(): void {\n rotation.value -= 90\n emit('rotate', rotation.value)\n}\n\nfunction rotateRight(): void {\n rotation.value += 90\n emit('rotate', rotation.value)\n}\n\nconst toolbarActions: GrImageViewerToolbarActions = {\n close: closeViewer,\n prev,\n next,\n zoomIn,\n zoomOut,\n reset: resetTransform,\n rotateLeft,\n rotateRight,\n}\n\nfunction onBackdropClick(): void {\n if (!props.hideOnClickModal) {\n return\n }\n\n closeViewer()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'Escape':\n if (!props.closeOnPressEscape) {\n return\n }\n\n event.preventDefault()\n closeViewer()\n return\n\n case 'ArrowLeft':\n event.preventDefault()\n prev()\n return\n\n case 'ArrowRight':\n event.preventDefault()\n next()\n return\n\n case '+':\n case '=':\n case 'Add':\n event.preventDefault()\n zoomIn()\n return\n\n case '-':\n case '_':\n case 'Subtract':\n event.preventDefault()\n zoomOut()\n return\n\n case '0':\n event.preventDefault()\n resetTransform()\n break\n\n default:\n }\n}\n\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (!isOpen) {\n return\n }\n\n syncIndexFromInitial()\n },\n { immediate: true },\n)\n\nwatch(\n () => props.initialIndex,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n)\n\nwatch(\n () => props.urlList,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n { deep: true },\n)\n\nwatch(\n currentIndex,\n (index) => {\n if (!hasImages.value || total.value < 2) {\n return\n }\n\n preloadAt(normalizeIndex(index - 1))\n preloadAt(normalizeIndex(index + 1))\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <teleport to=\"body\">\n <TransitionRoot :show=\"open\" as=\"template\">\n <Dialog\n as=\"div\"\n class=\"fixed inset-0\"\n :style=\"viewerStyle\"\n role=\"dialog\"\n aria-modal=\"true\"\n :static=\"true\"\n @keydown=\"onKeydown\"\n >\n <div class=\"fixed inset-0 overflow-hidden\">\n <TransitionChild\n as=\"template\"\n enter=\"duration-150 ease-out\"\n enter-from=\"opacity-0\"\n enter-to=\"opacity-100\"\n leave=\"duration-120 ease-in\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n data-ds-image-viewer-overlay\n class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\"\n aria-hidden=\"true\"\n @click=\"onBackdropClick\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n enter=\"duration-180 ease-out\"\n enter-from=\"opacity-0 scale-98\"\n enter-to=\"opacity-100 scale-100\"\n leave=\"duration-130 ease-in\"\n leave-from=\"opacity-100 scale-100\"\n leave-to=\"opacity-0 scale-98\"\n >\n <DialogPanel\n data-ds-image-viewer-panel\n class=\"relative z-10 h-full w-full outline-none\"\n tabindex=\"-1\"\n >\n <div class=\"pointer-events-none absolute inset-x-0 top-0 z-30 px-3 py-3 sm:px-6\">\n <div class=\"pointer-events-auto flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-2\">\n <div\n v-if=\"showProgress\"\n data-ds-image-viewer-progress\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-600 text-white/95 sm:text-sm\"\n >\n {{ displayIndex }} / {{ total }}\n </div>\n\n <div\n v-if=\"showZoomValue\"\n data-ds-image-viewer-zoom-value\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-700 text-white/95 sm:text-sm\"\n >\n {{ zoomValueText }}%\n </div>\n </div>\n\n <button\n type=\"button\"\n data-ds-image-viewer-close\n :aria-label=\"closeLabel\"\n class=\"h-11 w-11 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"closeViewer\"\n >\n <span aria-hidden=\"true\" class=\"text-lg leading-none\">✕</span>\n </button>\n </div>\n </div>\n\n <div class=\"relative z-10 h-full w-full flex items-center justify-center px-16 py-16 sm:px-24 sm:py-20\">\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-prev\n :aria-label=\"prevLabel\"\n class=\"absolute left-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:left-6\"\n @click=\"prev\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">‹</span>\n </button>\n\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-next\n :aria-label=\"nextLabel\"\n class=\"absolute right-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:right-6\"\n @click=\"next\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">›</span>\n </button>\n\n <div class=\"h-full w-full flex items-center justify-center\">\n <img\n v-if=\"currentUrl\"\n data-ds-image-viewer-image\n :src=\"currentUrl\"\n alt=\"\"\n draggable=\"false\"\n class=\"max-h-full max-w-full select-none object-contain will-change-transform transition-transform duration-150 ease-out\"\n :style=\"imageStyle\"\n >\n\n <div\n v-else\n class=\"rounded-[var(--ds-radius-xl)] border border-white/20 bg-black/25 px-4 py-3 text-sm text-white/80\"\n >\n {{ emptyText }}\n </div>\n </div>\n </div>\n\n <div class=\"pointer-events-none absolute inset-x-0 bottom-0 z-30 px-3 pb-3 sm:px-6 sm:pb-6\">\n <div class=\"pointer-events-auto mx-auto w-full max-w-max\">\n <slot\n name=\"toolbar\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n >\n <div class=\"rounded-full border border-white/20 bg-black/35 p-1 backdrop-blur-sm flex items-center gap-1\">\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-out\n :aria-label=\"zoomOutLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomOut\"\n >\n −\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-reset\n :aria-label=\"resetZoomLabel\"\n class=\"h-11 min-w-11 px-3 flex items-center justify-center rounded-full text-xs font-700 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"resetTransform\"\n >\n 100%\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-in\n :aria-label=\"zoomInLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomIn\"\n >\n +\n </button>\n\n <template v-if=\"$slots['toolbar-actions']\">\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <slot\n name=\"toolbar-actions\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n />\n\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n </template>\n\n <div v-else class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-left\n :aria-label=\"rotateLeftLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateLeft\"\n >\n ↺\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-right\n :aria-label=\"rotateRightLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateRight\"\n >\n ↻\n </button>\n </div>\n </slot>\n </div>\n </div>\n </DialogPanel>\n </TransitionChild>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\n/**\n * Usage:\n *\n * <GrImageViewer\n * v-model=\"open\"\n * :url-list=\"images\"\n * :initial-index=\"0\"\n * show-progress\n * hide-on-click-modal\n * />\n */\nconst props = withDefaults(\n defineProps<{\n modelValue: boolean\n urlList: string[]\n initialIndex?: number\n zoomRate?: number\n minScale?: number\n maxScale?: number\n hideOnClickModal?: boolean\n closeOnPressEscape?: boolean\n showProgress?: boolean\n showZoomValue?: boolean\n zIndex?: number\n /** i18n: aria-label кнопки закрытия. */\n closeLabel?: string\n /** i18n: aria-label кнопки «предыдущее изображение». */\n prevLabel?: string\n /** i18n: aria-label кнопки «следующее изображение». */\n nextLabel?: string\n /** i18n: aria-label кнопки «увеличить». */\n zoomInLabel?: string\n /** i18n: aria-label кнопки «уменьшить». */\n zoomOutLabel?: string\n /** i18n: aria-label кнопки «сбросить масштаб». */\n resetZoomLabel?: string\n /** i18n: aria-label кнопки «повернуть влево». */\n rotateLeftLabel?: string\n /** i18n: aria-label кнопки «повернуть вправо». */\n rotateRightLabel?: string\n /** i18n: текст в пустом состоянии (нет изображений). */\n emptyText?: string\n }>(),\n {\n initialIndex: 0,\n zoomRate: 1.2,\n minScale: 0.5,\n maxScale: 5,\n hideOnClickModal: false,\n closeOnPressEscape: true,\n showProgress: false,\n showZoomValue: true,\n zIndex: undefined,\n closeLabel: 'Close image viewer',\n prevLabel: 'Previous image',\n nextLabel: 'Next image',\n zoomInLabel: 'Zoom in',\n zoomOutLabel: 'Zoom out',\n resetZoomLabel: 'Reset zoom',\n rotateLeftLabel: 'Rotate left',\n rotateRightLabel: 'Rotate right',\n emptyText: 'No image',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n (e: 'close'): void\n (e: 'switch', newIndex: number): void\n (e: 'rotate', deg: number): void\n}>()\n\ntype GrImageViewerToolbarActions = {\n close: () => void\n prev: () => void\n next: () => void\n zoomIn: () => void\n zoomOut: () => void\n reset: () => void\n rotateLeft: () => void\n rotateRight: () => void\n}\n\nconst DEFAULT_Z_INDEX = 2000\nconst TRAILING_ZERO_DECIMAL_RE = /\\.0$/\n\nconst open = computed(() => props.modelValue)\nconst total = computed(() => props.urlList.length)\nconst hasImages = computed(() => total.value > 0)\n\nconst currentIndex = ref(0)\nconst scale = ref(1)\nconst rotation = ref(0)\nconst offsetX = ref(0)\nconst offsetY = ref(0)\n\nconst currentUrl = computed(() => {\n if (!hasImages.value) {\n return undefined\n }\n\n return props.urlList[currentIndex.value]\n})\n\nconst displayIndex = computed(() => {\n if (!hasImages.value) {\n return 0\n }\n\n return currentIndex.value + 1\n})\n\nconst viewerStyle = computed(() => ({\n zIndex: String(Number.isFinite(props.zIndex) ? props.zIndex : DEFAULT_Z_INDEX),\n}))\n\nconst imageStyle = computed(() => ({\n transform: `translate3d(${offsetX.value}px, ${offsetY.value}px, 0) scale(${scale.value}) rotate(${rotation.value}deg)`,\n}))\n\nconst zoomValueText = computed(() => {\n const zoomPercent = scale.value * 100\n\n if (Number.isInteger(zoomPercent)) {\n return String(zoomPercent)\n }\n\n return zoomPercent.toFixed(1).replace(TRAILING_ZERO_DECIMAL_RE, '')\n})\n\nfunction normalizeIndex(value: number): number {\n if (!hasImages.value) {\n return 0\n }\n\n const normalized = Number.isFinite(value) ? Math.trunc(value) : 0\n\n return ((normalized % total.value) + total.value) % total.value\n}\n\nfunction resetTransform(): void {\n scale.value = 1\n rotation.value = 0\n offsetX.value = 0\n offsetY.value = 0\n}\n\nfunction setIndex(nextIndex: number, options?: { emitSwitch?: boolean }): void {\n const normalizedIndex = normalizeIndex(nextIndex)\n\n if (normalizedIndex === currentIndex.value) {\n return\n }\n\n currentIndex.value = normalizedIndex\n resetTransform()\n\n if (options?.emitSwitch !== false) {\n emit('switch', normalizedIndex)\n }\n}\n\nfunction syncIndexFromInitial(): void {\n if (!hasImages.value) {\n currentIndex.value = 0\n return\n }\n\n currentIndex.value = normalizeIndex(props.initialIndex)\n resetTransform()\n}\n\nfunction preloadAt(index: number): void {\n const url = props.urlList[index]\n\n if (!url) {\n return\n }\n\n const image = new Image()\n image.decoding = 'async'\n image.src = url\n}\n\nfunction closeViewer(): void {\n emit('update:modelValue', false)\n emit('close')\n}\n\nfunction prev(): void {\n setIndex(currentIndex.value - 1)\n}\n\nfunction next(): void {\n setIndex(currentIndex.value + 1)\n}\n\nfunction zoomIn(): void {\n scale.value = Math.min(props.maxScale, Number((scale.value * props.zoomRate).toFixed(4)))\n}\n\nfunction zoomOut(): void {\n scale.value = Math.max(props.minScale, Number((scale.value / props.zoomRate).toFixed(4)))\n}\n\nfunction rotateLeft(): void {\n rotation.value -= 90\n emit('rotate', rotation.value)\n}\n\nfunction rotateRight(): void {\n rotation.value += 90\n emit('rotate', rotation.value)\n}\n\nconst toolbarActions: GrImageViewerToolbarActions = {\n close: closeViewer,\n prev,\n next,\n zoomIn,\n zoomOut,\n reset: resetTransform,\n rotateLeft,\n rotateRight,\n}\n\nfunction onBackdropClick(): void {\n if (!props.hideOnClickModal) {\n return\n }\n\n closeViewer()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'Escape':\n if (!props.closeOnPressEscape) {\n return\n }\n\n event.preventDefault()\n closeViewer()\n return\n\n case 'ArrowLeft':\n event.preventDefault()\n prev()\n return\n\n case 'ArrowRight':\n event.preventDefault()\n next()\n return\n\n case '+':\n case '=':\n case 'Add':\n event.preventDefault()\n zoomIn()\n return\n\n case '-':\n case '_':\n case 'Subtract':\n event.preventDefault()\n zoomOut()\n return\n\n case '0':\n event.preventDefault()\n resetTransform()\n break\n\n default:\n }\n}\n\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (!isOpen) {\n return\n }\n\n syncIndexFromInitial()\n },\n { immediate: true },\n)\n\nwatch(\n () => props.initialIndex,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n)\n\nwatch(\n () => props.urlList,\n () => {\n if (!props.modelValue) {\n return\n }\n\n syncIndexFromInitial()\n },\n { deep: true },\n)\n\nwatch(\n currentIndex,\n (index) => {\n if (!hasImages.value || total.value < 2) {\n return\n }\n\n preloadAt(normalizeIndex(index - 1))\n preloadAt(normalizeIndex(index + 1))\n },\n { immediate: true },\n)\n</script>\n\n<template>\n <teleport to=\"body\">\n <TransitionRoot :show=\"open\" as=\"template\">\n <Dialog\n as=\"div\"\n class=\"fixed inset-0\"\n :style=\"viewerStyle\"\n role=\"dialog\"\n aria-modal=\"true\"\n :static=\"true\"\n @keydown=\"onKeydown\"\n >\n <div class=\"fixed inset-0 overflow-hidden\">\n <TransitionChild\n as=\"template\"\n enter=\"duration-150 ease-out\"\n enter-from=\"opacity-0\"\n enter-to=\"opacity-100\"\n leave=\"duration-120 ease-in\"\n leave-from=\"opacity-100\"\n leave-to=\"opacity-0\"\n >\n <div\n data-ds-image-viewer-overlay\n class=\"absolute inset-0 bg-black/60 backdrop-blur-sm\"\n aria-hidden=\"true\"\n @click=\"onBackdropClick\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n enter=\"duration-180 ease-out\"\n enter-from=\"opacity-0 scale-98\"\n enter-to=\"opacity-100 scale-100\"\n leave=\"duration-130 ease-in\"\n leave-from=\"opacity-100 scale-100\"\n leave-to=\"opacity-0 scale-98\"\n >\n <DialogPanel\n data-ds-image-viewer-panel\n class=\"relative z-10 h-full w-full outline-none\"\n tabindex=\"-1\"\n >\n <div class=\"pointer-events-none absolute inset-x-0 top-0 z-30 px-3 py-3 sm:px-6\">\n <div class=\"pointer-events-auto flex items-center justify-between gap-3\">\n <div class=\"flex items-center gap-2\">\n <div\n v-if=\"showProgress\"\n data-ds-image-viewer-progress\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-600 text-white/95 sm:text-sm\"\n >\n {{ displayIndex }} / {{ total }}\n </div>\n\n <div\n v-if=\"showZoomValue\"\n data-ds-image-viewer-zoom-value\n class=\"rounded-full bg-black/35 px-3 py-1 text-xs font-700 text-white/95 sm:text-sm\"\n >\n {{ zoomValueText }}%\n </div>\n </div>\n\n <button\n type=\"button\"\n data-ds-image-viewer-close\n :aria-label=\"closeLabel\"\n class=\"h-11 w-11 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"closeViewer\"\n >\n <span aria-hidden=\"true\" class=\"text-lg leading-none\">✕</span>\n </button>\n </div>\n </div>\n\n <div class=\"relative z-10 h-full w-full flex items-center justify-center px-16 py-16 sm:px-24 sm:py-20\">\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-prev\n :aria-label=\"prevLabel\"\n class=\"absolute left-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:left-6\"\n @click=\"prev\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">‹</span>\n </button>\n\n <button\n v-if=\"total > 1\"\n type=\"button\"\n data-ds-image-viewer-next\n :aria-label=\"nextLabel\"\n class=\"absolute right-3 top-1/2 z-20 h-12 w-12 -translate-y-1/2 flex items-center justify-center rounded-full border border-white/20 bg-black/35 text-white transition-colors hover:bg-black/55 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80 sm:right-6\"\n @click=\"next\"\n >\n <span aria-hidden=\"true\" class=\"text-xl leading-none\">›</span>\n </button>\n\n <div class=\"h-full w-full flex items-center justify-center\">\n <img\n v-if=\"currentUrl\"\n data-ds-image-viewer-image\n :src=\"currentUrl\"\n alt=\"\"\n draggable=\"false\"\n class=\"max-h-full max-w-full select-none object-contain will-change-transform transition-transform duration-150 ease-out\"\n :style=\"imageStyle\"\n >\n\n <div\n v-else\n class=\"rounded-[var(--ds-radius-xl)] border border-white/20 bg-black/25 px-4 py-3 text-sm text-white/80\"\n >\n {{ emptyText }}\n </div>\n </div>\n </div>\n\n <div class=\"pointer-events-none absolute inset-x-0 bottom-0 z-30 px-3 pb-3 sm:px-6 sm:pb-6\">\n <div class=\"pointer-events-auto mx-auto w-full max-w-max\">\n <slot\n name=\"toolbar\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n >\n <div class=\"rounded-full border border-white/20 bg-black/35 p-1 backdrop-blur-sm flex items-center gap-1\">\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-out\n :aria-label=\"zoomOutLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomOut\"\n >\n −\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-reset\n :aria-label=\"resetZoomLabel\"\n class=\"h-11 min-w-11 px-3 flex items-center justify-center rounded-full text-xs font-700 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"resetTransform\"\n >\n 100%\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-zoom-in\n :aria-label=\"zoomInLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"zoomIn\"\n >\n +\n </button>\n\n <template v-if=\"$slots['toolbar-actions']\">\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <slot\n name=\"toolbar-actions\"\n :index=\"currentIndex\"\n :display-index=\"displayIndex\"\n :total=\"total\"\n :scale=\"scale\"\n :rotation=\"rotation\"\n :actions=\"toolbarActions\"\n />\n\n <div class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n </template>\n\n <div v-else class=\"mx-1 h-6 w-px bg-white/25\" aria-hidden=\"true\" />\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-left\n :aria-label=\"rotateLeftLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateLeft\"\n >\n ↺\n </button>\n\n <button\n type=\"button\"\n data-ds-image-viewer-rotate-right\n :aria-label=\"rotateRightLabel\"\n class=\"h-11 min-w-11 px-2 flex items-center justify-center rounded-full text-sm font-600 text-white transition-colors hover:bg-white/10 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white/80\"\n @click=\"rotateRight\"\n >\n ↻\n </button>\n </div>\n </slot>\n </div>\n </div>\n </DialogPanel>\n </TransitionChild>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrImageViewer_default } from "./chunks/GrImageViewer-
|
|
2
|
-
import { t as grImageViewerConfig } from "../../chunks/config-
|
|
1
|
+
import { t as GrImageViewer_default } from "./chunks/GrImageViewer-CjSnohW7.js";
|
|
2
|
+
import { t as grImageViewerConfig } from "../../chunks/config-BA0BWYzs.js";
|
|
3
3
|
export { GrImageViewer_default as GrImageViewer, GrImageViewer_default as default, grImageViewerConfig };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrInput-DLLRrH1A.js","names":["$slots","$attrs"],"sources":["../../../../src/components/GrInput/GrInput.vue","../../../../src/components/GrInput/GrInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {computed, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, useSlots} from 'vue'\nimport type {InputHTMLAttributes} from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrInputSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type GrInputTextAlign = 'left' | 'center' | 'right'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n type?: 'text' | 'email' | 'password' | 'number' | 'search'\n placeholder?: string\n autocomplete?: string\n inputmode?: InputHTMLAttributes['inputmode']\n disabled?: boolean\n invalid?: boolean\n state?: 'default' | 'success' | 'warning' | 'danger'\n name?: string\n id?: string\n size?: GrInputSize\n\n textAlign?: GrInputTextAlign\n\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n }>(),\n {\n type: 'text',\n placeholder: undefined,\n autocomplete: undefined,\n inputmode: undefined,\n disabled: false,\n invalid: false,\n state: 'default',\n name: undefined,\n id: undefined,\n size: 'md',\n\n textAlign: 'left',\n\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({\n focus,\n})\n\nconst slots = useSlots()\n\nconst hasPrefix = computed(() => Boolean(slots.prefix))\nconst hasSuffix = computed(() => Boolean(slots.suffix))\n\nconst defaultAddonMinWidth = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '2rem', // w-8\n sm: '2.25rem', // w-9\n md: '2.5rem', // w-10\n lg: '3rem', // w-12\n }\n\n return map[props.size]\n})\n\nconst prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\nconst prefixEl = ref<HTMLElement | null>(null)\nconst suffixEl = ref<HTMLElement | null>(null)\n\nconst measuredPrefixWidth = ref<string | undefined>(undefined)\nconst measuredSuffixWidth = ref<string | undefined>(undefined)\n\nlet ro: ResizeObserver | null = null\nlet scheduled = false\n\nfunction readWidthPx(el: HTMLElement | null): string | undefined {\n if (!el) return undefined\n\n const width = Math.ceil(el.getBoundingClientRect().width || 0)\n // jsdom often reports 0; don't overwrite fallback minWidth in that case.\n if (width <= 0) return undefined\n\n return `${width}px`\n}\n\nfunction measure(): void {\n measuredPrefixWidth.value = hasPrefix.value ? readWidthPx(prefixEl.value) : undefined\n measuredSuffixWidth.value = hasSuffix.value ? readWidthPx(suffixEl.value) : undefined\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') return\n if (!ro) ro = new ResizeObserver(() => measure())\n\n ro.disconnect()\n if (prefixEl.value) ro.observe(prefixEl.value)\n if (suffixEl.value) ro.observe(suffixEl.value)\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) return\n scheduled = true\n\n void nextTick(() => {\n scheduled = false\n measure()\n refreshObserver()\n })\n}\n\nonMounted(() => scheduleMeasure())\nonUpdated(() => scheduleMeasure())\nonBeforeUnmount(() => ro?.disconnect())\n\nfunction addLen(a: string, b: string): string {\n if (a === '0px') return b\n if (b === '0px') return a\n\n const apx = a.endsWith('px') ? Number(a.slice(0, -2)) : null\n const bpx = b.endsWith('px') ? Number(b.slice(0, -2)) : null\n\n if (apx !== null && Number.isFinite(apx) && bpx !== null && Number.isFinite(bpx)) {\n return `${apx + bpx}px`\n }\n\n return `calc(${a} + ${b})`\n}\n\nconst basePaddingXLen = computed(() => {\n // Must mirror `sizeClass` horizontal padding (px-*) because inline paddings override class paddings.\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '10px', // px-2.5\n sm: '12px', // px-3\n md: '12px', // px-3\n lg: '16px', // px-4\n }\n\n return map[props.size]\n})\n\nconst inputStyle = computed(() => {\n const leftReserved = hasPrefix.value ? measuredPrefixWidth.value ?? prefixMinWidth.value : '0px'\n const rightReserved = hasSuffix.value ? measuredSuffixWidth.value ?? suffixMinWidth.value : '0px'\n\n // Keep the same visual text padding as without addons (px-*), but add it on top of reserved space.\n const left = hasPrefix.value ? addLen(leftReserved, basePaddingXLen.value) : undefined\n const right = hasSuffix.value ? addLen(rightReserved, basePaddingXLen.value) : undefined\n\n return {\n paddingLeft: left,\n paddingRight: right,\n } as Record<string, string | undefined>\n})\n\nconst prefixStyle = computed(() => {\n return {\n minWidth: prefixMinWidth.value,\n maxWidth: props.prefixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst suffixStyle = computed(() => {\n return {\n minWidth: suffixMinWidth.value,\n maxWidth: props.suffixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst sizeClass = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: 'h-7 px-2.5 text-[12px]',\n sm: 'h-8 px-3 text-[13px]',\n md: 'h-10 px-3 text-[14px]',\n lg: 'h-11 px-4 text-[16px]',\n }\n\n return map[props.size]\n})\n\nconst textAlignClass = computed(() => {\n const map: Record<NonNullable<typeof props.textAlign>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n\n return map[props.textAlign]\n})\n\nconst className = computed(() => {\n const state = props.state\n\n const borderByState: Record<typeof state, string> = {\n default: 'border-[var(--brd)]',\n success: 'border-[var(--ds-success)] focus-visible:ring-[var(--ds-success)]',\n warning: 'border-[var(--ds-warning)] focus-visible:ring-[var(--ds-warning)]',\n danger: 'border-[var(--ds-danger)] focus-visible:ring-[var(--ds-danger)]',\n }\n\n return [\n sizeClass.value,\n textAlignClass.value,\n props.invalid ? borderByState.danger : borderByState[state],\n ].join(' ')\n})\n\nfunction onInput(e: Event): void {\n emit('update:modelValue', (e.target as HTMLInputElement).value)\n}\n</script>\n\n<template>\n <div class=\"relative w-full\">\n <div\n v-if=\"$slots.prefix\"\n ref=\"prefixEl\"\n data-testid=\"ds-input-prefix\"\n class=\"absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"prefixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"prefix\" />\n </div>\n\n <input\n :id=\"props.id\"\n ref=\"inputEl\"\n v-bind=\"$attrs\"\n :name=\"props.name\"\n :type=\"props.type\"\n :inputmode=\"props.inputmode\"\n :autocomplete=\"props.autocomplete\"\n :placeholder=\"props.placeholder\"\n :disabled=\"props.disabled\"\n :value=\"props.modelValue\"\n :aria-invalid=\"props.invalid ? 'true' : undefined\"\n class=\"w-full rounded-md border bg-[var(--bg)] text-[var(--fg)] placeholder:text-[var(--muted-fg)] focus:placeholder:text-transparent transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :class=\"className\"\n :style=\"inputStyle\"\n @input=\"onInput\"\n >\n\n <div\n v-if=\"$slots.suffix\"\n ref=\"suffixEl\"\n data-testid=\"ds-input-suffix\"\n class=\"absolute inset-y-0 right-0 flex items-center justify-center border-l border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport {computed, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, useSlots} from 'vue'\nimport type {InputHTMLAttributes} from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrInputSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type GrInputTextAlign = 'left' | 'center' | 'right'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n type?: 'text' | 'email' | 'password' | 'number' | 'search'\n placeholder?: string\n autocomplete?: string\n inputmode?: InputHTMLAttributes['inputmode']\n disabled?: boolean\n invalid?: boolean\n state?: 'default' | 'success' | 'warning' | 'danger'\n name?: string\n id?: string\n size?: GrInputSize\n\n textAlign?: GrInputTextAlign\n\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n }>(),\n {\n type: 'text',\n placeholder: undefined,\n autocomplete: undefined,\n inputmode: undefined,\n disabled: false,\n invalid: false,\n state: 'default',\n name: undefined,\n id: undefined,\n size: 'md',\n\n textAlign: 'left',\n\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({\n focus,\n})\n\nconst slots = useSlots()\n\nconst hasPrefix = computed(() => Boolean(slots.prefix))\nconst hasSuffix = computed(() => Boolean(slots.suffix))\n\nconst defaultAddonMinWidth = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '2rem', // w-8\n sm: '2.25rem', // w-9\n md: '2.5rem', // w-10\n lg: '3rem', // w-12\n }\n\n return map[props.size]\n})\n\nconst prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\nconst prefixEl = ref<HTMLElement | null>(null)\nconst suffixEl = ref<HTMLElement | null>(null)\n\nconst measuredPrefixWidth = ref<string | undefined>(undefined)\nconst measuredSuffixWidth = ref<string | undefined>(undefined)\n\nlet ro: ResizeObserver | null = null\nlet scheduled = false\n\nfunction readWidthPx(el: HTMLElement | null): string | undefined {\n if (!el) return undefined\n\n const width = Math.ceil(el.getBoundingClientRect().width || 0)\n // jsdom often reports 0; don't overwrite fallback minWidth in that case.\n if (width <= 0) return undefined\n\n return `${width}px`\n}\n\nfunction measure(): void {\n measuredPrefixWidth.value = hasPrefix.value ? readWidthPx(prefixEl.value) : undefined\n measuredSuffixWidth.value = hasSuffix.value ? readWidthPx(suffixEl.value) : undefined\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') return\n if (!ro) ro = new ResizeObserver(() => measure())\n\n ro.disconnect()\n if (prefixEl.value) ro.observe(prefixEl.value)\n if (suffixEl.value) ro.observe(suffixEl.value)\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) return\n scheduled = true\n\n void nextTick(() => {\n scheduled = false\n measure()\n refreshObserver()\n })\n}\n\nonMounted(() => scheduleMeasure())\nonUpdated(() => scheduleMeasure())\nonBeforeUnmount(() => ro?.disconnect())\n\nfunction addLen(a: string, b: string): string {\n if (a === '0px') return b\n if (b === '0px') return a\n\n const apx = a.endsWith('px') ? Number(a.slice(0, -2)) : null\n const bpx = b.endsWith('px') ? Number(b.slice(0, -2)) : null\n\n if (apx !== null && Number.isFinite(apx) && bpx !== null && Number.isFinite(bpx)) {\n return `${apx + bpx}px`\n }\n\n return `calc(${a} + ${b})`\n}\n\nconst basePaddingXLen = computed(() => {\n // Must mirror `sizeClass` horizontal padding (px-*) because inline paddings override class paddings.\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '10px', // px-2.5\n sm: '12px', // px-3\n md: '12px', // px-3\n lg: '16px', // px-4\n }\n\n return map[props.size]\n})\n\nconst inputStyle = computed(() => {\n const leftReserved = hasPrefix.value ? measuredPrefixWidth.value ?? prefixMinWidth.value : '0px'\n const rightReserved = hasSuffix.value ? measuredSuffixWidth.value ?? suffixMinWidth.value : '0px'\n\n // Keep the same visual text padding as without addons (px-*), but add it on top of reserved space.\n const left = hasPrefix.value ? addLen(leftReserved, basePaddingXLen.value) : undefined\n const right = hasSuffix.value ? addLen(rightReserved, basePaddingXLen.value) : undefined\n\n return {\n paddingLeft: left,\n paddingRight: right,\n } as Record<string, string | undefined>\n})\n\nconst prefixStyle = computed(() => {\n return {\n minWidth: prefixMinWidth.value,\n maxWidth: props.prefixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst suffixStyle = computed(() => {\n return {\n minWidth: suffixMinWidth.value,\n maxWidth: props.suffixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst sizeClass = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: 'h-7 px-2.5 text-[12px]',\n sm: 'h-8 px-3 text-[13px]',\n md: 'h-10 px-3 text-[14px]',\n lg: 'h-11 px-4 text-[16px]',\n }\n\n return map[props.size]\n})\n\nconst textAlignClass = computed(() => {\n const map: Record<NonNullable<typeof props.textAlign>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n\n return map[props.textAlign]\n})\n\nconst className = computed(() => {\n const state = props.state\n\n const borderByState: Record<typeof state, string> = {\n default: 'border-[var(--brd)]',\n success: 'border-[var(--ds-success)] focus-visible:ring-[var(--ds-success)]',\n warning: 'border-[var(--ds-warning)] focus-visible:ring-[var(--ds-warning)]',\n danger: 'border-[var(--ds-danger)] focus-visible:ring-[var(--ds-danger)]',\n }\n\n return [\n sizeClass.value,\n textAlignClass.value,\n props.invalid ? borderByState.danger : borderByState[state],\n ].join(' ')\n})\n\nfunction onInput(e: Event): void {\n emit('update:modelValue', (e.target as HTMLInputElement).value)\n}\n</script>\n\n<template>\n <div class=\"relative w-full\">\n <div\n v-if=\"$slots.prefix\"\n ref=\"prefixEl\"\n data-testid=\"ds-input-prefix\"\n class=\"absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"prefixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"prefix\" />\n </div>\n\n <input\n :id=\"props.id\"\n ref=\"inputEl\"\n v-bind=\"$attrs\"\n :name=\"props.name\"\n :type=\"props.type\"\n :inputmode=\"props.inputmode\"\n :autocomplete=\"props.autocomplete\"\n :placeholder=\"props.placeholder\"\n :disabled=\"props.disabled\"\n :value=\"props.modelValue\"\n :aria-invalid=\"props.invalid ? 'true' : undefined\"\n class=\"w-full rounded-md border bg-[var(--bg)] text-[var(--fg)] placeholder:text-[var(--muted-fg)] focus:placeholder:text-transparent transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :class=\"className\"\n :style=\"inputStyle\"\n @input=\"onInput\"\n >\n\n <div\n v-if=\"$slots.suffix\"\n ref=\"suffixEl\"\n data-testid=\"ds-input-suffix\"\n class=\"absolute inset-y-0 right-0 flex items-center justify-center border-l border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrInput-ghxaTf6d.js","names":["$slots","$attrs"],"sources":["../../../../src/components/GrInput/GrInput.vue","../../../../src/components/GrInput/GrInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {computed, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, useSlots} from 'vue'\nimport type {InputHTMLAttributes} from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrInputSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type GrInputTextAlign = 'left' | 'center' | 'right'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n type?: 'text' | 'email' | 'password' | 'number' | 'search'\n placeholder?: string\n autocomplete?: string\n inputmode?: InputHTMLAttributes['inputmode']\n disabled?: boolean\n invalid?: boolean\n state?: 'default' | 'success' | 'warning' | 'danger'\n name?: string\n id?: string\n size?: GrInputSize\n\n textAlign?: GrInputTextAlign\n\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n }>(),\n {\n type: 'text',\n placeholder: undefined,\n autocomplete: undefined,\n inputmode: undefined,\n disabled: false,\n invalid: false,\n state: 'default',\n name: undefined,\n id: undefined,\n size: 'md',\n\n textAlign: 'left',\n\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({\n focus,\n})\n\nconst slots = useSlots()\n\nconst hasPrefix = computed(() => Boolean(slots.prefix))\nconst hasSuffix = computed(() => Boolean(slots.suffix))\n\nconst defaultAddonMinWidth = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '2rem', // w-8\n sm: '2.25rem', // w-9\n md: '2.5rem', // w-10\n lg: '3rem', // w-12\n }\n\n return map[props.size]\n})\n\nconst prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\nconst prefixEl = ref<HTMLElement | null>(null)\nconst suffixEl = ref<HTMLElement | null>(null)\n\nconst measuredPrefixWidth = ref<string | undefined>(undefined)\nconst measuredSuffixWidth = ref<string | undefined>(undefined)\n\nlet ro: ResizeObserver | null = null\nlet scheduled = false\n\nfunction readWidthPx(el: HTMLElement | null): string | undefined {\n if (!el) return undefined\n\n const width = Math.ceil(el.getBoundingClientRect().width || 0)\n // jsdom often reports 0; don't overwrite fallback minWidth in that case.\n if (width <= 0) return undefined\n\n return `${width}px`\n}\n\nfunction measure(): void {\n measuredPrefixWidth.value = hasPrefix.value ? readWidthPx(prefixEl.value) : undefined\n measuredSuffixWidth.value = hasSuffix.value ? readWidthPx(suffixEl.value) : undefined\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') return\n if (!ro) ro = new ResizeObserver(() => measure())\n\n ro.disconnect()\n if (prefixEl.value) ro.observe(prefixEl.value)\n if (suffixEl.value) ro.observe(suffixEl.value)\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) return\n scheduled = true\n\n void nextTick(() => {\n scheduled = false\n measure()\n refreshObserver()\n })\n}\n\nonMounted(() => scheduleMeasure())\nonUpdated(() => scheduleMeasure())\nonBeforeUnmount(() => ro?.disconnect())\n\nfunction addLen(a: string, b: string): string {\n if (a === '0px') return b\n if (b === '0px') return a\n\n const apx = a.endsWith('px') ? Number(a.slice(0, -2)) : null\n const bpx = b.endsWith('px') ? Number(b.slice(0, -2)) : null\n\n if (apx !== null && Number.isFinite(apx) && bpx !== null && Number.isFinite(bpx)) {\n return `${apx + bpx}px`\n }\n\n return `calc(${a} + ${b})`\n}\n\nconst basePaddingXLen = computed(() => {\n // Must mirror `sizeClass` horizontal padding (px-*) because inline paddings override class paddings.\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '10px', // px-2.5\n sm: '12px', // px-3\n md: '12px', // px-3\n lg: '16px', // px-4\n }\n\n return map[props.size]\n})\n\nconst inputStyle = computed(() => {\n const leftReserved = hasPrefix.value ? measuredPrefixWidth.value ?? prefixMinWidth.value : '0px'\n const rightReserved = hasSuffix.value ? measuredSuffixWidth.value ?? suffixMinWidth.value : '0px'\n\n // Keep the same visual text padding as without addons (px-*), but add it on top of reserved space.\n const left = hasPrefix.value ? addLen(leftReserved, basePaddingXLen.value) : undefined\n const right = hasSuffix.value ? addLen(rightReserved, basePaddingXLen.value) : undefined\n\n return {\n paddingLeft: left,\n paddingRight: right,\n } as Record<string, string | undefined>\n})\n\nconst prefixStyle = computed(() => {\n return {\n minWidth: prefixMinWidth.value,\n maxWidth: props.prefixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst suffixStyle = computed(() => {\n return {\n minWidth: suffixMinWidth.value,\n maxWidth: props.suffixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst sizeClass = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: 'h-7 px-2.5 text-[12px]',\n sm: 'h-8 px-3 text-[13px]',\n md: 'h-10 px-3 text-[14px]',\n lg: 'h-11 px-4 text-[16px]',\n }\n\n return map[props.size]\n})\n\nconst textAlignClass = computed(() => {\n const map: Record<NonNullable<typeof props.textAlign>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n\n return map[props.textAlign]\n})\n\nconst className = computed(() => {\n const state = props.state\n\n const borderByState: Record<typeof state, string> = {\n default: 'border-[var(--brd)]',\n success: 'border-[var(--ds-success)] focus-visible:ring-[var(--ds-success)]',\n warning: 'border-[var(--ds-warning)] focus-visible:ring-[var(--ds-warning)]',\n danger: 'border-[var(--ds-danger)] focus-visible:ring-[var(--ds-danger)]',\n }\n\n return [\n sizeClass.value,\n textAlignClass.value,\n props.invalid ? borderByState.danger : borderByState[state],\n ].join(' ')\n})\n\nfunction onInput(e: Event): void {\n emit('update:modelValue', (e.target as HTMLInputElement).value)\n}\n</script>\n\n<template>\n <div class=\"relative w-full\">\n <div\n v-if=\"$slots.prefix\"\n ref=\"prefixEl\"\n data-testid=\"ds-input-prefix\"\n class=\"absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"prefixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"prefix\" />\n </div>\n\n <input\n :id=\"props.id\"\n ref=\"inputEl\"\n v-bind=\"$attrs\"\n :name=\"props.name\"\n :type=\"props.type\"\n :inputmode=\"props.inputmode\"\n :autocomplete=\"props.autocomplete\"\n :placeholder=\"props.placeholder\"\n :disabled=\"props.disabled\"\n :value=\"props.modelValue\"\n :aria-invalid=\"props.invalid ? 'true' : undefined\"\n class=\"w-full rounded-md border bg-[var(--bg)] text-[var(--fg)] placeholder:text-[var(--muted-fg)] focus:placeholder:text-transparent transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :class=\"className\"\n :style=\"inputStyle\"\n @input=\"onInput\"\n >\n\n <div\n v-if=\"$slots.suffix\"\n ref=\"suffixEl\"\n data-testid=\"ds-input-suffix\"\n class=\"absolute inset-y-0 right-0 flex items-center justify-center border-l border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport {computed, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, useSlots} from 'vue'\nimport type {InputHTMLAttributes} from 'vue'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type GrInputSize = 'xs' | 'sm' | 'md' | 'lg'\nexport type GrInputTextAlign = 'left' | 'center' | 'right'\n\nconst props = withDefaults(\n defineProps<{\n modelValue: string\n type?: 'text' | 'email' | 'password' | 'number' | 'search'\n placeholder?: string\n autocomplete?: string\n inputmode?: InputHTMLAttributes['inputmode']\n disabled?: boolean\n invalid?: boolean\n state?: 'default' | 'success' | 'warning' | 'danger'\n name?: string\n id?: string\n size?: GrInputSize\n\n textAlign?: GrInputTextAlign\n\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n }>(),\n {\n type: 'text',\n placeholder: undefined,\n autocomplete: undefined,\n inputmode: undefined,\n disabled: false,\n invalid: false,\n state: 'default',\n name: undefined,\n id: undefined,\n size: 'md',\n\n textAlign: 'left',\n\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n}>()\n\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({\n focus,\n})\n\nconst slots = useSlots()\n\nconst hasPrefix = computed(() => Boolean(slots.prefix))\nconst hasSuffix = computed(() => Boolean(slots.suffix))\n\nconst defaultAddonMinWidth = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '2rem', // w-8\n sm: '2.25rem', // w-9\n md: '2.5rem', // w-10\n lg: '3rem', // w-12\n }\n\n return map[props.size]\n})\n\nconst prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\nconst prefixEl = ref<HTMLElement | null>(null)\nconst suffixEl = ref<HTMLElement | null>(null)\n\nconst measuredPrefixWidth = ref<string | undefined>(undefined)\nconst measuredSuffixWidth = ref<string | undefined>(undefined)\n\nlet ro: ResizeObserver | null = null\nlet scheduled = false\n\nfunction readWidthPx(el: HTMLElement | null): string | undefined {\n if (!el) return undefined\n\n const width = Math.ceil(el.getBoundingClientRect().width || 0)\n // jsdom often reports 0; don't overwrite fallback minWidth in that case.\n if (width <= 0) return undefined\n\n return `${width}px`\n}\n\nfunction measure(): void {\n measuredPrefixWidth.value = hasPrefix.value ? readWidthPx(prefixEl.value) : undefined\n measuredSuffixWidth.value = hasSuffix.value ? readWidthPx(suffixEl.value) : undefined\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') return\n if (!ro) ro = new ResizeObserver(() => measure())\n\n ro.disconnect()\n if (prefixEl.value) ro.observe(prefixEl.value)\n if (suffixEl.value) ro.observe(suffixEl.value)\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) return\n scheduled = true\n\n void nextTick(() => {\n scheduled = false\n measure()\n refreshObserver()\n })\n}\n\nonMounted(() => scheduleMeasure())\nonUpdated(() => scheduleMeasure())\nonBeforeUnmount(() => ro?.disconnect())\n\nfunction addLen(a: string, b: string): string {\n if (a === '0px') return b\n if (b === '0px') return a\n\n const apx = a.endsWith('px') ? Number(a.slice(0, -2)) : null\n const bpx = b.endsWith('px') ? Number(b.slice(0, -2)) : null\n\n if (apx !== null && Number.isFinite(apx) && bpx !== null && Number.isFinite(bpx)) {\n return `${apx + bpx}px`\n }\n\n return `calc(${a} + ${b})`\n}\n\nconst basePaddingXLen = computed(() => {\n // Must mirror `sizeClass` horizontal padding (px-*) because inline paddings override class paddings.\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: '10px', // px-2.5\n sm: '12px', // px-3\n md: '12px', // px-3\n lg: '16px', // px-4\n }\n\n return map[props.size]\n})\n\nconst inputStyle = computed(() => {\n const leftReserved = hasPrefix.value ? measuredPrefixWidth.value ?? prefixMinWidth.value : '0px'\n const rightReserved = hasSuffix.value ? measuredSuffixWidth.value ?? suffixMinWidth.value : '0px'\n\n // Keep the same visual text padding as without addons (px-*), but add it on top of reserved space.\n const left = hasPrefix.value ? addLen(leftReserved, basePaddingXLen.value) : undefined\n const right = hasSuffix.value ? addLen(rightReserved, basePaddingXLen.value) : undefined\n\n return {\n paddingLeft: left,\n paddingRight: right,\n } as Record<string, string | undefined>\n})\n\nconst prefixStyle = computed(() => {\n return {\n minWidth: prefixMinWidth.value,\n maxWidth: props.prefixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst suffixStyle = computed(() => {\n return {\n minWidth: suffixMinWidth.value,\n maxWidth: props.suffixMaxWidth,\n } as Record<string, string | undefined>\n})\n\nconst sizeClass = computed(() => {\n const map: Record<NonNullable<typeof props.size>, string> = {\n xs: 'h-7 px-2.5 text-[12px]',\n sm: 'h-8 px-3 text-[13px]',\n md: 'h-10 px-3 text-[14px]',\n lg: 'h-11 px-4 text-[16px]',\n }\n\n return map[props.size]\n})\n\nconst textAlignClass = computed(() => {\n const map: Record<NonNullable<typeof props.textAlign>, string> = {\n left: 'text-left',\n center: 'text-center',\n right: 'text-right',\n }\n\n return map[props.textAlign]\n})\n\nconst className = computed(() => {\n const state = props.state\n\n const borderByState: Record<typeof state, string> = {\n default: 'border-[var(--brd)]',\n success: 'border-[var(--ds-success)] focus-visible:ring-[var(--ds-success)]',\n warning: 'border-[var(--ds-warning)] focus-visible:ring-[var(--ds-warning)]',\n danger: 'border-[var(--ds-danger)] focus-visible:ring-[var(--ds-danger)]',\n }\n\n return [\n sizeClass.value,\n textAlignClass.value,\n props.invalid ? borderByState.danger : borderByState[state],\n ].join(' ')\n})\n\nfunction onInput(e: Event): void {\n emit('update:modelValue', (e.target as HTMLInputElement).value)\n}\n</script>\n\n<template>\n <div class=\"relative w-full\">\n <div\n v-if=\"$slots.prefix\"\n ref=\"prefixEl\"\n data-testid=\"ds-input-prefix\"\n class=\"absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"prefixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"prefix\" />\n </div>\n\n <input\n :id=\"props.id\"\n ref=\"inputEl\"\n v-bind=\"$attrs\"\n :name=\"props.name\"\n :type=\"props.type\"\n :inputmode=\"props.inputmode\"\n :autocomplete=\"props.autocomplete\"\n :placeholder=\"props.placeholder\"\n :disabled=\"props.disabled\"\n :value=\"props.modelValue\"\n :aria-invalid=\"props.invalid ? 'true' : undefined\"\n class=\"w-full rounded-md border bg-[var(--bg)] text-[var(--fg)] placeholder:text-[var(--muted-fg)] focus:placeholder:text-transparent transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :class=\"className\"\n :style=\"inputStyle\"\n @input=\"onInput\"\n >\n\n <div\n v-if=\"$slots.suffix\"\n ref=\"suffixEl\"\n data-testid=\"ds-input-suffix\"\n class=\"absolute inset-y-0 right-0 flex items-center justify-center border-l border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWA,MAAM,QAAQ;EA0Cd,MAAM,OAAO;EAIb,MAAM,UAAU,IAA6B,KAAI;EAEjD,SAAS,QAAc;AACrB,WAAQ,OAAO,OAAM;;AAGvB,WAAa,EACX,OACD,CAAA;EAED,MAAM,QAAQ,UAAS;EAEvB,MAAM,YAAY,eAAe,QAAQ,MAAM,OAAO,CAAA;EACtD,MAAM,YAAY,eAAe,QAAQ,MAAM,OAAO,CAAA;EAEtD,MAAM,uBAAuB,eAAe;AAQ1C,UAP4D;IAC1D,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACN,CAEW,MAAM;IAClB;EAED,MAAM,iBAAiB,eAAe,MAAM,kBAAkB,qBAAqB,MAAK;EACxF,MAAM,iBAAiB,eAAe,MAAM,kBAAkB,qBAAqB,MAAK;EAExF,MAAM,WAAW,IAAwB,KAAI;EAC7C,MAAM,WAAW,IAAwB,KAAI;EAE7C,MAAM,sBAAsB,IAAwB,KAAA,EAAS;EAC7D,MAAM,sBAAsB,IAAwB,KAAA,EAAS;EAE7D,IAAI,KAA4B;EAChC,IAAI,YAAY;EAEhB,SAAS,YAAY,IAA4C;AAC/D,OAAI,CAAC,GAAI,QAAO,KAAA;GAEhB,MAAM,QAAQ,KAAK,KAAK,GAAG,uBAAuB,CAAC,SAAS,EAAC;AAE7D,OAAI,SAAS,EAAG,QAAO,KAAA;AAEvB,UAAO,GAAG,MAAM;;EAGlB,SAAS,UAAgB;AACvB,uBAAoB,QAAQ,UAAU,QAAQ,YAAY,SAAS,MAAM,GAAG,KAAA;AAC5E,uBAAoB,QAAQ,UAAU,QAAQ,YAAY,SAAS,MAAM,GAAG,KAAA;;EAG9E,SAAS,kBAAwB;AAC/B,OAAI,OAAO,mBAAmB,YAAa;AAC3C,OAAI,CAAC,GAAI,MAAK,IAAI,qBAAqB,SAAS,CAAA;AAEhD,MAAG,YAAW;AACd,OAAI,SAAS,MAAO,IAAG,QAAQ,SAAS,MAAK;AAC7C,OAAI,SAAS,MAAO,IAAG,QAAQ,SAAS,MAAK;;EAG/C,SAAS,kBAAwB;AAC/B,OAAI,UAAW;AACf,eAAY;AAEP,kBAAe;AAClB,gBAAY;AACZ,aAAQ;AACR,qBAAgB;KACjB;;AAGH,kBAAgB,iBAAiB,CAAA;AACjC,kBAAgB,iBAAiB,CAAA;AACjC,wBAAsB,IAAI,YAAY,CAAA;EAEtC,SAAS,OAAO,GAAW,GAAmB;AAC5C,OAAI,MAAM,MAAO,QAAO;AACxB,OAAI,MAAM,MAAO,QAAO;GAExB,MAAM,MAAM,EAAE,SAAS,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG;GACxD,MAAM,MAAM,EAAE,SAAS,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,GAAG,CAAC,GAAG;AAExD,OAAI,QAAQ,QAAQ,OAAO,SAAS,IAAI,IAAI,QAAQ,QAAQ,OAAO,SAAS,IAAI,CAC9E,QAAO,GAAG,MAAM,IAAI;AAGtB,UAAO,QAAQ,EAAE,KAAK,EAAE;;EAG1B,MAAM,kBAAkB,eAAe;AASrC,UAP4D;IAC1D,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACN,CAEW,MAAM;IAClB;EAED,MAAM,aAAa,eAAe;GAChC,MAAM,eAAe,UAAU,QAAQ,oBAAoB,SAAS,eAAe,QAAQ;GAC3F,MAAM,gBAAgB,UAAU,QAAQ,oBAAoB,SAAS,eAAe,QAAQ;AAM5F,UAAO;IACL,aAJW,UAAU,QAAQ,OAAO,cAAc,gBAAgB,MAAM,GAAG,KAAA;IAK3E,cAJY,UAAU,QAAQ,OAAO,eAAe,gBAAgB,MAAM,GAAG,KAAA;IAK9E;IACF;EAED,MAAM,cAAc,eAAe;AACjC,UAAO;IACL,UAAU,eAAe;IACzB,UAAU,MAAM;IACjB;IACF;EAED,MAAM,cAAc,eAAe;AACjC,UAAO;IACL,UAAU,eAAe;IACzB,UAAU,MAAM;IACjB;IACF;EAED,MAAM,YAAY,eAAe;AAQ/B,UAP4D;IAC1D,IAAI;IACJ,IAAI;IACJ,IAAI;IACJ,IAAI;IACN,CAEW,MAAM;IAClB;EAED,MAAM,iBAAiB,eAAe;AAOpC,UANiE;IAC/D,MAAM;IACN,QAAQ;IACR,OAAO;IACT,CAEW,MAAM;IAClB;EAED,MAAM,YAAY,eAAe;GAC/B,MAAM,QAAQ,MAAM;GAEpB,MAAM,gBAA8C;IAClD,SAAS;IACT,SAAS;IACT,SAAS;IACT,QAAQ;IACV;AAEA,UAAO;IACL,UAAU;IACV,eAAe;IACf,MAAM,UAAU,cAAc,SAAS,cAAc;IACtD,CAAC,KAAK,IAAG;IACX;EAED,SAAS,QAAQ,GAAgB;AAC/B,QAAK,qBAAsB,EAAE,OAA4B,MAAK;;;uBAK9D,mBAwCM,OAxCN,YAwCM;IAtCMA,KAAAA,OAAO,UAAA,WAAA,EADjB,mBASM,OAAA;;cAPE;KAAJ,KAAI;KACJ,eAAY;KACZ,OAAM;KACL,OAAK,eAAE,YAAA,MAAW;KACnB,eAAY;QAEd,WAAsB,KAAA,QAAA,SAAA,CAAA,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA;IAGxB,mBAgBC,SAhBD,WAgBC;KAfI,IAAI,MAAM;cACP;KAAJ,KAAI;OACIC,KAAAA,QAAM;KACb,MAAM,MAAM;KACZ,MAAM,MAAM;KACZ,WAAW,MAAM;KACjB,cAAc,MAAM;KACpB,aAAa,MAAM;KACnB,UAAU,MAAM;KAChB,OAAO,MAAM;KACb,gBAAc,MAAM,UAAO,SAAY,KAAA;KACxC,OAAK,CAAC,0RACE,UAAA,MAAS;KAChB,OAAO,WAAA;KACA;;IAIFD,KAAAA,OAAO,UAAA,WAAA,EADjB,mBASM,OAAA;;cAPE;KAAJ,KAAI;KACJ,eAAY;KACZ,OAAM;KACL,OAAK,eAAE,YAAA,MAAW;KACnB,eAAY;QAEd,WAAsB,KAAA,QAAA,SAAA,CAAA,EAAA,EAAA,IAAA,mBAAA,IAAA,KAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrInput_default } from "./chunks/GrInput-
|
|
2
|
-
import { n as grInputSafelist, t as grInputConfig } from "../../chunks/config-
|
|
1
|
+
import { t as GrInput_default } from "./chunks/GrInput-ghxaTf6d.js";
|
|
2
|
+
import { n as grInputSafelist, t as grInputConfig } from "../../chunks/config-D19pyP4D.js";
|
|
3
3
|
export { GrInput_default as GrInput, GrInput_default as default, grInputConfig, grInputSafelist };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as x_default } from "../../../chunks/x-Pa6C2hwi.js";
|
|
2
2
|
import { t as GrBadge_default } from "../../GrBadge/chunks/GrBadge-wuIb4_2K.js";
|
|
3
3
|
import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-BV7RBU_0.js";
|
|
4
|
-
import { i as grInputTagWrapperClass, r as grInputTagInputClass } from "../../../chunks/config-
|
|
4
|
+
import { i as grInputTagWrapperClass, r as grInputTagInputClass } from "../../../chunks/config-DgRJlF00.js";
|
|
5
5
|
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, renderSlot, toDisplayString, unref, withCtx, withModifiers } from "vue";
|
|
6
6
|
//#region src/components/GrInputTag/GrInputTag.vue?vue&type=script&setup=true&lang.ts
|
|
7
7
|
var _hoisted_1 = { class: "truncate max-w-[18rem]" };
|
|
@@ -255,5 +255,3 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
|
|
|
255
255
|
});
|
|
256
256
|
//#endregion
|
|
257
257
|
export { GrInputTag_default as t };
|
|
258
|
-
|
|
259
|
-
//# sourceMappingURL=GrInputTag-CzrrBxgU.js.map
|
package/dist/components/GrInputTag/chunks/{GrInputTag-CzrrBxgU.js.map → GrInputTag-B0x4U0Yk.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrInputTag-CzrrBxgU.js","names":[],"sources":["../../../../src/components/GrInputTag/GrInputTag.vue","../../../../src/components/GrInputTag/GrInputTag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport GrBadge from '../GrBadge/GrBadge.vue'\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\n\nimport {\n grInputTagInputClass,\n grInputTagWrapperClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n state: 'default',\n size: 'md',\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: 'Remove tag',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n}>()\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({ focus })\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !props.disabled && !props.readonly)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n let changed = false\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n changed = true\n emit('add', tag)\n }\n\n if (!changed)\n return false\n\n emit('update:modelValue', next)\n return true\n}\n\nfunction commitInput(): void {\n if (!canEdit.value || isMaxed.value || !inputValue.value)\n return\n\n const tags = splitToTags(inputValue.value)\n if (!tags.length)\n return\n\n const changed = addMany(tags)\n if (changed && props.clearInputOnAdd)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('remove', removed, index)\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n commitInput()\n return\n }\n\n if (e.key === 'Backspace' && inputValue.value.length === 0 && props.modelValue.length > 0) {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n addMany(tags)\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: props.size,\n state: props.state,\n invalid: props.invalid,\n disabled: props.disabled,\n })\n})\n\nconst inputClassName = computed(() => {\n return grInputTagInputClass(props.size)\n})\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n</script>\n\n<template>\n <div\n data-ds-input-tag\n data-testid=\"ds-input-tag\"\n class=\"w-full flex flex-wrap items-center rounded-md border bg-[var(--bg)] text-[var(--fg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--ring)]\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n >\n <GrBadge\n v-for=\"(tag, i) in modelValue\"\n :key=\"`${tag}-${i}`\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"tagSize\"\n :radius=\"tagRadius\"\n class=\"gap-1\"\n data-ds-input-tag-item\n data-testid=\"ds-input-tag-item\"\n :data-index=\"i\"\n >\n <slot name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n\n <button\n v-if=\"showRemove\"\n type=\"button\"\n class=\"-mr-0.5 inline-flex items-center justify-center rounded-[6px] p-0.5 opacity-70 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]\"\n :aria-label=\"removeTagLabel\"\n data-ds-input-tag-remove\n data-testid=\"ds-input-tag-remove\"\n :data-index=\"i\"\n @mousedown.prevent.stop\n @click.stop=\"removeAt(i)\"\n >\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconClose />\n </GrIcon>\n </button>\n </GrBadge>\n\n <input\n ref=\"inputEl\"\n data-ds-input-tag-input\n data-testid=\"ds-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"disabled || isMaxed\"\n :readonly=\"readonly\"\n :placeholder=\"placeholderText\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport GrBadge from '../GrBadge/GrBadge.vue'\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\n\nimport {\n grInputTagInputClass,\n grInputTagWrapperClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n state: 'default',\n size: 'md',\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: 'Remove tag',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n}>()\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({ focus })\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !props.disabled && !props.readonly)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n let changed = false\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n changed = true\n emit('add', tag)\n }\n\n if (!changed)\n return false\n\n emit('update:modelValue', next)\n return true\n}\n\nfunction commitInput(): void {\n if (!canEdit.value || isMaxed.value || !inputValue.value)\n return\n\n const tags = splitToTags(inputValue.value)\n if (!tags.length)\n return\n\n const changed = addMany(tags)\n if (changed && props.clearInputOnAdd)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('remove', removed, index)\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n commitInput()\n return\n }\n\n if (e.key === 'Backspace' && inputValue.value.length === 0 && props.modelValue.length > 0) {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n addMany(tags)\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: props.size,\n state: props.state,\n invalid: props.invalid,\n disabled: props.disabled,\n })\n})\n\nconst inputClassName = computed(() => {\n return grInputTagInputClass(props.size)\n})\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n</script>\n\n<template>\n <div\n data-ds-input-tag\n data-testid=\"ds-input-tag\"\n class=\"w-full flex flex-wrap items-center rounded-md border bg-[var(--bg)] text-[var(--fg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--ring)]\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n >\n <GrBadge\n v-for=\"(tag, i) in modelValue\"\n :key=\"`${tag}-${i}`\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"tagSize\"\n :radius=\"tagRadius\"\n class=\"gap-1\"\n data-ds-input-tag-item\n data-testid=\"ds-input-tag-item\"\n :data-index=\"i\"\n >\n <slot name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n\n <button\n v-if=\"showRemove\"\n type=\"button\"\n class=\"-mr-0.5 inline-flex items-center justify-center rounded-[6px] p-0.5 opacity-70 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]\"\n :aria-label=\"removeTagLabel\"\n data-ds-input-tag-remove\n data-testid=\"ds-input-tag-remove\"\n :data-index=\"i\"\n @mousedown.prevent.stop\n @click.stop=\"removeAt(i)\"\n >\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconClose />\n </GrIcon>\n </button>\n </GrBadge>\n\n <input\n ref=\"inputEl\"\n data-ds-input-tag-input\n data-testid=\"ds-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"disabled || isMaxed\"\n :readonly=\"readonly\"\n :placeholder=\"placeholderText\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrInputTag-B0x4U0Yk.js","names":[],"sources":["../../../../src/components/GrInputTag/GrInputTag.vue","../../../../src/components/GrInputTag/GrInputTag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport GrBadge from '../GrBadge/GrBadge.vue'\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\n\nimport {\n grInputTagInputClass,\n grInputTagWrapperClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n state: 'default',\n size: 'md',\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: 'Remove tag',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n}>()\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({ focus })\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !props.disabled && !props.readonly)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n let changed = false\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n changed = true\n emit('add', tag)\n }\n\n if (!changed)\n return false\n\n emit('update:modelValue', next)\n return true\n}\n\nfunction commitInput(): void {\n if (!canEdit.value || isMaxed.value || !inputValue.value)\n return\n\n const tags = splitToTags(inputValue.value)\n if (!tags.length)\n return\n\n const changed = addMany(tags)\n if (changed && props.clearInputOnAdd)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('remove', removed, index)\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n commitInput()\n return\n }\n\n if (e.key === 'Backspace' && inputValue.value.length === 0 && props.modelValue.length > 0) {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n addMany(tags)\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: props.size,\n state: props.state,\n invalid: props.invalid,\n disabled: props.disabled,\n })\n})\n\nconst inputClassName = computed(() => {\n return grInputTagInputClass(props.size)\n})\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n</script>\n\n<template>\n <div\n data-ds-input-tag\n data-testid=\"ds-input-tag\"\n class=\"w-full flex flex-wrap items-center rounded-md border bg-[var(--bg)] text-[var(--fg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--ring)]\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n >\n <GrBadge\n v-for=\"(tag, i) in modelValue\"\n :key=\"`${tag}-${i}`\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"tagSize\"\n :radius=\"tagRadius\"\n class=\"gap-1\"\n data-ds-input-tag-item\n data-testid=\"ds-input-tag-item\"\n :data-index=\"i\"\n >\n <slot name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n\n <button\n v-if=\"showRemove\"\n type=\"button\"\n class=\"-mr-0.5 inline-flex items-center justify-center rounded-[6px] p-0.5 opacity-70 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]\"\n :aria-label=\"removeTagLabel\"\n data-ds-input-tag-remove\n data-testid=\"ds-input-tag-remove\"\n :data-index=\"i\"\n @mousedown.prevent.stop\n @click.stop=\"removeAt(i)\"\n >\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconClose />\n </GrIcon>\n </button>\n </GrBadge>\n\n <input\n ref=\"inputEl\"\n data-ds-input-tag-input\n data-testid=\"ds-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"disabled || isMaxed\"\n :readonly=\"readonly\"\n :placeholder=\"placeholderText\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\n\nimport GrBadge from '../GrBadge/GrBadge.vue'\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\n\nimport {\n grInputTagInputClass,\n grInputTagWrapperClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n state: 'default',\n size: 'md',\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: 'Remove tag',\n },\n)\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n}>()\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\ndefineExpose({ focus })\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !props.disabled && !props.readonly)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n let changed = false\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n changed = true\n emit('add', tag)\n }\n\n if (!changed)\n return false\n\n emit('update:modelValue', next)\n return true\n}\n\nfunction commitInput(): void {\n if (!canEdit.value || isMaxed.value || !inputValue.value)\n return\n\n const tags = splitToTags(inputValue.value)\n if (!tags.length)\n return\n\n const changed = addMany(tags)\n if (changed && props.clearInputOnAdd)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('remove', removed, index)\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n commitInput()\n return\n }\n\n if (e.key === 'Backspace' && inputValue.value.length === 0 && props.modelValue.length > 0) {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n addMany(tags)\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: props.size,\n state: props.state,\n invalid: props.invalid,\n disabled: props.disabled,\n })\n})\n\nconst inputClassName = computed(() => {\n return grInputTagInputClass(props.size)\n})\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n</script>\n\n<template>\n <div\n data-ds-input-tag\n data-testid=\"ds-input-tag\"\n class=\"w-full flex flex-wrap items-center rounded-md border bg-[var(--bg)] text-[var(--fg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--ring)]\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n >\n <GrBadge\n v-for=\"(tag, i) in modelValue\"\n :key=\"`${tag}-${i}`\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"tagSize\"\n :radius=\"tagRadius\"\n class=\"gap-1\"\n data-ds-input-tag-item\n data-testid=\"ds-input-tag-item\"\n :data-index=\"i\"\n >\n <slot name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n\n <button\n v-if=\"showRemove\"\n type=\"button\"\n class=\"-mr-0.5 inline-flex items-center justify-center rounded-[6px] p-0.5 opacity-70 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]\"\n :aria-label=\"removeTagLabel\"\n data-ds-input-tag-remove\n data-testid=\"ds-input-tag-remove\"\n :data-index=\"i\"\n @mousedown.prevent.stop\n @click.stop=\"removeAt(i)\"\n >\n <GrIcon size=\"sm\" aria-hidden=\"true\">\n <IconClose />\n </GrIcon>\n </button>\n </GrBadge>\n\n <input\n ref=\"inputEl\"\n data-ds-input-tag-input\n data-testid=\"ds-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"disabled || isMaxed\"\n :readonly=\"readonly\"\n :placeholder=\"placeholderText\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as grInputTagSafelist, t as grInputTagConfig } from "../../chunks/config-
|
|
2
|
-
import { t as GrInputTag_default } from "./chunks/GrInputTag-
|
|
1
|
+
import { n as grInputTagSafelist, t as grInputTagConfig } from "../../chunks/config-DgRJlF00.js";
|
|
2
|
+
import { t as GrInputTag_default } from "./chunks/GrInputTag-B0x4U0Yk.js";
|
|
3
3
|
export { GrInputTag_default as GrInputTag, GrInputTag_default as default, grInputTagConfig, grInputTagSafelist };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as grLinkClass, i as focusRingClass, r as baseRootClass } from "../../../chunks/config-
|
|
1
|
+
import { a as grLinkClass, i as focusRingClass, r as baseRootClass } from "../../../chunks/config-DUtUkSzc.js";
|
|
2
2
|
import { computed, createElementBlock, defineComponent, mergeProps, openBlock, renderSlot, unref, useAttrs } from "vue";
|
|
3
3
|
//#region src/components/GrLink/GrLink.vue?vue&type=script&setup=true&lang.ts
|
|
4
4
|
var _hoisted_1 = [
|
|
@@ -78,5 +78,3 @@ var GrLink_default = /* @__PURE__ */ defineComponent({
|
|
|
78
78
|
});
|
|
79
79
|
//#endregion
|
|
80
80
|
export { GrLink_default as t };
|
|
81
|
-
|
|
82
|
-
//# sourceMappingURL=GrLink-Dhkid3Mp.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrLink-
|
|
1
|
+
{"version":3,"file":"GrLink-BbN7R3iP.js","names":[],"sources":["../../../../src/components/GrLink/GrLink.vue","../../../../src/components/GrLink/GrLink.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrLink — DS-примитив ссылки.\n *\n * Корневой тег зависит от пропов:\n * - `<a>` — когда заданы `href` и не `disabled`;\n * - `<span>` — во всех остальных случаях (включая `disabled`, даже если `href` задан).\n *\n * Это осознанное решение, чтобы отключённая ссылка не была кликабельной и\n * не участвовала в порядке табуляции. Учтите это в внешних CSS-селекторах.\n */\nimport { computed, useAttrs } from 'vue'\n\nimport {\n baseRootClass,\n grLinkClass,\n type GrLinkSize,\n type GrLinkUnderline,\n type GrLinkVariant,\n focusRingClass,\n} from './grLinkStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<{\n href?: string\n external?: boolean\n target?: string\n rel?: string\n disabled?: boolean\n ariaLabel?: string\n variant?: GrLinkVariant\n underline?: GrLinkUnderline\n size?: GrLinkSize\n}>(), {\n href: undefined,\n external: false,\n target: undefined,\n rel: undefined,\n disabled: false,\n ariaLabel: undefined,\n variant: 'primary',\n underline: 'auto',\n size: 'md',\n})\n\nconst attrs = useAttrs()\n\nconst isAnchor = computed(() => !!props.href && !props.disabled)\n\nconst resolvedTarget = computed(() => {\n if (props.target)\n return props.target\n\n if (props.external)\n return '_blank'\n\n return undefined\n})\n\nconst resolvedRel = computed(() => {\n if (props.rel)\n return props.rel\n\n // Авто-защита для любых ссылок, открывающихся в новой вкладке,\n // а не только когда выставлен `external`.\n if (resolvedTarget.value === '_blank')\n return 'noopener noreferrer'\n\n return undefined\n})\n\nconst rootClass = computed(() => {\n const variantClass = grLinkClass({\n size: props.size,\n underline: props.underline,\n variant: props.variant,\n disabled: props.disabled,\n })\n\n // На disabled-ветке (`<span>`) focus-ring не нужен: элемент не фокусируется,\n // а если снаружи ему навесят `tabindex`, фокус-рамка на «отключённой» ссылке смотрелась бы странно.\n return props.disabled\n ? `${baseRootClass} ${variantClass}`\n : `${baseRootClass} ${focusRingClass} ${variantClass}`\n})\n</script>\n\n<template>\n <a\n v-if=\"isAnchor\"\n v-bind=\"attrs\"\n :href=\"href\"\n :target=\"resolvedTarget\"\n :rel=\"resolvedRel\"\n :aria-label=\"ariaLabel\"\n :class=\"rootClass\"\n >\n <slot />\n </a>\n\n <span\n v-else\n v-bind=\"attrs\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :class=\"rootClass\"\n >\n <slot />\n </span>\n</template>","<script setup lang=\"ts\">\n/**\n * GrLink — DS-примитив ссылки.\n *\n * Корневой тег зависит от пропов:\n * - `<a>` — когда заданы `href` и не `disabled`;\n * - `<span>` — во всех остальных случаях (включая `disabled`, даже если `href` задан).\n *\n * Это осознанное решение, чтобы отключённая ссылка не была кликабельной и\n * не участвовала в порядке табуляции. Учтите это в внешних CSS-селекторах.\n */\nimport { computed, useAttrs } from 'vue'\n\nimport {\n baseRootClass,\n grLinkClass,\n type GrLinkSize,\n type GrLinkUnderline,\n type GrLinkVariant,\n focusRingClass,\n} from './grLinkStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<{\n href?: string\n external?: boolean\n target?: string\n rel?: string\n disabled?: boolean\n ariaLabel?: string\n variant?: GrLinkVariant\n underline?: GrLinkUnderline\n size?: GrLinkSize\n}>(), {\n href: undefined,\n external: false,\n target: undefined,\n rel: undefined,\n disabled: false,\n ariaLabel: undefined,\n variant: 'primary',\n underline: 'auto',\n size: 'md',\n})\n\nconst attrs = useAttrs()\n\nconst isAnchor = computed(() => !!props.href && !props.disabled)\n\nconst resolvedTarget = computed(() => {\n if (props.target)\n return props.target\n\n if (props.external)\n return '_blank'\n\n return undefined\n})\n\nconst resolvedRel = computed(() => {\n if (props.rel)\n return props.rel\n\n // Авто-защита для любых ссылок, открывающихся в новой вкладке,\n // а не только когда выставлен `external`.\n if (resolvedTarget.value === '_blank')\n return 'noopener noreferrer'\n\n return undefined\n})\n\nconst rootClass = computed(() => {\n const variantClass = grLinkClass({\n size: props.size,\n underline: props.underline,\n variant: props.variant,\n disabled: props.disabled,\n })\n\n // На disabled-ветке (`<span>`) focus-ring не нужен: элемент не фокусируется,\n // а если снаружи ему навесят `tabindex`, фокус-рамка на «отключённой» ссылке смотрелась бы странно.\n return props.disabled\n ? `${baseRootClass} ${variantClass}`\n : `${baseRootClass} ${focusRingClass} ${variantClass}`\n})\n</script>\n\n<template>\n <a\n v-if=\"isAnchor\"\n v-bind=\"attrs\"\n :href=\"href\"\n :target=\"resolvedTarget\"\n :rel=\"resolvedRel\"\n :aria-label=\"ariaLabel\"\n :class=\"rootClass\"\n >\n <slot />\n </a>\n\n <span\n v-else\n v-bind=\"attrs\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :class=\"rootClass\"\n >\n <slot />\n </span>\n</template>"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BA,MAAM,QAAQ;EAsBd,MAAM,QAAQ,UAAS;EAEvB,MAAM,WAAW,eAAe,CAAC,CAAC,MAAM,QAAQ,CAAC,MAAM,SAAQ;EAE/D,MAAM,iBAAiB,eAAe;AACpC,OAAI,MAAM,OACR,QAAO,MAAM;AAEf,OAAI,MAAM,SACR,QAAO;IAGV;EAED,MAAM,cAAc,eAAe;AACjC,OAAI,MAAM,IACR,QAAO,MAAM;AAIf,OAAI,eAAe,UAAU,SAC3B,QAAO;IAGV;EAED,MAAM,YAAY,eAAe;GAC/B,MAAM,eAAe,YAAY;IAC/B,MAAM,MAAM;IACZ,WAAW,MAAM;IACjB,SAAS,MAAM;IACf,UAAU,MAAM;IACjB,CAAA;AAID,UAAO,MAAM,WACT,GAAG,cAAc,GAAG,iBACpB,GAAG,cAAc,GAAG,eAAe,GAAG;IAC3C;;UAKS,SAAA,SAAA,WAAA,EADR,mBAUI,KAVJ,WAUI,EAAA,KAAA,GAAA,EARM,MAAA,MAAK,EAAA;IACZ,MAAM,QAAA;IACN,QAAQ,eAAA;IACR,KAAK,YAAA;IACL,cAAY,QAAA;IACZ,OAAO,UAAA;QAER,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,IAAA,WAAA,KAAA,WAAA,EAGV,mBAQO,QARP,WAQO,EAAA,KAAA,GAAA,EANG,MAAA,MAAK,EAAA;IACZ,cAAY,QAAA;IACZ,iBAAe,QAAA,WAAQ,SAAY,KAAA;IACnC,OAAO,UAAA;QAER,WAAQ,KAAA,QAAA,UAAA,CAAA,EAAA,IAAA,WAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as grLinkSafelist, t as grLinkConfig } from "../../chunks/config-
|
|
2
|
-
import { t as GrLink_default } from "./chunks/GrLink-
|
|
1
|
+
import { n as grLinkSafelist, t as grLinkConfig } from "../../chunks/config-DUtUkSzc.js";
|
|
2
|
+
import { t as GrLink_default } from "./chunks/GrLink-BbN7R3iP.js";
|
|
3
3
|
export { GrLink_default as GrLink, GrLink_default as default, grLinkConfig, grLinkSafelist };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrList
|
|
1
|
+
{"version":3,"file":"GrList--Ib4zLNw.js","names":["$slots"],"sources":["../../../../src/components/GrList/GrList.vue","../../../../src/components/GrList/GrList.vue","../../../../src/components/GrList/GrListItem.vue","../../../../src/components/GrList/GrListItem.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport GrCard from '../GrCard'\n\nexport interface GrListProps {\n /** Показывать ли горизонтальные разделители между элементами (по умолчанию — да). */\n divided?: boolean\n}\n\nwithDefaults(defineProps<GrListProps>(), {\n divided: true,\n})\n</script>\n\n<template>\n <GrCard>\n <div\n v-if=\"divided\"\n role=\"list\"\n class=\"divide-y divide-[var(--brd)]\"\n >\n <slot />\n </div>\n <div\n v-else\n role=\"list\"\n >\n <slot />\n </div>\n </GrCard>\n</template>","<script setup lang=\"ts\">\nimport GrCard from '../GrCard'\n\nexport interface GrListProps {\n /** Показывать ли горизонтальные разделители между элементами (по умолчанию — да). */\n divided?: boolean\n}\n\nwithDefaults(defineProps<GrListProps>(), {\n divided: true,\n})\n</script>\n\n<template>\n <GrCard>\n <div\n v-if=\"divided\"\n role=\"list\"\n class=\"divide-y divide-[var(--brd)]\"\n >\n <slot />\n </div>\n <div\n v-else\n role=\"list\"\n >\n <slot />\n </div>\n </GrCard>\n</template>","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nexport type GrListItemDensity = 'compact' | 'regular'\n\nexport interface GrListItemProps {\n /** Заголовок строки. Если передан слот `#title`, проп игнорируется. */\n title?: string\n /** Описание под заголовком. Если передан слот `#description`, проп игнорируется. */\n description?: string\n /** Плотность вертикальных отступов: `regular` — 12px, `compact` — 8px. */\n density?: GrListItemDensity\n}\n\nconst props = withDefaults(defineProps<GrListItemProps>(), {\n title: undefined,\n description: undefined,\n density: 'regular',\n})\n\nconst slots = useSlots()\n\nconst paddingClass = computed(() =>\n props.density === 'compact' ? 'px-4 py-2' : 'px-4 py-3',\n)\n\nconst hasTitle = computed(() => !!slots.title || !!props.title)\nconst hasDescription = computed(() => !!slots.description || !!props.description)\n</script>\n\n<template>\n <div\n role=\"listitem\"\n class=\"flex items-start justify-between gap-4\"\n :class=\"paddingClass\"\n >\n <div v-if=\"$slots.prefix\" class=\"shrink-0\">\n <slot name=\"prefix\" />\n </div>\n <div class=\"min-w-0 flex-1\">\n <div v-if=\"hasTitle\" class=\"text-[13px] font-700\">\n <slot name=\"title\">\n{{ title }}\n</slot>\n </div>\n <div\n v-if=\"hasDescription\"\n class=\"text-[13px] text-[var(--muted-fg)] mt-0.5\"\n >\n <slot name=\"description\">\n{{ description }}\n</slot>\n </div>\n </div>\n <div v-if=\"$slots.default\" class=\"shrink-0\">\n <slot />\n </div>\n </div>\n</template>","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nexport type GrListItemDensity = 'compact' | 'regular'\n\nexport interface GrListItemProps {\n /** Заголовок строки. Если передан слот `#title`, проп игнорируется. */\n title?: string\n /** Описание под заголовком. Если передан слот `#description`, проп игнорируется. */\n description?: string\n /** Плотность вертикальных отступов: `regular` — 12px, `compact` — 8px. */\n density?: GrListItemDensity\n}\n\nconst props = withDefaults(defineProps<GrListItemProps>(), {\n title: undefined,\n description: undefined,\n density: 'regular',\n})\n\nconst slots = useSlots()\n\nconst paddingClass = computed(() =>\n props.density === 'compact' ? 'px-4 py-2' : 'px-4 py-3',\n)\n\nconst hasTitle = computed(() => !!slots.title || !!props.title)\nconst hasDescription = computed(() => !!slots.description || !!props.description)\n</script>\n\n<template>\n <div\n role=\"listitem\"\n class=\"flex items-start justify-between gap-4\"\n :class=\"paddingClass\"\n >\n <div v-if=\"$slots.prefix\" class=\"shrink-0\">\n <slot name=\"prefix\" />\n </div>\n <div class=\"min-w-0 flex-1\">\n <div v-if=\"hasTitle\" class=\"text-[13px] font-700\">\n <slot name=\"title\">\n{{ title }}\n</slot>\n </div>\n <div\n v-if=\"hasDescription\"\n class=\"text-[13px] text-[var(--muted-fg)] mt-0.5\"\n >\n <slot name=\"description\">\n{{ description }}\n</slot>\n </div>\n </div>\n <div v-if=\"$slots.default\" class=\"shrink-0\">\n <slot />\n </div>\n </div>\n</template>"],"mappings":";;;;;;;;;;;;;;;;;;;;;;uBAcE,YAcS,MAAA,eAAA,EAAA,MAAA;2BAPD,CALE,QAAA,WAAA,WAAA,EADR,mBAMM,OANN,cAMM,CADJ,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA,KAAA,WAAA,EAEV,mBAKM,OALN,cAKM,CADJ,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA,EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EEZd,MAAM,QAAQ;EAMd,MAAM,QAAQ,UAAS;EAEvB,MAAM,eAAe,eACnB,MAAM,YAAY,YAAY,cAAc,YAC9C;EAEA,MAAM,WAAW,eAAe,CAAC,CAAC,MAAM,SAAS,CAAC,CAAC,MAAM,MAAK;EAC9D,MAAM,iBAAiB,eAAe,CAAC,CAAC,MAAM,eAAe,CAAC,CAAC,MAAM,YAAW;;uBAI9E,mBA0BM,OAAA;IAzBJ,MAAK;IACL,OAAK,eAAA,CAAC,0CACE,aAAA,MAAY,CAAA;;IAETA,KAAAA,OAAO,UAAA,WAAA,EAAlB,mBAEM,OAFN,YAEM,CADJ,WAAsB,KAAA,QAAA,SAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA;IAExB,mBAcM,OAdN,YAcM,CAbO,SAAA,SAAA,WAAA,EAAX,mBAIM,OAJN,YAIM,CAHJ,WAED,KAAA,QAAA,SAAA,EAAA,QAAA,CAAA,gBAAA,gBADJ,QAAA,MAAK,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA,EAIM,eAAA,SAAA,WAAA,EADR,mBAOM,OAPN,YAOM,CAHJ,WAED,KAAA,QAAA,eAAA,EAAA,QAAA,CAAA,gBAAA,gBADJ,QAAA,YAAW,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA,CAAA,CAAA;IAICA,KAAAA,OAAO,WAAA,WAAA,EAAlB,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,UAAA,CAAA,CAAA,IAAA,mBAAA,IAAA,KAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as GrList_default, t as GrListItem_default } from "./chunks/GrList
|
|
2
|
-
import { t as grListConfig } from "../../chunks/config-
|
|
1
|
+
import { n as GrList_default, t as GrListItem_default } from "./chunks/GrList--Ib4zLNw.js";
|
|
2
|
+
import { t as grListConfig } from "../../chunks/config-fCcRwjIB.js";
|
|
3
3
|
export { GrList_default as GrList, GrList_default as default, GrListItem_default as GrListItem, grListConfig };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as loader_circle_default } from "../../../chunks/loader-circle-B2rWDk5u.js";
|
|
2
|
-
import { t as grLoadingRootClass } from "../../../chunks/grLoadingStyles-
|
|
2
|
+
import { t as grLoadingRootClass } from "../../../chunks/grLoadingStyles-CrxZHFL0.js";
|
|
3
3
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, normalizeStyle, openBlock, resolveDynamicComponent, toDisplayString } from "vue";
|
|
4
4
|
import '../../../GrLoading.css';//#region src/components/GrLoading/GrLoading.vue?vue&type=script&setup=true&lang.ts
|
|
5
5
|
var _hoisted_1 = {
|
|
@@ -67,5 +67,3 @@ var GrLoading_default = /* @__PURE__ */ defineComponent({
|
|
|
67
67
|
});
|
|
68
68
|
//#endregion
|
|
69
69
|
export { GrLoading_default as t };
|
|
70
|
-
|
|
71
|
-
//# sourceMappingURL=GrLoading-DihGX3ol.js.map
|