@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.
Files changed (193) hide show
  1. package/README.md +2 -2
  2. package/dist/chunks/config-BXRmsn3t.js +172 -0
  3. package/dist/chunks/config-BXRmsn3t.js.map +1 -0
  4. package/dist/chunks/config-BkQ2jvXv.js +49 -0
  5. package/dist/chunks/config-BkQ2jvXv.js.map +1 -0
  6. package/dist/chunks/config-Dg0bSoGw.js +81 -0
  7. package/dist/chunks/config-Dg0bSoGw.js.map +1 -0
  8. package/dist/chunks/config-DmED6aJV.js +237 -0
  9. package/dist/chunks/config-DmED6aJV.js.map +1 -0
  10. package/dist/chunks/{config-DWL81-aM.js → config-hnoZvcIM.js} +2 -20
  11. package/dist/chunks/config-hnoZvcIM.js.map +1 -0
  12. package/dist/chunks/dragSortGeometry-CY-llfrQ.js +87 -0
  13. package/dist/chunks/dragSortGeometry-CY-llfrQ.js.map +1 -0
  14. package/dist/chunks/{en-B9E3jO6m.js → en-DiHzFact.js} +34 -1
  15. package/dist/chunks/en-DiHzFact.js.map +1 -0
  16. package/dist/chunks/{es-QpzdIEut.js → es-1ZL6NtkB.js} +34 -1
  17. package/dist/chunks/es-1ZL6NtkB.js.map +1 -0
  18. package/dist/chunks/{es-DCkqHTlU.js → es-CeKkMxZ_.js} +3 -3
  19. package/dist/chunks/{es-DCkqHTlU.js.map → es-CeKkMxZ_.js.map} +1 -1
  20. package/dist/chunks/{generated-B95IBXs6.js → generated-Hxu_sWPs.js} +238 -0
  21. package/dist/chunks/generated-Hxu_sWPs.js.map +1 -0
  22. package/dist/chunks/{granular-provider-BG_2XqkS.js → granular-provider-CCNbQa5U.js} +9 -1
  23. package/dist/chunks/granular-provider-CCNbQa5U.js.map +1 -0
  24. package/dist/chunks/{ru-D_1Ya489.js → ru-Dr2RYn0P.js} +34 -1
  25. package/dist/chunks/ru-Dr2RYn0P.js.map +1 -0
  26. package/dist/chunks/scrollOverflow-B_kEdcol.js +31 -0
  27. package/dist/chunks/scrollOverflow-B_kEdcol.js.map +1 -0
  28. package/dist/chunks/tones-CRJAaYyg.js +21 -0
  29. package/dist/chunks/tones-CRJAaYyg.js.map +1 -0
  30. package/dist/chunks/useScrollSpy-CIJpw0RI.js +360 -0
  31. package/dist/chunks/useScrollSpy-CIJpw0RI.js.map +1 -0
  32. package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js +272 -0
  33. package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js.map +1 -0
  34. package/dist/components/GrAffix/index.js +3 -0
  35. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js +761 -0
  36. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +1 -0
  37. package/dist/components/GrCarousel/index.js +3 -0
  38. package/dist/components/GrCarousel/styles.css +1 -0
  39. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js → GrColorPicker-9mTR-YZ_.js} +1 -1
  40. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js.map → GrColorPicker-9mTR-YZ_.js.map} +1 -1
  41. package/dist/components/GrColorPicker/index.js +1 -1
  42. package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js → GrDataTable-xNSmO_I-.js} +4 -3
  43. package/dist/components/GrDataTable/chunks/{GrDataTable-BBe7-uUe.js.map → GrDataTable-xNSmO_I-.js.map} +1 -1
  44. package/dist/components/GrDataTable/index.js +1 -1
  45. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js.map → GrImageViewer-DK-iVHHC.js.map} +1 -1
  46. package/dist/components/GrImageViewer/index.js +1 -1
  47. package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js.map → GrInputTag-Ci8AO1ze.js.map} +1 -1
  48. package/dist/components/GrInputTag/index.js +1 -1
  49. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js → GrJsonViewer-CwCBMh4h.js} +2 -2
  50. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BLCEWlwg.js.map → GrJsonViewer-CwCBMh4h.js.map} +1 -1
  51. package/dist/components/GrJsonViewer/index.js +1 -1
  52. package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js.map → GrNumberInput-CL5QhOmx.js.map} +1 -1
  53. package/dist/components/GrNumberInput/index.js +1 -1
  54. package/dist/components/GrProgressBar/index.js +1 -1
  55. package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js +207 -0
  56. package/dist/components/GrScrollSpy/chunks/GrScrollSpy-CQCH3zLC.js.map +1 -0
  57. package/dist/components/GrScrollSpy/index.js +3 -0
  58. package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js.map → GrSlider-CO8N9SF6.js.map} +1 -1
  59. package/dist/components/GrSlider/index.js +1 -1
  60. package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js → GrSortableList-NKriuGm_.js} +2 -1
  61. package/dist/components/GrSortableList/chunks/{GrSortableList-ce1psLL0.js.map → GrSortableList-NKriuGm_.js.map} +1 -1
  62. package/dist/components/GrSortableList/index.js +1 -1
  63. package/dist/components/GrTabs/chunks/{GrTabs-BArefUFv.js → GrTabs-s9RzC1WX.js} +2 -31
  64. package/dist/components/GrTabs/chunks/GrTabs-s9RzC1WX.js.map +1 -0
  65. package/dist/components/GrTabs/index.js +1 -1
  66. package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js +1368 -0
  67. package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js.map +1 -0
  68. package/dist/components/GrTransfer/index.js +3 -0
  69. package/dist/components/GrTransfer/styles.css +1 -0
  70. package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js → GrTree-CkHzgYg1.js} +3 -3
  71. package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js.map → GrTree-CkHzgYg1.js.map} +1 -1
  72. package/dist/components/GrTree/index.js +1 -1
  73. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js → GrTreeSelect-DUsv3_mF.js} +1 -1
  74. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js.map → GrTreeSelect-DUsv3_mF.js.map} +1 -1
  75. package/dist/components/GrTreeSelect/index.js +1 -1
  76. package/dist/composables/useDragSort.js +179 -1
  77. package/dist/composables/useDragSort.js.map +1 -0
  78. package/dist/composables/useScrollSpy.js +2 -0
  79. package/dist/granular-provider-node.js +1 -1
  80. package/dist/granular-provider.js +1 -1
  81. package/dist/i18n/all.js +1 -1
  82. package/dist/i18n/index.js +1 -1
  83. package/dist/index.js +26 -19
  84. package/dist/theme.js +1 -1
  85. package/dist/tokens.js +1 -1
  86. package/dist/types/components/GrAffix/GrAffix.vue.d.ts +91 -0
  87. package/dist/types/components/GrAffix/affixState.d.ts +81 -0
  88. package/dist/types/components/GrAffix/config.d.ts +1 -0
  89. package/dist/types/components/GrAffix/grAffixStyles.d.ts +46 -0
  90. package/dist/types/components/GrAffix/index.d.ts +9 -0
  91. package/dist/types/components/GrAffix/safelist.d.ts +1 -0
  92. package/dist/types/components/GrAlert/GrAlert.vue.d.ts +1 -1
  93. package/dist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +2 -2
  94. package/dist/types/components/GrButton/GrButton.vue.d.ts +2 -2
  95. package/dist/types/components/GrCard/GrCard.vue.d.ts +1 -1
  96. package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +151 -0
  97. package/dist/types/components/GrCarousel/GrCarouselSlide.vue.d.ts +53 -0
  98. package/dist/types/components/GrCarousel/carouselNavigation.d.ts +57 -0
  99. package/dist/types/components/GrCarousel/composables/useCarouselAutoplay.d.ts +33 -0
  100. package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +20 -0
  101. package/dist/types/components/GrCarousel/config.d.ts +7 -0
  102. package/dist/types/components/GrCarousel/defaults.d.ts +13 -0
  103. package/dist/types/components/GrCarousel/grCarouselContext.d.ts +46 -0
  104. package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +80 -0
  105. package/dist/types/components/GrCarousel/index.d.ts +12 -0
  106. package/dist/types/components/GrCarousel/safelist.d.ts +1 -0
  107. package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +3 -3
  108. package/dist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts +2 -2
  109. package/dist/types/components/GrChip/GrChip.vue.d.ts +2 -2
  110. package/dist/types/components/GrChipGroup/GrChipGroup.vue.d.ts +2 -2
  111. package/dist/types/components/GrCollapse/GrCollapse.vue.d.ts +1 -1
  112. package/dist/types/components/GrCollapse/GrCollapseItem.vue.d.ts +1 -1
  113. package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +3 -3
  114. package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +1 -1
  115. package/dist/types/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +1 -1
  116. package/dist/types/components/GrContextMenu/GrContextMenu.vue.d.ts +2 -2
  117. package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
  118. package/dist/types/components/GrDivider/GrDivider.vue.d.ts +2 -2
  119. package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
  120. package/dist/types/components/GrDropdown/GrDropdown.vue.d.ts +3 -3
  121. package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +3 -3
  122. package/dist/types/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +1 -1
  123. package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +1 -1
  124. package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
  125. package/dist/types/components/GrFormField/GrFormField.vue.d.ts +3 -3
  126. package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
  127. package/dist/types/components/GrFormSection/GrFormSection.vue.d.ts +1 -1
  128. package/dist/types/components/GrIcon/GrIcon.vue.d.ts +1 -1
  129. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +3 -3
  130. package/dist/types/components/GrInput/GrInput.vue.d.ts +4 -4
  131. package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +3 -3
  132. package/dist/types/components/GrKbd/GrKbd.vue.d.ts +1 -1
  133. package/dist/types/components/GrLink/GrLink.vue.d.ts +1 -1
  134. package/dist/types/components/GrList/GrListItem.vue.d.ts +2 -2
  135. package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +2 -2
  136. package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +3 -3
  137. package/dist/types/components/GrPagination/GrPagination.vue.d.ts +1 -1
  138. package/dist/types/components/GrPopover/GrPopover.vue.d.ts +3 -3
  139. package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +3 -3
  140. package/dist/types/components/GrRadio/GrRadio.vue.d.ts +2 -2
  141. package/dist/types/components/GrRadioGroup/GrRadioGroup.vue.d.ts +2 -2
  142. package/dist/types/components/GrRating/GrRating.vue.d.ts +2 -2
  143. package/dist/types/components/GrScrollSpy/GrScrollSpy.vue.d.ts +105 -0
  144. package/dist/types/components/GrScrollSpy/config.d.ts +1 -0
  145. package/dist/types/components/GrScrollSpy/grScrollSpyStyles.d.ts +26 -0
  146. package/dist/types/components/GrScrollSpy/index.d.ts +9 -0
  147. package/dist/types/components/GrScrollSpy/safelist.d.ts +1 -0
  148. package/dist/types/components/GrScrollSpy/scrollSpyItems.d.ts +44 -0
  149. package/dist/types/components/GrSegmented/GrSegmented.vue.d.ts +2 -2
  150. package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +1 -1
  151. package/dist/types/components/GrSkeleton/GrSkeleton.vue.d.ts +1 -1
  152. package/dist/types/components/GrSlider/GrSlider.vue.d.ts +3 -3
  153. package/dist/types/components/GrSplitter/GrSplitter.vue.d.ts +1 -1
  154. package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +2 -2
  155. package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +3 -3
  156. package/dist/types/components/GrTable/GrTable.vue.d.ts +1 -1
  157. package/dist/types/components/GrTabs/GrTabs.vue.d.ts +1 -1
  158. package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
  159. package/dist/types/components/GrTimeline/GrTimelineItem.vue.d.ts +2 -2
  160. package/dist/types/components/GrToaster/GrToaster.vue.d.ts +1 -1
  161. package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +3 -3
  162. package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +103 -0
  163. package/dist/types/components/GrTransfer/config.d.ts +1 -0
  164. package/dist/types/components/GrTransfer/defaults.d.ts +15 -0
  165. package/dist/types/components/GrTransfer/grTransferStyles.d.ts +127 -0
  166. package/dist/types/components/GrTransfer/index.d.ts +11 -0
  167. package/dist/types/components/GrTransfer/safelist.d.ts +1 -0
  168. package/dist/types/components/GrTransfer/transferGeometry.d.ts +44 -0
  169. package/dist/types/components/GrTransfer/transferModel.d.ts +68 -0
  170. package/dist/types/components/GrTransfer/transferSelection.d.ts +36 -0
  171. package/dist/types/components/GrTransfer/useTransferDrag.d.ts +48 -0
  172. package/dist/types/composables/internal/scrollSpyGeometry.d.ts +67 -0
  173. package/dist/types/composables/useScrollSpy.d.ts +59 -0
  174. package/dist/types/granular-provider/shared.d.ts +4 -0
  175. package/dist/types/i18n/messages/en.d.ts +64 -0
  176. package/dist/types/i18n/messages/es.d.ts +64 -0
  177. package/dist/types/i18n/messages/ru.d.ts +64 -0
  178. package/dist/types/index.d.ts +6 -0
  179. package/dist/web-types.json +809 -284
  180. package/package.json +25 -1
  181. package/dist/chunks/config-DWL81-aM.js.map +0 -1
  182. package/dist/chunks/en-B9E3jO6m.js.map +0 -1
  183. package/dist/chunks/es-QpzdIEut.js.map +0 -1
  184. package/dist/chunks/generated-B95IBXs6.js.map +0 -1
  185. package/dist/chunks/granular-provider-BG_2XqkS.js.map +0 -1
  186. package/dist/chunks/ru-D_1Ya489.js.map +0 -1
  187. package/dist/chunks/useDragSort-0l47h4yb.js +0 -265
  188. package/dist/chunks/useDragSort-0l47h4yb.js.map +0 -1
  189. package/dist/components/GrTabs/chunks/GrTabs-BArefUFv.js.map +0 -1
  190. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js → GrImageViewer-DK-iVHHC.js} +3 -3
  191. package/dist/components/GrInputTag/chunks/{GrInputTag-BKzm1PKw.js → GrInputTag-Ci8AO1ze.js} +1 -1
  192. package/dist/components/GrNumberInput/chunks/{GrNumberInput-Bm-V59TG.js → GrNumberInput-CL5QhOmx.js} +1 -1
  193. 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-DWL81-aM.js";
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 };