@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
package/dist/index.js
CHANGED
|
@@ -23,11 +23,11 @@ import { useComboboxNavigation } from "./composables/useComboboxNavigation.js";
|
|
|
23
23
|
import { useRovingFocus } from "./composables/useRovingFocus.js";
|
|
24
24
|
import { t as GrChip_default } from "./components/GrChip/chunks/GrChip-C0vU69tf.js";
|
|
25
25
|
import { n as grAutocompleteSafelist, t as grAutocompleteConfig } from "./chunks/config-vYMJ3Cr1.js";
|
|
26
|
-
import { t as GrAutocomplete_default } from "./components/GrAutocomplete/chunks/GrAutocomplete-
|
|
26
|
+
import { t as GrAutocomplete_default } from "./components/GrAutocomplete/chunks/GrAutocomplete-rYEY15UI.js";
|
|
27
27
|
import { t as GrSkeleton_default } from "./components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js";
|
|
28
28
|
import { n as GrAvatar_default, t as GrAvatarGroup_default } from "./components/GrAvatar/chunks/GrAvatar-CNmLmgcr.js";
|
|
29
29
|
import { c as initialsFrom, n as grAvatarSafelist, t as grAvatarConfig } from "./chunks/config-B3J0alyY.js";
|
|
30
|
-
import { t as GrBadge_default } from "./components/GrBadge/chunks/GrBadge-
|
|
30
|
+
import { t as GrBadge_default } from "./components/GrBadge/chunks/GrBadge-D2MfThPz.js";
|
|
31
31
|
import { t as grBadgeSafelist } from "./chunks/safelist-CtiHPgrj.js";
|
|
32
32
|
import { t as grBadgeConfig } from "./chunks/config-g8-JGZ_Y.js";
|
|
33
33
|
import { n as grBadgeWrapSafelist, o as formatBadgeValue, t as grBadgeWrapConfig } from "./chunks/config-DwABJHEo.js";
|
|
@@ -38,9 +38,9 @@ import { t as GrLink_default } from "./components/GrLink/chunks/GrLink-DYXw3W9w.
|
|
|
38
38
|
import { g as resolveBreadcrumbsLayout, h as resolveBreadcrumbsFit, n as grBreadcrumbsSafelist, t as grBreadcrumbsConfig } from "./chunks/config-C0Eu8jpG.js";
|
|
39
39
|
import { t as GrBreadcrumbs_default } from "./components/GrBreadcrumbs/chunks/GrBreadcrumbs-DRDNan_n.js";
|
|
40
40
|
import { n as useGrButtonGroup } from "./chunks/context-BfIQv7m1.js";
|
|
41
|
-
import { t as GrButton_default } from "./components/GrButton/chunks/GrButton-
|
|
42
|
-
import { t as grButtonSafelist } from "./chunks/safelist-
|
|
43
|
-
import { t as grButtonConfig } from "./chunks/config-
|
|
41
|
+
import { t as GrButton_default } from "./components/GrButton/chunks/GrButton-7GP0zObj.js";
|
|
42
|
+
import { t as grButtonSafelist } from "./chunks/safelist-DxkMj5IW.js";
|
|
43
|
+
import { t as grButtonConfig } from "./chunks/config-87fszqnD.js";
|
|
44
44
|
import { t as GrButtonGroup_default } from "./components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js";
|
|
45
45
|
import { t as grButtonGroupConfig } from "./chunks/config-DBmdgoVf2.js";
|
|
46
46
|
import "./components/GrButtonGroup/index.js";
|
|
@@ -56,27 +56,27 @@ import "./components/GrChip/index.js";
|
|
|
56
56
|
import { n as grChipGroupSafelist, t as grChipGroupConfig } from "./chunks/config-CZPDPJlg.js";
|
|
57
57
|
import { t as GrChipGroup_default } from "./components/GrChipGroup/chunks/GrChipGroup-C78Vcwos.js";
|
|
58
58
|
import { useAnnouncer } from "./composables/useAnnouncer.js";
|
|
59
|
-
import { t as GrCodeBlock_default } from "./components/GrCodeBlock/chunks/GrCodeBlock-
|
|
59
|
+
import { t as GrCodeBlock_default } from "./components/GrCodeBlock/chunks/GrCodeBlock-Dp0eEBTZ.js";
|
|
60
60
|
import { n as grCodeBlockSafelist, t as grCodeBlockConfig } from "./chunks/config-DolULhjJ.js";
|
|
61
61
|
import { n as grCollapseSafelist, t as grCollapseConfig } from "./chunks/config-BoUI0t-t.js";
|
|
62
62
|
import { n as GrCollapse_default, t as GrCollapseItem_default } from "./components/GrCollapse/chunks/GrCollapse-BlW6ybdL.js";
|
|
63
63
|
import { n as grIconSafelist, t as grIconConfig } from "./chunks/config-3bQeQvqd.js";
|
|
64
|
-
import { t as GrInput_default } from "./components/GrInput/chunks/GrInput-
|
|
64
|
+
import { t as GrInput_default } from "./components/GrInput/chunks/GrInput-BLywRZUN.js";
|
|
65
65
|
import { useFocusTrap } from "./composables/useFocusTrap.js";
|
|
66
66
|
import { t as GrPopover_default } from "./components/GrPopover/chunks/GrPopover-CofG-Tfe.js";
|
|
67
67
|
import { useDragGesture } from "./composables/useDragGesture.js";
|
|
68
|
-
import { t as GrSlider_default } from "./components/GrSlider/chunks/GrSlider-
|
|
69
|
-
import { t as GrColorPicker_default } from "./components/GrColorPicker/chunks/GrColorPicker-
|
|
68
|
+
import { t as GrSlider_default } from "./components/GrSlider/chunks/GrSlider-DTTrZTHK.js";
|
|
69
|
+
import { t as GrColorPicker_default } from "./components/GrColorPicker/chunks/GrColorPicker-B20gQ6AR.js";
|
|
70
70
|
import { n as grColorPickerSafelist, t as grColorPickerConfig } from "./chunks/config-DIDz_E5m.js";
|
|
71
71
|
import { a as GR_KBD_TOKENS, o as findKbdToken, t as GrKbd_default } from "./components/GrKbd/chunks/GrKbd-D2ga1H9i.js";
|
|
72
72
|
import { t as GrModal_default } from "./components/GrModal/chunks/GrModal-CCoWZuIl.js";
|
|
73
|
-
import { t as GrCommandPalette_default } from "./components/GrCommandPalette/chunks/GrCommandPalette-
|
|
73
|
+
import { t as GrCommandPalette_default } from "./components/GrCommandPalette/chunks/GrCommandPalette-Cd0Yo3Dw.js";
|
|
74
74
|
import { n as grCommandPaletteSafelist, t as grCommandPaletteConfig } from "./chunks/config-D0NzGYaE.js";
|
|
75
75
|
import { t as GrConfigProvider_default } from "./components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js";
|
|
76
76
|
import { t as grConfigProviderConfig } from "./chunks/config-B7W9VlZ7.js";
|
|
77
|
-
import { i as GrDialogFooter_default, n as GrDialogHeader_default, r as GrDialogCloseButton_default, t as GrDialog_default } from "./components/GrDialog/chunks/GrDialog-
|
|
78
|
-
import { a as extendDefaultParsers, n as coreResponseErrorParsers, r as createResponseErrorClassifier, s as normalizeError, t as GrResponseErrorBanner_default } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-
|
|
79
|
-
import { t as GrConfirmDialog_default } from "./components/GrConfirmDialog/chunks/GrConfirmDialog-
|
|
77
|
+
import { i as GrDialogFooter_default, n as GrDialogHeader_default, r as GrDialogCloseButton_default, t as GrDialog_default } from "./components/GrDialog/chunks/GrDialog-S1Vl-OhX.js";
|
|
78
|
+
import { a as extendDefaultParsers, n as coreResponseErrorParsers, r as createResponseErrorClassifier, s as normalizeError, t as GrResponseErrorBanner_default } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js";
|
|
79
|
+
import { t as GrConfirmDialog_default } from "./components/GrConfirmDialog/chunks/GrConfirmDialog-DOsbRhoZ.js";
|
|
80
80
|
import { t as grConfirmDialogConfig } from "./chunks/config-A-bBiotF.js";
|
|
81
81
|
import "./components/GrConfirmDialog/index.js";
|
|
82
82
|
import { a as GrDropdownMenuItem_default, c as GrDropdownMenuDivider_default, o as GrDropdownMenuGroup_default, s as GrDropdownMenuHeader_default, t as GrDropdownMenuList_default } from "./components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js";
|
|
@@ -84,7 +84,7 @@ import { t as GrContextMenu_default } from "./components/GrContextMenu/chunks/Gr
|
|
|
84
84
|
import { t as grContextMenuConfig } from "./chunks/config-CPSxM7XE.js";
|
|
85
85
|
import { t as GrTable_default } from "./components/GrTable/chunks/GrTable-Zcdz2St_.js";
|
|
86
86
|
import { t as useDragSort } from "./chunks/useDragSort-0l47h4yb.js";
|
|
87
|
-
import { t as GrDataTable_default } from "./components/GrDataTable/chunks/GrDataTable-
|
|
87
|
+
import { t as GrDataTable_default } from "./components/GrDataTable/chunks/GrDataTable-CAGgRk27.js";
|
|
88
88
|
import { n as grDataTableSafelist, t as grDataTableConfig } from "./chunks/config-DeyT9dJl.js";
|
|
89
89
|
import { t as GrDelta_default } from "./components/GrDelta/chunks/GrDelta-BZwkgQW-.js";
|
|
90
90
|
import { n as grValueSafelist, t as grValueConfig } from "./chunks/config-Z5LeUXys.js";
|
|
@@ -97,15 +97,15 @@ import { t as grDialogSafelist } from "./chunks/safelist-Y3zrlhOa.js";
|
|
|
97
97
|
import "./components/GrDialog/index.js";
|
|
98
98
|
import { n as useGrFormContext } from "./chunks/context-Bfrgsluh.js";
|
|
99
99
|
import { t as GrFormField_default } from "./components/GrFormField/chunks/GrFormField-DSylU7IU.js";
|
|
100
|
-
import { t as GrTextarea_default } from "./components/GrTextarea/chunks/GrTextarea-
|
|
100
|
+
import { t as GrTextarea_default } from "./components/GrTextarea/chunks/GrTextarea-DinXG12-.js";
|
|
101
101
|
import { n as getByPath, o as runFieldRules, r as isEmpty, s as setByPath, t as createGrFormMessageResolver } from "./chunks/validation-5HhpanPP.js";
|
|
102
|
-
import { t as GrPromptDialog_default } from "./components/GrPromptDialog/chunks/GrPromptDialog-
|
|
103
|
-
import { a as useDialogService, i as teardownDialogService, n as dialogService, r as granularityDialogServicePlugin, t as GrDialogServiceHost_default } from "./components/GrDialogService/chunks/GrDialogService-
|
|
102
|
+
import { t as GrPromptDialog_default } from "./components/GrPromptDialog/chunks/GrPromptDialog-BuJQMZLM.js";
|
|
103
|
+
import { a as useDialogService, i as teardownDialogService, n as dialogService, r as granularityDialogServicePlugin, t as GrDialogServiceHost_default } from "./components/GrDialogService/chunks/GrDialogService-Cuhc4YLp.js";
|
|
104
104
|
import { t as grDialogServiceConfig } from "./chunks/config-CjXjhphs.js";
|
|
105
105
|
import { n as grDividerSafelist, t as grDividerConfig } from "./chunks/config-D82r782v.js";
|
|
106
106
|
import { t as GrDivider_default } from "./components/GrDivider/chunks/GrDivider-BXavGcMX.js";
|
|
107
107
|
import { n as grDrawerSafelist, t as grDrawerConfig } from "./chunks/config-ChPg-BQv.js";
|
|
108
|
-
import { t as GrDrawer_default } from "./components/GrDrawer/chunks/GrDrawer-
|
|
108
|
+
import { t as GrDrawer_default } from "./components/GrDrawer/chunks/GrDrawer-C0YqVE9e.js";
|
|
109
109
|
import { t as GrDropdown_default } from "./components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js";
|
|
110
110
|
import { n as grDropdownSafelist, t as grDropdownConfig } from "./chunks/config-uzUuosv7.js";
|
|
111
111
|
import "./components/GrDropdown/index.js";
|
|
@@ -122,36 +122,36 @@ import { t as GrForm_default } from "./components/GrForm/chunks/GrForm-CrnfCsgj.
|
|
|
122
122
|
import { t as grFormConfig } from "./chunks/config-Droqn55j.js";
|
|
123
123
|
import { n as grFormFieldSafelist, t as grFormFieldConfig } from "./chunks/config-B0uvcTPH.js";
|
|
124
124
|
import "./components/GrFormField/index.js";
|
|
125
|
-
import { t as GrFormFile_default } from "./components/GrFormFile/chunks/GrFormFile-
|
|
125
|
+
import { t as GrFormFile_default } from "./components/GrFormFile/chunks/GrFormFile-B1jGZyIj.js";
|
|
126
126
|
import { n as grFormFileSafelist, t as grFormFileConfig } from "./chunks/config-BcXX7S7B.js";
|
|
127
127
|
import { n as grFormSectionSafelist, t as grFormSectionConfig } from "./chunks/config-BEO7brpO.js";
|
|
128
128
|
import { t as GrFormSection_default } from "./components/GrFormSection/chunks/GrFormSection-ejieOg9H.js";
|
|
129
129
|
import { t as GrImageViewer_default } from "./components/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js";
|
|
130
130
|
import { n as grImageViewerSafelist, t as grImageViewerConfig } from "./chunks/config-BDSaD-5p.js";
|
|
131
|
-
import { n as grInputSafelist, t as grInputConfig } from "./chunks/config-
|
|
131
|
+
import { n as grInputSafelist, t as grInputConfig } from "./chunks/config-CIkdsWUk.js";
|
|
132
132
|
import "./components/GrInput/index.js";
|
|
133
133
|
import { n as grInputTagSafelist, t as grInputTagConfig } from "./chunks/config-BqT6PMzO.js";
|
|
134
134
|
import { t as GrInputTag_default } from "./components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js";
|
|
135
|
-
import { t as GrTree_default } from "./components/GrTree/chunks/GrTree-
|
|
136
|
-
import { t as GrJsonViewer_default } from "./components/GrJsonViewer/chunks/GrJsonViewer-
|
|
135
|
+
import { t as GrTree_default } from "./components/GrTree/chunks/GrTree-Ci6CZfKR.js";
|
|
136
|
+
import { t as GrJsonViewer_default } from "./components/GrJsonViewer/chunks/GrJsonViewer-BCZ7lE2k.js";
|
|
137
137
|
import { n as grJsonViewerSafelist, t as grJsonViewerConfig } from "./chunks/config-DpAYidyY2.js";
|
|
138
138
|
import { n as grKbdSafelist, t as grKbdConfig } from "./chunks/config-BRESvs9g.js";
|
|
139
139
|
import "./components/GrKbd/index.js";
|
|
140
140
|
import { n as grLinkSafelist, t as grLinkConfig } from "./chunks/config-CQLNjc9X2.js";
|
|
141
141
|
import "./components/GrLink/index.js";
|
|
142
142
|
import { n as grListSafelist, t as grListConfig } from "./chunks/config-D0W8mGFD.js";
|
|
143
|
-
import { n as GrList_default, t as GrListItem_default } from "./components/GrList/chunks/GrList-
|
|
143
|
+
import { n as GrList_default, t as GrListItem_default } from "./components/GrList/chunks/GrList-B_CRJB4c.js";
|
|
144
144
|
import { n as grLoadingSafelist, t as grLoadingConfig } from "./chunks/config-Bjn30smH.js";
|
|
145
145
|
import "./components/GrLoading/index.js";
|
|
146
146
|
import { n as grModalSafelist, t as grModalConfig } from "./chunks/config-mlheIMtV.js";
|
|
147
147
|
import "./components/GrModal/index.js";
|
|
148
|
-
import { t as GrNavbar_default } from "./components/GrNavbar/chunks/GrNavbar-
|
|
148
|
+
import { t as GrNavbar_default } from "./components/GrNavbar/chunks/GrNavbar-_rtHKwTf.js";
|
|
149
149
|
import { n as grNavbarSafelist, t as grNavbarConfig } from "./chunks/config-2ZHRsdOc.js";
|
|
150
150
|
import { n as grNumberInputSafelist, t as grNumberInputConfig } from "./chunks/config-MmPym-Z72.js";
|
|
151
151
|
import { t as GrNumberInput_default } from "./components/GrNumberInput/chunks/GrNumberInput-DQ59YICu.js";
|
|
152
|
-
import { t as GrSelect_default } from "./components/GrSelect/chunks/GrSelect-
|
|
152
|
+
import { t as GrSelect_default } from "./components/GrSelect/chunks/GrSelect-gCeRFgQo.js";
|
|
153
153
|
import { n as grPaginationSafelist, t as grPaginationConfig } from "./chunks/config-CjKpUcmy.js";
|
|
154
|
-
import { t as GrPagination_default } from "./components/GrPagination/chunks/GrPagination-
|
|
154
|
+
import { t as GrPagination_default } from "./components/GrPagination/chunks/GrPagination-B_kAhoAV.js";
|
|
155
155
|
import { n as grPopoverSafelist, t as grPopoverConfig } from "./chunks/config-BTwYMQaz2.js";
|
|
156
156
|
import "./components/GrPopover/index.js";
|
|
157
157
|
import { n as grProgressBarSafelist, r as GR_TONES, t as grProgressBarConfig } from "./chunks/config-DWL81-aM.js";
|
|
@@ -160,23 +160,23 @@ import { t as GrProgressCircle_default } from "./components/GrProgressCircle/chu
|
|
|
160
160
|
import { n as grProgressCircleSafelist, t as grProgressCircleConfig } from "./chunks/config-CJzmDHfI.js";
|
|
161
161
|
import { t as grPromptDialogConfig } from "./chunks/config-C0Ea9ePP.js";
|
|
162
162
|
import "./components/GrPromptDialog/index.js";
|
|
163
|
-
import { t as GrRadio_default } from "./components/GrRadio/chunks/GrRadio-
|
|
164
|
-
import { n as grRadioSafelist, t as grRadioConfig } from "./chunks/config-
|
|
163
|
+
import { t as GrRadio_default } from "./components/GrRadio/chunks/GrRadio-Aq3v8XgG.js";
|
|
164
|
+
import { n as grRadioSafelist, t as grRadioConfig } from "./chunks/config-CuQmUkMw2.js";
|
|
165
165
|
import "./components/GrRadio/index.js";
|
|
166
|
-
import { t as GrRadioGroup_default } from "./components/GrRadioGroup/chunks/GrRadioGroup-
|
|
166
|
+
import { t as GrRadioGroup_default } from "./components/GrRadioGroup/chunks/GrRadioGroup-y9LVdTWh.js";
|
|
167
167
|
import { t as grRadioGroupConfig } from "./chunks/config-QaIc_gRa.js";
|
|
168
168
|
import { n as grRatingSafelist, t as grRatingConfig } from "./chunks/config-DRbojEzO.js";
|
|
169
169
|
import { t as GrRating_default } from "./components/GrRating/chunks/GrRating-IEiTOdnF.js";
|
|
170
|
-
import { n as GrFormErrorBanner_default, r as GrUploadErrorBanner_default, t as useResponseError } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-
|
|
170
|
+
import { n as GrFormErrorBanner_default, r as GrUploadErrorBanner_default, t as useResponseError } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-CBVRpgIG.js";
|
|
171
171
|
import { n as titleWhenTruncated, t as GrSegmented_default } from "./components/GrSegmented/chunks/GrSegmented-CB-VR-yL.js";
|
|
172
172
|
import { n as grSegmentedSafelist, t as grSegmentedConfig } from "./chunks/config-rLkc9Zn2.js";
|
|
173
173
|
import { n as grSelectSafelist, t as grSelectConfig } from "./chunks/config-DnF472Ox.js";
|
|
174
174
|
import "./components/GrSelect/index.js";
|
|
175
175
|
import { n as grSidebarSafelist, t as grSidebarConfig } from "./chunks/config-DNDgp9bB.js";
|
|
176
|
-
import { n as GrSidebarItem_default, r as GrSidebar_default, t as GrSidebarGroup_default } from "./components/GrSidebar/chunks/GrSidebar-
|
|
176
|
+
import { n as GrSidebarItem_default, r as GrSidebar_default, t as GrSidebarGroup_default } from "./components/GrSidebar/chunks/GrSidebar-alkwBUzL.js";
|
|
177
177
|
import { t as grSkeletonConfig } from "./chunks/config-8Pcutu1j.js";
|
|
178
178
|
import "./components/GrSkeleton/index.js";
|
|
179
|
-
import { n as grSliderSafelist, t as grSliderConfig } from "./chunks/config-
|
|
179
|
+
import { n as grSliderSafelist, t as grSliderConfig } from "./chunks/config-E1cTyRVV.js";
|
|
180
180
|
import "./components/GrSlider/index.js";
|
|
181
181
|
import { n as grSortableListSafelist, t as grSortableListConfig } from "./chunks/config-CbEbLyDE.js";
|
|
182
182
|
import { t as GrSortableList_default } from "./components/GrSortableList/chunks/GrSortableList-HyKX--rO.js";
|
|
@@ -187,7 +187,7 @@ import { n as grStatisticSafelist, t as grStatisticConfig } from "./chunks/confi
|
|
|
187
187
|
import { n as grStepsSafelist, t as grStepsConfig } from "./chunks/config-CLjjjPZj.js";
|
|
188
188
|
import { t as GrSteps_default } from "./components/GrSteps/chunks/GrSteps-C2jxpZoN.js";
|
|
189
189
|
import { n as grSwitchSafelist, t as grSwitchConfig } from "./chunks/config-Yy67uWHY.js";
|
|
190
|
-
import { t as GrSwitch_default } from "./components/GrSwitch/chunks/GrSwitch-
|
|
190
|
+
import { t as GrSwitch_default } from "./components/GrSwitch/chunks/GrSwitch-7Oe5QfQZ.js";
|
|
191
191
|
import { n as grTableSafelist, t as grTableConfig } from "./chunks/config-DCq4JySZ.js";
|
|
192
192
|
import "./components/GrTable/index.js";
|
|
193
193
|
import { n as GrTabPanels_default, t as GrTabPanel_default } from "./components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js";
|
|
@@ -200,12 +200,12 @@ import { n as GrTimeline_default, t as GrTimelineItem_default } from "./componen
|
|
|
200
200
|
import { n as grTimelineSafelist, t as grTimelineConfig } from "./chunks/config-Bd7QfiGj.js";
|
|
201
201
|
import { GRANULARITY_TOAST_STATE, granularityToastPlugin, useToast } from "./composables/useToast.js";
|
|
202
202
|
import { n as grToasterSafelist, t as grToasterConfig } from "./chunks/config-B5SBUa6u.js";
|
|
203
|
-
import { t as GrToaster_default } from "./components/GrToaster/chunks/GrToaster-
|
|
203
|
+
import { t as GrToaster_default } from "./components/GrToaster/chunks/GrToaster-COXIBKzq.js";
|
|
204
204
|
import { n as grTooltipSafelist, t as grTooltipConfig } from "./chunks/config-BTmfQFwi.js";
|
|
205
205
|
import { t as GrTooltip_default } from "./components/GrTooltip/chunks/GrTooltip-uYETdbCD.js";
|
|
206
206
|
import { n as grTreeSafelist, t as grTreeConfig } from "./chunks/config-CDat1wXf.js";
|
|
207
207
|
import { n as grTreeSelectSafelist, t as grTreeSelectConfig } from "./chunks/config-T3-DMXYm.js";
|
|
208
|
-
import { t as GrTreeSelect_default } from "./components/GrTreeSelect/chunks/GrTreeSelect-
|
|
208
|
+
import { t as GrTreeSelect_default } from "./components/GrTreeSelect/chunks/GrTreeSelect-BHwgGJcT.js";
|
|
209
209
|
import "./composables/useGrComponentConfig.js";
|
|
210
210
|
import "./composables/useGranularityTranslations.js";
|
|
211
211
|
import { GRANULARITY_THEME_STATE, granularityThemePlugin, initThemeEarly, useTheme } from "./composables/useTheme.js";
|
package/dist/testing.js
CHANGED
|
@@ -155,7 +155,7 @@ function resetGranularityDom() {
|
|
|
155
155
|
function stubMatchMedia(options = {}) {
|
|
156
156
|
const { reducedMotion = false, matches = false } = options;
|
|
157
157
|
const original = window.matchMedia;
|
|
158
|
-
window.matchMedia = (
|
|
158
|
+
window.matchMedia = (query) => ({
|
|
159
159
|
media: query,
|
|
160
160
|
matches: query.includes("prefers-reduced-motion") ? reducedMotion : matches,
|
|
161
161
|
onchange: null,
|
|
@@ -164,7 +164,7 @@ function stubMatchMedia(options = {}) {
|
|
|
164
164
|
addListener: () => {},
|
|
165
165
|
removeListener: () => {},
|
|
166
166
|
dispatchEvent: () => false
|
|
167
|
-
})
|
|
167
|
+
});
|
|
168
168
|
return () => {
|
|
169
169
|
window.matchMedia = original;
|
|
170
170
|
};
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","names":[],"sources":["../src/testing/pointer.ts","../src/testing/keyboard.ts","../src/testing/geometry.ts","../src/testing/env.ts","../src/testing/context.ts","../src/testing/announcer.ts"],"sourcesContent":["/**\n * Указательные жесты в тестах.\n *\n * Две вещи, которые ломают наивную запись жеста, и обе неочевидны:\n *\n * 1. **`pointerdown` идёт в элемент, а `pointermove`/`pointerup`/`pointercancel` — в `window`.**\n * Так слушает `useDragGesture` (и всё, что на нём стоит: слайдер, сплиттер,\n * перестановка, смахивание тоста): нажатие приходит от разметки, а движение\n * ловится глобально, иначе жест обрывался бы на выходе курсора за элемент.\n * Тест, отправивший движение в тот же элемент, ничего не проверяет — и молча.\n * 2. **`PointerEvent` в jsdom нет**, а `wrapper.trigger('pointerdown', { clientY })`\n * падает на попытке записать `clientY`. Поэтому события собираются\n * `MouseEvent`-ом и отправляются через `dispatchEvent`.\n *\n * Плюс `button: 0` по умолчанию: жест игнорирует неосновную кнопку, и без этого\n * «перетаскивание» в тесте не начинается вовсе.\n */\n\n/** Событие указателя: `MouseEvent`, потому что `PointerEvent` в jsdom не реализован. */\nexport function pointer(type: string, init: MouseEventInit = {}): MouseEvent {\n return new MouseEvent(type, { bubbles: true, ...init })\n}\n\n/** Нажатие: единственное событие жеста, которое адресуется элементу. */\nexport function press(target: Element, init: MouseEventInit = {}): void {\n target.dispatchEvent(pointer('pointerdown', { button: 0, ...init }))\n}\n\nexport function move(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointermove', init))\n}\n\nexport function release(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointerup', init))\n}\n\n/**\n * Обрыв жеста: система забрала указатель (системный жест, звонок, потеря окна).\n * Отдельная ветка поведения у всех потребителей — смахивание возвращает тост,\n * перестановка откатывает порядок, — поэтому проверяется отдельно от `release`.\n */\nexport function cancelPointer(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointercancel', init))\n}\n\n/** Жест целиком: нажали на элементе, провели, отпустили. */\nexport function drag(target: Element, from: MouseEventInit, to: MouseEventInit): void {\n press(target, from)\n move(to)\n release(to)\n}\n","/**\n * Клавиатурные события в тестах.\n *\n * Существует ради одного флага: **`isComposing` не переживает\n * `wrapper.trigger('keydown', …)`**. `@vue/test-utils` собирает событие из\n * переданного объекта, но `isComposing` — свойство только для чтения на\n * `KeyboardEvent`, и присвоение молча теряется. Тест «Enter во время\n * IME-композиции ничего не коммитит» при такой записи проверяет обычный Enter,\n * то есть зеленеет на сломанном коде.\n *\n * Пакет читает флаг через `isComposingEvent` (`src/internal/keyboard.ts`) —\n * `event.isComposing || event.keyCode === 229`, потому что Safari до 16.4 не\n * ставил первое. Генератор ставит оба, иначе тест проверял бы половину предиката.\n *\n * Композиция — это не экзотика: пока пользователь набирает 日本語, 한국어 или\n * что угодно через IME, `Enter` подтверждает **выбор иероглифа**, а не действие\n * виджета. Компонент, который на нём выберет опцию или отправит форму, у такого\n * пользователя неработоспособен.\n */\n\nexport type KeyboardEventOptions = KeyboardEventInit & { key: string }\n\n/** Клавиатурное событие с разумными умолчаниями (всплывает, отменяемо). */\nexport function keyboardEvent(type: string, init: KeyboardEventOptions): KeyboardEvent {\n return new KeyboardEvent(type, { bubbles: true, cancelable: true, ...init })\n}\n\n/** Нажатие клавиши в элемент. */\nexport function keydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n const event = keyboardEvent('keydown', { key, ...init })\n target.dispatchEvent(event)\n return event\n}\n\n/**\n * Нажатие во время IME-композиции. Отдельная функция, а не флаг у `keydown`:\n * из имени в тесте видно, что проверяется, а `keyCode: 229` не приходится\n * помнить на каждом вызове.\n */\nexport function composingKeydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n return keydown(target, key, { isComposing: true, keyCode: 229, ...init })\n}\n","/**\n * Геометрия в jsdom.\n *\n * Раскладки в jsdom нет: `getBoundingClientRect` у любого элемента возвращает\n * нули. Всё, что считает попадание указателя — слайдер, сплиттер, перестановка,\n * ширины колонок таблицы, — на нулевом прямоугольнике проверять не на чем,\n * поэтому геометрия задаётся руками.\n */\n\nexport type MockRect = Partial<Omit<DOMRect, 'toJSON'>>\n\n/** Прямоугольник элемента. Незаданные стороны выводятся из заданных. */\nexport function mockRect(target: Element, rect: MockRect): void {\n const left = rect.left ?? rect.x ?? 0\n const top = rect.top ?? rect.y ?? 0\n const width = rect.width ?? (rect.right ?? 0) - left\n const height = rect.height ?? (rect.bottom ?? 0) - top\n\n const value: DOMRect = {\n x: left,\n y: top,\n left,\n top,\n width,\n height,\n right: rect.right ?? left + width,\n bottom: rect.bottom ?? top + height,\n toJSON: () => ({}),\n }\n\n target.getBoundingClientRect = () => value\n}\n\nexport interface StackRectsOptions {\n /** Размер элемента вдоль оси. */\n size: number\n /** Ось раскладки. По умолчанию вертикальная — так лежат списки и строки. */\n axis?: 'vertical' | 'horizontal'\n /** Смещение первого элемента. */\n start?: number\n /** Размер поперёк оси. */\n cross?: number\n}\n\n/** Элементы подряд, встык, без зазоров: строки списка, ячейки шапки, деления шкалы. */\nexport function stackRects(targets: Iterable<Element>, options: StackRectsOptions): void {\n const { size, axis = 'vertical', start = 0, cross = 100 } = options\n\n let offset = start\n\n for (const target of targets) {\n mockRect(target, axis === 'vertical'\n ? { top: offset, height: size, left: 0, width: cross }\n : { left: offset, width: size, top: 0, height: cross })\n\n offset += size\n }\n}\n","import { resetAnnouncer } from '../composables/useAnnouncer'\nimport { resetPortalRoot } from '../composables/internal/portalRoot'\nimport { useToast } from '../composables/useToast'\n\n/**\n * Уборка между тестами.\n *\n * `document.body.innerHTML = ''` сам по себе оставляет пакет в разобранном\n * состоянии: корень портала и хост живого региона закэшированы модулями, и\n * после очистки `body` они указывают на узлы **вне документа**. Следующий\n * монтаж телепортирует туда оверлеи, тест ищет их в документе и не находит —\n * без единой ошибки в консоли. Очередь тостов переживает размонтирование по\n * замыслу, поэтому её тоже гасим.\n */\nexport function resetGranularityDom(): void {\n useToast().clear()\n resetAnnouncer()\n resetPortalRoot()\n\n if (typeof document !== 'undefined')\n document.body.innerHTML = ''\n}\n\nexport interface StubMatchMediaOptions {\n /** Ответ на `(prefers-reduced-motion: reduce)`. */\n reducedMotion?: boolean\n /** Ответ на остальные запросы. */\n matches?: boolean\n}\n\n/**\n * Ответ `matchMedia` — например «пользователь просил меньше движения».\n *\n * Не для того, чтобы «не падало»: сам пакет зовёт `matchMedia` опционально и без\n * него живёт. Нужно, когда проверяется поведение **под** медиазапросом.\n * Возвращает функцию отката: глобальное состояние обязано уйти вместе с тестом.\n */\nexport function stubMatchMedia(options: StubMatchMediaOptions = {}): () => void {\n const { reducedMotion = false, matches = false } = options\n const original = window.matchMedia\n\n window.matchMedia = ((query: string) => ({\n media: query,\n matches: query.includes('prefers-reduced-motion') ? reducedMotion : matches,\n onchange: null,\n addEventListener: () => {},\n removeEventListener: () => {},\n addListener: () => {},\n removeListener: () => {},\n dispatchEvent: () => false,\n }))\n\n return () => {\n window.matchMedia = original\n }\n}\n","import { computed, ref, type Ref } from 'vue'\n\nimport { GR_CONFIG_KEY, type GrComponentDefaults, type GrComponentSize, type GrConfigContext } from '../components/GrConfigProvider/context'\nimport { GRANULARITY_I18N_KEY, type GranularityI18nAdapter, type GranularityI18nParams } from '../i18n/adapter'\n\nexport interface I18nAdapterOptions {\n /** Перевод по ключу. По умолчанию — сам ключ: видно, что спросили. */\n t?: (key: string, params?: GranularityI18nParams) => string\n te?: (key: string) => boolean\n locale?: string | Ref<string>\n}\n\n/** Адаптер перевода для теста: словарь или своя функция. */\nexport function i18nAdapter(options: I18nAdapterOptions | Record<string, string> = {}): GranularityI18nAdapter {\n const isDictionary = typeof (options as I18nAdapterOptions).t !== 'function'\n && !('locale' in options)\n && !('te' in options)\n\n if (isDictionary) {\n const dictionary = options as Record<string, string>\n\n return {\n t: key => dictionary[key] ?? key,\n te: key => key in dictionary,\n }\n }\n\n const { t, te, locale } = options as I18nAdapterOptions\n\n return {\n t: t ?? (key => key),\n te,\n locale: typeof locale === 'string' ? ref(locale) : locale,\n }\n}\n\nexport interface GranularityGlobalOptions {\n size?: GrComponentSize\n componentDefaults?: GrComponentDefaults\n theme?: string\n portalTarget?: string | HTMLElement\n /** Адаптер перевода: готовый, словарь `{ ключ: перевод }` или опции `i18nAdapter`. */\n i18n?: GranularityI18nAdapter | I18nAdapterOptions | Record<string, string>\n}\n\n/**\n * Окружение пакета для монтирования — то, что `<GrConfigProvider>` раздаёт\n * через `provide`.\n *\n * Отдаётся объектом, а не компонентом-обёрткой, намеренно: провайдер тянет за\n * собой лишний корневой элемент, а искать компонент внутри чужой разметки в\n * каждом тесте дороже, чем передать `global`. Проверять **сам** провайдер\n * (`data-gr-config-provider`, тема на корне) этим нельзя и не нужно — для этого\n * его и монтируют.\n *\n * ```ts\n * mount(GrSelect, { props, global: granularityGlobal({ size: 'sm' }) })\n * ```\n */\nexport function granularityGlobal(options: GranularityGlobalOptions = {}): { provide: Record<symbol, unknown> } {\n const config: GrConfigContext = {\n size: computed(() => options.size),\n componentDefaults: computed(() => options.componentDefaults ?? {}),\n theme: computed(() => options.theme),\n portalTarget: computed(() => options.portalTarget),\n }\n\n const provide: Record<symbol, unknown> = { [GR_CONFIG_KEY]: config }\n\n if (options.i18n)\n provide[GRANULARITY_I18N_KEY] = 't' in options.i18n && typeof options.i18n.t === 'function'\n ? options.i18n\n : i18nAdapter(options.i18n)\n\n return { provide }\n}\n","import type { GrAnnouncerPoliteness } from '../composables/useAnnouncer'\n\n/**\n * Текст живого региона.\n *\n * Ждать здесь обязательно: `announce` пишет в регион **отложенным** макротаском,\n * и это не деталь реализации, а условие работы. Регион, в котором текст\n * появился в том же кадре, что и сам регион, часть AT не объявляет вовсе;\n * поэтому синхронное чтение сразу после действия покажет пустую строку.\n */\nexport async function announced(politeness: GrAnnouncerPoliteness = 'polite'): Promise<string> {\n await new Promise(resolve => setTimeout(resolve, 2))\n\n return document.querySelector(`[data-gr-announcer-region=\"${politeness}\"]`)?.textContent ?? ''\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testing.js","names":[],"sources":["../src/testing/pointer.ts","../src/testing/keyboard.ts","../src/testing/geometry.ts","../src/testing/env.ts","../src/testing/context.ts","../src/testing/announcer.ts"],"sourcesContent":["/**\n * Указательные жесты в тестах.\n *\n * Две вещи, которые ломают наивную запись жеста, и обе неочевидны:\n *\n * 1. **`pointerdown` идёт в элемент, а `pointermove`/`pointerup`/`pointercancel` — в `window`.**\n * Так слушает `useDragGesture` (и всё, что на нём стоит: слайдер, сплиттер,\n * перестановка, смахивание тоста): нажатие приходит от разметки, а движение\n * ловится глобально, иначе жест обрывался бы на выходе курсора за элемент.\n * Тест, отправивший движение в тот же элемент, ничего не проверяет — и молча.\n * 2. **`PointerEvent` в jsdom нет**, а `wrapper.trigger('pointerdown', { clientY })`\n * падает на попытке записать `clientY`. Поэтому события собираются\n * `MouseEvent`-ом и отправляются через `dispatchEvent`.\n *\n * Плюс `button: 0` по умолчанию: жест игнорирует неосновную кнопку, и без этого\n * «перетаскивание» в тесте не начинается вовсе.\n */\n\n/** Событие указателя: `MouseEvent`, потому что `PointerEvent` в jsdom не реализован. */\nexport function pointer(type: string, init: MouseEventInit = {}): MouseEvent {\n return new MouseEvent(type, { bubbles: true, ...init })\n}\n\n/** Нажатие: единственное событие жеста, которое адресуется элементу. */\nexport function press(target: Element, init: MouseEventInit = {}): void {\n target.dispatchEvent(pointer('pointerdown', { button: 0, ...init }))\n}\n\nexport function move(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointermove', init))\n}\n\nexport function release(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointerup', init))\n}\n\n/**\n * Обрыв жеста: система забрала указатель (системный жест, звонок, потеря окна).\n * Отдельная ветка поведения у всех потребителей — смахивание возвращает тост,\n * перестановка откатывает порядок, — поэтому проверяется отдельно от `release`.\n */\nexport function cancelPointer(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointercancel', init))\n}\n\n/** Жест целиком: нажали на элементе, провели, отпустили. */\nexport function drag(target: Element, from: MouseEventInit, to: MouseEventInit): void {\n press(target, from)\n move(to)\n release(to)\n}\n","/**\n * Клавиатурные события в тестах.\n *\n * Существует ради одного флага: **`isComposing` не переживает\n * `wrapper.trigger('keydown', …)`**. `@vue/test-utils` собирает событие из\n * переданного объекта, но `isComposing` — свойство только для чтения на\n * `KeyboardEvent`, и присвоение молча теряется. Тест «Enter во время\n * IME-композиции ничего не коммитит» при такой записи проверяет обычный Enter,\n * то есть зеленеет на сломанном коде.\n *\n * Пакет читает флаг через `isComposingEvent` (`src/internal/keyboard.ts`) —\n * `event.isComposing || event.keyCode === 229`, потому что Safari до 16.4 не\n * ставил первое. Генератор ставит оба, иначе тест проверял бы половину предиката.\n *\n * Композиция — это не экзотика: пока пользователь набирает 日本語, 한국어 или\n * что угодно через IME, `Enter` подтверждает **выбор иероглифа**, а не действие\n * виджета. Компонент, который на нём выберет опцию или отправит форму, у такого\n * пользователя неработоспособен.\n */\n\nexport type KeyboardEventOptions = KeyboardEventInit & { key: string }\n\n/** Клавиатурное событие с разумными умолчаниями (всплывает, отменяемо). */\nexport function keyboardEvent(type: string, init: KeyboardEventOptions): KeyboardEvent {\n return new KeyboardEvent(type, { bubbles: true, cancelable: true, ...init })\n}\n\n/** Нажатие клавиши в элемент. */\nexport function keydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n const event = keyboardEvent('keydown', { key, ...init })\n target.dispatchEvent(event)\n return event\n}\n\n/**\n * Нажатие во время IME-композиции. Отдельная функция, а не флаг у `keydown`:\n * из имени в тесте видно, что проверяется, а `keyCode: 229` не приходится\n * помнить на каждом вызове.\n */\nexport function composingKeydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n return keydown(target, key, { isComposing: true, keyCode: 229, ...init })\n}\n","/**\n * Геометрия в jsdom.\n *\n * Раскладки в jsdom нет: `getBoundingClientRect` у любого элемента возвращает\n * нули. Всё, что считает попадание указателя — слайдер, сплиттер, перестановка,\n * ширины колонок таблицы, — на нулевом прямоугольнике проверять не на чем,\n * поэтому геометрия задаётся руками.\n */\n\nexport type MockRect = Partial<Omit<DOMRect, 'toJSON'>>\n\n/** Прямоугольник элемента. Незаданные стороны выводятся из заданных. */\nexport function mockRect(target: Element, rect: MockRect): void {\n const left = rect.left ?? rect.x ?? 0\n const top = rect.top ?? rect.y ?? 0\n const width = rect.width ?? (rect.right ?? 0) - left\n const height = rect.height ?? (rect.bottom ?? 0) - top\n\n const value: DOMRect = {\n x: left,\n y: top,\n left,\n top,\n width,\n height,\n right: rect.right ?? left + width,\n bottom: rect.bottom ?? top + height,\n toJSON: () => ({}),\n }\n\n target.getBoundingClientRect = () => value\n}\n\nexport interface StackRectsOptions {\n /** Размер элемента вдоль оси. */\n size: number\n /** Ось раскладки. По умолчанию вертикальная — так лежат списки и строки. */\n axis?: 'vertical' | 'horizontal'\n /** Смещение первого элемента. */\n start?: number\n /** Размер поперёк оси. */\n cross?: number\n}\n\n/** Элементы подряд, встык, без зазоров: строки списка, ячейки шапки, деления шкалы. */\nexport function stackRects(targets: Iterable<Element>, options: StackRectsOptions): void {\n const { size, axis = 'vertical', start = 0, cross = 100 } = options\n\n let offset = start\n\n for (const target of targets) {\n mockRect(target, axis === 'vertical'\n ? { top: offset, height: size, left: 0, width: cross }\n : { left: offset, width: size, top: 0, height: cross })\n\n offset += size\n }\n}\n","import { resetAnnouncer } from '../composables/useAnnouncer'\nimport { resetPortalRoot } from '../composables/internal/portalRoot'\nimport { useToast } from '../composables/useToast'\n\n/**\n * Уборка между тестами.\n *\n * `document.body.innerHTML = ''` сам по себе оставляет пакет в разобранном\n * состоянии: корень портала и хост живого региона закэшированы модулями, и\n * после очистки `body` они указывают на узлы **вне документа**. Следующий\n * монтаж телепортирует туда оверлеи, тест ищет их в документе и не находит —\n * без единой ошибки в консоли. Очередь тостов переживает размонтирование по\n * замыслу, поэтому её тоже гасим.\n */\nexport function resetGranularityDom(): void {\n useToast().clear()\n resetAnnouncer()\n resetPortalRoot()\n\n if (typeof document !== 'undefined')\n document.body.innerHTML = ''\n}\n\nexport interface StubMatchMediaOptions {\n /** Ответ на `(prefers-reduced-motion: reduce)`. */\n reducedMotion?: boolean\n /** Ответ на остальные запросы. */\n matches?: boolean\n}\n\n/**\n * Ответ `matchMedia` — например «пользователь просил меньше движения».\n *\n * Не для того, чтобы «не падало»: сам пакет зовёт `matchMedia` опционально и без\n * него живёт. Нужно, когда проверяется поведение **под** медиазапросом.\n * Возвращает функцию отката: глобальное состояние обязано уйти вместе с тестом.\n */\nexport function stubMatchMedia(options: StubMatchMediaOptions = {}): () => void {\n const { reducedMotion = false, matches = false } = options\n const original = window.matchMedia\n\n window.matchMedia = (query: string) => ({\n media: query,\n matches: query.includes('prefers-reduced-motion') ? reducedMotion : matches,\n onchange: null,\n addEventListener: () => {},\n removeEventListener: () => {},\n addListener: () => {},\n removeListener: () => {},\n dispatchEvent: () => false,\n })\n\n return () => {\n window.matchMedia = original\n }\n}\n","import { computed, ref, type Ref } from 'vue'\n\nimport { GR_CONFIG_KEY, type GrComponentDefaults, type GrComponentSize, type GrConfigContext } from '../components/GrConfigProvider/context'\nimport { GRANULARITY_I18N_KEY, type GranularityI18nAdapter, type GranularityI18nParams } from '../i18n/adapter'\n\nexport interface I18nAdapterOptions {\n /** Перевод по ключу. По умолчанию — сам ключ: видно, что спросили. */\n t?: (key: string, params?: GranularityI18nParams) => string\n te?: (key: string) => boolean\n locale?: string | Ref<string>\n}\n\n/** Адаптер перевода для теста: словарь или своя функция. */\nexport function i18nAdapter(options: I18nAdapterOptions | Record<string, string> = {}): GranularityI18nAdapter {\n const isDictionary = typeof (options as I18nAdapterOptions).t !== 'function'\n && !('locale' in options)\n && !('te' in options)\n\n if (isDictionary) {\n const dictionary = options as Record<string, string>\n\n return {\n t: key => dictionary[key] ?? key,\n te: key => key in dictionary,\n }\n }\n\n const { t, te, locale } = options as I18nAdapterOptions\n\n return {\n t: t ?? (key => key),\n te,\n locale: typeof locale === 'string' ? ref(locale) : locale,\n }\n}\n\nexport interface GranularityGlobalOptions {\n size?: GrComponentSize\n componentDefaults?: GrComponentDefaults\n theme?: string\n portalTarget?: string | HTMLElement\n /** Адаптер перевода: готовый, словарь `{ ключ: перевод }` или опции `i18nAdapter`. */\n i18n?: GranularityI18nAdapter | I18nAdapterOptions | Record<string, string>\n}\n\n/**\n * Окружение пакета для монтирования — то, что `<GrConfigProvider>` раздаёт\n * через `provide`.\n *\n * Отдаётся объектом, а не компонентом-обёрткой, намеренно: провайдер тянет за\n * собой лишний корневой элемент, а искать компонент внутри чужой разметки в\n * каждом тесте дороже, чем передать `global`. Проверять **сам** провайдер\n * (`data-gr-config-provider`, тема на корне) этим нельзя и не нужно — для этого\n * его и монтируют.\n *\n * ```ts\n * mount(GrSelect, { props, global: granularityGlobal({ size: 'sm' }) })\n * ```\n */\nexport function granularityGlobal(options: GranularityGlobalOptions = {}): { provide: Record<symbol, unknown> } {\n const config: GrConfigContext = {\n size: computed(() => options.size),\n componentDefaults: computed(() => options.componentDefaults ?? {}),\n theme: computed(() => options.theme),\n portalTarget: computed(() => options.portalTarget),\n }\n\n const provide: Record<symbol, unknown> = { [GR_CONFIG_KEY]: config }\n\n if (options.i18n) {\n provide[GRANULARITY_I18N_KEY] = 't' in options.i18n && typeof options.i18n.t === 'function'\n ? options.i18n\n : i18nAdapter(options.i18n)\n }\n\n return { provide }\n}\n","import type { GrAnnouncerPoliteness } from '../composables/useAnnouncer'\n\n/**\n * Текст живого региона.\n *\n * Ждать здесь обязательно: `announce` пишет в регион **отложенным** макротаском,\n * и это не деталь реализации, а условие работы. Регион, в котором текст\n * появился в том же кадре, что и сам регион, часть AT не объявляет вовсе;\n * поэтому синхронное чтение сразу после действия покажет пустую строку.\n */\nexport async function announced(politeness: GrAnnouncerPoliteness = 'polite'): Promise<string> {\n await new Promise(resolve => setTimeout(resolve, 2))\n\n return document.querySelector(`[data-gr-announcer-region=\"${politeness}\"]`)?.textContent ?? ''\n}\n"],"mappings":"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"}
|
package/dist/theme-apply.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme-apply.js","names":[],"sources":["../src/theme/apply.ts"],"sourcesContent":["/**\n * Подключение темы в рантайме — `@feugene/granularity/theme/apply`.\n *\n * Отдельный подпуть от `@feugene/granularity/theme` не по вкусу, а по весу:\n * там справочник токенов (сотня килобайт данных), нужный, чтобы тему\n * **собрать**. Чтобы её **подключить**, не нужно ничего, кроме готовой строки,\n * — и приложению незачем платить за первое, если оно делает второе.\n *\n * Штатный путь всё же другой: собрать тему на сборке и отдать браузеру обычный\n * CSS-файл. Этот модуль — для случаев, когда тема появляется только в браузере:\n * редактор тем, превью, тема из пользовательских настроек.\n */\n\nconst ATTRIBUTE = 'data-gr-theme'\n\nexport interface ApplyThemeOptions {\n /**\n * Имя, под которым тема живёт в документе. Повторный вызов с тем же именем\n * заменяет её содержимое, а не добавляет второй `<style>`: иначе редактор\n * темы за минуту работы оставил бы в `<head>` сотню слоёв, и побеждал бы\n * последний — то есть результат зависел бы от истории правок.\n */\n name?: string\n /** Куда вставлять. По умолчанию `document.head`. */\n target?: HTMLElement | null\n}\n\n/** Подключает CSS темы и возвращает функцию, которая его снимает. */\nexport function applyTheme(css: string, options: ApplyThemeOptions = {}): () => void {\n const { name = 'custom', target } = options\n\n if (typeof document === 'undefined')\n return () => {}\n\n const host = target ?? document.head\n const existing = host.querySelector<HTMLStyleElement>(`style[${ATTRIBUTE}=\"${name}\"]`)\n const style = existing ?? document.createElement('style')\n\n style.setAttribute(ATTRIBUTE, name)\n style.textContent = css\n\n if (!existing)
|
|
1
|
+
{"version":3,"file":"theme-apply.js","names":[],"sources":["../src/theme/apply.ts"],"sourcesContent":["/**\n * Подключение темы в рантайме — `@feugene/granularity/theme/apply`.\n *\n * Отдельный подпуть от `@feugene/granularity/theme` не по вкусу, а по весу:\n * там справочник токенов (сотня килобайт данных), нужный, чтобы тему\n * **собрать**. Чтобы её **подключить**, не нужно ничего, кроме готовой строки,\n * — и приложению незачем платить за первое, если оно делает второе.\n *\n * Штатный путь всё же другой: собрать тему на сборке и отдать браузеру обычный\n * CSS-файл. Этот модуль — для случаев, когда тема появляется только в браузере:\n * редактор тем, превью, тема из пользовательских настроек.\n */\n\nconst ATTRIBUTE = 'data-gr-theme'\n\nexport interface ApplyThemeOptions {\n /**\n * Имя, под которым тема живёт в документе. Повторный вызов с тем же именем\n * заменяет её содержимое, а не добавляет второй `<style>`: иначе редактор\n * темы за минуту работы оставил бы в `<head>` сотню слоёв, и побеждал бы\n * последний — то есть результат зависел бы от истории правок.\n */\n name?: string\n /** Куда вставлять. По умолчанию `document.head`. */\n target?: HTMLElement | null\n}\n\n/** Подключает CSS темы и возвращает функцию, которая его снимает. */\nexport function applyTheme(css: string, options: ApplyThemeOptions = {}): () => void {\n const { name = 'custom', target } = options\n\n if (typeof document === 'undefined')\n return () => {}\n\n const host = target ?? document.head\n const existing = host.querySelector<HTMLStyleElement>(`style[${ATTRIBUTE}=\"${name}\"]`)\n const style = existing ?? document.createElement('style')\n\n style.setAttribute(ATTRIBUTE, name)\n style.textContent = css\n\n if (!existing)\n host.append(style)\n\n return () => style.remove()\n}\n\n/** Снимает тему, подключённую `applyTheme`. */\nexport function removeTheme(name = 'custom', target?: HTMLElement | null): void {\n if (typeof document === 'undefined')\n return\n\n const host = target ?? document.head\n host.querySelector(`style[${ATTRIBUTE}=\"${name}\"]`)?.remove()\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAM,YAAY;;AAelB,SAAgB,WAAW,KAAa,UAA6B,CAAC,GAAe;CACnF,MAAM,EAAE,OAAO,UAAU,WAAW;CAEpC,IAAI,OAAO,aAAa,aACtB,aAAa,CAAC;CAEhB,MAAM,OAAO,UAAU,SAAS;CAChC,MAAM,WAAW,KAAK,cAAgC,SAAS,UAAU,IAAI,KAAK,GAAG;CACrF,MAAM,QAAQ,YAAY,SAAS,cAAc,OAAO;CAExD,MAAM,aAAa,WAAW,IAAI;CAClC,MAAM,cAAc;CAEpB,IAAI,CAAC,UACH,KAAK,OAAO,KAAK;CAEnB,aAAa,MAAM,OAAO;AAC5B;;AAGA,SAAgB,YAAY,OAAO,UAAU,QAAmC;CAC9E,IAAI,OAAO,aAAa,aACtB;CAGF,CADa,UAAU,SAAS,KAAA,CAC3B,cAAc,SAAS,UAAU,IAAI,KAAK,GAAG,CAAC,EAAE,OAAO;AAC9D"}
|
package/dist/theme.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as grThemeTokens, n as grDerivedTokens, t as grComponentTokens } from "./chunks/generated-
|
|
1
|
+
import { a as grThemeTokens, n as grDerivedTokens, t as grComponentTokens } from "./chunks/generated-CSyPsWtM.js";
|
|
2
2
|
//#region src/theme/color.ts
|
|
3
3
|
function parseHex(value) {
|
|
4
4
|
const match = value.trim().match(/^#([\da-f]{3}|[\da-f]{6})$/i);
|
package/dist/theme.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"theme.js","names":[],"sources":["../src/theme/color.ts","../src/theme/roles.ts","../src/theme/validate.ts","../src/theme/extendTheme.ts","../src/theme/tone.ts"],"sourcesContent":["/**\n * Цветовая математика пакета — один источник на всех.\n *\n * Одну и ту же формулу считают три разных потребителя: генератор токенов\n * (фолбэки `@supports not (color-mix)`), композиция тем (`extendTheme`, `tone`)\n * и гейты контраста. Расхождение здесь не абстрактно: фолбэки уже жили\n * отдельной копией из сорока хексов, которые обязаны были совпадать с живым\n * `color-mix` до байта, и не совпадали.\n *\n * Модуль читает и генератор (`scripts/generate-tokens.mjs`, запускается\n * `node --experimental-strip-types`), поэтому синтаксис здесь только стираемый:\n * ни `enum`, ни `namespace`, ни параметров-свойств в конструкторах.\n */\n\nexport type Rgb = [number, number, number]\n\nexport function parseHex(value: string): Rgb {\n const match = value.trim().match(/^#([\\da-f]{3}|[\\da-f]{6})$/i)\n\n if (!match)\n throw new Error(`ожидался hex-цвет, получено: ${value}`)\n\n const hex = match[1].length === 3\n ? match[1].split('').map(char => char + char).join('')\n : match[1]\n\n return [0, 2, 4].map(offset => Number.parseInt(hex.slice(offset, offset + 2), 16)) as Rgb\n}\n\nexport function toHex(channels: Rgb): string {\n return `#${channels\n .map(channel => Math.round(Math.min(255, Math.max(0, channel))).toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/**\n * `color-mix(in srgb, base <amount>%, other)` для непрозрачных цветов — это\n * линейная интерполяция в gamma-кодированном sRGB, то есть ровно то, что делает\n * браузер. Поэтому посчитанный здесь фолбэк совпадает с живым `color-mix`.\n */\nexport function mixSrgb(baseHex: string, otherHex: string, amount: number): string {\n const base = parseHex(baseHex)\n const other = parseHex(otherHex)\n const ratio = amount / 100\n\n return toHex(base.map((channel, index) => channel * ratio + other[index] * (1 - ratio)) as Rgb)\n}\n\nexport function luminance(color: string | Rgb): number {\n const channels = (typeof color === 'string' ? parseHex(color) : color).map((channel) => {\n const normalized = channel / 255\n\n return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4\n })\n\n return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]\n}\n\n/** Отношение контраста по WCAG 2.1: от 1 (одинаковые) до 21 (чёрное на белом). */\nexport function contrast(foreground: string | Rgb, background: string | Rgb): number {\n const first = luminance(foreground)\n const second = luminance(background)\n const [lighter, darker] = first > second ? [first, second] : [second, first]\n\n return (lighter + 0.05) / (darker + 0.05)\n}\n\nfunction toLab(color: string | Rgb): [number, number, number] {\n const [red, green, blue] = (typeof color === 'string' ? parseHex(color) : color).map((channel) => {\n const normalized = channel / 255\n\n return normalized <= 0.04045 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4\n })\n\n // sRGB → XYZ (D65) → Lab, точки белого из CIE.\n const x = (red * 0.4124 + green * 0.3576 + blue * 0.1805) / 0.95047\n const y = red * 0.2126 + green * 0.7152 + blue * 0.0722\n const z = (red * 0.0193 + green * 0.1192 + blue * 0.9505) / 1.08883\n\n const f = (value: number): number => (value > 0.008856 ? value ** (1 / 3) : 7.787 * value + 16 / 116)\n const [fx, fy, fz] = [f(x), f(y), f(z)]\n\n return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)]\n}\n\n/**\n * Воспринимаемое расстояние между цветами (ΔE, CIE76).\n *\n * Контраст отвечает на вопрос «читается ли текст», а этот — на вопрос\n * «различит ли человек два тона рядом». Порог заметности около 2.3; всё, что\n * ниже, для глаза один цвет, каким бы разным ни выглядел hex.\n */\nexport function deltaE(first: string | Rgb, second: string | Rgb): number {\n const [firstLab, secondLab] = [toLab(first), toLab(second)]\n\n return Math.hypot(...firstLab.map((value, index) => value - secondLab[index]))\n}\n\n/** Цвет — это hex, а не `var()`/`rgb()`: производные и контраст считаются только по нему. */\nexport function isHex(value: string): boolean {\n return /^#(?:[\\da-f]{3}|[\\da-f]{6})$/i.test(value.trim())\n}\n","import { grThemeTokens } from '../tokens/generated'\nimport { isHex } from './color'\n\n/** Значения ролей темы: `--gr-bg` → `#041e2b`. */\nexport type GrThemeTokens = Record<string, string>\n\n/** Роли, известные пакету, в порядке объявления. */\nexport function themeRoleNames(): string[] {\n return grThemeTokens.map(token => token.name)\n}\n\n/**\n * Значение роли, годное для арифметики.\n *\n * Роль вправе ссылаться на другую (`--gr-invalid-brd: var(--gr-danger)`) — такую\n * ссылку разворачиваем, иначе фолбэк и проверки считать не из чего. Всё, что не\n * разворачивается в hex (`rgb(… / .45)` у подложки, `var()` за пределы темы),\n * возвращается как `null`: посчитать нельзя, и выдумывать не надо.\n *\n * Цикл рвём с ошибкой: тема потребителя вправе ошибиться, и упасть надо с\n * именами ролей, а не переполнением стека.\n */\nexport function resolveRole(tokens: GrThemeTokens, name: string, seen: string[] = []): string | null {\n const value = tokens[name]\n if (value === undefined) return null\n if (isHex(value)) return value\n\n const reference = value.trim().match(/^var\\(\\s*(--[\\w-]+)\\s*\\)$/)\n if (!reference) return null\n\n if (seen.includes(name))\n throw new Error(`роль ${name} ссылается сама на себя: ${[...seen, name].join(' → ')}`)\n\n return resolveRole(tokens, reference[1], [...seen, name])\n}\n","import { grDerivedTokens, grThemeTokens } from '../tokens/generated'\nimport { contrast, deltaE, mixSrgb } from './color'\nimport type { GrTheme } from './extendTheme'\nimport { resolveRole, type GrThemeTokens } from './roles'\n\nexport interface GrThemeIssue {\n kind: 'contrast' | 'distance'\n /** Роль, из-за которой всё встало. */\n token: string\n /** На чём проверяли: поверхность либо второй тон. */\n against: string\n actual: number\n expected: number\n message: string\n}\n\n/**\n * AA для обычного текста.\n *\n * Порога для самой заливки здесь нет намеренно: `--gr-success` в светлой теме\n * даёт 2.42:1 к фону, и это не дефект — информацию бейдж несёт текстом `-fg`\n * поверх заливки, а не самой заливкой. Правило «≥3:1 к фону» уронило бы\n * встроенные темы пакета, то есть проверяло бы не то, о чём договаривались.\n */\nconst AA_TEXT = 4.5\n/** Порог заметности ΔE: ниже — для глаза один цвет, каким бы разным ни был hex. */\nconst NOTICEABLE = 2.3\n\n/**\n * Тона, выведенные из данных, а не списком: тон — это роль, у которой есть\n * пара `-fg`. Новый тон пакета попадает под проверки сам.\n */\nfunction toneNames(): string[] {\n const names = new Set(grThemeTokens.map(token => token.name))\n\n return [...names]\n .filter(name => names.has(`${name}-fg`))\n .map(name => name.replace('--gr-', ''))\n}\n\nfunction derivedOf(role: string): { amount: number, mixWith: string }[] {\n return grDerivedTokens\n .filter(token => token.base === role)\n .map(token => ({ amount: token.amount, mixWith: token.mixWith }))\n}\n\nexport function validateTheme(theme: GrTheme | { name: string, tokens: GrThemeTokens }): GrThemeIssue[] {\n const { tokens } = theme\n const issues: GrThemeIssue[] = []\n\n const value = (role: string): string | null => resolveRole(tokens, role)\n\n function requireContrast(token: string, against: string, expected: number, what: string): void {\n const [foreground, background] = [value(token), value(against)]\n // Роль не разворачивается в цвет (например `rgb(… / .45)` у подложки) —\n // считать нечего: молчаливая «проверка» хуже её отсутствия.\n if (!foreground || !background) return\n\n const actual = contrast(foreground, background)\n if (actual >= expected) return\n\n issues.push({\n kind: 'contrast',\n token,\n against,\n actual: Math.round(actual * 100) / 100,\n expected,\n message: `${what}: ${token} на ${against} даёт ${actual.toFixed(2)}:1 при пороге ${expected}:1`,\n })\n }\n\n /** Заливка в hover/active уходит темнее — текст на ней может провалиться именно там. */\n function requireContrastWithStates(fgRole: string, fillRole: string, what: string): void {\n requireContrast(fgRole, fillRole, AA_TEXT, what)\n\n const fill = value(fillRole)\n const foreground = value(fgRole)\n if (!fill || !foreground) return\n\n for (const { amount, mixWith } of derivedOf(fillRole)) {\n const mixed = value(mixWith)\n if (!mixed) continue\n\n const state = contrast(foreground, mixSrgb(fill, mixed, amount))\n if (state >= AA_TEXT) continue\n\n issues.push({\n kind: 'contrast',\n token: fgRole,\n against: `${fillRole} (${amount}%)`,\n actual: Math.round(state * 100) / 100,\n expected: AA_TEXT,\n message: `${what}: ${fgRole} на состоянии ${fillRole} (${amount}%) даёт ${state.toFixed(2)}:1 при пороге ${AA_TEXT}:1`,\n })\n }\n }\n\n // Основной текст — только на поверхностях БЕЗ собственной пары `-fg`.\n // У карточки, поповера и сайдбара она есть, и проверяется ниже вместе с\n // тонами: сайдбар вправе быть инвертированным (тёмная панель в светлой теме),\n // и требовать на нём общий `--gr-fg` значило бы запретить это.\n const withOwnFg = new Set(toneNames().map(tone => `--gr-${tone}`))\n\n for (const surface of ['--gr-bg', '--gr-card', '--gr-popover', '--gr-sidebar']) {\n if (withOwnFg.has(surface)) continue\n\n requireContrast('--gr-fg', surface, AA_TEXT, 'основной текст')\n }\n\n for (const surface of ['--gr-bg', '--gr-card', '--gr-muted', '--gr-secondary'])\n requireContrast('--gr-muted-fg', surface, AA_TEXT, 'вторичный текст')\n\n for (const tone of toneNames()) {\n const fill = `--gr-${tone}`\n\n requireContrastWithStates(`${fill}-fg`, fill, `текст на заливке ${tone}`)\n\n // Состояния solid — свои роли темы, а не производные формулой, поэтому\n // текст на них проверяется отдельно: у темы с нуля это единственная защита.\n for (const state of ['-hover', '-active']) {\n if (tokens[`${fill}${state}`] === undefined) continue\n\n requireContrast(`${fill}-fg`, `${fill}${state}`, AA_TEXT, `текст на состоянии ${tone}${state}`)\n }\n\n if (tokens[`${fill}-text`] !== undefined) {\n requireContrast(`${fill}-text`, `${fill}-light`, AA_TEXT, `текст тона ${tone}`)\n requireContrast(`${fill}-text`, '--gr-bg', AA_TEXT, `текст тона ${tone}`)\n requireContrast(`${fill}-text`, '--gr-card', AA_TEXT, `текст тона ${tone}`)\n }\n }\n\n // Ловушка №5: два тона в двух шагах друг от друга. Пакет наступил на это сам —\n // `info` был индиго рядом с `primary`, и ссылки обоих тонов красились одинаково.\n const distinct = ['primary', 'success', 'warning', 'danger', 'info', 'slate', 'azure']\n\n for (let i = 0; i < distinct.length; i += 1) {\n for (let j = i + 1; j < distinct.length; j += 1) {\n const [first, second] = [`--gr-${distinct[i]}`, `--gr-${distinct[j]}`]\n const [firstValue, secondValue] = [value(first), value(second)]\n if (!firstValue || !secondValue) continue\n\n const distance = deltaE(firstValue, secondValue)\n if (distance >= NOTICEABLE) continue\n\n issues.push({\n kind: 'distance',\n token: first,\n against: second,\n actual: Math.round(distance * 100) / 100,\n expected: NOTICEABLE,\n message: `тона неразличимы: ΔE между ${first} и ${second} равно ${distance.toFixed(2)} при пороге ${NOTICEABLE}`,\n })\n }\n }\n\n return issues\n}\n","import { grComponentTokens, grDerivedTokens, grThemeTokens } from '../tokens/generated'\nimport type { GrThemeName } from '../tokens/types'\nimport { mixSrgb } from './color'\nimport { resolveRole, themeRoleNames, type GrThemeTokens } from './roles'\nimport { validateTheme, type GrThemeIssue } from './validate'\n\nexport interface GrTheme {\n name: string\n /** Селектор, под которым тема объявлена: по умолчанию `[data-theme='<name>']`. */\n selector: string\n /** Полный набор ролей: своё поверх базы. */\n tokens: GrThemeTokens\n /** Покомпонентные токены темы, если заданы. */\n componentTokens: GrThemeTokens\n /** Готовый CSS, включая фолбэк производных для браузеров без `color-mix`. */\n css: string\n}\n\nexport interface ExtendThemeOptions {\n name: string\n /** Готовая тема пакета, чужая тема или просто набор ролей. */\n base: GrThemeName | GrTheme | GrThemeTokens\n selector?: string\n /** Что меняем. Всё, чего здесь нет, приходит из базы. */\n tokens?: GrThemeTokens\n /**\n * Покомпонентные токены (`--gr-button-primary-bg`) — у них своя природа:\n * пакет держит для них отдельный слой и **не** наследует их между темами.\n * Поэтому они не достраиваются из базы, а просто едут в тот же селектор:\n * заданы — переопределены, не заданы — работает дефолт компонента.\n */\n componentTokens?: GrThemeTokens\n /**\n * Проверка контраста и различимости тонов перед выдачей. Включена: тема,\n * которая не читается, — это дефект, и узнать о нём на сборке дешевле, чем от\n * пользователя. Выключать осознанно, для заведомо декоративных тем.\n */\n validate?: boolean\n}\n\nexport class GrThemeError extends Error {\n issues: GrThemeIssue[]\n\n constructor(name: string, issues: GrThemeIssue[]) {\n super([\n `тема \"${name}\" не проходит проверку:`,\n ...issues.map(issue => ` • ${issue.message}`),\n ].join('\\n'))\n\n this.name = 'GrThemeError'\n this.issues = issues\n }\n}\n\nfunction baseTokens(base: ExtendThemeOptions['base']): GrThemeTokens {\n if (typeof base === 'string') {\n const known = ['light', 'dark']\n if (!known.includes(base))\n throw new Error(`неизвестная базовая тема \"${base}\"; встроенные: ${known.join(', ')}`)\n\n return Object.fromEntries(grThemeTokens.map(token => [token.name, token.values[base]]))\n }\n\n return 'tokens' in base ? { ...(base as GrTheme).tokens } : { ...base }\n}\n\nfunction renderDeclarations(tokens: GrThemeTokens, indent: string): string[] {\n return grThemeTokens.map(token => `${indent}${token.name}: ${tokens[token.name]};`)\n}\n\nfunction renderComponentDeclarations(tokens: GrThemeTokens, indent: string): string[] {\n const names = Object.keys(tokens)\n if (names.length === 0) return []\n\n return ['', `${indent}/* Покомпонентные токены темы. */`, ...names.map(name => `${indent}${name}: ${tokens[name]};`)]\n}\n\n/**\n * Фолбэк производных состояний для браузеров без `color-mix`.\n *\n * Без него тема наследует фолбэки из `:root`, то есть чужие: hover у кастомной\n * тёмной темы окажется от светлой. Формула та же, что в `tokens.css`, — считает\n * её общая математика (`color.ts`), поэтому разойтись с живым `color-mix` не\n * может.\n */\nfunction renderFallback(tokens: GrThemeTokens, selector: string): string[] {\n const lines = [\n '',\n '@supports not (color: color-mix(in srgb, #000 50%, #fff)) {',\n ` ${selector} {`,\n ]\n\n for (const token of grDerivedTokens) {\n const base = resolveRole(tokens, token.base)\n const mixWith = resolveRole(tokens, token.mixWith)\n\n // Роль ссылается не на цвет (например на `var()` вне темы) — фолбэк для неё\n // посчитать нечем, и выдумывать значение хуже, чем его не давать.\n if (!base || !mixWith) continue\n\n lines.push(` ${token.name}: ${mixSrgb(base, mixWith, token.amount)};`)\n }\n\n lines.push(' }', '}')\n\n return lines\n}\n\nexport function renderThemeCss(theme: Pick<GrTheme, 'name' | 'selector' | 'tokens'> & Partial<Pick<GrTheme, 'componentTokens'>>): string {\n return [\n `/* Тема \"${theme.name}\" собрана из @feugene/granularity/theme — правки здесь потеряются. */`,\n `${theme.selector} {`,\n ...renderDeclarations(theme.tokens, ' '),\n ...renderComponentDeclarations(theme.componentTokens ?? {}, ' '),\n '}',\n ...renderFallback(theme.tokens, theme.selector),\n '',\n ].join('\\n')\n}\n\ninterface BuildOptions {\n name: string\n tokens: GrThemeTokens\n componentTokens: GrThemeTokens\n selector: string\n validate: boolean\n /** Что сказать, если ролей не хватает: у темы с базой и без базы причины разные. */\n explainMissing: (missing: string[]) => string\n}\n\nfunction buildTheme(options: BuildOptions): GrTheme {\n const { name, tokens, componentTokens, selector, validate, explainMissing } = options\n\n const known = new Set(themeRoleNames())\n const unknown = Object.keys(tokens).filter(role => !known.has(role))\n\n if (unknown.length > 0) {\n throw new Error(\n `тема \"${name}\" объявляет роли, которых у пакета нет: ${unknown.join(', ')}.\\n`\n + 'Примитивы (`--gr-space-*`, `--gr-radius-*`) и производные (`-hover`/`-active`) темой не задаются: '\n + 'первые от темы не зависят, вторые выводятся формулой.',\n )\n }\n\n const knownComponent = new Set(grComponentTokens.map(token => token.name))\n const unknownComponent = Object.keys(componentTokens).filter(token => !knownComponent.has(token))\n\n if (unknownComponent.length > 0)\n throw new Error(`тема \"${name}\" объявляет покомпонентные токены, которых у пакета нет: ${unknownComponent.join(', ')}`)\n\n const missing = themeRoleNames().filter(role => tokens[role] === undefined)\n if (missing.length > 0) throw new Error(explainMissing(missing))\n\n const theme: GrTheme = {\n name,\n selector,\n tokens,\n componentTokens,\n css: renderThemeCss({ name, selector, tokens, componentTokens }),\n }\n\n if (validate) {\n const issues = validateTheme(theme)\n if (issues.length > 0) throw new GrThemeError(name, issues)\n }\n\n return theme\n}\n\n/**\n * Тема поверх готовой: объявляем только то, что меняем.\n *\n * Роль, которую тема не объявила, наследуется не от «своей» базы, а из `:root`,\n * то есть из светлой темы: тёмная тема с забытой ролью получает светлое пятно.\n * Поэтому здесь тема достраивается до полного набора **всех** ролей пакета — и\n * роль, добавленная пакетом завтра, приедет в неё сама, без правок потребителя.\n */\nexport function extendTheme(options: ExtendThemeOptions): GrTheme {\n const {\n name,\n base,\n tokens = {},\n componentTokens = {},\n selector = `[data-theme='${name}']`,\n validate = true,\n } = options\n\n return buildTheme({\n name,\n tokens: { ...baseTokens(base), ...tokens },\n componentTokens,\n selector,\n validate,\n explainMissing: missing => `база темы \"${name}\" не даёт ролей: ${missing.join(', ')}`,\n })\n}\n\n/**\n * Тема с нуля: без базы, все роли свои.\n *\n * «Без базы» — это не «ни от чего не наследуется»: в CSS так нельзя. Роль,\n * которую тема не объявила, придёт из `:root`, а `:root` — это **светлая тема\n * пакета**. Независимой тема становится ровно тогда, когда объявляет все роли\n * сама, и здесь это проверяется: не хватает — сборка падает со списком, а не\n * молча подмешивает чужую палитру.\n *\n * Цена честная и её видно: `extendTheme` получает новую роль пакета\n * автоматически, а тема с нуля — упадёт на следующей сборке и потребует решения.\n * Это и есть смысл выбора: полный контроль в обмен на сопровождение.\n */\nexport function createTheme(options: Omit<ExtendThemeOptions, 'base'>): GrTheme {\n const {\n name,\n tokens = {},\n componentTokens = {},\n selector = `[data-theme='${name}']`,\n validate = true,\n } = options\n\n return buildTheme({\n name,\n tokens,\n componentTokens,\n selector,\n validate,\n explainMissing: missing => [\n `тема \"${name}\" объявлена без базы, но не задаёт ${missing.length} ролей:`,\n ` ${missing.join(', ')}`,\n 'Незаявленная роль придёт не «ниоткуда», а из `:root` — то есть из светлой темы пакета.',\n 'Задайте их, либо соберите тему поверх готовой: `extendTheme({ base: \\'light\\' | \\'dark\\', tokens })`.',\n ].join('\\n'),\n })\n}\n","import { grThemeTokens } from '../tokens/generated'\nimport type { GrThemeName } from '../tokens/types'\nimport { contrast, mixSrgb, parseHex } from './color'\nimport { resolveRole, type GrThemeTokens } from './roles'\n\nexport type ToneRole = 'fill' | 'solid' | 'light' | 'text'\n\nexport interface ToneOptions {\n /** Тема, в которой тон будет жить: от неё зависят фон, текст и направление сдвигов. */\n base: GrThemeName | { tokens: GrThemeTokens } | GrThemeTokens\n /**\n * Что выводить. По умолчанию — ровно те роли, которые у этого тона есть **в\n * реестре пакета**: у `--gr-accent` это только `-fg`, у `--gr-primary` нет\n * `-light`. Для имени, которого в реестре нет, выводится полная семья.\n */\n roles?: ToneRole[]\n}\n\nconst AA_TEXT = 4.5\n/** Шаг подбора: 100 шагов по 1% дают точность, которой глаз не различает. */\nconst STEP = 1\n/**\n * Насколько темнеет solid в hover и active.\n *\n * Обычные состояния пакет считает подмесом `--gr-fg` (`tokens/derived.json`), но\n * solid — кнопочная заливка: в светлой теме `--gr-fg` тёмный, в тёмной светлый,\n * и вторая уводила бы кнопку в сторону текста, то есть высветляла. Кнопка при\n * нажатии темнеет в обеих темах, поэтому здесь подмес чёрного.\n *\n * Значения встроенных тем взяты из шкал палитры и лежат в диапазоне 81–99%:\n * `tone` даёт согласованную семью, а не копию пакетных цветов.\n */\nconst SOLID_HOVER = 92\nconst SOLID_ACTIVE = 84\n\nexport class GrToneError extends Error {\n constructor(role: string, actual: number, expected: number) {\n super(\n `${role}: не удалось выйти на контраст ${expected}:1, максимум ${actual.toFixed(2)}:1.\\n`\n + 'Возьмите семя дальше от фона темы либо задайте роль явно.',\n )\n\n this.name = 'GrToneError'\n }\n}\n\n/**\n * Роли, которые у этого тона есть в реестре. Лишняя роль — не «запас», а ошибка\n * сборки («роли, которых у пакета нет»), поэтому набор берётся из данных.\n */\nfunction rolesOf(name: string): ToneRole[] {\n const known = new Set(grThemeTokens.map(token => token.name))\n const prefix = `--gr-${name}`\n\n if (!known.has(prefix)) return ['fill', 'solid', 'light', 'text']\n\n return ([\n ['fill', prefix],\n ['solid', `${prefix}-solid`],\n ['light', `${prefix}-light`],\n ['text', `${prefix}-text`],\n ] as const)\n .filter(([, role]) => known.has(role))\n .map(([kind]) => kind)\n}\n\nfunction baseTokensOf(base: ToneOptions['base']): GrThemeTokens {\n if (typeof base === 'string')\n return Object.fromEntries(grThemeTokens.map(token => [token.name, token.values[base]]))\n\n return 'tokens' in base ? (base as { tokens: GrThemeTokens }).tokens : base\n}\n\nfunction requireColor(tokens: GrThemeTokens, role: string): string {\n const value = resolveRole(tokens, role)\n if (!value) throw new Error(`тон выводится от темы, а роль ${role} в ней не цвет`)\n\n return value\n}\n\n/**\n * Сдвигает цвет к цели, пока не наберётся нужный контраст с эталоном.\n * Возвращает первый годный шаг — самый близкий к исходному цвету.\n */\nfunction shiftUntil(from: string, towards: string, against: string, expected: number, role: string): string {\n let best = { value: from, ratio: contrast(from, against) }\n\n for (let amount = 100; amount >= 0; amount -= STEP) {\n const candidate = mixSrgb(from, towards, amount)\n const ratio = contrast(candidate, against)\n\n if (ratio >= expected) return candidate\n if (ratio > best.ratio) best = { value: candidate, ratio }\n }\n\n throw new GrToneError(role, best.ratio, expected)\n}\n\n/** Тёмная ли тема: фон темнее текста. Отсюда направление всех сдвигов. */\nfunction isDark(tokens: GrThemeTokens): boolean {\n const [bg, fg] = [requireColor(tokens, '--gr-bg'), requireColor(tokens, '--gr-fg')]\n const luminanceOf = (hex: string): number => parseHex(hex).reduce((sum, channel) => sum + channel, 0)\n\n return luminanceOf(bg) < luminanceOf(fg)\n}\n\n/**\n * Семья ролей тона из одного цвета.\n *\n * Без неё композиция снимает только объём работы: перекрасив `--gr-success`, вы\n * оставляете `-light`, `-text` и `-solid*` от базовой темы, и они расходятся с\n * новым тоном по контрасту — ловушка №3 из `docs/theming.md`. Правила вывода\n * взяты оттуда же (§«Суффиксы ролей»), пороги проверяются на каждом шаге:\n * не вышло — падаем с именем роли, а не отдаём нечитаемое.\n *\n * ```ts\n * extendTheme({ name: 'ocean', base: 'dark', tokens: { ...tone('success', '#3ddc97', { base: 'dark' }) } })\n * ```\n */\nexport function tone(name: string, seed: string, options: ToneOptions): GrThemeTokens {\n const tokens = baseTokensOf(options.base)\n const roles = options.roles ?? rolesOf(name)\n\n const bg = requireColor(tokens, '--gr-bg')\n const fg = requireColor(tokens, '--gr-fg')\n const card = requireColor(tokens, '--gr-card')\n const dark = isDark(tokens)\n\n const result: GrThemeTokens = {}\n const prefix = `--gr-${name}`\n\n if (roles.includes('fill')) {\n result[prefix] = seed\n\n // Текст на заливке — тот из полюсов темы, что читается лучше. Проверяем\n // не только базу: hover/active уводят заливку к `--gr-fg`, и провалиться\n // текст может именно там (ловушка №2).\n const candidates = [fg, bg]\n const scoreOf = (candidate: string): number => Math.min(\n contrast(candidate, seed),\n contrast(candidate, mixSrgb(seed, fg, 92)),\n contrast(candidate, mixSrgb(seed, fg, 84)),\n )\n\n const [best] = [...candidates].sort((left, right) => scoreOf(right) - scoreOf(left))\n if (scoreOf(best) < AA_TEXT) throw new GrToneError(`${prefix}-fg`, scoreOf(best), AA_TEXT)\n\n result[`${prefix}-fg`] = best\n }\n\n if (roles.includes('solid')) {\n // Solid — кнопочный вес, и он одинаков в обеих темах: тёмная заливка со\n // светлым текстом. Это не симметрия ради симметрии — кнопки всех тонов\n // обязаны выглядеть одной семьёй (docs/theming.md, «Зачем -solid»), а\n // светлая кнопка в тёмной теме читалась бы как другой компонент.\n // Отсюда же направление состояний: заливка темнеет при наведении и нажатии.\n const solidFg = dark ? fg : '#ffffff'\n\n const solid = shiftUntil(seed, '#000000', solidFg, AA_TEXT, `${prefix}-solid`)\n\n result[`${prefix}-solid`] = solid\n result[`${prefix}-solid-fg`] = solidFg\n\n // Состояния solid — темовые роли, а не производные: `color-mix` их не\n // считает, и без них тема с нуля не соберётся вовсе.\n for (const [suffix, amount] of [['-solid-hover', SOLID_HOVER], ['-solid-active', SOLID_ACTIVE]] as const) {\n const state = mixSrgb(solid, '#000000', amount)\n const ratio = contrast(solidFg, state)\n\n if (ratio < AA_TEXT) throw new GrToneError(`${prefix}${suffix}`, ratio, AA_TEXT)\n\n result[`${prefix}${suffix}`] = state\n }\n }\n\n if (roles.includes('light')) {\n // Мягкая подложка: тон, подмешанный в поверхность карточки.\n result[`${prefix}-light`] = mixSrgb(seed, card, dark ? 22 : 14)\n }\n\n if (roles.includes('text')) {\n const light = result[`${prefix}-light`] ?? mixSrgb(seed, card, dark ? 22 : 14)\n\n // Текст тона живёт и на мягкой подложке, и на фоне страницы, и на карточке —\n // сдвигаем до худшего из трёх.\n let value = seed\n for (const surface of [light, bg, card])\n value = shiftUntil(value, fg, surface, AA_TEXT, `${prefix}-text`)\n\n result[`${prefix}-text`] = value\n }\n\n return result\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"theme.js","names":[],"sources":["../src/theme/color.ts","../src/theme/roles.ts","../src/theme/validate.ts","../src/theme/extendTheme.ts","../src/theme/tone.ts"],"sourcesContent":["/**\n * Цветовая математика пакета — один источник на всех.\n *\n * Одну и ту же формулу считают три разных потребителя: генератор токенов\n * (фолбэки `@supports not (color-mix)`), композиция тем (`extendTheme`, `tone`)\n * и гейты контраста. Расхождение здесь не абстрактно: фолбэки уже жили\n * отдельной копией из сорока хексов, которые обязаны были совпадать с живым\n * `color-mix` до байта, и не совпадали.\n *\n * Модуль читает и генератор (`scripts/generate-tokens.mjs`, запускается\n * `node --experimental-strip-types`), поэтому синтаксис здесь только стираемый:\n * ни `enum`, ни `namespace`, ни параметров-свойств в конструкторах.\n */\n\nexport type Rgb = [number, number, number]\n\nexport function parseHex(value: string): Rgb {\n const match = value.trim().match(/^#([\\da-f]{3}|[\\da-f]{6})$/i)\n\n if (!match)\n throw new Error(`ожидался hex-цвет, получено: ${value}`)\n\n const hex = match[1].length === 3\n ? match[1].split('').map(char => char + char).join('')\n : match[1]\n\n return [0, 2, 4].map(offset => Number.parseInt(hex.slice(offset, offset + 2), 16)) as Rgb\n}\n\nexport function toHex(channels: Rgb): string {\n return `#${channels\n .map(channel => Math.round(Math.min(255, Math.max(0, channel))).toString(16).padStart(2, '0'))\n .join('')}`\n}\n\n/**\n * `color-mix(in srgb, base <amount>%, other)` для непрозрачных цветов — это\n * линейная интерполяция в gamma-кодированном sRGB, то есть ровно то, что делает\n * браузер. Поэтому посчитанный здесь фолбэк совпадает с живым `color-mix`.\n */\nexport function mixSrgb(baseHex: string, otherHex: string, amount: number): string {\n const base = parseHex(baseHex)\n const other = parseHex(otherHex)\n const ratio = amount / 100\n\n return toHex(base.map((channel, index) => channel * ratio + other[index] * (1 - ratio)) as Rgb)\n}\n\nexport function luminance(color: string | Rgb): number {\n const channels = (typeof color === 'string' ? parseHex(color) : color).map((channel) => {\n const normalized = channel / 255\n\n return normalized <= 0.03928 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4\n })\n\n return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]\n}\n\n/** Отношение контраста по WCAG 2.1: от 1 (одинаковые) до 21 (чёрное на белом). */\nexport function contrast(foreground: string | Rgb, background: string | Rgb): number {\n const first = luminance(foreground)\n const second = luminance(background)\n const [lighter, darker] = first > second ? [first, second] : [second, first]\n\n return (lighter + 0.05) / (darker + 0.05)\n}\n\nfunction toLab(color: string | Rgb): [number, number, number] {\n const [red, green, blue] = (typeof color === 'string' ? parseHex(color) : color).map((channel) => {\n const normalized = channel / 255\n\n return normalized <= 0.04045 ? normalized / 12.92 : ((normalized + 0.055) / 1.055) ** 2.4\n })\n\n // sRGB → XYZ (D65) → Lab, точки белого из CIE.\n const x = (red * 0.4124 + green * 0.3576 + blue * 0.1805) / 0.95047\n const y = red * 0.2126 + green * 0.7152 + blue * 0.0722\n const z = (red * 0.0193 + green * 0.1192 + blue * 0.9505) / 1.08883\n\n const f = (value: number): number => (value > 0.008856 ? value ** (1 / 3) : 7.787 * value + 16 / 116)\n const [fx, fy, fz] = [f(x), f(y), f(z)]\n\n return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)]\n}\n\n/**\n * Воспринимаемое расстояние между цветами (ΔE, CIE76).\n *\n * Контраст отвечает на вопрос «читается ли текст», а этот — на вопрос\n * «различит ли человек два тона рядом». Порог заметности около 2.3; всё, что\n * ниже, для глаза один цвет, каким бы разным ни выглядел hex.\n */\nexport function deltaE(first: string | Rgb, second: string | Rgb): number {\n const [firstLab, secondLab] = [toLab(first), toLab(second)]\n\n return Math.hypot(...firstLab.map((value, index) => value - secondLab[index]))\n}\n\n/** Цвет — это hex, а не `var()`/`rgb()`: производные и контраст считаются только по нему. */\nexport function isHex(value: string): boolean {\n return /^#(?:[\\da-f]{3}|[\\da-f]{6})$/i.test(value.trim())\n}\n","import { grThemeTokens } from '../tokens/generated'\nimport { isHex } from './color'\n\n/** Значения ролей темы: `--gr-bg` → `#041e2b`. */\nexport type GrThemeTokens = Record<string, string>\n\n/** Роли, известные пакету, в порядке объявления. */\nexport function themeRoleNames(): string[] {\n return grThemeTokens.map(token => token.name)\n}\n\n/**\n * Значение роли, годное для арифметики.\n *\n * Роль вправе ссылаться на другую (`--gr-invalid-brd: var(--gr-danger)`) — такую\n * ссылку разворачиваем, иначе фолбэк и проверки считать не из чего. Всё, что не\n * разворачивается в hex (`rgb(… / .45)` у подложки, `var()` за пределы темы),\n * возвращается как `null`: посчитать нельзя, и выдумывать не надо.\n *\n * Цикл рвём с ошибкой: тема потребителя вправе ошибиться, и упасть надо с\n * именами ролей, а не переполнением стека.\n */\nexport function resolveRole(tokens: GrThemeTokens, name: string, seen: string[] = []): string | null {\n const value = tokens[name]\n if (value === undefined)\n return null\n if (isHex(value))\n return value\n\n const reference = value.trim().match(/^var\\(\\s*(--[\\w-]+)\\s*\\)$/)\n if (!reference)\n return null\n\n if (seen.includes(name))\n throw new Error(`роль ${name} ссылается сама на себя: ${[...seen, name].join(' → ')}`)\n\n return resolveRole(tokens, reference[1], [...seen, name])\n}\n","import { grDerivedTokens, grThemeTokens } from '../tokens/generated'\nimport { contrast, deltaE, mixSrgb } from './color'\nimport type { GrTheme } from './extendTheme'\nimport { resolveRole, type GrThemeTokens } from './roles'\n\nexport interface GrThemeIssue {\n kind: 'contrast' | 'distance'\n /** Роль, из-за которой всё встало. */\n token: string\n /** На чём проверяли: поверхность либо второй тон. */\n against: string\n actual: number\n expected: number\n message: string\n}\n\n/**\n * AA для обычного текста.\n *\n * Порога для самой заливки здесь нет намеренно: `--gr-success` в светлой теме\n * даёт 2.42:1 к фону, и это не дефект — информацию бейдж несёт текстом `-fg`\n * поверх заливки, а не самой заливкой. Правило «≥3:1 к фону» уронило бы\n * встроенные темы пакета, то есть проверяло бы не то, о чём договаривались.\n */\nconst AA_TEXT = 4.5\n/** Порог заметности ΔE: ниже — для глаза один цвет, каким бы разным ни был hex. */\nconst NOTICEABLE = 2.3\n\n/**\n * Тона, выведенные из данных, а не списком: тон — это роль, у которой есть\n * пара `-fg`. Новый тон пакета попадает под проверки сам.\n */\nfunction toneNames(): string[] {\n const names = new Set(grThemeTokens.map(token => token.name))\n\n return [...names]\n .filter(name => names.has(`${name}-fg`))\n .map(name => name.replace('--gr-', ''))\n}\n\nfunction derivedOf(role: string): { amount: number, mixWith: string }[] {\n return grDerivedTokens\n .filter(token => token.base === role)\n .map(token => ({ amount: token.amount, mixWith: token.mixWith }))\n}\n\nexport function validateTheme(theme: GrTheme | { name: string, tokens: GrThemeTokens }): GrThemeIssue[] {\n const { tokens } = theme\n const issues: GrThemeIssue[] = []\n\n const value = (role: string): string | null => resolveRole(tokens, role)\n\n function requireContrast(token: string, against: string, expected: number, what: string): void {\n const [foreground, background] = [value(token), value(against)]\n // Роль не разворачивается в цвет (например `rgb(… / .45)` у подложки) —\n // считать нечего: молчаливая «проверка» хуже её отсутствия.\n if (!foreground || !background)\n return\n\n const actual = contrast(foreground, background)\n if (actual >= expected)\n return\n\n issues.push({\n kind: 'contrast',\n token,\n against,\n actual: Math.round(actual * 100) / 100,\n expected,\n message: `${what}: ${token} на ${against} даёт ${actual.toFixed(2)}:1 при пороге ${expected}:1`,\n })\n }\n\n /** Заливка в hover/active уходит темнее — текст на ней может провалиться именно там. */\n function requireContrastWithStates(fgRole: string, fillRole: string, what: string): void {\n requireContrast(fgRole, fillRole, AA_TEXT, what)\n\n const fill = value(fillRole)\n const foreground = value(fgRole)\n if (!fill || !foreground)\n return\n\n for (const { amount, mixWith } of derivedOf(fillRole)) {\n const mixed = value(mixWith)\n if (!mixed)\n continue\n\n const state = contrast(foreground, mixSrgb(fill, mixed, amount))\n if (state >= AA_TEXT)\n continue\n\n issues.push({\n kind: 'contrast',\n token: fgRole,\n against: `${fillRole} (${amount}%)`,\n actual: Math.round(state * 100) / 100,\n expected: AA_TEXT,\n message: `${what}: ${fgRole} на состоянии ${fillRole} (${amount}%) даёт ${state.toFixed(2)}:1 при пороге ${AA_TEXT}:1`,\n })\n }\n }\n\n // Основной текст — только на поверхностях БЕЗ собственной пары `-fg`.\n // У карточки, поповера и сайдбара она есть, и проверяется ниже вместе с\n // тонами: сайдбар вправе быть инвертированным (тёмная панель в светлой теме),\n // и требовать на нём общий `--gr-fg` значило бы запретить это.\n const withOwnFg = new Set(toneNames().map(tone => `--gr-${tone}`))\n\n for (const surface of ['--gr-bg', '--gr-card', '--gr-popover', '--gr-sidebar']) {\n if (withOwnFg.has(surface))\n continue\n\n requireContrast('--gr-fg', surface, AA_TEXT, 'основной текст')\n }\n\n for (const surface of ['--gr-bg', '--gr-card', '--gr-muted', '--gr-secondary'])\n requireContrast('--gr-muted-fg', surface, AA_TEXT, 'вторичный текст')\n\n for (const tone of toneNames()) {\n const fill = `--gr-${tone}`\n\n requireContrastWithStates(`${fill}-fg`, fill, `текст на заливке ${tone}`)\n\n // Состояния solid — свои роли темы, а не производные формулой, поэтому\n // текст на них проверяется отдельно: у темы с нуля это единственная защита.\n for (const state of ['-hover', '-active']) {\n if (tokens[`${fill}${state}`] === undefined)\n continue\n\n requireContrast(`${fill}-fg`, `${fill}${state}`, AA_TEXT, `текст на состоянии ${tone}${state}`)\n }\n\n if (tokens[`${fill}-text`] !== undefined) {\n requireContrast(`${fill}-text`, `${fill}-light`, AA_TEXT, `текст тона ${tone}`)\n requireContrast(`${fill}-text`, '--gr-bg', AA_TEXT, `текст тона ${tone}`)\n requireContrast(`${fill}-text`, '--gr-card', AA_TEXT, `текст тона ${tone}`)\n }\n }\n\n // Ловушка №5: два тона в двух шагах друг от друга. Пакет наступил на это сам —\n // `info` был индиго рядом с `primary`, и ссылки обоих тонов красились одинаково.\n const distinct = ['primary', 'success', 'warning', 'danger', 'info', 'slate', 'azure']\n\n for (let i = 0; i < distinct.length; i += 1) {\n for (let j = i + 1; j < distinct.length; j += 1) {\n const [first, second] = [`--gr-${distinct[i]}`, `--gr-${distinct[j]}`]\n const [firstValue, secondValue] = [value(first), value(second)]\n if (!firstValue || !secondValue)\n continue\n\n const distance = deltaE(firstValue, secondValue)\n if (distance >= NOTICEABLE)\n continue\n\n issues.push({\n kind: 'distance',\n token: first,\n against: second,\n actual: Math.round(distance * 100) / 100,\n expected: NOTICEABLE,\n message: `тона неразличимы: ΔE между ${first} и ${second} равно ${distance.toFixed(2)} при пороге ${NOTICEABLE}`,\n })\n }\n }\n\n return issues\n}\n","import { grComponentTokens, grDerivedTokens, grThemeTokens } from '../tokens/generated'\nimport type { GrThemeName } from '../tokens/types'\nimport { mixSrgb } from './color'\nimport { resolveRole, themeRoleNames, type GrThemeTokens } from './roles'\nimport { validateTheme, type GrThemeIssue } from './validate'\n\nexport interface GrTheme {\n name: string\n /** Селектор, под которым тема объявлена: по умолчанию `[data-theme='<name>']`. */\n selector: string\n /** Полный набор ролей: своё поверх базы. */\n tokens: GrThemeTokens\n /** Покомпонентные токены темы, если заданы. */\n componentTokens: GrThemeTokens\n /** Готовый CSS, включая фолбэк производных для браузеров без `color-mix`. */\n css: string\n}\n\nexport interface ExtendThemeOptions {\n name: string\n /** Готовая тема пакета, чужая тема или просто набор ролей. */\n base: GrThemeName | GrTheme | GrThemeTokens\n selector?: string\n /** Что меняем. Всё, чего здесь нет, приходит из базы. */\n tokens?: GrThemeTokens\n /**\n * Покомпонентные токены (`--gr-button-primary-bg`) — у них своя природа:\n * пакет держит для них отдельный слой и **не** наследует их между темами.\n * Поэтому они не достраиваются из базы, а просто едут в тот же селектор:\n * заданы — переопределены, не заданы — работает дефолт компонента.\n */\n componentTokens?: GrThemeTokens\n /**\n * Проверка контраста и различимости тонов перед выдачей. Включена: тема,\n * которая не читается, — это дефект, и узнать о нём на сборке дешевле, чем от\n * пользователя. Выключать осознанно, для заведомо декоративных тем.\n */\n validate?: boolean\n}\n\nexport class GrThemeError extends Error {\n issues: GrThemeIssue[]\n\n constructor(name: string, issues: GrThemeIssue[]) {\n super([\n `тема \"${name}\" не проходит проверку:`,\n ...issues.map(issue => ` • ${issue.message}`),\n ].join('\\n'))\n\n this.name = 'GrThemeError'\n this.issues = issues\n }\n}\n\nfunction baseTokens(base: ExtendThemeOptions['base']): GrThemeTokens {\n if (typeof base === 'string') {\n const known = ['light', 'dark']\n if (!known.includes(base))\n throw new Error(`неизвестная базовая тема \"${base}\"; встроенные: ${known.join(', ')}`)\n\n return Object.fromEntries(grThemeTokens.map(token => [token.name, token.values[base]]))\n }\n\n return 'tokens' in base ? { ...(base as GrTheme).tokens } : { ...base }\n}\n\nfunction renderDeclarations(tokens: GrThemeTokens, indent: string): string[] {\n return grThemeTokens.map(token => `${indent}${token.name}: ${tokens[token.name]};`)\n}\n\nfunction renderComponentDeclarations(tokens: GrThemeTokens, indent: string): string[] {\n const names = Object.keys(tokens)\n if (names.length === 0)\n return []\n\n return ['', `${indent}/* Покомпонентные токены темы. */`, ...names.map(name => `${indent}${name}: ${tokens[name]};`)]\n}\n\n/**\n * Фолбэк производных состояний для браузеров без `color-mix`.\n *\n * Без него тема наследует фолбэки из `:root`, то есть чужие: hover у кастомной\n * тёмной темы окажется от светлой. Формула та же, что в `tokens.css`, — считает\n * её общая математика (`color.ts`), поэтому разойтись с живым `color-mix` не\n * может.\n */\nfunction renderFallback(tokens: GrThemeTokens, selector: string): string[] {\n const lines = [\n '',\n '@supports not (color: color-mix(in srgb, #000 50%, #fff)) {',\n ` ${selector} {`,\n ]\n\n for (const token of grDerivedTokens) {\n const base = resolveRole(tokens, token.base)\n const mixWith = resolveRole(tokens, token.mixWith)\n\n // Роль ссылается не на цвет (например на `var()` вне темы) — фолбэк для неё\n // посчитать нечем, и выдумывать значение хуже, чем его не давать.\n if (!base || !mixWith)\n continue\n\n lines.push(` ${token.name}: ${mixSrgb(base, mixWith, token.amount)};`)\n }\n\n lines.push(' }', '}')\n\n return lines\n}\n\nexport function renderThemeCss(theme: Pick<GrTheme, 'name' | 'selector' | 'tokens'> & Partial<Pick<GrTheme, 'componentTokens'>>): string {\n return [\n `/* Тема \"${theme.name}\" собрана из @feugene/granularity/theme — правки здесь потеряются. */`,\n `${theme.selector} {`,\n ...renderDeclarations(theme.tokens, ' '),\n ...renderComponentDeclarations(theme.componentTokens ?? {}, ' '),\n '}',\n ...renderFallback(theme.tokens, theme.selector),\n '',\n ].join('\\n')\n}\n\ninterface BuildOptions {\n name: string\n tokens: GrThemeTokens\n componentTokens: GrThemeTokens\n selector: string\n validate: boolean\n /** Что сказать, если ролей не хватает: у темы с базой и без базы причины разные. */\n explainMissing: (missing: string[]) => string\n}\n\nfunction buildTheme(options: BuildOptions): GrTheme {\n const { name, tokens, componentTokens, selector, validate, explainMissing } = options\n\n const known = new Set(themeRoleNames())\n const unknown = Object.keys(tokens).filter(role => !known.has(role))\n\n if (unknown.length > 0) {\n throw new Error(\n `тема \"${name}\" объявляет роли, которых у пакета нет: ${unknown.join(', ')}.\\n`\n + 'Примитивы (`--gr-space-*`, `--gr-radius-*`) и производные (`-hover`/`-active`) темой не задаются: '\n + 'первые от темы не зависят, вторые выводятся формулой.',\n )\n }\n\n const knownComponent = new Set(grComponentTokens.map(token => token.name))\n const unknownComponent = Object.keys(componentTokens).filter(token => !knownComponent.has(token))\n\n if (unknownComponent.length > 0)\n throw new Error(`тема \"${name}\" объявляет покомпонентные токены, которых у пакета нет: ${unknownComponent.join(', ')}`)\n\n const missing = themeRoleNames().filter(role => tokens[role] === undefined)\n if (missing.length > 0)\n throw new Error(explainMissing(missing))\n\n const theme: GrTheme = {\n name,\n selector,\n tokens,\n componentTokens,\n css: renderThemeCss({ name, selector, tokens, componentTokens }),\n }\n\n if (validate) {\n const issues = validateTheme(theme)\n if (issues.length > 0)\n throw new GrThemeError(name, issues)\n }\n\n return theme\n}\n\n/**\n * Тема поверх готовой: объявляем только то, что меняем.\n *\n * Роль, которую тема не объявила, наследуется не от «своей» базы, а из `:root`,\n * то есть из светлой темы: тёмная тема с забытой ролью получает светлое пятно.\n * Поэтому здесь тема достраивается до полного набора **всех** ролей пакета — и\n * роль, добавленная пакетом завтра, приедет в неё сама, без правок потребителя.\n */\nexport function extendTheme(options: ExtendThemeOptions): GrTheme {\n const {\n name,\n base,\n tokens = {},\n componentTokens = {},\n selector = `[data-theme='${name}']`,\n validate = true,\n } = options\n\n return buildTheme({\n name,\n tokens: { ...baseTokens(base), ...tokens },\n componentTokens,\n selector,\n validate,\n explainMissing: missing => `база темы \"${name}\" не даёт ролей: ${missing.join(', ')}`,\n })\n}\n\n/**\n * Тема с нуля: без базы, все роли свои.\n *\n * «Без базы» — это не «ни от чего не наследуется»: в CSS так нельзя. Роль,\n * которую тема не объявила, придёт из `:root`, а `:root` — это **светлая тема\n * пакета**. Независимой тема становится ровно тогда, когда объявляет все роли\n * сама, и здесь это проверяется: не хватает — сборка падает со списком, а не\n * молча подмешивает чужую палитру.\n *\n * Цена честная и её видно: `extendTheme` получает новую роль пакета\n * автоматически, а тема с нуля — упадёт на следующей сборке и потребует решения.\n * Это и есть смысл выбора: полный контроль в обмен на сопровождение.\n */\nexport function createTheme(options: Omit<ExtendThemeOptions, 'base'>): GrTheme {\n const {\n name,\n tokens = {},\n componentTokens = {},\n selector = `[data-theme='${name}']`,\n validate = true,\n } = options\n\n return buildTheme({\n name,\n tokens,\n componentTokens,\n selector,\n validate,\n explainMissing: missing => [\n `тема \"${name}\" объявлена без базы, но не задаёт ${missing.length} ролей:`,\n ` ${missing.join(', ')}`,\n 'Незаявленная роль придёт не «ниоткуда», а из `:root` — то есть из светлой темы пакета.',\n 'Задайте их, либо соберите тему поверх готовой: `extendTheme({ base: \\'light\\' | \\'dark\\', tokens })`.',\n ].join('\\n'),\n })\n}\n","import { grThemeTokens } from '../tokens/generated'\nimport type { GrThemeName } from '../tokens/types'\nimport { contrast, mixSrgb, parseHex } from './color'\nimport { resolveRole, type GrThemeTokens } from './roles'\n\nexport type ToneRole = 'fill' | 'solid' | 'light' | 'text'\n\nexport interface ToneOptions {\n /** Тема, в которой тон будет жить: от неё зависят фон, текст и направление сдвигов. */\n base: GrThemeName | { tokens: GrThemeTokens } | GrThemeTokens\n /**\n * Что выводить. По умолчанию — ровно те роли, которые у этого тона есть **в\n * реестре пакета**: у `--gr-accent` это только `-fg`, у `--gr-primary` нет\n * `-light`. Для имени, которого в реестре нет, выводится полная семья.\n */\n roles?: ToneRole[]\n}\n\nconst AA_TEXT = 4.5\n/** Шаг подбора: 100 шагов по 1% дают точность, которой глаз не различает. */\nconst STEP = 1\n/**\n * Насколько темнеет solid в hover и active.\n *\n * Обычные состояния пакет считает подмесом `--gr-fg` (`tokens/derived.json`), но\n * solid — кнопочная заливка: в светлой теме `--gr-fg` тёмный, в тёмной светлый,\n * и вторая уводила бы кнопку в сторону текста, то есть высветляла. Кнопка при\n * нажатии темнеет в обеих темах, поэтому здесь подмес чёрного.\n *\n * Значения встроенных тем взяты из шкал палитры и лежат в диапазоне 81–99%:\n * `tone` даёт согласованную семью, а не копию пакетных цветов.\n */\nconst SOLID_HOVER = 92\nconst SOLID_ACTIVE = 84\n\nexport class GrToneError extends Error {\n constructor(role: string, actual: number, expected: number) {\n super(\n `${role}: не удалось выйти на контраст ${expected}:1, максимум ${actual.toFixed(2)}:1.\\n`\n + 'Возьмите семя дальше от фона темы либо задайте роль явно.',\n )\n\n this.name = 'GrToneError'\n }\n}\n\n/**\n * Роли, которые у этого тона есть в реестре. Лишняя роль — не «запас», а ошибка\n * сборки («роли, которых у пакета нет»), поэтому набор берётся из данных.\n */\nfunction rolesOf(name: string): ToneRole[] {\n const known = new Set(grThemeTokens.map(token => token.name))\n const prefix = `--gr-${name}`\n\n if (!known.has(prefix))\n return ['fill', 'solid', 'light', 'text']\n\n return ([\n ['fill', prefix],\n ['solid', `${prefix}-solid`],\n ['light', `${prefix}-light`],\n ['text', `${prefix}-text`],\n ] as const)\n .filter(([, role]) => known.has(role))\n .map(([kind]) => kind)\n}\n\nfunction baseTokensOf(base: ToneOptions['base']): GrThemeTokens {\n if (typeof base === 'string')\n return Object.fromEntries(grThemeTokens.map(token => [token.name, token.values[base]]))\n\n return 'tokens' in base ? (base as { tokens: GrThemeTokens }).tokens : base\n}\n\nfunction requireColor(tokens: GrThemeTokens, role: string): string {\n const value = resolveRole(tokens, role)\n if (!value)\n throw new Error(`тон выводится от темы, а роль ${role} в ней не цвет`)\n\n return value\n}\n\n/**\n * Сдвигает цвет к цели, пока не наберётся нужный контраст с эталоном.\n * Возвращает первый годный шаг — самый близкий к исходному цвету.\n */\nfunction shiftUntil(from: string, towards: string, against: string, expected: number, role: string): string {\n let best = { value: from, ratio: contrast(from, against) }\n\n for (let amount = 100; amount >= 0; amount -= STEP) {\n const candidate = mixSrgb(from, towards, amount)\n const ratio = contrast(candidate, against)\n\n if (ratio >= expected)\n return candidate\n if (ratio > best.ratio)\n best = { value: candidate, ratio }\n }\n\n throw new GrToneError(role, best.ratio, expected)\n}\n\n/** Тёмная ли тема: фон темнее текста. Отсюда направление всех сдвигов. */\nfunction isDark(tokens: GrThemeTokens): boolean {\n const [bg, fg] = [requireColor(tokens, '--gr-bg'), requireColor(tokens, '--gr-fg')]\n const luminanceOf = (hex: string): number => parseHex(hex).reduce((sum, channel) => sum + channel, 0)\n\n return luminanceOf(bg) < luminanceOf(fg)\n}\n\n/**\n * Семья ролей тона из одного цвета.\n *\n * Без неё композиция снимает только объём работы: перекрасив `--gr-success`, вы\n * оставляете `-light`, `-text` и `-solid*` от базовой темы, и они расходятся с\n * новым тоном по контрасту — ловушка №3 из `docs/theming.md`. Правила вывода\n * взяты оттуда же (§«Суффиксы ролей»), пороги проверяются на каждом шаге:\n * не вышло — падаем с именем роли, а не отдаём нечитаемое.\n *\n * ```ts\n * extendTheme({ name: 'ocean', base: 'dark', tokens: { ...tone('success', '#3ddc97', { base: 'dark' }) } })\n * ```\n */\nexport function tone(name: string, seed: string, options: ToneOptions): GrThemeTokens {\n const tokens = baseTokensOf(options.base)\n const roles = options.roles ?? rolesOf(name)\n\n const bg = requireColor(tokens, '--gr-bg')\n const fg = requireColor(tokens, '--gr-fg')\n const card = requireColor(tokens, '--gr-card')\n const dark = isDark(tokens)\n\n const result: GrThemeTokens = {}\n const prefix = `--gr-${name}`\n\n if (roles.includes('fill')) {\n result[prefix] = seed\n\n // Текст на заливке — тот из полюсов темы, что читается лучше. Проверяем\n // не только базу: hover/active уводят заливку к `--gr-fg`, и провалиться\n // текст может именно там (ловушка №2).\n const candidates = [fg, bg]\n const scoreOf = (candidate: string): number => Math.min(\n contrast(candidate, seed),\n contrast(candidate, mixSrgb(seed, fg, 92)),\n contrast(candidate, mixSrgb(seed, fg, 84)),\n )\n\n const [best] = [...candidates].sort((left, right) => scoreOf(right) - scoreOf(left))\n if (scoreOf(best) < AA_TEXT)\n throw new GrToneError(`${prefix}-fg`, scoreOf(best), AA_TEXT)\n\n result[`${prefix}-fg`] = best\n }\n\n if (roles.includes('solid')) {\n // Solid — кнопочный вес, и он одинаков в обеих темах: тёмная заливка со\n // светлым текстом. Это не симметрия ради симметрии — кнопки всех тонов\n // обязаны выглядеть одной семьёй (docs/theming.md, «Зачем -solid»), а\n // светлая кнопка в тёмной теме читалась бы как другой компонент.\n // Отсюда же направление состояний: заливка темнеет при наведении и нажатии.\n const solidFg = dark ? fg : '#ffffff'\n\n const solid = shiftUntil(seed, '#000000', solidFg, AA_TEXT, `${prefix}-solid`)\n\n result[`${prefix}-solid`] = solid\n result[`${prefix}-solid-fg`] = solidFg\n\n // Состояния solid — темовые роли, а не производные: `color-mix` их не\n // считает, и без них тема с нуля не соберётся вовсе.\n for (const [suffix, amount] of [['-solid-hover', SOLID_HOVER], ['-solid-active', SOLID_ACTIVE]] as const) {\n const state = mixSrgb(solid, '#000000', amount)\n const ratio = contrast(solidFg, state)\n\n if (ratio < AA_TEXT)\n throw new GrToneError(`${prefix}${suffix}`, ratio, AA_TEXT)\n\n result[`${prefix}${suffix}`] = state\n }\n }\n\n if (roles.includes('light')) {\n // Мягкая подложка: тон, подмешанный в поверхность карточки.\n result[`${prefix}-light`] = mixSrgb(seed, card, dark ? 22 : 14)\n }\n\n if (roles.includes('text')) {\n const light = result[`${prefix}-light`] ?? mixSrgb(seed, card, dark ? 22 : 14)\n\n // Текст тона живёт и на мягкой подложке, и на фоне страницы, и на карточке —\n // сдвигаем до худшего из трёх.\n let value = seed\n for (const surface of [light, bg, card])\n value = shiftUntil(value, fg, surface, AA_TEXT, `${prefix}-text`)\n\n result[`${prefix}-text`] = value\n }\n\n return result\n}\n"],"mappings":"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"}
|
package/dist/tokens.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as grThemeTokens, i as grThemeNames, n as grDerivedTokens, r as grFoundationTokens, t as grComponentTokens } from "./chunks/generated-
|
|
1
|
+
import { a as grThemeTokens, i as grThemeNames, n as grDerivedTokens, r as grFoundationTokens, t as grComponentTokens } from "./chunks/generated-CSyPsWtM.js";
|
|
2
2
|
export { grComponentTokens, grDerivedTokens, grFoundationTokens, grThemeNames, grThemeTokens };
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
* становятся токенами. Отсюда инвариант, который держит тест: склейка `text`
|
|
9
9
|
* всех токенов равна исходной строке. Любая потеря символа — сдвиг разметки.
|
|
10
10
|
*/
|
|
11
|
-
export type GrCodeTokenKind =
|
|
12
|
-
/** Имя поля объекта: строка, за которой идёт двоеточие. */
|
|
13
|
-
'key' | 'string' | 'number'
|
|
11
|
+
export type GrCodeTokenKind = 'key' | 'string' | 'number'
|
|
14
12
|
/** `true`, `false`, `null`. */
|
|
15
13
|
| 'literal'
|
|
16
14
|
/** Скобки, запятые, двоеточия. */
|
|
@@ -124,7 +124,7 @@ type GrImageViewerSlotProps = {
|
|
|
124
124
|
};
|
|
125
125
|
type __VLS_Slots = {
|
|
126
126
|
/** Панель инструментов целиком вместо встроенной. */
|
|
127
|
-
toolbar?: (props: GrImageViewerSlotProps) => any;
|
|
127
|
+
'toolbar'?: (props: GrImageViewerSlotProps) => any;
|
|
128
128
|
/** Свои кнопки рядом со встроенными — поворот, скачивание, печать. */
|
|
129
129
|
'toolbar-actions'?: (props: GrImageViewerSlotProps) => any;
|
|
130
130
|
};
|