@feugene/granularity 0.42.0 → 0.44.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 +2 -2
- package/dist/chunks/config-BXRmsn3t.js +172 -0
- package/dist/chunks/config-BXRmsn3t.js.map +1 -0
- package/dist/chunks/config-BkQ2jvXv.js +49 -0
- package/dist/chunks/config-BkQ2jvXv.js.map +1 -0
- package/dist/chunks/config-Dg0bSoGw.js +81 -0
- package/dist/chunks/config-Dg0bSoGw.js.map +1 -0
- package/dist/chunks/config-DmED6aJV.js +237 -0
- package/dist/chunks/config-DmED6aJV.js.map +1 -0
- package/dist/chunks/{config-DWL81-aM.js → config-hnoZvcIM.js} +2 -20
- package/dist/chunks/config-hnoZvcIM.js.map +1 -0
- package/dist/chunks/dragSortGeometry-CY-llfrQ.js +87 -0
- package/dist/chunks/dragSortGeometry-CY-llfrQ.js.map +1 -0
- package/dist/chunks/{en-B9E3jO6m.js → en-DiHzFact.js} +34 -1
- package/dist/chunks/en-DiHzFact.js.map +1 -0
- package/dist/chunks/{es-QpzdIEut.js → es-1ZL6NtkB.js} +34 -1
- package/dist/chunks/es-1ZL6NtkB.js.map +1 -0
- package/dist/chunks/{es-DCkqHTlU.js → es-CeKkMxZ_.js} +3 -3
- package/dist/chunks/{es-DCkqHTlU.js.map → es-CeKkMxZ_.js.map} +1 -1
- package/dist/chunks/{generated-B95IBXs6.js → generated-Hxu_sWPs.js} +238 -0
- package/dist/chunks/generated-Hxu_sWPs.js.map +1 -0
- package/dist/chunks/{granular-provider-BG_2XqkS.js → granular-provider-CCNbQa5U.js} +9 -1
- package/dist/chunks/granular-provider-CCNbQa5U.js.map +1 -0
- package/dist/chunks/{ru-D_1Ya489.js → ru-Dr2RYn0P.js} +34 -1
- package/dist/chunks/ru-Dr2RYn0P.js.map +1 -0
- package/dist/chunks/scrollOverflow-B_kEdcol.js +31 -0
- package/dist/chunks/scrollOverflow-B_kEdcol.js.map +1 -0
- package/dist/chunks/tones-CRJAaYyg.js +21 -0
- package/dist/chunks/tones-CRJAaYyg.js.map +1 -0
- package/dist/chunks/useScrollSpy-CIJpw0RI.js +360 -0
- package/dist/chunks/useScrollSpy-CIJpw0RI.js.map +1 -0
- package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js +272 -0
- package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js.map +1 -0
- package/dist/components/GrAffix/index.js +3 -0
- package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js +761 -0
- package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +1 -0
- package/dist/components/GrCarousel/index.js +3 -0
- package/dist/components/GrCarousel/styles.css +1 -0
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js → GrColorPicker-9mTR-YZ_.js} +1 -1
- package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js.map → GrColorPicker-9mTR-YZ_.js.map} +1 -1
- package/dist/components/GrColorPicker/index.js +1 -1
- package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js → GrDataTable-xNSmO_I-.js} +4 -3
- package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js.map → GrDataTable-xNSmO_I-.js.map} +1 -1
- package/dist/components/GrDataTable/index.js +1 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js.map → GrImageViewer-DK-iVHHC.js.map} +1 -1
- package/dist/components/GrImageViewer/index.js +1 -1
- package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js.map → GrInputTag-Ci8AO1ze.js.map} +1 -1
- package/dist/components/GrInputTag/index.js +1 -1
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js → GrJsonViewer-CwCBMh4h.js} +2 -2
- package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js.map → GrJsonViewer-CwCBMh4h.js.map} +1 -1
- package/dist/components/GrJsonViewer/index.js +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js.map → GrNumberInput-CL5QhOmx.js.map} +1 -1
- package/dist/components/GrNumberInput/index.js +1 -1
- package/dist/components/GrProgressBar/index.js +1 -1
- package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js +207 -0
- package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js.map +1 -0
- package/dist/components/GrScrollSpy/index.js +3 -0
- package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js.map → GrSlider-CO8N9SF6.js.map} +1 -1
- package/dist/components/GrSlider/index.js +1 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js → GrSortableList-NKriuGm_.js} +2 -1
- package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js.map → GrSortableList-NKriuGm_.js.map} +1 -1
- package/dist/components/GrSortableList/index.js +1 -1
- package/dist/components/GrTabs/chunks/{GrTabs-BArefUFv.js → GrTabs-s9RzC1WX.js} +2 -31
- package/dist/components/GrTabs/chunks/GrTabs-s9RzC1WX.js.map +1 -0
- package/dist/components/GrTabs/index.js +1 -1
- package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js +1368 -0
- package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js.map +1 -0
- package/dist/components/GrTransfer/index.js +3 -0
- package/dist/components/GrTransfer/styles.css +1 -0
- package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js → GrTree-CkHzgYg1.js} +3 -3
- package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js.map → GrTree-CkHzgYg1.js.map} +1 -1
- package/dist/components/GrTree/index.js +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js → GrTreeSelect-DUsv3_mF.js} +1 -1
- package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js.map → GrTreeSelect-DUsv3_mF.js.map} +1 -1
- package/dist/components/GrTreeSelect/index.js +1 -1
- package/dist/composables/useDragSort.js +179 -1
- package/dist/composables/useDragSort.js.map +1 -0
- package/dist/composables/useScrollSpy.js +2 -0
- package/dist/granular-provider-node.js +1 -1
- package/dist/granular-provider.js +1 -1
- package/dist/i18n/all.js +1 -1
- package/dist/i18n/index.js +1 -1
- package/dist/index.js +26 -19
- package/dist/theme.js +1 -1
- package/dist/tokens.js +1 -1
- package/dist/types/components/GrAffix/GrAffix.vue.d.ts +91 -0
- package/dist/types/components/GrAffix/affixState.d.ts +81 -0
- package/dist/types/components/GrAffix/config.d.ts +1 -0
- package/dist/types/components/GrAffix/grAffixStyles.d.ts +46 -0
- package/dist/types/components/GrAffix/index.d.ts +9 -0
- package/dist/types/components/GrAffix/safelist.d.ts +1 -0
- package/dist/types/components/GrAlert/GrAlert.vue.d.ts +1 -1
- package/dist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +2 -2
- package/dist/types/components/GrButton/GrButton.vue.d.ts +2 -2
- package/dist/types/components/GrCard/GrCard.vue.d.ts +1 -1
- package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +151 -0
- package/dist/types/components/GrCarousel/GrCarouselSlide.vue.d.ts +53 -0
- package/dist/types/components/GrCarousel/carouselNavigation.d.ts +57 -0
- package/dist/types/components/GrCarousel/composables/useCarouselAutoplay.d.ts +33 -0
- package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +20 -0
- package/dist/types/components/GrCarousel/config.d.ts +7 -0
- package/dist/types/components/GrCarousel/defaults.d.ts +13 -0
- package/dist/types/components/GrCarousel/grCarouselContext.d.ts +46 -0
- package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +80 -0
- package/dist/types/components/GrCarousel/index.d.ts +12 -0
- package/dist/types/components/GrCarousel/safelist.d.ts +1 -0
- package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +3 -3
- package/dist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts +2 -2
- package/dist/types/components/GrChip/GrChip.vue.d.ts +2 -2
- package/dist/types/components/GrChipGroup/GrChipGroup.vue.d.ts +2 -2
- package/dist/types/components/GrCollapse/GrCollapse.vue.d.ts +1 -1
- package/dist/types/components/GrCollapse/GrCollapseItem.vue.d.ts +1 -1
- package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +3 -3
- package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +1 -1
- package/dist/types/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +1 -1
- package/dist/types/components/GrContextMenu/GrContextMenu.vue.d.ts +2 -2
- package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
- package/dist/types/components/GrDivider/GrDivider.vue.d.ts +2 -2
- package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
- package/dist/types/components/GrDropdown/GrDropdown.vue.d.ts +3 -3
- package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +3 -3
- package/dist/types/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +1 -1
- package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +1 -1
- package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
- package/dist/types/components/GrFormField/GrFormField.vue.d.ts +3 -3
- package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
- package/dist/types/components/GrFormSection/GrFormSection.vue.d.ts +1 -1
- package/dist/types/components/GrIcon/GrIcon.vue.d.ts +1 -1
- package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +3 -3
- package/dist/types/components/GrInput/GrInput.vue.d.ts +4 -4
- package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +3 -3
- package/dist/types/components/GrKbd/GrKbd.vue.d.ts +1 -1
- package/dist/types/components/GrLink/GrLink.vue.d.ts +1 -1
- package/dist/types/components/GrList/GrListItem.vue.d.ts +2 -2
- package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +2 -2
- package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +3 -3
- package/dist/types/components/GrPagination/GrPagination.vue.d.ts +1 -1
- package/dist/types/components/GrPopover/GrPopover.vue.d.ts +3 -3
- package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +3 -3
- package/dist/types/components/GrRadio/GrRadio.vue.d.ts +2 -2
- package/dist/types/components/GrRadioGroup/GrRadioGroup.vue.d.ts +2 -2
- package/dist/types/components/GrRating/GrRating.vue.d.ts +2 -2
- package/dist/types/components/GrScrollSpy/GrScrollSpy.vue.d.ts +105 -0
- package/dist/types/components/GrScrollSpy/config.d.ts +1 -0
- package/dist/types/components/GrScrollSpy/grScrollSpyStyles.d.ts +26 -0
- package/dist/types/components/GrScrollSpy/index.d.ts +9 -0
- package/dist/types/components/GrScrollSpy/safelist.d.ts +1 -0
- package/dist/types/components/GrScrollSpy/scrollSpyItems.d.ts +44 -0
- package/dist/types/components/GrSegmented/GrSegmented.vue.d.ts +2 -2
- package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +1 -1
- package/dist/types/components/GrSkeleton/GrSkeleton.vue.d.ts +1 -1
- package/dist/types/components/GrSlider/GrSlider.vue.d.ts +3 -3
- package/dist/types/components/GrSplitter/GrSplitter.vue.d.ts +1 -1
- package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +2 -2
- package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +3 -3
- package/dist/types/components/GrTable/GrTable.vue.d.ts +1 -1
- package/dist/types/components/GrTabs/GrTabs.vue.d.ts +1 -1
- package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
- package/dist/types/components/GrTimeline/GrTimelineItem.vue.d.ts +2 -2
- package/dist/types/components/GrToaster/GrToaster.vue.d.ts +1 -1
- package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +3 -3
- package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +103 -0
- package/dist/types/components/GrTransfer/config.d.ts +1 -0
- package/dist/types/components/GrTransfer/defaults.d.ts +15 -0
- package/dist/types/components/GrTransfer/grTransferStyles.d.ts +127 -0
- package/dist/types/components/GrTransfer/index.d.ts +11 -0
- package/dist/types/components/GrTransfer/safelist.d.ts +1 -0
- package/dist/types/components/GrTransfer/transferGeometry.d.ts +44 -0
- package/dist/types/components/GrTransfer/transferModel.d.ts +68 -0
- package/dist/types/components/GrTransfer/transferSelection.d.ts +36 -0
- package/dist/types/components/GrTransfer/useTransferDrag.d.ts +48 -0
- package/dist/types/composables/internal/scrollSpyGeometry.d.ts +67 -0
- package/dist/types/composables/useScrollSpy.d.ts +59 -0
- package/dist/types/granular-provider/shared.d.ts +4 -0
- package/dist/types/i18n/messages/en.d.ts +64 -0
- package/dist/types/i18n/messages/es.d.ts +64 -0
- package/dist/types/i18n/messages/ru.d.ts +64 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/web-types.json +809 -284
- package/package.json +25 -1
- package/dist/chunks/config-DWL81-aM.js.map +0 -1
- package/dist/chunks/en-B9E3jO6m.js.map +0 -1
- package/dist/chunks/es-QpzdIEut.js.map +0 -1
- package/dist/chunks/generated-B95IBXs6.js.map +0 -1
- package/dist/chunks/granular-provider-BG_2XqkS.js.map +0 -1
- package/dist/chunks/ru-D_1Ya489.js.map +0 -1
- package/dist/chunks/useDragSort-0l47h4yb.js +0 -265
- package/dist/chunks/useDragSort-0l47h4yb.js.map +0 -1
- package/dist/components/GrTabs/chunks/GrTabs-BArefUFv.js.map +0 -1
- package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js → GrImageViewer-DK-iVHHC.js} +3 -3
- package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js → GrInputTag-Ci8AO1ze.js} +1 -1
- package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js → GrNumberInput-CL5QhOmx.js} +1 -1
- package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js → GrSlider-CO8N9SF6.js} +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as grAffixConfig } from "./config-Dg0bSoGw.js";
|
|
1
2
|
import { t as grAlertConfig } from "./config-BNu8lFQB.js";
|
|
2
3
|
import { t as grAutocompleteConfig } from "./config-BHLMTJaR.js";
|
|
3
4
|
import { t as grAvatarConfig } from "./config-B3J0alyY.js";
|
|
@@ -8,6 +9,7 @@ import { t as grBreadcrumbsConfig } from "./config-C0Eu8jpG.js";
|
|
|
8
9
|
import { t as grButtonConfig } from "./config-87fszqnD.js";
|
|
9
10
|
import { t as grButtonGroupConfig } from "./config-DBmdgoVf.js";
|
|
10
11
|
import { t as grCardConfig } from "./config-DUbbGcfw.js";
|
|
12
|
+
import { t as grCarouselConfig } from "./config-BXRmsn3t.js";
|
|
11
13
|
import { t as grCheckboxConfig } from "./config-DZCUPHPU.js";
|
|
12
14
|
import { t as grCheckboxGroupConfig } from "./config-BuGlNPE9.js";
|
|
13
15
|
import { t as grChipConfig } from "./config-2vrOFn2f.js";
|
|
@@ -49,12 +51,13 @@ import { t as grNavbarConfig } from "./config-2ZHRsdOc.js";
|
|
|
49
51
|
import { t as grNumberInputConfig } from "./config-MmPym-Z7.js";
|
|
50
52
|
import { t as grPaginationConfig } from "./config-CjKpUcmy.js";
|
|
51
53
|
import { t as grPopoverConfig } from "./config-tNqtapcT.js";
|
|
52
|
-
import { t as grProgressBarConfig } from "./config-
|
|
54
|
+
import { t as grProgressBarConfig } from "./config-hnoZvcIM.js";
|
|
53
55
|
import { t as grProgressCircleConfig } from "./config-CJzmDHfI.js";
|
|
54
56
|
import { t as grPromptDialogConfig } from "./config-C0Ea9ePP.js";
|
|
55
57
|
import { t as grRadioConfig } from "./config-BUNxHnEz.js";
|
|
56
58
|
import { t as grRadioGroupConfig } from "./config-QaIc_gRa.js";
|
|
57
59
|
import { t as grRatingConfig } from "./config-DRbojEzO.js";
|
|
60
|
+
import { t as grScrollSpyConfig } from "./config-BkQ2jvXv.js";
|
|
58
61
|
import { t as grSegmentedConfig } from "./config-rLkc9Zn2.js";
|
|
59
62
|
import { t as grSelectConfig } from "./config--t2dxj0t.js";
|
|
60
63
|
import { t as grSidebarConfig } from "./config-DNDgp9bB.js";
|
|
@@ -72,6 +75,7 @@ import { t as grTextareaConfig } from "./config-BhfNgyWL.js";
|
|
|
72
75
|
import { t as grTimelineConfig } from "./config-Bd7QfiGj.js";
|
|
73
76
|
import { t as grToasterConfig } from "./config-B5SBUa6u.js";
|
|
74
77
|
import { t as grTooltipConfig } from "./config-iemgzS4x.js";
|
|
78
|
+
import { t as grTransferConfig } from "./config-DmED6aJV.js";
|
|
75
79
|
import { t as grTreeConfig } from "./config-CDat1wXf.js";
|
|
76
80
|
import { t as grTreeSelectConfig } from "./config-BGCyyXiD.js";
|
|
77
81
|
import { defineGranularComponent, defineGranularProvider, resolvePackageBaseUrl } from "@feugene/unocss-preset-granular/contract";
|
|
@@ -110,6 +114,7 @@ var theme = {
|
|
|
110
114
|
* `@feugene/granularity/components/<Name>`.
|
|
111
115
|
*/
|
|
112
116
|
var granularityComponentConfigs = {
|
|
117
|
+
GrAffix: grAffixConfig,
|
|
113
118
|
GrAlert: grAlertConfig,
|
|
114
119
|
GrAutocomplete: grAutocompleteConfig,
|
|
115
120
|
GrAvatar: grAvatarConfig,
|
|
@@ -120,6 +125,7 @@ var granularityComponentConfigs = {
|
|
|
120
125
|
GrButton: grButtonConfig,
|
|
121
126
|
GrButtonGroup: grButtonGroupConfig,
|
|
122
127
|
GrCard: grCardConfig,
|
|
128
|
+
GrCarousel: grCarouselConfig,
|
|
123
129
|
GrCheckbox: grCheckboxConfig,
|
|
124
130
|
GrCheckboxGroup: grCheckboxGroupConfig,
|
|
125
131
|
GrChip: grChipConfig,
|
|
@@ -167,6 +173,7 @@ var granularityComponentConfigs = {
|
|
|
167
173
|
GrRadioGroup: grRadioGroupConfig,
|
|
168
174
|
GrRating: grRatingConfig,
|
|
169
175
|
GrResponseErrorBanner: grResponseErrorBannerConfig,
|
|
176
|
+
GrScrollSpy: grScrollSpyConfig,
|
|
170
177
|
GrSegmented: grSegmentedConfig,
|
|
171
178
|
GrSelect: grSelectConfig,
|
|
172
179
|
GrSidebar: grSidebarConfig,
|
|
@@ -184,6 +191,7 @@ var granularityComponentConfigs = {
|
|
|
184
191
|
GrTimeline: grTimelineConfig,
|
|
185
192
|
GrToaster: grToasterConfig,
|
|
186
193
|
GrTooltip: grTooltipConfig,
|
|
194
|
+
GrTransfer: grTransferConfig,
|
|
187
195
|
GrTree: grTreeConfig,
|
|
188
196
|
GrTreeSelect: grTreeSelectConfig,
|
|
189
197
|
GrValue: grValueConfig
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"granular-provider-CCNbQa5U.js","names":[],"sources":["../../src/components/GrDialog/config.ts","../../src/components/GrResponseErrorBanner/config.ts","../../src/granular-provider/shared.ts","../../src/granular-provider/index.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grDialogSafelist } from './safelist'\n\nexport const grDialogConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDialog',\n dependencies: ['GrButton', 'GrModal'],\n safelist: grDialogSafelist,\n})\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grResponseErrorBannerConfig = defineGranularComponent(import.meta.url, {\n name: 'GrResponseErrorBanner',\n dependencies: ['GrAlert', 'GrButton'],\n})\n","// `id`, `theme.*`, `packageBaseUrl` и реестр компонентов провайдера.\n//\n// Все `new URL('../styles/...', import.meta.url)` обязаны лежать именно здесь:\n// `shared.ts` в одной директории с `index.ts` / `node.ts`, поэтому\n// относительные пути совпадают. Для браузера безопасно — бандлеры\n// транслируют такие литералы в статические asset-URL.\n//\n// `apps/showcase/scripts/generate-component-api.mjs` читает список компонентов\n// из `Object.keys(granularityComponentConfigs)` через vite SSR.\nimport {\n defineGranularProvider,\n type GranularComponentDescriptor,\n type GranularProvider,\n resolvePackageBaseUrl,\n} from '@feugene/unocss-preset-granular/contract'\n// <granularity:components:imports> — блок генерируется `yarn generate:registry`\nimport { grAffixConfig } from '../components/GrAffix/config'\nimport { grAlertConfig } from '../components/GrAlert/config'\nimport { grAutocompleteConfig } from '../components/GrAutocomplete/config'\nimport { grAvatarConfig } from '../components/GrAvatar/config'\nimport { grBadgeConfig } from '../components/GrBadge/config'\nimport { grBadgeWrapConfig } from '../components/GrBadgeWrap/config'\nimport { grBottomNavConfig } from '../components/GrBottomNav/config'\nimport { grBreadcrumbsConfig } from '../components/GrBreadcrumbs/config'\nimport { grButtonConfig } from '../components/GrButton/config'\nimport { grButtonGroupConfig } from '../components/GrButtonGroup/config'\nimport { grCardConfig } from '../components/GrCard/config'\nimport { grCarouselConfig } from '../components/GrCarousel/config'\nimport { grCheckboxConfig } from '../components/GrCheckbox/config'\nimport { grCheckboxGroupConfig } from '../components/GrCheckboxGroup/config'\nimport { grChipConfig } from '../components/GrChip/config'\nimport { grChipGroupConfig } from '../components/GrChipGroup/config'\nimport { grCollapseConfig } from '../components/GrCollapse/config'\nimport { grColorPickerConfig } from '../components/GrColorPicker/config'\nimport { grCommandPaletteConfig } from '../components/GrCommandPalette/config'\nimport { grConfigProviderConfig } from '../components/GrConfigProvider/config'\nimport { grConfirmDialogConfig } from '../components/GrConfirmDialog/config'\nimport { grContextMenuConfig } from '../components/GrContextMenu/config'\nimport { grDataTableConfig } from '../components/GrDataTable/config'\nimport { grDeltaConfig } from '../components/GrDelta/config'\nimport { grDescriptionListConfig } from '../components/GrDescriptionList/config'\nimport { grDialogConfig } from '../components/GrDialog/config'\nimport { grDialogServiceConfig } from '../components/GrDialogService/config'\nimport { grDividerConfig } from '../components/GrDivider/config'\nimport { grDrawerConfig } from '../components/GrDrawer/config'\nimport { grDropdownConfig } from '../components/GrDropdown/config'\nimport { grDropdownMenuConfig } from '../components/GrDropdownMenu/config'\nimport { grEmptyStateConfig } from '../components/GrEmptyState/config'\nimport { grFilePreviewConfig } from '../components/GrFilePreview/config'\nimport { grFileUploadConfig } from '../components/GrFileUpload/config'\nimport { grFormConfig } from '../components/GrForm/config'\nimport { grFormFieldConfig } from '../components/GrFormField/config'\nimport { grFormFileConfig } from '../components/GrFormFile/config'\nimport { grFormSectionConfig } from '../components/GrFormSection/config'\nimport { grIconConfig } from '../components/GrIcon/config'\nimport { grImageViewerConfig } from '../components/GrImageViewer/config'\nimport { grInputConfig } from '../components/GrInput/config'\nimport { grInputTagConfig } from '../components/GrInputTag/config'\nimport { grJsonViewerConfig } from '../components/GrJsonViewer/config'\nimport { grKbdConfig } from '../components/GrKbd/config'\nimport { grLinkConfig } from '../components/GrLink/config'\nimport { grListConfig } from '../components/GrList/config'\nimport { grLoadingConfig } from '../components/GrLoading/config'\nimport { grModalConfig } from '../components/GrModal/config'\nimport { grNavbarConfig } from '../components/GrNavbar/config'\nimport { grNumberInputConfig } from '../components/GrNumberInput/config'\nimport { grPaginationConfig } from '../components/GrPagination/config'\nimport { grPopoverConfig } from '../components/GrPopover/config'\nimport { grProgressBarConfig } from '../components/GrProgressBar/config'\nimport { grProgressCircleConfig } from '../components/GrProgressCircle/config'\nimport { grPromptDialogConfig } from '../components/GrPromptDialog/config'\nimport { grRadioConfig } from '../components/GrRadio/config'\nimport { grRadioGroupConfig } from '../components/GrRadioGroup/config'\nimport { grRatingConfig } from '../components/GrRating/config'\nimport { grResponseErrorBannerConfig } from '../components/GrResponseErrorBanner/config'\nimport { grScrollSpyConfig } from '../components/GrScrollSpy/config'\nimport { grSegmentedConfig } from '../components/GrSegmented/config'\nimport { grSelectConfig } from '../components/GrSelect/config'\nimport { grSidebarConfig } from '../components/GrSidebar/config'\nimport { grSkeletonConfig } from '../components/GrSkeleton/config'\nimport { grSliderConfig } from '../components/GrSlider/config'\nimport { grSortableListConfig } from '../components/GrSortableList/config'\nimport { grSplitterConfig } from '../components/GrSplitter/config'\nimport { grStatisticConfig } from '../components/GrStatistic/config'\nimport { grStepsConfig } from '../components/GrSteps/config'\nimport { grSwitchConfig } from '../components/GrSwitch/config'\nimport { grTableConfig } from '../components/GrTable/config'\nimport { grTabPanelsConfig } from '../components/GrTabPanels/config'\nimport { grTabsConfig } from '../components/GrTabs/config'\nimport { grTextareaConfig } from '../components/GrTextarea/config'\nimport { grTimelineConfig } from '../components/GrTimeline/config'\nimport { grToasterConfig } from '../components/GrToaster/config'\nimport { grTooltipConfig } from '../components/GrTooltip/config'\nimport { grTransferConfig } from '../components/GrTransfer/config'\nimport { grTreeConfig } from '../components/GrTree/config'\nimport { grTreeSelectConfig } from '../components/GrTreeSelect/config'\nimport { grValueConfig } from '../components/GrValue/config'\n// </granularity:components:imports>\n\n/** Идентификатор провайдера — совпадает с именем пакета. */\nexport const GRANULARITY_PROVIDER_ID = '@feugene/granularity'\n\n// Не заменять на `new URL('..', import.meta.url)`: Vite и rolldown распознают\n// этот литерал и подставляют `data:`-URL, после чего scan-директории пустеют.\nconst packageBaseUrl = resolvePackageBaseUrl(import.meta.url)\n\n/** Встроенные темы пакета. Единственный источник правды о списке тем. */\nexport const granularityThemeNames = ['light', 'dark'] as const\nexport type GranularityThemeName = (typeof granularityThemeNames)[number]\n\n/** Темы, активные по умолчанию, если окружение не переопределяет выбор. */\nexport const granularityDefaultThemes: readonly GranularityThemeName[] = ['light']\n\nconst theme = {\n baseCssUrl: new URL('../styles/base.css', import.meta.url).href,\n tokensCssUrl: new URL('../styles/tokens.css', import.meta.url).href,\n themes: {\n light: new URL('../styles/themes/light.css', import.meta.url).href,\n dark: new URL('../styles/themes/dark.css', import.meta.url).href,\n },\n defaultThemes: granularityDefaultThemes,\n} as const\n\n/**\n * Реестр публичных компонентов. Ключи совпадают с subpath-экспортом\n * `@feugene/granularity/components/<Name>`.\n */\nexport const granularityComponentConfigs = {\n // <granularity:components:registry> — блок генерируется `yarn generate:registry`\n GrAffix: grAffixConfig,\n GrAlert: grAlertConfig,\n GrAutocomplete: grAutocompleteConfig,\n GrAvatar: grAvatarConfig,\n GrBadge: grBadgeConfig,\n GrBadgeWrap: grBadgeWrapConfig,\n GrBottomNav: grBottomNavConfig,\n GrBreadcrumbs: grBreadcrumbsConfig,\n GrButton: grButtonConfig,\n GrButtonGroup: grButtonGroupConfig,\n GrCard: grCardConfig,\n GrCarousel: grCarouselConfig,\n GrCheckbox: grCheckboxConfig,\n GrCheckboxGroup: grCheckboxGroupConfig,\n GrChip: grChipConfig,\n GrChipGroup: grChipGroupConfig,\n GrCollapse: grCollapseConfig,\n GrColorPicker: grColorPickerConfig,\n GrCommandPalette: grCommandPaletteConfig,\n GrConfigProvider: grConfigProviderConfig,\n GrConfirmDialog: grConfirmDialogConfig,\n GrContextMenu: grContextMenuConfig,\n GrDataTable: grDataTableConfig,\n GrDelta: grDeltaConfig,\n GrDescriptionList: grDescriptionListConfig,\n GrDialog: grDialogConfig,\n GrDialogService: grDialogServiceConfig,\n GrDivider: grDividerConfig,\n GrDrawer: grDrawerConfig,\n GrDropdown: grDropdownConfig,\n GrDropdownMenu: grDropdownMenuConfig,\n GrEmptyState: grEmptyStateConfig,\n GrFilePreview: grFilePreviewConfig,\n GrFileUpload: grFileUploadConfig,\n GrForm: grFormConfig,\n GrFormField: grFormFieldConfig,\n GrFormFile: grFormFileConfig,\n GrFormSection: grFormSectionConfig,\n GrIcon: grIconConfig,\n GrImageViewer: grImageViewerConfig,\n GrInput: grInputConfig,\n GrInputTag: grInputTagConfig,\n GrJsonViewer: grJsonViewerConfig,\n GrKbd: grKbdConfig,\n GrLink: grLinkConfig,\n GrList: grListConfig,\n GrLoading: grLoadingConfig,\n GrModal: grModalConfig,\n GrNavbar: grNavbarConfig,\n GrNumberInput: grNumberInputConfig,\n GrPagination: grPaginationConfig,\n GrPopover: grPopoverConfig,\n GrProgressBar: grProgressBarConfig,\n GrProgressCircle: grProgressCircleConfig,\n GrPromptDialog: grPromptDialogConfig,\n GrRadio: grRadioConfig,\n GrRadioGroup: grRadioGroupConfig,\n GrRating: grRatingConfig,\n GrResponseErrorBanner: grResponseErrorBannerConfig,\n GrScrollSpy: grScrollSpyConfig,\n GrSegmented: grSegmentedConfig,\n GrSelect: grSelectConfig,\n GrSidebar: grSidebarConfig,\n GrSkeleton: grSkeletonConfig,\n GrSlider: grSliderConfig,\n GrSortableList: grSortableListConfig,\n GrSplitter: grSplitterConfig,\n GrStatistic: grStatisticConfig,\n GrSteps: grStepsConfig,\n GrSwitch: grSwitchConfig,\n GrTable: grTableConfig,\n GrTabPanels: grTabPanelsConfig,\n GrTabs: grTabsConfig,\n GrTextarea: grTextareaConfig,\n GrTimeline: grTimelineConfig,\n GrToaster: grToasterConfig,\n GrTooltip: grTooltipConfig,\n GrTransfer: grTransferConfig,\n GrTree: grTreeConfig,\n GrTreeSelect: grTreeSelectConfig,\n GrValue: grValueConfig,\n // </granularity:components:registry>\n}\n\nexport type GranularityComponentName = keyof typeof granularityComponentConfigs\n\n/** Базовый набор компонентов в порядке реестра. */\nconst baseComponents: readonly GranularComponentDescriptor[] = Object.values(\n granularityComponentConfigs,\n)\n\n/**\n * Собирает granular-provider пакета.\n *\n * `overrides` — точка расширения для потребителя: дескриптор с именем из\n * базового реестра заменяет его, остальные дописываются в конец.\n */\nexport function createGranularityProvider(\n overrides: readonly GranularComponentDescriptor[] = [],\n): GranularProvider {\n const overrideByName = new Map(\n overrides.map(component => [component.name, component]),\n )\n const components: GranularComponentDescriptor[] = [\n ...baseComponents.map(component => overrideByName.get(component.name) ?? component),\n ...overrides.filter(component => !baseComponents.some(base => base.name === component.name)),\n ]\n\n return defineGranularProvider({\n id: GRANULARITY_PROVIDER_ID,\n contractVersion: 1,\n packageBaseUrl,\n components,\n theme,\n })\n}\n","import { createGranularityProvider } from './shared'\n\nexport * from './shared'\n\nexport const granularityProvider = createGranularityProvider()\n\nexport default granularityProvider\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAa,iBAAiB,wBAAwB,YAAY,KAAK;CACrE,MAAM;CACN,cAAc,CAAC,YAAY,SAAS;CACpC,UAAU;AACZ,CAAC;;;ACND,IAAa,8BAA8B,wBAAwB,YAAY,KAAK;CAClF,MAAM;CACN,cAAc,CAAC,WAAW,UAAU;AACtC,CAAC;;;;AC+FD,IAAa,0BAA0B;AAIvC,IAAM,iBAAiB,sBAAsB,YAAY,GAAG;;AAG5D,IAAa,wBAAwB,CAAC,SAAS,MAAM;;AAIrD,IAAa,2BAA4D,CAAC,OAAO;AAEjF,IAAM,QAAQ;CACZ,YAAY,IAAA,IAAA,q5KAAA,KAAA,YAAA,GAAA,CAA8C,CAAC;CAC3D,cAAc,IAAA,IAAA,65YAAA,KAAA,YAAA,GAAA,CAAgD,CAAC;CAC/D,QAAQ;EACN,OAAO,IAAA,IAAA,iyYAAA,KAAA,YAAA,GAAA,CAAsD,CAAC;EAC9D,MAAM,IAAA,IAAA,y/SAAA,KAAA,YAAA,GAAA,CAAqD,CAAC;CAC9D;CACA,eAAe;AACjB;;;;;AAMA,IAAa,8BAA8B;CAEzC,SAAS;CACT,SAAS;CACT,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,aAAa;CACb,aAAa;CACb,eAAe;CACf,UAAU;CACV,eAAe;CACf,QAAQ;CACR,YAAY;CACZ,YAAY;CACZ,iBAAiB;CACjB,QAAQ;CACR,aAAa;CACb,YAAY;CACZ,eAAe;CACf,kBAAkB;CAClB,kBAAkB;CAClB,iBAAiB;CACjB,eAAe;CACf,aAAa;CACb,SAAS;CACT,mBAAmB;CACnB,UAAU;CACV,iBAAiB;CACjB,WAAW;CACX,UAAU;CACV,YAAY;CACZ,gBAAgB;CAChB,cAAc;CACd,eAAe;CACf,cAAc;CACd,QAAQ;CACR,aAAa;CACb,YAAY;CACZ,eAAe;CACf,QAAQ;CACR,eAAe;CACf,SAAS;CACT,YAAY;CACZ,cAAc;CACd,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,SAAS;CACT,UAAU;CACV,eAAe;CACf,cAAc;CACd,WAAW;CACX,eAAe;CACf,kBAAkB;CAClB,gBAAgB;CAChB,SAAS;CACT,cAAc;CACd,UAAU;CACV,uBAAuB;CACvB,aAAa;CACb,aAAa;CACb,UAAU;CACV,WAAW;CACX,YAAY;CACZ,UAAU;CACV,gBAAgB;CAChB,YAAY;CACZ,aAAa;CACb,SAAS;CACT,UAAU;CACV,SAAS;CACT,aAAa;CACb,QAAQ;CACR,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,WAAW;CACX,YAAY;CACZ,QAAQ;CACR,cAAc;CACd,SAAS;AAEX;;AAKA,IAAM,iBAAyD,OAAO,OACpE,2BACF;;;;;;;AAQA,SAAgB,0BACd,YAAoD,CAAC,GACnC;CAClB,MAAM,iBAAiB,IAAI,IACzB,UAAU,KAAI,cAAa,CAAC,UAAU,MAAM,SAAS,CAAC,CACxD;CACA,MAAM,aAA4C,CAChD,GAAG,eAAe,KAAI,cAAa,eAAe,IAAI,UAAU,IAAI,KAAK,SAAS,GAClF,GAAG,UAAU,QAAO,cAAa,CAAC,eAAe,MAAK,SAAQ,KAAK,SAAS,UAAU,IAAI,CAAC,CAC7F;CAEA,OAAO,uBAAuB;EAC5B,IAAI;EACJ,iBAAiB;EACjB;EACA;EACA;CACF,CAAC;AACH;;;AChPA,IAAa,sBAAsB,0BAA0B"}
|
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
//#region src/i18n/locales/ru.json
|
|
2
|
+
var transfer = {
|
|
3
|
+
"sourceTitle": "Доступны",
|
|
4
|
+
"targetTitle": "Выбраны",
|
|
5
|
+
"search": "Поиск",
|
|
6
|
+
"toTarget": "Перенести к выбранным",
|
|
7
|
+
"toSource": "Вернуть к доступным",
|
|
8
|
+
"selectAll": "Выбрать всё показанное",
|
|
9
|
+
"moveUp": "Раньше",
|
|
10
|
+
"moveDown": "Позже",
|
|
11
|
+
"selected": "{count} из {total}",
|
|
12
|
+
"shown": "Показано {shown} из {total}",
|
|
13
|
+
"empty": "Здесь пока пусто",
|
|
14
|
+
"emptyFiltered": "Ничего не найдено",
|
|
15
|
+
"moved": "{count} перенесено в «{list}»",
|
|
16
|
+
"reordered": "Позиция {position} из {count}",
|
|
17
|
+
"reorderFiltered": "Пока включён поиск, порядок не меняется",
|
|
18
|
+
"cancelled": "Перенос отменён"
|
|
19
|
+
};
|
|
20
|
+
var carousel = {
|
|
21
|
+
"roledescription": "карусель",
|
|
22
|
+
"slideRoledescription": "слайд",
|
|
23
|
+
"slidePosition": "{index} из {total}",
|
|
24
|
+
"previous": "Предыдущий слайд",
|
|
25
|
+
"next": "Следующий слайд",
|
|
26
|
+
"play": "Запустить автопоказ",
|
|
27
|
+
"pause": "Остановить автопоказ",
|
|
28
|
+
"indicators": "Слайды",
|
|
29
|
+
"autoplayStopped": "Автопоказ остановлен"
|
|
30
|
+
};
|
|
2
31
|
var chip = {
|
|
3
32
|
"remove": "Убрать",
|
|
4
33
|
"removeNamed": "Убрать {label}"
|
|
@@ -126,6 +155,7 @@ var pagination = {
|
|
|
126
155
|
"status": "Страница {page} из {count}"
|
|
127
156
|
};
|
|
128
157
|
var navbar = { "openMenu": "Открыть меню" };
|
|
158
|
+
var scrollSpy = { "label": "На этой странице" };
|
|
129
159
|
var responseError = {
|
|
130
160
|
"networkTitle": "Нет связи с сервером",
|
|
131
161
|
"networkMessage": "Проверьте подключение к интернету и попробуйте ещё раз.",
|
|
@@ -325,6 +355,8 @@ var jsonViewer = {
|
|
|
325
355
|
};
|
|
326
356
|
var contextMenu = { "label": "Контекстное меню" };
|
|
327
357
|
var ru_default = {
|
|
358
|
+
transfer,
|
|
359
|
+
carousel,
|
|
328
360
|
chip,
|
|
329
361
|
common,
|
|
330
362
|
loading,
|
|
@@ -346,6 +378,7 @@ var ru_default = {
|
|
|
346
378
|
statistic,
|
|
347
379
|
pagination,
|
|
348
380
|
navbar,
|
|
381
|
+
scrollSpy,
|
|
349
382
|
responseError,
|
|
350
383
|
colors,
|
|
351
384
|
drawer,
|
|
@@ -381,4 +414,4 @@ var ru_default = {
|
|
|
381
414
|
contextMenu
|
|
382
415
|
};
|
|
383
416
|
//#endregion
|
|
384
|
-
export { autocomplete, avatar, badgeWrap, bottomNav, breadcrumbs, button, chip, collapse, colorPicker, colors, commandPalette, common, contextMenu, dataTable, ru_default as default, delta, dialog, drawer, emptyState, filePreview, fileUpload, fileValidation, form, formErrorBanner, formFile, imageViewer, input, inputTag, jsonViewer, kbd, link, list, loading, modal, navbar, numberInput, pagination, rating, responseError, select, sidebar, slider, sortable, splitter, statistic, steps, table, tabs, textarea, timeline, toaster, tree, treeSelect, uploadErrorBanner };
|
|
417
|
+
export { autocomplete, avatar, badgeWrap, bottomNav, breadcrumbs, button, carousel, chip, collapse, colorPicker, colors, commandPalette, common, contextMenu, dataTable, ru_default as default, delta, dialog, drawer, emptyState, filePreview, fileUpload, fileValidation, form, formErrorBanner, formFile, imageViewer, input, inputTag, jsonViewer, kbd, link, list, loading, modal, navbar, numberInput, pagination, rating, responseError, scrollSpy, select, sidebar, slider, sortable, splitter, statistic, steps, table, tabs, textarea, timeline, toaster, transfer, tree, treeSelect, uploadErrorBanner };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ru-Dr2RYn0P.js","names":[],"sources":["../../src/i18n/locales/ru.json"],"sourcesContent":["{\n \"transfer\": {\n \"sourceTitle\": \"Доступны\",\n \"targetTitle\": \"Выбраны\",\n \"search\": \"Поиск\",\n \"toTarget\": \"Перенести к выбранным\",\n \"toSource\": \"Вернуть к доступным\",\n \"selectAll\": \"Выбрать всё показанное\",\n \"moveUp\": \"Раньше\",\n \"moveDown\": \"Позже\",\n \"selected\": \"{count} из {total}\",\n \"shown\": \"Показано {shown} из {total}\",\n \"empty\": \"Здесь пока пусто\",\n \"emptyFiltered\": \"Ничего не найдено\",\n \"moved\": \"{count} перенесено в «{list}»\",\n \"reordered\": \"Позиция {position} из {count}\",\n \"reorderFiltered\": \"Пока включён поиск, порядок не меняется\",\n \"cancelled\": \"Перенос отменён\"\n },\n \"carousel\": {\n \"roledescription\": \"карусель\",\n \"slideRoledescription\": \"слайд\",\n \"slidePosition\": \"{index} из {total}\",\n \"previous\": \"Предыдущий слайд\",\n \"next\": \"Следующий слайд\",\n \"play\": \"Запустить автопоказ\",\n \"pause\": \"Остановить автопоказ\",\n \"indicators\": \"Слайды\",\n \"autoplayStopped\": \"Автопоказ остановлен\"\n },\n \"chip\": {\n \"remove\": \"Убрать\",\n \"removeNamed\": \"Убрать {label}\"\n },\n \"common\": {\n \"confirm\": \"Подтвердить\",\n \"cancel\": \"Отмена\",\n \"add\": \"Добавить\",\n \"clear\": \"Очистить\",\n \"close\": \"Закрыть\"\n },\n \"loading\": {\n \"defaultText\": \"Загрузка...\"\n },\n \"steps\": {\n \"label\": \"Ход выполнения\",\n \"status\": \"Шаг {step} из {count}\",\n \"completed\": \"выполнен\",\n \"error\": \"есть ошибки\"\n },\n \"treeSelect\": {\n \"filterPlaceholder\": \"Поиск…\",\n \"empty\": \"Нет данных\",\n \"loading\": \"Загрузка…\"\n },\n \"badgeWrap\": {\n \"count\": \"{count} новых\"\n },\n \"avatar\": {\n \"group\": \"Участники\",\n \"groupOverflow\": \"и ещё {count}\",\n \"status\": {\n \"online\": \"в сети\",\n \"offline\": \"не в сети\",\n \"busy\": \"занят\",\n \"away\": \"отошёл\"\n }\n },\n \"tree\": {\n \"drag\": \"Перетащить\",\n \"expand\": \"Развернуть\",\n \"collapse\": \"Свернуть\",\n \"moved\": \"{label} перемещён\"\n },\n \"select\": {\n \"customValuePlaceholder\": \"Добавить значение…\",\n \"addOption\": \"Добавить «{value}»\",\n \"clearOption\": \"Не выбрано\",\n \"searchPlaceholder\": \"Поиск…\",\n \"loading\": \"Загрузка…\",\n \"noResults\": \"Ничего не найдено\",\n \"removeTag\": \"Удалить {label}\"\n },\n \"dataTable\": {\n \"loading\": \"Загрузка…\",\n \"empty\": \"Нет данных\",\n \"selectAll\": \"Выбрать все строки\",\n \"selectRow\": \"Выбрать строку\",\n \"sortAsc\": \"Нажмите для сортировки по возрастанию\",\n \"sortDesc\": \"Нажмите для сортировки по убыванию\",\n \"sortNone\": \"Нажмите, чтобы снять сортировку\",\n \"moveColumn\": \"Переставить колонку {label}\",\n \"columnMoved\": \"Колонка {label} перемещена на позицию {position} из {count}\",\n \"resizeColumn\": \"Ширина колонки {label}\",\n \"columnResized\": \"Ширина колонки {label} — {width} пикселей\"\n },\n \"breadcrumbs\": {\n \"label\": \"Навигационная цепочка\",\n \"expand\": \"Показать скрытые уровни\"\n },\n \"autocomplete\": {\n \"loading\": \"Загрузка…\",\n \"noResults\": \"Ничего не найдено\",\n \"addOption\": \"Добавить «{value}»\",\n \"removeValue\": \"Убрать {label}\",\n \"typeMore\": {\n \"one\": \"Введите минимум {n} символ\",\n \"few\": \"Введите минимум {n} символа\",\n \"many\": \"Введите минимум {n} символов\",\n \"other\": \"Введите минимум {n} символа\"\n }\n },\n \"form\": {\n \"required\": \"Обязательное поле\",\n \"min\": \"Минимум {min}\",\n \"max\": \"Максимум {max}\",\n \"len\": \"Длина должна быть {len}\",\n \"pattern\": \"Неверный формат\",\n \"email\": \"Введите корректный e-mail\",\n \"url\": \"Введите корректный URL\",\n \"file\": \"Некорректный файл\",\n \"invalid\": \"Некорректное значение\",\n \"readonly\": \"Только для чтения\",\n \"validating\": \"Проверяем…\"\n },\n \"dialog\": {\n \"confirm\": {\n \"title\": \"Подтверждение\"\n },\n \"prompt\": {\n \"title\": \"Введите значение\",\n \"label\": \"Значение\",\n \"required\": \"Введите значение.\"\n },\n \"ok\": \"ОК\"\n },\n \"switch\": {\n \"loading\": \"Сохраняем…\"\n },\n \"slider\": {\n \"min\": \"минимум\",\n \"max\": \"максимум\"\n },\n \"sidebar\": {\n \"expand\": \"Развернуть панель\",\n \"collapse\": \"Свернуть панель\"\n },\n \"splitter\": {\n \"label\": \"Изменить размер панелей\"\n },\n \"statistic\": {\n \"trendUp\": \"Рост\",\n \"trendDown\": \"Падение\",\n \"trendFlat\": \"Без изменений\"\n },\n \"pagination\": {\n \"label\": \"Пагинация\",\n \"pageSize\": \"Размер страницы\",\n \"prev\": \"Назад\",\n \"next\": \"Вперёд\",\n \"page\": \"Страница {n}\",\n \"first\": \"Первая страница\",\n \"last\": \"Последняя страница\",\n \"jumpTo\": \"Перейти к\",\n \"total\": \"{from}–{to} из {total}\",\n \"status\": \"Страница {page} из {count}\"\n },\n \"navbar\": {\n \"openMenu\": \"Открыть меню\"\n },\n \"scrollSpy\": {\n \"label\": \"На этой странице\"\n },\n \"responseError\": {\n \"networkTitle\": \"Нет связи с сервером\",\n \"networkMessage\": \"Проверьте подключение к интернету и попробуйте ещё раз.\",\n \"abortedTitle\": \"Запрос отменён\",\n \"abortedMessage\": \"Запрос был отменён.\",\n \"validationTitle\": \"Проверьте данные\",\n \"validationMessage\": \"Сервер вернул ошибку валидации. Исправьте поля и попробуйте снова.\",\n \"clientTitle\": \"Ошибка запроса\",\n \"clientMessage\": \"Сервер отклонил запрос.\",\n \"serverTitle\": \"Ошибка сервера\",\n \"serverMessage\": \"Произошла ошибка на сервере. Попробуйте ещё раз.\",\n \"unknownTitle\": \"Что-то пошло не так\",\n \"unknownMessage\": \"Не удалось выполнить операцию. Попробуйте ещё раз.\",\n \"statusLabel\": \"HTTP {status}\",\n \"retryLabel\": \"Повторить\",\n \"dismissLabel\": \"Скрыть\"\n },\n \"colors\": {\n \"neutral\": \"Нейтральный\",\n \"success\": \"Успех\",\n \"warning\": \"Предупреждение\",\n \"danger\": \"Опасность\",\n \"info\": \"Инфо\",\n \"primary\": \"Primary\",\n \"slate\": \"Сланцевый\",\n \"azure\": \"Лазурный\"\n },\n \"drawer\": {\n \"title\": \"Панель\"\n },\n \"modal\": {\n \"title\": \"Диалог\"\n },\n \"numberInput\": {\n \"increase\": \"Увеличить\",\n \"decrease\": \"Уменьшить\"\n },\n \"toaster\": {\n \"dismiss\": \"Закрыть\",\n \"region\": \"Уведомления\"\n },\n \"inputTag\": {\n \"removeTag\": \"Удалить тег\",\n \"removeTagNamed\": \"Удалить тег {tag}\",\n \"clearAll\": \"Удалить все теги\",\n \"added\": \"Добавлен тег: {tag}\",\n \"addedMany\": \"Добавлено тегов: {count}\",\n \"removed\": \"Удалён тег: {tag}\",\n \"cleared\": \"Все теги удалены\",\n \"limitReached\": \"Достигнут предел тегов\"\n },\n \"fileUpload\": {\n \"placeholder\": \"Перетащите файлы сюда или нажмите для выбора\",\n \"progress\": \"Прогресс загрузки\",\n \"uploading\": \"Загрузка…\",\n \"success\": \"Загрузка завершена\",\n \"error\": \"Не удалось загрузить\",\n \"remove\": \"Убрать {fileName}\",\n \"retry\": \"Повторить загрузку\",\n \"retryFile\": \"Повторить {fileName}\",\n \"abortFile\": \"Отменить загрузку {fileName}\",\n \"statusPending\": \"В очереди\",\n \"statusUploading\": \"Загружается\",\n \"statusSuccess\": \"Загружен\",\n \"statusError\": \"Ошибка\"\n },\n \"formFile\": {\n \"upload\": \"Загрузить файл\",\n \"change\": \"Заменить файл\",\n \"remove\": \"Удалить\",\n \"clearAll\": \"Очистить всё\",\n \"placeholder\": \"Файлы не выбраны\",\n \"validateError\": \"Не удалось проверить перетащенные файлы\",\n \"removeFile\": \"Убрать {fileName}\"\n },\n \"imageViewer\": {\n \"close\": \"Закрыть просмотрщик\",\n \"prev\": \"Предыдущее изображение\",\n \"next\": \"Следующее изображение\",\n \"zoomIn\": \"Увеличить\",\n \"zoomOut\": \"Уменьшить\",\n \"resetZoom\": \"Сбросить масштаб\",\n \"zoomToNatural\": \"Натуральный размер (1:1)\",\n \"rotateLeft\": \"Повернуть влево\",\n \"rotateRight\": \"Повернуть вправо\",\n \"download\": \"Скачать изображение\",\n \"empty\": \"Нет изображения\",\n \"label\": \"Просмотр изображений\",\n \"position\": \"Изображение {index} из {total}\"\n },\n \"formErrorBanner\": {\n \"validationTitle\": \"Проверьте поля формы\",\n \"validationMessage\": \"Сервер отклонил данные. Исправьте выделенные поля и попробуйте снова.\",\n \"clientTitle\": \"Не удалось сохранить\",\n \"serverTitle\": \"Ошибка сохранения\",\n \"serverMessage\": \"Не удалось сохранить данные. Попробуйте позже.\"\n },\n \"uploadErrorBanner\": {\n \"networkTitle\": \"Не удалось загрузить файлы\",\n \"networkMessage\": \"Проверьте подключение и попробуйте снова.\",\n \"validationTitle\": \"Файлы не прошли проверку\",\n \"validationMessage\": \"Некоторые файлы не соответствуют требованиям.\",\n \"serverTitle\": \"Ошибка загрузки на сервере\",\n \"serverMessage\": \"Сервер не смог обработать загрузку. Попробуйте снова.\"\n },\n \"input\": {\n \"clear\": \"Очистить\",\n \"showPassword\": \"Показать пароль\",\n \"hidePassword\": \"Скрыть пароль\",\n \"limitReached\": \"Достигнут предел символов\"\n },\n \"textarea\": {\n \"lines\": {\n \"one\": \"{n} строка\",\n \"few\": \"{n} строки\",\n \"many\": \"{n} строк\",\n \"other\": \"{n} строки\"\n }\n },\n \"rating\": {\n \"label\": \"Оценка\",\n \"valueText\": \"{value} из {max}\",\n \"valueTextWithLabel\": \"{value} из {max}, {label}\"\n },\n \"commandPalette\": {\n \"label\": \"Палитра команд\",\n \"placeholder\": \"Введите команду или запрос…\",\n \"empty\": \"Ничего не найдено\",\n \"recent\": \"Недавние\",\n \"loading\": \"Загрузка…\"\n },\n \"delta\": {\n \"increase\": \"рост\"\n },\n \"filePreview\": {\n \"label\": \"Файл\"\n },\n \"fileValidation\": {\n \"accept\": \"Файл «{fileName}» не подходит под accept=\\\"{accept}\\\"\",\n \"extension\": \"У файла «{fileName}» недопустимое расширение «.{extension}»\",\n \"mimeType\": \"У файла «{fileName}» недопустимый тип «{mimeType}»\",\n \"mimeTypeFallback\": \"У файла «{fileName}» неопределённый тип «{mimeType}»\",\n \"maxFileSize\": \"Файл «{fileName}» слишком большой ({size} байт), максимум {maxBytes}\",\n \"maxCount\": \"Выбрано слишком много файлов ({count}), максимум — {maxCount}\",\n \"maxTotalSize\": \"Суммарный размер файлов слишком большой ({total} байт), максимум {maxBytes}\"\n },\n \"kbd\": {\n \"command\": \"Command\",\n \"option\": \"Option\",\n \"shift\": \"Shift\",\n \"control\": \"Control\",\n \"enter\": \"Enter\",\n \"escape\": \"Escape\",\n \"tab\": \"Tab\",\n \"backspace\": \"Backspace\",\n \"delete\": \"Delete\",\n \"pageUp\": \"Page Up\",\n \"pageDown\": \"Page Down\",\n \"arrowUp\": \"стрелка вверх\",\n \"arrowDown\": \"стрелка вниз\",\n \"arrowLeft\": \"стрелка влево\",\n \"arrowRight\": \"стрелка вправо\",\n \"then\": \"затем\"\n },\n \"link\": {\n \"opensInNewTab\": \"откроется в новой вкладке\"\n },\n \"colorPicker\": {\n \"panelLabel\": \"Выбор цвета\",\n \"hue\": \"Оттенок\",\n \"saturation\": \"Насыщенность\",\n \"lightness\": \"Светлота\",\n \"opacity\": \"Непрозрачность\",\n \"hexLabel\": \"Значение hex\",\n \"presetsLabel\": \"Палитра\",\n \"swatchLabel\": \"Цвет {color}\"\n },\n \"collapse\": {\n \"empty\": \"Пока пусто\"\n },\n \"list\": {\n \"empty\": \"Пока пусто\"\n },\n \"button\": {\n \"loading\": \"Загрузка…\"\n },\n \"table\": {\n \"empty\": \"Пока пусто\"\n },\n \"timeline\": {\n \"empty\": \"Пока пусто\"\n },\n \"tabs\": {\n \"empty\": \"Пока пусто\",\n \"close\": \"Закрыть вкладку\"\n },\n \"bottomNav\": {\n \"label\": \"Нижняя навигация\",\n \"badge\": \"{count} новых\"\n },\n \"emptyState\": {\n \"title\": \"Пока пусто\"\n },\n \"sortable\": {\n \"label\": \"Сортируемый список\",\n \"handle\": \"Переставить\",\n \"empty\": \"Пока нечего сортировать\",\n \"grabbed\": \"Взято. Позиция {position} из {count}\",\n \"moved\": \"Позиция {position} из {count}\",\n \"dropped\": \"Отпущено на позиции {position} из {count}\",\n \"cancelled\": \"Перенос отменён\"\n },\n \"jsonViewer\": {\n \"search\": \"Поиск по ключу или значению\",\n \"expandAll\": \"Раскрыть всё\",\n \"collapseAll\": \"Свернуть всё\",\n \"copy\": \"Скопировать значение\",\n \"copied\": \"Значение скопировано\",\n \"copyFailed\": \"Не удалось скопировать значение\",\n \"moreItems\": \"ещё\"\n },\n \"contextMenu\": {\n \"label\": \"Контекстное меню\"\n }\n}\n"],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/components/shared/scrollOverflow.ts
|
|
2
|
+
/**
|
|
3
|
+
* Состояние переполнения скроллера — по трём числам, без DOM.
|
|
4
|
+
*
|
|
5
|
+
* Отдельным модулем, потому что в jsdom раскладки нет: `scrollWidth` и
|
|
6
|
+
* `clientWidth` там нули, и через смонтированный компонент ни одна ветка не
|
|
7
|
+
* проверяется. Здесь она проверяется вся.
|
|
8
|
+
*
|
|
9
|
+
* `scrollStart` — расстояние от начала ряда, а не `scrollLeft`. Это не
|
|
10
|
+
* педантизм: в RTL современные браузеры отсчитывают `scrollLeft` от правого
|
|
11
|
+
* края и уводят его в минус, поэтому физическое «слева» и логическое «в начале»
|
|
12
|
+
* там не совпадают. Модуль знает только про начало и конец, а какой это край
|
|
13
|
+
* экрана — дело CSS.
|
|
14
|
+
*
|
|
15
|
+
* Запас в пиксель — как в {@link titleWhenTruncated}: браузеры округляют
|
|
16
|
+
* размеры вверх, и у ряда, влезающего целиком, разница бывает единичной.
|
|
17
|
+
* Без запаса затухание висело бы на ровном месте.
|
|
18
|
+
*/
|
|
19
|
+
function resolveScrollOverflow(scrollStart, scrollSize, clientSize) {
|
|
20
|
+
const hidden = scrollSize - clientSize;
|
|
21
|
+
if (hidden <= 1) return "none";
|
|
22
|
+
const start = Math.abs(scrollStart);
|
|
23
|
+
const atStart = start <= 1;
|
|
24
|
+
const atEnd = hidden - start <= 1;
|
|
25
|
+
if (atStart && atEnd) return "none";
|
|
26
|
+
if (atStart) return "end";
|
|
27
|
+
if (atEnd) return "start";
|
|
28
|
+
return "both";
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
export { resolveScrollOverflow as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scrollOverflow-B_kEdcol.js","names":[],"sources":["../../src/components/shared/scrollOverflow.ts"],"sourcesContent":["/** С какой стороны у скроллера осталось невидимое содержимое. */\nexport type GrScrollOverflow = 'none' | 'start' | 'end' | 'both'\n\n/**\n * Состояние переполнения скроллера — по трём числам, без DOM.\n *\n * Отдельным модулем, потому что в jsdom раскладки нет: `scrollWidth` и\n * `clientWidth` там нули, и через смонтированный компонент ни одна ветка не\n * проверяется. Здесь она проверяется вся.\n *\n * `scrollStart` — расстояние от начала ряда, а не `scrollLeft`. Это не\n * педантизм: в RTL современные браузеры отсчитывают `scrollLeft` от правого\n * края и уводят его в минус, поэтому физическое «слева» и логическое «в начале»\n * там не совпадают. Модуль знает только про начало и конец, а какой это край\n * экрана — дело CSS.\n *\n * Запас в пиксель — как в {@link titleWhenTruncated}: браузеры округляют\n * размеры вверх, и у ряда, влезающего целиком, разница бывает единичной.\n * Без запаса затухание висело бы на ровном месте.\n */\nexport function resolveScrollOverflow(\n scrollStart: number,\n scrollSize: number,\n clientSize: number,\n): GrScrollOverflow {\n const hidden = scrollSize - clientSize\n\n if (hidden <= 1)\n return 'none'\n\n const start = Math.abs(scrollStart)\n const atStart = start <= 1\n const atEnd = hidden - start <= 1\n\n if (atStart && atEnd)\n return 'none'\n\n if (atStart)\n return 'end'\n\n if (atEnd)\n return 'start'\n\n return 'both'\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAoBA,SAAgB,sBACd,aACA,YACA,YACkB;CAClB,MAAM,SAAS,aAAa;CAE5B,IAAI,UAAU,GACZ,OAAO;CAET,MAAM,QAAQ,KAAK,IAAI,WAAW;CAClC,MAAM,UAAU,SAAS;CACzB,MAAM,QAAQ,SAAS,SAAS;CAEhC,IAAI,WAAW,OACb,OAAO;CAET,IAAI,SACF,OAAO;CAET,IAAI,OACF,OAAO;CAET,OAAO;AACT"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/components/shared/tones.ts
|
|
2
|
+
/**
|
|
3
|
+
* Единый перечень дизайн-тонов для всех компонентов библиотеки.
|
|
4
|
+
*
|
|
5
|
+
* Источник истины: список объявлен как `as const`-кортеж, из которого
|
|
6
|
+
* автоматически выводится тип `GrTone`. Это позволяет использовать
|
|
7
|
+
* `GR_TONES` в рантайме (валидация, итерация, safelist) и `GrTone`
|
|
8
|
+
* в типах одновременно, без расхождений.
|
|
9
|
+
*/
|
|
10
|
+
var GR_TONES = [
|
|
11
|
+
"primary",
|
|
12
|
+
"neutral",
|
|
13
|
+
"success",
|
|
14
|
+
"warning",
|
|
15
|
+
"danger",
|
|
16
|
+
"info",
|
|
17
|
+
"slate",
|
|
18
|
+
"azure"
|
|
19
|
+
];
|
|
20
|
+
//#endregion
|
|
21
|
+
export { GR_TONES as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tones-CRJAaYyg.js","names":[],"sources":["../../src/components/shared/tones.ts"],"sourcesContent":["/**\n * Единый перечень дизайн-тонов для всех компонентов библиотеки.\n *\n * Источник истины: список объявлен как `as const`-кортеж, из которого\n * автоматически выводится тип `GrTone`. Это позволяет использовать\n * `GR_TONES` в рантайме (валидация, итерация, safelist) и `GrTone`\n * в типах одновременно, без расхождений.\n */\nexport const GR_TONES = [\n 'primary',\n 'neutral',\n 'success',\n 'warning',\n 'danger',\n 'info',\n 'slate',\n 'azure',\n] as const\n\nexport type GrTone = typeof GR_TONES[number]\n"],"mappings":";;;;;;;;;AAQA,IAAa,WAAW;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF"}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { onMounted, onScopeDispose, readonly, ref, watch } from "vue";
|
|
2
|
+
//#region src/composables/internal/scrollSpyGeometry.ts
|
|
3
|
+
/**
|
|
4
|
+
* Допуск линии активации.
|
|
5
|
+
*
|
|
6
|
+
* `GrAffix` от эпсилона отказался осознанно — там рядом стоит CSS, у которого
|
|
7
|
+
* его нет, и расхождение с ним было бы дороже дребезга. Здесь параллельного
|
|
8
|
+
* источника истины нет: единственный потребитель числа — этот модуль. А повод
|
|
9
|
+
* конкретный: прокрутка ставится так, чтобы верх раздела совпал с линией, но
|
|
10
|
+
* браузеры округляют смещение, и приземление на `line + 0.5` дало бы «кликнул
|
|
11
|
+
* третий раздел — подсветился второй».
|
|
12
|
+
*/
|
|
13
|
+
var SNAP_EPSILON = 2;
|
|
14
|
+
/**
|
|
15
|
+
* Какой раздел читают сейчас.
|
|
16
|
+
*
|
|
17
|
+
* Правило — «последний, чей верх выше линии», а не «самый видимый». Максимум
|
|
18
|
+
* доли пересечения ошибается двумя способами: длинный раздел выигрывает у
|
|
19
|
+
* короткого независимо от того, что читают, и подсветка отскакивает назад,
|
|
20
|
+
* когда следующий раздел только показался снизу. Здесь ответ — заголовок,
|
|
21
|
+
* ближайший сверху к линии чтения.
|
|
22
|
+
*
|
|
23
|
+
* Порядок массива на ответ не влияет: выбор идёт по геометрии. Это снимает
|
|
24
|
+
* класс дефектов, где объявленный список разошёлся с порядком разделов на
|
|
25
|
+
* странице — подсветку в таком случае невозможно отладить.
|
|
26
|
+
*
|
|
27
|
+
* `atEnd` побеждает правило линии, и без него последний раздел недостижим:
|
|
28
|
+
* раздел короче остатка скроллпорта никогда не доводит свой верх до линии,
|
|
29
|
+
* потому что прокрутка кончается раньше.
|
|
30
|
+
*/
|
|
31
|
+
function activeSectionId(rects, line, atEnd) {
|
|
32
|
+
if (rects.length === 0) return null;
|
|
33
|
+
let best = null;
|
|
34
|
+
for (const rect of rects) {
|
|
35
|
+
if (!atEnd && rect.top - line > SNAP_EPSILON) continue;
|
|
36
|
+
if (best === null || rect.top > best.top) best = rect;
|
|
37
|
+
}
|
|
38
|
+
return best?.id ?? null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* `rootMargin` наблюдателя: верх корня поджимается на отступ, и тогда его край
|
|
42
|
+
* совпадает с линией активации.
|
|
43
|
+
*
|
|
44
|
+
* Единицы только `px`: `rootMargin` произвольных длин не принимает, поэтому
|
|
45
|
+
* отступ приходит сюда уже замеренным.
|
|
46
|
+
*/
|
|
47
|
+
function scrollSpyRootMargin(offsetPx) {
|
|
48
|
+
const inset = `${-(Number.isFinite(offsetPx) ? Math.max(0, Math.round(offsetPx)) : 0)}px`;
|
|
49
|
+
const zero = "0px";
|
|
50
|
+
return [
|
|
51
|
+
inset,
|
|
52
|
+
zero,
|
|
53
|
+
zero,
|
|
54
|
+
zero
|
|
55
|
+
].join(" ");
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Куда прокрутить скроллпорт, чтобы верх раздела встал на линию активации.
|
|
59
|
+
*
|
|
60
|
+
* Своя арифметика вместо `scrollIntoView` — по трём независимым причинам:
|
|
61
|
+
* тот двигает всех предков (у карусели это стоило прыжка страницы на каждом
|
|
62
|
+
* шаге автопрокрутки), не умеет наш отступ, и в jsdom отсутствует вовсе, то
|
|
63
|
+
* есть клик стал бы непроверяемым.
|
|
64
|
+
*/
|
|
65
|
+
function scrollSpyTargetTop(scrollTop, sectionTop, portTop, offset, maxScrollTop) {
|
|
66
|
+
const upper = Math.max(0, Number.isFinite(maxScrollTop) ? maxScrollTop : 0);
|
|
67
|
+
const target = scrollTop + (sectionTop - portTop) - Math.max(0, offset);
|
|
68
|
+
return Math.min(upper, Math.max(0, target));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Прокручивается ли предок.
|
|
72
|
+
*
|
|
73
|
+
* Читается вычисленный `overflow-y`, а не объявленный: при
|
|
74
|
+
* `overflow-x: hidden; overflow-y: visible` спецификация превращает вычисленный
|
|
75
|
+
* `overflow-y` в `auto`, то есть предок действительно становится скроллпортом.
|
|
76
|
+
*/
|
|
77
|
+
function isScrollableOverflow(overflowY) {
|
|
78
|
+
return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Доехали ли до дна.
|
|
82
|
+
*
|
|
83
|
+
* `maxScrollTop > 1` — обязательное условие, а не перестраховка: содержимое
|
|
84
|
+
* короче скроллпорта даёт «дно» на нулевой прокрутке, и правило `atEnd`
|
|
85
|
+
* подсветило бы последний раздел на странице, где позиции чтения нет вовсе.
|
|
86
|
+
*/
|
|
87
|
+
function isScrolledToEnd(scrollTop, maxScrollTop) {
|
|
88
|
+
return maxScrollTop > 1 && scrollTop >= maxScrollTop - SNAP_EPSILON;
|
|
89
|
+
}
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region src/composables/useScrollSpy.ts
|
|
92
|
+
/**
|
|
93
|
+
* Порог простоя прокрутки, после которого она считается осевшей.
|
|
94
|
+
*
|
|
95
|
+
* Не догадка о длительности анимации — длину плавной прокрутки браузер
|
|
96
|
+
* выбирает сам от расстояния, и любой фиксированный таймаут либо короток, либо
|
|
97
|
+
* длинен. Это стандартный полифилл `scrollend`: порог обязан превышать
|
|
98
|
+
* межкадровый интервал потока событий с запасом на джанк и оставаться короче
|
|
99
|
+
* осмысленной паузы пользователя.
|
|
100
|
+
*/
|
|
101
|
+
var SETTLE_IDLE_MS = 120;
|
|
102
|
+
/** Насколько близко к цели считается «доехали». */
|
|
103
|
+
var SETTLE_EPSILON = 2;
|
|
104
|
+
function useScrollSpy(options) {
|
|
105
|
+
const active = ref(null);
|
|
106
|
+
let observer = null;
|
|
107
|
+
/** Идёт ли наблюдение: без него выводить активный раздел не из чего. */
|
|
108
|
+
let observing = false;
|
|
109
|
+
/** Элемент, чей `scrollTop` двигаем. Для окна — `document.scrollingElement`. */
|
|
110
|
+
let portEl = null;
|
|
111
|
+
/** Корень наблюдателя: `null` для вьюпорта. */
|
|
112
|
+
let portRoot = null;
|
|
113
|
+
/** Куда вешать `scroll`: на элемент или на документ. */
|
|
114
|
+
let portEvents = null;
|
|
115
|
+
let isDocumentPort = true;
|
|
116
|
+
let appliedOffsetPx = 0;
|
|
117
|
+
let lastAtEnd = false;
|
|
118
|
+
let pinnedId = null;
|
|
119
|
+
let pendingTop = null;
|
|
120
|
+
let settled = true;
|
|
121
|
+
let idleTimer = null;
|
|
122
|
+
const warnedMissing = /* @__PURE__ */ new Set();
|
|
123
|
+
function element(id) {
|
|
124
|
+
const custom = options.elementFor?.(id);
|
|
125
|
+
if (custom !== void 0) return custom ?? null;
|
|
126
|
+
return typeof document === "undefined" ? null : document.getElementById(id);
|
|
127
|
+
}
|
|
128
|
+
function portTop() {
|
|
129
|
+
if (!portEl) return 0;
|
|
130
|
+
return isDocumentPort ? 0 : portEl.getBoundingClientRect().top;
|
|
131
|
+
}
|
|
132
|
+
function portMaxScroll() {
|
|
133
|
+
return portEl ? portEl.scrollHeight - portEl.clientHeight : 0;
|
|
134
|
+
}
|
|
135
|
+
function measureOffset() {
|
|
136
|
+
const value = options.offset?.() ?? 0;
|
|
137
|
+
return Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Скроллпорт ищется от **первого раздела**, а не от места вызова: оглавление
|
|
141
|
+
* обычно стоит рядом с содержимым, отдельной колонкой, и обход предков от
|
|
142
|
+
* него привёл бы не туда. Скроллпорт определяют разделы, за ними и следим.
|
|
143
|
+
*
|
|
144
|
+
* Документ представляем через `document.scrollingElement`, а не через
|
|
145
|
+
* `window`: так остаётся один кодовый путь для окна и для коробки, и клик
|
|
146
|
+
* становится проверяемым — `window.scrollTo` в jsdom заглушка, печатающая
|
|
147
|
+
* «Not implemented», а `Element.scrollTop` там обычное хранимое свойство.
|
|
148
|
+
*/
|
|
149
|
+
function resolvePort() {
|
|
150
|
+
const explicit = options.scroller?.();
|
|
151
|
+
if (explicit) {
|
|
152
|
+
portEl = explicit;
|
|
153
|
+
portRoot = explicit;
|
|
154
|
+
portEvents = explicit;
|
|
155
|
+
isDocumentPort = false;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (typeof document !== "undefined" && typeof getComputedStyle === "function") {
|
|
159
|
+
const ids = options.sections();
|
|
160
|
+
let current = (ids.length > 0 ? element(ids[0]) : null)?.parentElement ?? null;
|
|
161
|
+
while (current && current !== document.body) {
|
|
162
|
+
if (isScrollableOverflow(getComputedStyle(current).overflowY)) {
|
|
163
|
+
portEl = current;
|
|
164
|
+
portRoot = current;
|
|
165
|
+
portEvents = current;
|
|
166
|
+
isDocumentPort = false;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
current = current.parentElement;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
portEl = typeof document === "undefined" ? null : document.scrollingElement ?? document.documentElement;
|
|
173
|
+
portRoot = null;
|
|
174
|
+
portEvents = typeof document === "undefined" ? null : document;
|
|
175
|
+
isDocumentPort = true;
|
|
176
|
+
}
|
|
177
|
+
function setActive(next) {
|
|
178
|
+
if (next === active.value) return;
|
|
179
|
+
const previous = active.value;
|
|
180
|
+
active.value = next;
|
|
181
|
+
options.onChange?.(next, previous);
|
|
182
|
+
}
|
|
183
|
+
function warnMissing(id) {
|
|
184
|
+
if (!(process.env.NODE_ENV !== "production") || warnedMissing.has(id)) return;
|
|
185
|
+
warnedMissing.add(id);
|
|
186
|
+
console.warn(`[granularity] useScrollSpy: раздела #${id} нет в документе — пункт оглавления останется неактивным, а клик по нему ничего не сделает. Обычно это опечатка в идентификаторе; если раздел дорисовывается позже, предупреждение можно не читать.`);
|
|
187
|
+
}
|
|
188
|
+
function recompute() {
|
|
189
|
+
if (pinnedId !== null) return;
|
|
190
|
+
if (!observing) {
|
|
191
|
+
setActive(null);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const rects = [];
|
|
195
|
+
for (const id of options.sections()) {
|
|
196
|
+
const el = element(id);
|
|
197
|
+
if (!el) {
|
|
198
|
+
warnMissing(id);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
rects.push({
|
|
202
|
+
id,
|
|
203
|
+
top: el.getBoundingClientRect().top
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
setActive(activeSectionId(rects, portTop() + appliedOffsetPx, lastAtEnd));
|
|
207
|
+
}
|
|
208
|
+
function clearIdleTimer() {
|
|
209
|
+
if (idleTimer !== null) {
|
|
210
|
+
clearTimeout(idleTimer);
|
|
211
|
+
idleTimer = null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function restartIdleTimer() {
|
|
215
|
+
clearIdleTimer();
|
|
216
|
+
idleTimer = setTimeout(() => {
|
|
217
|
+
idleTimer = null;
|
|
218
|
+
settled = true;
|
|
219
|
+
}, SETTLE_IDLE_MS);
|
|
220
|
+
}
|
|
221
|
+
function unpin() {
|
|
222
|
+
if (pinnedId === null) return;
|
|
223
|
+
pinnedId = null;
|
|
224
|
+
pendingTop = null;
|
|
225
|
+
settled = true;
|
|
226
|
+
clearIdleTimer();
|
|
227
|
+
recompute();
|
|
228
|
+
}
|
|
229
|
+
function onScroll() {
|
|
230
|
+
const top = portEl?.scrollTop ?? 0;
|
|
231
|
+
const atEnd = isScrolledToEnd(top, portMaxScroll());
|
|
232
|
+
if (atEnd !== lastAtEnd) {
|
|
233
|
+
lastAtEnd = atEnd;
|
|
234
|
+
recompute();
|
|
235
|
+
}
|
|
236
|
+
if (pinnedId === null) return;
|
|
237
|
+
if (settled) {
|
|
238
|
+
unpin();
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (pendingTop !== null && Math.abs(top - pendingTop) <= SETTLE_EPSILON) {
|
|
242
|
+
settled = true;
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
if (!hasScrollEnd()) restartIdleTimer();
|
|
246
|
+
}
|
|
247
|
+
function onScrollEnd() {
|
|
248
|
+
settled = true;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Пользователь перехватил прокрутку. Закреп снимается немедленно: браузер
|
|
252
|
+
* плавную прокрутку в этот момент отменяет, и цели мы не достигнем никогда.
|
|
253
|
+
*/
|
|
254
|
+
function onUserScrollIntent() {
|
|
255
|
+
unpin();
|
|
256
|
+
}
|
|
257
|
+
function hasScrollEnd() {
|
|
258
|
+
return typeof window !== "undefined" && "onscrollend" in window;
|
|
259
|
+
}
|
|
260
|
+
function prefersReducedMotion() {
|
|
261
|
+
return typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches === true;
|
|
262
|
+
}
|
|
263
|
+
function detach() {
|
|
264
|
+
observer?.disconnect();
|
|
265
|
+
observer = null;
|
|
266
|
+
observing = false;
|
|
267
|
+
clearIdleTimer();
|
|
268
|
+
if (portEvents) {
|
|
269
|
+
portEvents.removeEventListener("scroll", onScroll);
|
|
270
|
+
portEvents.removeEventListener("scrollend", onScrollEnd);
|
|
271
|
+
portEvents.removeEventListener("wheel", onUserScrollIntent);
|
|
272
|
+
portEvents.removeEventListener("touchstart", onUserScrollIntent);
|
|
273
|
+
portEvents.removeEventListener("keydown", onUserScrollIntent);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function attach() {
|
|
277
|
+
detach();
|
|
278
|
+
if (options.disabled?.() === true) {
|
|
279
|
+
pinnedId = null;
|
|
280
|
+
pendingTop = null;
|
|
281
|
+
setActive(null);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
resolvePort();
|
|
285
|
+
appliedOffsetPx = measureOffset();
|
|
286
|
+
lastAtEnd = isScrolledToEnd(portEl?.scrollTop ?? 0, portMaxScroll());
|
|
287
|
+
if (portEvents) {
|
|
288
|
+
portEvents.addEventListener("scroll", onScroll, { passive: true });
|
|
289
|
+
portEvents.addEventListener("scrollend", onScrollEnd);
|
|
290
|
+
portEvents.addEventListener("wheel", onUserScrollIntent, { passive: true });
|
|
291
|
+
portEvents.addEventListener("touchstart", onUserScrollIntent, { passive: true });
|
|
292
|
+
portEvents.addEventListener("keydown", onUserScrollIntent);
|
|
293
|
+
}
|
|
294
|
+
if (typeof IntersectionObserver === "undefined") return;
|
|
295
|
+
observing = true;
|
|
296
|
+
observer = new IntersectionObserver(handle, {
|
|
297
|
+
root: portRoot,
|
|
298
|
+
rootMargin: scrollSpyRootMargin(appliedOffsetPx),
|
|
299
|
+
threshold: 0
|
|
300
|
+
});
|
|
301
|
+
for (const id of options.sections()) {
|
|
302
|
+
const el = element(id);
|
|
303
|
+
if (el) observer.observe(el);
|
|
304
|
+
else warnMissing(id);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
function handle() {
|
|
308
|
+
recompute();
|
|
309
|
+
if (measureOffset() !== appliedOffsetPx) attach();
|
|
310
|
+
}
|
|
311
|
+
function scrollTo(id, scrollOptions) {
|
|
312
|
+
const el = element(id);
|
|
313
|
+
if (!el || !portEl) {
|
|
314
|
+
warnMissing(id);
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
appliedOffsetPx = measureOffset();
|
|
318
|
+
const top = scrollSpyTargetTop(portEl.scrollTop, el.getBoundingClientRect().top, portTop(), appliedOffsetPx, portMaxScroll());
|
|
319
|
+
pin(id);
|
|
320
|
+
pendingTop = top;
|
|
321
|
+
settled = false;
|
|
322
|
+
const behavior = scrollOptions?.behavior ?? (prefersReducedMotion() ? "auto" : "smooth");
|
|
323
|
+
if (typeof portEl.scrollTo === "function") portEl.scrollTo({
|
|
324
|
+
top,
|
|
325
|
+
behavior
|
|
326
|
+
});
|
|
327
|
+
else portEl.scrollTop = top;
|
|
328
|
+
if (!hasScrollEnd()) restartIdleTimer();
|
|
329
|
+
}
|
|
330
|
+
function pin(id) {
|
|
331
|
+
if (id === null) {
|
|
332
|
+
unpin();
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
pinnedId = id;
|
|
336
|
+
setActive(id);
|
|
337
|
+
}
|
|
338
|
+
function refresh() {
|
|
339
|
+
attach();
|
|
340
|
+
recompute();
|
|
341
|
+
}
|
|
342
|
+
onMounted(refresh);
|
|
343
|
+
onScopeDispose(detach);
|
|
344
|
+
watch(() => [
|
|
345
|
+
options.sections(),
|
|
346
|
+
options.disabled?.(),
|
|
347
|
+
options.scroller?.()
|
|
348
|
+
], () => {
|
|
349
|
+
if (pinnedId !== null && !options.sections().includes(pinnedId)) unpin();
|
|
350
|
+
refresh();
|
|
351
|
+
}, { flush: "post" });
|
|
352
|
+
return {
|
|
353
|
+
active: readonly(active),
|
|
354
|
+
scrollTo,
|
|
355
|
+
refresh,
|
|
356
|
+
pin
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
//#endregion
|
|
360
|
+
export { useScrollSpy as t };
|