@feugene/granularity 0.12.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/GrBadge.css +1 -1
- package/dist/GrFormFile.css +1 -1
- package/dist/GrToaster.css +1 -1
- package/dist/GrTree.css +1 -1
- package/dist/chunks/{config-ClhKPJvg.js → config-23WtUiAL.js} +1 -1
- package/dist/chunks/config-23WtUiAL.js.map +1 -0
- package/dist/chunks/config-8Pcutu1j.js.map +1 -0
- package/dist/chunks/{config-1uSYl98Y2.js → config-B0i5r8kH.js} +1 -1
- package/dist/chunks/config-B0i5r8kH.js.map +1 -0
- package/dist/chunks/{config-BOlr7qw7.js → config-B5Rknzkd.js} +33 -39
- package/dist/chunks/config-B5Rknzkd.js.map +1 -0
- package/dist/chunks/config-B7W9VlZ7.js +5 -0
- package/dist/chunks/config-B7W9VlZ7.js.map +1 -0
- package/dist/chunks/config-BDSHekVC.js +84 -0
- package/dist/chunks/config-BDSHekVC.js.map +1 -0
- package/dist/chunks/config-BLHqZhy-.js.map +1 -0
- package/dist/chunks/{config-eYLZYOUS2.js → config-BMKNHFMD2.js} +15 -15
- package/dist/chunks/config-BMKNHFMD2.js.map +1 -0
- package/dist/chunks/config-BUHuGBik2.js.map +1 -0
- package/dist/chunks/config-BX1JTrkV.js.map +1 -0
- package/dist/chunks/config-BXtAmU3s.js.map +1 -0
- package/dist/chunks/config-BZFUM3Ky.js +75 -0
- package/dist/chunks/config-BZFUM3Ky.js.map +1 -0
- package/dist/chunks/{config-DUcu1D682.js → config-BmNT0Fmx.js} +2 -2
- package/dist/chunks/config-BmNT0Fmx.js.map +1 -0
- package/dist/chunks/{config-C49QUoJL.js → config-BvVq2gbd.js} +1 -1
- package/dist/chunks/{config-C49QUoJL.js.map → config-BvVq2gbd.js.map} +1 -1
- package/dist/chunks/{config-CrG1XiE72.js → config-C4hJxXDa.js} +5 -5
- package/dist/chunks/config-C4hJxXDa.js.map +1 -0
- package/dist/chunks/config-CB4RVt9M.js +66 -0
- package/dist/chunks/config-CB4RVt9M.js.map +1 -0
- package/dist/chunks/config-CGHLoBlH2.js.map +1 -0
- package/dist/chunks/config-COE_vZ-l.js +52 -0
- package/dist/chunks/config-COE_vZ-l.js.map +1 -0
- package/dist/chunks/{config-CziwTDDL.js → config-CPdmr7tC.js} +1 -1
- package/dist/chunks/{config-CziwTDDL.js.map → config-CPdmr7tC.js.map} +1 -1
- package/dist/chunks/{config-BIRO0vDJ.js → config-DPDFYzIa.js} +2 -2
- package/dist/chunks/config-DPDFYzIa.js.map +1 -0
- package/dist/chunks/{config-DnvPqu4g2.js → config-DRKXJ9PW2.js} +1 -1
- package/dist/chunks/{config-DnvPqu4g2.js.map → config-DRKXJ9PW2.js.map} +1 -1
- package/dist/chunks/config-DToHb81g.js +45 -0
- package/dist/chunks/config-DToHb81g.js.map +1 -0
- package/dist/chunks/{config-jBp9wVv-.js → config-D_myOZbA.js} +1 -1
- package/dist/chunks/{config-jBp9wVv-.js.map → config-D_myOZbA.js.map} +1 -1
- package/dist/chunks/{config-D_R56_gT.js → config-Dg_6FTvJ.js} +1 -1
- package/dist/chunks/config-Dg_6FTvJ.js.map +1 -0
- package/dist/chunks/config-Dqy0rPPO2.js.map +1 -0
- package/dist/chunks/config-Droqn55j.js +8 -0
- package/dist/chunks/config-Droqn55j.js.map +1 -0
- package/dist/chunks/config-JpHA4Xx0.js.map +1 -0
- package/dist/chunks/{config-C4snOIXg.js → config-KXuionN3.js} +1 -1
- package/dist/chunks/{config-C4snOIXg.js.map → config-KXuionN3.js.map} +1 -1
- package/dist/chunks/{config-DezDih8_.js → config-LqDC_rvp.js} +2 -2
- package/dist/chunks/config-LqDC_rvp.js.map +1 -0
- package/dist/chunks/config-QaIc_gRa2.js.map +1 -0
- package/dist/chunks/config-U4m9PSql2.js.map +1 -0
- package/dist/chunks/{config-B7IIWGt_2.js → config-XmTv4pnI.js} +2 -2
- package/dist/chunks/config-XmTv4pnI.js.map +1 -0
- package/dist/chunks/config-eXB87DOi.js.map +1 -0
- package/dist/chunks/{config-C7NpDrfO.js → config-gZWR75Bh2.js} +1 -1
- package/dist/chunks/config-gZWR75Bh2.js.map +1 -0
- package/dist/chunks/config-ipvU0lzP.js.map +1 -0
- package/dist/chunks/config-xR4XVmcy2.js.map +1 -0
- package/dist/chunks/context-Bfrgsluh.js +9 -0
- package/dist/chunks/context-Bfrgsluh.js.map +1 -0
- package/dist/chunks/context-DfWYCBB-.js +129 -0
- package/dist/chunks/context-DfWYCBB-.js.map +1 -0
- package/dist/chunks/{en-CfkDa4GX.js → en-Cr6EkG8c.js} +46 -4
- package/dist/chunks/en-Cr6EkG8c.js.map +1 -0
- package/dist/chunks/{es-CgaLnFYx.js → es-DuYb1Qju.js} +3 -3
- package/dist/chunks/{es-CgaLnFYx.js.map → es-DuYb1Qju.js.map} +1 -1
- package/dist/chunks/{es-FkgECuCm.js → es-i08e9Sdo.js} +46 -4
- package/dist/chunks/es-i08e9Sdo.js.map +1 -0
- package/dist/chunks/{grBadgeStyles-DrycBuKT.js → grBadgeStyles-D3dFjr_N.js} +12 -12
- package/dist/chunks/grBadgeStyles-D3dFjr_N.js.map +1 -0
- package/dist/chunks/{grButtonStyles-C7Yga_Q1.js → grButtonStyles-DRBgDmOp.js} +28 -28
- package/dist/chunks/grButtonStyles-DRBgDmOp.js.map +1 -0
- package/dist/chunks/{grDropdownStyles-B_-DKytw.js → grDropdownStyles-HBPkghVr.js} +2 -2
- package/dist/chunks/{grDropdownStyles-B_-DKytw.js.map → grDropdownStyles-HBPkghVr.js.map} +1 -1
- package/dist/chunks/{grModalStyles-DWd3i05Q.js → grModalStyles-D8-shx9A.js} +1 -1
- package/dist/chunks/grModalStyles-D8-shx9A.js.map +1 -0
- package/dist/chunks/{grSelectStyles-CLK5hRd3.js → grSelectStyles-CwMUQrBZ.js} +12 -12
- package/dist/chunks/grSelectStyles-CwMUQrBZ.js.map +1 -0
- package/dist/chunks/{grStyle-Blc9otAx.js → grStyle-CdvxTXPH.js} +2 -2
- package/dist/chunks/grStyle-CdvxTXPH.js.map +1 -0
- package/dist/chunks/{granularityI18n-DoV7Ca2m.js → granularityI18n-SH0I--GW.js} +1 -1
- package/dist/chunks/{granularityI18n-DoV7Ca2m.js.map → granularityI18n-SH0I--GW.js.map} +1 -1
- package/dist/chunks/{ru-Bl8CxpEa.js → ru-B5XOOYZt.js} +46 -4
- package/dist/chunks/ru-B5XOOYZt.js.map +1 -0
- package/dist/chunks/{safelist-Do2RtzLB.js → safelist-BvO8HPnE.js} +1 -1
- package/dist/chunks/{safelist-Do2RtzLB.js.map → safelist-BvO8HPnE.js.map} +1 -1
- package/dist/chunks/shared-D-v9lit0.js +188 -0
- package/dist/chunks/shared-D-v9lit0.js.map +1 -0
- package/dist/components/GrAlert/chunks/GrAlert-B9gmpoPC.js +251 -0
- package/dist/components/GrAlert/chunks/GrAlert-B9gmpoPC.js.map +1 -0
- package/dist/components/GrAlert/index.js +2 -2
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-BVLoQ5tZ.js +499 -0
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-BVLoQ5tZ.js.map +1 -0
- package/dist/components/GrAutocomplete/index.js +3 -0
- package/dist/components/GrAvatar/chunks/{GrAvatar-96CpTCq5.js → GrAvatar-CTOUVBF7.js} +1 -1
- package/dist/components/GrAvatar/chunks/GrAvatar-CTOUVBF7.js.map +1 -0
- package/dist/components/GrAvatar/index.js +1 -1
- package/dist/components/GrBadge/chunks/{GrBadge-B77XlaqE.js → GrBadge-D1jefy4S.js} +12 -8
- package/dist/components/GrBadge/chunks/GrBadge-D1jefy4S.js.map +1 -0
- package/dist/components/GrBadge/index.js +2 -2
- package/dist/components/GrBadgeWrap/chunks/{GrBadgeWrap-CcktMOdg.js → GrBadgeWrap-DWDxHdiQ.js} +1 -1
- package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-DWDxHdiQ.js.map +1 -0
- package/dist/components/GrBadgeWrap/index.js +1 -1
- package/dist/components/GrBottomNav/chunks/{GrBottomNav-usuMgG8_.js → GrBottomNav-vSE4LXmk.js} +2 -2
- package/dist/components/GrBottomNav/chunks/GrBottomNav-vSE4LXmk.js.map +1 -0
- package/dist/components/GrBottomNav/index.js +1 -1
- package/dist/components/GrButton/chunks/{GrButton-BlffdeJr.js → GrButton-DCi4CUpo.js} +18 -14
- package/dist/components/GrButton/chunks/GrButton-DCi4CUpo.js.map +1 -0
- package/dist/components/GrButton/index.js +4 -4
- package/dist/components/GrCard/chunks/{GrCard-DUNMkuHW.js → GrCard-CxCjyHMb.js} +1 -1
- package/dist/components/GrCard/chunks/GrCard-CxCjyHMb.js.map +1 -0
- package/dist/components/GrCard/index.js +1 -1
- package/dist/components/GrCheckbox/chunks/{GrCheckbox-DJhzZZdO.js → GrCheckbox-BbIDRXtl.js} +5 -5
- package/dist/components/GrCheckbox/chunks/GrCheckbox-BbIDRXtl.js.map +1 -0
- package/dist/components/GrCheckbox/index.js +1 -1
- package/dist/components/GrCollapse/chunks/{GrCollapse-CPPLh_xU.js → GrCollapse-DApXztn8.js} +6 -6
- package/dist/components/GrCollapse/chunks/GrCollapse-DApXztn8.js.map +1 -0
- package/dist/components/GrCollapse/index.js +2 -2
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-6OyvNbek.js +410 -0
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-6OyvNbek.js.map +1 -0
- package/dist/components/GrCommandPalette/index.js +3 -0
- package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BtyeBGm8.js +57 -0
- package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BtyeBGm8.js.map +1 -0
- package/dist/components/GrConfigProvider/index.js +4 -0
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-D8CkOtqv.js → GrConfirmDialog-e4120mWw.js} +5 -5
- package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-e4120mWw.js.map +1 -0
- package/dist/components/GrConfirmDialog/index.js +2 -2
- package/dist/components/GrDataTable/chunks/{GrDataTable-Ds5OeGat.js → GrDataTable-C1CzxV0p.js} +127 -25
- package/dist/components/GrDataTable/chunks/GrDataTable-C1CzxV0p.js.map +1 -0
- package/dist/components/GrDataTable/index.js +2 -2
- package/dist/components/GrDialog/chunks/{GrDialog-Ctucxju9.js → GrDialog-BPMvDHOz.js} +5 -5
- package/dist/components/GrDialog/chunks/GrDialog-BPMvDHOz.js.map +1 -0
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-CU1Fbonc.js → GrDialogService-CYXCTGm3.js} +36 -11
- package/dist/components/GrDialogService/chunks/GrDialogService-CYXCTGm3.js.map +1 -0
- package/dist/components/GrDialogService/index.js +2 -2
- package/dist/components/GrDivider/chunks/{GrDivider-5bcE-BB4.js → GrDivider-BdENZ1w0.js} +5 -5
- package/dist/components/GrDivider/chunks/GrDivider-BdENZ1w0.js.map +1 -0
- package/dist/components/GrDivider/index.js +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-SLGKCY2A.js → GrDrawer-KevdZ5BB.js} +5 -5
- package/dist/components/GrDrawer/chunks/GrDrawer-KevdZ5BB.js.map +1 -0
- package/dist/components/GrDrawer/index.js +2 -2
- package/dist/components/GrDropdown/chunks/{GrDropdown-BnDMYP8v.js → GrDropdown-BKoy8hm-.js} +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-BnDMYP8v.js.map → GrDropdown-BKoy8hm-.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu--g9Vofcq.js → GrDropdownMenu-zCatXzmt.js} +11 -11
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-zCatXzmt.js.map +1 -0
- package/dist/components/GrDropdownMenu/index.js +1 -1
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-CA3BiTV7.js → GrEmptyState-CNb0BzjG.js} +3 -3
- package/dist/components/GrEmptyState/chunks/GrEmptyState-CNb0BzjG.js.map +1 -0
- package/dist/components/GrEmptyState/index.js +1 -1
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-DvWPpiJS.js → GrFileUpload-CnLgUGDF.js} +12 -12
- package/dist/components/GrFileUpload/chunks/GrFileUpload-CnLgUGDF.js.map +1 -0
- package/dist/components/GrFileUpload/index.js +1 -1
- package/dist/components/GrForm/chunks/GrForm-CdaFjcyl.js +234 -0
- package/dist/components/GrForm/chunks/GrForm-CdaFjcyl.js.map +1 -0
- package/dist/components/GrForm/index.js +4 -0
- package/dist/components/GrFormField/chunks/{GrFormField-DnfMHx_U.js → GrFormField-CXCDBd99.js} +41 -14
- package/dist/components/GrFormField/chunks/GrFormField-CXCDBd99.js.map +1 -0
- package/dist/components/GrFormField/index.js +1 -1
- package/dist/components/GrFormFile/chunks/{GrFormFile-CXcqqdvV.js → GrFormFile-CqacSbUl.js} +9 -9
- package/dist/components/GrFormFile/chunks/GrFormFile-CqacSbUl.js.map +1 -0
- package/dist/components/GrFormFile/index.js +1 -1
- package/dist/components/GrFormSection/chunks/{GrFormSection-Ce21jcgo.js → GrFormSection-C3w9DQJf.js} +1 -1
- package/dist/components/GrFormSection/chunks/GrFormSection-C3w9DQJf.js.map +1 -0
- package/dist/components/GrFormSection/index.js +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dla9IBkd.js → GrImageViewer-DDLJkvIU.js} +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dla9IBkd.js.map → GrImageViewer-DDLJkvIU.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInput/chunks/{GrInput-B8dd3JaA.js → GrInput-C1VBL0dg.js} +18 -15
- package/dist/components/GrInput/chunks/GrInput-C1VBL0dg.js.map +1 -0
- package/dist/components/GrInput/index.js +2 -2
- package/dist/components/GrInputTag/chunks/{GrInputTag-zMgFqp2g.js → GrInputTag-BMk9jm42.js} +6 -6
- package/dist/components/GrInputTag/chunks/GrInputTag-BMk9jm42.js.map +1 -0
- package/dist/components/GrInputTag/index.js +2 -2
- package/dist/components/GrKbd/chunks/{GrKbd-BEoYxWhE.js → GrKbd-DTspwtoN.js} +1 -1
- package/dist/components/GrKbd/chunks/GrKbd-DTspwtoN.js.map +1 -0
- package/dist/components/GrKbd/index.js +1 -1
- package/dist/components/GrLink/chunks/{GrLink-CYUe-Q8k.js → GrLink-BP0YrnL9.js} +1 -1
- package/dist/components/GrLink/chunks/{GrLink-CYUe-Q8k.js.map → GrLink-BP0YrnL9.js.map} +1 -1
- package/dist/components/GrLink/index.js +2 -2
- package/dist/components/GrList/chunks/{GrList-Dx772Ns4.js → GrList-5RA-tZzE.js} +3 -3
- package/dist/components/GrList/chunks/GrList-5RA-tZzE.js.map +1 -0
- package/dist/components/GrList/index.js +1 -1
- package/dist/components/GrLoading/chunks/{GrLoading--X_7rdbb.js → GrLoading-fRDtVfi7.js} +3 -3
- package/dist/components/GrLoading/chunks/GrLoading-fRDtVfi7.js.map +1 -0
- package/dist/components/GrLoading/index.js +2 -2
- package/dist/components/GrModal/chunks/{GrModal-C0GZrHN3.js → GrModal-BTu1-5eY.js} +1 -1
- package/dist/components/GrModal/chunks/{GrModal-C0GZrHN3.js.map → GrModal-BTu1-5eY.js.map} +1 -1
- package/dist/components/GrModal/index.js +3 -3
- package/dist/components/GrNavbar/chunks/{GrNavbar-DW3MiIIf.js → GrNavbar-keKT_mIM.js} +3 -3
- package/dist/components/GrNavbar/chunks/GrNavbar-keKT_mIM.js.map +1 -0
- package/dist/components/GrNavbar/index.js +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-DxCEvL7V.js → GrNumberInput-l9ZOHG9D.js} +19 -17
- package/dist/components/GrNumberInput/chunks/GrNumberInput-l9ZOHG9D.js.map +1 -0
- package/dist/components/GrNumberInput/index.js +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-mlyfLjQY.js → GrPagination-C5Y69CuK.js} +59 -16
- package/dist/components/GrPagination/chunks/GrPagination-C5Y69CuK.js.map +1 -0
- package/dist/components/GrPagination/index.js +2 -2
- package/dist/components/GrProgressBar/chunks/{GrProgressBar-CC3z-Zqp.js → GrProgressBar-Dqg4Fj9S.js} +2 -2
- package/dist/components/GrProgressBar/chunks/GrProgressBar-Dqg4Fj9S.js.map +1 -0
- package/dist/components/GrProgressBar/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-C-_BMNuY.js → GrPromptDialog-DNUjRVB9.js} +7 -7
- package/dist/components/GrPromptDialog/chunks/GrPromptDialog-DNUjRVB9.js.map +1 -0
- package/dist/components/GrPromptDialog/index.js +2 -2
- package/dist/components/GrRadio/chunks/{GrRadio-Dr-pvs_9.js → GrRadio-DlhxPGqf.js} +5 -7
- package/dist/components/GrRadio/chunks/GrRadio-DlhxPGqf.js.map +1 -0
- package/dist/components/GrRadio/index.js +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-nOdvfV_g.js → GrRadioGroup-BXt9iw4q.js} +7 -5
- package/dist/components/GrRadioGroup/chunks/GrRadioGroup-BXt9iw4q.js.map +1 -0
- package/dist/components/GrRadioGroup/index.js +2 -2
- package/dist/components/GrRating/chunks/GrRating-Co-3Rk4h.js +241 -0
- package/dist/components/GrRating/chunks/GrRating-Co-3Rk4h.js.map +1 -0
- package/dist/components/GrRating/index.js +3 -0
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BWJNe2gr.js → GrResponseErrorBanner-2CvM7Z08.js} +2 -2
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BWJNe2gr.js.map → GrResponseErrorBanner-2CvM7Z08.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-Cdu9ekK9.js → GrResponseErrorBanner-C8NGx8pE.js} +3 -3
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-Cdu9ekK9.js.map → GrResponseErrorBanner-C8NGx8pE.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/index.js +2 -2
- package/dist/components/GrSegmented/chunks/{GrSegmented-C1y0UXpQ.js → GrSegmented-CTd3n4PA.js} +14 -11
- package/dist/components/GrSegmented/chunks/GrSegmented-CTd3n4PA.js.map +1 -0
- package/dist/components/GrSegmented/index.js +2 -2
- package/dist/components/GrSelect/chunks/{GrSelect-BVCmitqa.js → GrSelect-Dn3FgJ3Z.js} +161 -75
- package/dist/components/GrSelect/chunks/GrSelect-Dn3FgJ3Z.js.map +1 -0
- package/dist/components/GrSelect/index.js +2 -2
- package/dist/components/GrSidebar/chunks/{GrSidebar-DkWozzwA.js → GrSidebar-cvnzBfj3.js} +7 -7
- package/dist/components/GrSidebar/chunks/GrSidebar-cvnzBfj3.js.map +1 -0
- package/dist/components/GrSidebar/index.js +2 -2
- package/dist/components/GrSkeleton/chunks/{GrSkeleton-DsN-_CDZ.js → GrSkeleton-BucA5F4J.js} +1 -1
- package/dist/components/GrSkeleton/chunks/GrSkeleton-BucA5F4J.js.map +1 -0
- package/dist/components/GrSkeleton/index.js +2 -2
- package/dist/components/GrSlider/chunks/GrSlider-CzzJ3bD-.js +286 -0
- package/dist/components/GrSlider/chunks/GrSlider-CzzJ3bD-.js.map +1 -0
- package/dist/components/GrSlider/index.js +3 -0
- package/dist/components/GrStatistic/chunks/GrStatistic-gHiAwrX5.js +128 -0
- package/dist/components/GrStatistic/chunks/GrStatistic-gHiAwrX5.js.map +1 -0
- package/dist/components/GrStatistic/index.js +3 -0
- package/dist/components/GrSwitch/chunks/{GrSwitch-DAioyccZ.js → GrSwitch-CJdRvS0s.js} +16 -7
- package/dist/components/GrSwitch/chunks/GrSwitch-CJdRvS0s.js.map +1 -0
- package/dist/components/GrSwitch/index.js +2 -2
- package/dist/components/GrTabPanels/chunks/{GrTabPanels-DbKybwe-.js → GrTabPanels-DeEMgb_y.js} +1 -1
- package/dist/components/GrTabPanels/chunks/{GrTabPanels-DbKybwe-.js.map → GrTabPanels-DeEMgb_y.js.map} +1 -1
- package/dist/components/GrTabPanels/index.js +2 -2
- package/dist/components/GrTable/chunks/{GrTable-Db3hRnKA.js → GrTable-sNvsA8wa.js} +24 -11
- package/dist/components/GrTable/chunks/GrTable-sNvsA8wa.js.map +1 -0
- package/dist/components/GrTable/index.js +2 -2
- package/dist/components/GrTabs/chunks/{GrTabs-DsLwWoRz.js → GrTabs-BqTak0SR.js} +3 -3
- package/dist/components/GrTabs/chunks/GrTabs-BqTak0SR.js.map +1 -0
- package/dist/components/GrTabs/index.js +2 -2
- package/dist/components/GrTextarea/chunks/{GrTextarea-CKukGlNl.js → GrTextarea-DIYBAPpP.js} +2 -2
- package/dist/components/GrTextarea/chunks/GrTextarea-DIYBAPpP.js.map +1 -0
- package/dist/components/GrTextarea/index.js +2 -2
- package/dist/components/GrToaster/chunks/{GrToaster-L2cu6cSR.js → GrToaster-BVHjIHcM.js} +51 -10
- package/dist/components/GrToaster/chunks/GrToaster-BVHjIHcM.js.map +1 -0
- package/dist/components/GrToaster/index.js +1 -1
- package/dist/components/GrTooltip/chunks/{GrTooltip-BeyZ8ssR.js → GrTooltip-BMKH2lIx.js} +3 -3
- package/dist/components/GrTooltip/chunks/GrTooltip-BMKH2lIx.js.map +1 -0
- package/dist/components/GrTooltip/index.js +1 -1
- package/dist/components/GrTree/chunks/{GrTree-B2_yW6g1.js → GrTree-_12ChXRQ.js} +3 -3
- package/dist/components/GrTree/chunks/GrTree-_12ChXRQ.js.map +1 -0
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-0aM62xyu.js → GrTreeSelect-CdaLG7Xq.js} +10 -10
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-CdaLG7Xq.js.map +1 -0
- package/dist/components/GrTreeSelect/index.js +2 -2
- package/dist/composables/useToast.js +3 -1
- package/dist/composables/useToast.js.map +1 -1
- package/dist/directives/loading.js +1 -1
- package/dist/granular-provider-node.js +6 -6
- package/dist/granular-provider-node.js.map +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/i18n/all.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.js +111 -93
- package/dist/index.js.map +1 -1
- package/dist/styles/base.css +2 -2
- package/dist/styles/index.css +6 -3
- package/dist/styles/preflight.css +3 -3
- package/dist/styles/themes/dark.css +52 -40
- package/dist/styles/themes/light.css +70 -45
- package/dist/styles/tokens.css +20 -20
- package/dist/types/src/components/GrAlert/GrAlert.vue.d.ts +26 -14
- package/dist/types/src/components/GrAlert/defaults.d.ts +17 -0
- package/dist/types/src/components/GrAlert/grAlertStyles.d.ts +55 -0
- package/dist/types/src/components/GrAlert/index.d.ts +4 -1
- package/dist/types/src/components/GrAutocomplete/GrAutocomplete.vue.d.ts +153 -0
- package/dist/types/src/components/GrAutocomplete/config.d.ts +1 -0
- package/dist/types/src/components/GrAutocomplete/defaults.d.ts +15 -0
- package/dist/types/src/components/GrAutocomplete/grAutocompleteStyles.d.ts +27 -0
- package/dist/types/src/components/GrAutocomplete/index.d.ts +6 -0
- package/dist/types/src/components/GrAutocomplete/safelist.d.ts +1 -0
- package/dist/types/src/components/GrAvatar/GrAvatar.vue.d.ts +1 -1
- package/dist/types/src/components/GrBadge/GrBadge.vue.d.ts +7 -7
- package/dist/types/src/components/GrBadge/defaults.d.ts +15 -0
- package/dist/types/src/components/GrBadge/index.d.ts +1 -0
- package/dist/types/src/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +1 -1
- package/dist/types/src/components/GrButton/GrButton.vue.d.ts +12 -12
- package/dist/types/src/components/GrButton/defaults.d.ts +25 -0
- package/dist/types/src/components/GrButton/grButtonStyles.d.ts +2 -2
- package/dist/types/src/components/GrButton/index.d.ts +1 -0
- package/dist/types/src/components/GrCheckbox/GrCheckbox.vue.d.ts +4 -4
- package/dist/types/src/components/GrCollapse/GrCollapse.vue.d.ts +2 -2
- package/dist/types/src/components/GrCollapse/GrCollapseItem.vue.d.ts +1 -1
- package/dist/types/src/components/GrCommandPalette/GrCommandPalette.vue.d.ts +128 -0
- package/dist/types/src/components/GrCommandPalette/config.d.ts +1 -0
- package/dist/types/src/components/GrCommandPalette/filtering.d.ts +35 -0
- package/dist/types/src/components/GrCommandPalette/grCommandPaletteStyles.d.ts +20 -0
- package/dist/types/src/components/GrCommandPalette/hotkey.d.ts +23 -0
- package/dist/types/src/components/GrCommandPalette/index.d.ts +6 -0
- package/dist/types/src/components/GrCommandPalette/safelist.d.ts +1 -0
- package/dist/types/src/components/GrConfigProvider/GrConfigProvider.vue.d.ts +59 -0
- package/dist/types/src/components/GrConfigProvider/config.d.ts +1 -0
- package/dist/types/src/components/GrConfigProvider/context.d.ts +131 -0
- package/dist/types/src/components/GrConfigProvider/index.d.ts +5 -0
- package/dist/types/src/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +2 -2
- package/dist/types/src/components/GrDataTable/GrDataTable.vue.d.ts +20 -0
- package/dist/types/src/components/GrDialog/GrDialog.vue.d.ts +1 -1
- package/dist/types/src/components/GrDialogService/store.d.ts +18 -0
- package/dist/types/src/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
- package/dist/types/src/components/GrDropdown/GrDropdown.vue.d.ts +1 -1
- package/dist/types/src/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +1 -1
- package/dist/types/src/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +1 -1
- package/dist/types/src/components/GrFileUpload/GrFileUpload.vue.d.ts +3 -3
- package/dist/types/src/components/GrForm/GrForm.vue.d.ts +93 -0
- package/dist/types/src/components/GrForm/config.d.ts +1 -0
- package/dist/types/src/components/GrForm/context.d.ts +27 -0
- package/dist/types/src/components/GrForm/index.d.ts +6 -0
- package/dist/types/src/components/GrForm/validation.d.ts +52 -0
- package/dist/types/src/components/GrFormField/GrFormField.vue.d.ts +11 -1
- package/dist/types/src/components/GrFormFile/GrFormFile.vue.d.ts +4 -4
- package/dist/types/src/components/GrImageViewer/GrImageViewer.vue.d.ts +3 -3
- package/dist/types/src/components/GrInput/GrInput.vue.d.ts +12 -12
- package/dist/types/src/components/GrInput/defaults.d.ts +18 -0
- package/dist/types/src/components/GrInput/grInputStyles.d.ts +1 -1
- package/dist/types/src/components/GrInput/index.d.ts +1 -0
- package/dist/types/src/components/GrInputTag/GrInputTag.vue.d.ts +3 -3
- package/dist/types/src/components/GrLink/GrLink.vue.d.ts +3 -3
- package/dist/types/src/components/GrLink/grLinkStyles.d.ts +3 -3
- package/dist/types/src/components/GrModal/grModalStyles.d.ts +1 -1
- package/dist/types/src/components/GrNumberInput/GrNumberInput.vue.d.ts +10 -10
- package/dist/types/src/components/GrNumberInput/defaults.d.ts +14 -0
- package/dist/types/src/components/GrNumberInput/index.d.ts +1 -0
- package/dist/types/src/components/GrPagination/GrPagination.vue.d.ts +18 -0
- package/dist/types/src/components/GrPromptDialog/GrPromptDialog.vue.d.ts +4 -4
- package/dist/types/src/components/GrRadio/GrRadio.vue.d.ts +5 -5
- package/dist/types/src/components/GrRadio/defaults.d.ts +14 -0
- package/dist/types/src/components/GrRadio/grRadioStyles.d.ts +3 -3
- package/dist/types/src/components/GrRadio/index.d.ts +1 -0
- package/dist/types/src/components/GrRadioGroup/GrRadioGroup.vue.d.ts +4 -4
- package/dist/types/src/components/GrRadioGroup/defaults.d.ts +14 -0
- package/dist/types/src/components/GrRadioGroup/index.d.ts +1 -0
- package/dist/types/src/components/GrRating/GrRating.vue.d.ts +124 -0
- package/dist/types/src/components/GrRating/config.d.ts +1 -0
- package/dist/types/src/components/GrRating/defaults.d.ts +14 -0
- package/dist/types/src/components/GrRating/grRatingStyles.d.ts +21 -0
- package/dist/types/src/components/GrRating/index.d.ts +6 -0
- package/dist/types/src/components/GrRating/safelist.d.ts +1 -0
- package/dist/types/src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue.d.ts +1 -1
- package/dist/types/src/components/GrSegmented/GrSegmented.vue.d.ts +7 -7
- package/dist/types/src/components/GrSegmented/defaults.d.ts +15 -0
- package/dist/types/src/components/GrSegmented/grSegmentedStyles.d.ts +1 -1
- package/dist/types/src/components/GrSegmented/index.d.ts +1 -0
- package/dist/types/src/components/GrSelect/GrSelect.vue.d.ts +57 -17
- package/dist/types/src/components/GrSelect/defaults.d.ts +17 -0
- package/dist/types/src/components/GrSelect/grSelectStyles.d.ts +3 -3
- package/dist/types/src/components/GrSelect/index.d.ts +1 -0
- package/dist/types/src/components/GrSidebar/GrSidebarItem.vue.d.ts +2 -2
- package/dist/types/src/components/GrSkeleton/GrSkeleton.vue.d.ts +1 -1
- package/dist/types/src/components/GrSlider/GrSlider.vue.d.ts +88 -0
- package/dist/types/src/components/GrSlider/config.d.ts +1 -0
- package/dist/types/src/components/GrSlider/defaults.d.ts +14 -0
- package/dist/types/src/components/GrSlider/grSliderStyles.d.ts +36 -0
- package/dist/types/src/components/GrSlider/index.d.ts +6 -0
- package/dist/types/src/components/GrSlider/safelist.d.ts +1 -0
- package/dist/types/src/components/GrStatistic/GrStatistic.vue.d.ts +116 -0
- package/dist/types/src/components/GrStatistic/config.d.ts +1 -0
- package/dist/types/src/components/GrStatistic/formatStatisticValue.d.ts +16 -0
- package/dist/types/src/components/GrStatistic/grStatisticStyles.d.ts +24 -0
- package/dist/types/src/components/GrStatistic/index.d.ts +6 -0
- package/dist/types/src/components/GrStatistic/safelist.d.ts +1 -0
- package/dist/types/src/components/GrSwitch/GrSwitch.vue.d.ts +4 -4
- package/dist/types/src/components/GrSwitch/defaults.d.ts +14 -0
- package/dist/types/src/components/GrSwitch/grSwitchStyles.d.ts +2 -2
- package/dist/types/src/components/GrSwitch/index.d.ts +1 -0
- package/dist/types/src/components/GrTable/GrTable.vue.d.ts +16 -0
- package/dist/types/src/components/GrTextarea/GrTextarea.vue.d.ts +5 -5
- package/dist/types/src/components/GrToaster/GrToaster.vue.d.ts +19 -2
- package/dist/types/src/components/GrToaster/index.d.ts +1 -1
- package/dist/types/src/components/GrTooltip/GrTooltip.vue.d.ts +1 -1
- package/dist/types/src/components/GrTreeSelect/GrTreeSelect.vue.d.ts +1 -1
- package/dist/types/src/components/GrTreeSelect/grTreeSelectStyles.d.ts +1 -1
- package/dist/types/src/composables/useToast.d.ts +24 -0
- package/dist/types/src/granular-provider/shared.d.ts +7 -0
- package/dist/types/src/i18n/messages/en.d.ts +74 -0
- package/dist/types/src/i18n/messages/es.d.ts +74 -0
- package/dist/types/src/i18n/messages/ru.d.ts +74 -0
- package/dist/types/src/index.d.ts +7 -0
- package/dist/web-types.json +1308 -271
- package/package.json +29 -1
- package/dist/chunks/config-1uSYl98Y2.js.map +0 -1
- package/dist/chunks/config-8Pcutu1j2.js.map +0 -1
- package/dist/chunks/config-B7IIWGt_2.js.map +0 -1
- package/dist/chunks/config-BIRO0vDJ.js.map +0 -1
- package/dist/chunks/config-BLHqZhy-2.js.map +0 -1
- package/dist/chunks/config-BOlr7qw7.js.map +0 -1
- package/dist/chunks/config-BUHuGBik.js.map +0 -1
- package/dist/chunks/config-BX1JTrkV2.js.map +0 -1
- package/dist/chunks/config-BXtAmU3s2.js.map +0 -1
- package/dist/chunks/config-C7NpDrfO.js.map +0 -1
- package/dist/chunks/config-CGHLoBlH.js.map +0 -1
- package/dist/chunks/config-ClhKPJvg.js.map +0 -1
- package/dist/chunks/config-Cpi9Mh2J.js.map +0 -1
- package/dist/chunks/config-CrG1XiE72.js.map +0 -1
- package/dist/chunks/config-DUcu1D682.js.map +0 -1
- package/dist/chunks/config-D_R56_gT.js.map +0 -1
- package/dist/chunks/config-DezDih8_.js.map +0 -1
- package/dist/chunks/config-JpHA4Xx02.js.map +0 -1
- package/dist/chunks/config-QaIc_gRa.js.map +0 -1
- package/dist/chunks/config-U4m9PSql.js.map +0 -1
- package/dist/chunks/config-eXB87DOi2.js.map +0 -1
- package/dist/chunks/config-eYLZYOUS2.js.map +0 -1
- package/dist/chunks/config-ipvU0lzP2.js.map +0 -1
- package/dist/chunks/config-xR4XVmcy.js.map +0 -1
- package/dist/chunks/en-CfkDa4GX.js.map +0 -1
- package/dist/chunks/es-FkgECuCm.js.map +0 -1
- package/dist/chunks/grBadgeStyles-DrycBuKT.js.map +0 -1
- package/dist/chunks/grButtonStyles-C7Yga_Q1.js.map +0 -1
- package/dist/chunks/grModalStyles-DWd3i05Q.js.map +0 -1
- package/dist/chunks/grSelectStyles-CLK5hRd3.js.map +0 -1
- package/dist/chunks/grStyle-Blc9otAx.js.map +0 -1
- package/dist/chunks/ru-Bl8CxpEa.js.map +0 -1
- package/dist/chunks/shared-B6Ay2081.js +0 -174
- package/dist/chunks/shared-B6Ay2081.js.map +0 -1
- package/dist/components/GrAlert/chunks/GrAlert-DPJSU_fG.js +0 -163
- package/dist/components/GrAlert/chunks/GrAlert-DPJSU_fG.js.map +0 -1
- package/dist/components/GrAvatar/chunks/GrAvatar-96CpTCq5.js.map +0 -1
- package/dist/components/GrBadge/chunks/GrBadge-B77XlaqE.js.map +0 -1
- package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-CcktMOdg.js.map +0 -1
- package/dist/components/GrBottomNav/chunks/GrBottomNav-usuMgG8_.js.map +0 -1
- package/dist/components/GrButton/chunks/GrButton-BlffdeJr.js.map +0 -1
- package/dist/components/GrCard/chunks/GrCard-DUNMkuHW.js.map +0 -1
- package/dist/components/GrCheckbox/chunks/GrCheckbox-DJhzZZdO.js.map +0 -1
- package/dist/components/GrCollapse/chunks/GrCollapse-CPPLh_xU.js.map +0 -1
- package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-D8CkOtqv.js.map +0 -1
- package/dist/components/GrDataTable/chunks/GrDataTable-Ds5OeGat.js.map +0 -1
- package/dist/components/GrDialog/chunks/GrDialog-Ctucxju9.js.map +0 -1
- package/dist/components/GrDialogService/chunks/GrDialogService-CU1Fbonc.js.map +0 -1
- package/dist/components/GrDivider/chunks/GrDivider-5bcE-BB4.js.map +0 -1
- package/dist/components/GrDrawer/chunks/GrDrawer-SLGKCY2A.js.map +0 -1
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu--g9Vofcq.js.map +0 -1
- package/dist/components/GrEmptyState/chunks/GrEmptyState-CA3BiTV7.js.map +0 -1
- package/dist/components/GrFileUpload/chunks/GrFileUpload-DvWPpiJS.js.map +0 -1
- package/dist/components/GrFormField/chunks/GrFormField-DnfMHx_U.js.map +0 -1
- package/dist/components/GrFormFile/chunks/GrFormFile-CXcqqdvV.js.map +0 -1
- package/dist/components/GrFormSection/chunks/GrFormSection-Ce21jcgo.js.map +0 -1
- package/dist/components/GrInput/chunks/GrInput-B8dd3JaA.js.map +0 -1
- package/dist/components/GrInputTag/chunks/GrInputTag-zMgFqp2g.js.map +0 -1
- package/dist/components/GrKbd/chunks/GrKbd-BEoYxWhE.js.map +0 -1
- package/dist/components/GrList/chunks/GrList-Dx772Ns4.js.map +0 -1
- package/dist/components/GrLoading/chunks/GrLoading--X_7rdbb.js.map +0 -1
- package/dist/components/GrNavbar/chunks/GrNavbar-DW3MiIIf.js.map +0 -1
- package/dist/components/GrNumberInput/chunks/GrNumberInput-DxCEvL7V.js.map +0 -1
- package/dist/components/GrPagination/chunks/GrPagination-mlyfLjQY.js.map +0 -1
- package/dist/components/GrProgressBar/chunks/GrProgressBar-CC3z-Zqp.js.map +0 -1
- package/dist/components/GrPromptDialog/chunks/GrPromptDialog-C-_BMNuY.js.map +0 -1
- package/dist/components/GrRadio/chunks/GrRadio-Dr-pvs_9.js.map +0 -1
- package/dist/components/GrRadioGroup/chunks/GrRadioGroup-nOdvfV_g.js.map +0 -1
- package/dist/components/GrSegmented/chunks/GrSegmented-C1y0UXpQ.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-BVCmitqa.js.map +0 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-DkWozzwA.js.map +0 -1
- package/dist/components/GrSkeleton/chunks/GrSkeleton-DsN-_CDZ.js.map +0 -1
- package/dist/components/GrSwitch/chunks/GrSwitch-DAioyccZ.js.map +0 -1
- package/dist/components/GrTable/chunks/GrTable-Db3hRnKA.js.map +0 -1
- package/dist/components/GrTabs/chunks/GrTabs-DsLwWoRz.js.map +0 -1
- package/dist/components/GrTextarea/chunks/GrTextarea-CKukGlNl.js.map +0 -1
- package/dist/components/GrToaster/chunks/GrToaster-L2cu6cSR.js.map +0 -1
- package/dist/components/GrTooltip/chunks/GrTooltip-BeyZ8ssR.js.map +0 -1
- package/dist/components/GrTree/chunks/GrTree-B2_yW6g1.js.map +0 -1
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-0aM62xyu.js.map +0 -1
- package/dist/chunks/{config-8Pcutu1j2.js → config-8Pcutu1j.js} +0 -0
- package/dist/chunks/{config-BLHqZhy-2.js → config-BLHqZhy-.js} +0 -0
- package/dist/chunks/{config-BUHuGBik.js → config-BUHuGBik2.js} +0 -0
- package/dist/chunks/{config-BX1JTrkV2.js → config-BX1JTrkV.js} +0 -0
- package/dist/chunks/{config-BXtAmU3s2.js → config-BXtAmU3s.js} +0 -0
- package/dist/chunks/{config-CGHLoBlH.js → config-CGHLoBlH2.js} +0 -0
- package/dist/chunks/{config-Cpi9Mh2J.js → config-Dqy0rPPO2.js} +1 -1
- /package/dist/chunks/{config-JpHA4Xx02.js → config-JpHA4Xx0.js} +0 -0
- /package/dist/chunks/{config-QaIc_gRa.js → config-QaIc_gRa2.js} +0 -0
- /package/dist/chunks/{config-U4m9PSql.js → config-U4m9PSql2.js} +0 -0
- /package/dist/chunks/{config-eXB87DOi2.js → config-eXB87DOi.js} +0 -0
- /package/dist/chunks/{config-ipvU0lzP2.js → config-ipvU0lzP.js} +0 -0
- /package/dist/chunks/{config-xR4XVmcy.js → config-xR4XVmcy2.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrModal-C0GZrHN3.js","names":["$slots"],"sources":["../../../../src/components/GrModal/grModalTopStack.ts","../../../../src/components/GrModal/GrModal.vue","../../../../src/components/GrModal/GrModal.vue"],"sourcesContent":["/**\n * grModalTopStack — общий стек открытых `GrModal` для вычисления «верхнего»\n * (последнего открытого) окна независимо от дерева рендера.\n *\n * Зачем нужен:\n * HeadlessUI ловит фокус (`FocusTrap` с `FocusLock`) у каждого открытого\n * `<Dialog>` и помечает остальную часть страницы как inert. Когда модалки\n * рендерятся в разных деревьях (например, диалоги `useDialogService`\n * монтируются отдельным `render()` в `document.body`), их HeadlessUI-стек не\n * общий: каждый `<Dialog>` считает себя верхним и продолжает удерживать фокус.\n * В итоге нижнее окно «ворует» фокус у верхнего диалога — нельзя, например,\n * сфокусировать input в открытом поверх `prompt`.\n *\n * Решение: единый стек регистраций. Верхней считается последняя\n * зарегистрированная модалка. Все нижние окна уведомляются (`setTopmost(false)`)\n * и помечают свой корень `inert`, освобождая фокус для верхнего окна. Когда\n * верхнее окно закрывается, следующая по стеку модалка снова становится\n * верхней (`setTopmost(true)`) и снимает `inert`.\n */\n\nexport interface GrModalTopEntry {\n /** Уникальный id зарегистрированной модалки. */\n id: number\n /** Колбэк-уведомление: является ли модалка сейчас верхней. */\n setTopmost: (isTopmost: boolean) => void\n}\n\nconst stack: GrModalTopEntry[] = []\nlet nextId = 1\n\n/** Пересчитывает «верхнее» окно и уведомляет все зарегистрированные модалки. */\nfunction sync(): void {\n const lastIndex = stack.length - 1\n stack.forEach((entry, index) => entry.setTopmost(index === lastIndex))\n}\n\n/** Регистрирует открытую модалку как верхнюю и возвращает её id. */\nexport function pushGrModalTop(entry: Omit<GrModalTopEntry, 'id'>): number {\n const id = nextId++\n stack.push({ ...entry, id })\n sync()\n return id\n}\n\n/** Снимает модалку со стека (при закрытии или размонтировании). */\nexport function removeGrModalTop(id: number): void {\n const index = stack.findIndex(item => item.id === id)\n if (index >= 0) stack.splice(index, 1)\n sync()\n}\n\n/** Тестовая/служебная очистка стека. */\nexport function resetGrModalTopStack(): void {\n stack.splice(0, stack.length)\n}\n","<script setup lang=\"ts\">\n/**\n * GrModal — GR-примитив модального окна на базе `@headlessui/vue`.\n *\n * Публичный API:\n * - `modelValue` (v-model) — открыто/закрыто;\n * - `size` — размер панели (`sm | md | lg | xl | full`);\n * - `closeOnBackdrop` (default: true) — закрывать при клике по оверлею;\n * - `closeOnEsc` (default: true) — закрывать по Esc;\n * - слоты `#title` / `#description` — если переданы, оборачиваются в\n * `DialogTitle` / `DialogDescription` (связь через `aria-labelledby` /\n * `aria-describedby` ставится HeadlessUI автоматически).\n *\n * Esc обрабатывается через общий стек открытых модалок (`grModalEscStack`):\n * единый capture-обработчик на `window` закрывает только верхнюю (последнюю\n * открытую) модалку и опережает window-обработчик Escape HeadlessUI. Это\n * чинит кейс, когда поверх `GrModal` открыт диалог `useDialogService` (другое\n * дерево рендера): Esc закрывает именно верхний диалог, а не нижнее окно.\n * Клик по оверлею (backdrop) по-прежнему идёт через `@close` HeadlessUI;\n * источник закрытия различается через ref `closeReason`.\n */\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\nimport { pushGrModalEsc, removeGrModalEsc } from './grModalEscStack'\nimport { pushGrModalTop, removeGrModalTop } from './grModalTopStack'\nimport { useScrollLock } from '../../composables/internal/useScrollLock'\n\nimport {\n type GrModalSize,\n getGrModalPanelClass,\n layout,\n overlay as overlayClass,\n overlayTransition,\n panelTransition,\n root as rootClass,\n shell,\n} from './grModalStyles'\n\nexport interface GrModalProps {\n modelValue: boolean\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n size?: GrModalSize\n}\n\nconst props = withDefaults(defineProps<GrModalProps>(), {\n closeOnBackdrop: true,\n closeOnEsc: true,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n}>()\n\nconst panelClass = computed(() => getGrModalPanelClass(props.size))\n\n// Ссылка на панель используется как `initialFocus` для HeadlessUI `<Dialog>`:\n// панель имеет `tabindex=\"-1\"`, поэтому всегда фокусируема программно. Это\n// убирает предупреждение «There are no focusable elements inside the\n// <FocusTrap />», которое HeadlessUI выводит, когда не находит фокусируемого\n// элемента (в т.ч. когда контент окна временно помечен `inert`).\nconst panelRef = ref<HTMLElement | null>(null)\n\n// Является ли это окно верхним (последним открытым) в общем стеке модалок.\n// Когда поверх открыт другой `GrModal`/диалог сервиса, окно перестаёт быть\n// верхним и помечается `inert`, чтобы не «воровать» фокус у верхнего окна.\nconst isTopmost = ref(true)\n\n// `inert` ставится только на нижние (не верхние) открытые окна. Inert-поддерево\n// не интерактивно и не фокусируемо, поэтому FocusLock нижнего `<Dialog>`\n// перестаёт возвращать фокус себе — верхний диалог удерживает фокус сам.\nconst inertAttr = computed(() => (props.modelValue && !isTopmost.value ? '' : undefined))\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем teleport,\n// а в клиенте включаем после маунта.\nconst isClient = typeof window !== 'undefined'\n\n// Источник закрытия от HeadlessUI `<Dialog>` — либо Esc, либо клик по оверлею.\n// Различаем их, чтобы `closeOnBackdrop` и `closeOnEsc` работали независимо.\nconst closeReason = ref<'backdrop' | 'esc' | null>(null)\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction onDialogClose(): void {\n const reason = closeReason.value\n closeReason.value = null\n\n if (reason === 'esc') {\n if (props.closeOnEsc) close()\n return\n }\n\n // По умолчанию (клик по оверлею или программный вызов `@close`)\n // уважаем `closeOnBackdrop`.\n if (props.closeOnBackdrop) close()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') closeReason.value = 'esc'\n}\n\n// ————— Esc-стек: гарантирует, что Esc закрывает именно верхнюю (последнюю\n// открытую) модалку, даже если окна живут в разных деревьях рендера\n// (например, диалоги `useDialogService` поверх `GrModal`).\nlet escEntryId: number | null = null\nlet topEntryId: number | null = null\n\nfunction registerEsc(): void {\n if (escEntryId !== null) return\n escEntryId = pushGrModalEsc({\n shouldClose: () => props.closeOnEsc,\n close,\n })\n}\n\nfunction unregisterEsc(): void {\n if (escEntryId === null) return\n removeGrModalEsc(escEntryId)\n escEntryId = null\n}\n\nfunction registerTop(): void {\n if (topEntryId !== null) return\n topEntryId = pushGrModalTop({\n setTopmost: (value) => { isTopmost.value = value },\n })\n}\n\nfunction unregisterTop(): void {\n if (topEntryId === null) return\n removeGrModalTop(topEntryId)\n topEntryId = null\n isTopmost.value = true\n}\n\nfunction onOverlayPointerDown(): void {\n closeReason.value = 'backdrop'\n}\n\n// ————— Scroll lock на `<body>` на время открытия.\n// HeadlessUI Vue этого не делает автоматически, а фон скроллится — для\n// GR-примитива это мешающий UX. Общий reference-counted lock корректно\n// работает при нескольких открытых оверлеях (LIFO-независимо) и компенсирует\n// ширину скроллбара, чтобы контент не дёргался.\nconst { lock: lockBodyScroll, unlock: unlockBodyScroll } = useScrollLock()\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (value) {\n lockBodyScroll()\n registerEsc()\n registerTop()\n }\n else {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n }\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n})\n\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <TransitionRoot :show=\"modelValue\" as=\"template\">\n <Dialog\n as=\"div\"\n :class=\"rootClass\"\n :initial-focus=\"panelRef\"\n :inert=\"inertAttr\"\n @close=\"onDialogClose\"\n @keydown.capture=\"onRootKeydown\"\n >\n <div :class=\"shell\">\n <div :class=\"layout\">\n <TransitionChild\n as=\"template\"\n :enter=\"overlayTransition.enter\"\n :enter-from=\"overlayTransition.enterFrom\"\n :enter-to=\"overlayTransition.enterTo\"\n :leave=\"overlayTransition.leave\"\n :leave-from=\"overlayTransition.leaveFrom\"\n :leave-to=\"overlayTransition.leaveTo\"\n >\n <div\n data-gr-modal-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n @pointerdown=\"onOverlayPointerDown\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n :enter=\"panelTransition.enter\"\n :enter-from=\"panelTransition.enterFrom\"\n :enter-to=\"panelTransition.enterTo\"\n :leave=\"panelTransition.leave\"\n :leave-from=\"panelTransition.leaveFrom\"\n :leave-to=\"panelTransition.leaveTo\"\n >\n <DialogPanel\n ref=\"panelRef\"\n data-gr-modal-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n >\n <DialogTitle v-if=\"$slots.title\" as=\"div\" data-gr-modal-title>\n <slot name=\"title\" />\n </DialogTitle>\n <DialogDescription v-if=\"$slots.description\" as=\"div\" data-gr-modal-description>\n <slot name=\"description\" />\n </DialogDescription>\n <slot />\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrModal — GR-примитив модального окна на базе `@headlessui/vue`.\n *\n * Публичный API:\n * - `modelValue` (v-model) — открыто/закрыто;\n * - `size` — размер панели (`sm | md | lg | xl | full`);\n * - `closeOnBackdrop` (default: true) — закрывать при клике по оверлею;\n * - `closeOnEsc` (default: true) — закрывать по Esc;\n * - слоты `#title` / `#description` — если переданы, оборачиваются в\n * `DialogTitle` / `DialogDescription` (связь через `aria-labelledby` /\n * `aria-describedby` ставится HeadlessUI автоматически).\n *\n * Esc обрабатывается через общий стек открытых модалок (`grModalEscStack`):\n * единый capture-обработчик на `window` закрывает только верхнюю (последнюю\n * открытую) модалку и опережает window-обработчик Escape HeadlessUI. Это\n * чинит кейс, когда поверх `GrModal` открыт диалог `useDialogService` (другое\n * дерево рендера): Esc закрывает именно верхний диалог, а не нижнее окно.\n * Клик по оверлею (backdrop) по-прежнему идёт через `@close` HeadlessUI;\n * источник закрытия различается через ref `closeReason`.\n */\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\nimport { pushGrModalEsc, removeGrModalEsc } from './grModalEscStack'\nimport { pushGrModalTop, removeGrModalTop } from './grModalTopStack'\nimport { useScrollLock } from '../../composables/internal/useScrollLock'\n\nimport {\n type GrModalSize,\n getGrModalPanelClass,\n layout,\n overlay as overlayClass,\n overlayTransition,\n panelTransition,\n root as rootClass,\n shell,\n} from './grModalStyles'\n\nexport interface GrModalProps {\n modelValue: boolean\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n size?: GrModalSize\n}\n\nconst props = withDefaults(defineProps<GrModalProps>(), {\n closeOnBackdrop: true,\n closeOnEsc: true,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n}>()\n\nconst panelClass = computed(() => getGrModalPanelClass(props.size))\n\n// Ссылка на панель используется как `initialFocus` для HeadlessUI `<Dialog>`:\n// панель имеет `tabindex=\"-1\"`, поэтому всегда фокусируема программно. Это\n// убирает предупреждение «There are no focusable elements inside the\n// <FocusTrap />», которое HeadlessUI выводит, когда не находит фокусируемого\n// элемента (в т.ч. когда контент окна временно помечен `inert`).\nconst panelRef = ref<HTMLElement | null>(null)\n\n// Является ли это окно верхним (последним открытым) в общем стеке модалок.\n// Когда поверх открыт другой `GrModal`/диалог сервиса, окно перестаёт быть\n// верхним и помечается `inert`, чтобы не «воровать» фокус у верхнего окна.\nconst isTopmost = ref(true)\n\n// `inert` ставится только на нижние (не верхние) открытые окна. Inert-поддерево\n// не интерактивно и не фокусируемо, поэтому FocusLock нижнего `<Dialog>`\n// перестаёт возвращать фокус себе — верхний диалог удерживает фокус сам.\nconst inertAttr = computed(() => (props.modelValue && !isTopmost.value ? '' : undefined))\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем teleport,\n// а в клиенте включаем после маунта.\nconst isClient = typeof window !== 'undefined'\n\n// Источник закрытия от HeadlessUI `<Dialog>` — либо Esc, либо клик по оверлею.\n// Различаем их, чтобы `closeOnBackdrop` и `closeOnEsc` работали независимо.\nconst closeReason = ref<'backdrop' | 'esc' | null>(null)\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction onDialogClose(): void {\n const reason = closeReason.value\n closeReason.value = null\n\n if (reason === 'esc') {\n if (props.closeOnEsc) close()\n return\n }\n\n // По умолчанию (клик по оверлею или программный вызов `@close`)\n // уважаем `closeOnBackdrop`.\n if (props.closeOnBackdrop) close()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') closeReason.value = 'esc'\n}\n\n// ————— Esc-стек: гарантирует, что Esc закрывает именно верхнюю (последнюю\n// открытую) модалку, даже если окна живут в разных деревьях рендера\n// (например, диалоги `useDialogService` поверх `GrModal`).\nlet escEntryId: number | null = null\nlet topEntryId: number | null = null\n\nfunction registerEsc(): void {\n if (escEntryId !== null) return\n escEntryId = pushGrModalEsc({\n shouldClose: () => props.closeOnEsc,\n close,\n })\n}\n\nfunction unregisterEsc(): void {\n if (escEntryId === null) return\n removeGrModalEsc(escEntryId)\n escEntryId = null\n}\n\nfunction registerTop(): void {\n if (topEntryId !== null) return\n topEntryId = pushGrModalTop({\n setTopmost: (value) => { isTopmost.value = value },\n })\n}\n\nfunction unregisterTop(): void {\n if (topEntryId === null) return\n removeGrModalTop(topEntryId)\n topEntryId = null\n isTopmost.value = true\n}\n\nfunction onOverlayPointerDown(): void {\n closeReason.value = 'backdrop'\n}\n\n// ————— Scroll lock на `<body>` на время открытия.\n// HeadlessUI Vue этого не делает автоматически, а фон скроллится — для\n// GR-примитива это мешающий UX. Общий reference-counted lock корректно\n// работает при нескольких открытых оверлеях (LIFO-независимо) и компенсирует\n// ширину скроллбара, чтобы контент не дёргался.\nconst { lock: lockBodyScroll, unlock: unlockBodyScroll } = useScrollLock()\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (value) {\n lockBodyScroll()\n registerEsc()\n registerTop()\n }\n else {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n }\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n})\n\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <TransitionRoot :show=\"modelValue\" as=\"template\">\n <Dialog\n as=\"div\"\n :class=\"rootClass\"\n :initial-focus=\"panelRef\"\n :inert=\"inertAttr\"\n @close=\"onDialogClose\"\n @keydown.capture=\"onRootKeydown\"\n >\n <div :class=\"shell\">\n <div :class=\"layout\">\n <TransitionChild\n as=\"template\"\n :enter=\"overlayTransition.enter\"\n :enter-from=\"overlayTransition.enterFrom\"\n :enter-to=\"overlayTransition.enterTo\"\n :leave=\"overlayTransition.leave\"\n :leave-from=\"overlayTransition.leaveFrom\"\n :leave-to=\"overlayTransition.leaveTo\"\n >\n <div\n data-gr-modal-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n @pointerdown=\"onOverlayPointerDown\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n :enter=\"panelTransition.enter\"\n :enter-from=\"panelTransition.enterFrom\"\n :enter-to=\"panelTransition.enterTo\"\n :leave=\"panelTransition.leave\"\n :leave-from=\"panelTransition.leaveFrom\"\n :leave-to=\"panelTransition.leaveTo\"\n >\n <DialogPanel\n ref=\"panelRef\"\n data-gr-modal-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n >\n <DialogTitle v-if=\"$slots.title\" as=\"div\" data-gr-modal-title>\n <slot name=\"title\" />\n </DialogTitle>\n <DialogDescription v-if=\"$slots.description\" as=\"div\" data-gr-modal-description>\n <slot name=\"description\" />\n </DialogDescription>\n <slot />\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrModal-BTu1-5eY.js","names":["$slots"],"sources":["../../../../src/components/GrModal/grModalTopStack.ts","../../../../src/components/GrModal/GrModal.vue","../../../../src/components/GrModal/GrModal.vue"],"sourcesContent":["/**\n * grModalTopStack — общий стек открытых `GrModal` для вычисления «верхнего»\n * (последнего открытого) окна независимо от дерева рендера.\n *\n * Зачем нужен:\n * HeadlessUI ловит фокус (`FocusTrap` с `FocusLock`) у каждого открытого\n * `<Dialog>` и помечает остальную часть страницы как inert. Когда модалки\n * рендерятся в разных деревьях (например, диалоги `useDialogService`\n * монтируются отдельным `render()` в `document.body`), их HeadlessUI-стек не\n * общий: каждый `<Dialog>` считает себя верхним и продолжает удерживать фокус.\n * В итоге нижнее окно «ворует» фокус у верхнего диалога — нельзя, например,\n * сфокусировать input в открытом поверх `prompt`.\n *\n * Решение: единый стек регистраций. Верхней считается последняя\n * зарегистрированная модалка. Все нижние окна уведомляются (`setTopmost(false)`)\n * и помечают свой корень `inert`, освобождая фокус для верхнего окна. Когда\n * верхнее окно закрывается, следующая по стеку модалка снова становится\n * верхней (`setTopmost(true)`) и снимает `inert`.\n */\n\nexport interface GrModalTopEntry {\n /** Уникальный id зарегистрированной модалки. */\n id: number\n /** Колбэк-уведомление: является ли модалка сейчас верхней. */\n setTopmost: (isTopmost: boolean) => void\n}\n\nconst stack: GrModalTopEntry[] = []\nlet nextId = 1\n\n/** Пересчитывает «верхнее» окно и уведомляет все зарегистрированные модалки. */\nfunction sync(): void {\n const lastIndex = stack.length - 1\n stack.forEach((entry, index) => entry.setTopmost(index === lastIndex))\n}\n\n/** Регистрирует открытую модалку как верхнюю и возвращает её id. */\nexport function pushGrModalTop(entry: Omit<GrModalTopEntry, 'id'>): number {\n const id = nextId++\n stack.push({ ...entry, id })\n sync()\n return id\n}\n\n/** Снимает модалку со стека (при закрытии или размонтировании). */\nexport function removeGrModalTop(id: number): void {\n const index = stack.findIndex(item => item.id === id)\n if (index >= 0) stack.splice(index, 1)\n sync()\n}\n\n/** Тестовая/служебная очистка стека. */\nexport function resetGrModalTopStack(): void {\n stack.splice(0, stack.length)\n}\n","<script setup lang=\"ts\">\n/**\n * GrModal — GR-примитив модального окна на базе `@headlessui/vue`.\n *\n * Публичный API:\n * - `modelValue` (v-model) — открыто/закрыто;\n * - `size` — размер панели (`sm | md | lg | xl | full`);\n * - `closeOnBackdrop` (default: true) — закрывать при клике по оверлею;\n * - `closeOnEsc` (default: true) — закрывать по Esc;\n * - слоты `#title` / `#description` — если переданы, оборачиваются в\n * `DialogTitle` / `DialogDescription` (связь через `aria-labelledby` /\n * `aria-describedby` ставится HeadlessUI автоматически).\n *\n * Esc обрабатывается через общий стек открытых модалок (`grModalEscStack`):\n * единый capture-обработчик на `window` закрывает только верхнюю (последнюю\n * открытую) модалку и опережает window-обработчик Escape HeadlessUI. Это\n * чинит кейс, когда поверх `GrModal` открыт диалог `useDialogService` (другое\n * дерево рендера): Esc закрывает именно верхний диалог, а не нижнее окно.\n * Клик по оверлею (backdrop) по-прежнему идёт через `@close` HeadlessUI;\n * источник закрытия различается через ref `closeReason`.\n */\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\nimport { pushGrModalEsc, removeGrModalEsc } from './grModalEscStack'\nimport { pushGrModalTop, removeGrModalTop } from './grModalTopStack'\nimport { useScrollLock } from '../../composables/internal/useScrollLock'\n\nimport {\n type GrModalSize,\n getGrModalPanelClass,\n layout,\n overlay as overlayClass,\n overlayTransition,\n panelTransition,\n root as rootClass,\n shell,\n} from './grModalStyles'\n\nexport interface GrModalProps {\n modelValue: boolean\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n size?: GrModalSize\n}\n\nconst props = withDefaults(defineProps<GrModalProps>(), {\n closeOnBackdrop: true,\n closeOnEsc: true,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n}>()\n\nconst panelClass = computed(() => getGrModalPanelClass(props.size))\n\n// Ссылка на панель используется как `initialFocus` для HeadlessUI `<Dialog>`:\n// панель имеет `tabindex=\"-1\"`, поэтому всегда фокусируема программно. Это\n// убирает предупреждение «There are no focusable elements inside the\n// <FocusTrap />», которое HeadlessUI выводит, когда не находит фокусируемого\n// элемента (в т.ч. когда контент окна временно помечен `inert`).\nconst panelRef = ref<HTMLElement | null>(null)\n\n// Является ли это окно верхним (последним открытым) в общем стеке модалок.\n// Когда поверх открыт другой `GrModal`/диалог сервиса, окно перестаёт быть\n// верхним и помечается `inert`, чтобы не «воровать» фокус у верхнего окна.\nconst isTopmost = ref(true)\n\n// `inert` ставится только на нижние (не верхние) открытые окна. Inert-поддерево\n// не интерактивно и не фокусируемо, поэтому FocusLock нижнего `<Dialog>`\n// перестаёт возвращать фокус себе — верхний диалог удерживает фокус сам.\nconst inertAttr = computed(() => (props.modelValue && !isTopmost.value ? '' : undefined))\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем teleport,\n// а в клиенте включаем после маунта.\nconst isClient = typeof window !== 'undefined'\n\n// Источник закрытия от HeadlessUI `<Dialog>` — либо Esc, либо клик по оверлею.\n// Различаем их, чтобы `closeOnBackdrop` и `closeOnEsc` работали независимо.\nconst closeReason = ref<'backdrop' | 'esc' | null>(null)\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction onDialogClose(): void {\n const reason = closeReason.value\n closeReason.value = null\n\n if (reason === 'esc') {\n if (props.closeOnEsc) close()\n return\n }\n\n // По умолчанию (клик по оверлею или программный вызов `@close`)\n // уважаем `closeOnBackdrop`.\n if (props.closeOnBackdrop) close()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') closeReason.value = 'esc'\n}\n\n// ————— Esc-стек: гарантирует, что Esc закрывает именно верхнюю (последнюю\n// открытую) модалку, даже если окна живут в разных деревьях рендера\n// (например, диалоги `useDialogService` поверх `GrModal`).\nlet escEntryId: number | null = null\nlet topEntryId: number | null = null\n\nfunction registerEsc(): void {\n if (escEntryId !== null) return\n escEntryId = pushGrModalEsc({\n shouldClose: () => props.closeOnEsc,\n close,\n })\n}\n\nfunction unregisterEsc(): void {\n if (escEntryId === null) return\n removeGrModalEsc(escEntryId)\n escEntryId = null\n}\n\nfunction registerTop(): void {\n if (topEntryId !== null) return\n topEntryId = pushGrModalTop({\n setTopmost: (value) => { isTopmost.value = value },\n })\n}\n\nfunction unregisterTop(): void {\n if (topEntryId === null) return\n removeGrModalTop(topEntryId)\n topEntryId = null\n isTopmost.value = true\n}\n\nfunction onOverlayPointerDown(): void {\n closeReason.value = 'backdrop'\n}\n\n// ————— Scroll lock на `<body>` на время открытия.\n// HeadlessUI Vue этого не делает автоматически, а фон скроллится — для\n// GR-примитива это мешающий UX. Общий reference-counted lock корректно\n// работает при нескольких открытых оверлеях (LIFO-независимо) и компенсирует\n// ширину скроллбара, чтобы контент не дёргался.\nconst { lock: lockBodyScroll, unlock: unlockBodyScroll } = useScrollLock()\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (value) {\n lockBodyScroll()\n registerEsc()\n registerTop()\n }\n else {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n }\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n})\n\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <TransitionRoot :show=\"modelValue\" as=\"template\">\n <Dialog\n as=\"div\"\n :class=\"rootClass\"\n :initial-focus=\"panelRef\"\n :inert=\"inertAttr\"\n @close=\"onDialogClose\"\n @keydown.capture=\"onRootKeydown\"\n >\n <div :class=\"shell\">\n <div :class=\"layout\">\n <TransitionChild\n as=\"template\"\n :enter=\"overlayTransition.enter\"\n :enter-from=\"overlayTransition.enterFrom\"\n :enter-to=\"overlayTransition.enterTo\"\n :leave=\"overlayTransition.leave\"\n :leave-from=\"overlayTransition.leaveFrom\"\n :leave-to=\"overlayTransition.leaveTo\"\n >\n <div\n data-gr-modal-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n @pointerdown=\"onOverlayPointerDown\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n :enter=\"panelTransition.enter\"\n :enter-from=\"panelTransition.enterFrom\"\n :enter-to=\"panelTransition.enterTo\"\n :leave=\"panelTransition.leave\"\n :leave-from=\"panelTransition.leaveFrom\"\n :leave-to=\"panelTransition.leaveTo\"\n >\n <DialogPanel\n ref=\"panelRef\"\n data-gr-modal-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n >\n <DialogTitle v-if=\"$slots.title\" as=\"div\" data-gr-modal-title>\n <slot name=\"title\" />\n </DialogTitle>\n <DialogDescription v-if=\"$slots.description\" as=\"div\" data-gr-modal-description>\n <slot name=\"description\" />\n </DialogDescription>\n <slot />\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrModal — GR-примитив модального окна на базе `@headlessui/vue`.\n *\n * Публичный API:\n * - `modelValue` (v-model) — открыто/закрыто;\n * - `size` — размер панели (`sm | md | lg | xl | full`);\n * - `closeOnBackdrop` (default: true) — закрывать при клике по оверлею;\n * - `closeOnEsc` (default: true) — закрывать по Esc;\n * - слоты `#title` / `#description` — если переданы, оборачиваются в\n * `DialogTitle` / `DialogDescription` (связь через `aria-labelledby` /\n * `aria-describedby` ставится HeadlessUI автоматически).\n *\n * Esc обрабатывается через общий стек открытых модалок (`grModalEscStack`):\n * единый capture-обработчик на `window` закрывает только верхнюю (последнюю\n * открытую) модалку и опережает window-обработчик Escape HeadlessUI. Это\n * чинит кейс, когда поверх `GrModal` открыт диалог `useDialogService` (другое\n * дерево рендера): Esc закрывает именно верхний диалог, а не нижнее окно.\n * Клик по оверлею (backdrop) по-прежнему идёт через `@close` HeadlessUI;\n * источник закрытия различается через ref `closeReason`.\n */\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport { Dialog, DialogDescription, DialogPanel, DialogTitle, TransitionChild, TransitionRoot } from '@headlessui/vue'\n\nimport { pushGrModalEsc, removeGrModalEsc } from './grModalEscStack'\nimport { pushGrModalTop, removeGrModalTop } from './grModalTopStack'\nimport { useScrollLock } from '../../composables/internal/useScrollLock'\n\nimport {\n type GrModalSize,\n getGrModalPanelClass,\n layout,\n overlay as overlayClass,\n overlayTransition,\n panelTransition,\n root as rootClass,\n shell,\n} from './grModalStyles'\n\nexport interface GrModalProps {\n modelValue: boolean\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n size?: GrModalSize\n}\n\nconst props = withDefaults(defineProps<GrModalProps>(), {\n closeOnBackdrop: true,\n closeOnEsc: true,\n size: 'md',\n})\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: boolean): void\n}>()\n\nconst panelClass = computed(() => getGrModalPanelClass(props.size))\n\n// Ссылка на панель используется как `initialFocus` для HeadlessUI `<Dialog>`:\n// панель имеет `tabindex=\"-1\"`, поэтому всегда фокусируема программно. Это\n// убирает предупреждение «There are no focusable elements inside the\n// <FocusTrap />», которое HeadlessUI выводит, когда не находит фокусируемого\n// элемента (в т.ч. когда контент окна временно помечен `inert`).\nconst panelRef = ref<HTMLElement | null>(null)\n\n// Является ли это окно верхним (последним открытым) в общем стеке модалок.\n// Когда поверх открыт другой `GrModal`/диалог сервиса, окно перестаёт быть\n// верхним и помечается `inert`, чтобы не «воровать» фокус у верхнего окна.\nconst isTopmost = ref(true)\n\n// `inert` ставится только на нижние (не верхние) открытые окна. Inert-поддерево\n// не интерактивно и не фокусируемо, поэтому FocusLock нижнего `<Dialog>`\n// перестаёт возвращать фокус себе — верхний диалог удерживает фокус сам.\nconst inertAttr = computed(() => (props.modelValue && !isTopmost.value ? '' : undefined))\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем teleport,\n// а в клиенте включаем после маунта.\nconst isClient = typeof window !== 'undefined'\n\n// Источник закрытия от HeadlessUI `<Dialog>` — либо Esc, либо клик по оверлею.\n// Различаем их, чтобы `closeOnBackdrop` и `closeOnEsc` работали независимо.\nconst closeReason = ref<'backdrop' | 'esc' | null>(null)\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction onDialogClose(): void {\n const reason = closeReason.value\n closeReason.value = null\n\n if (reason === 'esc') {\n if (props.closeOnEsc) close()\n return\n }\n\n // По умолчанию (клик по оверлею или программный вызов `@close`)\n // уважаем `closeOnBackdrop`.\n if (props.closeOnBackdrop) close()\n}\n\nfunction onRootKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape') closeReason.value = 'esc'\n}\n\n// ————— Esc-стек: гарантирует, что Esc закрывает именно верхнюю (последнюю\n// открытую) модалку, даже если окна живут в разных деревьях рендера\n// (например, диалоги `useDialogService` поверх `GrModal`).\nlet escEntryId: number | null = null\nlet topEntryId: number | null = null\n\nfunction registerEsc(): void {\n if (escEntryId !== null) return\n escEntryId = pushGrModalEsc({\n shouldClose: () => props.closeOnEsc,\n close,\n })\n}\n\nfunction unregisterEsc(): void {\n if (escEntryId === null) return\n removeGrModalEsc(escEntryId)\n escEntryId = null\n}\n\nfunction registerTop(): void {\n if (topEntryId !== null) return\n topEntryId = pushGrModalTop({\n setTopmost: (value) => { isTopmost.value = value },\n })\n}\n\nfunction unregisterTop(): void {\n if (topEntryId === null) return\n removeGrModalTop(topEntryId)\n topEntryId = null\n isTopmost.value = true\n}\n\nfunction onOverlayPointerDown(): void {\n closeReason.value = 'backdrop'\n}\n\n// ————— Scroll lock на `<body>` на время открытия.\n// HeadlessUI Vue этого не делает автоматически, а фон скроллится — для\n// GR-примитива это мешающий UX. Общий reference-counted lock корректно\n// работает при нескольких открытых оверлеях (LIFO-независимо) и компенсирует\n// ширину скроллбара, чтобы контент не дёргался.\nconst { lock: lockBodyScroll, unlock: unlockBodyScroll } = useScrollLock()\n\nwatch(\n () => props.modelValue,\n (value) => {\n if (value) {\n lockBodyScroll()\n registerEsc()\n registerTop()\n }\n else {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n }\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => {\n unlockBodyScroll()\n unregisterEsc()\n unregisterTop()\n})\n\n</script>\n\n<template>\n <teleport to=\"body\" :disabled=\"!isClient\">\n <TransitionRoot :show=\"modelValue\" as=\"template\">\n <Dialog\n as=\"div\"\n :class=\"rootClass\"\n :initial-focus=\"panelRef\"\n :inert=\"inertAttr\"\n @close=\"onDialogClose\"\n @keydown.capture=\"onRootKeydown\"\n >\n <div :class=\"shell\">\n <div :class=\"layout\">\n <TransitionChild\n as=\"template\"\n :enter=\"overlayTransition.enter\"\n :enter-from=\"overlayTransition.enterFrom\"\n :enter-to=\"overlayTransition.enterTo\"\n :leave=\"overlayTransition.leave\"\n :leave-from=\"overlayTransition.leaveFrom\"\n :leave-to=\"overlayTransition.leaveTo\"\n >\n <div\n data-gr-modal-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n @pointerdown=\"onOverlayPointerDown\"\n />\n </TransitionChild>\n\n <TransitionChild\n as=\"template\"\n :enter=\"panelTransition.enter\"\n :enter-from=\"panelTransition.enterFrom\"\n :enter-to=\"panelTransition.enterTo\"\n :leave=\"panelTransition.leave\"\n :leave-from=\"panelTransition.leaveFrom\"\n :leave-to=\"panelTransition.leaveTo\"\n >\n <DialogPanel\n ref=\"panelRef\"\n data-gr-modal-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n >\n <DialogTitle v-if=\"$slots.title\" as=\"div\" data-gr-modal-title>\n <slot name=\"title\" />\n </DialogTitle>\n <DialogDescription v-if=\"$slots.description\" as=\"div\" data-gr-modal-description>\n <slot name=\"description\" />\n </DialogDescription>\n <slot />\n </DialogPanel>\n </TransitionChild>\n </div>\n </div>\n </Dialog>\n </TransitionRoot>\n </teleport>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as GrModal_default } from "./chunks/GrModal-
|
|
2
|
-
import { t as getGrModalPanelClass } from "../../chunks/grModalStyles-
|
|
3
|
-
import { n as grModalClassTokens, r as grModalSafelist, t as grModalConfig } from "../../chunks/config-
|
|
1
|
+
import { t as GrModal_default } from "./chunks/GrModal-BTu1-5eY.js";
|
|
2
|
+
import { t as getGrModalPanelClass } from "../../chunks/grModalStyles-D8-shx9A.js";
|
|
3
|
+
import { n as grModalClassTokens, r as grModalSafelist, t as grModalConfig } from "../../chunks/config-CPdmr7tC.js";
|
|
4
4
|
export { GrModal_default as GrModal, GrModal_default as default, getGrModalPanelClass, grModalClassTokens, grModalConfig, grModalSafelist };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as GrButton_default } from "../../GrButton/chunks/GrButton-
|
|
1
|
+
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-SH0I--GW.js";
|
|
2
|
+
import { t as GrButton_default } from "../../GrButton/chunks/GrButton-DCi4CUpo.js";
|
|
3
3
|
import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-D9AWQLk2.js";
|
|
4
4
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, markRaw, normalizeClass, openBlock, renderSlot, toDisplayString, unref, withCtx } from "vue";
|
|
5
5
|
//#region ~icons/lucide/menu
|
|
@@ -26,7 +26,7 @@ var menu_default = markRaw({
|
|
|
26
26
|
//#region src/components/GrNavbar/GrNavbar.vue?vue&type=script&setup=true&lang.ts
|
|
27
27
|
var _hoisted_1 = {
|
|
28
28
|
"data-gr-navbar": "",
|
|
29
|
-
class: "h-[56px] border-b border-[var(--brd)] bg-[var(--bg)] flex items-center justify-between px-4 sm:px-6"
|
|
29
|
+
class: "h-[56px] border-b border-[var(--gr-brd)] bg-[var(--gr-bg)] flex items-center justify-between px-4 sm:px-6"
|
|
30
30
|
};
|
|
31
31
|
var _hoisted_2 = { class: "flex items-center gap-3" };
|
|
32
32
|
var _hoisted_3 = {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrNavbar-keKT_mIM.js","names":[],"sources":["../../../../src/components/GrNavbar/GrNavbar.vue","../../../../src/components/GrNavbar/GrNavbar.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport IconMenu from '~icons/lucide/menu'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrIcon from '../GrIcon/GrIcon.vue'\n\n/**\n * GrNavbar — верхняя панель приложения (header) с заголовком,\n * опциональной кнопкой меню (обычно — для мобильных) и правым слотом\n * для действий/аватара.\n *\n * - Корень — `<header>` (landmark), без собственного `role`.\n * - `aria-label` кнопки меню локализуется через `useGranularityTranslations`.\n */\nexport interface GrNavbarProps {\n title: string\n showMenuButton?: boolean\n /** Extra classes applied to the menu button wrapper (e.g. `sm:hidden`). */\n menuButtonClass?: string\n}\n\nwithDefaults(defineProps<GrNavbarProps>(), {\n showMenuButton: false,\n menuButtonClass: '',\n})\n\nconst emit = defineEmits<{\n (e: 'menu'): void\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst menuAriaLabel = computed(() => t('gr.navbar.openMenu', 'Open menu'))\n</script>\n\n<template>\n <header\n data-gr-navbar\n class=\"h-[56px] border-b border-[var(--gr-brd)] bg-[var(--gr-bg)] flex items-center justify-between px-4 sm:px-6\"\n >\n <div class=\"flex items-center gap-3\">\n <GrButton\n v-if=\"showMenuButton\"\n data-gr-navbar-menu\n variant=\"ghost\"\n size=\"sm\"\n square\n :aria-label=\"menuAriaLabel\"\n :class=\"menuButtonClass\"\n @click=\"emit('menu')\"\n >\n <GrIcon :size=\"16\">\n <IconMenu aria-hidden=\"true\" />\n </GrIcon>\n </GrButton>\n <div data-gr-navbar-title class=\"text-[14px] font-700\">\n <slot name=\"title\">\n {{ title }}\n </slot>\n </div>\n </div>\n\n <div class=\"flex items-center gap-3\">\n <slot />\n </div>\n </header>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport IconMenu from '~icons/lucide/menu'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrIcon from '../GrIcon/GrIcon.vue'\n\n/**\n * GrNavbar — верхняя панель приложения (header) с заголовком,\n * опциональной кнопкой меню (обычно — для мобильных) и правым слотом\n * для действий/аватара.\n *\n * - Корень — `<header>` (landmark), без собственного `role`.\n * - `aria-label` кнопки меню локализуется через `useGranularityTranslations`.\n */\nexport interface GrNavbarProps {\n title: string\n showMenuButton?: boolean\n /** Extra classes applied to the menu button wrapper (e.g. `sm:hidden`). */\n menuButtonClass?: string\n}\n\nwithDefaults(defineProps<GrNavbarProps>(), {\n showMenuButton: false,\n menuButtonClass: '',\n})\n\nconst emit = defineEmits<{\n (e: 'menu'): void\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst menuAriaLabel = computed(() => t('gr.navbar.openMenu', 'Open menu'))\n</script>\n\n<template>\n <header\n data-gr-navbar\n class=\"h-[56px] border-b border-[var(--gr-brd)] bg-[var(--gr-bg)] flex items-center justify-between px-4 sm:px-6\"\n >\n <div class=\"flex items-center gap-3\">\n <GrButton\n v-if=\"showMenuButton\"\n data-gr-navbar-menu\n variant=\"ghost\"\n size=\"sm\"\n square\n :aria-label=\"menuAriaLabel\"\n :class=\"menuButtonClass\"\n @click=\"emit('menu')\"\n >\n <GrIcon :size=\"16\">\n <IconMenu aria-hidden=\"true\" />\n </GrIcon>\n </GrButton>\n <div data-gr-navbar-title class=\"text-[14px] font-700\">\n <slot name=\"title\">\n {{ title }}\n </slot>\n </div>\n </div>\n\n <div class=\"flex items-center gap-3\">\n <slot />\n </div>\n </header>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6BA,MAAM,OAAO;EAIb,MAAM,EAAE,MAAM,2BAA2B;EAEzC,MAAM,gBAAgB,eAAe,EAAE,sBAAsB,WAAW,CAAC;;uBAIvE,mBA6BS,UA7BT,YA6BS,CAzBP,mBAoBM,OApBN,YAoBM,CAlBI,QAAA,kBAAA,UAAA,GADR,YAaW,kBAAA;;IAXT,uBAAA;IACA,SAAQ;IACR,MAAK;IACL,QAAA;IACC,cAAY,cAAA;IACZ,OAAK,eAAE,QAAA,eAAe;IACtB,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,MAAA;;2BAIH,CAFT,YAES,gBAAA,EAFA,MAAM,GAAE,GAAA;4BACgB,CAA/B,YAA+B,MAAA,YAAA,GAAA,EAArB,eAAY,OAAM,CAAA,CAAA,CAAA;;;;mEAGhC,mBAIM,OAJN,YAIM,CAHJ,WAEO,KAAA,QAAA,SAAA,CAAA,SAAA,CAAA,gBAAA,gBADF,QAAA,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAKd,mBAEM,OAFN,YAEM,CADJ,WAAQ,KAAA,QAAA,SAAA,CAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrNavbar_default } from "./chunks/GrNavbar-
|
|
1
|
+
import { t as GrNavbar_default } from "./chunks/GrNavbar-keKT_mIM.js";
|
|
2
2
|
import { t as grNavbarConfig } from "../../chunks/config-ZiXWIRBX.js";
|
|
3
3
|
export { GrNavbar_default as GrNavbar, GrNavbar_default as default, grNavbarConfig };
|
package/dist/components/GrNumberInput/chunks/{GrNumberInput-DxCEvL7V.js → GrNumberInput-l9ZOHG9D.js}
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as useGrComponentSize } from "../../../chunks/context-DfWYCBB-.js";
|
|
2
|
+
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-SH0I--GW.js";
|
|
2
3
|
import { n as useAddonMeasurement, t as addLen } from "../../../chunks/useAddonMeasurement-DM0akF4C.js";
|
|
3
|
-
import { i as grNumberInputShellClass, r as grNumberInputInputClass } from "../../../chunks/config-
|
|
4
|
+
import { i as grNumberInputShellClass, r as grNumberInputInputClass } from "../../../chunks/config-gZWR75Bh2.js";
|
|
4
5
|
import { computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, openBlock, ref, renderSlot, useSlots, withModifiers } from "vue";
|
|
5
6
|
//#region src/components/GrNumberInput/GrNumberInput.vue?vue&type=script&setup=true&lang.ts
|
|
6
7
|
var _hoisted_1 = [
|
|
@@ -42,7 +43,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
42
43
|
state: { default: "default" },
|
|
43
44
|
name: { default: void 0 },
|
|
44
45
|
id: { default: void 0 },
|
|
45
|
-
size: { default:
|
|
46
|
+
size: { default: void 0 },
|
|
46
47
|
textAlign: { default: "left" },
|
|
47
48
|
decimalSeparator: { default: "." },
|
|
48
49
|
step: { default: 1 },
|
|
@@ -92,6 +93,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
92
93
|
return `${n}px`;
|
|
93
94
|
}
|
|
94
95
|
const props = __props;
|
|
96
|
+
const resolvedSize = useGrComponentSize(() => props.size, { component: "GrNumberInput" });
|
|
95
97
|
const emit = __emit;
|
|
96
98
|
const inputEl = ref(null);
|
|
97
99
|
function focus() {
|
|
@@ -106,9 +108,9 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
106
108
|
const hasSuffix = computed(() => Boolean(slots.suffix));
|
|
107
109
|
const hasHorizontalControls = computed(() => props.controls && props.controlsDirection === "horizontal");
|
|
108
110
|
const hasVerticalControls = computed(() => props.controls && props.controlsDirection === "vertical");
|
|
109
|
-
const addonPx = computed(() => ADDON_PX_BY_SIZE[
|
|
111
|
+
const addonPx = computed(() => ADDON_PX_BY_SIZE[resolvedSize.value]);
|
|
110
112
|
const addonLen = computed(() => px(addonPx.value));
|
|
111
|
-
const basePaddingXLen = computed(() => BASE_PADDING_X_LEN_BY_SIZE[
|
|
113
|
+
const basePaddingXLen = computed(() => BASE_PADDING_X_LEN_BY_SIZE[resolvedSize.value]);
|
|
112
114
|
const defaultAddonMinWidth = computed(() => addonLen.value);
|
|
113
115
|
const prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value);
|
|
114
116
|
const suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value);
|
|
@@ -175,7 +177,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
175
177
|
});
|
|
176
178
|
const inputClassName = computed(() => {
|
|
177
179
|
return grNumberInputInputClass({
|
|
178
|
-
size:
|
|
180
|
+
size: resolvedSize.value,
|
|
179
181
|
textAlign: props.textAlign
|
|
180
182
|
});
|
|
181
183
|
});
|
|
@@ -313,7 +315,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
313
315
|
return (_ctx, _cache) => {
|
|
314
316
|
return openBlock(), createElementBlock("div", {
|
|
315
317
|
"data-gr-number-input": "",
|
|
316
|
-
class: normalizeClass(["relative w-full overflow-hidden rounded-md border bg-[var(--bg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--ring)]", shellClassName.value])
|
|
318
|
+
class: normalizeClass(["relative w-full overflow-hidden rounded-md border bg-[var(--gr-bg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--gr-ring)]", shellClassName.value])
|
|
317
319
|
}, [
|
|
318
320
|
_ctx.$slots.prefix ? (openBlock(), createElementBlock("div", {
|
|
319
321
|
key: 0,
|
|
@@ -321,7 +323,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
321
323
|
ref: prefixEl,
|
|
322
324
|
"data-testid": "number-input-prefix",
|
|
323
325
|
"data-gr-number-input-prefix": "",
|
|
324
|
-
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",
|
|
326
|
+
class: "absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate",
|
|
325
327
|
style: normalizeStyle(prefixStyle.value),
|
|
326
328
|
"aria-hidden": "true"
|
|
327
329
|
}, [renderSlot(_ctx.$slots, "prefix")], 4)) : createCommentVNode("", true),
|
|
@@ -342,7 +344,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
342
344
|
"aria-valuemin": __props.min,
|
|
343
345
|
"aria-valuemax": __props.max,
|
|
344
346
|
"aria-invalid": __props.invalid ? "true" : void 0,
|
|
345
|
-
class: ["w-full bg-transparent text-[var(--fg)] placeholder:text-[var(--muted-fg)] focus:placeholder:text-transparent focus:outline-none disabled:cursor-not-allowed", inputClassName.value],
|
|
347
|
+
class: ["w-full bg-transparent text-[var(--gr-fg)] placeholder:text-[var(--gr-muted-fg)] focus:placeholder:text-transparent focus:outline-none disabled:cursor-not-allowed", inputClassName.value],
|
|
346
348
|
style: inputStyle.value,
|
|
347
349
|
onInput,
|
|
348
350
|
onChange,
|
|
@@ -356,7 +358,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
356
358
|
ref: suffixEl,
|
|
357
359
|
"data-testid": "number-input-suffix",
|
|
358
360
|
"data-gr-number-input-suffix": "",
|
|
359
|
-
class: normalizeClass(["absolute inset-y-0 flex items-center justify-center border-l border-[var(--brd)] px-2 text-[var(--muted-fg)] pointer-events-none select-none truncate", __props.suffixFixed ? "[direction:rtl]" : ""]),
|
|
361
|
+
class: normalizeClass(["absolute inset-y-0 flex items-center justify-center border-l border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate", __props.suffixFixed ? "[direction:rtl]" : ""]),
|
|
360
362
|
style: normalizeStyle(suffixStyle.value),
|
|
361
363
|
"aria-hidden": "true"
|
|
362
364
|
}, [renderSlot(_ctx.$slots, "suffix")], 6)) : createCommentVNode("", true),
|
|
@@ -364,11 +366,11 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
364
366
|
key: 2,
|
|
365
367
|
"data-testid": "number-input-controls-vertical",
|
|
366
368
|
"data-gr-number-input-controls": "vertical",
|
|
367
|
-
class: "absolute inset-y-0 flex items-center justify-center border-l border-[var(--brd)]",
|
|
369
|
+
class: "absolute inset-y-0 flex items-center justify-center border-l border-[var(--gr-brd)]",
|
|
368
370
|
style: normalizeStyle(verticalControlsStyle.value)
|
|
369
371
|
}, [createElementVNode("div", _hoisted_2, [createElementVNode("button", {
|
|
370
372
|
type: "button",
|
|
371
|
-
class: "h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--muted-fg)] hover:bg-[var(--muted)] active:bg-[var(--muted)] disabled:opacity-50 disabled:cursor-not-allowed",
|
|
373
|
+
class: "h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed",
|
|
372
374
|
disabled: __props.disabled,
|
|
373
375
|
"aria-label": resolvedIncreaseLabel.value,
|
|
374
376
|
onMousedown: _cache[0] || (_cache[0] = withModifiers(() => {}, ["prevent"])),
|
|
@@ -388,7 +390,7 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
388
390
|
"stroke-linejoin": "round"
|
|
389
391
|
})], -1)])], 40, _hoisted_3), createElementVNode("button", {
|
|
390
392
|
type: "button",
|
|
391
|
-
class: "h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--muted-fg)] hover:bg-[var(--muted)] active:bg-[var(--muted)] disabled:opacity-50 disabled:cursor-not-allowed",
|
|
393
|
+
class: "h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed",
|
|
392
394
|
disabled: __props.disabled,
|
|
393
395
|
"aria-label": resolvedDecreaseLabel.value,
|
|
394
396
|
onMousedown: _cache[2] || (_cache[2] = withModifiers(() => {}, ["prevent"])),
|
|
@@ -411,11 +413,11 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
411
413
|
key: 3,
|
|
412
414
|
"data-testid": "number-input-controls-horizontal-left",
|
|
413
415
|
"data-gr-number-input-controls": "horizontal-left",
|
|
414
|
-
class: "absolute inset-y-0 flex items-stretch justify-center border-r border-[var(--brd)]",
|
|
416
|
+
class: "absolute inset-y-0 flex items-stretch justify-center border-r border-[var(--gr-brd)]",
|
|
415
417
|
style: normalizeStyle(horizontalLeftControlsStyle.value)
|
|
416
418
|
}, [createElementVNode("button", {
|
|
417
419
|
type: "button",
|
|
418
|
-
class: "h-full w-full inline-flex items-center justify-center text-[var(--muted-fg)] hover:bg-[var(--muted)] active:bg-[var(--muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]",
|
|
420
|
+
class: "h-full w-full inline-flex items-center justify-center text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]",
|
|
419
421
|
disabled: __props.disabled,
|
|
420
422
|
"aria-label": resolvedDecreaseLabel.value,
|
|
421
423
|
onMousedown: _cache[4] || (_cache[4] = withModifiers(() => {}, ["prevent"])),
|
|
@@ -438,11 +440,11 @@ var GrNumberInput_default = /* @__PURE__ */ defineComponent({
|
|
|
438
440
|
key: 4,
|
|
439
441
|
"data-testid": "number-input-controls-horizontal-right",
|
|
440
442
|
"data-gr-number-input-controls": "horizontal-right",
|
|
441
|
-
class: "absolute inset-y-0 flex items-stretch justify-center border-l border-[var(--brd)]",
|
|
443
|
+
class: "absolute inset-y-0 flex items-stretch justify-center border-l border-[var(--gr-brd)]",
|
|
442
444
|
style: normalizeStyle(horizontalRightControlsStyle.value)
|
|
443
445
|
}, [createElementVNode("button", {
|
|
444
446
|
type: "button",
|
|
445
|
-
class: "h-full w-full inline-flex items-center justify-center text-[var(--muted-fg)] hover:bg-[var(--muted)] active:bg-[var(--muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]",
|
|
447
|
+
class: "h-full w-full inline-flex items-center justify-center text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]",
|
|
446
448
|
disabled: __props.disabled,
|
|
447
449
|
"aria-label": resolvedIncreaseLabel.value,
|
|
448
450
|
onMousedown: _cache[6] || (_cache[6] = withModifiers(() => {}, ["prevent"])),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrNumberInput-l9ZOHG9D.js","names":["$slots","$attrs"],"sources":["../../../../src/components/GrNumberInput/GrNumberInput.vue","../../../../src/components/GrNumberInput/GrNumberInput.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { InputHTMLAttributes } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { computed, ref, useSlots } from 'vue'\n\nimport {\n grNumberInputInputClass,\n grNumberInputShellClass,\n type GrNumberInputControlsDirection,\n type GrNumberInputSize,\n type GrNumberInputState,\n type GrNumberInputTextAlign,\n} from './grNumberInputStyles'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { addLen, useAddonMeasurement } from '../../composables/internal/useAddonMeasurement'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst ADDON_PX_BY_SIZE: Record<GrNumberInputSize, number> = {\n xs: 32,\n sm: 36,\n md: 40,\n lg: 48,\n}\n\nconst BASE_PADDING_X_LEN_BY_SIZE: Record<GrNumberInputSize, string> = {\n xs: '10px',\n sm: '12px',\n md: '12px',\n lg: '16px',\n}\n\nfunction px(n: number): string {\n return `${n}px`\n}\n\nexport interface GrNumberInputProps {\n /** Значение (строка — контролируем форматирование внутри). */\n modelValue: string\n placeholder?: string\n autocomplete?: string\n inputmode?: InputHTMLAttributes['inputmode']\n disabled?: boolean\n /** Быстрый флаг невалидности; эквивалент `state='danger'` + `aria-invalid`. */\n invalid?: boolean\n state?: GrNumberInputState\n name?: string\n id?: string\n size?: GrNumberInputSize\n\n textAlign?: GrNumberInputTextAlign\n\n decimalSeparator?: string\n step?: number\n min?: number\n max?: number\n precision?: number\n\n /**\n * BCP-47 локаль для отображения значения (группировка разрядов и разделители\n * через `Intl.NumberFormat`). Работает вместе с `useGrouping`.\n */\n locale?: string\n /**\n * Группировать разряды при отображении (когда поле не в фокусе). При фокусе\n * показывается «сырое» значение для редактирования. По умолчанию выключено.\n */\n useGrouping?: boolean\n\n /** Показывать кнопки +/-. */\n controls?: boolean\n controlsDirection?: GrNumberInputControlsDirection\n\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n /**\n * Фиксированная ширина у prefix/suffix: жёсткая ширина (из `*MaxWidth` →\n * `*MinWidth` → дефолт) + обрезка контента по краю (prefix — справа,\n * suffix — слева). По умолчанию аддоны растягиваются под контент.\n */\n prefixFixed?: boolean\n suffixFixed?: boolean\n\n /** i18n-friendly aria-label для кнопки \"увеличить\". */\n increaseLabel?: string\n /** i18n-friendly aria-label для кнопки \"уменьшить\". */\n decreaseLabel?: string\n}\n\nconst props = withDefaults(defineProps<GrNumberInputProps>(), {\n placeholder: undefined,\n autocomplete: undefined,\n inputmode: 'decimal',\n disabled: false,\n invalid: false,\n state: 'default',\n name: undefined,\n id: undefined,\n size: undefined,\n\n textAlign: 'left',\n\n decimalSeparator: '.',\n step: 1,\n min: undefined,\n max: undefined,\n precision: undefined,\n locale: undefined,\n useGrouping: false,\n\n controls: false,\n controlsDirection: 'vertical',\n\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n prefixFixed: false,\n suffixFixed: false,\n\n increaseLabel: undefined,\n decreaseLabel: undefined,\n})\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrNumberInput' })\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n (e: 'change', 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 { t } = useGranularityTranslations()\nconst resolvedIncreaseLabel = computed(() => props.increaseLabel ?? t('gr.numberInput.increase', 'Increase'))\nconst resolvedDecreaseLabel = computed(() => props.decreaseLabel ?? t('gr.numberInput.decrease', 'Decrease'))\n\nconst hasPrefix = computed(() => Boolean(slots.prefix))\nconst hasSuffix = computed(() => Boolean(slots.suffix))\n\nconst hasHorizontalControls = computed(() => props.controls && props.controlsDirection === 'horizontal')\nconst hasVerticalControls = computed(() => props.controls && props.controlsDirection === 'vertical')\n\nconst addonPx = computed(() => ADDON_PX_BY_SIZE[resolvedSize.value])\nconst addonLen = computed(() => px(addonPx.value))\nconst basePaddingXLen = computed(() => BASE_PADDING_X_LEN_BY_SIZE[resolvedSize.value])\n\nconst defaultAddonMinWidth = computed(() => addonLen.value)\nconst prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\n// Жёсткая ширина для fixed-режима: max → min → дефолт.\nconst prefixFixedWidth = computed(() => props.prefixMaxWidth ?? props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixFixedWidth = computed(() => props.suffixMaxWidth ?? props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\nconst { prefixEl, suffixEl, measuredPrefixWidth, measuredSuffixWidth } = useAddonMeasurement(hasPrefix, hasSuffix)\n\nconst prefixLen = computed(() => {\n if (!hasPrefix.value) return '0px'\n return props.prefixFixed ? prefixFixedWidth.value : measuredPrefixWidth.value ?? prefixMinWidth.value\n})\nconst suffixLen = computed(() => {\n if (!hasSuffix.value) return '0px'\n return props.suffixFixed ? suffixFixedWidth.value : measuredSuffixWidth.value ?? suffixMinWidth.value\n})\n\nfunction addonStyle(side: 'left' | 'right', offset: string): Record<string, string> {\n return {\n width: addonLen.value,\n [side]: offset,\n }\n}\n\nconst inputStyle = computed(() => {\n const leftControls = hasHorizontalControls.value ? addonLen.value : '0px'\n const rightControlsCount = (hasHorizontalControls.value ? 1 : 0) + (hasVerticalControls.value ? 1 : 0)\n const rightControls = rightControlsCount > 0 ? px(addonPx.value * rightControlsCount) : '0px'\n\n const leftReserved = addLen(prefixLen.value, leftControls)\n const rightReserved = addLen(suffixLen.value, rightControls)\n\n const left = hasPrefix.value || hasHorizontalControls.value ? addLen(leftReserved, basePaddingXLen.value) : undefined\n const right = hasSuffix.value || rightControlsCount > 0 ? addLen(rightReserved, basePaddingXLen.value) : undefined\n\n return {\n paddingLeft: left,\n paddingRight: right,\n } as Record<string, string | undefined>\n})\n\nconst suffixStyle = computed(() => {\n if (props.suffixFixed) {\n return {\n right: '0px',\n width: suffixFixedWidth.value,\n minWidth: suffixFixedWidth.value,\n maxWidth: suffixFixedWidth.value,\n }\n }\n\n return {\n right: '0px',\n minWidth: suffixMinWidth.value,\n maxWidth: props.suffixMaxWidth,\n }\n})\n\nconst prefixStyle = computed(() => {\n if (props.prefixFixed) {\n return {\n width: prefixFixedWidth.value,\n minWidth: prefixFixedWidth.value,\n maxWidth: prefixFixedWidth.value,\n }\n }\n\n return {\n minWidth: prefixMinWidth.value,\n maxWidth: props.prefixMaxWidth,\n }\n})\n\nconst verticalControlsStyle = computed(() => addonStyle('right', suffixLen.value))\nconst horizontalLeftControlsStyle = computed(() => addonStyle('left', prefixLen.value))\nconst horizontalRightControlsStyle = computed(() => addonStyle('right', suffixLen.value))\n\nconst shellClassName = computed(() => {\n return grNumberInputShellClass({\n disabled: props.disabled,\n state: props.invalid ? 'danger' : props.state,\n })\n})\n\nconst inputClassName = computed(() => {\n return grNumberInputInputClass({\n size: resolvedSize.value,\n textAlign: props.textAlign,\n })\n})\n\nfunction isDigit(ch: string): boolean {\n return ch >= '0' && ch <= '9'\n}\n\nfunction sanitize(raw: string): string {\n const sep = props.decimalSeparator || '.'\n\n let out = ''\n let hasSepLocal = false\n\n for (let i = 0; i < raw.length; i++) {\n const ch = raw[i]\n\n // Ведущий минус: разрешаем один в начале, чтобы можно было ввести\n // отрицательное значение с клавиатуры (границы проверит `clamp` на change).\n if (ch === '-' && out.length === 0) {\n out += '-'\n continue\n }\n\n if (isDigit(ch)) {\n out += ch\n continue\n }\n\n if ((ch === sep || ch === '.' || ch === ',') && !hasSepLocal) {\n out += sep\n hasSepLocal = true\n }\n }\n\n return out\n}\n\nfunction toNumber(value: string): number | null {\n if (value.trim() === '') return null\n const sep = props.decimalSeparator || '.'\n const normalized = sep === '.' ? value : value.replace(sep, '.')\n const n = Number(normalized)\n if (!Number.isFinite(n)) return null\n return n\n}\n\nfunction clamp(v: number): number {\n if (props.min !== undefined) v = Math.max(props.min, v)\n if (props.max !== undefined) v = Math.min(props.max, v)\n return v\n}\n\nfunction normalize(v: number): number {\n if (props.precision === undefined) return v\n const p = Math.max(0, props.precision)\n return Number(v.toFixed(p))\n}\n\nfunction format(n: number): string {\n const sep = props.decimalSeparator || '.'\n const p = props.precision\n\n // Без `precision` избегаем экспоненциальной записи (`String(1e21)` → `\"1e+21\"`),\n // форматируя через `Intl` без группировки разрядов.\n let s = p === undefined\n ? n.toLocaleString('en-US', { useGrouping: false, maximumFractionDigits: 20 })\n : n.toFixed(Math.max(0, p))\n if (sep !== '.') s = s.replace('.', sep)\n return s\n}\n\nfunction onInput(e: Event): void {\n const el = e.target as HTMLInputElement\n const raw = el.value\n const next = sanitize(raw)\n\n if (raw !== next) {\n // Сохраняем позицию каретки: считаем, сколько валидных символов было ДО\n // каретки, и ставим её после стольких же в очищенной строке — иначе при\n // редактировании середины числа каретка прыгала в конец.\n const caret = el.selectionStart ?? raw.length\n const keptBefore = sanitize(raw.slice(0, caret)).length\n el.value = next\n el.setSelectionRange(keptBefore, keptBefore)\n }\n\n emit('update:modelValue', next)\n}\n\nfunction commit(el: HTMLInputElement): void {\n const num = toNumber(sanitize(el.value))\n // Пустое значение (или незавершённый ввод `-`) оставляем как есть.\n const next = num === null ? sanitize(el.value) : format(clamp(normalize(num)))\n\n if (el.value !== next) el.value = next\n if (next !== props.modelValue) emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction onChange(e: Event): void {\n // Клампинг границ (`min`/`max`) и нормализация — на `change`/`blur`, а не только\n // в кнопках: раньше ручной ввод «999» при `max=10` оставался невалидным.\n commit(e.target as HTMLInputElement)\n}\n\nfunction setValue(n: number): void {\n const nextStr = format(clamp(normalize(n)))\n emit('update:modelValue', nextStr)\n emit('change', nextStr)\n}\n\nfunction stepBy(dir: 1 | -1): void {\n if (props.disabled) return\n\n const current = toNumber(props.modelValue) ?? 0\n setValue(current + (props.step ?? 1) * dir)\n focus()\n}\n\n// Клавиатура спинбаттона (WAI-ARIA spinbutton): стрелки шагают, Home/End —\n// к границам `min`/`max` (если заданы).\nfunction onKeydown(e: KeyboardEvent): void {\n if (props.disabled) return\n\n switch (e.key) {\n case 'ArrowUp':\n e.preventDefault()\n stepBy(1)\n break\n case 'ArrowDown':\n e.preventDefault()\n stepBy(-1)\n break\n case 'Home':\n if (props.min !== undefined) {\n e.preventDefault()\n setValue(props.min)\n }\n break\n case 'End':\n if (props.max !== undefined) {\n e.preventDefault()\n setValue(props.max)\n }\n break\n }\n}\n\n// `aria-valuenow` — числовое значение для скринридеров; отсутствует, если поле пусто.\nconst ariaValueNow = computed(() => toNumber(props.modelValue) ?? undefined)\n\n// Локале-зависимое отображение: при фокусе показываем «сырое» значение для\n// редактирования, иначе — сгруппированное через `Intl.NumberFormat`.\nconst isFocused = ref(false)\n\nfunction formatGrouped(value: string): string {\n const num = toNumber(value)\n if (num === null) return value\n const sep = props.decimalSeparator || '.'\n // formatToParts позволяет оставить локале-зависимый групповой разделитель,\n // но принудительно подставить наш десятичный разделитель (`decimalSeparator`),\n // корректно работая для любой локали (в т.ч. de-DE, где группа — '.').\n return new Intl.NumberFormat(props.locale, {\n useGrouping: true,\n minimumFractionDigits: props.precision ?? 0,\n maximumFractionDigits: props.precision ?? 20,\n })\n .formatToParts(num)\n .map(part => (part.type === 'decimal' ? sep : part.value))\n .join('')\n}\n\nconst displayValue = computed(() => {\n if (!props.useGrouping || isFocused.value) return props.modelValue\n return formatGrouped(props.modelValue)\n})\n\nfunction onFocus(): void {\n isFocused.value = true\n}\n\nfunction onBlur(): void {\n isFocused.value = false\n}\n</script>\n\n<template>\n <div\n data-gr-number-input\n class=\"relative w-full overflow-hidden rounded-md border bg-[var(--gr-bg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--gr-ring)]\"\n :class=\"shellClassName\"\n >\n <div\n v-if=\"$slots.prefix\"\n ref=\"prefixEl\"\n data-testid=\"number-input-prefix\"\n data-gr-number-input-prefix\n class=\"absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--gr-brd)] px-2 text-[var(--gr-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=\"id\"\n ref=\"inputEl\"\n v-bind=\"$attrs\"\n :name=\"name\"\n type=\"text\"\n :inputmode=\"inputmode\"\n :autocomplete=\"autocomplete\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :value=\"displayValue\"\n role=\"spinbutton\"\n :aria-valuenow=\"ariaValueNow\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n class=\"w-full bg-transparent text-[var(--gr-fg)] placeholder:text-[var(--gr-muted-fg)] focus:placeholder:text-transparent focus:outline-none disabled:cursor-not-allowed\"\n :class=\"inputClassName\"\n :style=\"inputStyle\"\n @input=\"onInput\"\n @change=\"onChange\"\n @keydown=\"onKeydown\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n >\n\n <div\n v-if=\"$slots.suffix\"\n ref=\"suffixEl\"\n data-testid=\"number-input-suffix\"\n data-gr-number-input-suffix\n class=\"absolute inset-y-0 flex items-center justify-center border-l border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate\"\n :class=\"suffixFixed ? '[direction:rtl]' : ''\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n\n <div\n v-if=\"hasVerticalControls\"\n data-testid=\"number-input-controls-vertical\"\n data-gr-number-input-controls=\"vertical\"\n class=\"absolute inset-y-0 flex items-center justify-center border-l border-[var(--gr-brd)]\"\n :style=\"verticalControlsStyle\"\n >\n <div class=\"flex flex-col justify-center gap-1\">\n <button\n type=\"button\"\n class=\"h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedIncreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M7 14l5-5 5 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedDecreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(-1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M7 10l5 5 5-5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n <div\n v-if=\"hasHorizontalControls\"\n data-testid=\"number-input-controls-horizontal-left\"\n data-gr-number-input-controls=\"horizontal-left\"\n class=\"absolute inset-y-0 flex items-stretch justify-center border-r border-[var(--gr-brd)]\"\n :style=\"horizontalLeftControlsStyle\"\n >\n <button\n type=\"button\"\n class=\"h-full w-full inline-flex items-center justify-center text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedDecreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(-1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M14 7l-5 5 5 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n\n <div\n v-if=\"hasHorizontalControls\"\n data-testid=\"number-input-controls-horizontal-right\"\n data-gr-number-input-controls=\"horizontal-right\"\n class=\"absolute inset-y-0 flex items-stretch justify-center border-l border-[var(--gr-brd)]\"\n :style=\"horizontalRightControlsStyle\"\n >\n <button\n type=\"button\"\n class=\"h-full w-full inline-flex items-center justify-center text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedIncreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10 7l5 5-5 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { InputHTMLAttributes } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { computed, ref, useSlots } from 'vue'\n\nimport {\n grNumberInputInputClass,\n grNumberInputShellClass,\n type GrNumberInputControlsDirection,\n type GrNumberInputSize,\n type GrNumberInputState,\n type GrNumberInputTextAlign,\n} from './grNumberInputStyles'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { addLen, useAddonMeasurement } from '../../composables/internal/useAddonMeasurement'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst ADDON_PX_BY_SIZE: Record<GrNumberInputSize, number> = {\n xs: 32,\n sm: 36,\n md: 40,\n lg: 48,\n}\n\nconst BASE_PADDING_X_LEN_BY_SIZE: Record<GrNumberInputSize, string> = {\n xs: '10px',\n sm: '12px',\n md: '12px',\n lg: '16px',\n}\n\nfunction px(n: number): string {\n return `${n}px`\n}\n\nexport interface GrNumberInputProps {\n /** Значение (строка — контролируем форматирование внутри). */\n modelValue: string\n placeholder?: string\n autocomplete?: string\n inputmode?: InputHTMLAttributes['inputmode']\n disabled?: boolean\n /** Быстрый флаг невалидности; эквивалент `state='danger'` + `aria-invalid`. */\n invalid?: boolean\n state?: GrNumberInputState\n name?: string\n id?: string\n size?: GrNumberInputSize\n\n textAlign?: GrNumberInputTextAlign\n\n decimalSeparator?: string\n step?: number\n min?: number\n max?: number\n precision?: number\n\n /**\n * BCP-47 локаль для отображения значения (группировка разрядов и разделители\n * через `Intl.NumberFormat`). Работает вместе с `useGrouping`.\n */\n locale?: string\n /**\n * Группировать разряды при отображении (когда поле не в фокусе). При фокусе\n * показывается «сырое» значение для редактирования. По умолчанию выключено.\n */\n useGrouping?: boolean\n\n /** Показывать кнопки +/-. */\n controls?: boolean\n controlsDirection?: GrNumberInputControlsDirection\n\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n /**\n * Фиксированная ширина у prefix/suffix: жёсткая ширина (из `*MaxWidth` →\n * `*MinWidth` → дефолт) + обрезка контента по краю (prefix — справа,\n * suffix — слева). По умолчанию аддоны растягиваются под контент.\n */\n prefixFixed?: boolean\n suffixFixed?: boolean\n\n /** i18n-friendly aria-label для кнопки \"увеличить\". */\n increaseLabel?: string\n /** i18n-friendly aria-label для кнопки \"уменьшить\". */\n decreaseLabel?: string\n}\n\nconst props = withDefaults(defineProps<GrNumberInputProps>(), {\n placeholder: undefined,\n autocomplete: undefined,\n inputmode: 'decimal',\n disabled: false,\n invalid: false,\n state: 'default',\n name: undefined,\n id: undefined,\n size: undefined,\n\n textAlign: 'left',\n\n decimalSeparator: '.',\n step: 1,\n min: undefined,\n max: undefined,\n precision: undefined,\n locale: undefined,\n useGrouping: false,\n\n controls: false,\n controlsDirection: 'vertical',\n\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n prefixFixed: false,\n suffixFixed: false,\n\n increaseLabel: undefined,\n decreaseLabel: undefined,\n})\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrNumberInput' })\n\nconst emit = defineEmits<{\n (e: 'update:modelValue', value: string): void\n (e: 'change', 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 { t } = useGranularityTranslations()\nconst resolvedIncreaseLabel = computed(() => props.increaseLabel ?? t('gr.numberInput.increase', 'Increase'))\nconst resolvedDecreaseLabel = computed(() => props.decreaseLabel ?? t('gr.numberInput.decrease', 'Decrease'))\n\nconst hasPrefix = computed(() => Boolean(slots.prefix))\nconst hasSuffix = computed(() => Boolean(slots.suffix))\n\nconst hasHorizontalControls = computed(() => props.controls && props.controlsDirection === 'horizontal')\nconst hasVerticalControls = computed(() => props.controls && props.controlsDirection === 'vertical')\n\nconst addonPx = computed(() => ADDON_PX_BY_SIZE[resolvedSize.value])\nconst addonLen = computed(() => px(addonPx.value))\nconst basePaddingXLen = computed(() => BASE_PADDING_X_LEN_BY_SIZE[resolvedSize.value])\n\nconst defaultAddonMinWidth = computed(() => addonLen.value)\nconst prefixMinWidth = computed(() => props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixMinWidth = computed(() => props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\n// Жёсткая ширина для fixed-режима: max → min → дефолт.\nconst prefixFixedWidth = computed(() => props.prefixMaxWidth ?? props.prefixMinWidth ?? defaultAddonMinWidth.value)\nconst suffixFixedWidth = computed(() => props.suffixMaxWidth ?? props.suffixMinWidth ?? defaultAddonMinWidth.value)\n\nconst { prefixEl, suffixEl, measuredPrefixWidth, measuredSuffixWidth } = useAddonMeasurement(hasPrefix, hasSuffix)\n\nconst prefixLen = computed(() => {\n if (!hasPrefix.value) return '0px'\n return props.prefixFixed ? prefixFixedWidth.value : measuredPrefixWidth.value ?? prefixMinWidth.value\n})\nconst suffixLen = computed(() => {\n if (!hasSuffix.value) return '0px'\n return props.suffixFixed ? suffixFixedWidth.value : measuredSuffixWidth.value ?? suffixMinWidth.value\n})\n\nfunction addonStyle(side: 'left' | 'right', offset: string): Record<string, string> {\n return {\n width: addonLen.value,\n [side]: offset,\n }\n}\n\nconst inputStyle = computed(() => {\n const leftControls = hasHorizontalControls.value ? addonLen.value : '0px'\n const rightControlsCount = (hasHorizontalControls.value ? 1 : 0) + (hasVerticalControls.value ? 1 : 0)\n const rightControls = rightControlsCount > 0 ? px(addonPx.value * rightControlsCount) : '0px'\n\n const leftReserved = addLen(prefixLen.value, leftControls)\n const rightReserved = addLen(suffixLen.value, rightControls)\n\n const left = hasPrefix.value || hasHorizontalControls.value ? addLen(leftReserved, basePaddingXLen.value) : undefined\n const right = hasSuffix.value || rightControlsCount > 0 ? addLen(rightReserved, basePaddingXLen.value) : undefined\n\n return {\n paddingLeft: left,\n paddingRight: right,\n } as Record<string, string | undefined>\n})\n\nconst suffixStyle = computed(() => {\n if (props.suffixFixed) {\n return {\n right: '0px',\n width: suffixFixedWidth.value,\n minWidth: suffixFixedWidth.value,\n maxWidth: suffixFixedWidth.value,\n }\n }\n\n return {\n right: '0px',\n minWidth: suffixMinWidth.value,\n maxWidth: props.suffixMaxWidth,\n }\n})\n\nconst prefixStyle = computed(() => {\n if (props.prefixFixed) {\n return {\n width: prefixFixedWidth.value,\n minWidth: prefixFixedWidth.value,\n maxWidth: prefixFixedWidth.value,\n }\n }\n\n return {\n minWidth: prefixMinWidth.value,\n maxWidth: props.prefixMaxWidth,\n }\n})\n\nconst verticalControlsStyle = computed(() => addonStyle('right', suffixLen.value))\nconst horizontalLeftControlsStyle = computed(() => addonStyle('left', prefixLen.value))\nconst horizontalRightControlsStyle = computed(() => addonStyle('right', suffixLen.value))\n\nconst shellClassName = computed(() => {\n return grNumberInputShellClass({\n disabled: props.disabled,\n state: props.invalid ? 'danger' : props.state,\n })\n})\n\nconst inputClassName = computed(() => {\n return grNumberInputInputClass({\n size: resolvedSize.value,\n textAlign: props.textAlign,\n })\n})\n\nfunction isDigit(ch: string): boolean {\n return ch >= '0' && ch <= '9'\n}\n\nfunction sanitize(raw: string): string {\n const sep = props.decimalSeparator || '.'\n\n let out = ''\n let hasSepLocal = false\n\n for (let i = 0; i < raw.length; i++) {\n const ch = raw[i]\n\n // Ведущий минус: разрешаем один в начале, чтобы можно было ввести\n // отрицательное значение с клавиатуры (границы проверит `clamp` на change).\n if (ch === '-' && out.length === 0) {\n out += '-'\n continue\n }\n\n if (isDigit(ch)) {\n out += ch\n continue\n }\n\n if ((ch === sep || ch === '.' || ch === ',') && !hasSepLocal) {\n out += sep\n hasSepLocal = true\n }\n }\n\n return out\n}\n\nfunction toNumber(value: string): number | null {\n if (value.trim() === '') return null\n const sep = props.decimalSeparator || '.'\n const normalized = sep === '.' ? value : value.replace(sep, '.')\n const n = Number(normalized)\n if (!Number.isFinite(n)) return null\n return n\n}\n\nfunction clamp(v: number): number {\n if (props.min !== undefined) v = Math.max(props.min, v)\n if (props.max !== undefined) v = Math.min(props.max, v)\n return v\n}\n\nfunction normalize(v: number): number {\n if (props.precision === undefined) return v\n const p = Math.max(0, props.precision)\n return Number(v.toFixed(p))\n}\n\nfunction format(n: number): string {\n const sep = props.decimalSeparator || '.'\n const p = props.precision\n\n // Без `precision` избегаем экспоненциальной записи (`String(1e21)` → `\"1e+21\"`),\n // форматируя через `Intl` без группировки разрядов.\n let s = p === undefined\n ? n.toLocaleString('en-US', { useGrouping: false, maximumFractionDigits: 20 })\n : n.toFixed(Math.max(0, p))\n if (sep !== '.') s = s.replace('.', sep)\n return s\n}\n\nfunction onInput(e: Event): void {\n const el = e.target as HTMLInputElement\n const raw = el.value\n const next = sanitize(raw)\n\n if (raw !== next) {\n // Сохраняем позицию каретки: считаем, сколько валидных символов было ДО\n // каретки, и ставим её после стольких же в очищенной строке — иначе при\n // редактировании середины числа каретка прыгала в конец.\n const caret = el.selectionStart ?? raw.length\n const keptBefore = sanitize(raw.slice(0, caret)).length\n el.value = next\n el.setSelectionRange(keptBefore, keptBefore)\n }\n\n emit('update:modelValue', next)\n}\n\nfunction commit(el: HTMLInputElement): void {\n const num = toNumber(sanitize(el.value))\n // Пустое значение (или незавершённый ввод `-`) оставляем как есть.\n const next = num === null ? sanitize(el.value) : format(clamp(normalize(num)))\n\n if (el.value !== next) el.value = next\n if (next !== props.modelValue) emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction onChange(e: Event): void {\n // Клампинг границ (`min`/`max`) и нормализация — на `change`/`blur`, а не только\n // в кнопках: раньше ручной ввод «999» при `max=10` оставался невалидным.\n commit(e.target as HTMLInputElement)\n}\n\nfunction setValue(n: number): void {\n const nextStr = format(clamp(normalize(n)))\n emit('update:modelValue', nextStr)\n emit('change', nextStr)\n}\n\nfunction stepBy(dir: 1 | -1): void {\n if (props.disabled) return\n\n const current = toNumber(props.modelValue) ?? 0\n setValue(current + (props.step ?? 1) * dir)\n focus()\n}\n\n// Клавиатура спинбаттона (WAI-ARIA spinbutton): стрелки шагают, Home/End —\n// к границам `min`/`max` (если заданы).\nfunction onKeydown(e: KeyboardEvent): void {\n if (props.disabled) return\n\n switch (e.key) {\n case 'ArrowUp':\n e.preventDefault()\n stepBy(1)\n break\n case 'ArrowDown':\n e.preventDefault()\n stepBy(-1)\n break\n case 'Home':\n if (props.min !== undefined) {\n e.preventDefault()\n setValue(props.min)\n }\n break\n case 'End':\n if (props.max !== undefined) {\n e.preventDefault()\n setValue(props.max)\n }\n break\n }\n}\n\n// `aria-valuenow` — числовое значение для скринридеров; отсутствует, если поле пусто.\nconst ariaValueNow = computed(() => toNumber(props.modelValue) ?? undefined)\n\n// Локале-зависимое отображение: при фокусе показываем «сырое» значение для\n// редактирования, иначе — сгруппированное через `Intl.NumberFormat`.\nconst isFocused = ref(false)\n\nfunction formatGrouped(value: string): string {\n const num = toNumber(value)\n if (num === null) return value\n const sep = props.decimalSeparator || '.'\n // formatToParts позволяет оставить локале-зависимый групповой разделитель,\n // но принудительно подставить наш десятичный разделитель (`decimalSeparator`),\n // корректно работая для любой локали (в т.ч. de-DE, где группа — '.').\n return new Intl.NumberFormat(props.locale, {\n useGrouping: true,\n minimumFractionDigits: props.precision ?? 0,\n maximumFractionDigits: props.precision ?? 20,\n })\n .formatToParts(num)\n .map(part => (part.type === 'decimal' ? sep : part.value))\n .join('')\n}\n\nconst displayValue = computed(() => {\n if (!props.useGrouping || isFocused.value) return props.modelValue\n return formatGrouped(props.modelValue)\n})\n\nfunction onFocus(): void {\n isFocused.value = true\n}\n\nfunction onBlur(): void {\n isFocused.value = false\n}\n</script>\n\n<template>\n <div\n data-gr-number-input\n class=\"relative w-full overflow-hidden rounded-md border bg-[var(--gr-bg)] transition-colors duration-150 focus-within:ring-2 focus-within:ring-[var(--gr-ring)]\"\n :class=\"shellClassName\"\n >\n <div\n v-if=\"$slots.prefix\"\n ref=\"prefixEl\"\n data-testid=\"number-input-prefix\"\n data-gr-number-input-prefix\n class=\"absolute inset-y-0 left-0 flex items-center justify-center border-r border-[var(--gr-brd)] px-2 text-[var(--gr-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=\"id\"\n ref=\"inputEl\"\n v-bind=\"$attrs\"\n :name=\"name\"\n type=\"text\"\n :inputmode=\"inputmode\"\n :autocomplete=\"autocomplete\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :value=\"displayValue\"\n role=\"spinbutton\"\n :aria-valuenow=\"ariaValueNow\"\n :aria-valuemin=\"min\"\n :aria-valuemax=\"max\"\n :aria-invalid=\"invalid ? 'true' : undefined\"\n class=\"w-full bg-transparent text-[var(--gr-fg)] placeholder:text-[var(--gr-muted-fg)] focus:placeholder:text-transparent focus:outline-none disabled:cursor-not-allowed\"\n :class=\"inputClassName\"\n :style=\"inputStyle\"\n @input=\"onInput\"\n @change=\"onChange\"\n @keydown=\"onKeydown\"\n @focus=\"onFocus\"\n @blur=\"onBlur\"\n >\n\n <div\n v-if=\"$slots.suffix\"\n ref=\"suffixEl\"\n data-testid=\"number-input-suffix\"\n data-gr-number-input-suffix\n class=\"absolute inset-y-0 flex items-center justify-center border-l border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate\"\n :class=\"suffixFixed ? '[direction:rtl]' : ''\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n\n <div\n v-if=\"hasVerticalControls\"\n data-testid=\"number-input-controls-vertical\"\n data-gr-number-input-controls=\"vertical\"\n class=\"absolute inset-y-0 flex items-center justify-center border-l border-[var(--gr-brd)]\"\n :style=\"verticalControlsStyle\"\n >\n <div class=\"flex flex-col justify-center gap-1\">\n <button\n type=\"button\"\n class=\"h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedIncreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M7 14l5-5 5 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"h-4 w-7 inline-flex items-center justify-center rounded text-[10px] text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedDecreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(-1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M7 10l5 5 5-5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n\n <div\n v-if=\"hasHorizontalControls\"\n data-testid=\"number-input-controls-horizontal-left\"\n data-gr-number-input-controls=\"horizontal-left\"\n class=\"absolute inset-y-0 flex items-stretch justify-center border-r border-[var(--gr-brd)]\"\n :style=\"horizontalLeftControlsStyle\"\n >\n <button\n type=\"button\"\n class=\"h-full w-full inline-flex items-center justify-center text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedDecreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(-1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M14 7l-5 5 5 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n\n <div\n v-if=\"hasHorizontalControls\"\n data-testid=\"number-input-controls-horizontal-right\"\n data-gr-number-input-controls=\"horizontal-right\"\n class=\"absolute inset-y-0 flex items-stretch justify-center border-l border-[var(--gr-brd)]\"\n :style=\"horizontalRightControlsStyle\"\n >\n <button\n type=\"button\"\n class=\"h-full w-full inline-flex items-center justify-center text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] active:bg-[var(--gr-muted)] disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]\"\n :disabled=\"disabled\"\n :aria-label=\"resolvedIncreaseLabel\"\n @mousedown.prevent\n @click=\"stepBy(1)\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10 7l5 5-5 5\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as grNumberInputSafelist, t as grNumberInputConfig } from "../../chunks/config-
|
|
2
|
-
import { t as GrNumberInput_default } from "./chunks/GrNumberInput-
|
|
1
|
+
import { n as grNumberInputSafelist, t as grNumberInputConfig } from "../../chunks/config-gZWR75Bh2.js";
|
|
2
|
+
import { t as GrNumberInput_default } from "./chunks/GrNumberInput-l9ZOHG9D.js";
|
|
3
3
|
export { GrNumberInput_default as GrNumberInput, GrNumberInput_default as default, grNumberInputConfig, grNumberInputSafelist };
|
package/dist/components/GrPagination/chunks/{GrPagination-mlyfLjQY.js → GrPagination-C5Y69CuK.js}
RENAMED
|
@@ -1,22 +1,36 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as GrButton_default } from "../../GrButton/chunks/GrButton-
|
|
3
|
-
import { t as GrSelect_default } from "../../GrSelect/chunks/GrSelect-
|
|
4
|
-
import { Fragment, computed, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, renderList, toDisplayString, unref, watch, withCtx } from "vue";
|
|
1
|
+
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-SH0I--GW.js";
|
|
2
|
+
import { t as GrButton_default } from "../../GrButton/chunks/GrButton-DCi4CUpo.js";
|
|
3
|
+
import { t as GrSelect_default } from "../../GrSelect/chunks/GrSelect-Dn3FgJ3Z.js";
|
|
4
|
+
import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, toDisplayString, unref, vModelText, watch, withCtx, withDirectives, withKeys } from "vue";
|
|
5
5
|
//#region src/components/GrPagination/GrPagination.vue?vue&type=script&setup=true&lang.ts
|
|
6
6
|
var _hoisted_1 = ["aria-label"];
|
|
7
7
|
var _hoisted_2 = { class: "min-w-[100px]" };
|
|
8
|
-
var _hoisted_3 = {
|
|
8
|
+
var _hoisted_3 = {
|
|
9
|
+
key: 0,
|
|
10
|
+
"data-gr-pagination-compact": "",
|
|
11
|
+
class: "px-2 text-sm text-[var(--gr-fg)] tabular-nums",
|
|
12
|
+
"aria-live": "polite"
|
|
13
|
+
};
|
|
9
14
|
var _hoisted_4 = {
|
|
15
|
+
key: 1,
|
|
16
|
+
class: "flex items-center gap-1"
|
|
17
|
+
};
|
|
18
|
+
var _hoisted_5 = {
|
|
10
19
|
key: 0,
|
|
11
20
|
"data-gr-pagination-ellipsis": "",
|
|
12
21
|
"aria-hidden": "true",
|
|
13
|
-
class: "h-8 min-w-8 px-1 grid place-items-center text-sm text-[var(--muted-fg)]"
|
|
22
|
+
class: "h-8 min-w-8 px-1 grid place-items-center text-sm text-[var(--gr-muted-fg)]"
|
|
14
23
|
};
|
|
15
|
-
var
|
|
24
|
+
var _hoisted_6 = [
|
|
16
25
|
"aria-current",
|
|
17
26
|
"aria-label",
|
|
18
27
|
"onClick"
|
|
19
28
|
];
|
|
29
|
+
var _hoisted_7 = {
|
|
30
|
+
key: 2,
|
|
31
|
+
class: "flex items-center gap-2 text-sm text-[var(--gr-muted-fg)]"
|
|
32
|
+
};
|
|
33
|
+
var _hoisted_8 = ["max", "aria-label"];
|
|
20
34
|
//#endregion
|
|
21
35
|
//#region src/components/GrPagination/GrPagination.vue
|
|
22
36
|
var GrPagination_default = /* @__PURE__ */ defineComponent({
|
|
@@ -31,7 +45,16 @@ var GrPagination_default = /* @__PURE__ */ defineComponent({
|
|
|
31
45
|
50
|
|
32
46
|
] },
|
|
33
47
|
siblingCount: { default: 1 },
|
|
34
|
-
boundaryCount: { default: 1 }
|
|
48
|
+
boundaryCount: { default: 1 },
|
|
49
|
+
compact: {
|
|
50
|
+
type: Boolean,
|
|
51
|
+
default: false
|
|
52
|
+
},
|
|
53
|
+
showJumper: {
|
|
54
|
+
type: Boolean,
|
|
55
|
+
default: false
|
|
56
|
+
},
|
|
57
|
+
jumperLabel: { default: void 0 }
|
|
35
58
|
},
|
|
36
59
|
emits: ["update:page", "update:pageSize"],
|
|
37
60
|
setup(__props, { emit: __emit }) {
|
|
@@ -87,6 +110,14 @@ var GrPagination_default = /* @__PURE__ */ defineComponent({
|
|
|
87
110
|
function last() {
|
|
88
111
|
goTo(pageCount.value);
|
|
89
112
|
}
|
|
113
|
+
const jumperValue = ref("");
|
|
114
|
+
function submitJumper() {
|
|
115
|
+
const parsed = Number.parseInt(jumperValue.value, 10);
|
|
116
|
+
jumperValue.value = "";
|
|
117
|
+
if (Number.isNaN(parsed)) return;
|
|
118
|
+
goTo(Math.min(pageCount.value, Math.max(1, parsed)));
|
|
119
|
+
}
|
|
120
|
+
const resolvedJumperLabel = computed(() => props.jumperLabel ?? t("gr.pagination.jumpTo", "Go to"));
|
|
90
121
|
return (_ctx, _cache) => {
|
|
91
122
|
return openBlock(), createElementBlock("div", {
|
|
92
123
|
class: "flex flex-wrap items-center justify-end gap-3",
|
|
@@ -112,7 +143,7 @@ var GrPagination_default = /* @__PURE__ */ defineComponent({
|
|
|
112
143
|
"data-gr-pagination-first": "",
|
|
113
144
|
onClick: first
|
|
114
145
|
}, {
|
|
115
|
-
default: withCtx(() => [..._cache[
|
|
146
|
+
default: withCtx(() => [..._cache[2] || (_cache[2] = [createTextVNode(" « ", -1)])]),
|
|
116
147
|
_: 1
|
|
117
148
|
}, 8, ["disabled", "aria-label"]),
|
|
118
149
|
createVNode(GrButton_default, {
|
|
@@ -125,17 +156,17 @@ var GrPagination_default = /* @__PURE__ */ defineComponent({
|
|
|
125
156
|
default: withCtx(() => [createTextVNode(toDisplayString(unref(t)("gr.pagination.prev", "Prev")), 1)]),
|
|
126
157
|
_: 1
|
|
127
158
|
}, 8, ["disabled"]),
|
|
128
|
-
|
|
129
|
-
return openBlock(), createElementBlock(Fragment, { key: index }, [item === "ellipsis-start" || item === "ellipsis-end" ? (openBlock(), createElementBlock("span",
|
|
159
|
+
__props.compact ? (openBlock(), createElementBlock("div", _hoisted_3, toDisplayString(__props.page) + " / " + toDisplayString(pageCount.value), 1)) : (openBlock(), createElementBlock("div", _hoisted_4, [(openBlock(true), createElementBlock(Fragment, null, renderList(items.value, (item, index) => {
|
|
160
|
+
return openBlock(), createElementBlock(Fragment, { key: index }, [item === "ellipsis-start" || item === "ellipsis-end" ? (openBlock(), createElementBlock("span", _hoisted_5, "…")) : (openBlock(), createElementBlock("button", {
|
|
130
161
|
key: 1,
|
|
131
162
|
type: "button",
|
|
132
163
|
"data-gr-pagination-page": "",
|
|
133
164
|
"aria-current": item === __props.page ? "page" : void 0,
|
|
134
165
|
"aria-label": unref(t)("gr.pagination.page", "Page {n}", { n: item }),
|
|
135
|
-
class: normalizeClass(["h-8 min-w-8 px-2 rounded-md text-sm font-600 transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ring)]", item === __props.page ? "bg-[var(--primary)] text-[var(--primary-fg)]" : "text-[var(--muted-fg)] hover:bg-[var(--muted)] hover:text-[var(--fg)]"]),
|
|
166
|
+
class: normalizeClass(["h-8 min-w-8 px-2 rounded-md text-sm font-600 transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]", item === __props.page ? "bg-[var(--gr-primary)] text-[var(--gr-primary-fg)]" : "text-[var(--gr-muted-fg)] hover:bg-[var(--gr-muted)] hover:text-[var(--gr-fg)]"]),
|
|
136
167
|
onClick: ($event) => goTo(item)
|
|
137
|
-
}, toDisplayString(item), 11,
|
|
138
|
-
}), 128))]),
|
|
168
|
+
}, toDisplayString(item), 11, _hoisted_6))], 64);
|
|
169
|
+
}), 128))])),
|
|
139
170
|
createVNode(GrButton_default, {
|
|
140
171
|
variant: "ghost",
|
|
141
172
|
size: "sm",
|
|
@@ -154,9 +185,21 @@ var GrPagination_default = /* @__PURE__ */ defineComponent({
|
|
|
154
185
|
"data-gr-pagination-last": "",
|
|
155
186
|
onClick: last
|
|
156
187
|
}, {
|
|
157
|
-
default: withCtx(() => [..._cache[
|
|
188
|
+
default: withCtx(() => [..._cache[3] || (_cache[3] = [createTextVNode(" » ", -1)])]),
|
|
158
189
|
_: 1
|
|
159
|
-
}, 8, ["disabled", "aria-label"])
|
|
190
|
+
}, 8, ["disabled", "aria-label"]),
|
|
191
|
+
__props.showJumper ? (openBlock(), createElementBlock("div", _hoisted_7, [createElementVNode("span", null, toDisplayString(resolvedJumperLabel.value), 1), withDirectives(createElementVNode("input", {
|
|
192
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => jumperValue.value = $event),
|
|
193
|
+
type: "number",
|
|
194
|
+
min: "1",
|
|
195
|
+
max: pageCount.value,
|
|
196
|
+
inputmode: "numeric",
|
|
197
|
+
"data-gr-pagination-jumper": "",
|
|
198
|
+
"aria-label": resolvedJumperLabel.value,
|
|
199
|
+
class: "h-8 w-14 rounded-md border border-[var(--gr-brd)] bg-[var(--gr-bg)] px-2 text-center text-sm text-[var(--gr-fg)] tabular-nums transition-colors duration-150 focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]",
|
|
200
|
+
onKeydown: withKeys(submitJumper, ["enter"]),
|
|
201
|
+
onBlur: submitJumper
|
|
202
|
+
}, null, 40, _hoisted_8), [[vModelText, jumperValue.value]])])) : createCommentVNode("", true)
|
|
160
203
|
], 8, _hoisted_1);
|
|
161
204
|
};
|
|
162
205
|
}
|