@feugene/granularity 0.30.0 → 0.31.1
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 +0 -1
- package/dist/chunks/adapter-CAOxmn2G.js.map +1 -1
- package/dist/chunks/{config-BHcS5Cwm.js → config-87fszqnD.js} +1 -1
- package/dist/chunks/{config-BHcS5Cwm.js.map → config-87fszqnD.js.map} +1 -1
- package/dist/chunks/config-A-bBiotF.js.map +1 -1
- package/dist/chunks/config-B3J0alyY.js.map +1 -1
- package/dist/chunks/config-BhfNgyWL.js.map +1 -1
- package/dist/chunks/config-Bjn30smH.js.map +1 -1
- package/dist/chunks/config-BqT6PMzO.js.map +1 -1
- package/dist/chunks/config-C0Ea9ePP.js.map +1 -1
- package/dist/chunks/config-C0Eu8jpG.js.map +1 -1
- package/dist/chunks/config-CDat1wXf.js.map +1 -1
- package/dist/chunks/{config-DO8mjeIo.js → config-CIkdsWUk.js} +6 -2
- package/dist/chunks/config-CIkdsWUk.js.map +1 -0
- package/dist/chunks/config-CQLNjc9X2.js.map +1 -1
- package/dist/chunks/config-CbEbLyDE.js.map +1 -1
- package/dist/chunks/{config-jyr6AIZt2.js → config-CuQmUkMw2.js} +2 -2
- package/dist/chunks/{config-jyr6AIZt2.js.map → config-CuQmUkMw2.js.map} +1 -1
- package/dist/chunks/config-DeyT9dJl.js.map +1 -1
- package/dist/chunks/config-DnF472Ox.js.map +1 -1
- package/dist/chunks/config-DwABJHEo.js.map +1 -1
- package/dist/chunks/{config-tiUtEn4Q.js → config-E1cTyRVV.js} +1 -1
- package/dist/chunks/{config-tiUtEn4Q.js.map → config-E1cTyRVV.js.map} +1 -1
- package/dist/chunks/config-MmPym-Z72.js.map +1 -1
- package/dist/chunks/config-T3-DMXYm.js.map +1 -1
- package/dist/chunks/config-Yy67uWHY.js.map +1 -1
- package/dist/chunks/config-_jbgsFpw.js.map +1 -1
- package/dist/chunks/config-g8-JGZ_Y.js.map +1 -1
- package/dist/chunks/config-mlheIMtV.js.map +1 -1
- package/dist/chunks/config-rLkc9Zn2.js.map +1 -1
- package/dist/chunks/config-uzUuosv7.js.map +1 -1
- package/dist/chunks/context-CTbuwcYs.js.map +1 -1
- package/dist/chunks/deltaTone-B5OoS1vo.js.map +1 -1
- package/dist/chunks/es-Do2CNrC2.js.map +1 -1
- package/dist/chunks/fileValidation-D5TFBhbv.js.map +1 -1
- package/dist/chunks/focusables-BkzK42SQ.js.map +1 -1
- package/dist/chunks/{generated-DJ2dJ__C.js → generated-CSyPsWtM.js} +1 -1
- package/dist/chunks/{generated-DJ2dJ__C.js.map → generated-CSyPsWtM.js.map} +1 -1
- package/dist/chunks/grBadgeStyles-D8Mz73B5.js.map +1 -1
- package/dist/chunks/{grButtonStyles-B_-YRE__.js → grButtonStyles-B3wRWW_i.js} +4 -4
- package/dist/chunks/grButtonStyles-B3wRWW_i.js.map +1 -0
- package/dist/chunks/{grInputStyles-CAk3xKIb.js → grInputStyles-DgQYjJvD.js} +17 -1
- package/dist/chunks/{grInputStyles-CAk3xKIb.js.map → grInputStyles-DgQYjJvD.js.map} +1 -1
- package/dist/chunks/grLinkStyles-FME_qMpi.js.map +1 -1
- package/dist/chunks/grLoadingStyles-CnQaf5ry.js.map +1 -1
- package/dist/chunks/{grRadioStyles-D4gnU65n.js → grRadioStyles-DGL2QLy6.js} +1 -1
- package/dist/chunks/{grRadioStyles-D4gnU65n.js.map → grRadioStyles-DGL2QLy6.js.map} +1 -1
- package/dist/chunks/grSelectStyles-Cdtd10eY.js.map +1 -1
- package/dist/chunks/{grSliderStyles-B5uNxNJq.js → grSliderStyles-kaz6VXZ3.js} +9 -1
- package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +1 -0
- package/dist/chunks/{granular-provider-CHFaw3wU.js → granular-provider-Da2CJO6j.js} +4 -4
- package/dist/chunks/{granular-provider-CHFaw3wU.js.map → granular-provider-Da2CJO6j.js.map} +1 -1
- package/dist/chunks/granularityI18n-BC5zsj_d.js.map +1 -1
- package/dist/chunks/icon-Dag2tIMs.js.map +1 -1
- package/dist/chunks/inert-DIHCCn_1.js.map +1 -1
- package/dist/chunks/keyboard-DE2yhz_b.js.map +1 -1
- package/dist/chunks/numericStep-Bq2lj4ew.js.map +1 -1
- package/dist/chunks/optionFilter-DYw9XPPx.js.map +1 -1
- package/dist/chunks/overlayStack-C8cfsqXa.js.map +1 -1
- package/dist/chunks/portalRoot-CVhCgdG6.js.map +1 -1
- package/dist/chunks/renamedProp-BwcN-SJg.js.map +1 -1
- package/dist/chunks/{safelist-BOq5Li7p.js → safelist-DxkMj5IW.js} +1 -1
- package/dist/chunks/{safelist-BOq5Li7p.js.map → safelist-DxkMj5IW.js.map} +1 -1
- package/dist/chunks/slotNodes-DxNXpC7v.js.map +1 -1
- package/dist/chunks/useControlAddons-asUr10Pf.js.map +1 -1
- package/dist/chunks/useControlledOpen-DV3SqLTP.js.map +1 -1
- package/dist/chunks/useDragSort-0l47h4yb.js.map +1 -1
- package/dist/chunks/useFilePreviews-DnwgdyBs.js.map +1 -1
- package/dist/chunks/useFocusWithin-BwHE0rzm.js.map +1 -1
- package/dist/chunks/useModalOverlay-Cv5hF63W.js.map +1 -1
- package/dist/chunks/usePortalTarget-C0p-mhaM.js.map +1 -1
- package/dist/chunks/validation-5HhpanPP.js.map +1 -1
- package/dist/components/GrAlert/chunks/GrAlert-FAVf-ksH.js.map +1 -1
- package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-X6RlmiJQ.js → GrAutocomplete-rYEY15UI.js} +1 -1
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-rYEY15UI.js.map +1 -0
- package/dist/components/GrAutocomplete/index.js +1 -1
- package/dist/components/GrAutocomplete/styles.css +1 -1
- package/dist/components/GrAvatar/chunks/GrAvatar-CNmLmgcr.js.map +1 -1
- package/dist/components/GrBadge/chunks/{GrBadge-BsoocpF-.js → GrBadge-D2MfThPz.js} +1 -1
- package/dist/components/GrBadge/chunks/GrBadge-D2MfThPz.js.map +1 -0
- package/dist/components/GrBadge/index.js +1 -1
- package/dist/components/GrBadge/styles.css +1 -1
- package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-B-A3PRkE.js.map +1 -1
- package/dist/components/GrBottomNav/chunks/GrBottomNav-wtFatLjB.js.map +1 -1
- package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-DRDNan_n.js.map +1 -1
- package/dist/components/GrButton/chunks/{GrButton-Bw2AH4uX.js → GrButton-7GP0zObj.js} +1 -1
- package/dist/components/GrButton/chunks/GrButton-7GP0zObj.js.map +1 -0
- package/dist/components/GrButton/index.js +3 -3
- package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -1
- package/dist/components/GrCard/chunks/GrCard-BttXz1pQ.js.map +1 -1
- package/dist/components/GrCheckbox/chunks/GrCheckbox-CEcHIsXM.js.map +1 -1
- package/dist/components/GrCheckboxGroup/chunks/GrCheckboxGroup-BOwrVcFr.js.map +1 -1
- package/dist/components/GrChip/chunks/GrChip-C0vU69tf.js.map +1 -1
- package/dist/components/GrChipGroup/chunks/GrChipGroup-C78Vcwos.js.map +1 -1
- package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dkvkr91t.js → GrCodeBlock-Dp0eEBTZ.js} +1 -1
- package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dp0eEBTZ.js.map +1 -0
- package/dist/components/GrCodeBlock/index.js +1 -1
- package/dist/components/GrCollapse/chunks/GrCollapse-BlW6ybdL.js.map +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-CE-xtNP-.js → GrColorPicker-B20gQ6AR.js} +2 -2
- package/dist/components/GrColorPicker/chunks/GrColorPicker-B20gQ6AR.js.map +1 -0
- package/dist/components/GrColorPicker/index.js +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-C5abL2Y7.js → GrCommandPalette-Cd0Yo3Dw.js} +1 -1
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-Cd0Yo3Dw.js.map +1 -0
- package/dist/components/GrCommandPalette/index.js +1 -1
- package/dist/components/GrCommandPalette/styles.css +1 -1
- package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js.map +1 -1
- package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-B9mIU78E.js → GrConfirmDialog-DOsbRhoZ.js} +3 -3
- package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DOsbRhoZ.js.map +1 -0
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrContextMenu/chunks/GrContextMenu-_FKwQvuQ.js.map +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-C8a9_nCg.js → GrDataTable-CAGgRk27.js} +5 -3
- package/dist/components/GrDataTable/chunks/GrDataTable-CAGgRk27.js.map +1 -0
- package/dist/components/GrDataTable/index.js +1 -1
- package/dist/components/GrDelta/chunks/GrDelta-BZwkgQW-.js.map +1 -1
- package/dist/components/GrDescriptionList/chunks/GrDescriptionList-BMeCgFV3.js.map +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js → GrDialog-S1Vl-OhX.js} +1 -1
- package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js.map → GrDialog-S1Vl-OhX.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-k4SYIv64.js → GrDialogService-Cuhc4YLp.js} +4 -4
- package/dist/components/GrDialogService/chunks/GrDialogService-Cuhc4YLp.js.map +1 -0
- package/dist/components/GrDialogService/index.js +1 -1
- package/dist/components/GrDivider/chunks/GrDivider-BXavGcMX.js.map +1 -1
- package/dist/components/GrDrawer/chunks/{GrDrawer-B7PiAcbU.js → GrDrawer-C0YqVE9e.js} +1 -1
- package/dist/components/GrDrawer/chunks/GrDrawer-C0YqVE9e.js.map +1 -0
- package/dist/components/GrDrawer/index.js +1 -1
- package/dist/components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js.map +1 -1
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-GOzuAXsi.js.map +1 -1
- package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js.map +1 -1
- package/dist/components/GrFilePreview/chunks/GrFilePreview-C9Z7hMK8.js.map +1 -1
- package/dist/components/GrFileUpload/chunks/GrFileUpload-NsHkRRIa.js.map +1 -1
- package/dist/components/GrForm/chunks/GrForm-CrnfCsgj.js.map +1 -1
- package/dist/components/GrFormField/chunks/GrFormField-DSylU7IU.js.map +1 -1
- package/dist/components/GrFormFile/chunks/{GrFormFile-CYtXU9HV.js → GrFormFile-B1jGZyIj.js} +2 -2
- package/dist/components/GrFormFile/chunks/GrFormFile-B1jGZyIj.js.map +1 -0
- package/dist/components/GrFormFile/index.js +1 -1
- package/dist/components/GrFormFile/styles.css +1 -1
- package/dist/components/GrIcon/chunks/GrIcon-Dmf0c9ba.js.map +1 -1
- package/dist/components/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js.map +1 -1
- package/dist/components/GrInput/chunks/{GrInput-BqqoEl1b.js → GrInput-BLywRZUN.js} +10 -6
- package/dist/components/GrInput/chunks/GrInput-BLywRZUN.js.map +1 -0
- package/dist/components/GrInput/index.js +2 -2
- package/dist/components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js.map +1 -1
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CgwjoUJt.js → GrJsonViewer-BCZ7lE2k.js} +3 -3
- package/dist/components/GrJsonViewer/chunks/GrJsonViewer-BCZ7lE2k.js.map +1 -0
- package/dist/components/GrJsonViewer/index.js +1 -1
- package/dist/components/GrKbd/chunks/GrKbd-D2ga1H9i.js.map +1 -1
- package/dist/components/GrLink/chunks/GrLink-DYXw3W9w.js.map +1 -1
- package/dist/components/GrList/chunks/{GrList-DmT4qzLO.js → GrList-B_CRJB4c.js} +1 -1
- package/dist/components/GrList/chunks/GrList-B_CRJB4c.js.map +1 -0
- package/dist/components/GrList/index.js +1 -1
- package/dist/components/GrList/styles.css +1 -1
- package/dist/components/GrModal/chunks/GrModal-CCoWZuIl.js.map +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js → GrNavbar-_rtHKwTf.js} +1 -1
- package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js.map → GrNavbar-_rtHKwTf.js.map} +1 -1
- package/dist/components/GrNavbar/index.js +1 -1
- package/dist/components/GrNumberInput/chunks/GrNumberInput-DQ59YICu.js.map +1 -1
- package/dist/components/GrPagination/chunks/{GrPagination-kYCx6PAS.js → GrPagination-B_kAhoAV.js} +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-kYCx6PAS.js.map → GrPagination-B_kAhoAV.js.map} +1 -1
- package/dist/components/GrPagination/index.js +1 -1
- package/dist/components/GrPopover/chunks/GrPopover-CofG-Tfe.js.map +1 -1
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-D1ADRFxx.js → GrPromptDialog-BuJQMZLM.js} +5 -5
- package/dist/components/GrPromptDialog/chunks/GrPromptDialog-BuJQMZLM.js.map +1 -0
- package/dist/components/GrPromptDialog/index.js +1 -1
- package/dist/components/GrRadio/chunks/{GrRadio-C_rESc5g.js → GrRadio-Aq3v8XgG.js} +1 -1
- package/dist/components/GrRadio/chunks/GrRadio-Aq3v8XgG.js.map +1 -0
- package/dist/components/GrRadio/index.js +2 -2
- package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CdQO4G-U.js → GrRadioGroup-y9LVdTWh.js} +1 -1
- package/dist/components/GrRadioGroup/chunks/GrRadioGroup-y9LVdTWh.js.map +1 -0
- package/dist/components/GrRadioGroup/index.js +1 -1
- package/dist/components/GrRating/chunks/GrRating-IEiTOdnF.js.map +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js → GrResponseErrorBanner-CBVRpgIG.js} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js.map → GrResponseErrorBanner-CBVRpgIG.js.map} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DudGc9LO.js → GrResponseErrorBanner-DMeOWlzj.js} +1 -1
- package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js.map +1 -0
- package/dist/components/GrResponseErrorBanner/index.js +2 -2
- package/dist/components/GrSegmented/chunks/GrSegmented-CB-VR-yL.js.map +1 -1
- package/dist/components/GrSelect/chunks/{GrSelect-CBp0twbF.js → GrSelect-gCeRFgQo.js} +2 -2
- package/dist/components/GrSelect/chunks/GrSelect-gCeRFgQo.js.map +1 -0
- package/dist/components/GrSelect/index.js +1 -1
- package/dist/components/GrSelect/styles.css +1 -1
- package/dist/components/GrSidebar/chunks/{GrSidebar-B8EQIlfW.js → GrSidebar-alkwBUzL.js} +1 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-alkwBUzL.js.map +1 -0
- package/dist/components/GrSidebar/index.js +1 -1
- package/dist/components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js.map +1 -1
- package/dist/components/GrSlider/chunks/{GrSlider-DJfeEl4h.js → GrSlider-DTTrZTHK.js} +3 -3
- package/dist/components/GrSlider/chunks/GrSlider-DTTrZTHK.js.map +1 -0
- package/dist/components/GrSlider/index.js +2 -2
- package/dist/components/GrSortableList/chunks/GrSortableList-HyKX--rO.js.map +1 -1
- package/dist/components/GrSplitter/chunks/GrSplitter-MltjaADn.js.map +1 -1
- package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +1 -1
- package/dist/components/GrSteps/chunks/GrSteps-C2jxpZoN.js.map +1 -1
- package/dist/components/GrSwitch/chunks/{GrSwitch-g_OOSkh7.js → GrSwitch-7Oe5QfQZ.js} +1 -1
- package/dist/components/GrSwitch/chunks/GrSwitch-7Oe5QfQZ.js.map +1 -0
- package/dist/components/GrSwitch/index.js +1 -1
- package/dist/components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js.map +1 -1
- package/dist/components/GrTable/chunks/GrTable-Zcdz2St_.js.map +1 -1
- package/dist/components/GrTextarea/chunks/{GrTextarea-KREK75Bu.js → GrTextarea-DinXG12-.js} +10 -10
- package/dist/components/GrTextarea/chunks/GrTextarea-DinXG12-.js.map +1 -0
- package/dist/components/GrTextarea/index.js +1 -1
- package/dist/components/GrTimeline/chunks/GrTimeline-BiHpArsg.js.map +1 -1
- package/dist/components/GrToaster/chunks/{GrToaster-Dp7-4B8k.js → GrToaster-COXIBKzq.js} +2 -2
- package/dist/components/GrToaster/chunks/GrToaster-COXIBKzq.js.map +1 -0
- package/dist/components/GrToaster/index.js +1 -1
- package/dist/components/GrToaster/styles.css +1 -1
- package/dist/components/GrTooltip/chunks/GrTooltip-uYETdbCD.js.map +1 -1
- package/dist/components/GrTree/chunks/{GrTree-DC89I4AP.js → GrTree-Ci6CZfKR.js} +5 -5
- package/dist/components/GrTree/chunks/GrTree-Ci6CZfKR.js.map +1 -0
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTree/styles.css +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-CymO68Cv.js → GrTreeSelect-BHwgGJcT.js} +2 -2
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHwgGJcT.js.map +1 -0
- package/dist/components/GrTreeSelect/index.js +1 -1
- package/dist/composables/useAnnouncer.js.map +1 -1
- package/dist/composables/useComboboxNavigation.js.map +1 -1
- package/dist/composables/useDragGesture.js.map +1 -1
- package/dist/composables/useFocusTrap.js.map +1 -1
- package/dist/composables/useOverlayLayer.js.map +1 -1
- package/dist/composables/useRovingFocus.js.map +1 -1
- package/dist/composables/useTheme.js.map +1 -1
- package/dist/composables/useToast.js.map +1 -1
- package/dist/composables/useVirtualList.js.map +1 -1
- package/dist/directives/autofocus.js.map +1 -1
- package/dist/directives/autosize.js.map +1 -1
- package/dist/directives/clickOutside.js.map +1 -1
- package/dist/directives/dropzone.js.map +1 -1
- package/dist/directives/hotkey.js.map +1 -1
- package/dist/directives/loading.js.map +1 -1
- package/dist/granular-provider-node.js +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/index.js +35 -35
- package/dist/testing.js +2 -2
- package/dist/testing.js.map +1 -1
- package/dist/theme-apply.js.map +1 -1
- package/dist/theme.js +1 -1
- package/dist/theme.js.map +1 -1
- package/dist/tokens.js +1 -1
- package/dist/types/components/GrCodeBlock/tokenizeJson.d.ts +1 -3
- package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +1 -1
- package/dist/types/components/GrInput/GrInput.vue.d.ts +29 -13
- package/dist/types/components/GrInput/grInputStyles.d.ts +16 -0
- package/dist/types/components/GrSlider/grSliderStyles.d.ts +9 -1
- package/dist/types/components/GrTabPanels/GrTabPanel.vue.d.ts +3 -3
- package/dist/vue/index.js.map +1 -1
- package/dist/web-types.json +10 -1
- package/package.json +3 -3
- package/dist/chunks/config-DO8mjeIo.js.map +0 -1
- package/dist/chunks/grButtonStyles-B_-YRE__.js.map +0 -1
- package/dist/chunks/grSliderStyles-B5uNxNJq.js.map +0 -1
- package/dist/components/GrAutocomplete/chunks/GrAutocomplete-X6RlmiJQ.js.map +0 -1
- package/dist/components/GrBadge/chunks/GrBadge-BsoocpF-.js.map +0 -1
- package/dist/components/GrButton/chunks/GrButton-Bw2AH4uX.js.map +0 -1
- package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dkvkr91t.js.map +0 -1
- package/dist/components/GrColorPicker/chunks/GrColorPicker-CE-xtNP-.js.map +0 -1
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-C5abL2Y7.js.map +0 -1
- package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-B9mIU78E.js.map +0 -1
- package/dist/components/GrDataTable/chunks/GrDataTable-C8a9_nCg.js.map +0 -1
- package/dist/components/GrDialogService/chunks/GrDialogService-k4SYIv64.js.map +0 -1
- package/dist/components/GrDrawer/chunks/GrDrawer-B7PiAcbU.js.map +0 -1
- package/dist/components/GrFormFile/chunks/GrFormFile-CYtXU9HV.js.map +0 -1
- package/dist/components/GrInput/chunks/GrInput-BqqoEl1b.js.map +0 -1
- package/dist/components/GrJsonViewer/chunks/GrJsonViewer-CgwjoUJt.js.map +0 -1
- package/dist/components/GrList/chunks/GrList-DmT4qzLO.js.map +0 -1
- package/dist/components/GrPromptDialog/chunks/GrPromptDialog-D1ADRFxx.js.map +0 -1
- package/dist/components/GrRadio/chunks/GrRadio-C_rESc5g.js.map +0 -1
- package/dist/components/GrRadioGroup/chunks/GrRadioGroup-CdQO4G-U.js.map +0 -1
- package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DudGc9LO.js.map +0 -1
- package/dist/components/GrSelect/chunks/GrSelect-CBp0twbF.js.map +0 -1
- package/dist/components/GrSidebar/chunks/GrSidebar-B8EQIlfW.js.map +0 -1
- package/dist/components/GrSlider/chunks/GrSlider-DJfeEl4h.js.map +0 -1
- package/dist/components/GrSwitch/chunks/GrSwitch-g_OOSkh7.js.map +0 -1
- package/dist/components/GrTextarea/chunks/GrTextarea-KREK75Bu.js.map +0 -1
- package/dist/components/GrToaster/chunks/GrToaster-Dp7-4B8k.js.map +0 -1
- package/dist/components/GrTree/chunks/GrTree-DC89I4AP.js.map +0 -1
- package/dist/components/GrTreeSelect/chunks/GrTreeSelect-CymO68Cv.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GrDrawer-C0YqVE9e.js","names":["$slots"],"sources":["../../../../src/components/GrDrawer/GrDrawer.vue","../../../../src/components/GrDrawer/GrDrawer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, useId, watch } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n// Модальный слой целиком: стек (Esc верхнему, `inert` нижним модалкам), ловушка\n// фокуса, скролл-лок, портал. Немодальная панель регистрируется в стеке как\n// обычный dismissible-слой и страницу под собой не трогает.\nimport { useModalOverlay } from '../../composables/internal/useModalOverlay'\nimport {\n DEFAULT_GR_DRAWER_BODY_CONFIG,\n DEFAULT_GR_DRAWER_FOOTER_CONFIG,\n DEFAULT_GR_DRAWER_HEADER_CONFIG,\n footerBorderClass,\n grDrawerAxis,\n grDrawerPanelClass,\n grDrawerPanelEnterFrom,\n headerBorderClass,\n overlayClass,\n resolveGrDrawerSectionConfig,\n rootClass,\n rootPassThroughClass,\n srOnlyTitleClass,\n titleClass,\n type GrDrawerSectionConfig,\n type GrDrawerSide,\n type GrDrawerSize,\n} from './grDrawerStyles'\n\nimport IconClose from '~icons/lucide/x'\n\nimport './defaults'\n\nexport interface GrDrawerProps {\n /** Контроль открытия через v-model. */\n modelValue: boolean\n /** Заголовок; если передан — покажется в хедере. Можно переопределить слотом `#title`. */\n title?: string\n /**\n * Модальная панель: подложка, блокировка скролла, `inert` остальной странице\n * и ловушка фокуса. `false` — панель живёт рядом со страницей: с ней работают,\n * не закрывая, а Tab уходит наружу.\n */\n modal?: boolean\n /** Закрывать при клике по бэкдропу. В немодальном режиме подложки нет. */\n closeOnBackdrop?: boolean\n /** Закрывать по Esc. */\n closeOnEsc?: boolean\n /**\n * Запрет закрытия «мягкими» способами (бэкдроп, Esc) — на время операции,\n * которую нельзя бросить на полпути. Кнопка закрытия при этом остаётся:\n * панель без единого выхода — ловушка.\n */\n persistent?: boolean\n /** Сторона, с которой выезжает панель. */\n side?: GrDrawerSide\n /** Размер панели по её оси: ширина у боковых, высота у верхней и нижней. */\n size?: GrDrawerSize\n /** Произвольная ширина боковой панели. Число трактуется как пиксели; сильнее `size`. */\n width?: string | number\n /** Произвольная высота верхней или нижней панели. Число трактуется как пиксели. */\n height?: string | number\n /** Рендерить ли хедер (заголовок + кнопка закрытия). */\n showHeader?: boolean\n /** Рендерить ли кнопку закрытия в хедере. */\n showCloseButton?: boolean\n /** Паддинги и рамка секций — как у `GrDialog`. */\n headerConfig?: GrDrawerSectionConfig\n bodyConfig?: GrDrawerSectionConfig\n footerConfig?: GrDrawerSectionConfig\n /** Элемент, получающий фокус при открытии. По умолчанию — сама панель. */\n initialFocus?: HTMLElement | null\n /** i18n-friendly aria-label для кнопки закрытия. */\n closeLabel?: string\n}\n\nexport interface GrDrawerEmits {\n (e: 'update:modelValue', value: boolean): void\n /** Панель выехала и анимация закончилась. */\n (e: 'opened'): void\n /** Панель уехала и анимация закончилась. */\n (e: 'closed'): void\n}\n\n// Дефолты оформления намеренно `undefined`: «настоящий» дефолт живёт в\n// `useGrComponentProp`, иначе `GrConfigProvider` не отличит заданный\n// пользователем проп от подставленного Vue.\nconst props = withDefaults(defineProps<GrDrawerProps>(), {\n title: undefined,\n modal: true,\n closeOnBackdrop: true,\n closeOnEsc: true,\n persistent: false,\n side: undefined,\n size: undefined,\n width: undefined,\n height: undefined,\n showHeader: true,\n showCloseButton: true,\n headerConfig: undefined,\n bodyConfig: undefined,\n footerConfig: undefined,\n initialFocus: null,\n closeLabel: undefined,\n})\n\nconst { t } = useGranularityTranslations()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? t('gr.common.close', 'Close'))\n\nconst emit = defineEmits<GrDrawerEmits>()\n\nconst slots = defineSlots<{\n default?: () => any\n title?: () => any\n /** Своя шапка целиком: заголовок, кнопка закрытия и всё, что нужно рядом. */\n header?: (props: { title?: string, close: () => void }) => any\n footer?: () => any\n}>()\n\nconst titleId = useId()\n\nconst size = useGrComponentProp('GrDrawer', 'size', () => props.size, 'md')\nconst side = useGrComponentProp('GrDrawer', 'side', () => props.side, 'right')\n\nconst axis = computed(() => grDrawerAxis(side.value))\n\n// Пустой/пробельный заголовок считается отсутствующим — иначе хедер занимал бы\n// место ради строки-заглушки.\nconst resolvedTitle = computed(() => props.title?.trim() || undefined)\nconst hasTitle = computed(() => Boolean(resolvedTitle.value) || Boolean(slots.title))\nconst hasCustomHeader = computed(() => Boolean(slots.header))\nconst hasHeader = computed(() =>\n props.showHeader && (hasCustomHeader.value || hasTitle.value || props.showCloseButton),\n)\n\n/**\n * Видимый заголовок рисуется только в стандартной шапке. Со своей шапкой и без\n * шапки вовсе заголовок всё равно нужен — но скрытым: имя слоя обязано остаться\n * осмысленным, а не свалиться на обобщённое «Drawer» из локали.\n */\nconst showVisibleTitle = computed(() =>\n props.showHeader && !hasCustomHeader.value && hasTitle.value,\n)\nconst showSrOnlyTitle = computed(() => hasTitle.value && !showVisibleTitle.value)\n\n// Имя модального слоя обязательно: без него axe роняет `aria-dialog-name`.\n// Есть заголовок — связываем `aria-labelledby`, иначе даём `aria-label` из i18n.\nconst labelledBy = computed(() => (hasTitle.value ? titleId : undefined))\nconst ariaLabel = computed(() => (labelledBy.value ? undefined : t('gr.drawer.title', 'Drawer')))\n\nconst panelEl = ref<HTMLElement | null>(null)\n\n/** Произвольный размер — только по оси панели: у боковой ширина, у нижней высота. */\nconst customLength = computed(() => (axis.value === 'horizontal' ? props.width : props.height))\n\nconst panelClass = computed(() => grDrawerPanelClass({\n side: side.value,\n size: size.value,\n hasCustomLength: customLength.value !== undefined,\n}))\n\nconst panelStyle = computed(() => {\n const length = customLength.value\n if (length === undefined)\n return undefined\n\n const value = typeof length === 'number' ? `${length}px` : length\n return axis.value === 'horizontal' ? { width: value } : { height: value }\n})\n\n// Проп не своей оси молча не работал бы — а выглядит это как баг компонента.\nif (__GR_DEV__) {\n watch(\n [axis, () => props.width, () => props.height],\n ([currentAxis, width, height]) => {\n const ignored = currentAxis === 'horizontal' ? 'height' : 'width'\n const value = currentAxis === 'horizontal' ? height : width\n if (value === undefined)\n return\n\n console.warn(\n `[GrDrawer] Проп \\`${ignored}\\` не применяется к стороне \"${side.value}\": `\n + `панель по этой оси растянута. Задайте \\`${ignored === 'height' ? 'width' : 'height'}\\`.`,\n )\n },\n { immediate: true },\n )\n}\n\nconst panelEnterFrom = computed(() => grDrawerPanelEnterFrom(side.value))\n\nconst headerSection = computed(() => resolveGrDrawerSectionConfig(props.headerConfig, DEFAULT_GR_DRAWER_HEADER_CONFIG))\nconst bodySection = computed(() => resolveGrDrawerSectionConfig(props.bodyConfig, DEFAULT_GR_DRAWER_BODY_CONFIG))\nconst footerSection = computed(() => resolveGrDrawerSectionConfig(props.footerConfig, DEFAULT_GR_DRAWER_FOOTER_CONFIG))\n\nfunction sectionClass(\n section: { paddingX: string, paddingY: string, bordered: boolean },\n borderClass: string,\n): string[] {\n return [section.paddingX, section.paddingY, section.bordered ? borderClass : '']\n}\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\n/** Закрытие «мягким» способом: бэкдроп или Esc. `persistent` их и запрещает. */\nfunction closeSoftly(): void {\n if (props.persistent)\n return\n\n close()\n}\n\nconst rootClasses = computed(() => [rootClass, props.modal ? '' : rootPassThroughClass].filter(Boolean))\n\n// Немодальная панель остаётся в очереди Esc, но модалки под собой в `inert` не\n// отправляет и скролл не блокирует: она существует ровно ради работы со\n// страницей под ней, и Tab обязан уводить фокус туда.\nconst {\n rootEl,\n isMounted,\n isVisible,\n inertAttr,\n portalTarget,\n teleportEnabled,\n themeAttrs,\n onPanelAfterLeave: releasePresence,\n backdrop,\n} = useModalOverlay(computed(() => props.modelValue), closeSoftly, {\n panel: panelEl,\n modal: () => props.modal,\n closeOnEscape: () => props.closeOnEsc && !props.persistent,\n closeOnBackdrop: () => props.closeOnBackdrop,\n initialFocus: () => props.initialFocus ?? panelEl.value,\n})\n\nfunction onPanelAfterLeave(): void {\n releasePresence()\n emit('closed')\n}\n\ndefineExpose({\n /** Закрыть панель (эквивалент `v-model = false`), минуя `persistent`. */\n close,\n /** Вернуть фокус на панель — например после операции, уведшей его наружу. */\n focus: () => panelEl.value?.focus(),\n})\n</script>\n\n<template>\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <div\n v-if=\"teleportEnabled && isMounted\"\n ref=\"rootEl\"\n data-gr-drawer\n data-gr-overlay-root\n role=\"dialog\"\n :aria-modal=\"modal ? 'true' : undefined\"\n :class=\"rootClasses\"\n :inert=\"inertAttr\"\n :aria-labelledby=\"labelledBy\"\n :aria-label=\"ariaLabel\"\n >\n <Transition\n appear\n enter-active-class=\"duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n enter-from-class=\"opacity-0\"\n leave-active-class=\"duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)]\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"isVisible && modal\"\n data-gr-drawer-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n v-on=\"backdrop\"\n />\n </Transition>\n\n <Transition\n appear\n enter-active-class=\"duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n :enter-from-class=\"panelEnterFrom\"\n leave-active-class=\"duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)]\"\n :leave-to-class=\"panelEnterFrom\"\n @after-enter=\"emit('opened')\"\n @after-leave=\"onPanelAfterLeave\"\n >\n <div\n v-if=\"isVisible\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-drawer-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n :style=\"panelStyle\"\n >\n <!-- Заголовок без видимой шапки: имя слоя обязано остаться своим. -->\n <div\n v-if=\"showSrOnlyTitle\"\n :id=\"titleId\"\n data-gr-drawer-title\n :class=\"srOnlyTitleClass\"\n >\n <slot name=\"title\">\n {{ resolvedTitle }}\n </slot>\n </div>\n\n <div\n v-if=\"hasHeader\"\n data-gr-drawer-header\n :class=\"[hasCustomHeader ? '' : 'flex items-center justify-between gap-4', sectionClass(headerSection, headerBorderClass)]\"\n >\n <slot name=\"header\" :title=\"resolvedTitle\" :close=\"close\">\n <div\n v-if=\"showVisibleTitle\"\n :id=\"titleId\"\n data-gr-drawer-title\n :class=\"titleClass\"\n >\n <slot name=\"title\">\n {{ resolvedTitle }}\n </slot>\n </div>\n <div v-else class=\"min-w-0 flex-1\" />\n\n <GrButton\n v-if=\"showCloseButton\"\n variant=\"ghost\"\n size=\"sm\"\n square\n data-gr-drawer-close\n :aria-label=\"resolvedCloseLabel\"\n @click=\"close\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </GrButton>\n </slot>\n </div>\n\n <!-- Тело скроллится, поэтому обязано попадать в таб-порядок: длинный\n текст без единого фокусируемого элемента иначе не прокрутить с\n клавиатуры (axe: `scrollable-region-focusable`). -->\n <div\n data-gr-drawer-body\n tabindex=\"0\"\n class=\"min-h-0 flex-1 overflow-y-auto\"\n >\n <div :class=\"sectionClass(bodySection, '')\">\n <slot />\n </div>\n </div>\n\n <div\n v-if=\"$slots.footer\"\n data-gr-drawer-footer\n :class=\"sectionClass(footerSection, footerBorderClass)\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </Transition>\n </div>\n </teleport>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, useId, watch } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n// Модальный слой целиком: стек (Esc верхнему, `inert` нижним модалкам), ловушка\n// фокуса, скролл-лок, портал. Немодальная панель регистрируется в стеке как\n// обычный dismissible-слой и страницу под собой не трогает.\nimport { useModalOverlay } from '../../composables/internal/useModalOverlay'\nimport {\n DEFAULT_GR_DRAWER_BODY_CONFIG,\n DEFAULT_GR_DRAWER_FOOTER_CONFIG,\n DEFAULT_GR_DRAWER_HEADER_CONFIG,\n footerBorderClass,\n grDrawerAxis,\n grDrawerPanelClass,\n grDrawerPanelEnterFrom,\n headerBorderClass,\n overlayClass,\n resolveGrDrawerSectionConfig,\n rootClass,\n rootPassThroughClass,\n srOnlyTitleClass,\n titleClass,\n type GrDrawerSectionConfig,\n type GrDrawerSide,\n type GrDrawerSize,\n} from './grDrawerStyles'\n\nimport IconClose from '~icons/lucide/x'\n\nimport './defaults'\n\nexport interface GrDrawerProps {\n /** Контроль открытия через v-model. */\n modelValue: boolean\n /** Заголовок; если передан — покажется в хедере. Можно переопределить слотом `#title`. */\n title?: string\n /**\n * Модальная панель: подложка, блокировка скролла, `inert` остальной странице\n * и ловушка фокуса. `false` — панель живёт рядом со страницей: с ней работают,\n * не закрывая, а Tab уходит наружу.\n */\n modal?: boolean\n /** Закрывать при клике по бэкдропу. В немодальном режиме подложки нет. */\n closeOnBackdrop?: boolean\n /** Закрывать по Esc. */\n closeOnEsc?: boolean\n /**\n * Запрет закрытия «мягкими» способами (бэкдроп, Esc) — на время операции,\n * которую нельзя бросить на полпути. Кнопка закрытия при этом остаётся:\n * панель без единого выхода — ловушка.\n */\n persistent?: boolean\n /** Сторона, с которой выезжает панель. */\n side?: GrDrawerSide\n /** Размер панели по её оси: ширина у боковых, высота у верхней и нижней. */\n size?: GrDrawerSize\n /** Произвольная ширина боковой панели. Число трактуется как пиксели; сильнее `size`. */\n width?: string | number\n /** Произвольная высота верхней или нижней панели. Число трактуется как пиксели. */\n height?: string | number\n /** Рендерить ли хедер (заголовок + кнопка закрытия). */\n showHeader?: boolean\n /** Рендерить ли кнопку закрытия в хедере. */\n showCloseButton?: boolean\n /** Паддинги и рамка секций — как у `GrDialog`. */\n headerConfig?: GrDrawerSectionConfig\n bodyConfig?: GrDrawerSectionConfig\n footerConfig?: GrDrawerSectionConfig\n /** Элемент, получающий фокус при открытии. По умолчанию — сама панель. */\n initialFocus?: HTMLElement | null\n /** i18n-friendly aria-label для кнопки закрытия. */\n closeLabel?: string\n}\n\nexport interface GrDrawerEmits {\n (e: 'update:modelValue', value: boolean): void\n /** Панель выехала и анимация закончилась. */\n (e: 'opened'): void\n /** Панель уехала и анимация закончилась. */\n (e: 'closed'): void\n}\n\n// Дефолты оформления намеренно `undefined`: «настоящий» дефолт живёт в\n// `useGrComponentProp`, иначе `GrConfigProvider` не отличит заданный\n// пользователем проп от подставленного Vue.\nconst props = withDefaults(defineProps<GrDrawerProps>(), {\n title: undefined,\n modal: true,\n closeOnBackdrop: true,\n closeOnEsc: true,\n persistent: false,\n side: undefined,\n size: undefined,\n width: undefined,\n height: undefined,\n showHeader: true,\n showCloseButton: true,\n headerConfig: undefined,\n bodyConfig: undefined,\n footerConfig: undefined,\n initialFocus: null,\n closeLabel: undefined,\n})\n\nconst { t } = useGranularityTranslations()\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? t('gr.common.close', 'Close'))\n\nconst emit = defineEmits<GrDrawerEmits>()\n\nconst slots = defineSlots<{\n default?: () => any\n title?: () => any\n /** Своя шапка целиком: заголовок, кнопка закрытия и всё, что нужно рядом. */\n header?: (props: { title?: string, close: () => void }) => any\n footer?: () => any\n}>()\n\nconst titleId = useId()\n\nconst size = useGrComponentProp('GrDrawer', 'size', () => props.size, 'md')\nconst side = useGrComponentProp('GrDrawer', 'side', () => props.side, 'right')\n\nconst axis = computed(() => grDrawerAxis(side.value))\n\n// Пустой/пробельный заголовок считается отсутствующим — иначе хедер занимал бы\n// место ради строки-заглушки.\nconst resolvedTitle = computed(() => props.title?.trim() || undefined)\nconst hasTitle = computed(() => Boolean(resolvedTitle.value) || Boolean(slots.title))\nconst hasCustomHeader = computed(() => Boolean(slots.header))\nconst hasHeader = computed(() =>\n props.showHeader && (hasCustomHeader.value || hasTitle.value || props.showCloseButton),\n)\n\n/**\n * Видимый заголовок рисуется только в стандартной шапке. Со своей шапкой и без\n * шапки вовсе заголовок всё равно нужен — но скрытым: имя слоя обязано остаться\n * осмысленным, а не свалиться на обобщённое «Drawer» из локали.\n */\nconst showVisibleTitle = computed(() =>\n props.showHeader && !hasCustomHeader.value && hasTitle.value,\n)\nconst showSrOnlyTitle = computed(() => hasTitle.value && !showVisibleTitle.value)\n\n// Имя модального слоя обязательно: без него axe роняет `aria-dialog-name`.\n// Есть заголовок — связываем `aria-labelledby`, иначе даём `aria-label` из i18n.\nconst labelledBy = computed(() => (hasTitle.value ? titleId : undefined))\nconst ariaLabel = computed(() => (labelledBy.value ? undefined : t('gr.drawer.title', 'Drawer')))\n\nconst panelEl = ref<HTMLElement | null>(null)\n\n/** Произвольный размер — только по оси панели: у боковой ширина, у нижней высота. */\nconst customLength = computed(() => (axis.value === 'horizontal' ? props.width : props.height))\n\nconst panelClass = computed(() => grDrawerPanelClass({\n side: side.value,\n size: size.value,\n hasCustomLength: customLength.value !== undefined,\n}))\n\nconst panelStyle = computed(() => {\n const length = customLength.value\n if (length === undefined)\n return undefined\n\n const value = typeof length === 'number' ? `${length}px` : length\n return axis.value === 'horizontal' ? { width: value } : { height: value }\n})\n\n// Проп не своей оси молча не работал бы — а выглядит это как баг компонента.\nif (__GR_DEV__) {\n watch(\n [axis, () => props.width, () => props.height],\n ([currentAxis, width, height]) => {\n const ignored = currentAxis === 'horizontal' ? 'height' : 'width'\n const value = currentAxis === 'horizontal' ? height : width\n if (value === undefined)\n return\n\n console.warn(\n `[GrDrawer] Проп \\`${ignored}\\` не применяется к стороне \"${side.value}\": `\n + `панель по этой оси растянута. Задайте \\`${ignored === 'height' ? 'width' : 'height'}\\`.`,\n )\n },\n { immediate: true },\n )\n}\n\nconst panelEnterFrom = computed(() => grDrawerPanelEnterFrom(side.value))\n\nconst headerSection = computed(() => resolveGrDrawerSectionConfig(props.headerConfig, DEFAULT_GR_DRAWER_HEADER_CONFIG))\nconst bodySection = computed(() => resolveGrDrawerSectionConfig(props.bodyConfig, DEFAULT_GR_DRAWER_BODY_CONFIG))\nconst footerSection = computed(() => resolveGrDrawerSectionConfig(props.footerConfig, DEFAULT_GR_DRAWER_FOOTER_CONFIG))\n\nfunction sectionClass(\n section: { paddingX: string, paddingY: string, bordered: boolean },\n borderClass: string,\n): string[] {\n return [section.paddingX, section.paddingY, section.bordered ? borderClass : '']\n}\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\n/** Закрытие «мягким» способом: бэкдроп или Esc. `persistent` их и запрещает. */\nfunction closeSoftly(): void {\n if (props.persistent)\n return\n\n close()\n}\n\nconst rootClasses = computed(() => [rootClass, props.modal ? '' : rootPassThroughClass].filter(Boolean))\n\n// Немодальная панель остаётся в очереди Esc, но модалки под собой в `inert` не\n// отправляет и скролл не блокирует: она существует ровно ради работы со\n// страницей под ней, и Tab обязан уводить фокус туда.\nconst {\n rootEl,\n isMounted,\n isVisible,\n inertAttr,\n portalTarget,\n teleportEnabled,\n themeAttrs,\n onPanelAfterLeave: releasePresence,\n backdrop,\n} = useModalOverlay(computed(() => props.modelValue), closeSoftly, {\n panel: panelEl,\n modal: () => props.modal,\n closeOnEscape: () => props.closeOnEsc && !props.persistent,\n closeOnBackdrop: () => props.closeOnBackdrop,\n initialFocus: () => props.initialFocus ?? panelEl.value,\n})\n\nfunction onPanelAfterLeave(): void {\n releasePresence()\n emit('closed')\n}\n\ndefineExpose({\n /** Закрыть панель (эквивалент `v-model = false`), минуя `persistent`. */\n close,\n /** Вернуть фокус на панель — например после операции, уведшей его наружу. */\n focus: () => panelEl.value?.focus(),\n})\n</script>\n\n<template>\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <div\n v-if=\"teleportEnabled && isMounted\"\n ref=\"rootEl\"\n data-gr-drawer\n data-gr-overlay-root\n role=\"dialog\"\n :aria-modal=\"modal ? 'true' : undefined\"\n :class=\"rootClasses\"\n :inert=\"inertAttr\"\n :aria-labelledby=\"labelledBy\"\n :aria-label=\"ariaLabel\"\n >\n <Transition\n appear\n enter-active-class=\"duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n enter-from-class=\"opacity-0\"\n leave-active-class=\"duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)]\"\n leave-to-class=\"opacity-0\"\n >\n <div\n v-if=\"isVisible && modal\"\n data-gr-drawer-overlay\n :class=\"overlayClass\"\n aria-hidden=\"true\"\n v-on=\"backdrop\"\n />\n </Transition>\n\n <Transition\n appear\n enter-active-class=\"duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n :enter-from-class=\"panelEnterFrom\"\n leave-active-class=\"duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)]\"\n :leave-to-class=\"panelEnterFrom\"\n @after-enter=\"emit('opened')\"\n @after-leave=\"onPanelAfterLeave\"\n >\n <div\n v-if=\"isVisible\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-drawer-panel\n tabindex=\"-1\"\n :class=\"panelClass\"\n :style=\"panelStyle\"\n >\n <!-- Заголовок без видимой шапки: имя слоя обязано остаться своим. -->\n <div\n v-if=\"showSrOnlyTitle\"\n :id=\"titleId\"\n data-gr-drawer-title\n :class=\"srOnlyTitleClass\"\n >\n <slot name=\"title\">\n {{ resolvedTitle }}\n </slot>\n </div>\n\n <div\n v-if=\"hasHeader\"\n data-gr-drawer-header\n :class=\"[hasCustomHeader ? '' : 'flex items-center justify-between gap-4', sectionClass(headerSection, headerBorderClass)]\"\n >\n <slot name=\"header\" :title=\"resolvedTitle\" :close=\"close\">\n <div\n v-if=\"showVisibleTitle\"\n :id=\"titleId\"\n data-gr-drawer-title\n :class=\"titleClass\"\n >\n <slot name=\"title\">\n {{ resolvedTitle }}\n </slot>\n </div>\n <div v-else class=\"min-w-0 flex-1\" />\n\n <GrButton\n v-if=\"showCloseButton\"\n variant=\"ghost\"\n size=\"sm\"\n square\n data-gr-drawer-close\n :aria-label=\"resolvedCloseLabel\"\n @click=\"close\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </GrButton>\n </slot>\n </div>\n\n <!-- Тело скроллится, поэтому обязано попадать в таб-порядок: длинный\n текст без единого фокусируемого элемента иначе не прокрутить с\n клавиатуры (axe: `scrollable-region-focusable`). -->\n <div\n data-gr-drawer-body\n tabindex=\"0\"\n class=\"min-h-0 flex-1 overflow-y-auto\"\n >\n <div :class=\"sectionClass(bodySection, '')\">\n <slot />\n </div>\n </div>\n\n <div\n v-if=\"$slots.footer\"\n data-gr-drawer-footer\n :class=\"sectionClass(footerSection, footerBorderClass)\"\n >\n <slot name=\"footer\" />\n </div>\n </div>\n </Transition>\n </div>\n </teleport>\n</template>\n"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { n as grDrawerSafelist, t as grDrawerConfig } from "../../chunks/config-ChPg-BQv.js";
|
|
2
|
-
import { t as GrDrawer_default } from "./chunks/GrDrawer-
|
|
2
|
+
import { t as GrDrawer_default } from "./chunks/GrDrawer-C0YqVE9e.js";
|
|
3
3
|
export { GrDrawer_default as GrDrawer, GrDrawer_default as default, grDrawerConfig, grDrawerSafelist };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrDropdown-13Wt9eB_.js","names":[],"sources":["../../../../src/components/GrDropdown/GrDropdown.vue","../../../../src/components/GrDropdown/GrDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useMenuItemsFocus } from '../../composables/internal/useMenuItemsFocus'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport type GrDropdownTrigger = 'click' | 'hover'\n\nexport interface GrDropdownProps {\n /** Размещение панели относительно триггера; `flip` при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Панель не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n}\n\nexport interface GrDropdownEmits {\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: undefined,\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownEmits>()\n\n// Имя `isOpen` сохранено: читатели работают с computed-Ref.\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst panelId = useId()\n\n// Кольцо фокуса и поиск по буквам — общие с `GrContextMenu`: паттерн `menu`\n// один, и вторая его реализация разошлась бы с первой незаметно для тестов.\nconst menu = useMenuItemsFocus({\n container: () => panelEl.value,\n close: () => close(),\n})\n\nasync function openWithFocus(first: boolean): Promise<void> {\n if (props.disabled)\n return\n\n setOpen(true)\n await nextTick()\n menu.focusAt(first ? 0 : -1)\n}\n\n/**\n * Пропсы для реального фокусируемого триггера (кнопки). Консьюмер биндит их на\n * элемент внутри слота `#trigger`: `<GrButton v-bind=\"triggerProps\">`. Даёт\n * `aria-haspopup`/`aria-expanded`/`aria-controls`, клавиатуру и **клик**.\n *\n * Клик живёт здесь, а не на обёртке слота: обёртка ловила бы и клики по\n * вложенным кнопкам и ссылкам, переключая панель мимо намерения пользователя.\n */\nconst triggerProps = computed(() => ({\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'aria-disabled': props.disabled ? true : undefined,\n 'onClick': toggle,\n 'onKeydown': onTriggerKeydown,\n}))\n\nfunction onTriggerKeydown(event: KeyboardEvent): void {\n if (props.disabled)\n return\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault()\n void openWithFocus(true)\n break\n case 'ArrowUp':\n event.preventDefault()\n void openWithFocus(false)\n break\n case 'Escape':\n if (isOpen.value) {\n event.preventDefault()\n close()\n }\n break\n }\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n // Геттер, а не значение: иначе проп замрёт на моменте `setup`.\n get offsetPx() { return props.offset },\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\n// ————— Открытие по наведению. Задержки нужны обе: без `openDelay` панель\n// выпрыгивает на любое пересечение курсором, без `closeDelay` её не удержать\n// при переходе с триггера на панель — между ними зазор `offset`.\nlet hoverTimer: ReturnType<typeof setTimeout> | undefined\n\nfunction open(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(true)\n}\n\nfunction toggle(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(!isOpen.value)\n}\n\nfunction close(): void {\n clearTimeout(hoverTimer)\n setOpen(false)\n}\n\nfunction scheduleHover(next: boolean, delayMs: number): void {\n clearTimeout(hoverTimer)\n\n if (delayMs <= 0) {\n setOpen(next)\n return\n }\n\n hoverTimer = setTimeout(setOpen, delayMs, next)\n}\n\nfunction onHoverEnter(): void {\n if (props.disabled || props.trigger !== 'hover')\n return\n scheduleHover(true, props.openDelay)\n}\n\nfunction onHoverLeave(): void {\n if (props.trigger !== 'hover')\n return\n scheduleHover(false, props.closeDelay)\n}\n\n// Возврат фокуса — из контракта слоя: он запоминает активный элемент при\n// открытии и возвращает фокус, только если на момент закрытия тот всё ещё\n// внутри панели. Прежняя эвристика «возвращать, если открыли с клавиатуры»\n// промахивалась в обе стороны.\nuseOverlayLayer(isOpen, close, { root: panelEl })\n\nwatch(\n () => [props.placement, props.offset],\n () => {\n if (isOpen.value) updateFloatingPosition()\n },\n)\n\nwatch(\n () => props.disabled,\n (value) => {\n if (value) close()\n },\n)\n\nfunction toCssLength(value: GrDropdownWidth): string | undefined {\n if (value === 'auto')\n return undefined\n if (typeof value === 'number')\n return `${value}px`\n\n // Строка без единиц браузер просто отбросит, поэтому трактуем её как пиксели\n // — и предупреждаем: `width=\"48\"` легко прочесть как токен шкалы `w-48`.\n const bare = value.trim()\n if (/^\\d+$/.test(bare)) {\n if (__GR_DEV__) {\n console.warn(\n `[GrDropdown] width=\"${value}\" трактуется как ${bare}px. `\n + 'Шкалы tailwind-токенов (w-48) у пропа больше нет — укажите единицы: '\n + `width=\"${bare}px\" или :width=\"${bare}\".`,\n )\n }\n return `${bare}px`\n }\n\n return value\n}\n\nconst panelStyle = computed(() => {\n const width = toCssLength(props.width)\n return width ? { ...floatingStyle.value, width } : floatingStyle.value\n})\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => grDropdownOriginClass(resolvedPlacement.value))\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n\n// Триггер без `v-bind=\"triggerProps\"` — это триггер без клика, без клавиатуры и\n// без ARIA. Молчать об этом нельзя: панель просто не открывалась бы, и искать\n// причину пришлось бы в чужом коде.\nonMounted(() => {\n if (!__GR_DEV__)\n return\n if (rootEl.value?.querySelector('[aria-haspopup]'))\n return\n\n console.warn(\n '[GrDropdown] триггер не привязан: добавьте `v-bind=\"triggerProps\"` на элемент '\n + 'внутри слота #trigger — <template #trigger=\"{ triggerProps }\">'\n + '<GrButton v-bind=\"triggerProps\">…</GrButton></template>. '\n + 'Без этого у триггера нет ни клика, ни клавиатуры, ни aria-haspopup/aria-expanded.',\n )\n})\n\nonBeforeUnmount(() => {\n menu.reset()\n clearTimeout(hoverTimer)\n})\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(() => props.teleportTo)\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое меню. */\n content?: (props: { close: () => void }) => any\n}>()\n\n</script>\n\n<template>\n <div data-gr-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen, exclude: clickOutsideExclude }\"\n data-gr-dropdown-trigger\n class=\"inline-block max-w-full\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <slot name=\"trigger\" :open=\"isOpen\" :toggle=\"toggle\" :close=\"close\" :trigger-props=\"triggerProps\" />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-dropdown-panel\n data-gr-overlay-root\n role=\"menu\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n @keydown=\"menu.onKeydown\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <div data-gr-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useMenuItemsFocus } from '../../composables/internal/useMenuItemsFocus'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport type GrDropdownTrigger = 'click' | 'hover'\n\nexport interface GrDropdownProps {\n /** Размещение панели относительно триггера; `flip` при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Панель не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n}\n\nexport interface GrDropdownEmits {\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: undefined,\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownEmits>()\n\n// Имя `isOpen` сохранено: читатели работают с computed-Ref.\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst panelId = useId()\n\n// Кольцо фокуса и поиск по буквам — общие с `GrContextMenu`: паттерн `menu`\n// один, и вторая его реализация разошлась бы с первой незаметно для тестов.\nconst menu = useMenuItemsFocus({\n container: () => panelEl.value,\n close: () => close(),\n})\n\nasync function openWithFocus(first: boolean): Promise<void> {\n if (props.disabled)\n return\n\n setOpen(true)\n await nextTick()\n menu.focusAt(first ? 0 : -1)\n}\n\n/**\n * Пропсы для реального фокусируемого триггера (кнопки). Консьюмер биндит их на\n * элемент внутри слота `#trigger`: `<GrButton v-bind=\"triggerProps\">`. Даёт\n * `aria-haspopup`/`aria-expanded`/`aria-controls`, клавиатуру и **клик**.\n *\n * Клик живёт здесь, а не на обёртке слота: обёртка ловила бы и клики по\n * вложенным кнопкам и ссылкам, переключая панель мимо намерения пользователя.\n */\nconst triggerProps = computed(() => ({\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'aria-disabled': props.disabled ? true : undefined,\n 'onClick': toggle,\n 'onKeydown': onTriggerKeydown,\n}))\n\nfunction onTriggerKeydown(event: KeyboardEvent): void {\n if (props.disabled)\n return\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault()\n void openWithFocus(true)\n break\n case 'ArrowUp':\n event.preventDefault()\n void openWithFocus(false)\n break\n case 'Escape':\n if (isOpen.value) {\n event.preventDefault()\n close()\n }\n break\n }\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n // Геттер, а не значение: иначе проп замрёт на моменте `setup`.\n get offsetPx() { return props.offset },\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\n// ————— Открытие по наведению. Задержки нужны обе: без `openDelay` панель\n// выпрыгивает на любое пересечение курсором, без `closeDelay` её не удержать\n// при переходе с триггера на панель — между ними зазор `offset`.\nlet hoverTimer: ReturnType<typeof setTimeout> | undefined\n\nfunction open(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(true)\n}\n\nfunction toggle(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(!isOpen.value)\n}\n\nfunction close(): void {\n clearTimeout(hoverTimer)\n setOpen(false)\n}\n\nfunction scheduleHover(next: boolean, delayMs: number): void {\n clearTimeout(hoverTimer)\n\n if (delayMs <= 0) {\n setOpen(next)\n return\n }\n\n hoverTimer = setTimeout(setOpen, delayMs, next)\n}\n\nfunction onHoverEnter(): void {\n if (props.disabled || props.trigger !== 'hover')\n return\n scheduleHover(true, props.openDelay)\n}\n\nfunction onHoverLeave(): void {\n if (props.trigger !== 'hover')\n return\n scheduleHover(false, props.closeDelay)\n}\n\n// Возврат фокуса — из контракта слоя: он запоминает активный элемент при\n// открытии и возвращает фокус, только если на момент закрытия тот всё ещё\n// внутри панели. Прежняя эвристика «возвращать, если открыли с клавиатуры»\n// промахивалась в обе стороны.\nuseOverlayLayer(isOpen, close, { root: panelEl })\n\nwatch(\n () => [props.placement, props.offset],\n () => {\n if (isOpen.value) updateFloatingPosition()\n },\n)\n\nwatch(\n () => props.disabled,\n (value) => {\n if (value) close()\n },\n)\n\nfunction toCssLength(value: GrDropdownWidth): string | undefined {\n if (value === 'auto')\n return undefined\n if (typeof value === 'number')\n return `${value}px`\n\n // Строка без единиц браузер просто отбросит, поэтому трактуем её как пиксели\n // — и предупреждаем: `width=\"48\"` легко прочесть как токен шкалы `w-48`.\n const bare = value.trim()\n if (/^\\d+$/.test(bare)) {\n if (__GR_DEV__) {\n console.warn(\n `[GrDropdown] width=\"${value}\" трактуется как ${bare}px. `\n + 'Шкалы tailwind-токенов (w-48) у пропа больше нет — укажите единицы: '\n + `width=\"${bare}px\" или :width=\"${bare}\".`,\n )\n }\n return `${bare}px`\n }\n\n return value\n}\n\nconst panelStyle = computed(() => {\n const width = toCssLength(props.width)\n return width ? { ...floatingStyle.value, width } : floatingStyle.value\n})\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => grDropdownOriginClass(resolvedPlacement.value))\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n\n// Триггер без `v-bind=\"triggerProps\"` — это триггер без клика, без клавиатуры и\n// без ARIA. Молчать об этом нельзя: панель просто не открывалась бы, и искать\n// причину пришлось бы в чужом коде.\nonMounted(() => {\n if (!__GR_DEV__)\n return\n if (rootEl.value?.querySelector('[aria-haspopup]'))\n return\n\n console.warn(\n '[GrDropdown] триггер не привязан: добавьте `v-bind=\"triggerProps\"` на элемент '\n + 'внутри слота #trigger — <template #trigger=\"{ triggerProps }\">'\n + '<GrButton v-bind=\"triggerProps\">…</GrButton></template>. '\n + 'Без этого у триггера нет ни клика, ни клавиатуры, ни aria-haspopup/aria-expanded.',\n )\n})\n\nonBeforeUnmount(() => {\n menu.reset()\n clearTimeout(hoverTimer)\n})\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(() => props.teleportTo)\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое меню. */\n content?: (props: { close: () => void }) => any\n}>()\n\n</script>\n\n<template>\n <div data-gr-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen, exclude: clickOutsideExclude }\"\n data-gr-dropdown-trigger\n class=\"inline-block max-w-full\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <slot name=\"trigger\" :open=\"isOpen\" :toggle=\"toggle\" :close=\"close\" :trigger-props=\"triggerProps\" />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-dropdown-panel\n data-gr-overlay-root\n role=\"menu\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n @keydown=\"menu.onKeydown\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <div data-gr-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrDropdown-13Wt9eB_.js","names":[],"sources":["../../../../src/components/GrDropdown/GrDropdown.vue","../../../../src/components/GrDropdown/GrDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useMenuItemsFocus } from '../../composables/internal/useMenuItemsFocus'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport type GrDropdownTrigger = 'click' | 'hover'\n\nexport interface GrDropdownProps {\n /** Размещение панели относительно триггера; `flip` при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Панель не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n}\n\nexport interface GrDropdownEmits {\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: undefined,\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownEmits>()\n\n// Имя `isOpen` сохранено: читатели работают с computed-Ref.\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst panelId = useId()\n\n// Кольцо фокуса и поиск по буквам — общие с `GrContextMenu`: паттерн `menu`\n// один, и вторая его реализация разошлась бы с первой незаметно для тестов.\nconst menu = useMenuItemsFocus({\n container: () => panelEl.value,\n close: () => close(),\n})\n\nasync function openWithFocus(first: boolean): Promise<void> {\n if (props.disabled)\n return\n\n setOpen(true)\n await nextTick()\n menu.focusAt(first ? 0 : -1)\n}\n\n/**\n * Пропсы для реального фокусируемого триггера (кнопки). Консьюмер биндит их на\n * элемент внутри слота `#trigger`: `<GrButton v-bind=\"triggerProps\">`. Даёт\n * `aria-haspopup`/`aria-expanded`/`aria-controls`, клавиатуру и **клик**.\n *\n * Клик живёт здесь, а не на обёртке слота: обёртка ловила бы и клики по\n * вложенным кнопкам и ссылкам, переключая панель мимо намерения пользователя.\n */\nconst triggerProps = computed(() => ({\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'aria-disabled': props.disabled ? true : undefined,\n 'onClick': toggle,\n 'onKeydown': onTriggerKeydown,\n}))\n\nfunction onTriggerKeydown(event: KeyboardEvent): void {\n if (props.disabled)\n return\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault()\n void openWithFocus(true)\n break\n case 'ArrowUp':\n event.preventDefault()\n void openWithFocus(false)\n break\n case 'Escape':\n if (isOpen.value) {\n event.preventDefault()\n close()\n }\n break\n }\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n // Геттер, а не значение: иначе проп замрёт на моменте `setup`.\n get offsetPx() { return props.offset },\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\n// ————— Открытие по наведению. Задержки нужны обе: без `openDelay` панель\n// выпрыгивает на любое пересечение курсором, без `closeDelay` её не удержать\n// при переходе с триггера на панель — между ними зазор `offset`.\nlet hoverTimer: ReturnType<typeof setTimeout> | undefined\n\nfunction open(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(true)\n}\n\nfunction toggle(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(!isOpen.value)\n}\n\nfunction close(): void {\n clearTimeout(hoverTimer)\n setOpen(false)\n}\n\nfunction scheduleHover(next: boolean, delayMs: number): void {\n clearTimeout(hoverTimer)\n\n if (delayMs <= 0) {\n setOpen(next)\n return\n }\n\n hoverTimer = setTimeout(setOpen, delayMs, next)\n}\n\nfunction onHoverEnter(): void {\n if (props.disabled || props.trigger !== 'hover')\n return\n scheduleHover(true, props.openDelay)\n}\n\nfunction onHoverLeave(): void {\n if (props.trigger !== 'hover')\n return\n scheduleHover(false, props.closeDelay)\n}\n\n// Возврат фокуса — из контракта слоя: он запоминает активный элемент при\n// открытии и возвращает фокус, только если на момент закрытия тот всё ещё\n// внутри панели. Прежняя эвристика «возвращать, если открыли с клавиатуры»\n// промахивалась в обе стороны.\nuseOverlayLayer(isOpen, close, { root: panelEl })\n\nwatch(\n () => [props.placement, props.offset],\n () => {\n if (isOpen.value)\n updateFloatingPosition()\n },\n)\n\nwatch(\n () => props.disabled,\n (value) => {\n if (value)\n close()\n },\n)\n\nfunction toCssLength(value: GrDropdownWidth): string | undefined {\n if (value === 'auto')\n return undefined\n if (typeof value === 'number')\n return `${value}px`\n\n // Строка без единиц браузер просто отбросит, поэтому трактуем её как пиксели\n // — и предупреждаем: `width=\"48\"` легко прочесть как токен шкалы `w-48`.\n const bare = value.trim()\n if (/^\\d+$/.test(bare)) {\n if (__GR_DEV__) {\n console.warn(\n `[GrDropdown] width=\"${value}\" трактуется как ${bare}px. `\n + 'Шкалы tailwind-токенов (w-48) у пропа больше нет — укажите единицы: '\n + `width=\"${bare}px\" или :width=\"${bare}\".`,\n )\n }\n return `${bare}px`\n }\n\n return value\n}\n\nconst panelStyle = computed(() => {\n const width = toCssLength(props.width)\n return width ? { ...floatingStyle.value, width } : floatingStyle.value\n})\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => grDropdownOriginClass(resolvedPlacement.value))\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n\n// Триггер без `v-bind=\"triggerProps\"` — это триггер без клика, без клавиатуры и\n// без ARIA. Молчать об этом нельзя: панель просто не открывалась бы, и искать\n// причину пришлось бы в чужом коде.\nonMounted(() => {\n if (!__GR_DEV__)\n return\n if (rootEl.value?.querySelector('[aria-haspopup]'))\n return\n\n console.warn(\n '[GrDropdown] триггер не привязан: добавьте `v-bind=\"triggerProps\"` на элемент '\n + 'внутри слота #trigger — <template #trigger=\"{ triggerProps }\">'\n + '<GrButton v-bind=\"triggerProps\">…</GrButton></template>. '\n + 'Без этого у триггера нет ни клика, ни клавиатуры, ни aria-haspopup/aria-expanded.',\n )\n})\n\nonBeforeUnmount(() => {\n menu.reset()\n clearTimeout(hoverTimer)\n})\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(() => props.teleportTo)\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое меню. */\n content?: (props: { close: () => void }) => any\n}>()\n</script>\n\n<template>\n <div data-gr-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen, exclude: clickOutsideExclude }\"\n data-gr-dropdown-trigger\n class=\"inline-block max-w-full\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <slot name=\"trigger\" :open=\"isOpen\" :toggle=\"toggle\" :close=\"close\" :trigger-props=\"triggerProps\" />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-dropdown-panel\n data-gr-overlay-root\n role=\"menu\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n @keydown=\"menu.onKeydown\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <div data-gr-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useMenuItemsFocus } from '../../composables/internal/useMenuItemsFocus'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport type GrDropdownTrigger = 'click' | 'hover'\n\nexport interface GrDropdownProps {\n /** Размещение панели относительно триггера; `flip` при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Панель не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n}\n\nexport interface GrDropdownEmits {\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: undefined,\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownEmits>()\n\n// Имя `isOpen` сохранено: читатели работают с computed-Ref.\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst panelId = useId()\n\n// Кольцо фокуса и поиск по буквам — общие с `GrContextMenu`: паттерн `menu`\n// один, и вторая его реализация разошлась бы с первой незаметно для тестов.\nconst menu = useMenuItemsFocus({\n container: () => panelEl.value,\n close: () => close(),\n})\n\nasync function openWithFocus(first: boolean): Promise<void> {\n if (props.disabled)\n return\n\n setOpen(true)\n await nextTick()\n menu.focusAt(first ? 0 : -1)\n}\n\n/**\n * Пропсы для реального фокусируемого триггера (кнопки). Консьюмер биндит их на\n * элемент внутри слота `#trigger`: `<GrButton v-bind=\"triggerProps\">`. Даёт\n * `aria-haspopup`/`aria-expanded`/`aria-controls`, клавиатуру и **клик**.\n *\n * Клик живёт здесь, а не на обёртке слота: обёртка ловила бы и клики по\n * вложенным кнопкам и ссылкам, переключая панель мимо намерения пользователя.\n */\nconst triggerProps = computed(() => ({\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'aria-disabled': props.disabled ? true : undefined,\n 'onClick': toggle,\n 'onKeydown': onTriggerKeydown,\n}))\n\nfunction onTriggerKeydown(event: KeyboardEvent): void {\n if (props.disabled)\n return\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault()\n void openWithFocus(true)\n break\n case 'ArrowUp':\n event.preventDefault()\n void openWithFocus(false)\n break\n case 'Escape':\n if (isOpen.value) {\n event.preventDefault()\n close()\n }\n break\n }\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n // Геттер, а не значение: иначе проп замрёт на моменте `setup`.\n get offsetPx() { return props.offset },\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\n// ————— Открытие по наведению. Задержки нужны обе: без `openDelay` панель\n// выпрыгивает на любое пересечение курсором, без `closeDelay` её не удержать\n// при переходе с триггера на панель — между ними зазор `offset`.\nlet hoverTimer: ReturnType<typeof setTimeout> | undefined\n\nfunction open(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(true)\n}\n\nfunction toggle(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(!isOpen.value)\n}\n\nfunction close(): void {\n clearTimeout(hoverTimer)\n setOpen(false)\n}\n\nfunction scheduleHover(next: boolean, delayMs: number): void {\n clearTimeout(hoverTimer)\n\n if (delayMs <= 0) {\n setOpen(next)\n return\n }\n\n hoverTimer = setTimeout(setOpen, delayMs, next)\n}\n\nfunction onHoverEnter(): void {\n if (props.disabled || props.trigger !== 'hover')\n return\n scheduleHover(true, props.openDelay)\n}\n\nfunction onHoverLeave(): void {\n if (props.trigger !== 'hover')\n return\n scheduleHover(false, props.closeDelay)\n}\n\n// Возврат фокуса — из контракта слоя: он запоминает активный элемент при\n// открытии и возвращает фокус, только если на момент закрытия тот всё ещё\n// внутри панели. Прежняя эвристика «возвращать, если открыли с клавиатуры»\n// промахивалась в обе стороны.\nuseOverlayLayer(isOpen, close, { root: panelEl })\n\nwatch(\n () => [props.placement, props.offset],\n () => {\n if (isOpen.value)\n updateFloatingPosition()\n },\n)\n\nwatch(\n () => props.disabled,\n (value) => {\n if (value)\n close()\n },\n)\n\nfunction toCssLength(value: GrDropdownWidth): string | undefined {\n if (value === 'auto')\n return undefined\n if (typeof value === 'number')\n return `${value}px`\n\n // Строка без единиц браузер просто отбросит, поэтому трактуем её как пиксели\n // — и предупреждаем: `width=\"48\"` легко прочесть как токен шкалы `w-48`.\n const bare = value.trim()\n if (/^\\d+$/.test(bare)) {\n if (__GR_DEV__) {\n console.warn(\n `[GrDropdown] width=\"${value}\" трактуется как ${bare}px. `\n + 'Шкалы tailwind-токенов (w-48) у пропа больше нет — укажите единицы: '\n + `width=\"${bare}px\" или :width=\"${bare}\".`,\n )\n }\n return `${bare}px`\n }\n\n return value\n}\n\nconst panelStyle = computed(() => {\n const width = toCssLength(props.width)\n return width ? { ...floatingStyle.value, width } : floatingStyle.value\n})\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => grDropdownOriginClass(resolvedPlacement.value))\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n\n// Триггер без `v-bind=\"triggerProps\"` — это триггер без клика, без клавиатуры и\n// без ARIA. Молчать об этом нельзя: панель просто не открывалась бы, и искать\n// причину пришлось бы в чужом коде.\nonMounted(() => {\n if (!__GR_DEV__)\n return\n if (rootEl.value?.querySelector('[aria-haspopup]'))\n return\n\n console.warn(\n '[GrDropdown] триггер не привязан: добавьте `v-bind=\"triggerProps\"` на элемент '\n + 'внутри слота #trigger — <template #trigger=\"{ triggerProps }\">'\n + '<GrButton v-bind=\"triggerProps\">…</GrButton></template>. '\n + 'Без этого у триггера нет ни клика, ни клавиатуры, ни aria-haspopup/aria-expanded.',\n )\n})\n\nonBeforeUnmount(() => {\n menu.reset()\n clearTimeout(hoverTimer)\n})\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(() => props.teleportTo)\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое меню. */\n content?: (props: { close: () => void }) => any\n}>()\n</script>\n\n<template>\n <div data-gr-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen, exclude: clickOutsideExclude }\"\n data-gr-dropdown-trigger\n class=\"inline-block max-w-full\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <slot name=\"trigger\" :open=\"isOpen\" :toggle=\"toggle\" :close=\"close\" :trigger-props=\"triggerProps\" />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-dropdown-panel\n data-gr-overlay-root\n role=\"menu\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n @keydown=\"menu.onKeydown\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <div data-gr-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrDropdownMenu-GOzuAXsi.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n// Типы размещения и ширины — из владельца API, а не переобъявлением: расхождение\n// обнаружилось бы только рантаймом.\nimport type { GrDropdownTrigger } from '../GrDropdown/GrDropdown.vue'\nimport type { GrDropdownWidth } from '../GrDropdown/grDropdownStyles'\nimport type { UseFloatingPlacement } from '../../composables/useFloating'\n\nimport GrDropdownMenuEntries from './GrDropdownMenuEntries.vue'\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\n\nexport interface GrDropdownMenuProps {\n /** Размещение панели относительно триггера; переворот при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Меню не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Куда телепортировать панель (`body` по умолчанию). */\n /** Точечное переопределение точки монтирования; по умолчанию — общий портал. */\n teleportTo?: string | HTMLElement\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера. */\n contentClass?: string\n /**\n * Декларативное меню: пункты, группы и разделители массивом. Слот по\n * умолчанию сильнее — он для меню, которое из модели не собирается.\n */\n items?: GrDropdownMenuEntry[]\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n /**\n * Контролируемое состояние панели (`v-model:open`) — прокидывается в\n * `GrDropdown`. Без пропа меню ведёт себя само (uncontrolled).\n */\n open?: boolean\n}\n\nexport interface GrDropdownMenuEmits {\n /** Выбран пункт декларативного меню. */\n (e: 'select', item: GrDropdownMenuAction): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n teleportTo: undefined,\n closeOnContentClick: true,\n // Поле панели принадлежит панели. Гасить его отсюда своим `p-0` нельзя: оба\n // класса попадают в один атрибут с равной специфичностью, и победителя\n // выбирает порядок правил в сгенерированном CSS, а не разметка. Пункт вписан\n // в это поле собственным радиусом — см. `itemBaseClass`.\n contentClass: '',\n items: undefined,\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownMenuEmits>()\n\ndefineSlots<{\n /** Пункты меню. Слот-пропы прокидываются от `GrDropdown` как есть. */\n default?: (props: { close: () => void }) => any\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n}>()\n\n</script>\n\n<template>\n <GrDropdown\n data-gr-dropdown-menu\n :placement=\"placement\"\n :offset=\"offset\"\n :width=\"width\"\n :trigger=\"trigger\"\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n :disabled=\"disabled\"\n :teleport-to=\"teleportTo\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n :open=\"open\"\n @update:open=\"emit('update:open', $event)\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\">\n <GrDropdownMenuEntries :items=\"items\" @select=\"emit('select', $event)\" />\n </slot>\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n// Типы размещения и ширины — из владельца API, а не переобъявлением: расхождение\n// обнаружилось бы только рантаймом.\nimport type { GrDropdownTrigger } from '../GrDropdown/GrDropdown.vue'\nimport type { GrDropdownWidth } from '../GrDropdown/grDropdownStyles'\nimport type { UseFloatingPlacement } from '../../composables/useFloating'\n\nimport GrDropdownMenuEntries from './GrDropdownMenuEntries.vue'\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\n\nexport interface GrDropdownMenuProps {\n /** Размещение панели относительно триггера; переворот при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Меню не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Куда телепортировать панель (`body` по умолчанию). */\n /** Точечное переопределение точки монтирования; по умолчанию — общий портал. */\n teleportTo?: string | HTMLElement\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера. */\n contentClass?: string\n /**\n * Декларативное меню: пункты, группы и разделители массивом. Слот по\n * умолчанию сильнее — он для меню, которое из модели не собирается.\n */\n items?: GrDropdownMenuEntry[]\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n /**\n * Контролируемое состояние панели (`v-model:open`) — прокидывается в\n * `GrDropdown`. Без пропа меню ведёт себя само (uncontrolled).\n */\n open?: boolean\n}\n\nexport interface GrDropdownMenuEmits {\n /** Выбран пункт декларативного меню. */\n (e: 'select', item: GrDropdownMenuAction): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n teleportTo: undefined,\n closeOnContentClick: true,\n // Поле панели принадлежит панели. Гасить его отсюда своим `p-0` нельзя: оба\n // класса попадают в один атрибут с равной специфичностью, и победителя\n // выбирает порядок правил в сгенерированном CSS, а не разметка. Пункт вписан\n // в это поле собственным радиусом — см. `itemBaseClass`.\n contentClass: '',\n items: undefined,\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownMenuEmits>()\n\ndefineSlots<{\n /** Пункты меню. Слот-пропы прокидываются от `GrDropdown` как есть. */\n default?: (props: { close: () => void }) => any\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n}>()\n\n</script>\n\n<template>\n <GrDropdown\n data-gr-dropdown-menu\n :placement=\"placement\"\n :offset=\"offset\"\n :width=\"width\"\n :trigger=\"trigger\"\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n :disabled=\"disabled\"\n :teleport-to=\"teleportTo\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n :open=\"open\"\n @update:open=\"emit('update:open', $event)\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\">\n <GrDropdownMenuEntries :items=\"items\" @select=\"emit('select', $event)\" />\n </slot>\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport { alignClass, columnBaseClass, type GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\ndefineSlots<{\n /** Содержимое колонки меню. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-column\n role=\"none\"\n :class=\"[columnBaseClass, alignClass[align]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { alignClass, columnBaseClass, type GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\ndefineSlots<{\n /** Содержимое колонки меню. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-column\n role=\"none\"\n :class=\"[columnBaseClass, alignClass[align]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { colsClass, columnsBaseClass, type GrDropdownMenuColumnsCount } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: GrDropdownMenuColumnsCount\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\ndefineSlots<{\n /** Колонки меню (`GrDropdownMenuColumn`). */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-columns\n role=\"none\"\n :class=\"[columnsBaseClass, colsClass[cols]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { colsClass, columnsBaseClass, type GrDropdownMenuColumnsCount } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: GrDropdownMenuColumnsCount\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\ndefineSlots<{\n /** Колонки меню (`GrDropdownMenuColumn`). */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-columns\n role=\"none\"\n :class=\"[columnsBaseClass, colsClass[cols]]\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsFA,MAAM,OAAO;;uBAqBX,YA+Ba,oBAAA;IA9BX,yBAAA;IACC,WAAW,QAAA;IACX,QAAQ,QAAA;IACR,OAAO,QAAA;IACP,SAAS,QAAA;IACT,cAAY,QAAA;IACZ,eAAa,QAAA;IACb,UAAU,QAAA;IACV,eAAa,QAAA;IACb,0BAAwB,QAAA;IACxB,iBAAe,QAAA;IACf,MAAM,QAAA;IACN,iBAAW,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,eAAgB,MAAM;;IAE7B,SAAO,SAAE,cAAS,CAC3B,WAA0C,KAAA,QAAA,WAAA,eAAA,mBAAb,SAAS,CAAA,CAAA,CAAA,CAAA;IAG7B,SAAO,SAAE,cAAS,CAC3B,YASqB,4BAAA;KARlB,UAAU,QAAA;KACV,cAAY,QAAA;KACZ,iBAAe,QAAA;KACf,OAAK,eAAE,QAAA,SAAS;;4BAIV,CAFP,WAEO,KAAA,QAAA,WAAA,eAAA,mBAFO,SAAS,CAAA,SAEhB,CADL,YAAyE,+BAAA;MAAjD,OAAO,QAAA;MAAQ,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAW,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBEjH5E,mBAMM,OAAA;IALJ,gCAAA;IACA,MAAK;IACJ,OAAK,eAAA,CAAG,MAAA,eAAA,GAAiB,MAAA,UAAA,CAAU,CAAC,QAAA,MAAK,CAAA;OAE1C,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA;;;;;;;;;;;uBEPV,mBAMM,OAAA;IALJ,iCAAA;IACA,MAAK;IACJ,OAAK,eAAA,CAAG,MAAA,gBAAA,GAAkB,MAAA,SAAA,CAAS,CAAC,QAAA,KAAI,CAAA;OAEzC,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"GrDropdownMenu-GOzuAXsi.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n// Типы размещения и ширины — из владельца API, а не переобъявлением: расхождение\n// обнаружилось бы только рантаймом.\nimport type { GrDropdownTrigger } from '../GrDropdown/GrDropdown.vue'\nimport type { GrDropdownWidth } from '../GrDropdown/grDropdownStyles'\nimport type { UseFloatingPlacement } from '../../composables/useFloating'\n\nimport GrDropdownMenuEntries from './GrDropdownMenuEntries.vue'\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\n\nexport interface GrDropdownMenuProps {\n /** Размещение панели относительно триггера; переворот при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Меню не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Куда телепортировать панель (`body` по умолчанию). */\n /** Точечное переопределение точки монтирования; по умолчанию — общий портал. */\n teleportTo?: string | HTMLElement\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера. */\n contentClass?: string\n /**\n * Декларативное меню: пункты, группы и разделители массивом. Слот по\n * умолчанию сильнее — он для меню, которое из модели не собирается.\n */\n items?: GrDropdownMenuEntry[]\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n /**\n * Контролируемое состояние панели (`v-model:open`) — прокидывается в\n * `GrDropdown`. Без пропа меню ведёт себя само (uncontrolled).\n */\n open?: boolean\n}\n\nexport interface GrDropdownMenuEmits {\n /** Выбран пункт декларативного меню. */\n (e: 'select', item: GrDropdownMenuAction): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n teleportTo: undefined,\n closeOnContentClick: true,\n // Поле панели принадлежит панели. Гасить его отсюда своим `p-0` нельзя: оба\n // класса попадают в один атрибут с равной специфичностью, и победителя\n // выбирает порядок правил в сгенерированном CSS, а не разметка. Пункт вписан\n // в это поле собственным радиусом — см. `itemBaseClass`.\n contentClass: '',\n items: undefined,\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownMenuEmits>()\n\ndefineSlots<{\n /** Пункты меню. Слот-пропы прокидываются от `GrDropdown` как есть. */\n default?: (props: { close: () => void }) => any\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n}>()\n</script>\n\n<template>\n <GrDropdown\n data-gr-dropdown-menu\n :placement=\"placement\"\n :offset=\"offset\"\n :width=\"width\"\n :trigger=\"trigger\"\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n :disabled=\"disabled\"\n :teleport-to=\"teleportTo\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n :open=\"open\"\n @update:open=\"emit('update:open', $event)\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\">\n <GrDropdownMenuEntries :items=\"items\" @select=\"emit('select', $event)\" />\n </slot>\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n// Типы размещения и ширины — из владельца API, а не переобъявлением: расхождение\n// обнаружилось бы только рантаймом.\nimport type { GrDropdownTrigger } from '../GrDropdown/GrDropdown.vue'\nimport type { GrDropdownWidth } from '../GrDropdown/grDropdownStyles'\nimport type { UseFloatingPlacement } from '../../composables/useFloating'\n\nimport GrDropdownMenuEntries from './GrDropdownMenuEntries.vue'\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\n\nexport interface GrDropdownMenuProps {\n /** Размещение панели относительно триггера; переворот при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Меню не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Куда телепортировать панель (`body` по умолчанию). */\n /** Точечное переопределение точки монтирования; по умолчанию — общий портал. */\n teleportTo?: string | HTMLElement\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера. */\n contentClass?: string\n /**\n * Декларативное меню: пункты, группы и разделители массивом. Слот по\n * умолчанию сильнее — он для меню, которое из модели не собирается.\n */\n items?: GrDropdownMenuEntry[]\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n /**\n * Контролируемое состояние панели (`v-model:open`) — прокидывается в\n * `GrDropdown`. Без пропа меню ведёт себя само (uncontrolled).\n */\n open?: boolean\n}\n\nexport interface GrDropdownMenuEmits {\n /** Выбран пункт декларативного меню. */\n (e: 'select', item: GrDropdownMenuAction): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n teleportTo: undefined,\n closeOnContentClick: true,\n // Поле панели принадлежит панели. Гасить его отсюда своим `p-0` нельзя: оба\n // класса попадают в один атрибут с равной специфичностью, и победителя\n // выбирает порядок правил в сгенерированном CSS, а не разметка. Пункт вписан\n // в это поле собственным радиусом — см. `itemBaseClass`.\n contentClass: '',\n items: undefined,\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownMenuEmits>()\n\ndefineSlots<{\n /** Пункты меню. Слот-пропы прокидываются от `GrDropdown` как есть. */\n default?: (props: { close: () => void }) => any\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n}>()\n</script>\n\n<template>\n <GrDropdown\n data-gr-dropdown-menu\n :placement=\"placement\"\n :offset=\"offset\"\n :width=\"width\"\n :trigger=\"trigger\"\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n :disabled=\"disabled\"\n :teleport-to=\"teleportTo\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n :open=\"open\"\n @update:open=\"emit('update:open', $event)\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\">\n <GrDropdownMenuEntries :items=\"items\" @select=\"emit('select', $event)\" />\n </slot>\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport { alignClass, columnBaseClass, type GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\ndefineSlots<{\n /** Содержимое колонки меню. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-column\n role=\"none\"\n :class=\"[columnBaseClass, alignClass[align]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { alignClass, columnBaseClass, type GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n\ndefineSlots<{\n /** Содержимое колонки меню. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-column\n role=\"none\"\n :class=\"[columnBaseClass, alignClass[align]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { colsClass, columnsBaseClass, type GrDropdownMenuColumnsCount } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: GrDropdownMenuColumnsCount\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\ndefineSlots<{\n /** Колонки меню (`GrDropdownMenuColumn`). */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-columns\n role=\"none\"\n :class=\"[columnsBaseClass, colsClass[cols]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { colsClass, columnsBaseClass, type GrDropdownMenuColumnsCount } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: GrDropdownMenuColumnsCount\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n\ndefineSlots<{\n /** Колонки меню (`GrDropdownMenuColumn`). */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-columns\n role=\"none\"\n :class=\"[columnsBaseClass, colsClass[cols]]\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsFA,MAAM,OAAO;;uBAoBX,YA+Ba,oBAAA;IA9BX,yBAAA;IACC,WAAW,QAAA;IACX,QAAQ,QAAA;IACR,OAAO,QAAA;IACP,SAAS,QAAA;IACT,cAAY,QAAA;IACZ,eAAa,QAAA;IACb,UAAU,QAAA;IACV,eAAa,QAAA;IACb,0BAAwB,QAAA;IACxB,iBAAe,QAAA;IACf,MAAM,QAAA;IACN,iBAAW,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,eAAgB,MAAM;;IAE7B,SAAO,SAAE,cAAS,CAC3B,WAA0C,KAAA,QAAA,WAAA,eAAA,mBAAb,SAAS,CAAA,CAAA,CAAA,CAAA;IAG7B,SAAO,SAAE,cAAS,CAC3B,YASqB,4BAAA;KARlB,UAAU,QAAA;KACV,cAAY,QAAA;KACZ,iBAAe,QAAA;KACf,OAAK,eAAE,QAAA,SAAS;;4BAIV,CAFP,WAEO,KAAA,QAAA,WAAA,eAAA,mBAFO,SAAS,CAAA,SAEhB,CADL,YAAyE,+BAAA;MAAjD,OAAO,QAAA;MAAQ,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAW,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBEjH5E,mBAMM,OAAA;IALJ,gCAAA;IACA,MAAK;IACJ,OAAK,eAAA,CAAG,MAAA,eAAA,GAAiB,MAAA,UAAA,CAAU,CAAC,QAAA,MAAK,CAAA;OAE1C,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA;;;;;;;;;;;uBEPV,mBAMM,OAAA;IALJ,iCAAA;IACA,MAAK;IACJ,OAAK,eAAA,CAAG,MAAA,gBAAA,GAAkB,MAAA,SAAA,CAAS,CAAC,QAAA,KAAI,CAAA;OAEzC,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrDropdownMenuList-B33ZzwfB.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/menuModel.ts","../../../../src/components/GrDropdownMenu/GrDropdownMenuEntries.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuEntries.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { dividerClass, dividerInsetClass } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-divider\n role=\"separator\"\n :class=\"[dividerClass, inset ? dividerInsetClass : '']\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { dividerClass, dividerInsetClass } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-divider\n role=\"separator\"\n :class=\"[dividerClass, inset ? dividerInsetClass : '']\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nimport { headerClass, textAlignClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\n/**\n * Заголовок — подпись, а не пункт меню: `role=\"presentation\"` убирает его из\n * числа потомков `role=\"menu\"`. Имя группе он даёт через `aria-labelledby`\n * у `GrDropdownMenuGroup`.\n */\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\ndefineSlots<{\n /** Заголовок раздела меню вместо пропа `label`. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-gr-dropdown-menu-header\n role=\"presentation\"\n :class=\"[headerClass, textAlignClass[align], { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nimport { headerClass, textAlignClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\n/**\n * Заголовок — подпись, а не пункт меню: `role=\"presentation\"` убирает его из\n * числа потомков `role=\"menu\"`. Имя группе он даёт через `aria-labelledby`\n * у `GrDropdownMenuGroup`.\n */\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\ndefineSlots<{\n /** Заголовок раздела меню вместо пропа `label`. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-gr-dropdown-menu-header\n role=\"presentation\"\n :class=\"[headerClass, textAlignClass[align], { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useId } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport { dividersClass, listBaseClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst titleId = useId()\n// Имя группы читается диктором при входе в неё; без заголовка называть нечем.\nconst labelledBy = computed(() => (props.title ? titleId : undefined))\n\nconst itemsClass = computed(() => [\n listBaseClass,\n props.dividers ? dividersClass : '',\n].filter(Boolean).join(' '))\n\ndefineSlots<{\n /** Пункты группы. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-group\n role=\"group\"\n :aria-labelledby=\"labelledBy\"\n class=\"w-full\"\n >\n <GrDropdownMenuHeader\n v-if=\"title\"\n :id=\"titleId\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div role=\"none\" :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useId } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport { dividersClass, listBaseClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst titleId = useId()\n// Имя группы читается диктором при входе в неё; без заголовка называть нечем.\nconst labelledBy = computed(() => (props.title ? titleId : undefined))\n\nconst itemsClass = computed(() => [\n listBaseClass,\n props.dividers ? dividersClass : '',\n].filter(Boolean).join(' '))\n\ndefineSlots<{\n /** Пункты группы. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-group\n role=\"group\"\n :aria-labelledby=\"labelledBy\"\n class=\"w-full\"\n >\n <GrDropdownMenuHeader\n v-if=\"title\"\n :id=\"titleId\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div role=\"none\" :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\nimport IconCheck from '~icons/lucide/check'\n\nimport {\n grDropdownMenuItemClass,\n itemIndicatorClass,\n itemShortcutClass,\n type GrDropdownMenuItemAlign,\n type GrDropdownMenuItemVariant,\n} from './grDropdownMenuStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type { GrDropdownMenuItemAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Роль пункта. `menuitemcheckbox`/`menuitemradio` — пункты-переключатели: они\n * обязаны нести `aria-checked`, иначе AT прочитает их как обычные команды.\n */\nexport type GrDropdownMenuItemRole = 'menuitem' | 'menuitemcheckbox' | 'menuitemradio'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n /** Пункт-ссылка. У выключенного пункта не рендерится: ссылка осталась бы рабочей. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя. Осмысленно с `role=\"menuitemcheckbox|radio\"`. */\n checked?: boolean\n /** Иконка слева. Слот `#icon` сильнее. */\n icon?: Component\n /** Подпись сочетания клавиш справа. Слот `#shortcut` сильнее. */\n shortcut?: string\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n align: 'left',\n variant: 'default',\n role: 'menuitem',\n checked: undefined,\n icon: undefined,\n shortcut: undefined,\n})\n\nconst attrs = useAttrs()\n\n// Полиморфный корень: явный `as` сильнее всего, иначе `href` сам делает пункт\n// ссылкой — как у `GrButton`, чтобы не приходилось задавать `as=\"a\"` вручную.\nconst renderAs = computed<string | Component>(() => {\n if (props.as && props.as !== 'button')\n return props.as\n return props.href ? 'a' : 'button'\n})\n\nconst isNativeButton = computed(() => renderAs.value === 'button')\n\n// Выключенный пункт остаётся ссылкой, если оставить ему `href`: средняя кнопка и\n// контекстное меню браузера обойдут любой перехват клика (тот же приём в `GrButton`).\nconst resolvedHref = computed(() => (props.disabled ? undefined : props.href))\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() =>\n props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined),\n)\n// Отметка занимает место всегда, когда пункт переключаемый: иначе строки\n// «включено» и «выключено» разъезжаются по горизонтали.\nconst isCheckable = computed(() => props.role !== 'menuitem')\n\nconst className = computed(() => grDropdownMenuItemClass({\n align: props.align,\n variant: props.variant,\n disabled: props.disabled,\n}))\n\n/**\n * Roving tabindex паттерна menu: табируемым остаётся триггер, а внутри панели\n * фокусом распоряжаются стрелки (`GrDropdown` наводит его программно). Без\n * этого `Tab` ходил бы по пунктам, и меню было бы списком кнопок, а не меню.\n *\n * Выключённый пункт из обхода **не** выпадает: `aria-disabled` вместо нативного\n * `disabled` оставляет его фокусируемым, и пользователь узнаёт, что действие\n * существует, но сейчас недоступно (рекомендация WAI-ARIA APG).\n */\nconst resolvedTabindex = computed(() => (attrs.tabindex as number | string | undefined) ?? -1)\n\nfunction onClickCapture(e: MouseEvent): void {\n if (!props.disabled)\n return\n\n e.preventDefault()\n // `stopImmediatePropagation`, а не `stopPropagation`: обработчик, навешенный\n // на сам пункт через `v-bind=\"attrs\"`, живёт на этом же элементе, и обычная\n // остановка всплытия его не отменяет.\n e.stopImmediatePropagation()\n}\n\ndefineSlots<{\n /** Подпись пункта вместо пропа `label`. */\n default?: () => any\n /** Иконка перед подписью. */\n icon?: () => any\n /** Сочетание клавиш справа — обычно `GrKbd`. */\n shortcut?: () => any\n}>()\n\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n v-bind=\"attrs\"\n data-gr-dropdown-menu-item\n :role=\"role\"\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :href=\"resolvedHref\"\n :target=\"resolvedHref ? resolvedTarget : undefined\"\n :rel=\"resolvedHref ? resolvedRel : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-checked=\"isCheckable ? (checked ? 'true' : 'false') : undefined\"\n :tabindex=\"resolvedTabindex\"\n @click.capture=\"onClickCapture\"\n >\n <span\n v-if=\"isCheckable\"\n data-gr-dropdown-menu-item-indicator\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"checked\" :class=\"itemIndicatorClass\" />\n </span>\n\n <slot name=\"icon\">\n <component\n :is=\"icon\"\n v-if=\"icon\"\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n />\n </slot>\n\n <slot />\n\n <slot name=\"shortcut\">\n <span v-if=\"shortcut\" data-gr-dropdown-menu-item-shortcut :class=\"itemShortcutClass\">{{ shortcut }}</span>\n </slot>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\nimport IconCheck from '~icons/lucide/check'\n\nimport {\n grDropdownMenuItemClass,\n itemIndicatorClass,\n itemShortcutClass,\n type GrDropdownMenuItemAlign,\n type GrDropdownMenuItemVariant,\n} from './grDropdownMenuStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type { GrDropdownMenuItemAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Роль пункта. `menuitemcheckbox`/`menuitemradio` — пункты-переключатели: они\n * обязаны нести `aria-checked`, иначе AT прочитает их как обычные команды.\n */\nexport type GrDropdownMenuItemRole = 'menuitem' | 'menuitemcheckbox' | 'menuitemradio'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n /** Пункт-ссылка. У выключенного пункта не рендерится: ссылка осталась бы рабочей. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя. Осмысленно с `role=\"menuitemcheckbox|radio\"`. */\n checked?: boolean\n /** Иконка слева. Слот `#icon` сильнее. */\n icon?: Component\n /** Подпись сочетания клавиш справа. Слот `#shortcut` сильнее. */\n shortcut?: string\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n align: 'left',\n variant: 'default',\n role: 'menuitem',\n checked: undefined,\n icon: undefined,\n shortcut: undefined,\n})\n\nconst attrs = useAttrs()\n\n// Полиморфный корень: явный `as` сильнее всего, иначе `href` сам делает пункт\n// ссылкой — как у `GrButton`, чтобы не приходилось задавать `as=\"a\"` вручную.\nconst renderAs = computed<string | Component>(() => {\n if (props.as && props.as !== 'button')\n return props.as\n return props.href ? 'a' : 'button'\n})\n\nconst isNativeButton = computed(() => renderAs.value === 'button')\n\n// Выключенный пункт остаётся ссылкой, если оставить ему `href`: средняя кнопка и\n// контекстное меню браузера обойдут любой перехват клика (тот же приём в `GrButton`).\nconst resolvedHref = computed(() => (props.disabled ? undefined : props.href))\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() =>\n props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined),\n)\n// Отметка занимает место всегда, когда пункт переключаемый: иначе строки\n// «включено» и «выключено» разъезжаются по горизонтали.\nconst isCheckable = computed(() => props.role !== 'menuitem')\n\nconst className = computed(() => grDropdownMenuItemClass({\n align: props.align,\n variant: props.variant,\n disabled: props.disabled,\n}))\n\n/**\n * Roving tabindex паттерна menu: табируемым остаётся триггер, а внутри панели\n * фокусом распоряжаются стрелки (`GrDropdown` наводит его программно). Без\n * этого `Tab` ходил бы по пунктам, и меню было бы списком кнопок, а не меню.\n *\n * Выключённый пункт из обхода **не** выпадает: `aria-disabled` вместо нативного\n * `disabled` оставляет его фокусируемым, и пользователь узнаёт, что действие\n * существует, но сейчас недоступно (рекомендация WAI-ARIA APG).\n */\nconst resolvedTabindex = computed(() => (attrs.tabindex as number | string | undefined) ?? -1)\n\nfunction onClickCapture(e: MouseEvent): void {\n if (!props.disabled)\n return\n\n e.preventDefault()\n // `stopImmediatePropagation`, а не `stopPropagation`: обработчик, навешенный\n // на сам пункт через `v-bind=\"attrs\"`, живёт на этом же элементе, и обычная\n // остановка всплытия его не отменяет.\n e.stopImmediatePropagation()\n}\n\ndefineSlots<{\n /** Подпись пункта вместо пропа `label`. */\n default?: () => any\n /** Иконка перед подписью. */\n icon?: () => any\n /** Сочетание клавиш справа — обычно `GrKbd`. */\n shortcut?: () => any\n}>()\n\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n v-bind=\"attrs\"\n data-gr-dropdown-menu-item\n :role=\"role\"\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :href=\"resolvedHref\"\n :target=\"resolvedHref ? resolvedTarget : undefined\"\n :rel=\"resolvedHref ? resolvedRel : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-checked=\"isCheckable ? (checked ? 'true' : 'false') : undefined\"\n :tabindex=\"resolvedTabindex\"\n @click.capture=\"onClickCapture\"\n >\n <span\n v-if=\"isCheckable\"\n data-gr-dropdown-menu-item-indicator\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"checked\" :class=\"itemIndicatorClass\" />\n </span>\n\n <slot name=\"icon\">\n <component\n :is=\"icon\"\n v-if=\"icon\"\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n />\n </slot>\n\n <slot />\n\n <slot name=\"shortcut\">\n <span v-if=\"shortcut\" data-gr-dropdown-menu-item-shortcut :class=\"itemShortcutClass\">{{ shortcut }}</span>\n </slot>\n </component>\n</template>\n","import type { Component } from 'vue'\n\nimport type { GrDropdownMenuItemAlign, GrDropdownMenuItemRole } from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuHeaderAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Декларативная модель меню.\n *\n * Композиция из подкомпонентов остаётся основным способом — она нужна там, где\n * пункт нестандартный. Но девять меню из десяти однотипны («иконка, подпись,\n * шорткат, иногда разделитель»), и собирать их из пяти компонентов вручную\n * значит каждый раз заново решать, где `role`, где `disabled`, где ключ.\n */\nexport interface GrDropdownMenuAction {\n /** Ключ пункта — он же приходит в `select`. */\n key: string\n label: string\n icon?: Component\n shortcut?: string\n disabled?: boolean\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя для `menuitemcheckbox`/`menuitemradio`. */\n checked?: boolean\n /** Пункт-ссылка: рендерится как `<a>` с этим `href`. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n /**\n * Чем рендерить пункт: тег или компонент роутера.\n *\n * Без него пункт-ссылка из `items` остаётся обычным `<a>`, то есть в\n * SPA переход идёт перезагрузкой страницы — а обойти это в модели нечем:\n * `itemProps` внутренняя, слота на пункт нет. Проп есть у самого\n * `GrDropdownMenuItem` и у соседей по кольцу (`GrLink`, `GrBreadcrumbs`,\n * `GrSidebarItem`), из этого ряда выпадала только модель меню.\n */\n as?: string | Component\n /** Выравнивание содержимого пункта. */\n align?: GrDropdownMenuItemAlign\n}\n\nexport interface GrDropdownMenuSeparator {\n type: 'divider'\n inset?: boolean\n}\n\nexport interface GrDropdownMenuSection {\n type: 'group'\n title?: string\n /** Выравнивание заголовка группы. */\n titleAlign?: GrDropdownMenuHeaderAlign\n /** Разделители между пунктами группы. */\n dividers?: boolean\n /** Заголовок капсом. */\n uppercase?: boolean\n items: GrDropdownMenuAction[]\n}\n\nexport type GrDropdownMenuEntry = GrDropdownMenuAction | GrDropdownMenuSeparator | GrDropdownMenuSection\n\nexport function isMenuSeparator(entry: GrDropdownMenuEntry): entry is GrDropdownMenuSeparator {\n return 'type' in entry && entry.type === 'divider'\n}\n\nexport function isMenuSection(entry: GrDropdownMenuEntry): entry is GrDropdownMenuSection {\n return 'type' in entry && entry.type === 'group'\n}\n\nexport function isMenuAction(entry: GrDropdownMenuEntry): entry is GrDropdownMenuAction {\n return !isMenuSeparator(entry) && !isMenuSection(entry)\n}\n","<script setup lang=\"ts\">\n/**\n * Рендер декларативной модели меню — без обёртки списка: её ставит потребитель,\n * потому что `dividers`/`borderTop` принадлежат конкретному меню, а не модели.\n *\n * Вынесено из `GrDropdownMenu` ради `GrContextMenu`: модель у них общая, и\n * вторая копия цикла разошлась бы с первой при первом же новом поле пункта.\n */\nimport GrDropdownMenuDivider from './GrDropdownMenuDivider.vue'\nimport GrDropdownMenuGroup from './GrDropdownMenuGroup.vue'\nimport GrDropdownMenuItem from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\nimport { isMenuAction, isMenuSection, isMenuSeparator } from './menuModel'\n\nexport interface GrDropdownMenuEntriesProps {\n items?: GrDropdownMenuEntry[]\n}\n\nexport interface GrDropdownMenuEntriesEmits {\n (e: 'select', item: GrDropdownMenuAction): void\n}\n\ndefineProps<GrDropdownMenuEntriesProps>()\n\nconst emit = defineEmits<GrDropdownMenuEntriesEmits>()\n\nfunction itemProps(item: GrDropdownMenuAction): Record<string, unknown> {\n return {\n href: item.href,\n target: item.target,\n rel: item.rel,\n external: item.external,\n disabled: item.disabled,\n variant: item.variant,\n role: item.role,\n checked: item.checked,\n icon: item.icon,\n shortcut: item.shortcut,\n as: item.as,\n align: item.align,\n }\n}\n\nfunction onSelect(item: GrDropdownMenuAction): void {\n if (item.disabled)\n return\n\n emit('select', item)\n}\n</script>\n\n<template>\n <template v-for=\"(entry, index) in items ?? []\">\n <GrDropdownMenuDivider\n v-if=\"isMenuSeparator(entry)\"\n :key=\"`divider-${index}`\"\n :inset=\"entry.inset\"\n />\n\n <GrDropdownMenuGroup\n v-else-if=\"isMenuSection(entry)\"\n :key=\"`group-${entry.title ?? index}`\"\n :title=\"entry.title\"\n :title-align=\"entry.titleAlign\"\n :dividers=\"entry.dividers\"\n :uppercase=\"entry.uppercase\"\n >\n <GrDropdownMenuItem\n v-for=\"item in entry.items\"\n :key=\"item.key\"\n v-bind=\"itemProps(item)\"\n @click=\"onSelect(item)\"\n >\n {{ item.label }}\n </GrDropdownMenuItem>\n </GrDropdownMenuGroup>\n\n <GrDropdownMenuItem\n v-else-if=\"isMenuAction(entry)\"\n :key=\"entry.key\"\n v-bind=\"itemProps(entry)\"\n @click=\"onSelect(entry)\"\n >\n {{ entry.label }}\n </GrDropdownMenuItem>\n </template>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Рендер декларативной модели меню — без обёртки списка: её ставит потребитель,\n * потому что `dividers`/`borderTop` принадлежат конкретному меню, а не модели.\n *\n * Вынесено из `GrDropdownMenu` ради `GrContextMenu`: модель у них общая, и\n * вторая копия цикла разошлась бы с первой при первом же новом поле пункта.\n */\nimport GrDropdownMenuDivider from './GrDropdownMenuDivider.vue'\nimport GrDropdownMenuGroup from './GrDropdownMenuGroup.vue'\nimport GrDropdownMenuItem from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\nimport { isMenuAction, isMenuSection, isMenuSeparator } from './menuModel'\n\nexport interface GrDropdownMenuEntriesProps {\n items?: GrDropdownMenuEntry[]\n}\n\nexport interface GrDropdownMenuEntriesEmits {\n (e: 'select', item: GrDropdownMenuAction): void\n}\n\ndefineProps<GrDropdownMenuEntriesProps>()\n\nconst emit = defineEmits<GrDropdownMenuEntriesEmits>()\n\nfunction itemProps(item: GrDropdownMenuAction): Record<string, unknown> {\n return {\n href: item.href,\n target: item.target,\n rel: item.rel,\n external: item.external,\n disabled: item.disabled,\n variant: item.variant,\n role: item.role,\n checked: item.checked,\n icon: item.icon,\n shortcut: item.shortcut,\n as: item.as,\n align: item.align,\n }\n}\n\nfunction onSelect(item: GrDropdownMenuAction): void {\n if (item.disabled)\n return\n\n emit('select', item)\n}\n</script>\n\n<template>\n <template v-for=\"(entry, index) in items ?? []\">\n <GrDropdownMenuDivider\n v-if=\"isMenuSeparator(entry)\"\n :key=\"`divider-${index}`\"\n :inset=\"entry.inset\"\n />\n\n <GrDropdownMenuGroup\n v-else-if=\"isMenuSection(entry)\"\n :key=\"`group-${entry.title ?? index}`\"\n :title=\"entry.title\"\n :title-align=\"entry.titleAlign\"\n :dividers=\"entry.dividers\"\n :uppercase=\"entry.uppercase\"\n >\n <GrDropdownMenuItem\n v-for=\"item in entry.items\"\n :key=\"item.key\"\n v-bind=\"itemProps(item)\"\n @click=\"onSelect(item)\"\n >\n {{ item.label }}\n </GrDropdownMenuItem>\n </GrDropdownMenuGroup>\n\n <GrDropdownMenuItem\n v-else-if=\"isMenuAction(entry)\"\n :key=\"entry.key\"\n v-bind=\"itemProps(entry)\"\n @click=\"onSelect(entry)\"\n >\n {{ entry.label }}\n </GrDropdownMenuItem>\n </template>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { grDropdownMenuListClass } from './grDropdownMenuStyles'\n\n/**\n * `role=\"none\"` на обёртке обязателен: `role=\"menu\"` у панели объявляет своих\n * потомков презентационными, и любой div между панелью и пунктом ломает\n * `aria-required-children`, а пункты теряют принадлежность к меню.\n */\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => grDropdownMenuListClass({\n dividers: props.dividers,\n borderTop: props.borderTop,\n borderBottom: props.borderBottom,\n}))\n\ndefineSlots<{\n /** Пункты списка меню. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-list\n role=\"none\"\n :class=\"className\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { grDropdownMenuListClass } from './grDropdownMenuStyles'\n\n/**\n * `role=\"none\"` на обёртке обязателен: `role=\"menu\"` у панели объявляет своих\n * потомков презентационными, и любой div между панелью и пунктом ломает\n * `aria-required-children`, а пункты теряют принадлежность к меню.\n */\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => grDropdownMenuListClass({\n dividers: props.dividers,\n borderTop: props.borderTop,\n borderBottom: props.borderBottom,\n}))\n\ndefineSlots<{\n /** Пункты списка меню. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-list\n role=\"none\"\n :class=\"className\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"GrDropdownMenuList-B33ZzwfB.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/menuModel.ts","../../../../src/components/GrDropdownMenu/GrDropdownMenuEntries.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuEntries.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { dividerClass, dividerInsetClass } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-divider\n role=\"separator\"\n :class=\"[dividerClass, inset ? dividerInsetClass : '']\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { dividerClass, dividerInsetClass } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-divider\n role=\"separator\"\n :class=\"[dividerClass, inset ? dividerInsetClass : '']\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nimport { headerClass, textAlignClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\n/**\n * Заголовок — подпись, а не пункт меню: `role=\"presentation\"` убирает его из\n * числа потомков `role=\"menu\"`. Имя группе он даёт через `aria-labelledby`\n * у `GrDropdownMenuGroup`.\n */\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\ndefineSlots<{\n /** Заголовок раздела меню вместо пропа `label`. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-gr-dropdown-menu-header\n role=\"presentation\"\n :class=\"[headerClass, textAlignClass[align], { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nimport { headerClass, textAlignClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\n/**\n * Заголовок — подпись, а не пункт меню: `role=\"presentation\"` убирает его из\n * числа потомков `role=\"menu\"`. Имя группе он даёт через `aria-labelledby`\n * у `GrDropdownMenuGroup`.\n */\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n\ndefineSlots<{\n /** Заголовок раздела меню вместо пропа `label`. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-gr-dropdown-menu-header\n role=\"presentation\"\n :class=\"[headerClass, textAlignClass[align], { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useId } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport { dividersClass, listBaseClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst titleId = useId()\n// Имя группы читается диктором при входе в неё; без заголовка называть нечем.\nconst labelledBy = computed(() => (props.title ? titleId : undefined))\n\nconst itemsClass = computed(() => [\n listBaseClass,\n props.dividers ? dividersClass : '',\n].filter(Boolean).join(' '))\n\ndefineSlots<{\n /** Пункты группы. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-group\n role=\"group\"\n :aria-labelledby=\"labelledBy\"\n class=\"w-full\"\n >\n <GrDropdownMenuHeader\n v-if=\"title\"\n :id=\"titleId\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div role=\"none\" :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useId } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport { dividersClass, listBaseClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst titleId = useId()\n// Имя группы читается диктором при входе в неё; без заголовка называть нечем.\nconst labelledBy = computed(() => (props.title ? titleId : undefined))\n\nconst itemsClass = computed(() => [\n listBaseClass,\n props.dividers ? dividersClass : '',\n].filter(Boolean).join(' '))\n\ndefineSlots<{\n /** Пункты группы. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-group\n role=\"group\"\n :aria-labelledby=\"labelledBy\"\n class=\"w-full\"\n >\n <GrDropdownMenuHeader\n v-if=\"title\"\n :id=\"titleId\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div role=\"none\" :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\nimport IconCheck from '~icons/lucide/check'\n\nimport {\n grDropdownMenuItemClass,\n itemIndicatorClass,\n itemShortcutClass,\n type GrDropdownMenuItemAlign,\n type GrDropdownMenuItemVariant,\n} from './grDropdownMenuStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type { GrDropdownMenuItemAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Роль пункта. `menuitemcheckbox`/`menuitemradio` — пункты-переключатели: они\n * обязаны нести `aria-checked`, иначе AT прочитает их как обычные команды.\n */\nexport type GrDropdownMenuItemRole = 'menuitem' | 'menuitemcheckbox' | 'menuitemradio'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n /** Пункт-ссылка. У выключенного пункта не рендерится: ссылка осталась бы рабочей. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя. Осмысленно с `role=\"menuitemcheckbox|radio\"`. */\n checked?: boolean\n /** Иконка слева. Слот `#icon` сильнее. */\n icon?: Component\n /** Подпись сочетания клавиш справа. Слот `#shortcut` сильнее. */\n shortcut?: string\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n align: 'left',\n variant: 'default',\n role: 'menuitem',\n checked: undefined,\n icon: undefined,\n shortcut: undefined,\n})\n\nconst attrs = useAttrs()\n\n// Полиморфный корень: явный `as` сильнее всего, иначе `href` сам делает пункт\n// ссылкой — как у `GrButton`, чтобы не приходилось задавать `as=\"a\"` вручную.\nconst renderAs = computed<string | Component>(() => {\n if (props.as && props.as !== 'button')\n return props.as\n return props.href ? 'a' : 'button'\n})\n\nconst isNativeButton = computed(() => renderAs.value === 'button')\n\n// Выключенный пункт остаётся ссылкой, если оставить ему `href`: средняя кнопка и\n// контекстное меню браузера обойдут любой перехват клика (тот же приём в `GrButton`).\nconst resolvedHref = computed(() => (props.disabled ? undefined : props.href))\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() =>\n props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined),\n)\n// Отметка занимает место всегда, когда пункт переключаемый: иначе строки\n// «включено» и «выключено» разъезжаются по горизонтали.\nconst isCheckable = computed(() => props.role !== 'menuitem')\n\nconst className = computed(() => grDropdownMenuItemClass({\n align: props.align,\n variant: props.variant,\n disabled: props.disabled,\n}))\n\n/**\n * Roving tabindex паттерна menu: табируемым остаётся триггер, а внутри панели\n * фокусом распоряжаются стрелки (`GrDropdown` наводит его программно). Без\n * этого `Tab` ходил бы по пунктам, и меню было бы списком кнопок, а не меню.\n *\n * Выключённый пункт из обхода **не** выпадает: `aria-disabled` вместо нативного\n * `disabled` оставляет его фокусируемым, и пользователь узнаёт, что действие\n * существует, но сейчас недоступно (рекомендация WAI-ARIA APG).\n */\nconst resolvedTabindex = computed(() => (attrs.tabindex as number | string | undefined) ?? -1)\n\nfunction onClickCapture(e: MouseEvent): void {\n if (!props.disabled)\n return\n\n e.preventDefault()\n // `stopImmediatePropagation`, а не `stopPropagation`: обработчик, навешенный\n // на сам пункт через `v-bind=\"attrs\"`, живёт на этом же элементе, и обычная\n // остановка всплытия его не отменяет.\n e.stopImmediatePropagation()\n}\n\ndefineSlots<{\n /** Подпись пункта вместо пропа `label`. */\n default?: () => any\n /** Иконка перед подписью. */\n icon?: () => any\n /** Сочетание клавиш справа — обычно `GrKbd`. */\n shortcut?: () => any\n}>()\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n v-bind=\"attrs\"\n data-gr-dropdown-menu-item\n :role=\"role\"\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :href=\"resolvedHref\"\n :target=\"resolvedHref ? resolvedTarget : undefined\"\n :rel=\"resolvedHref ? resolvedRel : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-checked=\"isCheckable ? (checked ? 'true' : 'false') : undefined\"\n :tabindex=\"resolvedTabindex\"\n @click.capture=\"onClickCapture\"\n >\n <span\n v-if=\"isCheckable\"\n data-gr-dropdown-menu-item-indicator\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"checked\" :class=\"itemIndicatorClass\" />\n </span>\n\n <slot name=\"icon\">\n <component\n :is=\"icon\"\n v-if=\"icon\"\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n />\n </slot>\n\n <slot />\n\n <slot name=\"shortcut\">\n <span v-if=\"shortcut\" data-gr-dropdown-menu-item-shortcut :class=\"itemShortcutClass\">{{ shortcut }}</span>\n </slot>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\nimport IconCheck from '~icons/lucide/check'\n\nimport {\n grDropdownMenuItemClass,\n itemIndicatorClass,\n itemShortcutClass,\n type GrDropdownMenuItemAlign,\n type GrDropdownMenuItemVariant,\n} from './grDropdownMenuStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type { GrDropdownMenuItemAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Роль пункта. `menuitemcheckbox`/`menuitemradio` — пункты-переключатели: они\n * обязаны нести `aria-checked`, иначе AT прочитает их как обычные команды.\n */\nexport type GrDropdownMenuItemRole = 'menuitem' | 'menuitemcheckbox' | 'menuitemradio'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n /** Пункт-ссылка. У выключенного пункта не рендерится: ссылка осталась бы рабочей. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя. Осмысленно с `role=\"menuitemcheckbox|radio\"`. */\n checked?: boolean\n /** Иконка слева. Слот `#icon` сильнее. */\n icon?: Component\n /** Подпись сочетания клавиш справа. Слот `#shortcut` сильнее. */\n shortcut?: string\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n align: 'left',\n variant: 'default',\n role: 'menuitem',\n checked: undefined,\n icon: undefined,\n shortcut: undefined,\n})\n\nconst attrs = useAttrs()\n\n// Полиморфный корень: явный `as` сильнее всего, иначе `href` сам делает пункт\n// ссылкой — как у `GrButton`, чтобы не приходилось задавать `as=\"a\"` вручную.\nconst renderAs = computed<string | Component>(() => {\n if (props.as && props.as !== 'button')\n return props.as\n return props.href ? 'a' : 'button'\n})\n\nconst isNativeButton = computed(() => renderAs.value === 'button')\n\n// Выключенный пункт остаётся ссылкой, если оставить ему `href`: средняя кнопка и\n// контекстное меню браузера обойдут любой перехват клика (тот же приём в `GrButton`).\nconst resolvedHref = computed(() => (props.disabled ? undefined : props.href))\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() =>\n props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined),\n)\n// Отметка занимает место всегда, когда пункт переключаемый: иначе строки\n// «включено» и «выключено» разъезжаются по горизонтали.\nconst isCheckable = computed(() => props.role !== 'menuitem')\n\nconst className = computed(() => grDropdownMenuItemClass({\n align: props.align,\n variant: props.variant,\n disabled: props.disabled,\n}))\n\n/**\n * Roving tabindex паттерна menu: табируемым остаётся триггер, а внутри панели\n * фокусом распоряжаются стрелки (`GrDropdown` наводит его программно). Без\n * этого `Tab` ходил бы по пунктам, и меню было бы списком кнопок, а не меню.\n *\n * Выключённый пункт из обхода **не** выпадает: `aria-disabled` вместо нативного\n * `disabled` оставляет его фокусируемым, и пользователь узнаёт, что действие\n * существует, но сейчас недоступно (рекомендация WAI-ARIA APG).\n */\nconst resolvedTabindex = computed(() => (attrs.tabindex as number | string | undefined) ?? -1)\n\nfunction onClickCapture(e: MouseEvent): void {\n if (!props.disabled)\n return\n\n e.preventDefault()\n // `stopImmediatePropagation`, а не `stopPropagation`: обработчик, навешенный\n // на сам пункт через `v-bind=\"attrs\"`, живёт на этом же элементе, и обычная\n // остановка всплытия его не отменяет.\n e.stopImmediatePropagation()\n}\n\ndefineSlots<{\n /** Подпись пункта вместо пропа `label`. */\n default?: () => any\n /** Иконка перед подписью. */\n icon?: () => any\n /** Сочетание клавиш справа — обычно `GrKbd`. */\n shortcut?: () => any\n}>()\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n v-bind=\"attrs\"\n data-gr-dropdown-menu-item\n :role=\"role\"\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :href=\"resolvedHref\"\n :target=\"resolvedHref ? resolvedTarget : undefined\"\n :rel=\"resolvedHref ? resolvedRel : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-checked=\"isCheckable ? (checked ? 'true' : 'false') : undefined\"\n :tabindex=\"resolvedTabindex\"\n @click.capture=\"onClickCapture\"\n >\n <span\n v-if=\"isCheckable\"\n data-gr-dropdown-menu-item-indicator\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"checked\" :class=\"itemIndicatorClass\" />\n </span>\n\n <slot name=\"icon\">\n <component\n :is=\"icon\"\n v-if=\"icon\"\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n />\n </slot>\n\n <slot />\n\n <slot name=\"shortcut\">\n <span v-if=\"shortcut\" data-gr-dropdown-menu-item-shortcut :class=\"itemShortcutClass\">{{ shortcut }}</span>\n </slot>\n </component>\n</template>\n","import type { Component } from 'vue'\n\nimport type { GrDropdownMenuItemAlign, GrDropdownMenuItemRole } from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuHeaderAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Декларативная модель меню.\n *\n * Композиция из подкомпонентов остаётся основным способом — она нужна там, где\n * пункт нестандартный. Но девять меню из десяти однотипны («иконка, подпись,\n * шорткат, иногда разделитель»), и собирать их из пяти компонентов вручную\n * значит каждый раз заново решать, где `role`, где `disabled`, где ключ.\n */\nexport interface GrDropdownMenuAction {\n /** Ключ пункта — он же приходит в `select`. */\n key: string\n label: string\n icon?: Component\n shortcut?: string\n disabled?: boolean\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя для `menuitemcheckbox`/`menuitemradio`. */\n checked?: boolean\n /** Пункт-ссылка: рендерится как `<a>` с этим `href`. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n /**\n * Чем рендерить пункт: тег или компонент роутера.\n *\n * Без него пункт-ссылка из `items` остаётся обычным `<a>`, то есть в\n * SPA переход идёт перезагрузкой страницы — а обойти это в модели нечем:\n * `itemProps` внутренняя, слота на пункт нет. Проп есть у самого\n * `GrDropdownMenuItem` и у соседей по кольцу (`GrLink`, `GrBreadcrumbs`,\n * `GrSidebarItem`), из этого ряда выпадала только модель меню.\n */\n as?: string | Component\n /** Выравнивание содержимого пункта. */\n align?: GrDropdownMenuItemAlign\n}\n\nexport interface GrDropdownMenuSeparator {\n type: 'divider'\n inset?: boolean\n}\n\nexport interface GrDropdownMenuSection {\n type: 'group'\n title?: string\n /** Выравнивание заголовка группы. */\n titleAlign?: GrDropdownMenuHeaderAlign\n /** Разделители между пунктами группы. */\n dividers?: boolean\n /** Заголовок капсом. */\n uppercase?: boolean\n items: GrDropdownMenuAction[]\n}\n\nexport type GrDropdownMenuEntry = GrDropdownMenuAction | GrDropdownMenuSeparator | GrDropdownMenuSection\n\nexport function isMenuSeparator(entry: GrDropdownMenuEntry): entry is GrDropdownMenuSeparator {\n return 'type' in entry && entry.type === 'divider'\n}\n\nexport function isMenuSection(entry: GrDropdownMenuEntry): entry is GrDropdownMenuSection {\n return 'type' in entry && entry.type === 'group'\n}\n\nexport function isMenuAction(entry: GrDropdownMenuEntry): entry is GrDropdownMenuAction {\n return !isMenuSeparator(entry) && !isMenuSection(entry)\n}\n","<script setup lang=\"ts\">\n/**\n * Рендер декларативной модели меню — без обёртки списка: её ставит потребитель,\n * потому что `dividers`/`borderTop` принадлежат конкретному меню, а не модели.\n *\n * Вынесено из `GrDropdownMenu` ради `GrContextMenu`: модель у них общая, и\n * вторая копия цикла разошлась бы с первой при первом же новом поле пункта.\n */\nimport GrDropdownMenuDivider from './GrDropdownMenuDivider.vue'\nimport GrDropdownMenuGroup from './GrDropdownMenuGroup.vue'\nimport GrDropdownMenuItem from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\nimport { isMenuAction, isMenuSection, isMenuSeparator } from './menuModel'\n\nexport interface GrDropdownMenuEntriesProps {\n items?: GrDropdownMenuEntry[]\n}\n\nexport interface GrDropdownMenuEntriesEmits {\n (e: 'select', item: GrDropdownMenuAction): void\n}\n\ndefineProps<GrDropdownMenuEntriesProps>()\n\nconst emit = defineEmits<GrDropdownMenuEntriesEmits>()\n\nfunction itemProps(item: GrDropdownMenuAction): Record<string, unknown> {\n return {\n href: item.href,\n target: item.target,\n rel: item.rel,\n external: item.external,\n disabled: item.disabled,\n variant: item.variant,\n role: item.role,\n checked: item.checked,\n icon: item.icon,\n shortcut: item.shortcut,\n as: item.as,\n align: item.align,\n }\n}\n\nfunction onSelect(item: GrDropdownMenuAction): void {\n if (item.disabled)\n return\n\n emit('select', item)\n}\n</script>\n\n<template>\n <template v-for=\"(entry, index) in items ?? []\">\n <GrDropdownMenuDivider\n v-if=\"isMenuSeparator(entry)\"\n :key=\"`divider-${index}`\"\n :inset=\"entry.inset\"\n />\n\n <GrDropdownMenuGroup\n v-else-if=\"isMenuSection(entry)\"\n :key=\"`group-${entry.title ?? index}`\"\n :title=\"entry.title\"\n :title-align=\"entry.titleAlign\"\n :dividers=\"entry.dividers\"\n :uppercase=\"entry.uppercase\"\n >\n <GrDropdownMenuItem\n v-for=\"item in entry.items\"\n :key=\"item.key\"\n v-bind=\"itemProps(item)\"\n @click=\"onSelect(item)\"\n >\n {{ item.label }}\n </GrDropdownMenuItem>\n </GrDropdownMenuGroup>\n\n <GrDropdownMenuItem\n v-else-if=\"isMenuAction(entry)\"\n :key=\"entry.key\"\n v-bind=\"itemProps(entry)\"\n @click=\"onSelect(entry)\"\n >\n {{ entry.label }}\n </GrDropdownMenuItem>\n </template>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Рендер декларативной модели меню — без обёртки списка: её ставит потребитель,\n * потому что `dividers`/`borderTop` принадлежат конкретному меню, а не модели.\n *\n * Вынесено из `GrDropdownMenu` ради `GrContextMenu`: модель у них общая, и\n * вторая копия цикла разошлась бы с первой при первом же новом поле пункта.\n */\nimport GrDropdownMenuDivider from './GrDropdownMenuDivider.vue'\nimport GrDropdownMenuGroup from './GrDropdownMenuGroup.vue'\nimport GrDropdownMenuItem from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\nimport { isMenuAction, isMenuSection, isMenuSeparator } from './menuModel'\n\nexport interface GrDropdownMenuEntriesProps {\n items?: GrDropdownMenuEntry[]\n}\n\nexport interface GrDropdownMenuEntriesEmits {\n (e: 'select', item: GrDropdownMenuAction): void\n}\n\ndefineProps<GrDropdownMenuEntriesProps>()\n\nconst emit = defineEmits<GrDropdownMenuEntriesEmits>()\n\nfunction itemProps(item: GrDropdownMenuAction): Record<string, unknown> {\n return {\n href: item.href,\n target: item.target,\n rel: item.rel,\n external: item.external,\n disabled: item.disabled,\n variant: item.variant,\n role: item.role,\n checked: item.checked,\n icon: item.icon,\n shortcut: item.shortcut,\n as: item.as,\n align: item.align,\n }\n}\n\nfunction onSelect(item: GrDropdownMenuAction): void {\n if (item.disabled)\n return\n\n emit('select', item)\n}\n</script>\n\n<template>\n <template v-for=\"(entry, index) in items ?? []\">\n <GrDropdownMenuDivider\n v-if=\"isMenuSeparator(entry)\"\n :key=\"`divider-${index}`\"\n :inset=\"entry.inset\"\n />\n\n <GrDropdownMenuGroup\n v-else-if=\"isMenuSection(entry)\"\n :key=\"`group-${entry.title ?? index}`\"\n :title=\"entry.title\"\n :title-align=\"entry.titleAlign\"\n :dividers=\"entry.dividers\"\n :uppercase=\"entry.uppercase\"\n >\n <GrDropdownMenuItem\n v-for=\"item in entry.items\"\n :key=\"item.key\"\n v-bind=\"itemProps(item)\"\n @click=\"onSelect(item)\"\n >\n {{ item.label }}\n </GrDropdownMenuItem>\n </GrDropdownMenuGroup>\n\n <GrDropdownMenuItem\n v-else-if=\"isMenuAction(entry)\"\n :key=\"entry.key\"\n v-bind=\"itemProps(entry)\"\n @click=\"onSelect(entry)\"\n >\n {{ entry.label }}\n </GrDropdownMenuItem>\n </template>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { grDropdownMenuListClass } from './grDropdownMenuStyles'\n\n/**\n * `role=\"none\"` на обёртке обязателен: `role=\"menu\"` у панели объявляет своих\n * потомков презентационными, и любой div между панелью и пунктом ломает\n * `aria-required-children`, а пункты теряют принадлежность к меню.\n */\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => grDropdownMenuListClass({\n dividers: props.dividers,\n borderTop: props.borderTop,\n borderBottom: props.borderBottom,\n}))\n\ndefineSlots<{\n /** Пункты списка меню. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-list\n role=\"none\"\n :class=\"className\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { grDropdownMenuListClass } from './grDropdownMenuStyles'\n\n/**\n * `role=\"none\"` на обёртке обязателен: `role=\"menu\"` у панели объявляет своих\n * потомков презентационными, и любой div между панелью и пунктом ломает\n * `aria-required-children`, а пункты теряют принадлежность к меню.\n */\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => grDropdownMenuListClass({\n dividers: props.dividers,\n borderTop: props.borderTop,\n borderBottom: props.borderBottom,\n}))\n\ndefineSlots<{\n /** Пункты списка меню. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-list\n role=\"none\"\n :class=\"className\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":"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"}
|