@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrCarousel-CBj-PEPB.js","names":[],"sources":["../../../../src/components/GrCarousel/carouselNavigation.ts","../../../../src/components/GrCarousel/composables/useCarouselAutoplay.ts","../../../../src/components/GrCarousel/composables/useCarouselSwipe.ts","../../../../src/components/GrCarousel/grCarouselContext.ts","../../../../src/components/GrCarousel/GrCarousel.vue","../../../../src/components/GrCarousel/GrCarousel.vue","../../../../src/components/GrCarousel/GrCarouselSlide.vue","../../../../src/components/GrCarousel/GrCarouselSlide.vue"],"sourcesContent":["/** Сколько пикселей должен пройти указатель, чтобы это считалось листанием. */\nexport const SWIPE_THRESHOLD_PX = 60\n\n/**\n * Во сколько раз горизонталь обязана превысить вертикаль. Ниже этого жест\n * считается вертикальной прокруткой страницы и ленту не двигает: палец редко\n * идёт строго по оси, и без фильтра карусель перехватывала бы скролл.\n */\nexport const SWIPE_AXIS_RATIO = 1.5\n\n/**\n * Доля ширины вьюпорта, начиная с которой жест засчитывается. Работает вместе\n * с {@link SWIPE_THRESHOLD_PX} по максимуму: 60px на герое шириной 1200px —\n * это нервно, а на узкой карточке доля выродилась бы в пару пикселей.\n */\nexport const SWIPE_THRESHOLD_RATIO = 0.15\n\n/** Во сколько раз вязче идёт лента, когда листать в эту сторону уже некуда. */\nexport const SWIPE_RESISTANCE = 4\n\n/**\n * Логическое направление жеста: `1` — вперёд, `-1` — назад, `0` — не свайп.\n *\n * `dx` физический, в пикселях экрана; разворот под RTL — забота вызывающего,\n * модуль про направление письма не знает. Палец, ушедший влево, листает вперёд:\n * содержимое едет за пальцем, как в нативной прокрутке.\n *\n * Отдельным модулем, потому что в jsdom раскладки нет и через смонтированный\n * компонент ни одна ветка не проверяется — тот же довод, что у\n * {@link resolveScrollOverflow}.\n */\nexport function resolveSwipeDirection(\n dx: number,\n dy: number,\n threshold: number = SWIPE_THRESHOLD_PX,\n): -1 | 0 | 1 {\n if (Math.abs(dx) < threshold)\n return 0\n\n if (Math.abs(dx) < Math.abs(dy) * SWIPE_AXIS_RATIO)\n return 0\n\n return dx < 0 ? 1 : -1\n}\n\n/**\n * Порог жеста для ленты шириной `width`. При нулевой ширине — а в jsdom она\n * всегда нулевая — вырождается в пиксельный минимум, и жест остаётся\n * проверяемым.\n */\nexport function swipeThresholdFor(width: number): number {\n return Math.max(SWIPE_THRESHOLD_PX, width * SWIPE_THRESHOLD_RATIO)\n}\n\n/** Смещение ленты за пальцем: за краем — вязкое, иначе один в один. */\nexport function resistOffset(delta: number, atEdge: boolean): number {\n return atEdge ? delta / SWIPE_RESISTANCE : delta\n}\n\n/**\n * Индекс, зажатый в границы ленты. Пустая лента даёт `0`: слайда с таким\n * номером нет, но отрицательный индекс уехал бы в CSS-переменную трека.\n */\nexport function clampIndex(index: number, count: number): number {\n if (count <= 0)\n return 0\n\n if (!Number.isFinite(index))\n return 0\n\n return Math.min(Math.max(Math.trunc(index), 0), count - 1)\n}\n\n/**\n * Шаг по ленте. Без `loop` на краю возвращает тот же индекс — вызывающий по\n * этому признаку и гасит стрелку, отдельного предиката не нужно.\n */\nexport function stepIndex(index: number, delta: number, count: number, loop: boolean): number {\n if (count <= 0)\n return 0\n\n const current = clampIndex(index, count)\n const next = current + delta\n\n if (loop)\n return ((next % count) + count) % count\n\n return clampIndex(next, count)\n}\n\n/**\n * Насколько прокрутить полосу переключателей, чтобы кадр был виден.\n *\n * Считается своей арифметикой, а не `scrollIntoView`: тот прокручивает **всех**\n * предков, включая документ, — и карусель, уехавшая под сгиб, на каждом шаге\n * автопрокрутки утаскивала бы страницу обратно к себе. Здесь двигается только\n * сама полоса.\n *\n * Движение минимальное: элемент уже виден — `scrollLeft` не меняется вовсе.\n */\nexport function stripScrollLeft(\n scrollLeft: number,\n viewport: number,\n itemStart: number,\n itemEnd: number,\n padding = 0,\n): number {\n if (viewport <= 0)\n return scrollLeft\n\n if (itemStart - padding < scrollLeft)\n return Math.max(0, itemStart - padding)\n\n if (itemEnd + padding > scrollLeft + viewport)\n return itemEnd + padding - viewport\n\n return scrollLeft\n}\n","import { computed, onScopeDispose, ref, watchEffect } from 'vue'\nimport type { ComputedRef } from 'vue'\n\nexport interface UseCarouselAutoplayOptions {\n /** Пауза между слайдами, мс. */\n interval: () => number\n /** Показ включён: проп задан и его никто не остановил. */\n enabled: () => boolean\n /**\n * Отсчёт приостановлен — курсор над лентой, идёт жест, вкладка в фоне.\n * Это **не** остановка: остаток сохраняется, и по снятию паузы лента\n * досчитывает его, а не начинает интервал заново.\n */\n paused: () => boolean\n /** Шаг ленты. */\n advance: () => void\n}\n\nexport interface UseCarouselAutoplayReturn {\n /** Заведён ли отсчёт прямо сейчас. Пауза его снимает, намерение показа — нет. */\n running: ComputedRef<boolean>\n /** Забыть остаток и отсчитать интервал заново — после смены слайда извне. */\n restart: () => void\n}\n\n/**\n * Таймер автопрокрутки с паузой по остатку.\n *\n * Модель взята у `useToast` (`{ handle, remaining, startedAt }`), и `setInterval`\n * здесь не годится принципиально: паузу, сохраняющую остаток, на нём не\n * выразить — курсор, снятый за полсекунды до шага, откладывал бы шаг на полный\n * интервал.\n *\n * Композабл локальный: публичный потребовал бы записей в трёх реестрах пакета,\n * а переиспользовать его сегодня некому.\n */\nexport function useCarouselAutoplay(options: UseCarouselAutoplayOptions): UseCarouselAutoplayReturn {\n let handle: number | null = null\n let remaining = 0\n let startedAt = 0\n\n const armed = ref(false)\n\n function clear(): void {\n if (handle !== null) {\n clearTimeout(handle)\n handle = null\n }\n armed.value = false\n }\n\n function arm(): void {\n // На сервере таймеру взяться неоткуда, и заводить его там нечего.\n if (typeof window === 'undefined' || remaining <= 0)\n return\n\n startedAt = Date.now()\n armed.value = true\n handle = window.setTimeout(() => {\n handle = null\n remaining = options.interval()\n options.advance()\n\n // Шаг мог упереться в край без `loop` — тогда показ уже выключен.\n if (options.enabled() && !options.paused())\n arm()\n else clear()\n }, remaining)\n }\n\n function pause(): void {\n if (handle === null) {\n armed.value = false\n return\n }\n\n clearTimeout(handle)\n handle = null\n armed.value = false\n remaining = Math.max(0, remaining - (Date.now() - startedAt))\n }\n\n function restart(): void {\n clear()\n remaining = options.interval()\n if (options.enabled() && !options.paused())\n arm()\n }\n\n watchEffect(() => {\n // `interval()` читается ради зависимости: смена паузы обязана перезавести таймер.\n const ms = options.interval()\n\n if (!options.enabled() || options.paused() || ms <= 0) {\n pause()\n return\n }\n\n if (handle !== null)\n return\n\n if (remaining <= 0)\n remaining = ms\n\n arm()\n })\n\n onScopeDispose(clear)\n\n return { running: computed(() => armed.value), restart }\n}\n","import { ref } from 'vue'\nimport type { Ref } from 'vue'\n\nimport { useDragGesture } from '../../../composables/useDragGesture'\nimport {\n resistOffset,\n resolveSwipeDirection,\n SWIPE_AXIS_RATIO,\n swipeThresholdFor,\n} from '../carouselNavigation'\n\n/**\n * Что внутри слайда остаётся нажатием, а не превращается в протяжку. Ссылка и\n * кнопка в онбординг-слайде — обычный интерактив, и жест их перехватывать\n * не вправе (приём `GrToaster`).\n */\nconst INTERACTIVE_SELECTOR = 'a[href], button, input, textarea, select, summary, [role=\"button\"], [contenteditable]'\n\nexport interface UseCarouselSwipeOptions {\n disabled: () => boolean\n /** Вьюпорт: у него спрашиваются ширина и направление письма. */\n viewport: () => HTMLElement | null\n /** Порог пройден. Направление логическое: `1` — вперёд, `-1` — назад. */\n onSwipe: (direction: 1 | -1) => void\n /** Листать в эту сторону некуда — жест идёт вязко. */\n atEdge: (direction: 1 | -1) => boolean\n /** Жест начался: показ пора ставить на паузу. */\n onStart?: () => void\n /**\n * Ось движения ленты. По вертикали ведущей становится `dy`, а поперечная\n * прокрутка страницы отдаётся ей же — иначе карусель перехватывала бы скролл.\n */\n orientation?: () => 'horizontal' | 'vertical'\n}\n\nexport interface UseCarouselSwipeReturn {\n isDragging: Ref<boolean>\n /** Смещение ленты за указателем, px. Физическое: зеркалит его CSS, не JS. */\n offset: Ref<number>\n /** Вешается на `@pointerdown` вьюпорта. */\n start: (event: PointerEvent) => void\n}\n\nexport function useCarouselSwipe(options: UseCarouselSwipeOptions): UseCarouselSwipeReturn {\n const offset = ref(0)\n\n let startX = 0\n let startY = 0\n let threshold = 0\n let rtl = false\n\n function reset(): void {\n offset.value = 0\n }\n\n const drag = useDragGesture({\n disabled: options.disabled,\n onStart: (event) => {\n const target = event.target as HTMLElement | null\n if (target?.closest(INTERACTIVE_SELECTOR))\n return false\n\n const viewport = options.viewport()\n if (!viewport)\n return false\n\n startX = event.clientX\n startY = event.clientY\n offset.value = 0\n\n // Замеры снимаются один раз на жест и в обработчике, а не в `setup`:\n // на сервере ни ширины, ни направления письма не существует.\n threshold = swipeThresholdFor(viewport.getBoundingClientRect().width)\n rtl = getComputedStyle(viewport).direction === 'rtl'\n\n options.onStart?.()\n },\n onMove: (event) => {\n // `useDragGesture` намеренно не зовёт `preventDefault`, а без него\n // протяжка выделяет текст слайда.\n event.preventDefault()\n\n // По вертикали оси меняются ролями: ведущей становится `dy`.\n const vertical = options.orientation?.() === 'vertical'\n const dx = vertical ? event.clientY - startY : event.clientX - startX\n const dy = vertical ? event.clientX - startX : event.clientY - startY\n\n // Пока жест выглядит вертикальным, лента не двигается: это прокрутка\n // страницы, и перехватывать её карусель не вправе.\n if (Math.abs(dx) < Math.abs(dy) * SWIPE_AXIS_RATIO) {\n offset.value = 0\n return\n }\n\n const logical = physicalToLogical(dx < 0 ? 1 : -1)\n offset.value = resistOffset(dx, options.atEdge(logical))\n },\n onEnd: (event) => {\n const direction = event\n ? resolveSwipeDirection(\n options.orientation?.() === 'vertical' ? event.clientY - startY : event.clientX - startX,\n options.orientation?.() === 'vertical' ? event.clientX - startX : event.clientY - startY,\n threshold,\n )\n : 0\n\n reset()\n\n if (direction !== 0)\n options.onSwipe(physicalToLogical(direction))\n },\n // Обрыв — не жест: указатель забрал браузер, а не пользователь довёл\n // протяжку. Кадр возвращается на место, слайд не меняется.\n onCancel: reset,\n })\n\n /** В RTL содержимое течёт справа налево, и палец влево листает назад. */\n function physicalToLogical(direction: 1 | -1): 1 | -1 {\n return rtl ? (direction === 1 ? -1 : 1) : direction\n }\n\n return { isDragging: drag.isDragging, offset, start: drag.start }\n}\n","import type { ComputedRef, InjectionKey } from 'vue'\n\n/** Что слайд сообщает о себе ленте при регистрации. */\nexport interface GrCarouselSlideEntry {\n /** `useId()` слайда. Он же его DOM-id и ключ реестра. */\n id: string\n /** Имя слайда: подпись его переключателя и `aria-label` самого слайда. */\n label: () => string | undefined\n /** URL миниатюры. */\n thumbnailSrc: () => string | undefined\n /**\n * Дал ли слайд свою разметку миниатюры. Геттер, а не снимок: слот, появившийся\n * позже, снимком в `setup` не увиделся бы.\n */\n hasThumbnail: () => boolean\n /**\n * Своя разметка миниатюры. Рендерит её **полоса переключателей**, а не слайд:\n * узел уезжает наверх ссылкой. Ссылка стабильна — иначе `:is` перемонтировал\n * бы миниатюру на каждый рендер.\n */\n thumbnail: () => unknown\n /**\n * Корневой узел. Геттер, а не значение: регистрация идёт в `setup`, когда\n * элемента ещё нет. По нему же восстанавливается порядок слайдов в документе.\n */\n el: () => HTMLElement | null\n}\n\nexport interface GrCarouselContext {\n /** Регистрация слайда. Возвращает отписку. */\n register: (entry: GrCarouselSlideEntry) => () => void\n /** Позиция слайда в ленте; `-1`, пока он не зарегистрирован. */\n indexOf: (id: string) => number\n isCurrent: (id: string) => boolean\n total: ComputedRef<number>\n /**\n * `tabpanel`, когда есть полоса переключателей, иначе `group`. Роль слайда\n * зависит от наличия переключателя, а не от его вида: `tab` требует парного\n * `tabpanel`, и без полосы привязать его было бы не к чему.\n */\n slideRole: ComputedRef<'tabpanel' | 'group'>\n slideRoledescription: ComputedRef<string>\n /** id переключателя для `aria-labelledby` слайда; `undefined` без полосы. */\n tabIdFor: (id: string) => string | undefined\n /** «N из M» — имя слайда, когда своего `label` у него нет. */\n positionLabel: (id: string) => string\n /**\n * Смещение слайда в процентах ширины ленты на время замыкания петли.\n *\n * Кольцо делается **без клонирования кадров**: на шаге «последний → первый»\n * первый слайд временно переезжает за последний, лента доезжает до него как\n * до обычного соседа, и уже после перехода индекс снимается на ноль без\n * анимации. Клон здесь невозможен по устройству: кадры приходят слотом, и\n * копия чужого узла унесла бы с собой его состояние и ссылки.\n */\n displacementOf: (id: string) => number\n /** Ось движения ленты: по ней кадр выбирает, какой размер занимать целиком. */\n orientation: ComputedRef<'horizontal' | 'vertical'>\n /**\n * Рисовать ли содержимое кадра.\n *\n * Виртуализация здесь **содержимого, а не самих кадров**: кадры приходят\n * слотом, и не отрисовать чужой узел лента не может — но может попросить его\n * не рисовать своё нутро. Пустая обёртка держит место в ряду и весит\n * пренебрежимо мало, а тяжёлое (картинки, карточки) уходит из DOM.\n */\n shouldRender: (id: string) => boolean\n}\n\nexport const GR_CAROUSEL_CONTEXT: InjectionKey<GrCarouselContext> = Symbol('GR_CAROUSEL_CONTEXT')\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, provide, ref, watch, watchEffect } from 'vue'\nimport type { ComponentPublicInstance } from 'vue'\n\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { resolveScrollOverflow } from '../shared/scrollOverflow'\nimport type { GrScrollOverflow } from '../shared/scrollOverflow'\nimport { clampIndex, stepIndex, stripScrollLeft } from './carouselNavigation'\nimport { useCarouselAutoplay } from './composables/useCarouselAutoplay'\nimport { useCarouselSwipe } from './composables/useCarouselSwipe'\nimport { GR_CAROUSEL_CONTEXT } from './grCarouselContext'\nimport type { GrCarouselSlideEntry } from './grCarouselContext'\nimport {\n carouselIconClass,\n carouselRootAxis,\n carouselRootBase,\n carouselThumbFallbackClass,\n carouselThumbImageClass,\n carouselToggleClass,\n carouselTrackAxis,\n carouselTrackBase,\n carouselViewportAxis,\n carouselViewportBase,\n carouselViewportSwipeClass,\n carouselViewportTouchAction,\n grCarouselControlClass,\n grCarouselIndicatorClass,\n grCarouselIndicatorsClass,\n} from './grCarouselStyles'\nimport type {\n GrCarouselActivationMode,\n GrCarouselIndicators,\n GrCarouselOrientation,\n} from './grCarouselStyles'\nimport type { GrTone } from '../shared/tones'\n\nimport IconChevronDown from '~icons/lucide/chevron-down'\nimport IconChevronLeft from '~icons/lucide/chevron-left'\nimport IconChevronRight from '~icons/lucide/chevron-right'\nimport IconChevronUp from '~icons/lucide/chevron-up'\nimport IconPause from '~icons/lucide/pause'\nimport IconPlay from '~icons/lucide/play'\n\nexport interface GrCarouselProps {\n /** Индекс текущего кадра. Не передан — лента ведёт позицию сама. */\n modelValue?: number\n /** Запустить показ. Под `prefers-reduced-motion` не стартует — тумблер остаётся. */\n autoplay?: boolean\n /** Пауза между кадрами, мс. */\n autoplayInterval?: number\n /** Замкнуть ленту. Выключено — стрелки на краях гаснут. */\n loop?: boolean\n /**\n * Ось движения ленты. По вертикали вьюпорту нужна **определённая высота**:\n * шаг считается от неё, и без высоты лента вырождается в столбец кадров.\n */\n orientation?: GrCarouselOrientation\n /**\n * Не рисовать содержимое кадров вдали от текущего.\n *\n * Виртуализируется **нутро кадра, а не кадр**: кадры приходят слотом, и не\n * отрисовать чужой узел лента не может. Пустая обёртка держит место в ряду и\n * почти ничего не весит, а картинки и карточки из DOM уходят.\n */\n virtual?: boolean\n /**\n * Сколько кадров по обе стороны от текущего рисовать сверх него. Меньше\n * единицы ставить нельзя: следующий кадр обязан быть готов **до** перехода,\n * иначе лента поедет на пустоту, а содержимое проявится уже на месте.\n */\n virtualOverscan?: number\n /** Вид переключателя кадров. `none` меняет и роль самих слайдов. */\n indicators?: GrCarouselIndicators\n /** Тон текущего переключателя по общей шкале пакета. */\n tone?: GrTone\n /** Листает ли стрелка по переключателям сразу или только двигает фокус. */\n activationMode?: GrCarouselActivationMode\n /** Стрелки «назад/вперёд». */\n arrows?: boolean\n /** Листание протяжкой указателя. */\n swipe?: boolean\n /** Сделать карусель ориентиром страницы (`role=\"region\"`). */\n landmark?: boolean\n /** Имя карусели. APG требует его: `aria-roledescription` именем не считается. */\n ariaLabel?: string\n /** Имя из заголовка на странице. Сильнее `ariaLabel`. */\n ariaLabelledby?: string\n prevLabel?: string\n nextLabel?: string\n playLabel?: string\n pauseLabel?: string\n /** Имя полосы переключателей. */\n indicatorsLabel?: string\n}\n\nexport interface GrCarouselEmits {\n (e: 'update:modelValue', index: number): void\n}\n\nconst props = withDefaults(defineProps<GrCarouselProps>(), {\n modelValue: undefined,\n autoplay: false,\n autoplayInterval: 5000,\n loop: true,\n orientation: 'horizontal',\n virtual: false,\n virtualOverscan: 1,\n // Дефолт живёт в резолвере: Vue подставил бы свой раньше `GrConfigProvider`,\n // и «пользователь передал» стало бы неотличимо от «сработал дефолт».\n indicators: undefined,\n tone: undefined,\n activationMode: undefined,\n arrows: true,\n swipe: true,\n landmark: false,\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n prevLabel: undefined,\n nextLabel: undefined,\n playLabel: undefined,\n pauseLabel: undefined,\n indicatorsLabel: undefined,\n})\n\nconst emit = defineEmits<GrCarouselEmits>()\n\ndefineSlots<{\n /** Кадры ленты — `GrCarouselSlide`. */\n default?: () => unknown\n /**\n * Своя иконка кнопки «назад». Заменяет содержимое кнопки, но не её саму:\n * имя, `aria-disabled` и поведение на краю остаются за компонентом.\n */\n prev?: (props: { disabled: boolean }) => unknown\n /** Своя иконка кнопки «вперёд». */\n next?: (props: { disabled: boolean }) => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\n\nconst resolvedIndicators = useGrComponentProp('GrCarousel', 'indicators', () => props.indicators, 'dots')\nconst resolvedActivation = useGrComponentProp('GrCarousel', 'activationMode', () => props.activationMode, 'automatic')\nconst resolvedTone = useGrComponentProp('GrCarousel', 'tone', () => props.tone, 'primary')\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst viewportEl = ref<HTMLElement | null>(null)\nconst indicatorsEl = ref<HTMLElement | null>(null)\nconst tabRefs = ref<(HTMLElement | null)[]>([])\n\nconst entries = ref<GrCarouselSlideEntry[]>([])\nconst total = computed(() => entries.value.length)\n\nlet reorderScheduled = false\n\n/**\n * Порядок регистрации совпадает с документом только при первом монтировании:\n * кадр, появившийся посреди ленты позже, встал бы в конец, и переключатели\n * разъехались бы с лентой. Пересортировка откладывается на такт — к этому\n * моменту узлы уже в DOM.\n */\nfunction scheduleReorder(): void {\n if (reorderScheduled || typeof document === 'undefined')\n return\n\n reorderScheduled = true\n void nextTick(() => {\n reorderScheduled = false\n entries.value = [...entries.value].sort((left, right) => {\n const a = left.el()\n const b = right.el()\n if (!a || !b)\n return 0\n return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1\n })\n })\n}\n\nfunction register(entry: GrCarouselSlideEntry): () => void {\n entries.value.push(entry)\n scheduleReorder()\n\n return () => {\n // Поиск по `id`, а не по ссылке: пересортировка выше пересобирает массив\n // через spread реактивного прокси, и элементы в нём — уже прокси, а не те\n // объекты, что пришли в `register`. `indexOf` по исходной ссылке вернул бы\n // `-1`, и кадр остался бы в полосе после размонтирования.\n const index = entries.value.findIndex(item => item.id === entry.id)\n if (index >= 0)\n entries.value.splice(index, 1)\n scheduleReorder()\n }\n}\n\n/**\n * Потолок ожидания конца перехода ленты. `--gr-duration-base` — 240ms; запас\n * нужен на прерванный переход и на среду, где переходов нет вовсе.\n */\nconst WRAP_FALLBACK_MS = 600\n\nconst internalIndex = ref(0)\nconst currentIndex = computed(() => clampIndex(props.modelValue ?? internalIndex.value, total.value))\n\n/**\n * Замыкание кольца: `1` — идём с последнего кадра на первый, `-1` — обратно,\n * `0` — обычный шаг.\n *\n * Раньше `loop` просто сбрасывал индекс, и лента **прокручивалась назад через\n * все кадры**: на десятикадровой карусели с автопрокруткой каждый десятый шаг\n * был длинным обратным ходом. Теперь крайний слайд временно переезжает на\n * противоположный конец, лента доезжает до него как до соседа, и уже после\n * перехода индекс снимается без анимации.\n */\nconst wrapStep = ref<-1 | 0 | 1>(0)\n\n/** Сама лента: по ней делается принудительная перерисовка при снятии кольца. */\nconst trackEl = ref<HTMLElement | null>(null)\n\n/** На время снятия индекса переход выключается — иначе снятие само поедет. */\nconst suppressTransition = ref(false)\n\nlet wrapFallback: ReturnType<typeof setTimeout> | undefined\n\n/** Позиция ленты: при замыкании она уезжает на один кадр за край. */\nconst trackIndex = computed(() => {\n if (wrapStep.value === 1)\n return total.value\n if (wrapStep.value === -1)\n return -1\n return currentIndex.value\n})\n\n/**\n * Смещение слайда, изображающего соседа за краем. Вперёд — первый кадр уезжает\n * за последний, назад — последний встаёт перед первым.\n */\nfunction displacementOf(id: string): number {\n if (wrapStep.value === 0 || total.value < 2)\n return 0\n\n const index = entries.value.findIndex(entry => entry.id === id)\n if (wrapStep.value === 1)\n return index === 0 ? total.value * 100 : 0\n\n return index === total.value - 1 ? total.value * -100 : 0\n}\n\n/**\n * Попадает ли кадр в окно отрисовки. Окно замкнуто вместе с лентой: при `loop`\n * соседи последнего кадра — первые, и не нарисовать их значит показать пустоту\n * ровно в момент замыкания кольца.\n */\nfunction shouldRender(id: string): boolean {\n if (!props.virtual)\n return true\n\n const count = total.value\n if (count === 0)\n return true\n\n const index = entries.value.findIndex(entry => entry.id === id)\n if (index < 0)\n return true\n\n const overscan = Math.max(1, Math.trunc(props.virtualOverscan))\n const distance = Math.abs(index - currentIndex.value)\n\n return props.loop\n ? Math.min(distance, count - distance) <= overscan\n : distance <= overscan\n}\n\n/**\n * Конец замыкания: лента возвращается с позиции «за краем» на настоящий индекс.\n *\n * Модель здесь уже давно на новом кадре — её обновил `startWrap`. Отложи мы её\n * до этого момента, `update:modelValue` опаздывал бы на длительность перехода,\n * а там, где переходов нет вовсе, — на страховочный таймер.\n */\nfunction finishWrap(): void {\n if (wrapStep.value === 0)\n return\n\n clearTimeout(wrapFallback)\n wrapFallback = undefined\n\n suppressTransition.value = true\n wrapStep.value = 0\n\n /*\n * Переход возвращается после **принудительной перерисовки**, а не через\n * `requestAnimationFrame`: в фоновой вкладке кадры не идут вовсе, и лента\n * осталась бы с выключенным переходом навсегда — то есть дальше дёргалась бы\n * вместо движения. Чтение `offsetHeight` фиксирует новое положение\n * синхронно, и это работает в любой вкладке.\n */\n void nextTick().then(() => {\n void trackEl.value?.offsetHeight\n suppressTransition.value = false\n })\n}\n\n/**\n * Замкнуть кольцо в сторону `direction`. Возвращает `false`, если шаг обычный\n * и его надо выполнить как раньше.\n */\nfunction startWrap(direction: 1 | -1): boolean {\n if (!props.loop || total.value < 2)\n return false\n\n const atLast = currentIndex.value === total.value - 1\n const atFirst = currentIndex.value === 0\n if (!(direction === 1 ? atLast : atFirst))\n return false\n\n finishWrap()\n wrapStep.value = direction\n // Модель — сразу: она про то, какой кадр показан, а не про то, доехала ли\n // лента. Смещение и позиция «за краем» держатся до конца перехода.\n setIndex(direction === 1 ? 0 : total.value - 1)\n\n // `transitionend` в jsdom не наступает вовсе, а в живом браузере может не\n // прийти при прерванном переходе. Страховка возвращает ленту сама.\n wrapFallback = setTimeout(finishWrap, WRAP_FALLBACK_MS)\n return true\n}\n\nonBeforeUnmount(() => clearTimeout(wrapFallback))\n\nfunction setIndex(next: number): void {\n const value = clampIndex(next, total.value)\n if (value === currentIndex.value)\n return\n\n internalIndex.value = value\n emit('update:modelValue', value)\n}\n\nconst showIndicators = computed(() => resolvedIndicators.value !== 'none' && total.value > 1)\nconst showArrows = computed(() => props.arrows && total.value > 1)\nconst isThumbnails = computed(() => resolvedIndicators.value === 'thumbnails')\n\nconst atStart = computed(() => !props.loop && currentIndex.value <= 0)\nconst atEnd = computed(() => !props.loop && currentIndex.value >= total.value - 1)\n\nconst reducedMotion = ref(false)\nconst hovered = ref(false)\nconst documentHidden = ref(false)\n\n/** `null` — тумблер не трогали, и решает проп. */\nconst userIntent = ref<boolean | null>(null)\n\nconst playing = computed(() => total.value > 1\n && (userIntent.value ?? (props.autoplay && !reducedMotion.value)))\n\n/**\n * Живой регион читает кадр, только когда лента стоит: у движущейся карусели\n * объявление каждого кадра превратило бы страницу в неработающую.\n */\nconst liveMode = computed<'off' | 'polite'>(() => (playing.value ? 'off' : 'polite'))\n\nconst swipeGesture = useCarouselSwipe({\n disabled: () => !props.swipe || total.value <= 1,\n viewport: () => viewportEl.value,\n orientation: () => props.orientation,\n atEdge: direction => (direction === 1 ? atEnd.value : atStart.value),\n onStart: stopAutoplay,\n onSwipe: (direction) => {\n void stepBy(direction)\n },\n})\n\nconst autoplayTimer = useCarouselAutoplay({\n interval: () => props.autoplayInterval,\n enabled: () => playing.value,\n paused: () => hovered.value || documentHidden.value || swipeGesture.isDragging.value,\n advance: () => {\n if (startWrap(1))\n return\n\n const next = stepIndex(currentIndex.value, 1, total.value, props.loop)\n // Упёрлись в край без `loop` — показ окончен, а не зациклился.\n if (next === currentIndex.value) {\n userIntent.value = false\n return\n }\n finishWrap()\n setIndex(next)\n },\n})\n\nfunction stopAutoplay(): void {\n if (!playing.value)\n return\n\n userIntent.value = false\n announce(t('gr.carousel.autoplayStopped', 'Automatic slide show stopped'))\n}\n\n/**\n * `aria-live` обязан стать `polite` **раньше**, чем поменяется содержимое:\n * иначе мутация случится, пока регион ещё `off`, и не прозвучит вовсе.\n */\nasync function commitUserNavigation(next: number): Promise<void> {\n if (playing.value) {\n stopAutoplay()\n await nextTick()\n }\n\n finishWrap()\n setIndex(next)\n}\n\n/**\n * Шаг на соседний кадр. На краю кольца замыкание идёт через смещение крайнего\n * слайда, а не через сброс индекса: сброс прокручивал бы ленту назад через всё.\n */\nasync function stepBy(delta: 1 | -1): Promise<void> {\n if (playing.value) {\n stopAutoplay()\n await nextTick()\n }\n\n if (startWrap(delta))\n return\n\n finishWrap()\n setIndex(stepIndex(currentIndex.value, delta, total.value, props.loop))\n}\n\n/**\n * Переход ленты доехал — можно снимать замыкание. Слушаем только свой узел\n * (`.self`): всплывший переход дочернего кадра снял бы кольцо раньше времени.\n */\nfunction onTrackTransitionEnd(event: TransitionEvent): void {\n if (event.propertyName === 'transform')\n finishWrap()\n}\n\nfunction toggleAutoplay(): void {\n if (playing.value) {\n stopAutoplay()\n return\n }\n\n userIntent.value = true\n autoplayTimer.restart()\n}\n\nfunction goTo(index: number): void {\n void commitUserNavigation(clampIndex(index, total.value))\n}\n\nfunction step(delta: 1 | -1): void {\n void stepBy(delta as 1 | -1)\n}\n\nconst roving = useRovingFocus<number>({\n items: () => entries.value.map((_, index) => index),\n elementFor: index => tabRefs.value[index],\n orientation: () => 'horizontal',\n // Кольцо полосы замкнуто независимо от `loop`: тот управляет стрелками и\n // показом, а выбрать любой кадр напрямую можно всегда.\n wrap: () => true,\n initialKey: () => (total.value > 0 ? currentIndex.value : undefined),\n // Прокрутка до фокуса, а не после: иначе браузер доскроллит по-своему и\n // полоса дёрнется дважды.\n beforeFocus: index => scrollTabIntoView(index),\n})\n\n// Лента укоротилась под текущим кадром: модель потребителя и картинка разошлись\n// бы молча, поэтому индекс доводится до края и эмитится.\nwatch(total, (count) => {\n if (count === 0) {\n roving.reset()\n return\n }\n\n const requested = props.modelValue ?? internalIndex.value\n const clamped = clampIndex(requested, count)\n if (clamped !== requested) {\n internalIndex.value = clamped\n emit('update:modelValue', clamped)\n }\n})\n\n/**\n * Прокрутка **полосы**, а не страницы.\n *\n * `scrollIntoView` двигает всех предков, включая документ: карусель, уехавшая\n * под сгиб, на каждом шаге автопрокрутки утаскивала бы страницу обратно к себе.\n * Поэтому позиция считается сама и присваивается `scrollLeft` полосы.\n */\nfunction scrollTabIntoView(index: number): void {\n const strip = indicatorsEl.value\n const tab = tabRefs.value[index]\n if (!strip || !tab)\n return\n\n const next = stripScrollLeft(\n strip.scrollLeft,\n strip.clientWidth,\n tab.offsetLeft,\n tab.offsetLeft + tab.offsetWidth,\n )\n\n if (next !== strip.scrollLeft)\n strip.scrollLeft = next\n}\n\nfunction setTabRef(el: Element | ComponentPublicInstance | null, index: number): void {\n tabRefs.value[index] = el as HTMLElement | null\n}\n\nfunction onIndicatorKeydown(event: KeyboardEvent): void {\n if (total.value === 0)\n return\n\n const current = roving.rovingKey.value ?? 0\n\n if ((event.key === 'Enter' || event.key === ' ') && resolvedActivation.value === 'manual') {\n event.preventDefault()\n void commitUserNavigation(current)\n return\n }\n\n // Стрелки, `Home`, `End` ведёт примитив. Выбор не вешается на его `onMove`:\n // клик тоже зовёт `focusKey`, и модель менялась бы дважды.\n if (!roving.handleNavigationKeys(event))\n return\n\n if (resolvedActivation.value !== 'manual')\n void commitUserNavigation(roving.rovingKey.value ?? current)\n}\n\nfunction onIndicatorClick(index: number): void {\n roving.setActive(index)\n void commitUserNavigation(index)\n}\n\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, { enter: stopAutoplay })\n\nconst stripOverflow = ref<GrScrollOverflow>('none')\nlet resizeObserver: ResizeObserver | null = null\nlet measureScheduled = false\n\nfunction measureOverflow(): void {\n const el = indicatorsEl.value\n\n if (!el || !isThumbnails.value) {\n stripOverflow.value = 'none'\n return\n }\n\n stripOverflow.value = resolveScrollOverflow(el.scrollLeft, el.scrollWidth, el.clientWidth)\n}\n\nfunction scheduleMeasure(): void {\n if (measureScheduled)\n return\n\n measureScheduled = true\n void nextTick(() => {\n measureScheduled = false\n measureOverflow()\n })\n}\n\nfunction onVisibilityChange(): void {\n documentHidden.value = document.hidden\n}\n\nonMounted(() => {\n // Браузерный API в теле `setup` разошёлся бы с серверным рендером.\n reducedMotion.value = typeof window !== 'undefined'\n && window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true\n\n document.addEventListener('visibilitychange', onVisibilityChange)\n scheduleMeasure()\n\n // На сервере и в jsdom `ResizeObserver` отсутствует — измерять там нечего.\n if (typeof ResizeObserver === 'undefined')\n return\n\n resizeObserver = new ResizeObserver(scheduleMeasure)\n if (indicatorsEl.value)\n resizeObserver.observe(indicatorsEl.value)\n})\n\nonBeforeUnmount(() => {\n document.removeEventListener('visibilitychange', onVisibilityChange)\n resizeObserver?.disconnect()\n resizeObserver = null\n})\n\nwatch([total, isThumbnails], scheduleMeasure)\n\n// Кадр мог смениться не фокусом — показом или свайпом; переключатель всё равно\n// обязан оказаться на виду.\nwatch(currentIndex, async (index) => {\n await nextTick()\n scrollTabIntoView(index)\n})\n\nfunction entryAt(index: number): GrCarouselSlideEntry | undefined {\n return entries.value[index]\n}\n\nfunction positionLabelAt(index: number): string {\n return t('gr.carousel.slidePosition', '{index} of {total}', {\n index: index + 1,\n total: total.value,\n })\n}\n\nfunction indicatorName(index: number): string {\n return entryAt(index)?.label() ?? positionLabelAt(index)\n}\n\nfunction tabDomId(index: number): string {\n return `${entryAt(index)?.id ?? index}-tab`\n}\n\nconst trackStyle = computed(() => {\n const style: Record<string, string> = {\n '--gr-carousel-index': String(trackIndex.value),\n '--gr-carousel-drag': `${swipeGesture.offset.value}px`,\n }\n\n // На время жеста лента идёт за пальцем один в один: переход догонял бы курсор.\n if (swipeGesture.isDragging.value)\n style.transition = 'none'\n\n return style\n})\n\nprovide(GR_CAROUSEL_CONTEXT, {\n register,\n indexOf: id => entries.value.findIndex(entry => entry.id === id),\n isCurrent: id => entries.value[currentIndex.value]?.id === id,\n total,\n slideRole: computed(() => (showIndicators.value ? 'tabpanel' : 'group')),\n slideRoledescription: computed(() => t('gr.carousel.slideRoledescription', 'slide')),\n tabIdFor: (id) => {\n if (!showIndicators.value)\n return undefined\n const index = entries.value.findIndex(entry => entry.id === id)\n return index >= 0 ? tabDomId(index) : undefined\n },\n positionLabel: (id) => {\n const index = entries.value.findIndex(entry => entry.id === id)\n return positionLabelAt(index >= 0 ? index : 0)\n },\n displacementOf,\n orientation: computed(() => props.orientation),\n shouldRender,\n})\n\nif (__GR_DEV__) {\n onMounted(() => {\n if (props.orientation !== 'vertical')\n return\n\n // Высота вьюпорта — обязательное условие вертикальной ленты, и молчаливый\n // отказ тут хуже ошибки: карусель превращается в столбец кадров, а причина\n // не видна ни в разметке, ни в консоли.\n if ((viewportEl.value?.clientHeight ?? 0) === 0) {\n console.warn(\n '[granularity] GrCarousel: у вертикальной ленты нулевая высота вьюпорта — '\n + 'шаг считается от неё. Задайте высоту классом или стилем, иначе кадры '\n + 'встанут столбцом.',\n )\n }\n })\n\n watchEffect(() => {\n if (!props.ariaLabel && !props.ariaLabelledby) {\n console.warn(\n '[granularity] GrCarousel: у карусели нет доступного имени — передайте '\n + '`ariaLabel` или `ariaLabelledby`. `aria-roledescription` именем не является.',\n )\n }\n\n if (!props.arrows && resolvedIndicators.value === 'none' && total.value > 1) {\n console.warn(\n '[granularity] GrCarousel: `arrows: false` вместе с `indicators: \"none\"` '\n + 'не оставляет ни одного способа сменить кадр с клавиатуры.',\n )\n }\n\n if (isThumbnails.value && total.value > 0\n && entries.value.every(entry => !entry.hasThumbnail() && !entry.thumbnailSrc())) {\n console.warn(\n '[granularity] GrCarousel: `indicators=\"thumbnails\"`, но ни один слайд не дал '\n + 'миниатюру — задайте проп `thumbnail` или слот `#thumbnail` у `GrCarouselSlide`.',\n )\n }\n })\n}\n\ndefineExpose({\n /** Текущий кадр — единственный способ прочитать позицию без `v-model`. */\n index: computed(() => currentIndex.value),\n /** Число кадров: состав живёт в слоте, снаружи его посчитать нечем. */\n count: total,\n /** Идёт ли показ. Пауза под курсором его не выключает. */\n playing: computed(() => playing.value),\n next: () => step(1),\n prev: () => step(-1),\n goTo,\n play: () => {\n if (!playing.value)\n toggleAutoplay()\n },\n pause: stopAutoplay,\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-carousel\n :class=\"[carouselRootBase, carouselRootAxis[props.orientation]]\"\n :role=\"landmark ? 'region' : 'group'\"\n :aria-roledescription=\"t('gr.carousel.roledescription', 'carousel')\"\n :aria-label=\"ariaLabelledby ? undefined : ariaLabel\"\n :aria-labelledby=\"ariaLabelledby\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <div\n ref=\"viewportEl\"\n data-gr-carousel-viewport\n :class=\"[\n carouselViewportBase,\n carouselViewportAxis[props.orientation],\n carouselViewportTouchAction[props.orientation],\n props.swipe ? carouselViewportSwipeClass : '',\n ]\"\n :aria-live=\"liveMode\"\n aria-atomic=\"true\"\n @pointerdown=\"swipeGesture.start\"\n >\n <div\n ref=\"trackEl\"\n data-gr-carousel-track\n :data-gr-carousel-vertical=\"props.orientation === 'vertical' ? '' : undefined\"\n :data-gr-carousel-wrapping=\"suppressTransition ? '' : undefined\"\n :class=\"[carouselTrackBase, carouselTrackAxis[props.orientation]]\"\n :style=\"trackStyle\"\n @transitionend.self=\"onTrackTransitionEnd\"\n >\n <slot />\n </div>\n\n <button\n v-if=\"props.autoplay && total > 1\"\n type=\"button\"\n data-gr-carousel-toggle\n :class=\"carouselToggleClass\"\n :aria-label=\"playing\n ? (pauseLabel ?? t('gr.carousel.pause', 'Stop automatic slide show'))\n : (playLabel ?? t('gr.carousel.play', 'Start automatic slide show'))\"\n @click=\"toggleAutoplay\"\n >\n <component :is=\"playing ? IconPause : IconPlay\" :class=\"carouselIconClass\" aria-hidden=\"true\" />\n </button>\n\n <button\n v-if=\"showArrows\"\n type=\"button\"\n data-gr-carousel-prev\n :class=\"grCarouselControlClass('prev', atStart, props.orientation)\"\n :aria-disabled=\"atStart ? 'true' : undefined\"\n :aria-label=\"prevLabel ?? t('gr.carousel.previous', 'Previous slide')\"\n @click=\"atStart ? undefined : step(-1)\"\n >\n <slot name=\"prev\" :disabled=\"atStart\">\n <component\n :is=\"props.orientation === 'vertical' ? IconChevronUp : IconChevronLeft\"\n :class=\"carouselIconClass\"\n aria-hidden=\"true\"\n />\n </slot>\n </button>\n\n <button\n v-if=\"showArrows\"\n type=\"button\"\n data-gr-carousel-next\n :class=\"grCarouselControlClass('next', atEnd, props.orientation)\"\n :aria-disabled=\"atEnd ? 'true' : undefined\"\n :aria-label=\"nextLabel ?? t('gr.carousel.next', 'Next slide')\"\n @click=\"atEnd ? undefined : step(1)\"\n >\n <slot name=\"next\" :disabled=\"atEnd\">\n <component\n :is=\"props.orientation === 'vertical' ? IconChevronDown : IconChevronRight\"\n :class=\"carouselIconClass\"\n aria-hidden=\"true\"\n />\n </slot>\n </button>\n </div>\n\n <div\n v-if=\"showIndicators\"\n ref=\"indicatorsEl\"\n role=\"tablist\"\n data-gr-carousel-indicators\n :data-variant=\"resolvedIndicators\"\n :data-overflow=\"stripOverflow\"\n :class=\"grCarouselIndicatorsClass(resolvedIndicators)\"\n :aria-label=\"indicatorsLabel ?? t('gr.carousel.indicators', 'Slides')\"\n @keydown=\"onIndicatorKeydown\"\n @scroll.passive=\"scheduleMeasure\"\n >\n <button\n v-for=\"(entry, index) in entries\"\n :id=\"tabDomId(index)\"\n :key=\"entry.id\"\n :ref=\"el => setTabRef(el, index)\"\n type=\"button\"\n role=\"tab\"\n data-gr-carousel-indicator\n :aria-selected=\"index === currentIndex ? 'true' : 'false'\"\n :aria-controls=\"entry.id\"\n :aria-label=\"indicatorName(index)\"\n :tabindex=\"roving.tabindexFor(index)\"\n :class=\"grCarouselIndicatorClass(resolvedIndicators, index === currentIndex, resolvedTone)\"\n @click=\"onIndicatorClick(index)\"\n >\n <component :is=\"entry.thumbnail\" v-if=\"isThumbnails && entry.hasThumbnail()\" />\n <img\n v-else-if=\"isThumbnails && entry.thumbnailSrc()\"\n :src=\"entry.thumbnailSrc()\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n :class=\"carouselThumbImageClass\"\n >\n <span v-else-if=\"isThumbnails\" :class=\"carouselThumbFallbackClass\">{{ index + 1 }}</span>\n </button>\n </div>\n </div>\n</template>\n\n<style>\n[data-gr-carousel-track] {\n transform: translateX(calc(var(--gr-carousel-index, 0) * -100% + var(--gr-carousel-drag, 0px)));\n}\n\n/*\n * Снятие индекса после замыкания кольца обязано пройти без анимации: иначе\n * лента поедет обратно через все кадры — ровно тот ход, ради устранения\n * которого замыкание и сделано.\n */\n[data-gr-carousel-track][data-gr-carousel-wrapping] {\n transition: none;\n}\n\n/*\n * Вертикальная лента: шаг считается от **высоты вьюпорта**, а не от высоты\n * самой ленты. Поэтому вьюпорту нужна определённая высота — без неё колонка\n * кадров растёт по содержимому, и `-100%` означает всю ленту разом.\n *\n * Направление письма вертикали не касается, поэтому RTL-зеркала здесь нет.\n */\n[data-gr-carousel-track][data-gr-carousel-vertical],\n[dir='rtl'] [data-gr-carousel-track][data-gr-carousel-vertical] {\n transform: translateY(calc(var(--gr-carousel-index, 0) * -100% + var(--gr-carousel-drag, 0px)));\n}\n\n/*\n * Индекс зеркалится, смещение жеста — нет: палец двигает ленту на столько же\n * физических пикселей независимо от направления письма.\n */\n[dir='rtl'] [data-gr-carousel-track] {\n transform: translateX(calc(var(--gr-carousel-index, 0) * 100% + var(--gr-carousel-drag, 0px)));\n}\n\n[data-gr-carousel-indicators][data-variant='thumbnails'] {\n /*\n * `scrollIntoView({ inline: 'nearest' })` прижимает миниатюру вплотную к краю.\n * Без отступа прокрутки фокус-кольцо оказалось бы ровно под затуханием.\n */\n scroll-padding-inline: var(--gr-carousel-thumbs-fade, 1.5rem);\n}\n\n[data-gr-carousel-indicators][data-overflow='start'] {\n --gr-carousel-thumbs-mask: linear-gradient(to right, transparent 0, #000 var(--gr-carousel-thumbs-fade, 1.5rem));\n}\n\n[data-gr-carousel-indicators][data-overflow='end'] {\n --gr-carousel-thumbs-mask: linear-gradient(to right, #000 calc(100% - var(--gr-carousel-thumbs-fade, 1.5rem)), transparent 100%);\n}\n\n[data-gr-carousel-indicators][data-overflow='both'] {\n --gr-carousel-thumbs-mask: linear-gradient(\n to right,\n transparent 0,\n #000 var(--gr-carousel-thumbs-fade, 1.5rem),\n #000 calc(100% - var(--gr-carousel-thumbs-fade, 1.5rem)),\n transparent 100%\n );\n}\n\n[dir='rtl'] [data-gr-carousel-indicators][data-overflow='start'] {\n --gr-carousel-thumbs-mask: linear-gradient(to left, transparent 0, #000 var(--gr-carousel-thumbs-fade, 1.5rem));\n}\n\n[dir='rtl'] [data-gr-carousel-indicators][data-overflow='end'] {\n --gr-carousel-thumbs-mask: linear-gradient(to left, #000 calc(100% - var(--gr-carousel-thumbs-fade, 1.5rem)), transparent 100%);\n}\n\n[data-gr-carousel-indicators]:is([data-overflow='start'], [data-overflow='end'], [data-overflow='both']) {\n -webkit-mask-image: var(--gr-carousel-thumbs-mask);\n mask-image: var(--gr-carousel-thumbs-mask);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, provide, ref, watch, watchEffect } from 'vue'\nimport type { ComponentPublicInstance } from 'vue'\n\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { resolveScrollOverflow } from '../shared/scrollOverflow'\nimport type { GrScrollOverflow } from '../shared/scrollOverflow'\nimport { clampIndex, stepIndex, stripScrollLeft } from './carouselNavigation'\nimport { useCarouselAutoplay } from './composables/useCarouselAutoplay'\nimport { useCarouselSwipe } from './composables/useCarouselSwipe'\nimport { GR_CAROUSEL_CONTEXT } from './grCarouselContext'\nimport type { GrCarouselSlideEntry } from './grCarouselContext'\nimport {\n carouselIconClass,\n carouselRootAxis,\n carouselRootBase,\n carouselThumbFallbackClass,\n carouselThumbImageClass,\n carouselToggleClass,\n carouselTrackAxis,\n carouselTrackBase,\n carouselViewportAxis,\n carouselViewportBase,\n carouselViewportSwipeClass,\n carouselViewportTouchAction,\n grCarouselControlClass,\n grCarouselIndicatorClass,\n grCarouselIndicatorsClass,\n} from './grCarouselStyles'\nimport type {\n GrCarouselActivationMode,\n GrCarouselIndicators,\n GrCarouselOrientation,\n} from './grCarouselStyles'\nimport type { GrTone } from '../shared/tones'\n\nimport IconChevronDown from '~icons/lucide/chevron-down'\nimport IconChevronLeft from '~icons/lucide/chevron-left'\nimport IconChevronRight from '~icons/lucide/chevron-right'\nimport IconChevronUp from '~icons/lucide/chevron-up'\nimport IconPause from '~icons/lucide/pause'\nimport IconPlay from '~icons/lucide/play'\n\nexport interface GrCarouselProps {\n /** Индекс текущего кадра. Не передан — лента ведёт позицию сама. */\n modelValue?: number\n /** Запустить показ. Под `prefers-reduced-motion` не стартует — тумблер остаётся. */\n autoplay?: boolean\n /** Пауза между кадрами, мс. */\n autoplayInterval?: number\n /** Замкнуть ленту. Выключено — стрелки на краях гаснут. */\n loop?: boolean\n /**\n * Ось движения ленты. По вертикали вьюпорту нужна **определённая высота**:\n * шаг считается от неё, и без высоты лента вырождается в столбец кадров.\n */\n orientation?: GrCarouselOrientation\n /**\n * Не рисовать содержимое кадров вдали от текущего.\n *\n * Виртуализируется **нутро кадра, а не кадр**: кадры приходят слотом, и не\n * отрисовать чужой узел лента не может. Пустая обёртка держит место в ряду и\n * почти ничего не весит, а картинки и карточки из DOM уходят.\n */\n virtual?: boolean\n /**\n * Сколько кадров по обе стороны от текущего рисовать сверх него. Меньше\n * единицы ставить нельзя: следующий кадр обязан быть готов **до** перехода,\n * иначе лента поедет на пустоту, а содержимое проявится уже на месте.\n */\n virtualOverscan?: number\n /** Вид переключателя кадров. `none` меняет и роль самих слайдов. */\n indicators?: GrCarouselIndicators\n /** Тон текущего переключателя по общей шкале пакета. */\n tone?: GrTone\n /** Листает ли стрелка по переключателям сразу или только двигает фокус. */\n activationMode?: GrCarouselActivationMode\n /** Стрелки «назад/вперёд». */\n arrows?: boolean\n /** Листание протяжкой указателя. */\n swipe?: boolean\n /** Сделать карусель ориентиром страницы (`role=\"region\"`). */\n landmark?: boolean\n /** Имя карусели. APG требует его: `aria-roledescription` именем не считается. */\n ariaLabel?: string\n /** Имя из заголовка на странице. Сильнее `ariaLabel`. */\n ariaLabelledby?: string\n prevLabel?: string\n nextLabel?: string\n playLabel?: string\n pauseLabel?: string\n /** Имя полосы переключателей. */\n indicatorsLabel?: string\n}\n\nexport interface GrCarouselEmits {\n (e: 'update:modelValue', index: number): void\n}\n\nconst props = withDefaults(defineProps<GrCarouselProps>(), {\n modelValue: undefined,\n autoplay: false,\n autoplayInterval: 5000,\n loop: true,\n orientation: 'horizontal',\n virtual: false,\n virtualOverscan: 1,\n // Дефолт живёт в резолвере: Vue подставил бы свой раньше `GrConfigProvider`,\n // и «пользователь передал» стало бы неотличимо от «сработал дефолт».\n indicators: undefined,\n tone: undefined,\n activationMode: undefined,\n arrows: true,\n swipe: true,\n landmark: false,\n ariaLabel: undefined,\n ariaLabelledby: undefined,\n prevLabel: undefined,\n nextLabel: undefined,\n playLabel: undefined,\n pauseLabel: undefined,\n indicatorsLabel: undefined,\n})\n\nconst emit = defineEmits<GrCarouselEmits>()\n\ndefineSlots<{\n /** Кадры ленты — `GrCarouselSlide`. */\n default?: () => unknown\n /**\n * Своя иконка кнопки «назад». Заменяет содержимое кнопки, но не её саму:\n * имя, `aria-disabled` и поведение на краю остаются за компонентом.\n */\n prev?: (props: { disabled: boolean }) => unknown\n /** Своя иконка кнопки «вперёд». */\n next?: (props: { disabled: boolean }) => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\n\nconst resolvedIndicators = useGrComponentProp('GrCarousel', 'indicators', () => props.indicators, 'dots')\nconst resolvedActivation = useGrComponentProp('GrCarousel', 'activationMode', () => props.activationMode, 'automatic')\nconst resolvedTone = useGrComponentProp('GrCarousel', 'tone', () => props.tone, 'primary')\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst viewportEl = ref<HTMLElement | null>(null)\nconst indicatorsEl = ref<HTMLElement | null>(null)\nconst tabRefs = ref<(HTMLElement | null)[]>([])\n\nconst entries = ref<GrCarouselSlideEntry[]>([])\nconst total = computed(() => entries.value.length)\n\nlet reorderScheduled = false\n\n/**\n * Порядок регистрации совпадает с документом только при первом монтировании:\n * кадр, появившийся посреди ленты позже, встал бы в конец, и переключатели\n * разъехались бы с лентой. Пересортировка откладывается на такт — к этому\n * моменту узлы уже в DOM.\n */\nfunction scheduleReorder(): void {\n if (reorderScheduled || typeof document === 'undefined')\n return\n\n reorderScheduled = true\n void nextTick(() => {\n reorderScheduled = false\n entries.value = [...entries.value].sort((left, right) => {\n const a = left.el()\n const b = right.el()\n if (!a || !b)\n return 0\n return a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1\n })\n })\n}\n\nfunction register(entry: GrCarouselSlideEntry): () => void {\n entries.value.push(entry)\n scheduleReorder()\n\n return () => {\n // Поиск по `id`, а не по ссылке: пересортировка выше пересобирает массив\n // через spread реактивного прокси, и элементы в нём — уже прокси, а не те\n // объекты, что пришли в `register`. `indexOf` по исходной ссылке вернул бы\n // `-1`, и кадр остался бы в полосе после размонтирования.\n const index = entries.value.findIndex(item => item.id === entry.id)\n if (index >= 0)\n entries.value.splice(index, 1)\n scheduleReorder()\n }\n}\n\n/**\n * Потолок ожидания конца перехода ленты. `--gr-duration-base` — 240ms; запас\n * нужен на прерванный переход и на среду, где переходов нет вовсе.\n */\nconst WRAP_FALLBACK_MS = 600\n\nconst internalIndex = ref(0)\nconst currentIndex = computed(() => clampIndex(props.modelValue ?? internalIndex.value, total.value))\n\n/**\n * Замыкание кольца: `1` — идём с последнего кадра на первый, `-1` — обратно,\n * `0` — обычный шаг.\n *\n * Раньше `loop` просто сбрасывал индекс, и лента **прокручивалась назад через\n * все кадры**: на десятикадровой карусели с автопрокруткой каждый десятый шаг\n * был длинным обратным ходом. Теперь крайний слайд временно переезжает на\n * противоположный конец, лента доезжает до него как до соседа, и уже после\n * перехода индекс снимается без анимации.\n */\nconst wrapStep = ref<-1 | 0 | 1>(0)\n\n/** Сама лента: по ней делается принудительная перерисовка при снятии кольца. */\nconst trackEl = ref<HTMLElement | null>(null)\n\n/** На время снятия индекса переход выключается — иначе снятие само поедет. */\nconst suppressTransition = ref(false)\n\nlet wrapFallback: ReturnType<typeof setTimeout> | undefined\n\n/** Позиция ленты: при замыкании она уезжает на один кадр за край. */\nconst trackIndex = computed(() => {\n if (wrapStep.value === 1)\n return total.value\n if (wrapStep.value === -1)\n return -1\n return currentIndex.value\n})\n\n/**\n * Смещение слайда, изображающего соседа за краем. Вперёд — первый кадр уезжает\n * за последний, назад — последний встаёт перед первым.\n */\nfunction displacementOf(id: string): number {\n if (wrapStep.value === 0 || total.value < 2)\n return 0\n\n const index = entries.value.findIndex(entry => entry.id === id)\n if (wrapStep.value === 1)\n return index === 0 ? total.value * 100 : 0\n\n return index === total.value - 1 ? total.value * -100 : 0\n}\n\n/**\n * Попадает ли кадр в окно отрисовки. Окно замкнуто вместе с лентой: при `loop`\n * соседи последнего кадра — первые, и не нарисовать их значит показать пустоту\n * ровно в момент замыкания кольца.\n */\nfunction shouldRender(id: string): boolean {\n if (!props.virtual)\n return true\n\n const count = total.value\n if (count === 0)\n return true\n\n const index = entries.value.findIndex(entry => entry.id === id)\n if (index < 0)\n return true\n\n const overscan = Math.max(1, Math.trunc(props.virtualOverscan))\n const distance = Math.abs(index - currentIndex.value)\n\n return props.loop\n ? Math.min(distance, count - distance) <= overscan\n : distance <= overscan\n}\n\n/**\n * Конец замыкания: лента возвращается с позиции «за краем» на настоящий индекс.\n *\n * Модель здесь уже давно на новом кадре — её обновил `startWrap`. Отложи мы её\n * до этого момента, `update:modelValue` опаздывал бы на длительность перехода,\n * а там, где переходов нет вовсе, — на страховочный таймер.\n */\nfunction finishWrap(): void {\n if (wrapStep.value === 0)\n return\n\n clearTimeout(wrapFallback)\n wrapFallback = undefined\n\n suppressTransition.value = true\n wrapStep.value = 0\n\n /*\n * Переход возвращается после **принудительной перерисовки**, а не через\n * `requestAnimationFrame`: в фоновой вкладке кадры не идут вовсе, и лента\n * осталась бы с выключенным переходом навсегда — то есть дальше дёргалась бы\n * вместо движения. Чтение `offsetHeight` фиксирует новое положение\n * синхронно, и это работает в любой вкладке.\n */\n void nextTick().then(() => {\n void trackEl.value?.offsetHeight\n suppressTransition.value = false\n })\n}\n\n/**\n * Замкнуть кольцо в сторону `direction`. Возвращает `false`, если шаг обычный\n * и его надо выполнить как раньше.\n */\nfunction startWrap(direction: 1 | -1): boolean {\n if (!props.loop || total.value < 2)\n return false\n\n const atLast = currentIndex.value === total.value - 1\n const atFirst = currentIndex.value === 0\n if (!(direction === 1 ? atLast : atFirst))\n return false\n\n finishWrap()\n wrapStep.value = direction\n // Модель — сразу: она про то, какой кадр показан, а не про то, доехала ли\n // лента. Смещение и позиция «за краем» держатся до конца перехода.\n setIndex(direction === 1 ? 0 : total.value - 1)\n\n // `transitionend` в jsdom не наступает вовсе, а в живом браузере может не\n // прийти при прерванном переходе. Страховка возвращает ленту сама.\n wrapFallback = setTimeout(finishWrap, WRAP_FALLBACK_MS)\n return true\n}\n\nonBeforeUnmount(() => clearTimeout(wrapFallback))\n\nfunction setIndex(next: number): void {\n const value = clampIndex(next, total.value)\n if (value === currentIndex.value)\n return\n\n internalIndex.value = value\n emit('update:modelValue', value)\n}\n\nconst showIndicators = computed(() => resolvedIndicators.value !== 'none' && total.value > 1)\nconst showArrows = computed(() => props.arrows && total.value > 1)\nconst isThumbnails = computed(() => resolvedIndicators.value === 'thumbnails')\n\nconst atStart = computed(() => !props.loop && currentIndex.value <= 0)\nconst atEnd = computed(() => !props.loop && currentIndex.value >= total.value - 1)\n\nconst reducedMotion = ref(false)\nconst hovered = ref(false)\nconst documentHidden = ref(false)\n\n/** `null` — тумблер не трогали, и решает проп. */\nconst userIntent = ref<boolean | null>(null)\n\nconst playing = computed(() => total.value > 1\n && (userIntent.value ?? (props.autoplay && !reducedMotion.value)))\n\n/**\n * Живой регион читает кадр, только когда лента стоит: у движущейся карусели\n * объявление каждого кадра превратило бы страницу в неработающую.\n */\nconst liveMode = computed<'off' | 'polite'>(() => (playing.value ? 'off' : 'polite'))\n\nconst swipeGesture = useCarouselSwipe({\n disabled: () => !props.swipe || total.value <= 1,\n viewport: () => viewportEl.value,\n orientation: () => props.orientation,\n atEdge: direction => (direction === 1 ? atEnd.value : atStart.value),\n onStart: stopAutoplay,\n onSwipe: (direction) => {\n void stepBy(direction)\n },\n})\n\nconst autoplayTimer = useCarouselAutoplay({\n interval: () => props.autoplayInterval,\n enabled: () => playing.value,\n paused: () => hovered.value || documentHidden.value || swipeGesture.isDragging.value,\n advance: () => {\n if (startWrap(1))\n return\n\n const next = stepIndex(currentIndex.value, 1, total.value, props.loop)\n // Упёрлись в край без `loop` — показ окончен, а не зациклился.\n if (next === currentIndex.value) {\n userIntent.value = false\n return\n }\n finishWrap()\n setIndex(next)\n },\n})\n\nfunction stopAutoplay(): void {\n if (!playing.value)\n return\n\n userIntent.value = false\n announce(t('gr.carousel.autoplayStopped', 'Automatic slide show stopped'))\n}\n\n/**\n * `aria-live` обязан стать `polite` **раньше**, чем поменяется содержимое:\n * иначе мутация случится, пока регион ещё `off`, и не прозвучит вовсе.\n */\nasync function commitUserNavigation(next: number): Promise<void> {\n if (playing.value) {\n stopAutoplay()\n await nextTick()\n }\n\n finishWrap()\n setIndex(next)\n}\n\n/**\n * Шаг на соседний кадр. На краю кольца замыкание идёт через смещение крайнего\n * слайда, а не через сброс индекса: сброс прокручивал бы ленту назад через всё.\n */\nasync function stepBy(delta: 1 | -1): Promise<void> {\n if (playing.value) {\n stopAutoplay()\n await nextTick()\n }\n\n if (startWrap(delta))\n return\n\n finishWrap()\n setIndex(stepIndex(currentIndex.value, delta, total.value, props.loop))\n}\n\n/**\n * Переход ленты доехал — можно снимать замыкание. Слушаем только свой узел\n * (`.self`): всплывший переход дочернего кадра снял бы кольцо раньше времени.\n */\nfunction onTrackTransitionEnd(event: TransitionEvent): void {\n if (event.propertyName === 'transform')\n finishWrap()\n}\n\nfunction toggleAutoplay(): void {\n if (playing.value) {\n stopAutoplay()\n return\n }\n\n userIntent.value = true\n autoplayTimer.restart()\n}\n\nfunction goTo(index: number): void {\n void commitUserNavigation(clampIndex(index, total.value))\n}\n\nfunction step(delta: 1 | -1): void {\n void stepBy(delta as 1 | -1)\n}\n\nconst roving = useRovingFocus<number>({\n items: () => entries.value.map((_, index) => index),\n elementFor: index => tabRefs.value[index],\n orientation: () => 'horizontal',\n // Кольцо полосы замкнуто независимо от `loop`: тот управляет стрелками и\n // показом, а выбрать любой кадр напрямую можно всегда.\n wrap: () => true,\n initialKey: () => (total.value > 0 ? currentIndex.value : undefined),\n // Прокрутка до фокуса, а не после: иначе браузер доскроллит по-своему и\n // полоса дёрнется дважды.\n beforeFocus: index => scrollTabIntoView(index),\n})\n\n// Лента укоротилась под текущим кадром: модель потребителя и картинка разошлись\n// бы молча, поэтому индекс доводится до края и эмитится.\nwatch(total, (count) => {\n if (count === 0) {\n roving.reset()\n return\n }\n\n const requested = props.modelValue ?? internalIndex.value\n const clamped = clampIndex(requested, count)\n if (clamped !== requested) {\n internalIndex.value = clamped\n emit('update:modelValue', clamped)\n }\n})\n\n/**\n * Прокрутка **полосы**, а не страницы.\n *\n * `scrollIntoView` двигает всех предков, включая документ: карусель, уехавшая\n * под сгиб, на каждом шаге автопрокрутки утаскивала бы страницу обратно к себе.\n * Поэтому позиция считается сама и присваивается `scrollLeft` полосы.\n */\nfunction scrollTabIntoView(index: number): void {\n const strip = indicatorsEl.value\n const tab = tabRefs.value[index]\n if (!strip || !tab)\n return\n\n const next = stripScrollLeft(\n strip.scrollLeft,\n strip.clientWidth,\n tab.offsetLeft,\n tab.offsetLeft + tab.offsetWidth,\n )\n\n if (next !== strip.scrollLeft)\n strip.scrollLeft = next\n}\n\nfunction setTabRef(el: Element | ComponentPublicInstance | null, index: number): void {\n tabRefs.value[index] = el as HTMLElement | null\n}\n\nfunction onIndicatorKeydown(event: KeyboardEvent): void {\n if (total.value === 0)\n return\n\n const current = roving.rovingKey.value ?? 0\n\n if ((event.key === 'Enter' || event.key === ' ') && resolvedActivation.value === 'manual') {\n event.preventDefault()\n void commitUserNavigation(current)\n return\n }\n\n // Стрелки, `Home`, `End` ведёт примитив. Выбор не вешается на его `onMove`:\n // клик тоже зовёт `focusKey`, и модель менялась бы дважды.\n if (!roving.handleNavigationKeys(event))\n return\n\n if (resolvedActivation.value !== 'manual')\n void commitUserNavigation(roving.rovingKey.value ?? current)\n}\n\nfunction onIndicatorClick(index: number): void {\n roving.setActive(index)\n void commitUserNavigation(index)\n}\n\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, { enter: stopAutoplay })\n\nconst stripOverflow = ref<GrScrollOverflow>('none')\nlet resizeObserver: ResizeObserver | null = null\nlet measureScheduled = false\n\nfunction measureOverflow(): void {\n const el = indicatorsEl.value\n\n if (!el || !isThumbnails.value) {\n stripOverflow.value = 'none'\n return\n }\n\n stripOverflow.value = resolveScrollOverflow(el.scrollLeft, el.scrollWidth, el.clientWidth)\n}\n\nfunction scheduleMeasure(): void {\n if (measureScheduled)\n return\n\n measureScheduled = true\n void nextTick(() => {\n measureScheduled = false\n measureOverflow()\n })\n}\n\nfunction onVisibilityChange(): void {\n documentHidden.value = document.hidden\n}\n\nonMounted(() => {\n // Браузерный API в теле `setup` разошёлся бы с серверным рендером.\n reducedMotion.value = typeof window !== 'undefined'\n && window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches === true\n\n document.addEventListener('visibilitychange', onVisibilityChange)\n scheduleMeasure()\n\n // На сервере и в jsdom `ResizeObserver` отсутствует — измерять там нечего.\n if (typeof ResizeObserver === 'undefined')\n return\n\n resizeObserver = new ResizeObserver(scheduleMeasure)\n if (indicatorsEl.value)\n resizeObserver.observe(indicatorsEl.value)\n})\n\nonBeforeUnmount(() => {\n document.removeEventListener('visibilitychange', onVisibilityChange)\n resizeObserver?.disconnect()\n resizeObserver = null\n})\n\nwatch([total, isThumbnails], scheduleMeasure)\n\n// Кадр мог смениться не фокусом — показом или свайпом; переключатель всё равно\n// обязан оказаться на виду.\nwatch(currentIndex, async (index) => {\n await nextTick()\n scrollTabIntoView(index)\n})\n\nfunction entryAt(index: number): GrCarouselSlideEntry | undefined {\n return entries.value[index]\n}\n\nfunction positionLabelAt(index: number): string {\n return t('gr.carousel.slidePosition', '{index} of {total}', {\n index: index + 1,\n total: total.value,\n })\n}\n\nfunction indicatorName(index: number): string {\n return entryAt(index)?.label() ?? positionLabelAt(index)\n}\n\nfunction tabDomId(index: number): string {\n return `${entryAt(index)?.id ?? index}-tab`\n}\n\nconst trackStyle = computed(() => {\n const style: Record<string, string> = {\n '--gr-carousel-index': String(trackIndex.value),\n '--gr-carousel-drag': `${swipeGesture.offset.value}px`,\n }\n\n // На время жеста лента идёт за пальцем один в один: переход догонял бы курсор.\n if (swipeGesture.isDragging.value)\n style.transition = 'none'\n\n return style\n})\n\nprovide(GR_CAROUSEL_CONTEXT, {\n register,\n indexOf: id => entries.value.findIndex(entry => entry.id === id),\n isCurrent: id => entries.value[currentIndex.value]?.id === id,\n total,\n slideRole: computed(() => (showIndicators.value ? 'tabpanel' : 'group')),\n slideRoledescription: computed(() => t('gr.carousel.slideRoledescription', 'slide')),\n tabIdFor: (id) => {\n if (!showIndicators.value)\n return undefined\n const index = entries.value.findIndex(entry => entry.id === id)\n return index >= 0 ? tabDomId(index) : undefined\n },\n positionLabel: (id) => {\n const index = entries.value.findIndex(entry => entry.id === id)\n return positionLabelAt(index >= 0 ? index : 0)\n },\n displacementOf,\n orientation: computed(() => props.orientation),\n shouldRender,\n})\n\nif (__GR_DEV__) {\n onMounted(() => {\n if (props.orientation !== 'vertical')\n return\n\n // Высота вьюпорта — обязательное условие вертикальной ленты, и молчаливый\n // отказ тут хуже ошибки: карусель превращается в столбец кадров, а причина\n // не видна ни в разметке, ни в консоли.\n if ((viewportEl.value?.clientHeight ?? 0) === 0) {\n console.warn(\n '[granularity] GrCarousel: у вертикальной ленты нулевая высота вьюпорта — '\n + 'шаг считается от неё. Задайте высоту классом или стилем, иначе кадры '\n + 'встанут столбцом.',\n )\n }\n })\n\n watchEffect(() => {\n if (!props.ariaLabel && !props.ariaLabelledby) {\n console.warn(\n '[granularity] GrCarousel: у карусели нет доступного имени — передайте '\n + '`ariaLabel` или `ariaLabelledby`. `aria-roledescription` именем не является.',\n )\n }\n\n if (!props.arrows && resolvedIndicators.value === 'none' && total.value > 1) {\n console.warn(\n '[granularity] GrCarousel: `arrows: false` вместе с `indicators: \"none\"` '\n + 'не оставляет ни одного способа сменить кадр с клавиатуры.',\n )\n }\n\n if (isThumbnails.value && total.value > 0\n && entries.value.every(entry => !entry.hasThumbnail() && !entry.thumbnailSrc())) {\n console.warn(\n '[granularity] GrCarousel: `indicators=\"thumbnails\"`, но ни один слайд не дал '\n + 'миниатюру — задайте проп `thumbnail` или слот `#thumbnail` у `GrCarouselSlide`.',\n )\n }\n })\n}\n\ndefineExpose({\n /** Текущий кадр — единственный способ прочитать позицию без `v-model`. */\n index: computed(() => currentIndex.value),\n /** Число кадров: состав живёт в слоте, снаружи его посчитать нечем. */\n count: total,\n /** Идёт ли показ. Пауза под курсором его не выключает. */\n playing: computed(() => playing.value),\n next: () => step(1),\n prev: () => step(-1),\n goTo,\n play: () => {\n if (!playing.value)\n toggleAutoplay()\n },\n pause: stopAutoplay,\n})\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-carousel\n :class=\"[carouselRootBase, carouselRootAxis[props.orientation]]\"\n :role=\"landmark ? 'region' : 'group'\"\n :aria-roledescription=\"t('gr.carousel.roledescription', 'carousel')\"\n :aria-label=\"ariaLabelledby ? undefined : ariaLabel\"\n :aria-labelledby=\"ariaLabelledby\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <div\n ref=\"viewportEl\"\n data-gr-carousel-viewport\n :class=\"[\n carouselViewportBase,\n carouselViewportAxis[props.orientation],\n carouselViewportTouchAction[props.orientation],\n props.swipe ? carouselViewportSwipeClass : '',\n ]\"\n :aria-live=\"liveMode\"\n aria-atomic=\"true\"\n @pointerdown=\"swipeGesture.start\"\n >\n <div\n ref=\"trackEl\"\n data-gr-carousel-track\n :data-gr-carousel-vertical=\"props.orientation === 'vertical' ? '' : undefined\"\n :data-gr-carousel-wrapping=\"suppressTransition ? '' : undefined\"\n :class=\"[carouselTrackBase, carouselTrackAxis[props.orientation]]\"\n :style=\"trackStyle\"\n @transitionend.self=\"onTrackTransitionEnd\"\n >\n <slot />\n </div>\n\n <button\n v-if=\"props.autoplay && total > 1\"\n type=\"button\"\n data-gr-carousel-toggle\n :class=\"carouselToggleClass\"\n :aria-label=\"playing\n ? (pauseLabel ?? t('gr.carousel.pause', 'Stop automatic slide show'))\n : (playLabel ?? t('gr.carousel.play', 'Start automatic slide show'))\"\n @click=\"toggleAutoplay\"\n >\n <component :is=\"playing ? IconPause : IconPlay\" :class=\"carouselIconClass\" aria-hidden=\"true\" />\n </button>\n\n <button\n v-if=\"showArrows\"\n type=\"button\"\n data-gr-carousel-prev\n :class=\"grCarouselControlClass('prev', atStart, props.orientation)\"\n :aria-disabled=\"atStart ? 'true' : undefined\"\n :aria-label=\"prevLabel ?? t('gr.carousel.previous', 'Previous slide')\"\n @click=\"atStart ? undefined : step(-1)\"\n >\n <slot name=\"prev\" :disabled=\"atStart\">\n <component\n :is=\"props.orientation === 'vertical' ? IconChevronUp : IconChevronLeft\"\n :class=\"carouselIconClass\"\n aria-hidden=\"true\"\n />\n </slot>\n </button>\n\n <button\n v-if=\"showArrows\"\n type=\"button\"\n data-gr-carousel-next\n :class=\"grCarouselControlClass('next', atEnd, props.orientation)\"\n :aria-disabled=\"atEnd ? 'true' : undefined\"\n :aria-label=\"nextLabel ?? t('gr.carousel.next', 'Next slide')\"\n @click=\"atEnd ? undefined : step(1)\"\n >\n <slot name=\"next\" :disabled=\"atEnd\">\n <component\n :is=\"props.orientation === 'vertical' ? IconChevronDown : IconChevronRight\"\n :class=\"carouselIconClass\"\n aria-hidden=\"true\"\n />\n </slot>\n </button>\n </div>\n\n <div\n v-if=\"showIndicators\"\n ref=\"indicatorsEl\"\n role=\"tablist\"\n data-gr-carousel-indicators\n :data-variant=\"resolvedIndicators\"\n :data-overflow=\"stripOverflow\"\n :class=\"grCarouselIndicatorsClass(resolvedIndicators)\"\n :aria-label=\"indicatorsLabel ?? t('gr.carousel.indicators', 'Slides')\"\n @keydown=\"onIndicatorKeydown\"\n @scroll.passive=\"scheduleMeasure\"\n >\n <button\n v-for=\"(entry, index) in entries\"\n :id=\"tabDomId(index)\"\n :key=\"entry.id\"\n :ref=\"el => setTabRef(el, index)\"\n type=\"button\"\n role=\"tab\"\n data-gr-carousel-indicator\n :aria-selected=\"index === currentIndex ? 'true' : 'false'\"\n :aria-controls=\"entry.id\"\n :aria-label=\"indicatorName(index)\"\n :tabindex=\"roving.tabindexFor(index)\"\n :class=\"grCarouselIndicatorClass(resolvedIndicators, index === currentIndex, resolvedTone)\"\n @click=\"onIndicatorClick(index)\"\n >\n <component :is=\"entry.thumbnail\" v-if=\"isThumbnails && entry.hasThumbnail()\" />\n <img\n v-else-if=\"isThumbnails && entry.thumbnailSrc()\"\n :src=\"entry.thumbnailSrc()\"\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n :class=\"carouselThumbImageClass\"\n >\n <span v-else-if=\"isThumbnails\" :class=\"carouselThumbFallbackClass\">{{ index + 1 }}</span>\n </button>\n </div>\n </div>\n</template>\n\n<style>\n[data-gr-carousel-track] {\n transform: translateX(calc(var(--gr-carousel-index, 0) * -100% + var(--gr-carousel-drag, 0px)));\n}\n\n/*\n * Снятие индекса после замыкания кольца обязано пройти без анимации: иначе\n * лента поедет обратно через все кадры — ровно тот ход, ради устранения\n * которого замыкание и сделано.\n */\n[data-gr-carousel-track][data-gr-carousel-wrapping] {\n transition: none;\n}\n\n/*\n * Вертикальная лента: шаг считается от **высоты вьюпорта**, а не от высоты\n * самой ленты. Поэтому вьюпорту нужна определённая высота — без неё колонка\n * кадров растёт по содержимому, и `-100%` означает всю ленту разом.\n *\n * Направление письма вертикали не касается, поэтому RTL-зеркала здесь нет.\n */\n[data-gr-carousel-track][data-gr-carousel-vertical],\n[dir='rtl'] [data-gr-carousel-track][data-gr-carousel-vertical] {\n transform: translateY(calc(var(--gr-carousel-index, 0) * -100% + var(--gr-carousel-drag, 0px)));\n}\n\n/*\n * Индекс зеркалится, смещение жеста — нет: палец двигает ленту на столько же\n * физических пикселей независимо от направления письма.\n */\n[dir='rtl'] [data-gr-carousel-track] {\n transform: translateX(calc(var(--gr-carousel-index, 0) * 100% + var(--gr-carousel-drag, 0px)));\n}\n\n[data-gr-carousel-indicators][data-variant='thumbnails'] {\n /*\n * `scrollIntoView({ inline: 'nearest' })` прижимает миниатюру вплотную к краю.\n * Без отступа прокрутки фокус-кольцо оказалось бы ровно под затуханием.\n */\n scroll-padding-inline: var(--gr-carousel-thumbs-fade, 1.5rem);\n}\n\n[data-gr-carousel-indicators][data-overflow='start'] {\n --gr-carousel-thumbs-mask: linear-gradient(to right, transparent 0, #000 var(--gr-carousel-thumbs-fade, 1.5rem));\n}\n\n[data-gr-carousel-indicators][data-overflow='end'] {\n --gr-carousel-thumbs-mask: linear-gradient(to right, #000 calc(100% - var(--gr-carousel-thumbs-fade, 1.5rem)), transparent 100%);\n}\n\n[data-gr-carousel-indicators][data-overflow='both'] {\n --gr-carousel-thumbs-mask: linear-gradient(\n to right,\n transparent 0,\n #000 var(--gr-carousel-thumbs-fade, 1.5rem),\n #000 calc(100% - var(--gr-carousel-thumbs-fade, 1.5rem)),\n transparent 100%\n );\n}\n\n[dir='rtl'] [data-gr-carousel-indicators][data-overflow='start'] {\n --gr-carousel-thumbs-mask: linear-gradient(to left, transparent 0, #000 var(--gr-carousel-thumbs-fade, 1.5rem));\n}\n\n[dir='rtl'] [data-gr-carousel-indicators][data-overflow='end'] {\n --gr-carousel-thumbs-mask: linear-gradient(to left, #000 calc(100% - var(--gr-carousel-thumbs-fade, 1.5rem)), transparent 100%);\n}\n\n[data-gr-carousel-indicators]:is([data-overflow='start'], [data-overflow='end'], [data-overflow='both']) {\n -webkit-mask-image: var(--gr-carousel-thumbs-mask);\n mask-image: var(--gr-carousel-thumbs-mask);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, inject, onBeforeUnmount, ref, useId, useSlots } from 'vue'\n\nimport { GR_CAROUSEL_CONTEXT } from './grCarouselContext'\nimport { carouselSlideAxis, carouselSlideBase } from './grCarouselStyles'\n\nexport interface GrCarouselSlideProps {\n /** Имя слайда: подпись его переключателя и доступное имя самого кадра. */\n label?: string\n /** URL миниатюры для `indicators=\"thumbnails\"`. Слот `#thumbnail` сильнее. */\n thumbnail?: string\n}\n\nconst props = withDefaults(defineProps<GrCarouselSlideProps>(), {\n label: undefined,\n thumbnail: undefined,\n})\n\ndefineSlots<{\n /** Содержимое кадра. */\n default?: () => unknown\n /**\n * Своя разметка миниатюры. Рендерит её полоса переключателей `GrCarousel`,\n * поэтому `<slot name=\"thumbnail\">` здесь не стоит: узел уезжает наверх при\n * регистрации. Появится он тут — понадобится запись в `DOMAIN_SLOTS` гейта\n * `slotContract.test.ts`.\n */\n thumbnail?: () => unknown\n}>()\n\nconst carousel = inject(GR_CAROUSEL_CONTEXT)\n\nif (!carousel) {\n throw new Error('GrCarouselSlide must be used inside GrCarousel')\n}\n\nconst slots = useSlots()\nconst slideId = useId()\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Ссылка создаётся один раз: `:is` со стабильной ссылкой не перемонтирует\n// миниатюру на каждый рендер полосы.\nfunction renderThumbnail(): unknown {\n return slots.thumbnail?.()\n}\n\nonBeforeUnmount(carousel.register({\n id: slideId,\n label: () => props.label,\n thumbnailSrc: () => props.thumbnail,\n hasThumbnail: () => Boolean(slots.thumbnail),\n thumbnail: renderThumbnail,\n el: () => rootEl.value,\n}))\n\nconst isCurrent = computed(() => carousel.isCurrent(slideId))\nconst renders = computed(() => carousel.shouldRender(slideId))\n\n/**\n * Слайд не анимирует своё смещение намеренно: он обязан оказаться на новом\n * месте **до** того, как поедет лента, иначе кадр гнался бы за ней.\n */\nconst displacementStyle = computed(() => {\n const percent = carousel.displacementOf(slideId)\n return percent === 0 ? undefined : { transform: `translateX(${percent}%)` }\n})\nconst labelledBy = computed(() => carousel.tabIdFor(slideId))\nconst accessibleName = computed(() => props.label ?? carousel.positionLabel(slideId))\n</script>\n\n<template>\n <div\n :id=\"slideId\"\n ref=\"rootEl\"\n data-gr-carousel-slide\n :class=\"[carouselSlideBase, carouselSlideAxis[carousel!.orientation.value]]\"\n :role=\"carousel!.slideRole.value\"\n :aria-roledescription=\"carousel!.slideRoledescription.value\"\n :aria-labelledby=\"labelledBy\"\n :aria-label=\"labelledBy ? undefined : accessibleName\"\n :inert=\"isCurrent ? undefined : true\"\n :style=\"displacementStyle\"\n >\n <slot v-if=\"renders\" />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, onBeforeUnmount, ref, useId, useSlots } from 'vue'\n\nimport { GR_CAROUSEL_CONTEXT } from './grCarouselContext'\nimport { carouselSlideAxis, carouselSlideBase } from './grCarouselStyles'\n\nexport interface GrCarouselSlideProps {\n /** Имя слайда: подпись его переключателя и доступное имя самого кадра. */\n label?: string\n /** URL миниатюры для `indicators=\"thumbnails\"`. Слот `#thumbnail` сильнее. */\n thumbnail?: string\n}\n\nconst props = withDefaults(defineProps<GrCarouselSlideProps>(), {\n label: undefined,\n thumbnail: undefined,\n})\n\ndefineSlots<{\n /** Содержимое кадра. */\n default?: () => unknown\n /**\n * Своя разметка миниатюры. Рендерит её полоса переключателей `GrCarousel`,\n * поэтому `<slot name=\"thumbnail\">` здесь не стоит: узел уезжает наверх при\n * регистрации. Появится он тут — понадобится запись в `DOMAIN_SLOTS` гейта\n * `slotContract.test.ts`.\n */\n thumbnail?: () => unknown\n}>()\n\nconst carousel = inject(GR_CAROUSEL_CONTEXT)\n\nif (!carousel) {\n throw new Error('GrCarouselSlide must be used inside GrCarousel')\n}\n\nconst slots = useSlots()\nconst slideId = useId()\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Ссылка создаётся один раз: `:is` со стабильной ссылкой не перемонтирует\n// миниатюру на каждый рендер полосы.\nfunction renderThumbnail(): unknown {\n return slots.thumbnail?.()\n}\n\nonBeforeUnmount(carousel.register({\n id: slideId,\n label: () => props.label,\n thumbnailSrc: () => props.thumbnail,\n hasThumbnail: () => Boolean(slots.thumbnail),\n thumbnail: renderThumbnail,\n el: () => rootEl.value,\n}))\n\nconst isCurrent = computed(() => carousel.isCurrent(slideId))\nconst renders = computed(() => carousel.shouldRender(slideId))\n\n/**\n * Слайд не анимирует своё смещение намеренно: он обязан оказаться на новом\n * месте **до** того, как поедет лента, иначе кадр гнался бы за ней.\n */\nconst displacementStyle = computed(() => {\n const percent = carousel.displacementOf(slideId)\n return percent === 0 ? undefined : { transform: `translateX(${percent}%)` }\n})\nconst labelledBy = computed(() => carousel.tabIdFor(slideId))\nconst accessibleName = computed(() => props.label ?? carousel.positionLabel(slideId))\n</script>\n\n<template>\n <div\n :id=\"slideId\"\n ref=\"rootEl\"\n data-gr-carousel-slide\n :class=\"[carouselSlideBase, carouselSlideAxis[carousel!.orientation.value]]\"\n :role=\"carousel!.slideRole.value\"\n :aria-roledescription=\"carousel!.slideRoledescription.value\"\n :aria-labelledby=\"labelledBy\"\n :aria-label=\"labelledBy ? undefined : accessibleName\"\n :inert=\"isCurrent ? undefined : true\"\n :style=\"displacementStyle\"\n >\n <slot v-if=\"renders\" />\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { n as GrCarousel_default, t as GrCarouselSlide_default } from "./chunks/GrCarousel-
|
|
2
|
-
import { n as grCarouselSafelist, t as grCarouselConfig } from "../../chunks/config-
|
|
1
|
+
import { n as GrCarousel_default, t as GrCarouselSlide_default } from "./chunks/GrCarousel-CBj-PEPB.js";
|
|
2
|
+
import { n as grCarouselSafelist, t as grCarouselConfig } from "../../chunks/config-CPhcZzHi.js";
|
|
3
3
|
export { GrCarousel_default as GrCarousel, GrCarousel_default as default, GrCarouselSlide_default as GrCarouselSlide, grCarouselConfig, grCarouselSafelist };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[data-gr-carousel-track]{transform:translateX(calc(var(--gr-carousel-index,0) * -100% + var(--gr-carousel-drag,0px)))}[dir=rtl] [data-gr-carousel-track]{transform:translateX(calc(var(--gr-carousel-index,0) * 100% + var(--gr-carousel-drag,0px)))}[data-gr-carousel-indicators][data-variant=thumbnails]{scroll-padding-inline:var(--gr-carousel-thumbs-fade,1.5rem)}[data-gr-carousel-indicators][data-overflow=start]{--gr-carousel-thumbs-mask:linear-gradient(to right, transparent 0, #000 var(--gr-carousel-thumbs-fade,1.5rem))}[data-gr-carousel-indicators][data-overflow=end]{--gr-carousel-thumbs-mask:linear-gradient(to right, #000 calc(100% - var(--gr-carousel-thumbs-fade,1.5rem)), transparent 100%)}[data-gr-carousel-indicators][data-overflow=both]{--gr-carousel-thumbs-mask:linear-gradient(to right, transparent 0, #000 var(--gr-carousel-thumbs-fade,1.5rem), #000 calc(100% - var(--gr-carousel-thumbs-fade,1.5rem)), transparent 100%)}[dir=rtl] [data-gr-carousel-indicators][data-overflow=start]{--gr-carousel-thumbs-mask:linear-gradient(to left, transparent 0, #000 var(--gr-carousel-thumbs-fade,1.5rem))}[dir=rtl] [data-gr-carousel-indicators][data-overflow=end]{--gr-carousel-thumbs-mask:linear-gradient(to left, #000 calc(100% - var(--gr-carousel-thumbs-fade,1.5rem)), transparent 100%)}[data-gr-carousel-indicators]:is([data-overflow=start],[data-overflow=end],[data-overflow=both]){-webkit-mask-image:var(--gr-carousel-thumbs-mask);mask-image:var(--gr-carousel-thumbs-mask)}
|
|
1
|
+
[data-gr-carousel-track]{transform:translateX(calc(var(--gr-carousel-index,0) * -100% + var(--gr-carousel-drag,0px)))}[data-gr-carousel-track][data-gr-carousel-wrapping]{transition:none}[data-gr-carousel-track][data-gr-carousel-vertical],[dir=rtl] [data-gr-carousel-track][data-gr-carousel-vertical]{transform:translateY(calc(var(--gr-carousel-index,0) * -100% + var(--gr-carousel-drag,0px)))}[dir=rtl] [data-gr-carousel-track]{transform:translateX(calc(var(--gr-carousel-index,0) * 100% + var(--gr-carousel-drag,0px)))}[data-gr-carousel-indicators][data-variant=thumbnails]{scroll-padding-inline:var(--gr-carousel-thumbs-fade,1.5rem)}[data-gr-carousel-indicators][data-overflow=start]{--gr-carousel-thumbs-mask:linear-gradient(to right, transparent 0, #000 var(--gr-carousel-thumbs-fade,1.5rem))}[data-gr-carousel-indicators][data-overflow=end]{--gr-carousel-thumbs-mask:linear-gradient(to right, #000 calc(100% - var(--gr-carousel-thumbs-fade,1.5rem)), transparent 100%)}[data-gr-carousel-indicators][data-overflow=both]{--gr-carousel-thumbs-mask:linear-gradient(to right, transparent 0, #000 var(--gr-carousel-thumbs-fade,1.5rem), #000 calc(100% - var(--gr-carousel-thumbs-fade,1.5rem)), transparent 100%)}[dir=rtl] [data-gr-carousel-indicators][data-overflow=start]{--gr-carousel-thumbs-mask:linear-gradient(to left, transparent 0, #000 var(--gr-carousel-thumbs-fade,1.5rem))}[dir=rtl] [data-gr-carousel-indicators][data-overflow=end]{--gr-carousel-thumbs-mask:linear-gradient(to left, #000 calc(100% - var(--gr-carousel-thumbs-fade,1.5rem)), transparent 100%)}[data-gr-carousel-indicators]:is([data-overflow=start],[data-overflow=end],[data-overflow=both]){-webkit-mask-image:var(--gr-carousel-thumbs-mask);mask-image:var(--gr-carousel-thumbs-mask)}
|
|
@@ -35,6 +35,7 @@ var _hoisted_3 = ["id"];
|
|
|
35
35
|
var GrCheckbox_default = /* @__PURE__ */ defineComponent({
|
|
36
36
|
__name: "GrCheckbox",
|
|
37
37
|
props: {
|
|
38
|
+
tabindex: { default: void 0 },
|
|
38
39
|
modelValue: {
|
|
39
40
|
type: Boolean,
|
|
40
41
|
default: void 0
|
|
@@ -237,7 +238,7 @@ var GrCheckbox_default = /* @__PURE__ */ defineComponent({
|
|
|
237
238
|
"aria-describedby": unref(describedBy),
|
|
238
239
|
"aria-label": __props.ariaLabel,
|
|
239
240
|
"aria-labelledby": labelledBy.value,
|
|
240
|
-
tabindex: resolvedDisabled.value ? -1 : 0,
|
|
241
|
+
tabindex: resolvedDisabled.value ? -1 : __props.tabindex ?? 0,
|
|
241
242
|
class: normalizeClass(controlClassName.value),
|
|
242
243
|
onKeydown: withKeys(withModifiers(toggle, ["prevent"]), ["space"]),
|
|
243
244
|
onFocus: _cache[0] || (_cache[0] = ($event) => emit("focus", $event)),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrCheckbox-B4NJc7Ur.js","names":[],"sources":["../../../../src/components/GrCheckbox/grCheckboxGroupContext.ts","../../../../src/components/GrCheckbox/GrCheckbox.vue","../../../../src/components/GrCheckbox/GrCheckbox.vue"],"sourcesContent":["import type { ComputedRef, InjectionKey } from 'vue'\n\nimport type { GrCheckboxSize } from './grCheckboxStyles'\n\nexport type GrCheckboxGroupContext = {\n /** Выбранные значения группы. Чекбокс сравнивает с ними свой `value`. */\n modelValue: ComputedRef<string[]>\n name: ComputedRef<string | undefined>\n disabled: ComputedRef<boolean>\n readonly: ComputedRef<boolean>\n invalid: ComputedRef<boolean>\n /**\n * Обязательность группы объявляют её чекбоксы: `role=\"group\"` не поддерживает\n * `aria-required` (axe: `aria-allowed-attr`), а `role=\"checkbox\"` — да.\n */\n required: ComputedRef<boolean>\n size: ComputedRef<GrCheckboxSize>\n /** Добавляет или убирает значение из выбранных. */\n toggle: (value: string, checked: boolean) => void\n}\n\nexport const GR_CHECKBOX_GROUP_CONTEXT: InjectionKey<GrCheckboxGroupContext> = Symbol('GR_CHECKBOX_GROUP_CONTEXT')\n","<script setup lang=\"ts\">\n/**\n * GrCheckbox — GR-примитив чекбокса с нативным скрытым `<input type=\"checkbox\">`\n * для интеграции с HTML-формами (`FormData`, `form`).\n *\n * Источник истины — нативный input: клик по нему (в т.ч. по внешнему\n * `<label for=\"...\">`) слушается через `@change` и эмитит модель. Клик по видимой\n * части компонента переключает через корневой обработчик.\n *\n * Клавиатура: `Space` переключает значение (Enter — намеренно нет, это нестандартно\n * для чекбоксов). Фокус — на самом контроле (квадратике), как у нативного чекбокса.\n *\n * A11y: `role=\"checkbox\"` + `aria-checked` (`true`/`false`/`mixed`) + `aria-disabled`.\n * Роль висит **только на контроле**, а не на всей строке с подписью — по двум причинам:\n * - роль объявляет своих потомков презентационными, поэтому ни нативный input, ни\n * интерактивная подпись (ссылка на политику, кнопка «показать изменения») не могут\n * жить внутри: скринридер теряет их, axe падает на `nested-interactive`;\n * - имя виджета берётся из подписи через `aria-labelledby`, что и позволяет держать\n * её снаружи вместе со всем её интерактивным содержимым.\n *\n * `required` объявляется только через `aria-required`, на скрытый input он не уходит.\n * Нативная проверка потребовала бы фокуса на невалидном контроле, а он невидим и\n * `aria-hidden` — Chrome в таком случае молча отменяет сабмит всей формы\n * («An invalid form control … is not focusable»). Обязательность проверяет\n * `GrForm` правилом `required` — см. `docs/components/GrCheckbox.md`.\n *\n * Внутри `GrCheckboxGroup` значение приходит из группы: свой `modelValue` не\n * задаётся, а `value` сравнивается с массивом выбранных.\n */\nimport { computed, inject, onMounted, ref, useId, useSlots, watch } from 'vue'\nimport IconCheck from '~icons/lucide/check'\nimport IconMinus from '~icons/lucide/minus'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport { GR_CHECKBOX_GROUP_CONTEXT } from './grCheckboxGroupContext'\nimport {\n grCheckboxCheckIconClass,\n grCheckboxControlClass,\n grCheckboxIndeterminateIconClass,\n grCheckboxLabelClass,\n grCheckboxRootClass,\n type GrCheckboxLabelPosition,\n type GrCheckboxSize,\n} from './grCheckboxStyles'\n\nexport type { GrCheckboxLabelPosition, GrCheckboxSize } from './grCheckboxStyles'\n\nexport interface GrCheckboxProps {\n /**\n * Остановка `Tab` у самого переключателя.\n *\n * Нужна составным виджетам, которые забирают таб-порядок себе: в сетке\n * `GrDataTable` (`cell-navigation`) `Tab` принадлежит таблице целиком, и\n * чекбокс в ячейке своей остановки держать не должен — до него добираются\n * стрелкой до ячейки и `Enter`. Выключенный переключатель остаётся вне\n * обхода в любом случае.\n */\n tabindex?: number\n\n /** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */\n modelValue?: boolean\n disabled?: boolean\n name?: string\n value?: string\n /** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */\n required?: boolean\n /** Только для чтения: состояние видно, но не переключается. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n form?: string\n /** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for=\"...\">`. */\n id?: string\n /** Промежуточное («смешанное») состояние: `aria-checked=\"mixed\"`, индикатор — тире. */\n indeterminate?: boolean\n /** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */\n ariaLabel?: string\n /** Сторона подписи относительно контрола. */\n labelPosition?: GrCheckboxLabelPosition\n /** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */\n size?: GrCheckboxSize\n}\n\nexport interface GrCheckboxEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'change', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst hiddenInputStyle = {\n position: 'absolute',\n opacity: '0',\n width: '0',\n height: '0',\n pointerEvents: 'none',\n} as const\n\nconst props = withDefaults(defineProps<GrCheckboxProps>(), {\n modelValue: undefined,\n tabindex: undefined,\n disabled: undefined,\n name: undefined,\n value: 'on',\n required: false,\n readonly: false,\n invalid: false,\n form: undefined,\n id: undefined,\n indeterminate: false,\n ariaLabel: undefined,\n labelPosition: 'end',\n size: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxEmits>()\ndefineSlots<{\n /** Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. */\n default?: () => any\n}>()\n\nconst slots = useSlots()\n\nconst labelId = useId()\nconst hasLabel = computed(() => Boolean(slots.default))\n\nconst group = inject(GR_CHECKBOX_GROUP_CONTEXT, null)\n\nconst checked = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n if (group)\n return group.modelValue.value.includes(props.value)\n\n return false\n})\n\nconst resolvedName = computed(() => props.name ?? group?.name.value)\n\n// Контекст `GrFormField`. Id поля вешается на `span[role=\"checkbox\"]` — именно он\n// виджет и держит фокус; на скрытом `aria-hidden`-инпуте он был бы бесполезен\n// (клик по подписи уводил бы фокус в невидимый элемент). Роль-виджет не является\n// labelable-элементом, поэтому имя от подписи поля приходит через `aria-labelledby`.\nconst {\n disabled: isDisabled,\n id: fieldControlId,\n labelId: fieldLabelId,\n describedBy,\n invalid: fieldInvalid,\n required: fieldRequired,\n readonly: fieldReadonly,\n} = useGrFormControl(() => props)\n\n// «Или», а не `??`: `isDisabled` уже сведён к булеву (свой проп + контекст\n// поля и формы), и `??` до группы просто не дошёл бы.\nconst resolvedDisabled = computed(() => isDisabled.value || Boolean(group?.disabled.value))\n\n// `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` — объявлять\n// обязательность и режим чтения группы обязаны сами чекбоксы.\nconst isRequired = computed(() => fieldRequired.value || Boolean(group?.required.value))\n\nconst isReadonly = computed(() => fieldReadonly.value || Boolean(group?.readonly.value))\n\n// Ошибка группы красит чекбоксы, но не объявляется на каждом из них: `aria-invalid`\n// уже висит на самой группе, и дублировать его на всех пунктах — значит заставить\n// диктор повторить «неверное значение» столько раз, сколько в группе чекбоксов.\nconst isInvalid = computed(() => fieldInvalid.value)\nconst showsInvalid = computed(() => isInvalid.value || Boolean(group?.invalid.value))\n\nconst labelledBy = computed(() => {\n if (props.ariaLabel)\n return undefined\n if (hasLabel.value)\n return labelId\n return fieldLabelId.value\n})\n\n// Эффективный размер: локальный проп → группа → `GrConfigProvider` → `md`.\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrCheckbox' },\n)\n\nconst rootClassName = computed(() => grCheckboxRootClass({\n size: resolvedSize.value,\n disabled: resolvedDisabled.value,\n labelPosition: props.labelPosition,\n}))\n\nconst controlClassName = computed(() => grCheckboxControlClass({\n size: resolvedSize.value,\n active: checked.value || props.indeterminate,\n disabled: resolvedDisabled.value,\n invalid: showsInvalid.value,\n}))\n\nconst indeterminateIconClassName = computed(() => grCheckboxIndeterminateIconClass(resolvedSize.value))\n\nconst checkIconClassName = computed(() => grCheckboxCheckIconClass({\n size: resolvedSize.value,\n checked: checked.value,\n}))\n\nconst labelClassName = computed(() => grCheckboxLabelClass(resolvedSize.value))\n\n// Держим `.checked` на нативном input синхронно с состоянием — `:checked`-биндинг\n// на скрытом элементе иногда отстаёт при программных обновлениях.\nconst nativeInput = ref<HTMLInputElement | null>(null)\nconst control = ref<HTMLElement | null>(null)\nwatch(\n checked,\n (value) => {\n if (nativeInput.value && nativeInput.value.checked !== value)\n nativeInput.value.checked = value\n },\n)\n\n// `indeterminate` можно выставить только через JS-свойство (не атрибут).\nfunction syncIndeterminate(): void {\n if (nativeInput.value)\n nativeInput.value.indeterminate = props.indeterminate\n}\nwatch(() => props.indeterminate, syncIndeterminate)\nonMounted(syncIndeterminate)\n\nfunction setChecked(next: boolean): void {\n if (resolvedDisabled.value || isReadonly.value) {\n // Нативный input мог уже переключиться от клика по внешнему `<label for>` —\n // возвращаем его к состоянию модели, иначе форма отправит непринятое значение.\n if (nativeInput.value)\n nativeInput.value.checked = checked.value\n return\n }\n\n if (props.modelValue !== undefined || !group) {\n emit('update:modelValue', next)\n emit('change', next)\n return\n }\n\n group.toggle(props.value, next)\n emit('change', next)\n}\n\nfunction toggle(): void {\n // Из промежуточного состояния переключаемся во «включено» (стандартное поведение).\n setChecked(props.indeterminate ? true : !checked.value)\n}\n\n// Клик по нативному input (в т.ч. по внешнему `<label for=\"...\">`) уже переключил его\n// `.checked` — берём значение как источник истины и эмитим модель.\nfunction onNativeChange(e: Event): void {\n setChecked((e.target as HTMLInputElement).checked)\n}\n\n// `<label for>` уводит фокус на скрытый input — визуально фокус пропадает. Возвращаем\n// его на контрол, который этот фокус и показывает.\nfunction onNativeFocus(): void {\n control.value?.focus()\n}\n\nfunction focus(): void {\n control.value?.focus()\n}\n\nfunction blur(): void {\n control.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n// Подпись держится снаружи роли-виджета именно для того, чтобы могла содержать\n// ссылки и кнопки, — поэтому клик по её интерактивному содержимому чекбокс не\n// переключает. Вложенный `<label>` считается интерактивным: он адресует\n// собственный контрол, и переключение чекбокса «заодно» было бы сюрпризом.\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el)\n return false\n return !!el.closest('a,button,input,select,textarea,label,[role=\"button\"],[role=\"link\"]')\n}\n\nfunction onClick(e: MouseEvent): void {\n if (isInteractiveTarget(e.target))\n return\n toggle()\n}\n</script>\n\n<template>\n <div\n data-gr-checkbox\n :class=\"rootClassName\"\n @click=\"onClick\"\n >\n <input\n :id=\"id\"\n ref=\"nativeInput\"\n type=\"checkbox\"\n :checked=\"checked\"\n :disabled=\"resolvedDisabled\"\n :name=\"resolvedName\"\n :value=\"value\"\n :form=\"form\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :style=\"hiddenInputStyle\"\n @change=\"onNativeChange\"\n @focus=\"onNativeFocus\"\n >\n <span\n :id=\"fieldControlId\"\n ref=\"control\"\n data-gr-checkbox-indicator\n role=\"checkbox\"\n :aria-checked=\"indeterminate ? 'mixed' : (checked ? 'true' : 'false')\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :tabindex=\"resolvedDisabled ? -1 : (tabindex ?? 0)\"\n :class=\"controlClassName\"\n @keydown.space.prevent=\"toggle\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <IconMinus\n v-if=\"indeterminate\"\n :class=\"indeterminateIconClassName\"\n />\n <IconCheck\n v-else\n :class=\"checkIconClassName\"\n />\n </span>\n <span\n v-if=\"hasLabel\"\n :id=\"labelId\"\n :class=\"labelClassName\"\n >\n <slot />\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckbox — GR-примитив чекбокса с нативным скрытым `<input type=\"checkbox\">`\n * для интеграции с HTML-формами (`FormData`, `form`).\n *\n * Источник истины — нативный input: клик по нему (в т.ч. по внешнему\n * `<label for=\"...\">`) слушается через `@change` и эмитит модель. Клик по видимой\n * части компонента переключает через корневой обработчик.\n *\n * Клавиатура: `Space` переключает значение (Enter — намеренно нет, это нестандартно\n * для чекбоксов). Фокус — на самом контроле (квадратике), как у нативного чекбокса.\n *\n * A11y: `role=\"checkbox\"` + `aria-checked` (`true`/`false`/`mixed`) + `aria-disabled`.\n * Роль висит **только на контроле**, а не на всей строке с подписью — по двум причинам:\n * - роль объявляет своих потомков презентационными, поэтому ни нативный input, ни\n * интерактивная подпись (ссылка на политику, кнопка «показать изменения») не могут\n * жить внутри: скринридер теряет их, axe падает на `nested-interactive`;\n * - имя виджета берётся из подписи через `aria-labelledby`, что и позволяет держать\n * её снаружи вместе со всем её интерактивным содержимым.\n *\n * `required` объявляется только через `aria-required`, на скрытый input он не уходит.\n * Нативная проверка потребовала бы фокуса на невалидном контроле, а он невидим и\n * `aria-hidden` — Chrome в таком случае молча отменяет сабмит всей формы\n * («An invalid form control … is not focusable»). Обязательность проверяет\n * `GrForm` правилом `required` — см. `docs/components/GrCheckbox.md`.\n *\n * Внутри `GrCheckboxGroup` значение приходит из группы: свой `modelValue` не\n * задаётся, а `value` сравнивается с массивом выбранных.\n */\nimport { computed, inject, onMounted, ref, useId, useSlots, watch } from 'vue'\nimport IconCheck from '~icons/lucide/check'\nimport IconMinus from '~icons/lucide/minus'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\n\nimport { GR_CHECKBOX_GROUP_CONTEXT } from './grCheckboxGroupContext'\nimport {\n grCheckboxCheckIconClass,\n grCheckboxControlClass,\n grCheckboxIndeterminateIconClass,\n grCheckboxLabelClass,\n grCheckboxRootClass,\n type GrCheckboxLabelPosition,\n type GrCheckboxSize,\n} from './grCheckboxStyles'\n\nexport type { GrCheckboxLabelPosition, GrCheckboxSize } from './grCheckboxStyles'\n\nexport interface GrCheckboxProps {\n /**\n * Остановка `Tab` у самого переключателя.\n *\n * Нужна составным виджетам, которые забирают таб-порядок себе: в сетке\n * `GrDataTable` (`cell-navigation`) `Tab` принадлежит таблице целиком, и\n * чекбокс в ячейке своей остановки держать не должен — до него добираются\n * стрелкой до ячейки и `Enter`. Выключенный переключатель остаётся вне\n * обхода в любом случае.\n */\n tabindex?: number\n\n /** Не задан внутри `GrCheckboxGroup` — состояние берётся из группы. */\n modelValue?: boolean\n disabled?: boolean\n name?: string\n value?: string\n /** Обязательное поле: объявляется как `aria-required`, нативной проверки нет. */\n required?: boolean\n /** Только для чтения: состояние видно, но не переключается. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n form?: string\n /** Пробрасывается на скрытый нативный `<input>`, чтобы работал `<label for=\"...\">`. */\n id?: string\n /** Промежуточное («смешанное») состояние: `aria-checked=\"mixed\"`, индикатор — тире. */\n indeterminate?: boolean\n /** Имя контрола, когда подписи в слоте нет (или она чисто визуальная). */\n ariaLabel?: string\n /** Сторона подписи относительно контрола. */\n labelPosition?: GrCheckboxLabelPosition\n /** Размер контрола. Не задан — берётся из группы, затем из `GrConfigProvider`, иначе `md`. */\n size?: GrCheckboxSize\n}\n\nexport interface GrCheckboxEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'change', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst hiddenInputStyle = {\n position: 'absolute',\n opacity: '0',\n width: '0',\n height: '0',\n pointerEvents: 'none',\n} as const\n\nconst props = withDefaults(defineProps<GrCheckboxProps>(), {\n modelValue: undefined,\n tabindex: undefined,\n disabled: undefined,\n name: undefined,\n value: 'on',\n required: false,\n readonly: false,\n invalid: false,\n form: undefined,\n id: undefined,\n indeterminate: false,\n ariaLabel: undefined,\n labelPosition: 'end',\n size: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxEmits>()\ndefineSlots<{\n /** Подпись флажка. Может содержать ссылки: роль остаётся на самом контроле. */\n default?: () => any\n}>()\n\nconst slots = useSlots()\n\nconst labelId = useId()\nconst hasLabel = computed(() => Boolean(slots.default))\n\nconst group = inject(GR_CHECKBOX_GROUP_CONTEXT, null)\n\nconst checked = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n if (group)\n return group.modelValue.value.includes(props.value)\n\n return false\n})\n\nconst resolvedName = computed(() => props.name ?? group?.name.value)\n\n// Контекст `GrFormField`. Id поля вешается на `span[role=\"checkbox\"]` — именно он\n// виджет и держит фокус; на скрытом `aria-hidden`-инпуте он был бы бесполезен\n// (клик по подписи уводил бы фокус в невидимый элемент). Роль-виджет не является\n// labelable-элементом, поэтому имя от подписи поля приходит через `aria-labelledby`.\nconst {\n disabled: isDisabled,\n id: fieldControlId,\n labelId: fieldLabelId,\n describedBy,\n invalid: fieldInvalid,\n required: fieldRequired,\n readonly: fieldReadonly,\n} = useGrFormControl(() => props)\n\n// «Или», а не `??`: `isDisabled` уже сведён к булеву (свой проп + контекст\n// поля и формы), и `??` до группы просто не дошёл бы.\nconst resolvedDisabled = computed(() => isDisabled.value || Boolean(group?.disabled.value))\n\n// `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` — объявлять\n// обязательность и режим чтения группы обязаны сами чекбоксы.\nconst isRequired = computed(() => fieldRequired.value || Boolean(group?.required.value))\n\nconst isReadonly = computed(() => fieldReadonly.value || Boolean(group?.readonly.value))\n\n// Ошибка группы красит чекбоксы, но не объявляется на каждом из них: `aria-invalid`\n// уже висит на самой группе, и дублировать его на всех пунктах — значит заставить\n// диктор повторить «неверное значение» столько раз, сколько в группе чекбоксов.\nconst isInvalid = computed(() => fieldInvalid.value)\nconst showsInvalid = computed(() => isInvalid.value || Boolean(group?.invalid.value))\n\nconst labelledBy = computed(() => {\n if (props.ariaLabel)\n return undefined\n if (hasLabel.value)\n return labelId\n return fieldLabelId.value\n})\n\n// Эффективный размер: локальный проп → группа → `GrConfigProvider` → `md`.\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrCheckbox' },\n)\n\nconst rootClassName = computed(() => grCheckboxRootClass({\n size: resolvedSize.value,\n disabled: resolvedDisabled.value,\n labelPosition: props.labelPosition,\n}))\n\nconst controlClassName = computed(() => grCheckboxControlClass({\n size: resolvedSize.value,\n active: checked.value || props.indeterminate,\n disabled: resolvedDisabled.value,\n invalid: showsInvalid.value,\n}))\n\nconst indeterminateIconClassName = computed(() => grCheckboxIndeterminateIconClass(resolvedSize.value))\n\nconst checkIconClassName = computed(() => grCheckboxCheckIconClass({\n size: resolvedSize.value,\n checked: checked.value,\n}))\n\nconst labelClassName = computed(() => grCheckboxLabelClass(resolvedSize.value))\n\n// Держим `.checked` на нативном input синхронно с состоянием — `:checked`-биндинг\n// на скрытом элементе иногда отстаёт при программных обновлениях.\nconst nativeInput = ref<HTMLInputElement | null>(null)\nconst control = ref<HTMLElement | null>(null)\nwatch(\n checked,\n (value) => {\n if (nativeInput.value && nativeInput.value.checked !== value)\n nativeInput.value.checked = value\n },\n)\n\n// `indeterminate` можно выставить только через JS-свойство (не атрибут).\nfunction syncIndeterminate(): void {\n if (nativeInput.value)\n nativeInput.value.indeterminate = props.indeterminate\n}\nwatch(() => props.indeterminate, syncIndeterminate)\nonMounted(syncIndeterminate)\n\nfunction setChecked(next: boolean): void {\n if (resolvedDisabled.value || isReadonly.value) {\n // Нативный input мог уже переключиться от клика по внешнему `<label for>` —\n // возвращаем его к состоянию модели, иначе форма отправит непринятое значение.\n if (nativeInput.value)\n nativeInput.value.checked = checked.value\n return\n }\n\n if (props.modelValue !== undefined || !group) {\n emit('update:modelValue', next)\n emit('change', next)\n return\n }\n\n group.toggle(props.value, next)\n emit('change', next)\n}\n\nfunction toggle(): void {\n // Из промежуточного состояния переключаемся во «включено» (стандартное поведение).\n setChecked(props.indeterminate ? true : !checked.value)\n}\n\n// Клик по нативному input (в т.ч. по внешнему `<label for=\"...\">`) уже переключил его\n// `.checked` — берём значение как источник истины и эмитим модель.\nfunction onNativeChange(e: Event): void {\n setChecked((e.target as HTMLInputElement).checked)\n}\n\n// `<label for>` уводит фокус на скрытый input — визуально фокус пропадает. Возвращаем\n// его на контрол, который этот фокус и показывает.\nfunction onNativeFocus(): void {\n control.value?.focus()\n}\n\nfunction focus(): void {\n control.value?.focus()\n}\n\nfunction blur(): void {\n control.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\n// Подпись держится снаружи роли-виджета именно для того, чтобы могла содержать\n// ссылки и кнопки, — поэтому клик по её интерактивному содержимому чекбокс не\n// переключает. Вложенный `<label>` считается интерактивным: он адресует\n// собственный контрол, и переключение чекбокса «заодно» было бы сюрпризом.\nfunction isInteractiveTarget(target: EventTarget | null): boolean {\n const el = target as HTMLElement | null\n if (!el)\n return false\n return !!el.closest('a,button,input,select,textarea,label,[role=\"button\"],[role=\"link\"]')\n}\n\nfunction onClick(e: MouseEvent): void {\n if (isInteractiveTarget(e.target))\n return\n toggle()\n}\n</script>\n\n<template>\n <div\n data-gr-checkbox\n :class=\"rootClassName\"\n @click=\"onClick\"\n >\n <input\n :id=\"id\"\n ref=\"nativeInput\"\n type=\"checkbox\"\n :checked=\"checked\"\n :disabled=\"resolvedDisabled\"\n :name=\"resolvedName\"\n :value=\"value\"\n :form=\"form\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n :style=\"hiddenInputStyle\"\n @change=\"onNativeChange\"\n @focus=\"onNativeFocus\"\n >\n <span\n :id=\"fieldControlId\"\n ref=\"control\"\n data-gr-checkbox-indicator\n role=\"checkbox\"\n :aria-checked=\"indeterminate ? 'mixed' : (checked ? 'true' : 'false')\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :tabindex=\"resolvedDisabled ? -1 : (tabindex ?? 0)\"\n :class=\"controlClassName\"\n @keydown.space.prevent=\"toggle\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <IconMinus\n v-if=\"indeterminate\"\n :class=\"indeterminateIconClassName\"\n />\n <IconCheck\n v-else\n :class=\"checkIconClassName\"\n />\n </span>\n <span\n v-if=\"hasLabel\"\n :id=\"labelId\"\n :class=\"labelClassName\"\n >\n <slot />\n </span>\n </div>\n</template>\n"],"mappings":";;;;;;;AAqBA,IAAa,4BAAkE,OAAO,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ECuEjH,MAAM,mBAAmB;GACvB,UAAU;GACV,SAAS;GACT,OAAO;GACP,QAAQ;GACR,eAAe;EACjB;EAEA,MAAM,QAAQ;EAiBd,MAAM,OAAO;EAMb,MAAM,QAAQ,SAAS;EAEvB,MAAM,UAAU,MAAM;EACtB,MAAM,WAAW,eAAe,QAAQ,MAAM,OAAO,CAAC;EAEtD,MAAM,QAAQ,OAAO,2BAA2B,IAAI;EAEpD,MAAM,UAAU,eAAe;GAC7B,IAAI,MAAM,eAAe,KAAA,GACvB,OAAO,MAAM;GAEf,IAAI,OACF,OAAO,MAAM,WAAW,MAAM,SAAS,MAAM,KAAK;GAEpD,OAAO;EACT,CAAC;EAED,MAAM,eAAe,eAAe,MAAM,QAAQ,OAAO,KAAK,KAAK;EAMnE,MAAM,EACJ,UAAU,YACV,IAAI,gBACJ,SAAS,cACT,aACA,SAAS,cACT,UAAU,eACV,UAAU,kBACR,uBAAuB,KAAK;EAIhC,MAAM,mBAAmB,eAAe,WAAW,SAAS,QAAQ,OAAO,SAAS,KAAK,CAAC;EAI1F,MAAM,aAAa,eAAe,cAAc,SAAS,QAAQ,OAAO,SAAS,KAAK,CAAC;EAEvF,MAAM,aAAa,eAAe,cAAc,SAAS,QAAQ,OAAO,SAAS,KAAK,CAAC;EAKvF,MAAM,YAAY,eAAe,aAAa,KAAK;EACnD,MAAM,eAAe,eAAe,UAAU,SAAS,QAAQ,OAAO,QAAQ,KAAK,CAAC;EAEpF,MAAM,aAAa,eAAe;GAChC,IAAI,MAAM,WACR,OAAO,KAAA;GACT,IAAI,SAAS,OACX,OAAO;GACT,OAAO,aAAa;EACtB,CAAC;EAGD,MAAM,eAAe,yBACb,MAAM,QAAQ,OAAO,KAAK,OAChC,EAAE,WAAW,aAAa,CAC5B;EAEA,MAAM,gBAAgB,eAAe,oBAAoB;GACvD,MAAM,aAAa;GACnB,UAAU,iBAAiB;GAC3B,eAAe,MAAM;EACvB,CAAC,CAAC;EAEF,MAAM,mBAAmB,eAAe,uBAAuB;GAC7D,MAAM,aAAa;GACnB,QAAQ,QAAQ,SAAS,MAAM;GAC/B,UAAU,iBAAiB;GAC3B,SAAS,aAAa;EACxB,CAAC,CAAC;EAEF,MAAM,6BAA6B,eAAe,iCAAiC,aAAa,KAAK,CAAC;EAEtG,MAAM,qBAAqB,eAAe,yBAAyB;GACjE,MAAM,aAAa;GACnB,SAAS,QAAQ;EACnB,CAAC,CAAC;EAEF,MAAM,iBAAiB,eAAe,qBAAqB,aAAa,KAAK,CAAC;EAI9E,MAAM,cAAc,IAA6B,IAAI;EACrD,MAAM,UAAU,IAAwB,IAAI;EAC5C,MACE,UACC,UAAU;GACT,IAAI,YAAY,SAAS,YAAY,MAAM,YAAY,OACrD,YAAY,MAAM,UAAU;EAChC,CACF;EAGA,SAAS,oBAA0B;GACjC,IAAI,YAAY,OACd,YAAY,MAAM,gBAAgB,MAAM;EAC5C;EACA,YAAY,MAAM,eAAe,iBAAiB;EAClD,UAAU,iBAAiB;EAE3B,SAAS,WAAW,MAAqB;GACvC,IAAI,iBAAiB,SAAS,WAAW,OAAO;IAG9C,IAAI,YAAY,OACd,YAAY,MAAM,UAAU,QAAQ;IACtC;GACF;GAEA,IAAI,MAAM,eAAe,KAAA,KAAa,CAAC,OAAO;IAC5C,KAAK,qBAAqB,IAAI;IAC9B,KAAK,UAAU,IAAI;IACnB;GACF;GAEA,MAAM,OAAO,MAAM,OAAO,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;EAEA,SAAS,SAAe;GAEtB,WAAW,MAAM,gBAAgB,OAAO,CAAC,QAAQ,KAAK;EACxD;EAIA,SAAS,eAAe,GAAgB;GACtC,WAAY,EAAE,OAA4B,OAAO;EACnD;EAIA,SAAS,gBAAsB;GAC7B,QAAQ,OAAO,MAAM;EACvB;EAEA,SAAS,QAAc;GACrB,QAAQ,OAAO,MAAM;EACvB;EAEA,SAAS,OAAa;GACpB,QAAQ,OAAO,KAAK;EACtB;EAEA,SAAa;GAAE;GAAO;EAAK,CAAC;EAM5B,SAAS,oBAAoB,QAAqC;GAChE,MAAM,KAAK;GACX,IAAI,CAAC,IACH,OAAO;GACT,OAAO,CAAC,CAAC,GAAG,QAAQ,wEAAoE;EAC1F;EAEA,SAAS,QAAQ,GAAqB;GACpC,IAAI,oBAAoB,EAAE,MAAM,GAC9B;GACF,OAAO;EACT;;GAIE,OAAA,UAAA,GAAA,mBAuDM,OAAA;IAtDJ,oBAAA;IACC,OAAK,eAAE,cAAA,KAAa;IACb;;IAER,mBAcC,SAAA;KAbE,IAAI,QAAA;KACD,SAAA;KAAJ,KAAI;KACJ,MAAK;KACJ,SAAS,QAAA;KACT,UAAU,iBAAA;KACV,MAAM,aAAA;KACN,OAAO,QAAA;KACP,MAAM,QAAA;KACP,UAAS;KACT,eAAY;KACX,OAAO;KACP,UAAQ;KACR,SAAO;;IAEV,mBA2BO,QAAA;KA1BJ,IAAI,MAAA,cAAA;KACD,SAAA;KAAJ,KAAI;KACJ,8BAAA;KACA,MAAK;KACJ,gBAAc,QAAA,gBAAa,UAAc,QAAA,QAAO,SAAA;KAChD,iBAAe,iBAAA,QAAgB,SAAY,KAAA;KAC3C,iBAAe,WAAA,QAAU,SAAY,KAAA;KACrC,iBAAe,WAAA,QAAU,SAAY,KAAA;KACrC,gBAAc,UAAA,QAAS,SAAY,KAAA;KACnC,oBAAkB,MAAA,WAAA;KAClB,cAAY,QAAA;KACZ,mBAAiB,WAAA;KACjB,UAAU,iBAAA,QAAgB,KAAS,QAAA,YAAQ;KAC3C,OAAK,eAAE,iBAAA,KAAgB;KACvB,WAAO,SAAA,cAAgB,QAAM,CAAA,SAAA,CAAA,GAAA,CAAA,OAAA,CAAA;KAC7B,SAAK,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,SAAU,MAAM;KAC3B,QAAI,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,QAAS,MAAM;IAGlB,GAAA,CAAA,QAAA,iBADR,UAAA,GAAA,YAGE,MAAA,aAAA,GAAA;;KADC,OAAK,eAAE,2BAAA,KAA0B;IAEpC,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,MAAA,UAAA,GAAA,YAGE,MAAA,aAAA,GAAA;;KADC,OAAK,eAAE,mBAAA,KAAkB;;IAItB,SAAA,SADR,UAAA,GAAA,mBAMO,QAAA;;KAJJ,IAAI,MAAA,OAAA;KACJ,OAAK,eAAE,eAAA,KAAc;IAEtB,GAAA,CAAA,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA,KAAA,mBAAA,IAAA,IAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrCheckbox_default } from "./chunks/GrCheckbox-
|
|
1
|
+
import { t as GrCheckbox_default } from "./chunks/GrCheckbox-B4NJc7Ur.js";
|
|
2
2
|
import { n as grCheckboxSafelist, t as grCheckboxConfig } from "../../chunks/config-DZCUPHPU.js";
|
|
3
3
|
export { GrCheckbox_default as GrCheckbox, GrCheckbox_default as default, grCheckboxConfig, grCheckboxSafelist };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as useGrComponentSize } from "../../../chunks/context-CPMRfwVr.js";
|
|
2
2
|
import { useGrFormControl } from "../../../composables/useGrFormControl.js";
|
|
3
3
|
import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
|
|
4
|
-
import { n as GR_CHECKBOX_GROUP_CONTEXT, t as GrCheckbox_default } from "../../GrCheckbox/chunks/GrCheckbox-
|
|
4
|
+
import { n as GR_CHECKBOX_GROUP_CONTEXT, t as GrCheckbox_default } from "../../GrCheckbox/chunks/GrCheckbox-B4NJc7Ur.js";
|
|
5
5
|
import { Fragment, computed, createBlock, createElementBlock, createTextVNode, defineComponent, normalizeClass, openBlock, provide, ref, renderList, renderSlot, toDisplayString, unref, withCtx } from "vue";
|
|
6
6
|
//#region src/components/GrCheckboxGroup/GrCheckboxGroup.vue?vue&type=script&setup=true&lang.ts
|
|
7
7
|
var _hoisted_1 = [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrCheckboxGroup-IpqG5qwm.js","names":[],"sources":["../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue","../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Фокус ходит между чекбоксами группы: без границы каждый переход давал бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_GROUP_CONTEXT, {\n modelValue: computed(() => props.modelValue),\n name: computed(() => props.name),\n disabled: computed(() => isDisabled.value),\n readonly: isReadonly,\n invalid: isInvalid,\n size: resolvedSize,\n required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Фокус ходит между чекбоксами группы: без границы каждый переход давал бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_GROUP_CONTEXT, {\n modelValue: computed(() => props.modelValue),\n name: computed(() => props.name),\n disabled: computed(() => isDisabled.value),\n readonly: isReadonly,\n invalid: isInvalid,\n size: resolvedSize,\n required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDA,MAAM,QAAQ;EAYd,MAAM,OAAO;EAQb,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,kBAAkB,CAAC;EAI1F,MAAM,EACJ,UAAU,YACV,IAAI,SACJ,SAAS,cACT,aACA,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;EAEhC,MAAM,aAAa,eAAgB,MAAM,YAAY,KAAA,IAAY,aAAa,KAAM;EAEpF,MAAM,cAAc,eAClB,MAAM,cAAc,eAAe,sCAAsC,YAC3E;EAEA,SAAS,OAAO,OAAe,SAAwB;GACrD,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,IAAI,SAAS;IACX,IAAI,MAAM,WAAW,SAAS,KAAK,GACjC;IACF,OAAO,CAAC,GAAG,MAAM,YAAY,KAAK,CAAC;IACnC;GACF;GAEA,OAAO,MAAM,WAAW,QAAO,SAAQ,SAAS,KAAK,CAAC;EACxD;EAEA,SAAS,OAAO,MAAsB;GACpC,KAAK,qBAAqB,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;EAEA,MAAM,SAAS,IAAwB,IAAI;EAI3C,MAAM,EAAE,WAAW,eAAe,eAAe,QAAQ;GACvD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;EACpC,CAAC;EAED,SAAS,gBAAgD;GACvD,OAAO,OAAO,OAAO,cAA2B,mDAA+C;EACjG;EAEA,SAAS,QAAc;GACrB,cAAc,CAAC,EAAE,MAAM;EACzB;EAEA,SAAS,OAAa;GACpB,cAAc,CAAC,EAAE,KAAK;EACxB;EAEA,SAAa;GAAE;GAAO;EAAK,CAAC;EAE5B,QAAQ,2BAA2B;GACjC,YAAY,eAAe,MAAM,UAAU;GAC3C,MAAM,eAAe,MAAM,IAAI;GAC/B,UAAU,eAAe,WAAW,KAAK;GACzC,UAAU;GACV,SAAS;GACT,MAAM;GACN,UAAU;GACV;EACF,CAAC;;GAIC,OAAA,UAAA,GAAA,mBAwBM,OAAA;IAvBH,IAAI,MAAA,OAAA;IACD,SAAA;IAAJ,KAAI;IACJ,0BAAA;IACA,MAAK;IACJ,OAAK,eAAE,YAAA,KAAW;IAClB,cAAY,QAAA;IACZ,mBAAiB,WAAA;IACjB,oBAAkB,MAAA,WAAA;IAClB,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;IACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,WAAO,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACT,YAAQ,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;GAEX,GAAA,CAAA,WASO,KAAA,QAAA,WAAA,CAAA,SAAA,EARL,UAAA,IAAA,GAAA,mBAOa,UAAA,MAAA,WANM,QAAA,WAAO,CAAA,IAAjB,WAAM;IADf,OAAA,UAAA,GAAA,YAOa,oBAAA;KALV,KAAK,OAAO;KACZ,OAAO,OAAO;KACd,UAAU,OAAO;;KAElB,SAAA,cAAkB,CAAf,gBAAA,gBAAA,OAAO,KAAK,GAAA,CAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"GrCheckboxGroup-qZHpNFCX.js","names":[],"sources":["../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue","../../../../src/components/GrCheckboxGroup/GrCheckboxGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Фокус ходит между чекбоксами группы: без границы каждый переход давал бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_GROUP_CONTEXT, {\n modelValue: computed(() => props.modelValue),\n name: computed(() => props.name),\n disabled: computed(() => isDisabled.value),\n readonly: isReadonly,\n invalid: isInvalid,\n size: resolvedSize,\n required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrCheckboxGroup — контейнер группы `GrCheckbox` с общей моделью `string[]`.\n *\n * Работает и через слот (ручной рендер `GrCheckbox` с собственными подписями),\n * и через проп `options`. Дочерние чекбоксы получают из контекста выбранные\n * значения, `name`, `size` и состояния `disabled`/`readonly`/`invalid`, поэтому\n * свой `v-model` им не нужен.\n *\n * A11y: `role=\"group\"` — не `radiogroup`. У группы чекбоксов нет roving tabindex\n * и переезда выбора стрелками: каждый чекбокс независим и остаётся собственной\n * остановкой `Tab`, ровно как набор нативных `<input type=\"checkbox\">`.\n * `role=\"group\"` не поддерживает `aria-required` и `aria-readonly` (axe:\n * `aria-allowed-attr`), поэтому оба состояния объявляют чекбоксы группы.\n */\nimport { computed, provide, ref } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\n\nimport GrCheckbox from '../GrCheckbox/GrCheckbox.vue'\nimport { GR_CHECKBOX_GROUP_CONTEXT } from '../GrCheckbox/grCheckboxGroupContext'\nimport type { GrCheckboxSize } from '../GrCheckbox/grCheckboxStyles'\n\nexport type GrCheckboxGroupDirection = 'vertical' | 'horizontal'\n\nexport interface GrCheckboxGroupOption {\n value: string\n label: string\n disabled?: boolean\n}\n\nexport interface GrCheckboxGroupProps {\n modelValue: string[]\n options?: GrCheckboxGroupOption[]\n /** Общее имя для нативной формы: значения уйдут как повторяющиеся поля. */\n name?: string\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки для всей группы. */\n invalid?: boolean\n /** Обязательная группа: `aria-required` объявляют сами чекбоксы. */\n required?: boolean\n direction?: GrCheckboxGroupDirection\n size?: GrCheckboxSize\n ariaLabel?: string\n}\n\nexport interface GrCheckboxGroupEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCheckboxGroupProps>(), {\n options: undefined,\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n direction: 'vertical',\n size: undefined,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrCheckboxGroupEmits>()\ndefineSlots<{\n /** Собственная разметка флажков вместо генерации из `options`. */\n default?: () => any\n}>()\n\n// Эффективный размер группы: локальный проп → `GrConfigProvider` → `md`.\n// Дочерние чекбоксы получают уже разрешённое значение через контекст.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCheckboxGroup' })\n\n// Контекст `GrFormField`. Группа — не labelable-элемент, поэтому имя приходит\n// через `aria-labelledby` на подпись поля, а не через `<label for>`.\nconst {\n disabled: isDisabled,\n id: fieldId,\n labelId: fieldLabelId,\n describedBy,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : fieldLabelId.value))\n\nconst layoutClass = computed(() =>\n props.direction === 'horizontal' ? 'flex flex-wrap items-center gap-4' : 'grid gap-2',\n)\n\nfunction toggle(value: string, checked: boolean): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n if (checked) {\n if (props.modelValue.includes(value))\n return\n commit([...props.modelValue, value])\n return\n }\n\n commit(props.modelValue.filter(item => item !== value))\n}\n\nfunction commit(next: string[]): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Фокус ходит между чекбоксами группы: без границы каждый переход давал бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\nfunction firstCheckbox(): HTMLElement | null | undefined {\n return rootEl.value?.querySelector<HTMLElement>('[role=\"checkbox\"]:not([aria-disabled=\"true\"])')\n}\n\nfunction focus(): void {\n firstCheckbox()?.focus()\n}\n\nfunction blur(): void {\n firstCheckbox()?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nprovide(GR_CHECKBOX_GROUP_CONTEXT, {\n modelValue: computed(() => props.modelValue),\n name: computed(() => props.name),\n disabled: computed(() => isDisabled.value),\n readonly: isReadonly,\n invalid: isInvalid,\n size: resolvedSize,\n required: isRequired,\n toggle,\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootEl\"\n data-gr-checkbox-group\n role=\"group\"\n :class=\"layoutClass\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <slot>\n <GrCheckbox\n v-for=\"option in options ?? []\"\n :key=\"option.value\"\n :value=\"option.value\"\n :disabled=\"option.disabled\"\n >\n {{ option.label }}\n </GrCheckbox>\n </slot>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyDA,MAAM,QAAQ;EAYd,MAAM,OAAO;EAQb,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,kBAAkB,CAAC;EAI1F,MAAM,EACJ,UAAU,YACV,IAAI,SACJ,SAAS,cACT,aACA,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;EAEhC,MAAM,aAAa,eAAgB,MAAM,YAAY,KAAA,IAAY,aAAa,KAAM;EAEpF,MAAM,cAAc,eAClB,MAAM,cAAc,eAAe,sCAAsC,YAC3E;EAEA,SAAS,OAAO,OAAe,SAAwB;GACrD,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,IAAI,SAAS;IACX,IAAI,MAAM,WAAW,SAAS,KAAK,GACjC;IACF,OAAO,CAAC,GAAG,MAAM,YAAY,KAAK,CAAC;IACnC;GACF;GAEA,OAAO,MAAM,WAAW,QAAO,SAAQ,SAAS,KAAK,CAAC;EACxD;EAEA,SAAS,OAAO,MAAsB;GACpC,KAAK,qBAAqB,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;EAEA,MAAM,SAAS,IAAwB,IAAI;EAI3C,MAAM,EAAE,WAAW,eAAe,eAAe,QAAQ;GACvD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;EACpC,CAAC;EAED,SAAS,gBAAgD;GACvD,OAAO,OAAO,OAAO,cAA2B,mDAA+C;EACjG;EAEA,SAAS,QAAc;GACrB,cAAc,CAAC,EAAE,MAAM;EACzB;EAEA,SAAS,OAAa;GACpB,cAAc,CAAC,EAAE,KAAK;EACxB;EAEA,SAAa;GAAE;GAAO;EAAK,CAAC;EAE5B,QAAQ,2BAA2B;GACjC,YAAY,eAAe,MAAM,UAAU;GAC3C,MAAM,eAAe,MAAM,IAAI;GAC/B,UAAU,eAAe,WAAW,KAAK;GACzC,UAAU;GACV,SAAS;GACT,MAAM;GACN,UAAU;GACV;EACF,CAAC;;GAIC,OAAA,UAAA,GAAA,mBAwBM,OAAA;IAvBH,IAAI,MAAA,OAAA;IACD,SAAA;IAAJ,KAAI;IACJ,0BAAA;IACA,MAAK;IACJ,OAAK,eAAE,YAAA,KAAW;IAClB,cAAY,QAAA;IACZ,mBAAiB,WAAA;IACjB,oBAAkB,MAAA,WAAA;IAClB,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;IACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,WAAO,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACT,YAAQ,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;GAEX,GAAA,CAAA,WASO,KAAA,QAAA,WAAA,CAAA,SAAA,EARL,UAAA,IAAA,GAAA,mBAOa,UAAA,MAAA,WANM,QAAA,WAAO,CAAA,IAAjB,WAAM;IADf,OAAA,UAAA,GAAA,YAOa,oBAAA;KALV,KAAK,OAAO;KACZ,OAAO,OAAO;KACd,UAAU,OAAO;;KAElB,SAAA,cAAkB,CAAf,gBAAA,gBAAA,OAAO,KAAK,GAAA,CAAA,CAAA,CAAA"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as GrCheckboxGroup_default } from "./chunks/GrCheckboxGroup-
|
|
1
|
+
import { t as GrCheckboxGroup_default } from "./chunks/GrCheckboxGroup-qZHpNFCX.js";
|
|
2
2
|
import { t as grCheckboxGroupConfig } from "../../chunks/config-BuGlNPE9.js";
|
|
3
3
|
export { GrCheckboxGroup_default as GrCheckboxGroup, GrCheckboxGroup_default as default, grCheckboxGroupConfig };
|
|
@@ -3,7 +3,7 @@ import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunk
|
|
|
3
3
|
import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
|
|
4
4
|
import { t as warnRenamedProp } from "../../../chunks/renamedProp-Dy96tT-F.js";
|
|
5
5
|
import { t as GR_CHIP_GROUP_CONTEXT } from "../../../chunks/grChipGroupContext-DZXkACap.js";
|
|
6
|
-
import { a as chipIconSizeClassBySize, f as grChipClass, i as chipIconClass, n as chipCloseClass, s as chipLabelClass, t as chipCloseButtonClass } from "../../../chunks/grChipStyles-
|
|
6
|
+
import { a as chipIconSizeClassBySize, f as grChipClass, i as chipIconClass, n as chipCloseClass, s as chipLabelClass, t as chipCloseButtonClass } from "../../../chunks/grChipStyles-CA9Wj1_E.js";
|
|
7
7
|
import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, normalizeClass, onBeforeUnmount, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, unref, useAttrs, withCtx, withModifiers } from "vue";
|
|
8
8
|
//#region src/components/GrChip/GrChip.vue?vue&type=script&setup=true&lang.ts
|
|
9
9
|
var _hoisted_1 = ["title"];
|