@feugene/granularity 0.48.0 → 0.50.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/README.md +3 -3
- package/dist/chunks/chevron-up-BhW6hi8L.js +23 -0
- package/dist/chunks/chevron-up-BhW6hi8L.js.map +1 -0
- package/dist/chunks/{config-E1cTyRVV.js → config-8n1VR0ju.js} +1 -1
- package/dist/chunks/{config-E1cTyRVV.js.map → config-8n1VR0ju.js.map} +1 -1
- package/dist/chunks/{config-2vrOFn2f.js → config-AKpLyIGD.js} +2 -2
- package/dist/chunks/{config-2vrOFn2f.js.map → config-AKpLyIGD.js.map} +1 -1
- package/dist/chunks/{config-DIDz_E5m.js → config-B34mkd53.js} +66 -1
- package/dist/chunks/config-B34mkd53.js.map +1 -0
- package/dist/chunks/{config-B5SBUa6u.js → config-B7qZqiUB.js} +28 -1
- package/dist/chunks/config-B7qZqiUB.js.map +1 -0
- package/dist/chunks/config-BBrPUEye.js +8 -0
- package/dist/chunks/config-BBrPUEye.js.map +1 -0
- package/dist/chunks/config-BBtBQE3s.js +108 -0
- package/dist/chunks/config-BBtBQE3s.js.map +1 -0
- package/dist/chunks/{config-CT4lP6S4.js → config-BOCzHqWh.js} +2 -2
- package/dist/chunks/{config-CT4lP6S4.js.map → config-BOCzHqWh.js.map} +1 -1
- package/dist/chunks/{config-iemgzS4x.js → config-BP1ktzwh.js} +2 -24
- package/dist/chunks/config-BP1ktzwh.js.map +1 -0
- package/dist/chunks/config-BTxmdRzT.js +28 -0
- package/dist/chunks/config-BTxmdRzT.js.map +1 -0
- package/dist/chunks/{config-CjWOTgLL.js → config-Bk52xd5l.js} +12 -5
- package/dist/chunks/config-Bk52xd5l.js.map +1 -0
- package/dist/chunks/{config-D3HOuHDe.js → config-C3SqBqSQ.js} +3 -1
- package/dist/chunks/config-C3SqBqSQ.js.map +1 -0
- package/dist/chunks/{config-2ZHRsdOc.js → config-C3uqd-sW.js} +1 -1
- package/dist/chunks/config-C3uqd-sW.js.map +1 -0
- package/dist/chunks/{config-BXRmsn3t.js → config-CPhcZzHi.js} +72 -10
- package/dist/chunks/config-CPhcZzHi.js.map +1 -0
- package/dist/chunks/config-CWtfxkM9.js.map +1 -1
- package/dist/chunks/{config--t2dxj0t.js → config-CmLTCmY9.js} +2 -2
- package/dist/chunks/{config--t2dxj0t.js.map → config-CmLTCmY9.js.map} +1 -1
- package/dist/chunks/{config-BAse0laT.js → config-CvtqB4ki.js} +8 -3
- package/dist/chunks/config-CvtqB4ki.js.map +1 -0
- package/dist/chunks/{config-BcXX7S7B.js → config-D-JgqV0J.js} +5 -1
- package/dist/chunks/{config-BcXX7S7B.js.map → config-D-JgqV0J.js.map} +1 -1
- package/dist/chunks/{config-BHLMTJaR.js → config-D1oVht-E.js} +8 -3
- package/dist/chunks/config-D1oVht-E.js.map +1 -0
- package/dist/chunks/{config-BscVxZR3.js → config-DF1ezU6y.js} +1 -1
- package/dist/chunks/{config-BscVxZR3.js.map → config-DF1ezU6y.js.map} +1 -1
- package/dist/chunks/{config-B42iJ48O.js → config-DG41PD9i.js} +13 -1
- package/dist/chunks/config-DG41PD9i.js.map +1 -0
- package/dist/chunks/{config-Bs1HwUcx.js → config-DPJ3jtiB.js} +12 -2
- package/dist/chunks/config-DPJ3jtiB.js.map +1 -0
- package/dist/chunks/{config-tNqtapcT.js → config-DpqjlCfB.js} +2 -2
- package/dist/chunks/{config-tNqtapcT.js.map → config-DpqjlCfB.js.map} +1 -1
- package/dist/chunks/{config-DNDgp9bB.js → config-DpzFoSIh.js} +64 -2
- package/dist/chunks/config-DpzFoSIh.js.map +1 -0
- package/dist/chunks/config-MUkhktTP.js +267 -0
- package/dist/chunks/config-MUkhktTP.js.map +1 -0
- package/dist/chunks/config-SPugeaHT.js +37 -0
- package/dist/chunks/config-SPugeaHT.js.map +1 -0
- package/dist/chunks/{en-Bxyn5lW7.js → en-mIFywnV2.js} +27 -7
- package/dist/chunks/en-mIFywnV2.js.map +1 -0
- package/dist/chunks/{es-Dtl-a7ui.js → es-CvthYwtB.js} +27 -7
- package/dist/chunks/es-CvthYwtB.js.map +1 -0
- package/dist/chunks/{es-Bj_vc18Z.js → es-DlGd6Mrj.js} +3 -3
- package/dist/chunks/{es-Bj_vc18Z.js.map → es-DlGd6Mrj.js.map} +1 -1
- package/dist/chunks/{generated-hELWB0gZ.js → generated-Cx4C7GRN.js} +126 -0
- package/dist/chunks/{generated-hELWB0gZ.js.map → generated-Cx4C7GRN.js.map} +1 -1
- package/dist/chunks/{grBadgeStyles-DV0DrAew.js → grBadgeStyles-D51AXbj5.js} +57 -1
- package/dist/chunks/grBadgeStyles-D51AXbj5.js.map +1 -0
- package/dist/chunks/{grChipStyles-DcDyxAL0.js → grChipStyles-CA9Wj1_E.js} +1 -1
- package/dist/chunks/{grChipStyles-DcDyxAL0.js.map → grChipStyles-CA9Wj1_E.js.map} +1 -1
- package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js → grPopoverStyles-CncEkiPu.js} +1 -1
- package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js.map → grPopoverStyles-CncEkiPu.js.map} +1 -1
- package/dist/chunks/{grSelectStyles-D9EQ-pgK.js → grSelectStyles-Cam-IG9s.js} +3 -2
- package/dist/chunks/grSelectStyles-Cam-IG9s.js.map +1 -0
- package/dist/chunks/{grSliderStyles-kaz6VXZ3.js → grSliderStyles-CqzV0hll.js} +1 -1
- package/dist/chunks/grSliderStyles-CqzV0hll.js.map +1 -0
- package/dist/chunks/{config-CbEbLyDE.js → grSortableListStyles-CxieDmpe.js} +1 -27
- package/dist/chunks/grSortableListStyles-CxieDmpe.js.map +1 -0
- package/dist/chunks/grTableStyles-CPSxDTOW.js +66 -0
- package/dist/chunks/grTableStyles-CPSxDTOW.js.map +1 -0
- package/dist/chunks/{config-CMNfZO7S.js → grTabsStyles-DIz2VdIm.js} +1 -36
- package/dist/chunks/grTabsStyles-DIz2VdIm.js.map +1 -0
- package/dist/chunks/grTooltipStyles-CtbGEEGV.js +24 -0
- package/dist/chunks/grTooltipStyles-CtbGEEGV.js.map +1 -0
- package/dist/chunks/{granular-provider-BOQp7N5o.js → granular-provider-cv5vaM1a.js} +26 -22
- package/dist/chunks/granular-provider-cv5vaM1a.js.map +1 -0
- package/dist/chunks/hotkeySequence-BTHIM_5A.js +46 -0
- package/dist/chunks/hotkeySequence-BTHIM_5A.js.map +1 -0
- package/dist/chunks/{keyboard-DE2yhz_b.js → keyboard-BiFSgWLt.js} +70 -1
- package/dist/chunks/keyboard-BiFSgWLt.js.map +1 -0
- package/dist/chunks/optionPanel-DvY7Tv_4.js +182 -0
- package/dist/chunks/optionPanel-DvY7Tv_4.js.map +1 -0
- package/dist/chunks/overlayListPanel-D91jBCHU.js +21 -0
- package/dist/chunks/overlayListPanel-D91jBCHU.js.map +1 -0
- package/dist/chunks/{overlayStack-DH4Z7am1.js → overlayStack-DCkCgXZP.js} +1 -1
- package/dist/chunks/{overlayStack-DH4Z7am1.js.map → overlayStack-DCkCgXZP.js.map} +1 -1
- package/dist/chunks/{overlayPanelSurface-BKeMhRx4.js → overlayTransition-C0FDMx7Q.js} +24 -24
- package/dist/chunks/overlayTransition-C0FDMx7Q.js.map +1 -0
- package/dist/chunks/{ru-hrB4I1u_.js → ru-CQKDR-kD.js} +27 -7
- package/dist/chunks/ru-CQKDR-kD.js.map +1 -0
- package/dist/chunks/{safelist-x8USecK8.js → safelist-CSfynUC1.js} +5 -1
- package/dist/chunks/safelist-CSfynUC1.js.map +1 -0
- package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js → useMenuItemsFocus-C031blYS.js} +1 -1
- package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js.map → useMenuItemsFocus-C031blYS.js.map} +1 -1
- package/dist/chunks/{useModalOverlay-ACRkflzx.js → useModalOverlay-CKCQkGdB.js} +1 -1
- package/dist/chunks/{useModalOverlay-ACRkflzx.js.map → useModalOverlay-CKCQkGdB.js.map} +1 -1
- package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-C-uovdv8.js → GrAutocomplete-Cyr1-ENw.js} +183 -125
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-Cyr1-ENw.js.map +1 -0
- package/dist/components/GrAutocomplete/index.js +2 -2
- package/dist/components/GrAutocomplete/styles.css +1 -1
- package/dist/components/GrBadge/chunks/GrBadge-C42KLyUD.js +71 -0
- package/dist/components/GrBadge/chunks/GrBadge-C42KLyUD.js.map +1 -0
- package/dist/components/GrBadge/index.js +3 -3
- package/dist/components/GrBadge/styles.css +1 -1
- package/dist/components/GrCarousel/chunks/{GrCarousel-ByuughtI.js → GrCarousel-CBj-PEPB.js} +186 -37
- package/dist/components/GrCarousel/chunks/GrCarousel-CBj-PEPB.js.map +1 -0
- package/dist/components/GrCarousel/index.js +2 -2
- package/dist/components/GrCarousel/styles.css +1 -1
- package/dist/components/GrCheckbox/chunks/{GrCheckbox-Dp201frb.js → GrCheckbox-B4NJc7Ur.js} +2 -1
- package/dist/components/GrCheckbox/chunks/GrCheckbox-B4NJc7Ur.js.map +1 -0
- package/dist/components/GrCheckbox/index.js +1 -1
- package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js → GrCheckboxGroup-qZHpNFCX.js} +1 -1
- package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js.map → GrCheckboxGroup-qZHpNFCX.js.map} +1 -1
- package/dist/components/GrCheckboxGroup/index.js +1 -1
- package/dist/components/GrChip/chunks/{GrChip-CKqyzYcv.js → GrChip-DoyS1Dr4.js} +1 -1
- package/dist/components/GrChip/chunks/{GrChip-CKqyzYcv.js.map → GrChip-DoyS1Dr4.js.map} +1 -1
- package/dist/components/GrChip/index.js +2 -2
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BRM_4lyI.js → GrColorPicker-vGSgpUV9.js} +353 -38
- package/dist/components/GrColorPicker/chunks/GrColorPicker-vGSgpUV9.js.map +1 -0
- package/dist/components/GrColorPicker/index.js +2 -2
- package/dist/components/GrColorPicker/styles.css +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BJHmkDQv.js → GrCommandPalette-CAHgj0Aa.js} +23 -7
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-CAHgj0Aa.js.map +1 -0
- package/dist/components/GrCommandPalette/index.js +1 -1
- package/dist/components/GrCommandPalette/styles.css +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js → GrConfirmDialog-dg021BMd.js} +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js.map → GrConfirmDialog-dg021BMd.js.map} +1 -1
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js → GrContextMenu-bQ1Vvy2c.js} +3 -3
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js.map → GrContextMenu-bQ1Vvy2c.js.map} +1 -1
- package/dist/components/GrContextMenu/index.js +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-DQxYYgQk.js → GrDataTable-Bb2jWnRG.js} +576 -136
- package/dist/components/GrDataTable/chunks/GrDataTable-Bb2jWnRG.js.map +1 -0
- package/dist/components/GrDataTable/index.js +2 -2
- package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js → GrDelta-BSv1KdMy.js} +0 -0
- package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js.map → GrDelta-BSv1KdMy.js.map} +1 -1
- package/dist/components/GrDelta/index.js +2 -2
- package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js → GrDialog-C9Zu72jB.js} +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js.map → GrDialog-C9Zu72jB.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js → GrDialogService-DLBifO61.js} +2 -2
- package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js.map → GrDialogService-DLBifO61.js.map} +1 -1
- package/dist/components/GrDialogService/index.js +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js → GrDrawer-DOcRTE8G.js} +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js.map → GrDrawer-DOcRTE8G.js.map} +1 -1
- package/dist/components/GrDrawer/index.js +1 -1
- package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js → GrDropdown-kxwmgfSe.js} +2 -2
- package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js.map → GrDropdown-kxwmgfSe.js.map} +1 -1
- package/dist/components/GrDropdown/index.js +2 -2
- package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-Dxkz_ry4.js → GrDropdownMenu--VoK3VY0.js} +3 -34
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu--VoK3VY0.js.map +1 -0
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js +34 -0
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js.map +1 -0
- package/dist/components/GrDropdownMenu/index.js +2 -1
- package/dist/components/GrEmptyState/chunks/{GrEmptyState-BbvwE-E0.js → GrEmptyState-Bz6-_ED4.js} +42 -6
- package/dist/components/GrEmptyState/chunks/GrEmptyState-Bz6-_ED4.js.map +1 -0
- package/dist/components/GrEmptyState/index.js +1 -1
- package/dist/components/GrFileUpload/chunks/{GrFileUpload-BwMR71zN.js → GrFileUpload-Bgdfnkd8.js} +5 -2
- package/dist/components/GrFileUpload/chunks/GrFileUpload-Bgdfnkd8.js.map +1 -0
- package/dist/components/GrFileUpload/index.js +1 -1
- package/dist/components/GrFormFile/chunks/{GrFormFile-Dlxx-9zi.js → GrFormFile-Ctq1isz-.js} +78 -11
- package/dist/components/GrFormFile/chunks/GrFormFile-Ctq1isz-.js.map +1 -0
- package/dist/components/GrFormFile/index.js +2 -2
- package/dist/components/GrFormFile/styles.css +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js → GrImageViewer-Bnql_dNP.js} +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js.map → GrImageViewer-Bnql_dNP.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInput/chunks/{GrInput-DV4gMWPR.js → GrInput-CoaFLpaU.js} +43 -22
- package/dist/components/GrInput/chunks/GrInput-CoaFLpaU.js.map +1 -0
- package/dist/components/GrInput/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-CO0YU-ok.js → GrInputTag-BzzNRBe3.js} +247 -20
- package/dist/components/GrInputTag/chunks/GrInputTag-BzzNRBe3.js.map +1 -0
- package/dist/components/GrInputTag/index.js +2 -2
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js → GrJsonViewer-B6ZJ3GFH.js} +2 -2
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js.map → GrJsonViewer-B6ZJ3GFH.js.map} +1 -1
- package/dist/components/GrJsonViewer/index.js +1 -1
- package/dist/components/GrKbd/chunks/{GrKbd-BNMeoaLV.js → GrKbd-D2rHDkQv.js} +42 -37
- package/dist/components/GrKbd/chunks/GrKbd-D2rHDkQv.js.map +1 -0
- package/dist/components/GrKbd/index.js +1 -1
- package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js → GrModal-SHb1U2qx.js} +1 -1
- package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js.map → GrModal-SHb1U2qx.js.map} +1 -1
- package/dist/components/GrModal/index.js +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-BRGuksiy.js → GrNavbar-IEIHC5Vt.js} +10 -4
- package/dist/components/GrNavbar/chunks/GrNavbar-IEIHC5Vt.js.map +1 -0
- package/dist/components/GrNavbar/index.js +2 -2
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js → GrNumberInput-CmnUDaKi.js} +2 -22
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js.map → GrNumberInput-CmnUDaKi.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +1 -1
- package/dist/components/GrOtpInput/chunks/GrOtpInput-B_Q-RDLw.js +419 -0
- package/dist/components/GrOtpInput/chunks/GrOtpInput-B_Q-RDLw.js.map +1 -0
- package/dist/components/GrOtpInput/index.js +3 -0
- package/dist/components/GrOtpInput/styles.css +1 -0
- package/dist/components/GrPagination/chunks/{GrPagination-BbaF5eXk.js → GrPagination-AMbn5D8I.js} +1 -1
- package/dist/components/GrPagination/chunks/{GrPagination-BbaF5eXk.js.map → GrPagination-AMbn5D8I.js.map} +1 -1
- package/dist/components/GrPagination/index.js +1 -1
- package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js → GrPopover-DjVxt8bf.js} +3 -3
- package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js.map → GrPopover-DjVxt8bf.js.map} +1 -1
- package/dist/components/GrPopover/index.js +2 -2
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js → GrPromptDialog-BhbIZP1f.js} +3 -3
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js.map → GrPromptDialog-BhbIZP1f.js.map} +1 -1
- package/dist/components/GrPromptDialog/index.js +1 -1
- package/dist/components/GrSelect/chunks/{GrSelect-0iI4wdR_.js → GrSelect-B-ykrHpL.js} +26 -182
- package/dist/components/GrSelect/chunks/GrSelect-B-ykrHpL.js.map +1 -0
- package/dist/components/GrSelect/index.js +2 -2
- package/dist/components/GrSelect/styles.css +1 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js +543 -0
- package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js.map +1 -0
- package/dist/components/GrSidebar/index.js +2 -2
- package/dist/components/GrSlider/chunks/{GrSlider-CO8N9SF6.js → GrSlider-DF2Cq0rV.js} +29 -4
- package/dist/components/GrSlider/chunks/GrSlider-DF2Cq0rV.js.map +1 -0
- package/dist/components/GrSlider/index.js +2 -2
- package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js → GrSortableList-ChH9nQBv.js} +1 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js.map → GrSortableList-ChH9nQBv.js.map} +1 -1
- package/dist/components/GrSortableList/index.js +2 -2
- package/dist/components/GrSwitch/chunks/{GrSwitch-CriHWT2A.js → GrSwitch-D7X42uIA.js} +61 -7
- package/dist/components/GrSwitch/chunks/GrSwitch-D7X42uIA.js.map +1 -0
- package/dist/components/GrSwitch/index.js +2 -2
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js +30 -0
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js.map +1 -0
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js +83 -0
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js.map +1 -0
- package/dist/components/GrTabPanels/index.js +2 -1
- package/dist/components/GrTable/chunks/{GrTable-CKJ-HrsN.js → GrTable-BQitSDep.js} +52 -16
- package/dist/components/GrTable/chunks/GrTable-BQitSDep.js.map +1 -0
- package/dist/components/GrTable/index.js +2 -2
- package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js → GrTabs-DVC6nfWB.js} +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js.map → GrTabs-DVC6nfWB.js.map} +1 -1
- package/dist/components/GrTabs/index.js +2 -2
- package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js +98 -0
- package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js.map +1 -0
- package/dist/components/GrTabsWithPanels/index.js +3 -0
- package/dist/components/GrTextarea/chunks/{GrTextarea-Bfgc0DD2.js → GrTextarea-BFwyqcHB.js} +22 -5
- package/dist/components/GrTextarea/chunks/GrTextarea-BFwyqcHB.js.map +1 -0
- package/dist/components/GrTextarea/index.js +1 -1
- package/dist/components/GrToaster/chunks/{GrToaster-CZixNk0l.js → GrToaster-OzT1VKcp.js} +163 -32
- package/dist/components/GrToaster/chunks/GrToaster-OzT1VKcp.js.map +1 -0
- package/dist/components/GrToaster/index.js +2 -2
- package/dist/components/GrToaster/styles.css +1 -1
- package/dist/components/GrTooltip/chunks/{GrTooltip-DkMMM0uq.js → GrTooltip-BDcFycvW.js} +26 -13
- package/dist/components/GrTooltip/chunks/GrTooltip-BDcFycvW.js.map +1 -0
- package/dist/components/GrTooltip/index.js +2 -2
- package/dist/components/GrTransfer/chunks/{GrTransfer-DdfBUf35.js → GrTransfer-CV7BL5UK.js} +114 -12
- package/dist/components/GrTransfer/chunks/GrTransfer-CV7BL5UK.js.map +1 -0
- package/dist/components/GrTransfer/index.js +1 -1
- package/dist/components/GrTransfer/styles.css +1 -1
- package/dist/components/GrTree/chunks/{GrTree-6yZrncJE.js → GrTree-DpgaP8hk.js} +39 -1
- package/dist/components/GrTree/chunks/GrTree-DpgaP8hk.js.map +1 -0
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTree/styles.css +1 -1
- package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js → GrTreeSections-BeOj__44.js} +1 -1
- package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js.map → GrTreeSections-BeOj__44.js.map} +1 -1
- package/dist/components/GrTreeSections/index.js +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-B6KoDYiZ.js → GrTreeSelect-BHq-T8wH.js} +113 -14
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHq-T8wH.js.map +1 -0
- package/dist/components/GrTreeSelect/index.js +2 -2
- package/dist/composables/useFloating.js +1 -1
- package/dist/composables/useHotkeys.js +89 -0
- package/dist/composables/useHotkeys.js.map +1 -0
- package/dist/composables/useOverlayLayer.js +1 -1
- package/dist/directives/hotkey.js +19 -46
- package/dist/directives/hotkey.js.map +1 -1
- package/dist/granular-provider-node.js +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 +80 -71
- package/dist/theme.js +1 -1
- package/dist/tokens.js +1 -1
- package/dist/types/components/GrAutocomplete/GrAutocomplete.vue.d.ts +4 -4
- package/dist/types/components/GrAutocomplete/composables/useAutocompleteNavigation.d.ts +12 -3
- package/dist/types/components/GrAutocomplete/composables/useAutocompletePanel.d.ts +12 -2
- package/dist/types/components/GrAutocomplete/composables/useAutocompleteValues.d.ts +7 -4
- package/dist/types/components/GrAutocomplete/composables/useRemoteOptions.d.ts +4 -4
- package/dist/types/components/GrAutocomplete/grAutocompleteStyles.d.ts +15 -1
- package/dist/types/components/GrAutocomplete/index.d.ts +1 -1
- package/dist/types/components/GrBadge/GrBadge.vue.d.ts +15 -1
- package/dist/types/components/GrBadge/grBadgeStyles.d.ts +57 -0
- package/dist/types/components/GrBadge/index.d.ts +1 -1
- package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +29 -1
- package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +5 -0
- package/dist/types/components/GrCarousel/grCarouselContext.d.ts +21 -0
- package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +39 -9
- package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +13 -0
- package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +18 -2
- package/dist/types/components/GrColorPicker/color.d.ts +13 -1
- package/dist/types/components/GrColorPicker/colorArea.d.ts +59 -0
- package/dist/types/components/GrColorPicker/defaults.d.ts +3 -1
- package/dist/types/components/GrColorPicker/eyeDropper.d.ts +21 -0
- package/dist/types/components/GrColorPicker/grColorPickerStyles.d.ts +42 -0
- package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +10 -1
- package/dist/types/components/GrDataTable/GrDataTable.vue.d.ts +41 -1
- package/dist/types/components/GrDataTable/composables/useDataTableGridNavigation.d.ts +53 -0
- package/dist/types/components/GrDataTable/grDataTableStyles.d.ts +8 -0
- package/dist/types/components/GrDataTable/index.d.ts +1 -1
- package/dist/types/components/GrDelta/grDeltaStyles.d.ts +10 -3
- package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +11 -2
- package/dist/types/components/GrEmptyState/grEmptyStateStyles.d.ts +10 -0
- package/dist/types/components/GrEmptyState/index.d.ts +1 -1
- package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +2 -1
- package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +10 -0
- package/dist/types/components/GrInput/GrInput.vue.d.ts +15 -0
- package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +16 -0
- package/dist/types/components/GrInputTag/grInputTagStyles.d.ts +11 -0
- package/dist/types/components/GrKbd/GrKbd.vue.d.ts +14 -0
- package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +18 -0
- package/dist/types/components/GrNavbar/grNavbarStyles.d.ts +10 -1
- package/dist/types/components/GrNavbar/index.d.ts +1 -0
- package/dist/types/components/GrOtpInput/GrOtpInput.vue.d.ts +164 -0
- package/dist/types/components/GrOtpInput/config.d.ts +1 -0
- package/dist/types/components/GrOtpInput/defaults.d.ts +15 -0
- package/dist/types/components/GrOtpInput/grOtpInputStyles.d.ts +62 -0
- package/dist/types/components/GrOtpInput/index.d.ts +9 -0
- package/dist/types/components/GrOtpInput/otpValue.d.ts +71 -0
- package/dist/types/components/GrOtpInput/safelist.d.ts +7 -0
- package/dist/types/components/GrSelect/composables/useSelectPanelItems.d.ts +8 -34
- package/dist/types/components/GrSelect/composables/useSelectVirtualization.d.ts +7 -0
- package/dist/types/components/GrSelect/grSelectStyles.d.ts +1 -1
- package/dist/types/components/GrSidebar/GrSidebar.vue.d.ts +20 -0
- package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +39 -5
- package/dist/types/components/GrSidebar/grSidebarStyles.d.ts +32 -0
- package/dist/types/components/GrSidebar/index.d.ts +1 -1
- package/dist/types/components/GrSidebar/sidebarContext.d.ts +23 -1
- package/dist/types/components/GrSlider/GrSlider.vue.d.ts +39 -1
- package/dist/types/components/GrSlider/grSliderStyles.d.ts +1 -1
- package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +42 -4
- package/dist/types/components/GrSwitch/defaults.d.ts +2 -0
- package/dist/types/components/GrSwitch/grSwitchStyles.d.ts +129 -25
- package/dist/types/components/GrSwitch/index.d.ts +1 -1
- package/dist/types/components/GrSwitch/safelist.d.ts +4 -3
- package/dist/types/components/GrTabPanels/context.d.ts +6 -0
- package/dist/types/components/GrTable/GrTable.vue.d.ts +37 -0
- package/dist/types/components/GrTable/grTableStyles.d.ts +16 -7
- package/dist/types/components/GrTabsWithPanels/GrTabsWithPanels.vue.d.ts +77 -0
- package/dist/types/components/GrTabsWithPanels/config.d.ts +1 -0
- package/dist/types/components/GrTabsWithPanels/index.d.ts +4 -0
- package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +19 -1
- package/dist/types/components/GrToaster/GrToaster.vue.d.ts +12 -0
- package/dist/types/components/GrToaster/grToasterStyles.d.ts +26 -0
- package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +22 -0
- package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +23 -0
- package/dist/types/components/GrTreeSelect/grTreeSelectStyles.d.ts +1 -1
- package/dist/types/components/GrTreeSelect/grTreeSelectTypes.d.ts +20 -0
- package/dist/types/components/shared/hotkey.d.ts +8 -9
- package/dist/types/components/shared/optionPanel.d.ts +100 -0
- package/dist/types/components/shared/overlayListPanel.d.ts +18 -0
- package/dist/types/composables/useHotkeys.d.ts +43 -0
- package/dist/types/granular-provider/shared.d.ts +2 -0
- package/dist/types/i18n/messages/en.d.ts +32 -0
- package/dist/types/i18n/messages/es.d.ts +32 -0
- package/dist/types/i18n/messages/ru.d.ts +32 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/internal/hotkeySequence.d.ts +22 -0
- package/dist/types/internal/keyboard.d.ts +45 -0
- package/dist/web-types.json +784 -101
- package/package.json +13 -1
- package/dist/chunks/config-2ZHRsdOc.js.map +0 -1
- package/dist/chunks/config-B42iJ48O.js.map +0 -1
- package/dist/chunks/config-B5SBUa6u.js.map +0 -1
- package/dist/chunks/config-BAse0laT.js.map +0 -1
- package/dist/chunks/config-BHLMTJaR.js.map +0 -1
- package/dist/chunks/config-BXRmsn3t.js.map +0 -1
- package/dist/chunks/config-Bs1HwUcx.js.map +0 -1
- package/dist/chunks/config-CMNfZO7S.js.map +0 -1
- package/dist/chunks/config-CbEbLyDE.js.map +0 -1
- package/dist/chunks/config-CjWOTgLL.js.map +0 -1
- package/dist/chunks/config-D3HOuHDe.js.map +0 -1
- package/dist/chunks/config-DIDz_E5m.js.map +0 -1
- package/dist/chunks/config-DNDgp9bB.js.map +0 -1
- package/dist/chunks/config-Yy67uWHY.js +0 -140
- package/dist/chunks/config-Yy67uWHY.js.map +0 -1
- package/dist/chunks/config-iemgzS4x.js.map +0 -1
- package/dist/chunks/en-Bxyn5lW7.js.map +0 -1
- package/dist/chunks/es-Dtl-a7ui.js.map +0 -1
- package/dist/chunks/grBadgeStyles-DV0DrAew.js.map +0 -1
- package/dist/chunks/grSelectStyles-D9EQ-pgK.js.map +0 -1
- package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +0 -1
- package/dist/chunks/grTableStyles-DkQPMfx9.js +0 -39
- package/dist/chunks/grTableStyles-DkQPMfx9.js.map +0 -1
- package/dist/chunks/granular-provider-BOQp7N5o.js.map +0 -1
- package/dist/chunks/keyboard-DE2yhz_b.js.map +0 -1
- package/dist/chunks/overlayPanelSurface-BKeMhRx4.js.map +0 -1
- package/dist/chunks/ru-hrB4I1u_.js.map +0 -1
- package/dist/chunks/safelist-x8USecK8.js.map +0 -1
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-C-uovdv8.js.map +0 -1
- package/dist/components/GrBadge/chunks/GrBadge-DBeQXEir.js +0 -47
- package/dist/components/GrBadge/chunks/GrBadge-DBeQXEir.js.map +0 -1
- package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +0 -1
- package/dist/components/GrCheckbox/chunks/GrCheckbox-Dp201frb.js.map +0 -1
- package/dist/components/GrColorPicker/chunks/GrColorPicker-BRM_4lyI.js.map +0 -1
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BJHmkDQv.js.map +0 -1
- package/dist/components/GrDataTable/chunks/GrDataTable-DQxYYgQk.js.map +0 -1
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-Dxkz_ry4.js.map +0 -1
- package/dist/components/GrEmptyState/chunks/GrEmptyState-BbvwE-E0.js.map +0 -1
- package/dist/components/GrFileUpload/chunks/GrFileUpload-BwMR71zN.js.map +0 -1
- package/dist/components/GrFormFile/chunks/GrFormFile-Dlxx-9zi.js.map +0 -1
- package/dist/components/GrInput/chunks/GrInput-DV4gMWPR.js.map +0 -1
- package/dist/components/GrInputTag/chunks/GrInputTag-CO0YU-ok.js.map +0 -1
- package/dist/components/GrKbd/chunks/GrKbd-BNMeoaLV.js.map +0 -1
- package/dist/components/GrNavbar/chunks/GrNavbar-BRGuksiy.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-0iI4wdR_.js.map +0 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js +0 -264
- package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js.map +0 -1
- package/dist/components/GrSlider/chunks/GrSlider-CO8N9SF6.js.map +0 -1
- package/dist/components/GrSwitch/chunks/GrSwitch-CriHWT2A.js.map +0 -1
- package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js +0 -92
- package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js.map +0 -1
- package/dist/components/GrTable/chunks/GrTable-CKJ-HrsN.js.map +0 -1
- package/dist/components/GrTextarea/chunks/GrTextarea-Bfgc0DD2.js.map +0 -1
- package/dist/components/GrToaster/chunks/GrToaster-CZixNk0l.js.map +0 -1
- package/dist/components/GrTooltip/chunks/GrTooltip-DkMMM0uq.js.map +0 -1
- package/dist/components/GrTransfer/chunks/GrTransfer-DdfBUf35.js.map +0 -1
- package/dist/components/GrTree/chunks/GrTree-6yZrncJE.js.map +0 -1
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-B6KoDYiZ.js.map +0 -1
- package/dist/types/components/GrAutocomplete/composables/useAutocompleteVirtual.d.ts +0 -33
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlayStack-DH4Z7am1.js","names":[],"sources":["../../src/composables/internal/overlayStack.ts"],"sourcesContent":["/**\n * Единый стек слоёв оверлеев: модалки, drawer'ы, просмотрщик, панели селектов,\n * дропдауны, подсказки — всё, что открывается поверх страницы.\n *\n * Список один, и порядок регистрации совпадает с порядком открытия, но из него\n * выводятся **две разные вершины**:\n *\n * - **Esc** → последний слой любого рода. Дропдаун, открытый внутри модалки,\n * обязан закрыться первым — пользователь видит верхним именно его.\n * - **`inert`** → ставится на модальные слои ниже последнего **модального**.\n * Немодальный слой сверху модалку не понижает: иначе окно ушло бы в `inert`\n * вместе со своим же открытым дропдауном и перестало отвечать.\n * - **высота** → `openModalCount()` поднимает floating-панель над окном, из\n * которого её открыли: телепортированная панель лежит рядом с корнем окна,\n * и статический `z-index` дропдауна оставлял её под ним.\n *\n * Вести эти две вершины в двух независимых реестрах нельзя: реестры описывают\n * один и тот же порядок и расходятся молча — достаточно оверлея, который\n * зарегистрировался в одном и забыл про другой.\n *\n * Ловушку фокуса стек не реализует сам, но питает её (`useFocusTrap`): он\n * видит слои из **разных деревьев рендера** (диалоги `useDialogService`\n * монтируются отдельным `render()` в `body`) и знает их корни.\n */\n\nimport type { GrLayerFocus, GrOverlaySnapshot } from '../../internal/devHook'\nimport { emitGrDevEvent, provideGrDevLayers } from '../../internal/devHook'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nexport interface OverlayLayer {\n /** Уникальный id зарегистрированного слоя. */\n id: number\n /**\n * Модальный слой: блокирует страницу и участвует в вычислении `inert`.\n * Немодальные (поповеры, меню, подсказки) — только в очереди Esc.\n */\n modal: boolean\n /** Закрывать ли слой по Esc (реактивный геттер: `closeOnEsc` и подобные). */\n shouldClose: () => boolean\n /** Закрыть слой. */\n close: () => void\n /** Уведомление «этот модальный слой сейчас верхний». Только для `modal`. */\n setTopmost?: (isTopmost: boolean) => void\n /**\n * Позиция слоя среди модальных, от нуля. Только для `modal`.\n *\n * От неё считается высота: у всех модальных слоёв один токен\n * (`--gr-z-modal`), и без этой прибавки порядок отрисовки решал бы порядок\n * узлов в портале, а он задаётся **созданием** телепорта, а не открытием\n * слоя. Диалог, объявленный в шаблоне статически, вставал бы под окном,\n * открытым позже, — и получал бы `inert` от стека, оставаясь видимым.\n */\n setDepth?: (depth: number) => void\n /**\n * Корень слоя. Ловушка фокуса нижнего слоя обязана считать его своим:\n * панель селекта, открытого внутри модалки, телепортирована в `body` и лежит\n * вне DOM-поддерева окна, но для пользователя это тот же слой.\n */\n root?: () => HTMLElement | null\n /**\n * Компонент, открывший слой. Только для наблюдателя: стеку он не нужен, но\n * без него слой в панели — безымянный номер.\n */\n owner?: string | null\n /**\n * Картина фокуса глазами самого слоя. Геттер, а не значение: она меняется от\n * каждого клика, а спрашивают её только в момент снимка.\n */\n describeFocus?: () => GrLayerFocus | null\n}\n\nconst stack: OverlayLayer[] = []\nlet listening = false\nlet nextId = 1\n\n/**\n * Пересчитывает состояние модальных слоёв: кто верхний и на какой высоте.\n *\n * Обе величины выводятся из одного порядка, поэтому и считаются в одном месте:\n * разъедься они — «верхний» для `inert` и «верхний» для отрисовки перестали бы\n * совпадать, а это ровно тот дефект, из-за которого высота и заведена.\n */\nfunction syncModalLayers(): void {\n const modals = stack.filter(layer => layer.modal)\n const top = modals[modals.length - 1]\n\n modals.forEach((layer, index) => {\n layer.setTopmost?.(layer === top)\n layer.setDepth?.(index)\n })\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:sync', layers: snapshotLayers() })\n}\n\n/**\n * Снимок стека для dev-канала.\n *\n * Считается здесь же, где `syncModalLayers` раздаёт то же самое слоям, и по тем\n * же выражениям: разъедься они — наблюдатель показывал бы картину, которой в\n * пакете нет, и отладка по ней уводила бы в сторону.\n */\nfunction snapshotLayers(): GrOverlaySnapshot[] {\n const modals = stack.filter(layer => layer.modal)\n const topModal = modals[modals.length - 1]\n const top = stack[stack.length - 1]\n\n return stack.map(layer => ({\n id: layer.id,\n owner: layer.owner ?? null,\n focus: layer.describeFocus?.() ?? null,\n modal: layer.modal,\n topmostForEscape: layer === top,\n inert: layer.modal && layer !== topModal,\n depth: layer.modal ? modals.indexOf(layer) : null,\n closesOnEscape: layer.shouldClose(),\n }))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Escape')\n return\n // Esc во время IME-композиции отменяет её, а не закрывает слой.\n if (isComposingEvent(event))\n return\n if (stack.length === 0)\n return\n\n const top = stack[stack.length - 1]\n\n // Гасим всегда, даже если верхний слой не закрывается по Esc: иначе нажатие\n // «провалится» на слой ниже и закроет не то, что видит пользователь.\n event.preventDefault()\n event.stopPropagation()\n if (typeof event.stopImmediatePropagation === 'function')\n event.stopImmediatePropagation()\n\n const closes = top.shouldClose()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:escape', id: top.id, closed: closes })\n\n if (closes)\n top.close()\n}\n\nfunction startListening(): void {\n if (listening)\n return\n if (typeof window === 'undefined')\n return\n // Capture-фаза опережает любые локальные обработчики: Esc обязан достаться\n // верхнему слою, а не тому, кто первым подписался.\n window.addEventListener('keydown', handleKeydown, true)\n listening = true\n}\n\nfunction stopListening(): void {\n if (!listening)\n return\n if (typeof window === 'undefined')\n return\n window.removeEventListener('keydown', handleKeydown, true)\n listening = false\n}\n\n/** Регистрирует слой как верхний и возвращает его id. */\nexport function pushOverlayLayer(layer: Omit<OverlayLayer, 'id'>): number {\n const id = nextId++\n stack.push({ ...layer, id })\n startListening()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:push', id, modal: layer.modal, owner: layer.owner ?? null })\n\n syncModalLayers()\n return id\n}\n\n/** Снимает слой со стека (при закрытии или размонтировании). */\nexport function removeOverlayLayer(id: number): void {\n const index = stack.findIndex(item => item.id === id)\n if (index >= 0)\n stack.splice(index, 1)\n if (stack.length === 0)\n stopListening()\n\n if (__GR_DEV__ && index >= 0)\n emitGrDevEvent({ type: 'overlay:remove', id })\n\n syncModalLayers()\n}\n\n/**\n * Корни слоёв, открытых **поверх** данного.\n *\n * Ими ловушка фокуса дополняет свой контейнер: всё, что открыто изнутри слоя\n * (панель селекта, меню, подсказка), лежит в `body` отдельным поддеревом, и\n * без этого списка ловушка утаскивала бы из него фокус обратно в окно.\n */\nexport function layerRootsAbove(id: number): HTMLElement[] {\n const index = stack.findIndex(layer => layer.id === id)\n if (index < 0)\n return []\n\n return stack\n .slice(index + 1)\n .map(layer => layer.root?.() ?? null)\n .filter((root): root is HTMLElement => root !== null)\n}\n\n/** Корни всех зарегистрированных слоёв. */\nexport function allLayerRoots(): HTMLElement[] {\n return stack\n .map(layer => layer.root?.() ?? null)\n .filter((root): root is HTMLElement => root !== null)\n}\n\n/** Сколько слоёв открыто. Для тестов и диагностики. */\nexport function overlayStackSize(): number {\n return stack.length\n}\n\n/**\n * Сколько **модальных** слоёв открыто прямо сейчас.\n *\n * Читает `useFloating`, когда считает высоту панели: панель телепортирована в\n * общий портал и лежит рядом с корнем окна, а не внутри него, поэтому свой\n * стек-контекст её не спасает — высоту приходится брать из порядка слоёв.\n */\nexport function openModalCount(): number {\n return stack.reduce((count, layer) => count + (layer.modal ? 1 : 0), 0)\n}\n\n/**\n * Высота слоя, лежащего внутри открытого окна.\n *\n * Панель телепортирована в общий портал и становится **соседом** корня окна, а\n * не его потомком: собственный stacking-контекст окна её не накрывает, и\n * статический `--gr-z-dropdown` (1000) оставлял её под окном (1100). Слагаемое —\n * число модальных слоёв, поэтому панель встаёт над самым верхним из них, а\n * полноэкранная загрузка (1150) и тосты (1200) остаются сверху.\n *\n * Обратный случай — «поповер снаружи не должен перекрывать окно» — не страдает:\n * пока окно открыто, страница под ним в `inert`, и открыть там поповер нечем.\n */\nexport function floatingLayerZIndex(zIndexVar: string): string {\n const modals = openModalCount()\n\n return modals > 0 ? `calc(var(--gr-z-modal) + ${modals})` : `var(${zIndexVar})`\n}\n\n/**\n * Высота самого модального слоя: базовый токен плюс его позиция в стеке.\n *\n * Нулевая глубина оставляет чистый `var(...)` — у единственного окна на экране\n * в стилях не появляется лишней арифметики.\n */\nexport function modalLayerZIndex(depth: number, zIndexVar = '--gr-z-modal'): string {\n return depth > 0 ? `calc(var(${zIndexVar}) + ${depth})` : `var(${zIndexVar})`\n}\n\n// Читалка регистрируется на загрузке модуля: наблюдатель может подключиться\n// раньше первого открытого слоя, и тогда спросить ему было бы нечего.\nif (__GR_DEV__)\n provideGrDevLayers(snapshotLayers)\n\n/** Тестовая/служебная очистка стека. */\nexport function resetOverlayStack(): void {\n stack.splice(0, stack.length)\n stopListening()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:sync', layers: [] })\n}\n"],"mappings":";;;AAuEA,IAAM,QAAwB,CAAC;AAC/B,IAAI,YAAY;AAChB,IAAI,SAAS;;;;;;;;AASb,SAAS,kBAAwB;CAC/B,MAAM,SAAS,MAAM,QAAO,UAAS,MAAM,KAAK;CAChD,MAAM,MAAM,OAAO,OAAO,SAAS;CAEnC,OAAO,SAAS,OAAO,UAAU;EAC/B,MAAM,aAAa,UAAU,GAAG;EAChC,MAAM,WAAW,KAAK;CACxB,CAAC;CAED,IAAA,QAAA,IAAA,aAAA,cACE,eAAe;EAAE,MAAM;EAAgB,QAAQ,eAAe;CAAE,CAAC;AACrE;;;;;;;;AASA,SAAS,iBAAsC;CAC7C,MAAM,SAAS,MAAM,QAAO,UAAS,MAAM,KAAK;CAChD,MAAM,WAAW,OAAO,OAAO,SAAS;CACxC,MAAM,MAAM,MAAM,MAAM,SAAS;CAEjC,OAAO,MAAM,KAAI,WAAU;EACzB,IAAI,MAAM;EACV,OAAO,MAAM,SAAS;EACtB,OAAO,MAAM,gBAAgB,KAAK;EAClC,OAAO,MAAM;EACb,kBAAkB,UAAU;EAC5B,OAAO,MAAM,SAAS,UAAU;EAChC,OAAO,MAAM,QAAQ,OAAO,QAAQ,KAAK,IAAI;EAC7C,gBAAgB,MAAM,YAAY;CACpC,EAAE;AACJ;AAEA,SAAS,cAAc,OAA4B;CACjD,IAAI,MAAM,QAAQ,UAChB;CAEF,IAAI,iBAAiB,KAAK,GACxB;CACF,IAAI,MAAM,WAAW,GACnB;CAEF,MAAM,MAAM,MAAM,MAAM,SAAS;CAIjC,MAAM,eAAe;CACrB,MAAM,gBAAgB;CACtB,IAAI,OAAO,MAAM,6BAA6B,YAC5C,MAAM,yBAAyB;CAEjC,MAAM,SAAS,IAAI,YAAY;CAE/B,IAAA,QAAA,IAAA,aAAA,cACE,eAAe;EAAE,MAAM;EAAkB,IAAI,IAAI;EAAI,QAAQ;CAAO,CAAC;CAEvE,IAAI,QACF,IAAI,MAAM;AACd;AAEA,SAAS,iBAAuB;CAC9B,IAAI,WACF;CACF,IAAI,OAAO,WAAW,aACpB;CAGF,OAAO,iBAAiB,WAAW,eAAe,IAAI;CACtD,YAAY;AACd;AAEA,SAAS,gBAAsB;CAC7B,IAAI,CAAC,WACH;CACF,IAAI,OAAO,WAAW,aACpB;CACF,OAAO,oBAAoB,WAAW,eAAe,IAAI;CACzD,YAAY;AACd;;AAGA,SAAgB,iBAAiB,OAAyC;CACxE,MAAM,KAAK;CACX,MAAM,KAAK;EAAE,GAAG;EAAO;CAAG,CAAC;CAC3B,eAAe;CAEf,IAAA,QAAA,IAAA,aAAA,cACE,eAAe;EAAE,MAAM;EAAgB;EAAI,OAAO,MAAM;EAAO,OAAO,MAAM,SAAS;CAAK,CAAC;CAE7F,gBAAgB;CAChB,OAAO;AACT;;AAGA,SAAgB,mBAAmB,IAAkB;CACnD,MAAM,QAAQ,MAAM,WAAU,SAAQ,KAAK,OAAO,EAAE;CACpD,IAAI,SAAS,GACX,MAAM,OAAO,OAAO,CAAC;CACvB,IAAI,MAAM,WAAW,GACnB,cAAc;CAEhB,IAAA,QAAA,IAAA,aAAA,gBAAkB,SAAS,GACzB,eAAe;EAAE,MAAM;EAAkB;CAAG,CAAC;CAE/C,gBAAgB;AAClB;;;;;;;;AASA,SAAgB,gBAAgB,IAA2B;CACzD,MAAM,QAAQ,MAAM,WAAU,UAAS,MAAM,OAAO,EAAE;CACtD,IAAI,QAAQ,GACV,OAAO,CAAC;CAEV,OAAO,MACJ,MAAM,QAAQ,CAAC,CAAC,CAChB,KAAI,UAAS,MAAM,OAAO,KAAK,IAAI,CAAC,CACpC,QAAQ,SAA8B,SAAS,IAAI;AACxD;;;;;;;;AAqBA,SAAgB,iBAAyB;CACvC,OAAO,MAAM,QAAQ,OAAO,UAAU,SAAS,MAAM,QAAQ,IAAI,IAAI,CAAC;AACxE;;;;;;;;;;;;;AAcA,SAAgB,oBAAoB,WAA2B;CAC7D,MAAM,SAAS,eAAe;CAE9B,OAAO,SAAS,IAAI,4BAA4B,OAAO,KAAK,OAAO,UAAU;AAC/E;;;;;;;AAQA,SAAgB,iBAAiB,OAAe,YAAY,gBAAwB;CAClF,OAAO,QAAQ,IAAI,YAAY,UAAU,MAAM,MAAM,KAAK,OAAO,UAAU;AAC7E;AAIA,IAAA,QAAA,IAAA,aAAA,cACE,mBAAmB,cAAc"}
|
|
1
|
+
{"version":3,"file":"overlayStack-DCkCgXZP.js","names":[],"sources":["../../src/composables/internal/overlayStack.ts"],"sourcesContent":["/**\n * Единый стек слоёв оверлеев: модалки, drawer'ы, просмотрщик, панели селектов,\n * дропдауны, подсказки — всё, что открывается поверх страницы.\n *\n * Список один, и порядок регистрации совпадает с порядком открытия, но из него\n * выводятся **две разные вершины**:\n *\n * - **Esc** → последний слой любого рода. Дропдаун, открытый внутри модалки,\n * обязан закрыться первым — пользователь видит верхним именно его.\n * - **`inert`** → ставится на модальные слои ниже последнего **модального**.\n * Немодальный слой сверху модалку не понижает: иначе окно ушло бы в `inert`\n * вместе со своим же открытым дропдауном и перестало отвечать.\n * - **высота** → `openModalCount()` поднимает floating-панель над окном, из\n * которого её открыли: телепортированная панель лежит рядом с корнем окна,\n * и статический `z-index` дропдауна оставлял её под ним.\n *\n * Вести эти две вершины в двух независимых реестрах нельзя: реестры описывают\n * один и тот же порядок и расходятся молча — достаточно оверлея, который\n * зарегистрировался в одном и забыл про другой.\n *\n * Ловушку фокуса стек не реализует сам, но питает её (`useFocusTrap`): он\n * видит слои из **разных деревьев рендера** (диалоги `useDialogService`\n * монтируются отдельным `render()` в `body`) и знает их корни.\n */\n\nimport type { GrLayerFocus, GrOverlaySnapshot } from '../../internal/devHook'\nimport { emitGrDevEvent, provideGrDevLayers } from '../../internal/devHook'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nexport interface OverlayLayer {\n /** Уникальный id зарегистрированного слоя. */\n id: number\n /**\n * Модальный слой: блокирует страницу и участвует в вычислении `inert`.\n * Немодальные (поповеры, меню, подсказки) — только в очереди Esc.\n */\n modal: boolean\n /** Закрывать ли слой по Esc (реактивный геттер: `closeOnEsc` и подобные). */\n shouldClose: () => boolean\n /** Закрыть слой. */\n close: () => void\n /** Уведомление «этот модальный слой сейчас верхний». Только для `modal`. */\n setTopmost?: (isTopmost: boolean) => void\n /**\n * Позиция слоя среди модальных, от нуля. Только для `modal`.\n *\n * От неё считается высота: у всех модальных слоёв один токен\n * (`--gr-z-modal`), и без этой прибавки порядок отрисовки решал бы порядок\n * узлов в портале, а он задаётся **созданием** телепорта, а не открытием\n * слоя. Диалог, объявленный в шаблоне статически, вставал бы под окном,\n * открытым позже, — и получал бы `inert` от стека, оставаясь видимым.\n */\n setDepth?: (depth: number) => void\n /**\n * Корень слоя. Ловушка фокуса нижнего слоя обязана считать его своим:\n * панель селекта, открытого внутри модалки, телепортирована в `body` и лежит\n * вне DOM-поддерева окна, но для пользователя это тот же слой.\n */\n root?: () => HTMLElement | null\n /**\n * Компонент, открывший слой. Только для наблюдателя: стеку он не нужен, но\n * без него слой в панели — безымянный номер.\n */\n owner?: string | null\n /**\n * Картина фокуса глазами самого слоя. Геттер, а не значение: она меняется от\n * каждого клика, а спрашивают её только в момент снимка.\n */\n describeFocus?: () => GrLayerFocus | null\n}\n\nconst stack: OverlayLayer[] = []\nlet listening = false\nlet nextId = 1\n\n/**\n * Пересчитывает состояние модальных слоёв: кто верхний и на какой высоте.\n *\n * Обе величины выводятся из одного порядка, поэтому и считаются в одном месте:\n * разъедься они — «верхний» для `inert` и «верхний» для отрисовки перестали бы\n * совпадать, а это ровно тот дефект, из-за которого высота и заведена.\n */\nfunction syncModalLayers(): void {\n const modals = stack.filter(layer => layer.modal)\n const top = modals[modals.length - 1]\n\n modals.forEach((layer, index) => {\n layer.setTopmost?.(layer === top)\n layer.setDepth?.(index)\n })\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:sync', layers: snapshotLayers() })\n}\n\n/**\n * Снимок стека для dev-канала.\n *\n * Считается здесь же, где `syncModalLayers` раздаёт то же самое слоям, и по тем\n * же выражениям: разъедься они — наблюдатель показывал бы картину, которой в\n * пакете нет, и отладка по ней уводила бы в сторону.\n */\nfunction snapshotLayers(): GrOverlaySnapshot[] {\n const modals = stack.filter(layer => layer.modal)\n const topModal = modals[modals.length - 1]\n const top = stack[stack.length - 1]\n\n return stack.map(layer => ({\n id: layer.id,\n owner: layer.owner ?? null,\n focus: layer.describeFocus?.() ?? null,\n modal: layer.modal,\n topmostForEscape: layer === top,\n inert: layer.modal && layer !== topModal,\n depth: layer.modal ? modals.indexOf(layer) : null,\n closesOnEscape: layer.shouldClose(),\n }))\n}\n\nfunction handleKeydown(event: KeyboardEvent): void {\n if (event.key !== 'Escape')\n return\n // Esc во время IME-композиции отменяет её, а не закрывает слой.\n if (isComposingEvent(event))\n return\n if (stack.length === 0)\n return\n\n const top = stack[stack.length - 1]\n\n // Гасим всегда, даже если верхний слой не закрывается по Esc: иначе нажатие\n // «провалится» на слой ниже и закроет не то, что видит пользователь.\n event.preventDefault()\n event.stopPropagation()\n if (typeof event.stopImmediatePropagation === 'function')\n event.stopImmediatePropagation()\n\n const closes = top.shouldClose()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:escape', id: top.id, closed: closes })\n\n if (closes)\n top.close()\n}\n\nfunction startListening(): void {\n if (listening)\n return\n if (typeof window === 'undefined')\n return\n // Capture-фаза опережает любые локальные обработчики: Esc обязан достаться\n // верхнему слою, а не тому, кто первым подписался.\n window.addEventListener('keydown', handleKeydown, true)\n listening = true\n}\n\nfunction stopListening(): void {\n if (!listening)\n return\n if (typeof window === 'undefined')\n return\n window.removeEventListener('keydown', handleKeydown, true)\n listening = false\n}\n\n/** Регистрирует слой как верхний и возвращает его id. */\nexport function pushOverlayLayer(layer: Omit<OverlayLayer, 'id'>): number {\n const id = nextId++\n stack.push({ ...layer, id })\n startListening()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:push', id, modal: layer.modal, owner: layer.owner ?? null })\n\n syncModalLayers()\n return id\n}\n\n/** Снимает слой со стека (при закрытии или размонтировании). */\nexport function removeOverlayLayer(id: number): void {\n const index = stack.findIndex(item => item.id === id)\n if (index >= 0)\n stack.splice(index, 1)\n if (stack.length === 0)\n stopListening()\n\n if (__GR_DEV__ && index >= 0)\n emitGrDevEvent({ type: 'overlay:remove', id })\n\n syncModalLayers()\n}\n\n/**\n * Корни слоёв, открытых **поверх** данного.\n *\n * Ими ловушка фокуса дополняет свой контейнер: всё, что открыто изнутри слоя\n * (панель селекта, меню, подсказка), лежит в `body` отдельным поддеревом, и\n * без этого списка ловушка утаскивала бы из него фокус обратно в окно.\n */\nexport function layerRootsAbove(id: number): HTMLElement[] {\n const index = stack.findIndex(layer => layer.id === id)\n if (index < 0)\n return []\n\n return stack\n .slice(index + 1)\n .map(layer => layer.root?.() ?? null)\n .filter((root): root is HTMLElement => root !== null)\n}\n\n/** Корни всех зарегистрированных слоёв. */\nexport function allLayerRoots(): HTMLElement[] {\n return stack\n .map(layer => layer.root?.() ?? null)\n .filter((root): root is HTMLElement => root !== null)\n}\n\n/** Сколько слоёв открыто. Для тестов и диагностики. */\nexport function overlayStackSize(): number {\n return stack.length\n}\n\n/**\n * Сколько **модальных** слоёв открыто прямо сейчас.\n *\n * Читает `useFloating`, когда считает высоту панели: панель телепортирована в\n * общий портал и лежит рядом с корнем окна, а не внутри него, поэтому свой\n * стек-контекст её не спасает — высоту приходится брать из порядка слоёв.\n */\nexport function openModalCount(): number {\n return stack.reduce((count, layer) => count + (layer.modal ? 1 : 0), 0)\n}\n\n/**\n * Высота слоя, лежащего внутри открытого окна.\n *\n * Панель телепортирована в общий портал и становится **соседом** корня окна, а\n * не его потомком: собственный stacking-контекст окна её не накрывает, и\n * статический `--gr-z-dropdown` (1000) оставлял её под окном (1100). Слагаемое —\n * число модальных слоёв, поэтому панель встаёт над самым верхним из них, а\n * полноэкранная загрузка (1150) и тосты (1200) остаются сверху.\n *\n * Обратный случай — «поповер снаружи не должен перекрывать окно» — не страдает:\n * пока окно открыто, страница под ним в `inert`, и открыть там поповер нечем.\n */\nexport function floatingLayerZIndex(zIndexVar: string): string {\n const modals = openModalCount()\n\n return modals > 0 ? `calc(var(--gr-z-modal) + ${modals})` : `var(${zIndexVar})`\n}\n\n/**\n * Высота самого модального слоя: базовый токен плюс его позиция в стеке.\n *\n * Нулевая глубина оставляет чистый `var(...)` — у единственного окна на экране\n * в стилях не появляется лишней арифметики.\n */\nexport function modalLayerZIndex(depth: number, zIndexVar = '--gr-z-modal'): string {\n return depth > 0 ? `calc(var(${zIndexVar}) + ${depth})` : `var(${zIndexVar})`\n}\n\n// Читалка регистрируется на загрузке модуля: наблюдатель может подключиться\n// раньше первого открытого слоя, и тогда спросить ему было бы нечего.\nif (__GR_DEV__)\n provideGrDevLayers(snapshotLayers)\n\n/** Тестовая/служебная очистка стека. */\nexport function resetOverlayStack(): void {\n stack.splice(0, stack.length)\n stopListening()\n\n if (__GR_DEV__)\n emitGrDevEvent({ type: 'overlay:sync', layers: [] })\n}\n"],"mappings":"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"}
|
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
//#region src/components/shared/overlayPanelSurface.ts
|
|
2
|
+
/**
|
|
3
|
+
* Общая поверхность всплывающей панели: радиус, рамка, фон, тень.
|
|
4
|
+
*
|
|
5
|
+
* До выноса шесть этих утилит были скопированы пять раз — у поповера,
|
|
6
|
+
* выпадающего меню и трёх списков выбора. Расходились бы молча: разница в одном
|
|
7
|
+
* токене видна только рядом с эталоном, а эталоны у компонентов свои.
|
|
8
|
+
*
|
|
9
|
+
* Фон — `--gr-popover`, и это не выбор из двух равных. Описание токена в
|
|
10
|
+
* `tokens/themes/*.json` — «Фон popover-, dropdown- и overlay-поверхностей», то
|
|
11
|
+
* есть он заведён ровно под этот случай; `--gr-card` — фон карточки. Четверо из
|
|
12
|
+
* пяти брали карточный, и значения совпадали, поэтому расхождение не
|
|
13
|
+
* проявлялось. Проявилось бы у первого, кто перекрасит `--gr-popover`, чтобы
|
|
14
|
+
* отличать всплывающие поверхности от карточек.
|
|
15
|
+
*
|
|
16
|
+
* Всё, что специфично для компонента, — поле, потолок ширины, `overflow` — он
|
|
17
|
+
* дописывает сам: это уже не поверхность, а его собственная раскладка.
|
|
18
|
+
*
|
|
19
|
+
* Модуль безадресный: в `dist` он уезжает в общий чанк, который пресет не
|
|
20
|
+
* сканирует, поэтому каждый потребитель объявляет эти классы в своём `safelist.ts`.
|
|
21
|
+
*/
|
|
22
|
+
var overlayPanelSurfaceClass = "rounded-[var(--gr-radius-xl)] border border-[var(--gr-brd)] bg-[var(--gr-popover)] text-[var(--gr-popover-fg)] shadow-[var(--gr-shadow-2)]";
|
|
23
|
+
//#endregion
|
|
1
24
|
//#region src/components/shared/overlayTransition.ts
|
|
2
25
|
/**
|
|
3
26
|
* Набор перехода всплывающей панели.
|
|
@@ -33,27 +56,4 @@ var panelPopTransition = {
|
|
|
33
56
|
leaveTo: "transform opacity-0 scale-95"
|
|
34
57
|
};
|
|
35
58
|
//#endregion
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Общая поверхность всплывающей панели: радиус, рамка, фон, тень.
|
|
39
|
-
*
|
|
40
|
-
* До выноса шесть этих утилит были скопированы пять раз — у поповера,
|
|
41
|
-
* выпадающего меню и трёх списков выбора. Расходились бы молча: разница в одном
|
|
42
|
-
* токене видна только рядом с эталоном, а эталоны у компонентов свои.
|
|
43
|
-
*
|
|
44
|
-
* Фон — `--gr-popover`, и это не выбор из двух равных. Описание токена в
|
|
45
|
-
* `tokens/themes/*.json` — «Фон popover-, dropdown- и overlay-поверхностей», то
|
|
46
|
-
* есть он заведён ровно под этот случай; `--gr-card` — фон карточки. Четверо из
|
|
47
|
-
* пяти брали карточный, и значения совпадали, поэтому расхождение не
|
|
48
|
-
* проявлялось. Проявилось бы у первого, кто перекрасит `--gr-popover`, чтобы
|
|
49
|
-
* отличать всплывающие поверхности от карточек.
|
|
50
|
-
*
|
|
51
|
-
* Всё, что специфично для компонента, — поле, потолок ширины, `overflow` — он
|
|
52
|
-
* дописывает сам: это уже не поверхность, а его собственная раскладка.
|
|
53
|
-
*
|
|
54
|
-
* Модуль безадресный: в `dist` он уезжает в общий чанк, который пресет не
|
|
55
|
-
* сканирует, поэтому каждый потребитель объявляет эти классы в своём `safelist.ts`.
|
|
56
|
-
*/
|
|
57
|
-
var overlayPanelSurfaceClass = "rounded-[var(--gr-radius-xl)] border border-[var(--gr-brd)] bg-[var(--gr-popover)] text-[var(--gr-popover-fg)] shadow-[var(--gr-shadow-2)]";
|
|
58
|
-
//#endregion
|
|
59
|
-
export { panelPopTransition as n, overlayPanelSurfaceClass as t };
|
|
59
|
+
export { overlayPanelSurfaceClass as n, panelPopTransition as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlayTransition-C0FDMx7Q.js","names":[],"sources":["../../src/components/shared/overlayPanelSurface.ts","../../src/components/shared/overlayTransition.ts"],"sourcesContent":["/**\n * Общая поверхность всплывающей панели: радиус, рамка, фон, тень.\n *\n * До выноса шесть этих утилит были скопированы пять раз — у поповера,\n * выпадающего меню и трёх списков выбора. Расходились бы молча: разница в одном\n * токене видна только рядом с эталоном, а эталоны у компонентов свои.\n *\n * Фон — `--gr-popover`, и это не выбор из двух равных. Описание токена в\n * `tokens/themes/*.json` — «Фон popover-, dropdown- и overlay-поверхностей», то\n * есть он заведён ровно под этот случай; `--gr-card` — фон карточки. Четверо из\n * пяти брали карточный, и значения совпадали, поэтому расхождение не\n * проявлялось. Проявилось бы у первого, кто перекрасит `--gr-popover`, чтобы\n * отличать всплывающие поверхности от карточек.\n *\n * Всё, что специфично для компонента, — поле, потолок ширины, `overflow` — он\n * дописывает сам: это уже не поверхность, а его собственная раскладка.\n *\n * Модуль безадресный: в `dist` он уезжает в общий чанк, который пресет не\n * сканирует, поэтому каждый потребитель объявляет эти классы в своём `safelist.ts`.\n */\nexport const overlayPanelSurfaceClass = 'rounded-[var(--gr-radius-xl)] border border-[var(--gr-brd)] bg-[var(--gr-popover)] text-[var(--gr-popover-fg)] shadow-[var(--gr-shadow-2)]'\n","/**\n * Набор перехода всплывающей панели.\n *\n * Пять панелей — выпадающее меню, поповер, списки выбора — появляются\n * одинаково, и до выноса держали этот набор литералами в своих шаблонах:\n * шесть строк, повторённых дословно пять раз. Разъезжались они молча, потому\n * что визуально расхождение в одной фазе заметно только рядом с эталоном.\n *\n * Форма — объект по фазам, как `overlayTransition`/`panelTransition` у\n * `GrModal`: так набор биндится в `<transition>` по одному имени на фазу и\n * разворачивается в safelist одним вызовом, не превращаясь в «мешок токенов».\n *\n * Два правила, оба следуют из того, что модуль безадресный (в `dist` он лежит\n * в общем чанке, который пресет не сканирует):\n *\n * 1. **Каждый потребитель обязан объявить эти классы в своём `safelist.ts`** —\n * через `flattenTransitionTokens`. Гейт `src/__tests__/safelist.test.ts`\n * проверяет это обходом импортов; забывшего он назовёт поимённо.\n * 2. **Один пресет — один файл.** Второй набор, положенный сюда же, обложил бы\n * налогом потребителей первого: safelist считается по модулю целиком, и\n * `GrDropdown` понёс бы классы, которых не рендерит.\n *\n * Набор с единственным потребителем сюда не переезжает вовсе — литералы в его\n * `.vue` находит скан, и это дешевле. Поэтому здесь нет фейда `GrTooltip`.\n */\nexport const panelPopTransition = {\n enter: 'transition ease-[var(--gr-ease-out)] duration-[var(--gr-duration-fast)]',\n enterFrom: 'transform opacity-0 scale-95',\n enterTo: 'transform opacity-100 scale-100',\n leave: 'transition ease-[var(--gr-ease-in)] duration-[var(--gr-duration-fast)]',\n leaveFrom: 'transform opacity-100 scale-100',\n leaveTo: 'transform opacity-0 scale-95',\n} as const\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAoBA,IAAa,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACKxC,IAAa,qBAAqB;CAChC,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,WAAW;CACX,SAAS;AACX"}
|
|
@@ -15,7 +15,8 @@ var transfer = {
|
|
|
15
15
|
"moved": "{count} перенесено в «{list}»",
|
|
16
16
|
"reordered": "Позиция {position} из {count}",
|
|
17
17
|
"reorderFiltered": "Пока включён поиск, порядок не меняется",
|
|
18
|
-
"cancelled": "Перенос отменён"
|
|
18
|
+
"cancelled": "Перенос отменён",
|
|
19
|
+
"loading": "Ищем…"
|
|
19
20
|
};
|
|
20
21
|
var carousel = {
|
|
21
22
|
"roledescription": "карусель",
|
|
@@ -51,7 +52,8 @@ var steps = {
|
|
|
51
52
|
var treeSelect = {
|
|
52
53
|
"filterPlaceholder": "Поиск…",
|
|
53
54
|
"empty": "Нет данных",
|
|
54
|
-
"loading": "Загрузка…"
|
|
55
|
+
"loading": "Загрузка…",
|
|
56
|
+
"removeTag": "Удалить {label}"
|
|
55
57
|
};
|
|
56
58
|
var badgeWrap = { "count": "{count} новых" };
|
|
57
59
|
var avatar = {
|
|
@@ -98,7 +100,14 @@ var dataTable = {
|
|
|
98
100
|
"detailRetry": "Повторить",
|
|
99
101
|
"detailExpanded": "Подробности строки раскрыты",
|
|
100
102
|
"detailCollapsed": "Подробности строки свёрнуты",
|
|
101
|
-
"detailReady": "Подробности строки загружены"
|
|
103
|
+
"detailReady": "Подробности строки загружены",
|
|
104
|
+
"columnMenu": "Действия с колонкой {label}",
|
|
105
|
+
"pinLeft": "Закрепить слева",
|
|
106
|
+
"pinRight": "Закрепить справа",
|
|
107
|
+
"unpin": "Открепить",
|
|
108
|
+
"columnPinnedLeft": "Колонка {label} закреплена слева",
|
|
109
|
+
"columnPinnedRight": "Колонка {label} закреплена справа",
|
|
110
|
+
"columnUnpinned": "Колонка {label} откреплена"
|
|
102
111
|
};
|
|
103
112
|
var breadcrumbs = {
|
|
104
113
|
"label": "Навигационная цепочка",
|
|
@@ -211,7 +220,9 @@ var inputTag = {
|
|
|
211
220
|
"addedMany": "Добавлено тегов: {count}",
|
|
212
221
|
"removed": "Удалён тег: {tag}",
|
|
213
222
|
"cleared": "Все теги удалены",
|
|
214
|
-
"limitReached": "Достигнут предел тегов"
|
|
223
|
+
"limitReached": "Достигнут предел тегов",
|
|
224
|
+
"editTag": "Правка тега {tag}",
|
|
225
|
+
"edited": "Тег изменён: {tag}"
|
|
215
226
|
};
|
|
216
227
|
var fileUpload = {
|
|
217
228
|
"placeholder": "Перетащите файлы сюда или нажмите для выбора",
|
|
@@ -329,7 +340,9 @@ var colorPicker = {
|
|
|
329
340
|
"opacity": "Непрозрачность",
|
|
330
341
|
"hexLabel": "Значение hex",
|
|
331
342
|
"presetsLabel": "Палитра",
|
|
332
|
-
"swatchLabel": "Цвет {color}"
|
|
343
|
+
"swatchLabel": "Цвет {color}",
|
|
344
|
+
"area": "Насыщенность и светлота",
|
|
345
|
+
"eyedropper": "Взять цвет с экрана"
|
|
333
346
|
};
|
|
334
347
|
var collapse = { "empty": "Пока пусто" };
|
|
335
348
|
var list = { "empty": "Пока пусто" };
|
|
@@ -344,7 +357,10 @@ var bottomNav = {
|
|
|
344
357
|
"label": "Нижняя навигация",
|
|
345
358
|
"badge": "{count} новых"
|
|
346
359
|
};
|
|
347
|
-
var emptyState = {
|
|
360
|
+
var emptyState = {
|
|
361
|
+
"title": "Пока пусто",
|
|
362
|
+
"searchTitle": "Ничего не найдено"
|
|
363
|
+
};
|
|
348
364
|
var sortable = {
|
|
349
365
|
"label": "Сортируемый список",
|
|
350
366
|
"handle": "Переставить",
|
|
@@ -381,7 +397,11 @@ var ru_default = {
|
|
|
381
397
|
autocomplete,
|
|
382
398
|
form,
|
|
383
399
|
dialog,
|
|
384
|
-
"switch": {
|
|
400
|
+
"switch": {
|
|
401
|
+
"loading": "Сохраняем…",
|
|
402
|
+
"on": "ДА",
|
|
403
|
+
"off": "НЕТ"
|
|
404
|
+
},
|
|
385
405
|
slider,
|
|
386
406
|
sidebar,
|
|
387
407
|
splitter,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ru-CQKDR-kD.js","names":[],"sources":["../../src/i18n/locales/ru.json"],"sourcesContent":["{\n \"transfer\": {\n \"sourceTitle\": \"Доступны\",\n \"targetTitle\": \"Выбраны\",\n \"search\": \"Поиск\",\n \"toTarget\": \"Перенести к выбранным\",\n \"toSource\": \"Вернуть к доступным\",\n \"selectAll\": \"Выбрать всё показанное\",\n \"moveUp\": \"Раньше\",\n \"moveDown\": \"Позже\",\n \"selected\": \"{count} из {total}\",\n \"shown\": \"Показано {shown} из {total}\",\n \"empty\": \"Здесь пока пусто\",\n \"emptyFiltered\": \"Ничего не найдено\",\n \"moved\": \"{count} перенесено в «{list}»\",\n \"reordered\": \"Позиция {position} из {count}\",\n \"reorderFiltered\": \"Пока включён поиск, порядок не меняется\",\n \"cancelled\": \"Перенос отменён\",\n \"loading\": \"Ищем…\"\n },\n \"carousel\": {\n \"roledescription\": \"карусель\",\n \"slideRoledescription\": \"слайд\",\n \"slidePosition\": \"{index} из {total}\",\n \"previous\": \"Предыдущий слайд\",\n \"next\": \"Следующий слайд\",\n \"play\": \"Запустить автопоказ\",\n \"pause\": \"Остановить автопоказ\",\n \"indicators\": \"Слайды\",\n \"autoplayStopped\": \"Автопоказ остановлен\"\n },\n \"chip\": {\n \"remove\": \"Убрать\",\n \"removeNamed\": \"Убрать {label}\"\n },\n \"common\": {\n \"confirm\": \"Подтвердить\",\n \"cancel\": \"Отмена\",\n \"add\": \"Добавить\",\n \"clear\": \"Очистить\",\n \"close\": \"Закрыть\",\n \"stateSuccess\": \"Корректно\",\n \"stateWarning\": \"Предупреждение\"\n },\n \"loading\": {\n \"defaultText\": \"Загрузка...\"\n },\n \"steps\": {\n \"label\": \"Ход выполнения\",\n \"status\": \"Шаг {step} из {count}\",\n \"completed\": \"выполнен\",\n \"error\": \"есть ошибки\"\n },\n \"treeSelect\": {\n \"filterPlaceholder\": \"Поиск…\",\n \"empty\": \"Нет данных\",\n \"loading\": \"Загрузка…\",\n \"removeTag\": \"Удалить {label}\"\n },\n \"badgeWrap\": {\n \"count\": \"{count} новых\"\n },\n \"avatar\": {\n \"group\": \"Участники\",\n \"groupOverflow\": \"и ещё {count}\",\n \"status\": {\n \"online\": \"в сети\",\n \"offline\": \"не в сети\",\n \"busy\": \"занят\",\n \"away\": \"отошёл\"\n }\n },\n \"tree\": {\n \"drag\": \"Перетащить\",\n \"expand\": \"Развернуть\",\n \"collapse\": \"Свернуть\",\n \"moved\": \"{label} перемещён\"\n },\n \"select\": {\n \"customValuePlaceholder\": \"Добавить значение…\",\n \"addOption\": \"Добавить «{value}»\",\n \"clearOption\": \"Не выбрано\",\n \"searchPlaceholder\": \"Поиск…\",\n \"loading\": \"Загрузка…\",\n \"noResults\": \"Ничего не найдено\",\n \"removeTag\": \"Удалить {label}\"\n },\n \"dataTable\": {\n \"loading\": \"Загрузка…\",\n \"empty\": \"Нет данных\",\n \"selectAll\": \"Выбрать все строки\",\n \"selectRow\": \"Выбрать строку\",\n \"sortAsc\": \"Нажмите для сортировки по возрастанию\",\n \"sortDesc\": \"Нажмите для сортировки по убыванию\",\n \"sortNone\": \"Нажмите, чтобы снять сортировку\",\n \"moveColumn\": \"Переставить колонку {label}\",\n \"columnMoved\": \"Колонка {label} перемещена на позицию {position} из {count}\",\n \"resizeColumn\": \"Ширина колонки {label}\",\n \"columnResized\": \"Ширина колонки {label} — {width} пикселей\",\n \"expandRow\": \"Показать подробности\",\n \"collapseRow\": \"Скрыть подробности\",\n \"detailLoading\": \"Загружаем подробности…\",\n \"detailError\": \"Не удалось загрузить подробности\",\n \"detailRetry\": \"Повторить\",\n \"detailExpanded\": \"Подробности строки раскрыты\",\n \"detailCollapsed\": \"Подробности строки свёрнуты\",\n \"detailReady\": \"Подробности строки загружены\",\n \"columnMenu\": \"Действия с колонкой {label}\",\n \"pinLeft\": \"Закрепить слева\",\n \"pinRight\": \"Закрепить справа\",\n \"unpin\": \"Открепить\",\n \"columnPinnedLeft\": \"Колонка {label} закреплена слева\",\n \"columnPinnedRight\": \"Колонка {label} закреплена справа\",\n \"columnUnpinned\": \"Колонка {label} откреплена\"\n },\n \"breadcrumbs\": {\n \"label\": \"Навигационная цепочка\",\n \"expand\": \"Показать скрытые уровни\"\n },\n \"autocomplete\": {\n \"loading\": \"Загрузка…\",\n \"noResults\": \"Ничего не найдено\",\n \"addOption\": \"Добавить «{value}»\",\n \"removeValue\": \"Убрать {label}\",\n \"typeMore\": {\n \"one\": \"Введите минимум {n} символ\",\n \"few\": \"Введите минимум {n} символа\",\n \"many\": \"Введите минимум {n} символов\",\n \"other\": \"Введите минимум {n} символа\"\n }\n },\n \"form\": {\n \"required\": \"Обязательное поле\",\n \"min\": \"Минимум {min}\",\n \"max\": \"Максимум {max}\",\n \"len\": \"Длина должна быть {len}\",\n \"pattern\": \"Неверный формат\",\n \"email\": \"Введите корректный e-mail\",\n \"url\": \"Введите корректный URL\",\n \"file\": \"Некорректный файл\",\n \"invalid\": \"Некорректное значение\",\n \"readonly\": \"Только для чтения\",\n \"validating\": \"Проверяем…\"\n },\n \"dialog\": {\n \"confirm\": {\n \"title\": \"Подтверждение\"\n },\n \"prompt\": {\n \"title\": \"Введите значение\",\n \"label\": \"Значение\",\n \"required\": \"Введите значение.\"\n },\n \"ok\": \"ОК\"\n },\n \"switch\": {\n \"loading\": \"Сохраняем…\",\n \"on\": \"ДА\",\n \"off\": \"НЕТ\"\n },\n \"slider\": {\n \"min\": \"минимум\",\n \"max\": \"максимум\"\n },\n \"sidebar\": {\n \"expand\": \"Развернуть панель\",\n \"collapse\": \"Свернуть панель\"\n },\n \"splitter\": {\n \"label\": \"Изменить размер панелей\"\n },\n \"statistic\": {\n \"trendUp\": \"Рост\",\n \"trendDown\": \"Падение\",\n \"trendFlat\": \"Без изменений\"\n },\n \"pagination\": {\n \"label\": \"Пагинация\",\n \"pageSize\": \"Размер страницы\",\n \"prev\": \"Назад\",\n \"next\": \"Вперёд\",\n \"page\": \"Страница {n}\",\n \"first\": \"Первая страница\",\n \"last\": \"Последняя страница\",\n \"jumpTo\": \"Перейти к\",\n \"total\": \"{from}–{to} из {total}\",\n \"status\": \"Страница {page} из {count}\"\n },\n \"navbar\": {\n \"openMenu\": \"Открыть меню\"\n },\n \"scrollSpy\": {\n \"label\": \"На этой странице\"\n },\n \"responseError\": {\n \"networkTitle\": \"Нет связи с сервером\",\n \"networkMessage\": \"Проверьте подключение к интернету и попробуйте ещё раз.\",\n \"abortedTitle\": \"Запрос отменён\",\n \"abortedMessage\": \"Запрос был отменён.\",\n \"validationTitle\": \"Проверьте данные\",\n \"validationMessage\": \"Сервер вернул ошибку валидации. Исправьте поля и попробуйте снова.\",\n \"clientTitle\": \"Ошибка запроса\",\n \"clientMessage\": \"Сервер отклонил запрос.\",\n \"serverTitle\": \"Ошибка сервера\",\n \"serverMessage\": \"Произошла ошибка на сервере. Попробуйте ещё раз.\",\n \"unknownTitle\": \"Что-то пошло не так\",\n \"unknownMessage\": \"Не удалось выполнить операцию. Попробуйте ещё раз.\",\n \"statusLabel\": \"HTTP {status}\",\n \"retryLabel\": \"Повторить\",\n \"dismissLabel\": \"Скрыть\"\n },\n \"colors\": {\n \"neutral\": \"Нейтральный\",\n \"success\": \"Успех\",\n \"warning\": \"Предупреждение\",\n \"danger\": \"Опасность\",\n \"info\": \"Инфо\",\n \"primary\": \"Primary\",\n \"slate\": \"Сланцевый\",\n \"azure\": \"Лазурный\"\n },\n \"drawer\": {\n \"title\": \"Панель\"\n },\n \"modal\": {\n \"title\": \"Диалог\"\n },\n \"numberInput\": {\n \"increase\": \"Увеличить\",\n \"decrease\": \"Уменьшить\"\n },\n \"toaster\": {\n \"dismiss\": \"Закрыть\",\n \"region\": \"Уведомления\"\n },\n \"inputTag\": {\n \"removeTag\": \"Удалить тег\",\n \"removeTagNamed\": \"Удалить тег {tag}\",\n \"clearAll\": \"Удалить все теги\",\n \"added\": \"Добавлен тег: {tag}\",\n \"addedMany\": \"Добавлено тегов: {count}\",\n \"removed\": \"Удалён тег: {tag}\",\n \"cleared\": \"Все теги удалены\",\n \"limitReached\": \"Достигнут предел тегов\",\n \"editTag\": \"Правка тега {tag}\",\n \"edited\": \"Тег изменён: {tag}\"\n },\n \"fileUpload\": {\n \"placeholder\": \"Перетащите файлы сюда или нажмите для выбора\",\n \"progress\": \"Прогресс загрузки\",\n \"uploading\": \"Загрузка…\",\n \"success\": \"Загрузка завершена\",\n \"error\": \"Не удалось загрузить\",\n \"remove\": \"Убрать {fileName}\",\n \"retry\": \"Повторить загрузку\",\n \"retryFile\": \"Повторить {fileName}\",\n \"abortFile\": \"Отменить загрузку {fileName}\",\n \"statusPending\": \"В очереди\",\n \"statusUploading\": \"Загружается\",\n \"statusSuccess\": \"Загружен\",\n \"statusError\": \"Ошибка\"\n },\n \"formFile\": {\n \"upload\": \"Загрузить файл\",\n \"change\": \"Заменить файл\",\n \"remove\": \"Удалить\",\n \"clearAll\": \"Очистить всё\",\n \"placeholder\": \"Файлы не выбраны\",\n \"validateError\": \"Не удалось проверить перетащенные файлы\",\n \"removeFile\": \"Убрать {fileName}\"\n },\n \"imageViewer\": {\n \"close\": \"Закрыть просмотрщик\",\n \"prev\": \"Предыдущее изображение\",\n \"next\": \"Следующее изображение\",\n \"zoomIn\": \"Увеличить\",\n \"zoomOut\": \"Уменьшить\",\n \"resetZoom\": \"Сбросить масштаб\",\n \"zoomToNatural\": \"Натуральный размер (1:1)\",\n \"rotateLeft\": \"Повернуть влево\",\n \"rotateRight\": \"Повернуть вправо\",\n \"download\": \"Скачать изображение\",\n \"empty\": \"Нет изображения\",\n \"label\": \"Просмотр изображений\",\n \"position\": \"Изображение {index} из {total}\"\n },\n \"formErrorBanner\": {\n \"validationTitle\": \"Проверьте поля формы\",\n \"validationMessage\": \"Сервер отклонил данные. Исправьте выделенные поля и попробуйте снова.\",\n \"clientTitle\": \"Не удалось сохранить\",\n \"serverTitle\": \"Ошибка сохранения\",\n \"serverMessage\": \"Не удалось сохранить данные. Попробуйте позже.\"\n },\n \"uploadErrorBanner\": {\n \"networkTitle\": \"Не удалось загрузить файлы\",\n \"networkMessage\": \"Проверьте подключение и попробуйте снова.\",\n \"validationTitle\": \"Файлы не прошли проверку\",\n \"validationMessage\": \"Некоторые файлы не соответствуют требованиям.\",\n \"serverTitle\": \"Ошибка загрузки на сервере\",\n \"serverMessage\": \"Сервер не смог обработать загрузку. Попробуйте снова.\"\n },\n \"input\": {\n \"clear\": \"Очистить\",\n \"showPassword\": \"Показать пароль\",\n \"hidePassword\": \"Скрыть пароль\",\n \"limitReached\": \"Достигнут предел символов\"\n },\n \"textarea\": {\n \"lines\": {\n \"one\": \"{n} строка\",\n \"few\": \"{n} строки\",\n \"many\": \"{n} строк\",\n \"other\": \"{n} строки\"\n }\n },\n \"rating\": {\n \"label\": \"Оценка\",\n \"valueText\": \"{value} из {max}\",\n \"valueTextWithLabel\": \"{value} из {max}, {label}\"\n },\n \"commandPalette\": {\n \"label\": \"Палитра команд\",\n \"placeholder\": \"Введите команду или запрос…\",\n \"empty\": \"Ничего не найдено\",\n \"recent\": \"Недавние\",\n \"loading\": \"Загрузка…\"\n },\n \"delta\": {\n \"increase\": \"рост\"\n },\n \"filePreview\": {\n \"label\": \"Файл\"\n },\n \"fileValidation\": {\n \"accept\": \"Файл «{fileName}» не подходит под accept=\\\"{accept}\\\"\",\n \"extension\": \"У файла «{fileName}» недопустимое расширение «.{extension}»\",\n \"mimeType\": \"У файла «{fileName}» недопустимый тип «{mimeType}»\",\n \"mimeTypeFallback\": \"У файла «{fileName}» неопределённый тип «{mimeType}»\",\n \"maxFileSize\": \"Файл «{fileName}» слишком большой ({size} байт), максимум {maxBytes}\",\n \"maxCount\": \"Выбрано слишком много файлов ({count}), максимум — {maxCount}\",\n \"maxTotalSize\": \"Суммарный размер файлов слишком большой ({total} байт), максимум {maxBytes}\"\n },\n \"kbd\": {\n \"command\": \"Command\",\n \"option\": \"Option\",\n \"shift\": \"Shift\",\n \"control\": \"Control\",\n \"enter\": \"Enter\",\n \"escape\": \"Escape\",\n \"tab\": \"Tab\",\n \"backspace\": \"Backspace\",\n \"delete\": \"Delete\",\n \"pageUp\": \"Page Up\",\n \"pageDown\": \"Page Down\",\n \"arrowUp\": \"стрелка вверх\",\n \"arrowDown\": \"стрелка вниз\",\n \"arrowLeft\": \"стрелка влево\",\n \"arrowRight\": \"стрелка вправо\",\n \"then\": \"затем\"\n },\n \"link\": {\n \"opensInNewTab\": \"откроется в новой вкладке\"\n },\n \"colorPicker\": {\n \"panelLabel\": \"Выбор цвета\",\n \"hue\": \"Оттенок\",\n \"saturation\": \"Насыщенность\",\n \"lightness\": \"Светлота\",\n \"opacity\": \"Непрозрачность\",\n \"hexLabel\": \"Значение hex\",\n \"presetsLabel\": \"Палитра\",\n \"swatchLabel\": \"Цвет {color}\",\n \"area\": \"Насыщенность и светлота\",\n \"eyedropper\": \"Взять цвет с экрана\"\n },\n \"collapse\": {\n \"empty\": \"Пока пусто\"\n },\n \"list\": {\n \"empty\": \"Пока пусто\"\n },\n \"button\": {\n \"loading\": \"Загрузка…\"\n },\n \"table\": {\n \"empty\": \"Пока пусто\"\n },\n \"timeline\": {\n \"empty\": \"Пока пусто\"\n },\n \"tabs\": {\n \"empty\": \"Пока пусто\",\n \"close\": \"Закрыть вкладку\"\n },\n \"bottomNav\": {\n \"label\": \"Нижняя навигация\",\n \"badge\": \"{count} новых\"\n },\n \"emptyState\": {\n \"title\": \"Пока пусто\",\n \"searchTitle\": \"Ничего не найдено\"\n },\n \"sortable\": {\n \"label\": \"Сортируемый список\",\n \"handle\": \"Переставить\",\n \"empty\": \"Пока нечего сортировать\",\n \"grabbed\": \"Взято. Позиция {position} из {count}\",\n \"moved\": \"Позиция {position} из {count}\",\n \"dropped\": \"Отпущено на позиции {position} из {count}\",\n \"cancelled\": \"Перенос отменён\"\n },\n \"jsonViewer\": {\n \"search\": \"Поиск по ключу или значению\",\n \"expandAll\": \"Раскрыть всё\",\n \"collapseAll\": \"Свернуть всё\",\n \"copy\": \"Скопировать значение\",\n \"copied\": \"Значение скопировано\",\n \"copyFailed\": \"Не удалось скопировать значение\",\n \"moreItems\": \"ещё\"\n },\n \"contextMenu\": {\n \"label\": \"Контекстное меню\"\n }\n}\n"],"mappings":""}
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { n as splitClassTokens } from "./classTokens-8v2XC74x.js";
|
|
2
|
-
import { a as
|
|
2
|
+
import { a as badgeDotToneClass, c as darkToneClassByTone, f as semiRadiusClassBySize, i as badgeDotSizeClassBySize, o as badgeIconClass, p as sizeClassBySize, r as badgeDotCurrentColorClass, s as badgeIconSizeClassBySize, t as badgeDotClass, u as lightToneClassByTone } from "./grBadgeStyles-D51AXbj5.js";
|
|
3
3
|
//#region src/components/GrBadge/safelist.ts
|
|
4
4
|
var grBadgeSafelist = [.../* @__PURE__ */ new Set([
|
|
5
5
|
...Object.values(sizeClassBySize).flatMap(splitClassTokens),
|
|
6
6
|
...Object.values(badgeIconSizeClassBySize).flatMap(splitClassTokens),
|
|
7
7
|
...splitClassTokens(badgeIconClass),
|
|
8
|
+
...Object.values(badgeDotSizeClassBySize).flatMap(splitClassTokens),
|
|
9
|
+
...splitClassTokens(badgeDotClass),
|
|
10
|
+
...splitClassTokens(badgeDotCurrentColorClass),
|
|
11
|
+
...Object.values(badgeDotToneClass).flatMap(splitClassTokens),
|
|
8
12
|
...Object.values(semiRadiusClassBySize).flatMap(splitClassTokens),
|
|
9
13
|
"rounded-[var(--gr-radius-none)]",
|
|
10
14
|
"rounded-[var(--gr-radius-full)]",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safelist-CSfynUC1.js","names":[],"sources":["../../src/components/GrBadge/safelist.ts"],"sourcesContent":["import { splitClassTokens } from '../shared/classTokens'\nimport {\n badgeDotClass,\n badgeDotCurrentColorClass,\n badgeDotSizeClassBySize,\n badgeDotToneClass,\n badgeIconClass,\n badgeIconSizeClassBySize,\n darkToneClassByTone,\n lightToneClassByTone,\n semiRadiusClassBySize,\n sizeClassBySize,\n} from './grBadgeStyles'\n\nexport const grBadgeSafelist = [...new Set([\n ...Object.values(sizeClassBySize).flatMap(splitClassTokens),\n ...Object.values(badgeIconSizeClassBySize).flatMap(splitClassTokens),\n ...splitClassTokens(badgeIconClass),\n ...Object.values(badgeDotSizeClassBySize).flatMap(splitClassTokens),\n ...splitClassTokens(badgeDotClass),\n ...splitClassTokens(badgeDotCurrentColorClass),\n ...Object.values(badgeDotToneClass).flatMap(splitClassTokens),\n ...Object.values(semiRadiusClassBySize).flatMap(splitClassTokens),\n 'rounded-[var(--gr-radius-none)]',\n 'rounded-[var(--gr-radius-full)]',\n ...Object.values(lightToneClassByTone).flatMap(splitClassTokens),\n ...Object.values(darkToneClassByTone).flatMap(splitClassTokens),\n])]\n"],"mappings":";;;AAcA,IAAa,kBAAkB,CAAC,mBAAG,IAAI,IAAI;CACzC,GAAG,OAAO,OAAO,eAAe,CAAC,CAAC,QAAQ,gBAAgB;CAC1D,GAAG,OAAO,OAAO,wBAAwB,CAAC,CAAC,QAAQ,gBAAgB;CACnE,GAAG,iBAAiB,cAAc;CAClC,GAAG,OAAO,OAAO,uBAAuB,CAAC,CAAC,QAAQ,gBAAgB;CAClE,GAAG,iBAAiB,aAAa;CACjC,GAAG,iBAAiB,yBAAyB;CAC7C,GAAG,OAAO,OAAO,iBAAiB,CAAC,CAAC,QAAQ,gBAAgB;CAC5D,GAAG,OAAO,OAAO,qBAAqB,CAAC,CAAC,QAAQ,gBAAgB;CAChE;CACA;CACA,GAAG,OAAO,OAAO,oBAAoB,CAAC,CAAC,QAAQ,gBAAgB;CAC/D,GAAG,OAAO,OAAO,mBAAmB,CAAC,CAAC,QAAQ,gBAAgB;AAChE,CAAC,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { r as isEditableTarget } from "./keyboard-BiFSgWLt.js";
|
|
2
2
|
import { n as getFocusableElements } from "./useFocusTrap-D9bIPNF6.js";
|
|
3
3
|
import { t as useTypeahead } from "./useTypeahead-mxPtPBf2.js";
|
|
4
4
|
//#region src/composables/internal/useMenuItemsFocus.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMenuItemsFocus-
|
|
1
|
+
{"version":3,"file":"useMenuItemsFocus-C031blYS.js","names":[],"sources":["../../src/composables/internal/useMenuItemsFocus.ts"],"sourcesContent":["import { isEditableTarget } from '../../internal/keyboard'\n\nimport { getFocusableElements } from './focusables'\nimport { useTypeahead } from './useTypeahead'\n\nexport interface UseMenuItemsFocusOptions {\n /** Корень, внутри которого живут пункты. */\n container: () => HTMLElement | null\n /** Закрыть меню — `Tab` уводит фокус наружу, панель при этом закрывается. */\n close: () => void\n}\n\nexport interface UseMenuItemsFocusReturn {\n /** Пункты в порядке документа. */\n items: () => HTMLElement[]\n /** Сфокусировать по индексу; отрицательный и превышающий заворачиваются. */\n focusAt: (index: number) => void\n /** Стрелки, `Home`/`End`, `Tab`, typeahead. `true` — клавиша обработана. */\n onKeydown: (event: KeyboardEvent) => boolean\n reset: () => void\n}\n\n/**\n * Клавиатура панели-меню: кольцо фокуса плюс поиск по первым буквам.\n *\n * Пункты ищутся в DOM, а не в модели, и это осознанно: у панели бывает\n * произвольное содержимое из слота, в котором ключей нет вовсе. По той же\n * причине здесь не `useRovingFocus` — он адресуется ключами и ведёт\n * `tabindex=\"0\"` на активном элементе, а пункты меню обязаны быть `-1`.\n */\nexport function useMenuItemsFocus(options: UseMenuItemsFocusOptions): UseMenuItemsFocusReturn {\n /**\n * `tabbableOnly: false` — не оплошность: пункты меню намеренно `tabindex=\"-1\"`,\n * и список участников таб-порядка был бы пуст.\n */\n function items(): HTMLElement[] {\n return getFocusableElements(options.container(), { tabbableOnly: false })\n }\n\n function focusAt(index: number): void {\n const list = items()\n if (list.length === 0)\n return\n\n // `preventScroll` обязателен: панель уже приведена во вьюпорт позиционером,\n // поэтому прокрутка ради фокуса внутри неё паразитная. У контекстного меню\n // она к тому же порождала `scroll`, по которому меню закрывало само себя.\n list[(index + list.length) % list.length]?.focus({ preventScroll: true })\n }\n\n const typeahead = useTypeahead<HTMLElement>({\n items,\n textOf: element => element.textContent ?? '',\n currentIndex: list => list.indexOf(document.activeElement as HTMLElement),\n onMatch: element => element.focus({ preventScroll: true }),\n })\n\n function onKeydown(event: KeyboardEvent): boolean {\n const list = items()\n const currentIndex = list.indexOf(document.activeElement as HTMLElement)\n\n // Панель бывает не только меню из кнопок: с `closeOnContentClick={false}` в\n // ней живут поля и чекбоксы. Клавиши, которые сфокусированный контрол умеет\n // сам, остаются ему — иначе в поле не напечатать, а чекбокс не переключить.\n const editable = isEditableTarget(event.target)\n\n switch (event.key) {\n // Стрелки — исключение: они за меню даже в поле. `Tab` панель закрывает, и\n // без них из поля внутри панели не было бы выхода вовсе.\n case 'ArrowDown':\n event.preventDefault()\n focusAt(currentIndex + 1)\n return true\n case 'ArrowUp':\n event.preventDefault()\n focusAt(currentIndex - 1)\n return true\n case 'Home':\n if (editable)\n return false\n event.preventDefault()\n focusAt(0)\n return true\n case 'End':\n if (editable)\n return false\n event.preventDefault()\n focusAt(-1)\n return true\n case 'Tab':\n options.close()\n return true\n }\n\n if (editable)\n return false\n\n // Пробел при пустом буфере — активация сфокусированного пункта, а не поиск:\n // пункты меню это кнопки, и пробел для них родная клавиша. В буфер он входит,\n // только когда поиск уже идёт (правило typeahead из WAI-ARIA APG).\n if (event.key === ' ' && typeahead.isEmpty())\n return false\n\n // Печатный символ без модификаторов — поиск по пунктам, а не команда.\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {\n event.preventDefault()\n typeahead.type(event.key)\n return true\n }\n\n return false\n }\n\n return { items, focusAt, onKeydown, reset: typeahead.reset }\n}\n"],"mappings":";;;;;;;;;;;;AA8BA,SAAgB,kBAAkB,SAA4D;;;;;CAK5F,SAAS,QAAuB;EAC9B,OAAO,qBAAqB,QAAQ,UAAU,GAAG,EAAE,cAAc,MAAM,CAAC;CAC1E;CAEA,SAAS,QAAQ,OAAqB;EACpC,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,WAAW,GAClB;EAKF,MAAM,QAAQ,KAAK,UAAU,KAAK,OAAO,EAAE,MAAM,EAAE,eAAe,KAAK,CAAC;CAC1E;CAEA,MAAM,YAAY,aAA0B;EAC1C;EACA,SAAQ,YAAW,QAAQ,eAAe;EAC1C,eAAc,SAAQ,KAAK,QAAQ,SAAS,aAA4B;EACxE,UAAS,YAAW,QAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;CAC3D,CAAC;CAED,SAAS,UAAU,OAA+B;EAEhD,MAAM,eADO,MACQ,CAAA,CAAK,QAAQ,SAAS,aAA4B;EAKvE,MAAM,WAAW,iBAAiB,MAAM,MAAM;EAE9C,QAAQ,MAAM,KAAd;GAGE,KAAK;IACH,MAAM,eAAe;IACrB,QAAQ,eAAe,CAAC;IACxB,OAAO;GACT,KAAK;IACH,MAAM,eAAe;IACrB,QAAQ,eAAe,CAAC;IACxB,OAAO;GACT,KAAK;IACH,IAAI,UACF,OAAO;IACT,MAAM,eAAe;IACrB,QAAQ,CAAC;IACT,OAAO;GACT,KAAK;IACH,IAAI,UACF,OAAO;IACT,MAAM,eAAe;IACrB,QAAQ,EAAE;IACV,OAAO;GACT,KAAK;IACH,QAAQ,MAAM;IACd,OAAO;EACX;EAEA,IAAI,UACF,OAAO;EAKT,IAAI,MAAM,QAAQ,OAAO,UAAU,QAAQ,GACzC,OAAO;EAGT,IAAI,MAAM,IAAI,WAAW,KAAK,CAAC,MAAM,WAAW,CAAC,MAAM,WAAW,CAAC,MAAM,QAAQ;GAC/E,MAAM,eAAe;GACrB,UAAU,KAAK,MAAM,GAAG;GACxB,OAAO;EACT;EAEA,OAAO;CACT;CAEA,OAAO;EAAE;EAAO;EAAS;EAAW,OAAO,UAAU;CAAM;AAC7D"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { s as useGrThemeAttrs } from "./context-CPMRfwVr.js";
|
|
2
2
|
import { t as usePortalTarget } from "./usePortalTarget-BhrRgdqW.js";
|
|
3
3
|
import { n as markInert, t as inertableOutside } from "./inert-DIHCCn_1.js";
|
|
4
|
-
import { r as modalLayerZIndex } from "./overlayStack-
|
|
4
|
+
import { r as modalLayerZIndex } from "./overlayStack-DCkCgXZP.js";
|
|
5
5
|
import { useOverlayLayer } from "../composables/useOverlayLayer.js";
|
|
6
6
|
import { t as useFocusTrap } from "./useFocusTrap-D9bIPNF6.js";
|
|
7
7
|
import { computed, onBeforeUnmount, onScopeDispose, ref, watch } from "vue";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModalOverlay-ACRkflzx.js","names":[],"sources":["../../src/composables/internal/useInertOthers.ts","../../src/composables/internal/useOverlayPresence.ts","../../src/composables/internal/useScrollLock.ts","../../src/composables/internal/useModalOverlay.ts"],"sourcesContent":["import type { Ref } from 'vue'\nimport { onScopeDispose, watch } from 'vue'\n\nimport { inertableOutside, markInert } from './inert'\n\n/**\n * Пока слой активен, всё вне его ветки помечено `inert`: от корня оверлея вверх\n * до `<body>`, на каждом уровне — соседи.\n *\n * Это вторая половина модальности: `z-index` перекрывает страницу глазами,\n * `inert` — клавиатурой и скринридером.\n */\nexport function useInertOthers(root: Ref<HTMLElement | null>, active: () => boolean): void {\n let release: (() => void) | undefined\n\n function apply(): void {\n release?.()\n release = markInert(inertableOutside(root.value))\n }\n\n function clear(): void {\n release?.()\n release = undefined\n }\n\n watch(\n () => Boolean(active()) && Boolean(root.value),\n (isActive) => {\n if (isActive)\n apply()\n else clear()\n },\n { immediate: true, flush: 'post' },\n )\n\n onScopeDispose(clear)\n}\n","import type { Ref } from 'vue'\nimport { ref, watch } from 'vue'\n\nexport interface OverlayPresence {\n /** Смонтировано ли поддерево слоя: держится до конца leave-анимации. */\n mounted: Ref<boolean>\n /** Показан ли слой: этим переключаются `<Transition>` внутри. */\n visible: Ref<boolean>\n /** Вызывается из `@after-leave` панели. */\n onPanelAfterLeave: () => void\n}\n\n/**\n * Присутствие оверлея в DOM отдельно от его видимости.\n *\n * Штатный `<Transition>` анимирует свой элемент, но не координирует соседей:\n * убери обёртку по `v-if` — и подложка с панелью исчезнут мгновенно, без\n * leave-анимации. Поэтому присутствие поддерева и видимость слоя — два разных\n * флага: первый снимается только по концу leave-анимации панели.\n *\n * Видимость включается **в том же такте**, что и монтирование: содержимое окна\n * обязано появляться в DOM сразу после открытия — на этом стоит и код\n * потребителя, и внутренние компоненты, которые ищут в панели свои элементы.\n * Enter-анимацию это не отменяет: `<Transition appear>` проигрывает её и на\n * первом рендере ребёнка.\n */\nexport function useOverlayPresence(open: Ref<boolean>): OverlayPresence {\n const mounted = ref(open.value)\n const visible = ref(open.value)\n\n watch(open, (isOpen) => {\n if (isOpen)\n mounted.value = true\n visible.value = isOpen\n })\n\n function onPanelAfterLeave(): void {\n // Пока панель уезжала, слой могли открыть заново — тогда размонтировать\n // нечего и незачем.\n if (!open.value)\n mounted.value = false\n }\n\n return { mounted, visible, onPanelAfterLeave }\n}\n","/**\n * useScrollLock — общий **reference-counted** lock скролла `<body>` для оверлеев\n * (GrModal, GrDrawer, GrImageViewer).\n *\n * Зачем счётчик: состояние `<body>` принадлежит не оверлею, а их совокупности.\n * Держи каждый свой `savedBodyOverflow`, и закрытие A при ещё открытой B вернуло\n * бы странице прокрутку под открытым окном — закрывают не всегда в порядке\n * открытия. Поэтому состояние сохраняется один раз (переход счётчика 0→1) и\n * восстанавливается только когда закрыт последний оверлей (1→0).\n *\n * Плюс компенсация ширины скроллбара: при `overflow: hidden` скроллбар исчезает и\n * контент дёргается вправо — добавляем `padding-right` на его ширину.\n *\n * Отдельная ветка — iOS Safari: там `overflow: hidden` фон не держит, страница\n * продолжает «резинить» под открытым окном. Лечится тем же, чем лечил\n * HeadlessUI (`handleIOSLocking`): гасим `touchmove` вне скроллящихся областей\n * оверлея и возвращаем позицию прокрутки после снятия лока.\n */\n\ninterface SavedBodyStyle {\n overflow: string\n paddingRight: string\n overscrollBehavior: string\n}\n\nlet lockCount = 0\nlet saved: SavedBodyStyle | null = null\nlet savedScrollY = 0\nlet releaseTouchGuard: (() => void) | null = null\n\n/**\n * iOS определяем по платформе, а не по ширине экрана: лечение специфично для\n * движка, а не для размера. `maxTouchPoints` отличает iPadOS, который со времён\n * 13-й версии представляется десктопным Mac.\n */\nfunction isIOS(): boolean {\n if (typeof navigator === 'undefined')\n return false\n return /iP(?:hone|ad|od)/.test(navigator.platform)\n || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)\n}\n\n/** Прокручиваемая область оверлея — единственное, чему `touchmove` разрешён. */\nfunction isScrollableOverlayArea(target: EventTarget | null): boolean {\n if (!(target instanceof Element))\n return false\n\n for (let node: Element | null = target; node; node = node.parentElement) {\n if (!(node instanceof HTMLElement))\n continue\n if (node.hasAttribute('data-gr-overlay-root'))\n return true\n }\n\n return false\n}\n\nfunction applyTouchGuard(): void {\n if (!isIOS())\n return\n\n const onTouchMove = (event: TouchEvent): void => {\n // Внутри оверлея скролл законен (длинное окно, лента изображений), а всё\n // остальное — это и есть фон, который лок обязан держать.\n if (isScrollableOverlayArea(event.target))\n return\n if (event.cancelable)\n event.preventDefault()\n }\n\n document.addEventListener('touchmove', onTouchMove, { passive: false })\n releaseTouchGuard = () => document.removeEventListener('touchmove', onTouchMove)\n}\n\nfunction getScrollbarWidth(): number {\n return window.innerWidth - document.documentElement.clientWidth\n}\n\nfunction applyLock(): void {\n const body = document.body\n saved = {\n overflow: body.style.overflow,\n paddingRight: body.style.paddingRight,\n overscrollBehavior: body.style.overscrollBehavior,\n }\n savedScrollY = window.scrollY\n\n // Ширину скроллбара считаем ДО `overflow: hidden` (после — `clientWidth` меняется).\n const scrollbarWidth = getScrollbarWidth()\n\n body.style.overflow = 'hidden'\n // Прокрутка, «доехавшая» до края внутри окна, не должна продолжаться фоном.\n body.style.overscrollBehavior = 'contain'\n if (scrollbarWidth > 0) {\n const currentPadding = Number.parseFloat(getComputedStyle(body).paddingRight) || 0\n body.style.paddingRight = `${currentPadding + scrollbarWidth}px`\n }\n\n applyTouchGuard()\n}\n\nfunction releaseLock(): void {\n releaseTouchGuard?.()\n releaseTouchGuard = null\n\n if (!saved)\n return\n document.body.style.overflow = saved.overflow\n document.body.style.paddingRight = saved.paddingRight\n document.body.style.overscrollBehavior = saved.overscrollBehavior\n saved = null\n\n // iOS сдвигает страницу, пока фон заблокирован; возвращаем её на место.\n if (isIOS() && window.scrollY !== savedScrollY)\n window.scrollTo(0, savedScrollY)\n}\n\n/**\n * Возвращает пару `lock`/`unlock`, идемпотентную **в пределах одного инстанса**\n * (повторный `lock()` без `unlock()` не увеличивает глобальный счётчик дважды).\n * Глобальный счётчик разделяется всеми оверлеями.\n */\nexport function useScrollLock() {\n const isClient = typeof window !== 'undefined'\n let held = false\n\n function lock(): void {\n if (!isClient || held)\n return\n held = true\n lockCount += 1\n if (lockCount === 1)\n applyLock()\n }\n\n function unlock(): void {\n if (!isClient || !held)\n return\n held = false\n lockCount = Math.max(0, lockCount - 1)\n if (lockCount === 0)\n releaseLock()\n }\n\n return { lock, unlock }\n}\n\n/** Тестовая/служебная очистка глобального состояния. */\nexport function resetScrollLock(): void {\n lockCount = 0\n if (typeof document !== 'undefined')\n releaseLock()\n saved = null\n}\n","import type { ComputedRef, Ref } from 'vue'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\n\nimport { useGrThemeAttrs } from '../../components/GrConfigProvider/context'\nimport { modalLayerZIndex } from './overlayStack'\nimport { useFocusTrap } from '../useFocusTrap'\nimport { useOverlayLayer } from '../useOverlayLayer'\nimport { usePortalTarget } from '../usePortalTarget'\nimport { useInertOthers } from './useInertOthers'\nimport { useOverlayPresence } from './useOverlayPresence'\nimport { useScrollLock } from './useScrollLock'\n\n/**\n * Модальный слой целиком: одна сборка на весь пакет.\n *\n * Модальность собиралась вручную в трёх компонентах (`GrModal`, `GrDrawer`,\n * `GrImageViewer`) из шести примитивов, и сборка повторялась дословно. Дело не\n * в объёме: в этой проводке сидят инварианты, каждый из которых при пропуске\n * даёт тихий баг доступности, а не заметную поломку. Здесь они собраны в одном\n * месте — забыть часть модального слоя больше нельзя.\n *\n * Что именно неочевидно:\n *\n * - **`restoreFocus: false` у ловушки.** Возврат фокуса принадлежит стеку\n * слоёв: у него правило строже — вернуть, только если на момент закрытия\n * фокус ещё был внутри слоя. Две системы возврата подрались бы за фокус.\n * - **`containers: layer.rootsAbove`.** Панель селекта, открытого ВНУТРИ окна,\n * телепортирована в `body` и лежит вне поддерева панели. Без этого списка\n * ловушка считала бы её «снаружи» и отбирала фокус.\n * - **Ловушка и `inert` работают, только пока слой верхний.** Иначе нижнее\n * окно ворует фокус у открытого поверх него, а `inert` гасит собственную\n * панель вместе со страницей.\n * - **Клик по подложке считается только тот, что на ней и начался.** Иначе\n * выделение текста мышью или перетаскивание, отпущенное за пределами панели,\n * закрывает слой.\n *\n * Чего композабл НЕ делает: не рисует разметку. Корневой `div`, подложка и\n * панель у трёх компонентов различаются по существу (обёртки скролла у окна,\n * сквозные клики у немодальной панели, слои хрома у просмотрщика), а классами\n * общий модуль владеть не вправе — пресет гранулярности подмешивает safelist\n * только по директориям выбранных компонентов.\n */\nexport interface UseModalOverlayOptions {\n /**\n * Модальный ли слой: блокирует страницу, держит фокус, гасит нижние окна.\n * Геттером — там, где модальность включается пропом (`GrDrawer`).\n */\n modal?: boolean | (() => boolean)\n /** Закрывать ли по Esc. Геттер — проп компонента реактивен. */\n closeOnEscape?: () => boolean\n /** Закрывать ли по клику в подложку; читается обработчиками `backdrop`. */\n closeOnBackdrop?: () => boolean\n /** Панель слоя: контейнер ловушки фокуса и её запасной приёмник. */\n panel: Ref<HTMLElement | null>\n /**\n * Свой корень слоя. У якорного оверлея (`GrPopover`) корень и панель — один\n * элемент: в портал уезжает сама панель, отдельной обёртки нет. Не задан —\n * композабл заводит корень сам, как у центрированных окон.\n */\n root?: Ref<HTMLElement | null>\n /**\n * Имя CSS-переменной слоя. Escape-hatch мимо `--gr-z-modal` — им пользуется\n * просмотрщик. Глубина слоя прибавляется и к подменённой переменной.\n */\n zIndexVar?: () => string | undefined\n /**\n * Точечное переопределение точки монтирования (проп `teleportTo`). По\n * умолчанию — общий портал оверлеев.\n */\n teleportTo?: () => string | HTMLElement | undefined\n /**\n * Кому отдать фокус при открытии. Не задан — первому фокусируемому внутри\n * панели (правило `useFocusTrap`): просмотрщику нужна именно кнопка тулбара,\n * а окну — сама панель, и оно передаёт её явно.\n */\n initialFocus?: () => HTMLElement | null | undefined\n /**\n * Блокировать ли скролл страницы. По умолчанию — пока слой открыт и модален:\n * немодальная панель существует ровно ради работы со страницей под ней.\n */\n lockScroll?: () => boolean\n}\n\nexport interface ModalOverlay {\n /** Корень слоя: цель `ref` в шаблоне, хозяин `inert` и корень для стека слоёв. */\n rootEl: Ref<HTMLElement | null>\n /** Смонтировано ли поддерево: держится до конца leave-анимации панели. */\n isMounted: Ref<boolean>\n /** Показан ли слой: этим переключаются `<Transition>` внутри. */\n isVisible: Ref<boolean>\n /** Верхний ли это слой сейчас. */\n isTopmost: Ref<boolean>\n /** Значение атрибута `inert` для корня: слой перестал быть верхним. */\n inertAttr: ComputedRef<true | undefined>\n /**\n * Высота слоя: базовый токен плюс позиция в стеке.\n *\n * Один токен на все модальные слои означал бы, что порядок отрисовки решает\n * порядок узлов в портале, а он задан **созданием** телепорта, а не\n * открытием: статически объявленный диалог вставал бы под окном, открытым\n * позже, и оказывался невидимым — при том что стек считает верхним его.\n */\n layerZIndex: ComputedRef<string>\n portalTarget: ComputedRef<string | HTMLElement>\n teleportEnabled: ComputedRef<boolean>\n /** `data-theme` на телепортированный корень: в DOM он вне обёртки провайдера. */\n themeAttrs: ComputedRef<{ 'data-theme'?: string }>\n /** Для `@after-leave` панели. Компонент оборачивает, если ему нужен эмит `closed`. */\n onPanelAfterLeave: () => void\n /**\n * Обработчики подложки вместе с guard'ом «клик начался на ней». Имена — под\n * `v-on=\"backdrop\"`: объектный синтаксис ждёт имена событий, а не пропов.\n */\n backdrop: {\n mousedown: (event: MouseEvent) => void\n click: (event: MouseEvent) => void\n }\n}\n\nexport function useModalOverlay(\n open: Ref<boolean>,\n onDismiss: () => void,\n options: UseModalOverlayOptions,\n): ModalOverlay {\n const isModal = (): boolean =>\n typeof options.modal === 'function' ? options.modal() : options.modal ?? true\n\n const rootEl = options.root ?? ref<HTMLElement | null>(null)\n const isTopmost = ref(true)\n\n const inertAttr = computed(() => (open.value && isModal() && !isTopmost.value ? true : undefined))\n\n // Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n // рендер не совпадёт с серверным и сломается гидрация.\n const { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(options.teleportTo)\n\n // Панель уезжает в `body`, то есть вне обёртки провайдера, и `data-theme` с\n // неё не наследуется. В дереве компонентов слой остаётся внутри — `inject`\n // доходит, и тему он ставит себе сам.\n const themeAttrs = useGrThemeAttrs()\n\n const { mounted: isMounted, visible: isVisible, onPanelAfterLeave } = useOverlayPresence(open)\n\n const layer = useOverlayLayer(open, onDismiss, {\n modal: isModal,\n closeOnEscape: options.closeOnEscape,\n onTopmostChange: (value) => { isTopmost.value = value },\n root: rootEl,\n })\n\n const layerZIndex = computed(() => modalLayerZIndex(\n layer.depth.value,\n options.zIndexVar?.() ?? '--gr-z-modal',\n ))\n\n useFocusTrap(options.panel, {\n active: () => open.value && isModal() && isTopmost.value,\n initialFocus: options.initialFocus,\n fallbackFocus: () => options.panel.value,\n containers: layer.rootsAbove,\n restoreFocus: false,\n })\n\n useInertOthers(rootEl, () => open.value && isModal() && isTopmost.value)\n\n // Общий reference-counted lock: несколько открытых оверлеев снимают блокировку\n // независимо от порядка закрытия, ширина скроллбара компенсируется.\n const { lock, unlock } = useScrollLock()\n\n watch(\n () => options.lockScroll?.() ?? (open.value && isModal()),\n (locked) => {\n if (locked)\n lock()\n else unlock()\n },\n { immediate: true },\n )\n\n onBeforeUnmount(unlock)\n\n let pointerDownOnBackdrop = false\n\n return {\n rootEl,\n isMounted,\n isVisible,\n isTopmost,\n inertAttr,\n layerZIndex,\n portalTarget,\n teleportEnabled,\n themeAttrs,\n onPanelAfterLeave,\n backdrop: {\n mousedown(event: MouseEvent): void {\n pointerDownOnBackdrop = event.target === event.currentTarget\n },\n click(event: MouseEvent): void {\n const startedHere = pointerDownOnBackdrop\n pointerDownOnBackdrop = false\n\n if (!startedHere || event.target !== event.currentTarget)\n return\n if (options.closeOnBackdrop?.() === false)\n return\n\n onDismiss()\n },\n },\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useModalOverlay-CKCQkGdB.js","names":[],"sources":["../../src/composables/internal/useInertOthers.ts","../../src/composables/internal/useOverlayPresence.ts","../../src/composables/internal/useScrollLock.ts","../../src/composables/internal/useModalOverlay.ts"],"sourcesContent":["import type { Ref } from 'vue'\nimport { onScopeDispose, watch } from 'vue'\n\nimport { inertableOutside, markInert } from './inert'\n\n/**\n * Пока слой активен, всё вне его ветки помечено `inert`: от корня оверлея вверх\n * до `<body>`, на каждом уровне — соседи.\n *\n * Это вторая половина модальности: `z-index` перекрывает страницу глазами,\n * `inert` — клавиатурой и скринридером.\n */\nexport function useInertOthers(root: Ref<HTMLElement | null>, active: () => boolean): void {\n let release: (() => void) | undefined\n\n function apply(): void {\n release?.()\n release = markInert(inertableOutside(root.value))\n }\n\n function clear(): void {\n release?.()\n release = undefined\n }\n\n watch(\n () => Boolean(active()) && Boolean(root.value),\n (isActive) => {\n if (isActive)\n apply()\n else clear()\n },\n { immediate: true, flush: 'post' },\n )\n\n onScopeDispose(clear)\n}\n","import type { Ref } from 'vue'\nimport { ref, watch } from 'vue'\n\nexport interface OverlayPresence {\n /** Смонтировано ли поддерево слоя: держится до конца leave-анимации. */\n mounted: Ref<boolean>\n /** Показан ли слой: этим переключаются `<Transition>` внутри. */\n visible: Ref<boolean>\n /** Вызывается из `@after-leave` панели. */\n onPanelAfterLeave: () => void\n}\n\n/**\n * Присутствие оверлея в DOM отдельно от его видимости.\n *\n * Штатный `<Transition>` анимирует свой элемент, но не координирует соседей:\n * убери обёртку по `v-if` — и подложка с панелью исчезнут мгновенно, без\n * leave-анимации. Поэтому присутствие поддерева и видимость слоя — два разных\n * флага: первый снимается только по концу leave-анимации панели.\n *\n * Видимость включается **в том же такте**, что и монтирование: содержимое окна\n * обязано появляться в DOM сразу после открытия — на этом стоит и код\n * потребителя, и внутренние компоненты, которые ищут в панели свои элементы.\n * Enter-анимацию это не отменяет: `<Transition appear>` проигрывает её и на\n * первом рендере ребёнка.\n */\nexport function useOverlayPresence(open: Ref<boolean>): OverlayPresence {\n const mounted = ref(open.value)\n const visible = ref(open.value)\n\n watch(open, (isOpen) => {\n if (isOpen)\n mounted.value = true\n visible.value = isOpen\n })\n\n function onPanelAfterLeave(): void {\n // Пока панель уезжала, слой могли открыть заново — тогда размонтировать\n // нечего и незачем.\n if (!open.value)\n mounted.value = false\n }\n\n return { mounted, visible, onPanelAfterLeave }\n}\n","/**\n * useScrollLock — общий **reference-counted** lock скролла `<body>` для оверлеев\n * (GrModal, GrDrawer, GrImageViewer).\n *\n * Зачем счётчик: состояние `<body>` принадлежит не оверлею, а их совокупности.\n * Держи каждый свой `savedBodyOverflow`, и закрытие A при ещё открытой B вернуло\n * бы странице прокрутку под открытым окном — закрывают не всегда в порядке\n * открытия. Поэтому состояние сохраняется один раз (переход счётчика 0→1) и\n * восстанавливается только когда закрыт последний оверлей (1→0).\n *\n * Плюс компенсация ширины скроллбара: при `overflow: hidden` скроллбар исчезает и\n * контент дёргается вправо — добавляем `padding-right` на его ширину.\n *\n * Отдельная ветка — iOS Safari: там `overflow: hidden` фон не держит, страница\n * продолжает «резинить» под открытым окном. Лечится тем же, чем лечил\n * HeadlessUI (`handleIOSLocking`): гасим `touchmove` вне скроллящихся областей\n * оверлея и возвращаем позицию прокрутки после снятия лока.\n */\n\ninterface SavedBodyStyle {\n overflow: string\n paddingRight: string\n overscrollBehavior: string\n}\n\nlet lockCount = 0\nlet saved: SavedBodyStyle | null = null\nlet savedScrollY = 0\nlet releaseTouchGuard: (() => void) | null = null\n\n/**\n * iOS определяем по платформе, а не по ширине экрана: лечение специфично для\n * движка, а не для размера. `maxTouchPoints` отличает iPadOS, который со времён\n * 13-й версии представляется десктопным Mac.\n */\nfunction isIOS(): boolean {\n if (typeof navigator === 'undefined')\n return false\n return /iP(?:hone|ad|od)/.test(navigator.platform)\n || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)\n}\n\n/** Прокручиваемая область оверлея — единственное, чему `touchmove` разрешён. */\nfunction isScrollableOverlayArea(target: EventTarget | null): boolean {\n if (!(target instanceof Element))\n return false\n\n for (let node: Element | null = target; node; node = node.parentElement) {\n if (!(node instanceof HTMLElement))\n continue\n if (node.hasAttribute('data-gr-overlay-root'))\n return true\n }\n\n return false\n}\n\nfunction applyTouchGuard(): void {\n if (!isIOS())\n return\n\n const onTouchMove = (event: TouchEvent): void => {\n // Внутри оверлея скролл законен (длинное окно, лента изображений), а всё\n // остальное — это и есть фон, который лок обязан держать.\n if (isScrollableOverlayArea(event.target))\n return\n if (event.cancelable)\n event.preventDefault()\n }\n\n document.addEventListener('touchmove', onTouchMove, { passive: false })\n releaseTouchGuard = () => document.removeEventListener('touchmove', onTouchMove)\n}\n\nfunction getScrollbarWidth(): number {\n return window.innerWidth - document.documentElement.clientWidth\n}\n\nfunction applyLock(): void {\n const body = document.body\n saved = {\n overflow: body.style.overflow,\n paddingRight: body.style.paddingRight,\n overscrollBehavior: body.style.overscrollBehavior,\n }\n savedScrollY = window.scrollY\n\n // Ширину скроллбара считаем ДО `overflow: hidden` (после — `clientWidth` меняется).\n const scrollbarWidth = getScrollbarWidth()\n\n body.style.overflow = 'hidden'\n // Прокрутка, «доехавшая» до края внутри окна, не должна продолжаться фоном.\n body.style.overscrollBehavior = 'contain'\n if (scrollbarWidth > 0) {\n const currentPadding = Number.parseFloat(getComputedStyle(body).paddingRight) || 0\n body.style.paddingRight = `${currentPadding + scrollbarWidth}px`\n }\n\n applyTouchGuard()\n}\n\nfunction releaseLock(): void {\n releaseTouchGuard?.()\n releaseTouchGuard = null\n\n if (!saved)\n return\n document.body.style.overflow = saved.overflow\n document.body.style.paddingRight = saved.paddingRight\n document.body.style.overscrollBehavior = saved.overscrollBehavior\n saved = null\n\n // iOS сдвигает страницу, пока фон заблокирован; возвращаем её на место.\n if (isIOS() && window.scrollY !== savedScrollY)\n window.scrollTo(0, savedScrollY)\n}\n\n/**\n * Возвращает пару `lock`/`unlock`, идемпотентную **в пределах одного инстанса**\n * (повторный `lock()` без `unlock()` не увеличивает глобальный счётчик дважды).\n * Глобальный счётчик разделяется всеми оверлеями.\n */\nexport function useScrollLock() {\n const isClient = typeof window !== 'undefined'\n let held = false\n\n function lock(): void {\n if (!isClient || held)\n return\n held = true\n lockCount += 1\n if (lockCount === 1)\n applyLock()\n }\n\n function unlock(): void {\n if (!isClient || !held)\n return\n held = false\n lockCount = Math.max(0, lockCount - 1)\n if (lockCount === 0)\n releaseLock()\n }\n\n return { lock, unlock }\n}\n\n/** Тестовая/служебная очистка глобального состояния. */\nexport function resetScrollLock(): void {\n lockCount = 0\n if (typeof document !== 'undefined')\n releaseLock()\n saved = null\n}\n","import type { ComputedRef, Ref } from 'vue'\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\n\nimport { useGrThemeAttrs } from '../../components/GrConfigProvider/context'\nimport { modalLayerZIndex } from './overlayStack'\nimport { useFocusTrap } from '../useFocusTrap'\nimport { useOverlayLayer } from '../useOverlayLayer'\nimport { usePortalTarget } from '../usePortalTarget'\nimport { useInertOthers } from './useInertOthers'\nimport { useOverlayPresence } from './useOverlayPresence'\nimport { useScrollLock } from './useScrollLock'\n\n/**\n * Модальный слой целиком: одна сборка на весь пакет.\n *\n * Модальность собиралась вручную в трёх компонентах (`GrModal`, `GrDrawer`,\n * `GrImageViewer`) из шести примитивов, и сборка повторялась дословно. Дело не\n * в объёме: в этой проводке сидят инварианты, каждый из которых при пропуске\n * даёт тихий баг доступности, а не заметную поломку. Здесь они собраны в одном\n * месте — забыть часть модального слоя больше нельзя.\n *\n * Что именно неочевидно:\n *\n * - **`restoreFocus: false` у ловушки.** Возврат фокуса принадлежит стеку\n * слоёв: у него правило строже — вернуть, только если на момент закрытия\n * фокус ещё был внутри слоя. Две системы возврата подрались бы за фокус.\n * - **`containers: layer.rootsAbove`.** Панель селекта, открытого ВНУТРИ окна,\n * телепортирована в `body` и лежит вне поддерева панели. Без этого списка\n * ловушка считала бы её «снаружи» и отбирала фокус.\n * - **Ловушка и `inert` работают, только пока слой верхний.** Иначе нижнее\n * окно ворует фокус у открытого поверх него, а `inert` гасит собственную\n * панель вместе со страницей.\n * - **Клик по подложке считается только тот, что на ней и начался.** Иначе\n * выделение текста мышью или перетаскивание, отпущенное за пределами панели,\n * закрывает слой.\n *\n * Чего композабл НЕ делает: не рисует разметку. Корневой `div`, подложка и\n * панель у трёх компонентов различаются по существу (обёртки скролла у окна,\n * сквозные клики у немодальной панели, слои хрома у просмотрщика), а классами\n * общий модуль владеть не вправе — пресет гранулярности подмешивает safelist\n * только по директориям выбранных компонентов.\n */\nexport interface UseModalOverlayOptions {\n /**\n * Модальный ли слой: блокирует страницу, держит фокус, гасит нижние окна.\n * Геттером — там, где модальность включается пропом (`GrDrawer`).\n */\n modal?: boolean | (() => boolean)\n /** Закрывать ли по Esc. Геттер — проп компонента реактивен. */\n closeOnEscape?: () => boolean\n /** Закрывать ли по клику в подложку; читается обработчиками `backdrop`. */\n closeOnBackdrop?: () => boolean\n /** Панель слоя: контейнер ловушки фокуса и её запасной приёмник. */\n panel: Ref<HTMLElement | null>\n /**\n * Свой корень слоя. У якорного оверлея (`GrPopover`) корень и панель — один\n * элемент: в портал уезжает сама панель, отдельной обёртки нет. Не задан —\n * композабл заводит корень сам, как у центрированных окон.\n */\n root?: Ref<HTMLElement | null>\n /**\n * Имя CSS-переменной слоя. Escape-hatch мимо `--gr-z-modal` — им пользуется\n * просмотрщик. Глубина слоя прибавляется и к подменённой переменной.\n */\n zIndexVar?: () => string | undefined\n /**\n * Точечное переопределение точки монтирования (проп `teleportTo`). По\n * умолчанию — общий портал оверлеев.\n */\n teleportTo?: () => string | HTMLElement | undefined\n /**\n * Кому отдать фокус при открытии. Не задан — первому фокусируемому внутри\n * панели (правило `useFocusTrap`): просмотрщику нужна именно кнопка тулбара,\n * а окну — сама панель, и оно передаёт её явно.\n */\n initialFocus?: () => HTMLElement | null | undefined\n /**\n * Блокировать ли скролл страницы. По умолчанию — пока слой открыт и модален:\n * немодальная панель существует ровно ради работы со страницей под ней.\n */\n lockScroll?: () => boolean\n}\n\nexport interface ModalOverlay {\n /** Корень слоя: цель `ref` в шаблоне, хозяин `inert` и корень для стека слоёв. */\n rootEl: Ref<HTMLElement | null>\n /** Смонтировано ли поддерево: держится до конца leave-анимации панели. */\n isMounted: Ref<boolean>\n /** Показан ли слой: этим переключаются `<Transition>` внутри. */\n isVisible: Ref<boolean>\n /** Верхний ли это слой сейчас. */\n isTopmost: Ref<boolean>\n /** Значение атрибута `inert` для корня: слой перестал быть верхним. */\n inertAttr: ComputedRef<true | undefined>\n /**\n * Высота слоя: базовый токен плюс позиция в стеке.\n *\n * Один токен на все модальные слои означал бы, что порядок отрисовки решает\n * порядок узлов в портале, а он задан **созданием** телепорта, а не\n * открытием: статически объявленный диалог вставал бы под окном, открытым\n * позже, и оказывался невидимым — при том что стек считает верхним его.\n */\n layerZIndex: ComputedRef<string>\n portalTarget: ComputedRef<string | HTMLElement>\n teleportEnabled: ComputedRef<boolean>\n /** `data-theme` на телепортированный корень: в DOM он вне обёртки провайдера. */\n themeAttrs: ComputedRef<{ 'data-theme'?: string }>\n /** Для `@after-leave` панели. Компонент оборачивает, если ему нужен эмит `closed`. */\n onPanelAfterLeave: () => void\n /**\n * Обработчики подложки вместе с guard'ом «клик начался на ней». Имена — под\n * `v-on=\"backdrop\"`: объектный синтаксис ждёт имена событий, а не пропов.\n */\n backdrop: {\n mousedown: (event: MouseEvent) => void\n click: (event: MouseEvent) => void\n }\n}\n\nexport function useModalOverlay(\n open: Ref<boolean>,\n onDismiss: () => void,\n options: UseModalOverlayOptions,\n): ModalOverlay {\n const isModal = (): boolean =>\n typeof options.modal === 'function' ? options.modal() : options.modal ?? true\n\n const rootEl = options.root ?? ref<HTMLElement | null>(null)\n const isTopmost = ref(true)\n\n const inertAttr = computed(() => (open.value && isModal() && !isTopmost.value ? true : undefined))\n\n // Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n // рендер не совпадёт с серверным и сломается гидрация.\n const { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(options.teleportTo)\n\n // Панель уезжает в `body`, то есть вне обёртки провайдера, и `data-theme` с\n // неё не наследуется. В дереве компонентов слой остаётся внутри — `inject`\n // доходит, и тему он ставит себе сам.\n const themeAttrs = useGrThemeAttrs()\n\n const { mounted: isMounted, visible: isVisible, onPanelAfterLeave } = useOverlayPresence(open)\n\n const layer = useOverlayLayer(open, onDismiss, {\n modal: isModal,\n closeOnEscape: options.closeOnEscape,\n onTopmostChange: (value) => { isTopmost.value = value },\n root: rootEl,\n })\n\n const layerZIndex = computed(() => modalLayerZIndex(\n layer.depth.value,\n options.zIndexVar?.() ?? '--gr-z-modal',\n ))\n\n useFocusTrap(options.panel, {\n active: () => open.value && isModal() && isTopmost.value,\n initialFocus: options.initialFocus,\n fallbackFocus: () => options.panel.value,\n containers: layer.rootsAbove,\n restoreFocus: false,\n })\n\n useInertOthers(rootEl, () => open.value && isModal() && isTopmost.value)\n\n // Общий reference-counted lock: несколько открытых оверлеев снимают блокировку\n // независимо от порядка закрытия, ширина скроллбара компенсируется.\n const { lock, unlock } = useScrollLock()\n\n watch(\n () => options.lockScroll?.() ?? (open.value && isModal()),\n (locked) => {\n if (locked)\n lock()\n else unlock()\n },\n { immediate: true },\n )\n\n onBeforeUnmount(unlock)\n\n let pointerDownOnBackdrop = false\n\n return {\n rootEl,\n isMounted,\n isVisible,\n isTopmost,\n inertAttr,\n layerZIndex,\n portalTarget,\n teleportEnabled,\n themeAttrs,\n onPanelAfterLeave,\n backdrop: {\n mousedown(event: MouseEvent): void {\n pointerDownOnBackdrop = event.target === event.currentTarget\n },\n click(event: MouseEvent): void {\n const startedHere = pointerDownOnBackdrop\n pointerDownOnBackdrop = false\n\n if (!startedHere || event.target !== event.currentTarget)\n return\n if (options.closeOnBackdrop?.() === false)\n return\n\n onDismiss()\n },\n },\n }\n}\n"],"mappings":"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"}
|