@feugene/granularity 0.31.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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-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/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-yJNX1g1G.js → granular-provider-Da2CJO6j.js} +3 -3
- package/dist/chunks/{granular-provider-yJNX1g1G.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 → overlayStack-0CZS99Da.js} +40 -6
- package/dist/chunks/overlayStack-0CZS99Da.js.map +1 -0
- 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 → useModalOverlay-D__CqLGn.js} +3 -0
- package/dist/chunks/useModalOverlay-D__CqLGn.js.map +1 -0
- 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-C7ifyQ0R.js → GrColorPicker-p2XH_8cE.js} +2 -2
- package/dist/components/GrColorPicker/chunks/GrColorPicker-p2XH_8cE.js.map +1 -0
- package/dist/components/GrColorPicker/index.js +1 -1
- package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-C5abL2Y7.js → GrCommandPalette-BXbh3q7O.js} +2 -2
- package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BXbh3q7O.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-CUP43q__.js} +3 -3
- package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-CUP43q__.js.map +1 -0
- package/dist/components/GrConfirmDialog/index.js +1 -1
- package/dist/components/GrContextMenu/chunks/{GrContextMenu-_FKwQvuQ.js → GrContextMenu-ClkVjdcP.js} +1 -1
- package/dist/components/GrContextMenu/chunks/GrContextMenu-ClkVjdcP.js.map +1 -0
- package/dist/components/GrContextMenu/index.js +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-BiMJ9_T4.js} +2 -2
- package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js.map → GrDialog-BiMJ9_T4.js.map} +1 -1
- package/dist/components/GrDialog/index.js +1 -1
- package/dist/components/GrDialogService/chunks/{GrDialogService-6s2cQ-_6.js → GrDialogService-BxNK6crD.js} +4 -4
- package/dist/components/GrDialogService/chunks/GrDialogService-BxNK6crD.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-Ce2l3zaG.js} +6 -5
- package/dist/components/GrDrawer/chunks/GrDrawer-Ce2l3zaG.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 → GrImageViewer-CG4vUBg_.js} +4 -3
- package/dist/components/GrImageViewer/chunks/GrImageViewer-CG4vUBg_.js.map +1 -0
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInput/chunks/GrInput-BLywRZUN.js.map +1 -1
- package/dist/components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js.map +1 -1
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-Cy2bknHO.js → GrJsonViewer-BCZ7lE2k.js} +2 -2
- 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 → GrModal-D0mf1SAx.js} +3 -2
- package/dist/components/GrModal/chunks/GrModal-D0mf1SAx.js.map +1 -0
- package/dist/components/GrModal/index.js +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-Cw3R21dp.js → GrPagination-B_kAhoAV.js} +2 -2
- package/dist/components/GrPagination/chunks/{GrPagination-Cw3R21dp.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 → GrPopover-faJanmGs.js} +1 -1
- package/dist/components/GrPopover/chunks/GrPopover-faJanmGs.js.map +1 -0
- package/dist/components/GrPopover/index.js +1 -1
- package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-DLcl1xiq.js → GrPromptDialog-C6QGC7QJ.js} +4 -4
- package/dist/components/GrPromptDialog/chunks/GrPromptDialog-C6QGC7QJ.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-BiUrSSxc.js → GrSelect-gCeRFgQo.js} +1 -1
- 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-iJnMl2t9.js → GrTreeSelect-BHwgGJcT.js} +1 -1
- 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/useFloating.js +2 -22
- package/dist/composables/useFloating.js.map +1 -1
- package/dist/composables/useFocusTrap.js.map +1 -1
- package/dist/composables/useOverlayLayer.js +10 -3
- 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 +37 -37
- 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 +24 -24
- package/dist/types/components/GrSlider/grSliderStyles.d.ts +9 -1
- package/dist/types/components/GrTabPanels/GrTabPanel.vue.d.ts +3 -3
- package/dist/types/composables/internal/overlayStack.d.ts +30 -0
- package/dist/types/composables/internal/useModalOverlay.d.ts +14 -0
- package/dist/types/composables/useOverlayLayer.d.ts +8 -0
- package/dist/vue/index.js.map +1 -1
- package/dist/web-types.json +1 -1
- package/package.json +3 -3
- package/dist/chunks/grButtonStyles-B_-YRE__.js.map +0 -1
- package/dist/chunks/grSliderStyles-B5uNxNJq.js.map +0 -1
- package/dist/chunks/overlayStack-C8cfsqXa.js.map +0 -1
- package/dist/chunks/useModalOverlay-Cv5hF63W.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-C7ifyQ0R.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/GrContextMenu/chunks/GrContextMenu-_FKwQvuQ.js.map +0 -1
- package/dist/components/GrDataTable/chunks/GrDataTable-C8a9_nCg.js.map +0 -1
- package/dist/components/GrDialogService/chunks/GrDialogService-6s2cQ-_6.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/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js.map +0 -1
- package/dist/components/GrJsonViewer/chunks/GrJsonViewer-Cy2bknHO.js.map +0 -1
- package/dist/components/GrList/chunks/GrList-DmT4qzLO.js.map +0 -1
- package/dist/components/GrModal/chunks/GrModal-CCoWZuIl.js.map +0 -1
- package/dist/components/GrPopover/chunks/GrPopover-CofG-Tfe.js.map +0 -1
- package/dist/components/GrPromptDialog/chunks/GrPromptDialog-DLcl1xiq.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-BiUrSSxc.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-iJnMl2t9.js.map +0 -1
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":";;AAgBA,SAAgB,SAAS,OAAoB;CAC3C,MAAM,QAAQ,MAAM,KAAK,CAAC,CAAC,MAAM,6BAA6B;CAE9D,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,gCAAgC,OAAO;CAEzD,MAAM,MAAM,MAAM,EAAE,CAAC,WAAW,IAC5B,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,KAAI,SAAQ,OAAO,IAAI,CAAC,CAAC,KAAK,EAAE,IACnD,MAAM;CAEV,OAAO;EAAC;EAAG;EAAG;CAAC,CAAC,CAAC,KAAI,WAAU,OAAO,SAAS,IAAI,MAAM,QAAQ,SAAS,CAAC,GAAG,EAAE,CAAC;AACnF;AAEA,SAAgB,MAAM,UAAuB;CAC3C,OAAO,IAAI,SACR,KAAI,YAAW,KAAK,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAC7F,KAAK,EAAE;AACZ;;;;;;AAOA,SAAgB,QAAQ,SAAiB,UAAkB,QAAwB;CACjF,MAAM,OAAO,SAAS,OAAO;CAC7B,MAAM,QAAQ,SAAS,QAAQ;CAC/B,MAAM,QAAQ,SAAS;CAEvB,OAAO,MAAM,KAAK,KAAK,SAAS,UAAU,UAAU,QAAQ,MAAM,UAAU,IAAI,MAAM,CAAQ;AAChG;AAEA,SAAgB,UAAU,OAA6B;CACrD,MAAM,YAAY,OAAO,UAAU,WAAW,SAAS,KAAK,IAAI,MAAA,CAAO,KAAK,YAAY;EACtF,MAAM,aAAa,UAAU;EAE7B,OAAO,cAAc,SAAU,aAAa,UAAU,aAAa,QAAS,UAAU;CACxF,CAAC;CAED,OAAO,QAAS,SAAS,KAAK,QAAS,SAAS,KAAK,QAAS,SAAS;AACzE;;AAGA,SAAgB,SAAS,YAA0B,YAAkC;CACnF,MAAM,QAAQ,UAAU,UAAU;CAClC,MAAM,SAAS,UAAU,UAAU;CACnC,MAAM,CAAC,SAAS,UAAU,QAAQ,SAAS,CAAC,OAAO,MAAM,IAAI,CAAC,QAAQ,KAAK;CAE3E,QAAQ,UAAU,QAAS,SAAS;AACtC;AAEA,SAAS,MAAM,OAA+C;CAC5D,MAAM,CAAC,KAAK,OAAO,SAAS,OAAO,UAAU,WAAW,SAAS,KAAK,IAAI,MAAA,CAAO,KAAK,YAAY;EAChG,MAAM,aAAa,UAAU;EAE7B,OAAO,cAAc,SAAU,aAAa,UAAU,aAAa,QAAS,UAAU;CACxF,CAAC;CAGD,MAAM,KAAK,MAAM,QAAS,QAAQ,QAAS,OAAO,SAAU;CAC5D,MAAM,IAAI,MAAM,QAAS,QAAQ,QAAS,OAAO;CACjD,MAAM,KAAK,MAAM,QAAS,QAAQ,QAAS,OAAO,SAAU;CAE5D,MAAM,KAAK,UAA2B,QAAQ,UAAW,UAAU,IAAI,KAAK,QAAQ,QAAQ,KAAK;CACjG,MAAM,CAAC,IAAI,IAAI,MAAM;EAAC,EAAE,CAAC;EAAG,EAAE,CAAC;EAAG,EAAE,CAAC;CAAC;CAEtC,OAAO;EAAC,MAAM,KAAK;EAAI,OAAO,KAAK;EAAK,OAAO,KAAK;CAAG;AACzD;;;;;;;;AASA,SAAgB,OAAO,OAAqB,QAA8B;CACxE,MAAM,CAAC,UAAU,aAAa,CAAC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;CAE1D,OAAO,KAAK,MAAM,GAAG,SAAS,KAAK,OAAO,UAAU,QAAQ,UAAU,MAAM,CAAC;AAC/E;;AAGA,SAAgB,MAAM,OAAwB;CAC5C,OAAO,gCAAgC,KAAK,MAAM,KAAK,CAAC;AAC1D;;;;AC9FA,SAAgB,iBAA2B;CACzC,OAAO,cAAc,KAAI,UAAS,MAAM,IAAI;AAC9C;;;;;;;;;;;;AAaA,SAAgB,YAAY,QAAuB,MAAc,OAAiB,CAAC,GAAkB;CACnG,MAAM,QAAQ,OAAO;CACrB,IAAI,UAAU,KAAA,GACZ,OAAO;CACT,IAAI,MAAM,KAAK,GACb,OAAO;CAET,MAAM,YAAY,MAAM,KAAK,CAAC,CAAC,MAAM,2BAA2B;CAChE,IAAI,CAAC,WACH,OAAO;CAET,IAAI,KAAK,SAAS,IAAI,GACpB,MAAM,IAAI,MAAM,QAAQ,KAAK,2BAA2B,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,KAAK,GAAG;CAEvF,OAAO,YAAY,QAAQ,UAAU,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC;AAC1D;;;;;;;;;;;ACbA,IAAM,YAAU;;AAEhB,IAAM,aAAa;;;;;AAMnB,SAAS,YAAsB;CAC7B,MAAM,QAAQ,IAAI,IAAI,cAAc,KAAI,UAAS,MAAM,IAAI,CAAC;CAE5D,OAAO,CAAC,GAAG,KAAK,CAAC,CACd,QAAO,SAAQ,MAAM,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,CACvC,KAAI,SAAQ,KAAK,QAAQ,SAAS,EAAE,CAAC;AAC1C;AAEA,SAAS,UAAU,MAAqD;CACtE,OAAO,gBACJ,QAAO,UAAS,MAAM,SAAS,IAAI,CAAC,CACpC,KAAI,WAAU;EAAE,QAAQ,MAAM;EAAQ,SAAS,MAAM;CAAQ,EAAE;AACpE;AAEA,SAAgB,cAAc,OAA0E;CACtG,MAAM,EAAE,WAAW;CACnB,MAAM,SAAyB,CAAC;CAEhC,MAAM,SAAS,SAAgC,YAAY,QAAQ,IAAI;CAEvE,SAAS,gBAAgB,OAAe,SAAiB,UAAkB,MAAoB;EAC7F,MAAM,CAAC,YAAY,cAAc,CAAC,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC;EAG9D,IAAI,CAAC,cAAc,CAAC,YAClB;EAEF,MAAM,SAAS,SAAS,YAAY,UAAU;EAC9C,IAAI,UAAU,UACZ;EAEF,OAAO,KAAK;GACV,MAAM;GACN;GACA;GACA,QAAQ,KAAK,MAAM,SAAS,GAAG,IAAI;GACnC;GACA,SAAS,GAAG,KAAK,IAAI,MAAM,MAAM,QAAQ,QAAQ,OAAO,QAAQ,CAAC,EAAE,gBAAgB,SAAS;EAC9F,CAAC;CACH;;CAGA,SAAS,0BAA0B,QAAgB,UAAkB,MAAoB;EACvF,gBAAgB,QAAQ,UAAU,WAAS,IAAI;EAE/C,MAAM,OAAO,MAAM,QAAQ;EAC3B,MAAM,aAAa,MAAM,MAAM;EAC/B,IAAI,CAAC,QAAQ,CAAC,YACZ;EAEF,KAAK,MAAM,EAAE,QAAQ,aAAa,UAAU,QAAQ,GAAG;GACrD,MAAM,QAAQ,MAAM,OAAO;GAC3B,IAAI,CAAC,OACH;GAEF,MAAM,QAAQ,SAAS,YAAY,QAAQ,MAAM,OAAO,MAAM,CAAC;GAC/D,IAAI,SAAS,WACX;GAEF,OAAO,KAAK;IACV,MAAM;IACN,OAAO;IACP,SAAS,GAAG,SAAS,IAAI,OAAO;IAChC,QAAQ,KAAK,MAAM,QAAQ,GAAG,IAAI;IAClC,UAAU;IACV,SAAS,GAAG,KAAK,IAAI,OAAO,gBAAgB,SAAS,IAAI,OAAO,UAAU,MAAM,QAAQ,CAAC,EAAE,gBAAgB,UAAQ;GACrH,CAAC;EACH;CACF;CAMA,MAAM,YAAY,IAAI,IAAI,UAAU,CAAC,CAAC,KAAI,SAAQ,QAAQ,MAAM,CAAC;CAEjE,KAAK,MAAM,WAAW;EAAC;EAAW;EAAa;EAAgB;CAAc,GAAG;EAC9E,IAAI,UAAU,IAAI,OAAO,GACvB;EAEF,gBAAgB,WAAW,SAAS,WAAS,gBAAgB;CAC/D;CAEA,KAAK,MAAM,WAAW;EAAC;EAAW;EAAa;EAAc;CAAgB,GAC3E,gBAAgB,iBAAiB,SAAS,WAAS,iBAAiB;CAEtE,KAAK,MAAM,QAAQ,UAAU,GAAG;EAC9B,MAAM,OAAO,QAAQ;EAErB,0BAA0B,GAAG,KAAK,MAAM,MAAM,oBAAoB,MAAM;EAIxE,KAAK,MAAM,SAAS,CAAC,UAAU,SAAS,GAAG;GACzC,IAAI,OAAO,GAAG,OAAO,aAAa,KAAA,GAChC;GAEF,gBAAgB,GAAG,KAAK,MAAM,GAAG,OAAO,SAAS,WAAS,sBAAsB,OAAO,OAAO;EAChG;EAEA,IAAI,OAAO,GAAG,KAAK,YAAY,KAAA,GAAW;GACxC,gBAAgB,GAAG,KAAK,QAAQ,GAAG,KAAK,SAAS,WAAS,cAAc,MAAM;GAC9E,gBAAgB,GAAG,KAAK,QAAQ,WAAW,WAAS,cAAc,MAAM;GACxE,gBAAgB,GAAG,KAAK,QAAQ,aAAa,WAAS,cAAc,MAAM;EAC5E;CACF;CAIA,MAAM,WAAW;EAAC;EAAW;EAAW;EAAW;EAAU;EAAQ;EAAS;CAAO;CAErF,KAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GACxC,KAAK,IAAI,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;EAC/C,MAAM,CAAC,OAAO,UAAU,CAAC,QAAQ,SAAS,MAAM,QAAQ,SAAS,IAAI;EACrE,MAAM,CAAC,YAAY,eAAe,CAAC,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;EAC9D,IAAI,CAAC,cAAc,CAAC,aAClB;EAEF,MAAM,WAAW,OAAO,YAAY,WAAW;EAC/C,IAAI,YAAY,YACd;EAEF,OAAO,KAAK;GACV,MAAM;GACN,OAAO;GACP,SAAS;GACT,QAAQ,KAAK,MAAM,WAAW,GAAG,IAAI;GACrC,UAAU;GACV,SAAS,8BAA8B,MAAM,KAAK,OAAO,SAAS,SAAS,QAAQ,CAAC,EAAE,cAAc;EACtG,CAAC;CACH;CAGF,OAAO;AACT;;;AC9HA,IAAa,eAAb,cAAkC,MAAM;CACtC;CAEA,YAAY,MAAc,QAAwB;EAChD,MAAM,CACJ,SAAS,KAAK,0BACd,GAAG,OAAO,KAAI,UAAS,OAAO,MAAM,SAAS,CAC/C,CAAC,CAAC,KAAK,IAAI,CAAC;EAEZ,KAAK,OAAO;EACZ,KAAK,SAAS;CAChB;AACF;AAEA,SAAS,WAAW,MAAiD;CACnE,IAAI,OAAO,SAAS,UAAU;EAC5B,MAAM,QAAQ,CAAC,SAAS,MAAM;EAC9B,IAAI,CAAC,MAAM,SAAS,IAAI,GACtB,MAAM,IAAI,MAAM,6BAA6B,KAAK,iBAAiB,MAAM,KAAK,IAAI,GAAG;EAEvF,OAAO,OAAO,YAAY,cAAc,KAAI,UAAS,CAAC,MAAM,MAAM,MAAM,OAAO,KAAK,CAAC,CAAC;CACxF;CAEA,OAAO,YAAY,OAAO,EAAE,GAAI,KAAiB,OAAO,IAAI,EAAE,GAAG,KAAK;AACxE;AAEA,SAAS,mBAAmB,QAAuB,QAA0B;CAC3E,OAAO,cAAc,KAAI,UAAS,GAAG,SAAS,MAAM,KAAK,IAAI,OAAO,MAAM,MAAM,EAAE;AACpF;AAEA,SAAS,4BAA4B,QAAuB,QAA0B;CACpF,MAAM,QAAQ,OAAO,KAAK,MAAM;CAChC,IAAI,MAAM,WAAW,GACnB,OAAO,CAAC;CAEV,OAAO;EAAC;EAAI,GAAG,OAAO;EAAoC,GAAG,MAAM,KAAI,SAAQ,GAAG,SAAS,KAAK,IAAI,OAAO,MAAM,EAAE;CAAC;AACtH;;;;;;;;;AAUA,SAAS,eAAe,QAAuB,UAA4B;CACzE,MAAM,QAAQ;EACZ;EACA;EACA,KAAK,SAAS;CAChB;CAEA,KAAK,MAAM,SAAS,iBAAiB;EACnC,MAAM,OAAO,YAAY,QAAQ,MAAM,IAAI;EAC3C,MAAM,UAAU,YAAY,QAAQ,MAAM,OAAO;EAIjD,IAAI,CAAC,QAAQ,CAAC,SACZ;EAEF,MAAM,KAAK,OAAO,MAAM,KAAK,IAAI,QAAQ,MAAM,SAAS,MAAM,MAAM,EAAE,EAAE;CAC1E;CAEA,MAAM,KAAK,OAAO,GAAG;CAErB,OAAO;AACT;AAEA,SAAgB,eAAe,OAA0G;CACvI,OAAO;EACL,YAAY,MAAM,KAAK;EACvB,GAAG,MAAM,SAAS;EAClB,GAAG,mBAAmB,MAAM,QAAQ,IAAI;EACxC,GAAG,4BAA4B,MAAM,mBAAmB,CAAC,GAAG,IAAI;EAChE;EACA,GAAG,eAAe,MAAM,QAAQ,MAAM,QAAQ;EAC9C;CACF,CAAC,CAAC,KAAK,IAAI;AACb;AAYA,SAAS,WAAW,SAAgC;CAClD,MAAM,EAAE,MAAM,QAAQ,iBAAiB,UAAU,UAAU,mBAAmB;CAE9E,MAAM,QAAQ,IAAI,IAAI,eAAe,CAAC;CACtC,MAAM,UAAU,OAAO,KAAK,MAAM,CAAC,CAAC,QAAO,SAAQ,CAAC,MAAM,IAAI,IAAI,CAAC;CAEnE,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MACR,SAAS,KAAK,0CAA0C,QAAQ,KAAK,IAAI,EAAE,mKAG7E;CAGF,MAAM,iBAAiB,IAAI,IAAI,kBAAkB,KAAI,UAAS,MAAM,IAAI,CAAC;CACzE,MAAM,mBAAmB,OAAO,KAAK,eAAe,CAAC,CAAC,QAAO,UAAS,CAAC,eAAe,IAAI,KAAK,CAAC;CAEhG,IAAI,iBAAiB,SAAS,GAC5B,MAAM,IAAI,MAAM,SAAS,KAAK,2DAA2D,iBAAiB,KAAK,IAAI,GAAG;CAExH,MAAM,UAAU,eAAe,CAAC,CAAC,QAAO,SAAQ,OAAO,UAAU,KAAA,CAAS;CAC1E,IAAI,QAAQ,SAAS,GACnB,MAAM,IAAI,MAAM,eAAe,OAAO,CAAC;CAEzC,MAAM,QAAiB;EACrB;EACA;EACA;EACA;EACA,KAAK,eAAe;GAAE;GAAM;GAAU;GAAQ;EAAgB,CAAC;CACjE;CAEA,IAAI,UAAU;EACZ,MAAM,SAAS,cAAc,KAAK;EAClC,IAAI,OAAO,SAAS,GAClB,MAAM,IAAI,aAAa,MAAM,MAAM;CACvC;CAEA,OAAO;AACT;;;;;;;;;AAUA,SAAgB,YAAY,SAAsC;CAChE,MAAM,EACJ,MACA,MACA,SAAS,CAAC,GACV,kBAAkB,CAAC,GACnB,WAAW,gBAAgB,KAAK,KAChC,WAAW,SACT;CAEJ,OAAO,WAAW;EAChB;EACA,QAAQ;GAAE,GAAG,WAAW,IAAI;GAAG,GAAG;EAAO;EACzC;EACA;EACA;EACA,iBAAgB,YAAW,cAAc,KAAK,mBAAmB,QAAQ,KAAK,IAAI;CACpF,CAAC;AACH;;;;;;;;;;;;;;AAeA,SAAgB,YAAY,SAAoD;CAC9E,MAAM,EACJ,MACA,SAAS,CAAC,GACV,kBAAkB,CAAC,GACnB,WAAW,gBAAgB,KAAK,KAChC,WAAW,SACT;CAEJ,OAAO,WAAW;EAChB;EACA;EACA;EACA;EACA;EACA,iBAAgB,YAAW;GACzB,SAAS,KAAK,qCAAqC,QAAQ,OAAO;GAClE,KAAK,QAAQ,KAAK,IAAI;GACtB;GACA;EACF,CAAC,CAAC,KAAK,IAAI;CACb,CAAC;AACH;;;AC1NA,IAAM,UAAU;;AAEhB,IAAM,OAAO;;;;;;;;;;;;AAYb,IAAM,cAAc;AACpB,IAAM,eAAe;AAErB,IAAa,cAAb,cAAiC,MAAM;CACrC,YAAY,MAAc,QAAgB,UAAkB;EAC1D,MACE,GAAG,KAAK,iCAAiC,SAAS,eAAe,OAAO,QAAQ,CAAC,EAAE,+DAErF;EAEA,KAAK,OAAO;CACd;AACF;;;;;AAMA,SAAS,QAAQ,MAA0B;CACzC,MAAM,QAAQ,IAAI,IAAI,cAAc,KAAI,UAAS,MAAM,IAAI,CAAC;CAC5D,MAAM,SAAS,QAAQ;CAEvB,IAAI,CAAC,MAAM,IAAI,MAAM,GACnB,OAAO;EAAC;EAAQ;EAAS;EAAS;CAAM;CAE1C,OAAQ;EACN,CAAC,QAAQ,MAAM;EACf,CAAC,SAAS,GAAG,OAAO,OAAO;EAC3B,CAAC,SAAS,GAAG,OAAO,OAAO;EAC3B,CAAC,QAAQ,GAAG,OAAO,MAAM;CAC3B,CAAC,CACE,QAAQ,GAAG,UAAU,MAAM,IAAI,IAAI,CAAC,CAAC,CACrC,KAAK,CAAC,UAAU,IAAI;AACzB;AAEA,SAAS,aAAa,MAA0C;CAC9D,IAAI,OAAO,SAAS,UAClB,OAAO,OAAO,YAAY,cAAc,KAAI,UAAS,CAAC,MAAM,MAAM,MAAM,OAAO,KAAK,CAAC,CAAC;CAExF,OAAO,YAAY,OAAQ,KAAmC,SAAS;AACzE;AAEA,SAAS,aAAa,QAAuB,MAAsB;CACjE,MAAM,QAAQ,YAAY,QAAQ,IAAI;CACtC,IAAI,CAAC,OACH,MAAM,IAAI,MAAM,iCAAiC,KAAK,eAAe;CAEvE,OAAO;AACT;;;;;AAMA,SAAS,WAAW,MAAc,SAAiB,SAAiB,UAAkB,MAAsB;CAC1G,IAAI,OAAO;EAAE,OAAO;EAAM,OAAO,SAAS,MAAM,OAAO;CAAE;CAEzD,KAAK,IAAI,SAAS,KAAK,UAAU,GAAG,UAAU,MAAM;EAClD,MAAM,YAAY,QAAQ,MAAM,SAAS,MAAM;EAC/C,MAAM,QAAQ,SAAS,WAAW,OAAO;EAEzC,IAAI,SAAS,UACX,OAAO;EACT,IAAI,QAAQ,KAAK,OACf,OAAO;GAAE,OAAO;GAAW;EAAM;CACrC;CAEA,MAAM,IAAI,YAAY,MAAM,KAAK,OAAO,QAAQ;AAClD;;AAGA,SAAS,OAAO,QAAgC;CAC9C,MAAM,CAAC,IAAI,MAAM,CAAC,aAAa,QAAQ,SAAS,GAAG,aAAa,QAAQ,SAAS,CAAC;CAClF,MAAM,eAAe,QAAwB,SAAS,GAAG,CAAC,CAAC,QAAQ,KAAK,YAAY,MAAM,SAAS,CAAC;CAEpG,OAAO,YAAY,EAAE,IAAI,YAAY,EAAE;AACzC;;;;;;;;;;;;;;AAeA,SAAgB,KAAK,MAAc,MAAc,SAAqC;CACpF,MAAM,SAAS,aAAa,QAAQ,IAAI;CACxC,MAAM,QAAQ,QAAQ,SAAS,QAAQ,IAAI;CAE3C,MAAM,KAAK,aAAa,QAAQ,SAAS;CACzC,MAAM,KAAK,aAAa,QAAQ,SAAS;CACzC,MAAM,OAAO,aAAa,QAAQ,WAAW;CAC7C,MAAM,OAAO,OAAO,MAAM;CAE1B,MAAM,SAAwB,CAAC;CAC/B,MAAM,SAAS,QAAQ;CAEvB,IAAI,MAAM,SAAS,MAAM,GAAG;EAC1B,OAAO,UAAU;EAKjB,MAAM,aAAa,CAAC,IAAI,EAAE;EAC1B,MAAM,WAAW,cAA8B,KAAK,IAClD,SAAS,WAAW,IAAI,GACxB,SAAS,WAAW,QAAQ,MAAM,IAAI,EAAE,CAAC,GACzC,SAAS,WAAW,QAAQ,MAAM,IAAI,EAAE,CAAC,CAC3C;EAEA,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,CAAC,MAAM,MAAM,UAAU,QAAQ,KAAK,IAAI,QAAQ,IAAI,CAAC;EACnF,IAAI,QAAQ,IAAI,IAAI,SAClB,MAAM,IAAI,YAAY,GAAG,OAAO,MAAM,QAAQ,IAAI,GAAG,OAAO;EAE9D,OAAO,GAAG,OAAO,QAAQ;CAC3B;CAEA,IAAI,MAAM,SAAS,OAAO,GAAG;EAM3B,MAAM,UAAU,OAAO,KAAK;EAE5B,MAAM,QAAQ,WAAW,MAAM,WAAW,SAAS,SAAS,GAAG,OAAO,OAAO;EAE7E,OAAO,GAAG,OAAO,WAAW;EAC5B,OAAO,GAAG,OAAO,cAAc;EAI/B,KAAK,MAAM,CAAC,QAAQ,WAAW,CAAC,CAAC,gBAAgB,WAAW,GAAG,CAAC,iBAAiB,YAAY,CAAC,GAAY;GACxG,MAAM,QAAQ,QAAQ,OAAO,WAAW,MAAM;GAC9C,MAAM,QAAQ,SAAS,SAAS,KAAK;GAErC,IAAI,QAAQ,SACV,MAAM,IAAI,YAAY,GAAG,SAAS,UAAU,OAAO,OAAO;GAE5D,OAAO,GAAG,SAAS,YAAY;EACjC;CACF;CAEA,IAAI,MAAM,SAAS,OAAO,GAExB,OAAO,GAAG,OAAO,WAAW,QAAQ,MAAM,MAAM,OAAO,KAAK,EAAE;CAGhE,IAAI,MAAM,SAAS,MAAM,GAAG;EAC1B,MAAM,QAAQ,OAAO,GAAG,OAAO,YAAY,QAAQ,MAAM,MAAM,OAAO,KAAK,EAAE;EAI7E,IAAI,QAAQ;EACZ,KAAK,MAAM,WAAW;GAAC;GAAO;GAAI;EAAI,GACpC,QAAQ,WAAW,OAAO,IAAI,SAAS,SAAS,GAAG,OAAO,MAAM;EAElE,OAAO,GAAG,OAAO,UAAU;CAC7B;CAEA,OAAO;AACT"}
|
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
|
};
|
|
@@ -2,10 +2,10 @@ import type { GrComponentSize } from '../shared/sizes';
|
|
|
2
2
|
import type { InputHTMLAttributes } from 'vue';
|
|
3
3
|
export interface GrInputProps {
|
|
4
4
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
* Значение поля. Необязательное: без `v-model` поле рисуется пустым.
|
|
6
|
+
* Дефолт — пустая строка, а не `undefined`: длина значения читается
|
|
7
|
+
* напрямую (`showClear`), и `undefined` уронил бы рендер.
|
|
8
|
+
*/
|
|
9
9
|
modelValue?: string;
|
|
10
10
|
type?: 'text' | 'email' | 'password' | 'number' | 'search' | 'tel' | 'url';
|
|
11
11
|
placeholder?: string;
|
|
@@ -32,10 +32,10 @@ export interface GrInputProps {
|
|
|
32
32
|
/** Показывать счётчик символов (`len` или `len/maxlength`). */
|
|
33
33
|
showCount?: boolean;
|
|
34
34
|
/**
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
* Фоновая работа по полю (проверка занятости логина, автосохранение):
|
|
36
|
+
* спиннер в trailing-области + `aria-busy`. Ввод не блокируется —
|
|
37
|
+
* для этого есть `disabled`/`readonly`.
|
|
38
|
+
*/
|
|
39
39
|
loading?: boolean;
|
|
40
40
|
/** Кнопка показать/скрыть пароль (только при `type="password"`). */
|
|
41
41
|
passwordToggle?: boolean;
|
|
@@ -48,25 +48,25 @@ export interface GrInputProps {
|
|
|
48
48
|
suffixMinWidth?: string;
|
|
49
49
|
suffixMaxWidth?: string;
|
|
50
50
|
/**
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
* Фиксированная ширина у prefix/suffix: аддон получает жёсткую ширину
|
|
52
|
+
* (из `*MaxWidth` → `*MinWidth` → дефолт), а контент обрезается по краю
|
|
53
|
+
* (prefix — справа, suffix — слева). По умолчанию аддоны «растягиваются»
|
|
54
|
+
* под контент (в пределах min/max), а излишек клипается оболочкой.
|
|
55
|
+
*/
|
|
56
56
|
prefixFixed?: boolean;
|
|
57
57
|
suffixFixed?: boolean;
|
|
58
58
|
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
59
|
+
* Как выглядят аддоны `#prefix`/`#suffix`.
|
|
60
|
+
*
|
|
61
|
+
* `segment` (по умолчанию) — отдельный отсек, отрезанный рамкой и выровненный
|
|
62
|
+
* по ступени размера: так поле с «₽» и поле с «USD» стоят в колонку.
|
|
63
|
+
* `inline` — украшение внутри рамки: ни разделителя, ни своей ширины.
|
|
64
|
+
*
|
|
65
|
+
* Разница не косметическая. Поисковая строка с лупой в сегменте читается
|
|
66
|
+
* составным элементом — полем с приклеенной кнопкой, — а не одним полем;
|
|
67
|
+
* именно поэтому иконку внутри рамки нельзя было выразить аддоном, и
|
|
68
|
+
* потребители отказывались от неё вовсе.
|
|
69
|
+
*/
|
|
70
70
|
addon?: 'segment' | 'inline';
|
|
71
71
|
}
|
|
72
72
|
export interface GrInputEmits {
|
|
@@ -26,7 +26,15 @@ export declare const sliderTrackWidthBySize: Record<GrSliderSize, string>;
|
|
|
26
26
|
export declare const sliderTrackVerticalLengthClass = "h-[var(--gr-slider-length,10rem)]";
|
|
27
27
|
export declare const sliderThumbSizeBySize: Record<GrSliderSize, string>;
|
|
28
28
|
export declare const sliderPaddingBySize: Record<GrSliderSize, string>;
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Дорожка — `--gr-brd`, а не полупрозрачный `--gr-muted`.
|
|
31
|
+
*
|
|
32
|
+
* Прежний дефолт (`color-mix(--gr-muted 45%, transparent)`) на светлой теме
|
|
33
|
+
* давал #f1f5f9 при 45 % поверх почти такой же поверхности: непройденная часть
|
|
34
|
+
* шкалы не читалась вовсе, и слайдер выглядел точкой на пустом месте — по нему
|
|
35
|
+
* нельзя было понять ни диапазон, ни положение внутри него.
|
|
36
|
+
*/
|
|
37
|
+
export declare const sliderRailClass = "absolute inset-0 rounded-[var(--gr-radius-full)] bg-[var(--gr-slider-rail,var(--gr-brd))]";
|
|
30
38
|
export declare const sliderFillBaseClass = "absolute rounded-[var(--gr-radius-full)]";
|
|
31
39
|
/** Заливка растёт вдоль дорожки: по горизонтали — влево-вправо, по вертикали — снизу вверх. */
|
|
32
40
|
export declare const sliderFillOrientationClass: Record<GrSliderOrientation, string>;
|
|
@@ -2,9 +2,9 @@ export interface GrTabPanelProps {
|
|
|
2
2
|
value: string;
|
|
3
3
|
keepAlive?: boolean;
|
|
4
4
|
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
* Не монтировать содержимое, пока панель не показали впервые. Имеет смысл
|
|
6
|
+
* вместе с `keepAlive`: без него неактивная панель и так не в DOM.
|
|
7
|
+
*/
|
|
8
8
|
lazy?: boolean;
|
|
9
9
|
}
|
|
10
10
|
type __VLS_Slots = {
|
|
@@ -36,6 +36,16 @@ export interface OverlayLayer {
|
|
|
36
36
|
close: () => void;
|
|
37
37
|
/** Уведомление «этот модальный слой сейчас верхний». Только для `modal`. */
|
|
38
38
|
setTopmost?: (isTopmost: boolean) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Позиция слоя среди модальных, от нуля. Только для `modal`.
|
|
41
|
+
*
|
|
42
|
+
* От неё считается высота: у всех модальных слоёв один токен
|
|
43
|
+
* (`--gr-z-modal`), и без этой прибавки порядок отрисовки решал бы порядок
|
|
44
|
+
* узлов в портале, а он задаётся **созданием** телепорта, а не открытием
|
|
45
|
+
* слоя. Диалог, объявленный в шаблоне статически, вставал бы под окном,
|
|
46
|
+
* открытым позже, — и получал бы `inert` от стека, оставаясь видимым.
|
|
47
|
+
*/
|
|
48
|
+
setDepth?: (depth: number) => void;
|
|
39
49
|
/**
|
|
40
50
|
* Корень слоя. Ловушка фокуса нижнего слоя обязана считать его своим:
|
|
41
51
|
* панель селекта, открытого внутри модалки, телепортирована в `body` и лежит
|
|
@@ -67,5 +77,25 @@ export declare function overlayStackSize(): number;
|
|
|
67
77
|
* стек-контекст её не спасает — высоту приходится брать из порядка слоёв.
|
|
68
78
|
*/
|
|
69
79
|
export declare function openModalCount(): number;
|
|
80
|
+
/**
|
|
81
|
+
* Высота слоя, лежащего внутри открытого окна.
|
|
82
|
+
*
|
|
83
|
+
* Панель телепортирована в общий портал и становится **соседом** корня окна, а
|
|
84
|
+
* не его потомком: собственный stacking-контекст окна её не накрывает, и
|
|
85
|
+
* статический `--gr-z-dropdown` (1000) оставлял её под окном (1100). Слагаемое —
|
|
86
|
+
* число модальных слоёв, поэтому панель встаёт над самым верхним из них, а
|
|
87
|
+
* полноэкранная загрузка (1150) и тосты (1200) остаются сверху.
|
|
88
|
+
*
|
|
89
|
+
* Обратный случай — «поповер снаружи не должен перекрывать окно» — не страдает:
|
|
90
|
+
* пока окно открыто, страница под ним в `inert`, и открыть там поповер нечем.
|
|
91
|
+
*/
|
|
92
|
+
export declare function floatingLayerZIndex(zIndexVar: string): string;
|
|
93
|
+
/**
|
|
94
|
+
* Высота самого модального слоя: базовый токен плюс его позиция в стеке.
|
|
95
|
+
*
|
|
96
|
+
* Нулевая глубина оставляет чистый `var(...)` — у единственного окна на экране
|
|
97
|
+
* в стилях не появляется лишней арифметики.
|
|
98
|
+
*/
|
|
99
|
+
export declare function modalLayerZIndex(depth: number, zIndexVar?: string): string;
|
|
70
100
|
/** Тестовая/служебная очистка стека. */
|
|
71
101
|
export declare function resetOverlayStack(): void;
|
|
@@ -47,6 +47,11 @@ export interface UseModalOverlayOptions {
|
|
|
47
47
|
* композабл заводит корень сам, как у центрированных окон.
|
|
48
48
|
*/
|
|
49
49
|
root?: Ref<HTMLElement | null>;
|
|
50
|
+
/**
|
|
51
|
+
* Имя CSS-переменной слоя. Escape-hatch мимо `--gr-z-modal` — им пользуется
|
|
52
|
+
* просмотрщик. Глубина слоя прибавляется и к подменённой переменной.
|
|
53
|
+
*/
|
|
54
|
+
zIndexVar?: () => string | undefined;
|
|
50
55
|
/**
|
|
51
56
|
* Точечное переопределение точки монтирования (проп `teleportTo`). По
|
|
52
57
|
* умолчанию — общий портал оверлеев.
|
|
@@ -75,6 +80,15 @@ export interface ModalOverlay {
|
|
|
75
80
|
isTopmost: Ref<boolean>;
|
|
76
81
|
/** Значение атрибута `inert` для корня: слой перестал быть верхним. */
|
|
77
82
|
inertAttr: ComputedRef<true | undefined>;
|
|
83
|
+
/**
|
|
84
|
+
* Высота слоя: базовый токен плюс позиция в стеке.
|
|
85
|
+
*
|
|
86
|
+
* Один токен на все модальные слои означал бы, что порядок отрисовки решает
|
|
87
|
+
* порядок узлов в портале, а он задан **созданием** телепорта, а не
|
|
88
|
+
* открытием: статически объявленный диалог вставал бы под окном, открытым
|
|
89
|
+
* позже, и оказывался невидимым — при том что стек считает верхним его.
|
|
90
|
+
*/
|
|
91
|
+
layerZIndex: ComputedRef<string>;
|
|
78
92
|
portalTarget: ComputedRef<string | HTMLElement>;
|
|
79
93
|
teleportEnabled: ComputedRef<boolean>;
|
|
80
94
|
/** `data-theme` на телепортированный корень: в DOM он вне обёртки провайдера. */
|
|
@@ -43,6 +43,14 @@ export interface OverlayLayerHandle {
|
|
|
43
43
|
* законен.
|
|
44
44
|
*/
|
|
45
45
|
rootsAbove: () => HTMLElement[];
|
|
46
|
+
/**
|
|
47
|
+
* Позиция среди модальных слоёв, от нуля. По ней компонент считает высоту.
|
|
48
|
+
*
|
|
49
|
+
* Значение **не сбрасывается** при закрытии: слой уходит из стека сразу, а
|
|
50
|
+
* его поддерево живёт до конца leave-анимации. Обнули глубину там — уходящее
|
|
51
|
+
* окно нырнуло бы под соседнее прямо во время ухода.
|
|
52
|
+
*/
|
|
53
|
+
depth: Ref<number>;
|
|
46
54
|
}
|
|
47
55
|
/**
|
|
48
56
|
* Регистрирует оверлей в общем стеке слоёв, пока `open` истинно.
|
package/dist/vue/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/vue/plugin.ts"],"sourcesContent":["import type { App, Component, Directive, Plugin } from 'vue'\n\n/**\n * Лёгкий контейнер, который может быть зарегистрирован в Vue:\n * - SFC-компонент (Vue сам компилирует `__name` из имени файла) — достаточно просто передать сам компонент,\n * - SFC-компонент с опциональным `install` (по аналогии с Element Plus / Naive UI),\n * - объект с собственным `install`,\n * - либо объект `{ name, component }`, если имя нужно задать явно.\n */\nexport type GranularityInstallableComponent
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/vue/plugin.ts"],"sourcesContent":["import type { App, Component, Directive, Plugin } from 'vue'\n\n/**\n * Лёгкий контейнер, который может быть зарегистрирован в Vue:\n * - SFC-компонент (Vue сам компилирует `__name` из имени файла) — достаточно просто передать сам компонент,\n * - SFC-компонент с опциональным `install` (по аналогии с Element Plus / Naive UI),\n * - объект с собственным `install`,\n * - либо объект `{ name, component }`, если имя нужно задать явно.\n */\nexport type GranularityInstallableComponent\n = | (Component & { name?: string, __name?: string, install?: (app: App) => void })\n | { install: (app: App) => void }\n | { name: string, component: Component }\n\n/**\n * Директива — либо пара `{ name, directive }`, либо объект с `install`.\n */\nexport type GranularityInstallableDirective\n = | { name: string, directive: Directive }\n | { install: (app: App) => void }\n\nexport interface CreateGranularityOptions {\n /**\n * Список компонентов для глобальной регистрации.\n * Пакет сам по себе ничего не импортирует — пользователь передаёт сюда только те компоненты,\n * которые ему действительно нужны. За счёт этого tree-shaking остаётся полным.\n */\n components?: GranularityInstallableComponent[]\n /**\n * Список директив. Передавайте ровно те, что нужны, по аналогии с компонентами.\n */\n directives?: GranularityInstallableDirective[]\n /**\n * Произвольные `provide`-значения. Ключи могут быть `symbol` или строкой.\n * Пакет не навязывает конкретные ключи (например, i18n) — выбор за пользователем.\n */\n provides?: Array<{ key: string | symbol, value: unknown }>\n /**\n * Произвольные `app.config.globalProperties` — по умолчанию ничего не ставим.\n */\n globalProperties?: Record<string, unknown>\n}\n\n/**\n * Вспомогательная обёртка: превращает произвольный компонент в `GranularityInstallableComponent`\n * с явным именем регистрации.\n *\n * ```ts\n * import { GrButton } from '@feugene/granularity/components/GrButton'\n * import { defineInstallable } from '@feugene/granularity/vue'\n *\n * const installable = defineInstallable(GrButton, 'GrButton')\n * ```\n */\nexport function defineInstallable<T extends Component>(component: T, name: string): GranularityInstallableComponent {\n return {\n install(app: App) {\n app.component(name, component)\n },\n }\n}\n\nfunction installComponent(app: App, c: GranularityInstallableComponent): void {\n if (typeof (c as any).install === 'function') {\n ;(c as any).install(app)\n return\n }\n\n // Форма `{ name, component }` — явное указание имени для произвольного компонента.\n // Допускаем как object-компоненты (SFC / options), так и functional-компоненты.\n if (\n typeof (c as any).name === 'string'\n && (c as any).component\n && (typeof (c as any).component === 'object' || typeof (c as any).component === 'function')\n ) {\n const { name, component } = c as { name: string, component: Component }\n app.component(name, component)\n return\n }\n\n // SFC: Vue 3 компилирует имя компонента из имени файла в поле `__name`\n // (например, `GrButton.vue` → `__name: 'GrButton'`). Также поддерживаем явное `name`.\n const resolvedName\n = (c as Component & { name?: string }).name\n ?? (c as { __name?: string }).__name\n if (resolvedName) {\n app.component(resolvedName, c as Component)\n return\n }\n\n // Сознательно без throw — просто сообщаем в dev-режиме.\n if (!__GR_DEV__)\n return\n\n console.warn('[granularity] component passed to createGranularity has no `install`, `name`, or `__name` — skipped.')\n}\n\nfunction installDirective(app: App, d: GranularityInstallableDirective): void {\n if ('install' in d && typeof d.install === 'function') {\n d.install(app)\n return\n }\n\n if ('name' in d && 'directive' in d) {\n app.directive(d.name, d.directive)\n return\n }\n\n // Сознательно без throw — согласовано с `installComponent`.\n if (!__GR_DEV__)\n return\n\n console.warn('[granularity] directive passed to createGranularity has no `install` or `{ name, directive }` — skipped.')\n}\n\n/**\n * Применяет опции к переданному приложению. Экспортируется отдельно от фабрики —\n * удобно, когда плагин не нужен (например, в тестах).\n */\nexport function installGranularity(app: App, options: CreateGranularityOptions = {}): void {\n for (const c of options.components ?? [])\n installComponent(app, c)\n\n for (const d of options.directives ?? [])\n installDirective(app, d)\n\n for (const { key, value } of options.provides ?? [])\n app.provide(key as any, value)\n\n if (options.globalProperties) {\n for (const [key, value] of Object.entries(options.globalProperties))\n app.config.globalProperties[key] = value\n }\n}\n\n/**\n * Создаёт Vue-плагин `{ install }`, который при `app.use(...)` зарегистрирует переданные\n * компоненты, директивы и provide-значения. Сам модуль НЕ импортирует ни компонентов,\n * ни директив из пакета — всё приходит снаружи. Это сохраняет гранулярность:\n * бандлер увидит только те символы, которые вы реально передали.\n *\n * ```ts\n * import { createApp } from 'vue'\n * import { createGranularity } from '@feugene/granularity/vue'\n * import { GrButton } from '@feugene/granularity/components/GrButton'\n * import { GrInput } from '@feugene/granularity/components/GrInput'\n * import { vHotkey } from '@feugene/granularity/directives/hotkey'\n *\n * createApp(App)\n * .use(createGranularity({\n * // Достаточно передать сами компоненты — имя будет взято из `__name` (Vue SFC)\n * // или из `name`; можно также указать явно через `{ name, component }`.\n * components: [GrButton, GrInput],\n * directives: [{ name: 'hotkey', directive: vHotkey }],\n * }))\n * .mount('#app')\n * ```\n */\nexport function createGranularity(options: CreateGranularityOptions = {}): Plugin {\n return {\n install(app: App) {\n installGranularity(app, options)\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;AAsDA,SAAgB,kBAAuC,WAAc,MAA+C;CAClH,OAAO,EACL,QAAQ,KAAU;EAChB,IAAI,UAAU,MAAM,SAAS;CAC/B,EACF;AACF;AAEA,SAAS,iBAAiB,KAAU,GAA0C;CAC5E,IAAI,OAAQ,EAAU,YAAY,YAAY;EAC3C,EAAW,QAAQ,GAAG;EACvB;CACF;CAIA,IACE,OAAQ,EAAU,SAAS,YACvB,EAAU,cACV,OAAQ,EAAU,cAAc,YAAY,OAAQ,EAAU,cAAc,aAChF;EACA,MAAM,EAAE,MAAM,cAAc;EAC5B,IAAI,UAAU,MAAM,SAAS;EAC7B;CACF;CAIA,MAAM,eACD,EAAoC,QACjC,EAA0B;CAClC,IAAI,cAAc;EAChB,IAAI,UAAU,cAAc,CAAc;EAC1C;CACF;CAGA,IAAI,EAAA,OAAA,YAAA,eAAA,QAAA,IAAA,aAAA,eACF;CAEF,QAAQ,KAAK,sGAAsG;AACrH;AAEA,SAAS,iBAAiB,KAAU,GAA0C;CAC5E,IAAI,aAAa,KAAK,OAAO,EAAE,YAAY,YAAY;EACrD,EAAE,QAAQ,GAAG;EACb;CACF;CAEA,IAAI,UAAU,KAAK,eAAe,GAAG;EACnC,IAAI,UAAU,EAAE,MAAM,EAAE,SAAS;EACjC;CACF;CAGA,IAAI,EAAA,OAAA,YAAA,eAAA,QAAA,IAAA,aAAA,eACF;CAEF,QAAQ,KAAK,0GAA0G;AACzH;;;;;AAMA,SAAgB,mBAAmB,KAAU,UAAoC,CAAC,GAAS;CACzF,KAAK,MAAM,KAAK,QAAQ,cAAc,CAAC,GACrC,iBAAiB,KAAK,CAAC;CAEzB,KAAK,MAAM,KAAK,QAAQ,cAAc,CAAC,GACrC,iBAAiB,KAAK,CAAC;CAEzB,KAAK,MAAM,EAAE,KAAK,WAAW,QAAQ,YAAY,CAAC,GAChD,IAAI,QAAQ,KAAY,KAAK;CAE/B,IAAI,QAAQ,kBACV,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,gBAAgB,GAChE,IAAI,OAAO,iBAAiB,OAAO;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,kBAAkB,UAAoC,CAAC,GAAW;CAChF,OAAO,EACL,QAAQ,KAAU;EAChB,mBAAmB,KAAK,OAAO;CACjC,EACF;AACF"}
|
package/dist/web-types.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/JetBrains/web-types/master/schema/web-types.json",
|
|
3
3
|
"name": "@feugene/granularity",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.32.0",
|
|
5
5
|
"framework": "vue",
|
|
6
6
|
"js-types-syntax": "typescript",
|
|
7
7
|
"description-markup": "markdown",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feugene/granularity",
|
|
3
3
|
"description": "Granularity design system package with Vue 3 components, consumed via the `@feugene/unocss-preset-granular` preset.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.32.0",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Evgeniy Fureev",
|
|
@@ -592,7 +592,7 @@
|
|
|
592
592
|
},
|
|
593
593
|
"peerDependencies": {
|
|
594
594
|
"@feugene/fint-i18n": "^0.6.0",
|
|
595
|
-
"@feugene/unocss-preset-granular": "^0.
|
|
595
|
+
"@feugene/unocss-preset-granular": "^0.11.0",
|
|
596
596
|
"@floating-ui/dom": "^1.8.0",
|
|
597
597
|
"vue": "^3.5.0"
|
|
598
598
|
},
|
|
@@ -608,7 +608,7 @@
|
|
|
608
608
|
"@antfu/eslint-config": "^9.1.0",
|
|
609
609
|
"@feugene/fint-i18n": "^0.6.0",
|
|
610
610
|
"@feugene/granularity-test-kit": "^0.7.0",
|
|
611
|
-
"@feugene/unocss-preset-granular": "^0.
|
|
611
|
+
"@feugene/unocss-preset-granular": "^0.11.0",
|
|
612
612
|
"@floating-ui/dom": "^1.8.0",
|
|
613
613
|
"@iconify-json/lucide": "^1.2.117",
|
|
614
614
|
"@types/node": "^25.9.5",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"grButtonStyles-B_-YRE__.js","names":[],"sources":["../../src/components/GrButton/grButtonStyles.ts"],"sourcesContent":["import type { GrComponentSize } from '../shared/sizes'\n\nimport type { GrTone } from '../shared/tones'\n\nexport type GrButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'ghost-border'\nexport type GrButtonTone = GrTone\nexport type GrButtonSize = GrComponentSize\n\nexport type GrButtonClassOptions = {\n variant: GrButtonVariant\n tone: GrButtonTone\n size: GrButtonSize\n square: boolean\n /** Необязательные: `grButtonClass` — публичный хелпер, его зовёт и `GrRadio`. */\n disabled?: boolean\n block?: boolean\n}\n\nexport type GrButtonToneTokens = {\n solidBackground: string\n solidBackgroundHover: string\n solidBackgroundActive: string\n solidForeground: string\n accentText: string\n softBackground: string\n softBackgroundHover: string\n softBackgroundActive: string\n softForeground: string\n border: string\n borderHover: string\n borderActive: string\n}\n\nexport const base =\n 'inline-flex items-center justify-center gap-2 select-none whitespace-nowrap rounded-[var(--gr-button-radius,0.375rem)] transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed'\n\n/** Кнопка на всю ширину контейнера. */\nexport const blockClass = 'w-full'\n\n/**\n * Отключённая кнопка гасится токенами, а не `opacity`: прозрачность разбавляет\n * выверенные на AA цвета, а кнопка чаще всего оказывается на цветной подложке,\n * где разбавленный текст проваливается первым.\n *\n * Классы применяются ВМЕСТО вариантных, а не поверх: два `bg-*` одной\n * специфичности разрулил бы порядок в сгенерированном CSS, а не порядок в\n * списке классов. Отсюда же и разбиение по вариантам: у прозрачных\n * (`outline`, `ghost`, `ghost-border`) заливки нет и в отключённом виде —\n * иначе стрелка пагинации превращалась бы в залитую плашку.\n */\nexport const disabledClassByVariant: Record<GrButtonVariant, string> = {\n primary: 'bg-[var(--gr-button-disabled-bg)] text-[var(--gr-button-disabled-fg)] border border-[var(--gr-button-disabled-brd)] cursor-not-allowed',\n secondary: 'bg-[var(--gr-button-disabled-bg)] text-[var(--gr-button-disabled-fg)] border border-[var(--gr-button-disabled-brd)] cursor-not-allowed',\n outline: 'bg-transparent text-[var(--gr-button-disabled-fg)] border border-[var(--gr-button-disabled-brd)] cursor-not-allowed',\n ghost: 'bg-transparent text-[var(--gr-button-disabled-fg)] cursor-not-allowed',\n 'ghost-border': 'bg-transparent text-[var(--gr-button-disabled-fg)] border border-transparent cursor-not-allowed',\n}\n\nexport const grButtonBaseClass = base\n\nexport const sizes: Record<GrButtonSize, string> = {\n xs: 'h-7 text-[length:var(--gr-text-xs)] leading-[var(--gr-leading-xs)] px-2.5',\n sm: 'h-8 text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] px-3',\n md: 'h-10 text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] px-4',\n lg: 'h-11 text-[length:var(--gr-text-base)] leading-[var(--gr-leading-base)] px-5',\n}\n\n/**\n * Квадратный режим — через `--gr-button-square-size` с размерным дефолтом в\n * fallback: потребитель задаёт переменную в своём CSS и подгоняет кнопку под\n * свою сетку (приём из `GrSlider`). Размер задаётся только здесь: инлайн-стиль\n * в SFC перекрыл бы эти классы, и переменная перестала бы что-либо значить.\n */\nexport const squareSizes: Record<GrButtonSize, string> = {\n xs: 'h-[var(--gr-button-square-size,1.75rem)] w-[var(--gr-button-square-size,1.75rem)] min-w-[var(--gr-button-square-size,1.75rem)] p-0',\n sm: 'h-[var(--gr-button-square-size,2rem)] w-[var(--gr-button-square-size,2rem)] min-w-[var(--gr-button-square-size,2rem)] p-0',\n md: 'h-[var(--gr-button-square-size,2.5rem)] w-[var(--gr-button-square-size,2.5rem)] min-w-[var(--gr-button-square-size,2.5rem)] p-0',\n lg: 'h-[var(--gr-button-square-size,2.75rem)] w-[var(--gr-button-square-size,2.75rem)] min-w-[var(--gr-button-square-size,2.75rem)] p-0',\n}\n\nexport const tones: Record<GrButtonTone, GrButtonToneTokens> = {\n primary: {\n solidBackground: 'var(--gr-button-primary-bg,var(--gr-primary))',\n solidBackgroundHover: 'var(--gr-button-primary-bg-hover,var(--gr-primary-hover))',\n solidBackgroundActive: 'var(--gr-button-primary-bg-active,var(--gr-primary-active))',\n solidForeground: 'var(--gr-button-primary-fg,var(--gr-primary-fg))',\n accentText: 'var(--gr-accent-fg)',\n softBackground: 'var(--gr-button-primary-soft-bg)',\n softBackgroundHover: 'var(--gr-button-primary-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-primary-soft-bg-active)',\n softForeground: 'var(--gr-accent-fg)',\n border: 'var(--gr-primary)',\n borderHover: 'var(--gr-primary-hover)',\n borderActive: 'var(--gr-primary-active)',\n },\n neutral: {\n solidBackground: 'var(--gr-secondary)',\n solidBackgroundHover: 'var(--gr-secondary-hover)',\n solidBackgroundActive: 'var(--gr-secondary-active)',\n solidForeground: 'var(--gr-secondary-fg)',\n accentText: 'var(--gr-fg)',\n softBackground: 'var(--gr-secondary)',\n softBackgroundHover: 'var(--gr-secondary-hover)',\n softBackgroundActive: 'var(--gr-secondary-active)',\n softForeground: 'var(--gr-secondary-fg)',\n border: 'var(--gr-brd)',\n borderHover: 'var(--gr-brd-hover,var(--gr-brd))',\n borderActive: 'var(--gr-brd-active,var(--gr-brd))',\n },\n success: {\n solidBackground: 'var(--gr-button-success-bg,var(--gr-success))',\n solidBackgroundHover: 'var(--gr-button-success-bg-hover,var(--gr-success-hover))',\n solidBackgroundActive: 'var(--gr-button-success-bg-active,var(--gr-success-active))',\n solidForeground: 'var(--gr-button-success-fg,var(--gr-success-fg,var(--gr-fg)))',\n accentText: 'var(--gr-success-text,var(--gr-success))',\n softBackground: 'var(--gr-button-success-soft-bg)',\n softBackgroundHover: 'var(--gr-button-success-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-success-soft-bg-active)',\n softForeground: 'var(--gr-success-text,var(--gr-success))',\n border: 'var(--gr-success)',\n borderHover: 'var(--gr-success-hover)',\n borderActive: 'var(--gr-success-active)',\n },\n warning: {\n solidBackground: 'var(--gr-button-warning-bg,var(--gr-warning))',\n solidBackgroundHover: 'var(--gr-button-warning-bg-hover,var(--gr-warning-hover))',\n solidBackgroundActive: 'var(--gr-button-warning-bg-active,var(--gr-warning-active))',\n solidForeground: 'var(--gr-button-warning-fg,var(--gr-warning-fg,var(--gr-fg)))',\n accentText: 'var(--gr-warning-text,var(--gr-warning))',\n softBackground: 'var(--gr-button-warning-soft-bg)',\n softBackgroundHover: 'var(--gr-button-warning-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-warning-soft-bg-active)',\n softForeground: 'var(--gr-warning-text,var(--gr-warning))',\n border: 'var(--gr-warning)',\n borderHover: 'var(--gr-warning-hover)',\n borderActive: 'var(--gr-warning-active)',\n },\n danger: {\n solidBackground: 'var(--gr-button-danger-bg,var(--gr-danger))',\n solidBackgroundHover: 'var(--gr-button-danger-bg-hover,var(--gr-danger-hover))',\n solidBackgroundActive: 'var(--gr-button-danger-bg-active,var(--gr-danger-active))',\n solidForeground: 'var(--gr-button-danger-fg,var(--gr-danger-fg,var(--gr-fg)))',\n accentText: 'var(--gr-danger-text,var(--gr-danger))',\n softBackground: 'var(--gr-button-danger-soft-bg)',\n softBackgroundHover: 'var(--gr-button-danger-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-danger-soft-bg-active)',\n softForeground: 'var(--gr-danger-text,var(--gr-danger))',\n border: 'var(--gr-danger)',\n borderHover: 'var(--gr-danger-hover)',\n borderActive: 'var(--gr-danger-active)',\n },\n info: {\n solidBackground: 'var(--gr-button-info-bg,var(--gr-info))',\n solidBackgroundHover: 'var(--gr-button-info-bg-hover,var(--gr-info-hover))',\n solidBackgroundActive: 'var(--gr-button-info-bg-active,var(--gr-info-active))',\n solidForeground: 'var(--gr-button-info-fg,var(--gr-info-fg,var(--gr-fg)))',\n accentText: 'var(--gr-info-text,var(--gr-info))',\n softBackground: 'var(--gr-button-info-soft-bg)',\n softBackgroundHover: 'var(--gr-button-info-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-info-soft-bg-active)',\n softForeground: 'var(--gr-info-text,var(--gr-info))',\n border: 'var(--gr-info)',\n borderHover: 'var(--gr-info-hover)',\n borderActive: 'var(--gr-info-active)',\n },\n slate: {\n solidBackground: 'var(--gr-button-slate-bg,var(--gr-slate))',\n solidBackgroundHover: 'var(--gr-button-slate-bg-hover,var(--gr-slate-hover))',\n solidBackgroundActive: 'var(--gr-button-slate-bg-active,var(--gr-slate-active))',\n solidForeground: 'var(--gr-button-slate-fg,var(--gr-slate-fg,var(--gr-fg)))',\n accentText: 'var(--gr-slate-text,var(--gr-slate))',\n softBackground: 'var(--gr-button-slate-soft-bg)',\n softBackgroundHover: 'var(--gr-button-slate-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-slate-soft-bg-active)',\n softForeground: 'var(--gr-slate-text,var(--gr-slate))',\n border: 'var(--gr-slate)',\n borderHover: 'var(--gr-slate-hover)',\n borderActive: 'var(--gr-slate-active)',\n },\n azure: {\n solidBackground: 'var(--gr-button-azure-bg,var(--gr-azure))',\n solidBackgroundHover: 'var(--gr-button-azure-bg-hover,var(--gr-azure-hover))',\n solidBackgroundActive: 'var(--gr-button-azure-bg-active,var(--gr-azure-active))',\n solidForeground: 'var(--gr-button-azure-fg,var(--gr-azure-fg,var(--gr-fg)))',\n accentText: 'var(--gr-azure-text,var(--gr-azure))',\n softBackground: 'var(--gr-button-azure-soft-bg)',\n softBackgroundHover: 'var(--gr-button-azure-soft-bg-hover)',\n softBackgroundActive: 'var(--gr-button-azure-soft-bg-active)',\n softForeground: 'var(--gr-azure-text,var(--gr-azure))',\n border: 'var(--gr-azure)',\n borderHover: 'var(--gr-azure-hover)',\n borderActive: 'var(--gr-azure-active)',\n },\n}\n\nfunction withVar(token: string): string {\n return `[${token}]`\n}\n\nexport function variantClass(variant: GrButtonVariant, tone: GrButtonTone): string {\n const tokens = tones[tone]\n\n if (variant === 'primary') {\n return [\n `bg-${withVar(tokens.solidBackground)}`,\n `text-${withVar(tokens.solidForeground)}`,\n `border border-${withVar(tokens.solidBackground)}`,\n `hover:bg-${withVar(tokens.solidBackgroundHover)}`,\n `hover:border-${withVar(tokens.solidBackgroundHover)}`,\n `active:bg-${withVar(tokens.solidBackgroundActive)}`,\n `hover:active:bg-${withVar(tokens.solidBackgroundActive)}`,\n `active:border-${withVar(tokens.solidBackgroundActive)}`,\n `hover:active:border-${withVar(tokens.solidBackgroundActive)}`,\n ].join(' ')\n }\n\n if (variant === 'secondary') {\n return [\n `bg-${withVar(tokens.softBackground)}`,\n `text-${withVar(tokens.softForeground)}`,\n `border border-${withVar(tokens.border)}`,\n `hover:bg-${withVar(tokens.softBackgroundHover)}`,\n `hover:border-${withVar(tokens.borderHover)}`,\n `active:bg-${withVar(tokens.softBackgroundActive)}`,\n `hover:active:bg-${withVar(tokens.softBackgroundActive)}`,\n `active:border-${withVar(tokens.borderActive)}`,\n `hover:active:border-${withVar(tokens.borderActive)}`,\n ].join(' ')\n }\n\n if (variant === 'outline') {\n return [\n 'bg-transparent',\n `text-${withVar(tokens.accentText)}`,\n `border border-${withVar(tokens.border)}`,\n `hover:bg-${withVar(tokens.softBackgroundHover)}`,\n `hover:border-${withVar(tokens.borderHover)}`,\n `active:bg-${withVar(tokens.softBackgroundActive)}`,\n `hover:active:bg-${withVar(tokens.softBackgroundActive)}`,\n `active:border-${withVar(tokens.borderActive)}`,\n `hover:active:border-${withVar(tokens.borderActive)}`,\n ].join(' ')\n }\n\n if (variant === 'ghost') {\n return [\n 'bg-transparent',\n `text-${withVar(tokens.accentText)}`,\n `hover:bg-${withVar(tokens.softBackgroundHover)}`,\n `active:bg-${withVar(tokens.softBackgroundActive)}`,\n `hover:active:bg-${withVar(tokens.softBackgroundActive)}`,\n ].join(' ')\n }\n\n return [\n 'bg-transparent',\n `text-${withVar(tokens.accentText)}`,\n 'border border-transparent',\n `hover:bg-${withVar(tokens.softBackgroundHover)}`,\n `hover:border-${withVar(tokens.borderHover)}`,\n `active:bg-${withVar(tokens.softBackgroundActive)}`,\n `hover:active:bg-${withVar(tokens.softBackgroundActive)}`,\n `active:border-${withVar(tokens.borderActive)}`,\n `hover:active:border-${withVar(tokens.borderActive)}`,\n ].join(' ')\n}\n\nexport function grButtonClass(options: GrButtonClassOptions): string {\n return [\n options.square ? squareSizes[options.size] : sizes[options.size],\n options.block ? blockClass : '',\n // `loading` сюда не входит: у него свой спиннер, и выглядеть отключённым он\n // не должен.\n options.disabled ? disabledClassByVariant[options.variant] : variantClass(options.variant, options.tone),\n ].filter(Boolean).join(' ')\n}\n"],"mappings":"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"}
|