@feugene/granularity 0.41.0 → 0.43.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 (220) hide show
  1. package/LICENSE +13 -162
  2. package/README.md +5 -5
  3. package/dist/chunks/config-BXRmsn3t.js +172 -0
  4. package/dist/chunks/config-BXRmsn3t.js.map +1 -0
  5. package/dist/chunks/{config-BRESvs9g.js → config-Ca8qr8Q3.js} +1 -1
  6. package/dist/chunks/{config-BRESvs9g.js.map → config-Ca8qr8Q3.js.map} +1 -1
  7. package/dist/chunks/config-Dg0bSoGw.js +81 -0
  8. package/dist/chunks/config-Dg0bSoGw.js.map +1 -0
  9. package/dist/chunks/config-DmED6aJV.js +237 -0
  10. package/dist/chunks/config-DmED6aJV.js.map +1 -0
  11. package/dist/chunks/{config-DWL81-aM.js → config-hnoZvcIM.js} +2 -20
  12. package/dist/chunks/config-hnoZvcIM.js.map +1 -0
  13. package/dist/chunks/dragSortGeometry-CY-llfrQ.js +87 -0
  14. package/dist/chunks/dragSortGeometry-CY-llfrQ.js.map +1 -0
  15. package/dist/chunks/{en-CuuLfNHX.js → en-C_QkUTRL.js} +36 -1
  16. package/dist/chunks/en-C_QkUTRL.js.map +1 -0
  17. package/dist/chunks/{es-CsmvfESn.js → es-B4t_3Wnh.js} +3 -3
  18. package/dist/chunks/{es-CsmvfESn.js.map → es-B4t_3Wnh.js.map} +1 -1
  19. package/dist/chunks/{es-CSnmrcMw.js → es-DemSEhZE.js} +36 -1
  20. package/dist/chunks/es-DemSEhZE.js.map +1 -0
  21. package/dist/chunks/{generated-B95IBXs6.js → generated-VcxJTo_q.js} +210 -0
  22. package/dist/chunks/generated-VcxJTo_q.js.map +1 -0
  23. package/dist/chunks/{grKbdStyles-DENu8pUK.js → grKbdStyles-ByMsX-lQ.js} +17 -2
  24. package/dist/chunks/grKbdStyles-ByMsX-lQ.js.map +1 -0
  25. package/dist/chunks/{granular-provider-BshNi2la.js → granular-provider-BohXQcNt.js} +8 -2
  26. package/dist/chunks/granular-provider-BohXQcNt.js.map +1 -0
  27. package/dist/chunks/{ru-BKWafECI.js → ru-CLUErjhY.js} +36 -1
  28. package/dist/chunks/ru-CLUErjhY.js.map +1 -0
  29. package/dist/chunks/scrollOverflow-B_kEdcol.js +31 -0
  30. package/dist/chunks/scrollOverflow-B_kEdcol.js.map +1 -0
  31. package/dist/chunks/tones-CRJAaYyg.js +21 -0
  32. package/dist/chunks/tones-CRJAaYyg.js.map +1 -0
  33. package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js +272 -0
  34. package/dist/components/GrAffix/chunks/GrAffix-CWtC7yi8.js.map +1 -0
  35. package/dist/components/GrAffix/index.js +3 -0
  36. package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-DOpwY2EF.js → GrBreadcrumbs-D0qPry_R.js} +4 -1
  37. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-D0qPry_R.js.map +1 -0
  38. package/dist/components/GrBreadcrumbs/index.js +1 -1
  39. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js +761 -0
  40. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +1 -0
  41. package/dist/components/GrCarousel/index.js +3 -0
  42. package/dist/components/GrCarousel/styles.css +1 -0
  43. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js → GrColorPicker-9mTR-YZ_.js} +1 -1
  44. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BwzRLs-i.js.map → GrColorPicker-9mTR-YZ_.js.map} +1 -1
  45. package/dist/components/GrColorPicker/index.js +1 -1
  46. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-CnzPuoIM.js → GrCommandPalette-Ha4s3DMT.js} +1 -1
  47. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-CnzPuoIM.js.map → GrCommandPalette-Ha4s3DMT.js.map} +1 -1
  48. package/dist/components/GrCommandPalette/index.js +1 -1
  49. package/dist/components/GrDataTable/chunks/{GrDataTable-DpyipOFx.js → GrDataTable-xNSmO_I-.js} +9 -4
  50. package/dist/components/GrDataTable/chunks/GrDataTable-xNSmO_I-.js.map +1 -0
  51. package/dist/components/GrDataTable/index.js +1 -1
  52. package/dist/components/GrDelta/chunks/{GrDelta-BpfqebEV.js → GrDelta-CgTvfoIN.js} +0 -0
  53. package/dist/components/GrDelta/chunks/GrDelta-CgTvfoIN.js.map +1 -0
  54. package/dist/components/GrDelta/index.js +1 -1
  55. package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-D8ANFpn_.js → GrDescriptionList-Dz2Jj1if.js} +26 -11
  56. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-Dz2Jj1if.js.map +1 -0
  57. package/dist/components/GrDescriptionList/index.js +1 -1
  58. package/dist/components/GrFilePreview/chunks/{GrFilePreview-PabkLgYX.js → GrFilePreview-2kVOg1C7.js} +40 -5
  59. package/dist/components/GrFilePreview/chunks/GrFilePreview-2kVOg1C7.js.map +1 -0
  60. package/dist/components/GrFilePreview/index.js +1 -1
  61. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js.map → GrImageViewer-DK-iVHHC.js.map} +1 -1
  62. package/dist/components/GrImageViewer/index.js +1 -1
  63. package/dist/components/GrInputTag/chunks/{GrInputTag-3Au5HWZL.js → GrInputTag-Ci8AO1ze.js} +5 -2
  64. package/dist/components/GrInputTag/chunks/GrInputTag-Ci8AO1ze.js.map +1 -0
  65. package/dist/components/GrInputTag/index.js +1 -1
  66. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CDGOX3C0.js → GrJsonViewer-CwCBMh4h.js} +34 -8
  67. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-CwCBMh4h.js.map +1 -0
  68. package/dist/components/GrJsonViewer/index.js +1 -1
  69. package/dist/components/GrKbd/chunks/{GrKbd-D_a1mPLe.js → GrKbd-BNMeoaLV.js} +1 -1
  70. package/dist/components/GrKbd/chunks/{GrKbd-D_a1mPLe.js.map → GrKbd-BNMeoaLV.js.map} +1 -1
  71. package/dist/components/GrKbd/index.js +2 -2
  72. package/dist/components/GrNumberInput/chunks/{GrNumberInput-BqPydXpK.js → GrNumberInput-CL5QhOmx.js} +5 -2
  73. package/dist/components/GrNumberInput/chunks/GrNumberInput-CL5QhOmx.js.map +1 -0
  74. package/dist/components/GrNumberInput/index.js +1 -1
  75. package/dist/components/GrProgressBar/index.js +1 -1
  76. package/dist/components/GrSegmented/chunks/{GrSegmented-NKTi9bMG.js → GrSegmented-CuDaKA6S.js} +5 -1
  77. package/dist/components/GrSegmented/chunks/GrSegmented-CuDaKA6S.js.map +1 -0
  78. package/dist/components/GrSegmented/index.js +1 -1
  79. package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js.map → GrSlider-CO8N9SF6.js.map} +1 -1
  80. package/dist/components/GrSlider/index.js +1 -1
  81. package/dist/components/GrSortableList/chunks/{GrSortableList-CQCaWivn.js → GrSortableList-NKriuGm_.js} +6 -2
  82. package/dist/components/GrSortableList/chunks/GrSortableList-NKriuGm_.js.map +1 -0
  83. package/dist/components/GrSortableList/index.js +1 -1
  84. package/dist/components/GrSteps/chunks/{GrSteps-DXj7m-WO.js → GrSteps-Cng-Wrjk.js} +5 -1
  85. package/dist/components/GrSteps/chunks/GrSteps-Cng-Wrjk.js.map +1 -0
  86. package/dist/components/GrSteps/index.js +1 -1
  87. package/dist/components/GrTabs/chunks/{GrTabs-DHfv67cp.js → GrTabs-s9RzC1WX.js} +7 -32
  88. package/dist/components/GrTabs/chunks/GrTabs-s9RzC1WX.js.map +1 -0
  89. package/dist/components/GrTabs/index.js +1 -1
  90. package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js +1368 -0
  91. package/dist/components/GrTransfer/chunks/GrTransfer-8FA78ny6.js.map +1 -0
  92. package/dist/components/GrTransfer/index.js +3 -0
  93. package/dist/components/GrTransfer/styles.css +1 -0
  94. package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js → GrTree-CkHzgYg1.js} +3 -3
  95. package/dist/components/GrTree/chunks/{GrTree-BFWFc0Bm.js.map → GrTree-CkHzgYg1.js.map} +1 -1
  96. package/dist/components/GrTree/index.js +1 -1
  97. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js → GrTreeSelect-DUsv3_mF.js} +1 -1
  98. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DJa2lYGe.js.map → GrTreeSelect-DUsv3_mF.js.map} +1 -1
  99. package/dist/components/GrTreeSelect/index.js +1 -1
  100. package/dist/composables/useDragSort.js +179 -1
  101. package/dist/composables/useDragSort.js.map +1 -0
  102. package/dist/granular-provider-node.js +1 -1
  103. package/dist/granular-provider.js +1 -1
  104. package/dist/i18n/all.js +1 -1
  105. package/dist/i18n/index.js +1 -1
  106. package/dist/index.js +32 -28
  107. package/dist/theme.js +1 -1
  108. package/dist/tokens.js +1 -1
  109. package/dist/types/components/GrAffix/GrAffix.vue.d.ts +91 -0
  110. package/dist/types/components/GrAffix/affixState.d.ts +81 -0
  111. package/dist/types/components/GrAffix/config.d.ts +1 -0
  112. package/dist/types/components/GrAffix/grAffixStyles.d.ts +46 -0
  113. package/dist/types/components/GrAffix/index.d.ts +9 -0
  114. package/dist/types/components/GrAffix/safelist.d.ts +1 -0
  115. package/dist/types/components/GrAlert/GrAlert.vue.d.ts +1 -1
  116. package/dist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +2 -2
  117. package/dist/types/components/GrButton/GrButton.vue.d.ts +2 -2
  118. package/dist/types/components/GrCard/GrCard.vue.d.ts +1 -1
  119. package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +151 -0
  120. package/dist/types/components/GrCarousel/GrCarouselSlide.vue.d.ts +53 -0
  121. package/dist/types/components/GrCarousel/carouselNavigation.d.ts +57 -0
  122. package/dist/types/components/GrCarousel/composables/useCarouselAutoplay.d.ts +33 -0
  123. package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +20 -0
  124. package/dist/types/components/GrCarousel/config.d.ts +7 -0
  125. package/dist/types/components/GrCarousel/defaults.d.ts +13 -0
  126. package/dist/types/components/GrCarousel/grCarouselContext.d.ts +46 -0
  127. package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +80 -0
  128. package/dist/types/components/GrCarousel/index.d.ts +12 -0
  129. package/dist/types/components/GrCarousel/safelist.d.ts +1 -0
  130. package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +3 -3
  131. package/dist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts +2 -2
  132. package/dist/types/components/GrChip/GrChip.vue.d.ts +2 -2
  133. package/dist/types/components/GrChipGroup/GrChipGroup.vue.d.ts +2 -2
  134. package/dist/types/components/GrCollapse/GrCollapse.vue.d.ts +1 -1
  135. package/dist/types/components/GrCollapse/GrCollapseItem.vue.d.ts +1 -1
  136. package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +3 -3
  137. package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +1 -1
  138. package/dist/types/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +1 -1
  139. package/dist/types/components/GrContextMenu/GrContextMenu.vue.d.ts +2 -2
  140. package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
  141. package/dist/types/components/GrDivider/GrDivider.vue.d.ts +2 -2
  142. package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
  143. package/dist/types/components/GrDropdown/GrDropdown.vue.d.ts +3 -3
  144. package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +3 -3
  145. package/dist/types/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +1 -1
  146. package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +1 -1
  147. package/dist/types/components/GrFilePreview/GrFilePreview.vue.d.ts +14 -0
  148. package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +1 -1
  149. package/dist/types/components/GrFormField/GrFormField.vue.d.ts +3 -3
  150. package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +2 -2
  151. package/dist/types/components/GrFormSection/GrFormSection.vue.d.ts +1 -1
  152. package/dist/types/components/GrIcon/GrIcon.vue.d.ts +1 -1
  153. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +3 -3
  154. package/dist/types/components/GrInput/GrInput.vue.d.ts +4 -4
  155. package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +3 -3
  156. package/dist/types/components/GrKbd/GrKbd.vue.d.ts +1 -1
  157. package/dist/types/components/GrKbd/grKbdStyles.d.ts +17 -2
  158. package/dist/types/components/GrLink/GrLink.vue.d.ts +1 -1
  159. package/dist/types/components/GrList/GrListItem.vue.d.ts +2 -2
  160. package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +2 -2
  161. package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +3 -3
  162. package/dist/types/components/GrPagination/GrPagination.vue.d.ts +1 -1
  163. package/dist/types/components/GrPopover/GrPopover.vue.d.ts +3 -3
  164. package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +3 -3
  165. package/dist/types/components/GrRadio/GrRadio.vue.d.ts +2 -2
  166. package/dist/types/components/GrRadioGroup/GrRadioGroup.vue.d.ts +2 -2
  167. package/dist/types/components/GrRating/GrRating.vue.d.ts +2 -2
  168. package/dist/types/components/GrSegmented/GrSegmented.vue.d.ts +2 -2
  169. package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +1 -1
  170. package/dist/types/components/GrSkeleton/GrSkeleton.vue.d.ts +1 -1
  171. package/dist/types/components/GrSlider/GrSlider.vue.d.ts +3 -3
  172. package/dist/types/components/GrSplitter/GrSplitter.vue.d.ts +1 -1
  173. package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +2 -2
  174. package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +3 -3
  175. package/dist/types/components/GrTable/GrTable.vue.d.ts +1 -1
  176. package/dist/types/components/GrTabs/GrTabs.vue.d.ts +1 -1
  177. package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +2 -2
  178. package/dist/types/components/GrTimeline/GrTimelineItem.vue.d.ts +2 -2
  179. package/dist/types/components/GrToaster/GrToaster.vue.d.ts +1 -1
  180. package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +3 -3
  181. package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +103 -0
  182. package/dist/types/components/GrTransfer/config.d.ts +1 -0
  183. package/dist/types/components/GrTransfer/defaults.d.ts +15 -0
  184. package/dist/types/components/GrTransfer/grTransferStyles.d.ts +127 -0
  185. package/dist/types/components/GrTransfer/index.d.ts +11 -0
  186. package/dist/types/components/GrTransfer/safelist.d.ts +1 -0
  187. package/dist/types/components/GrTransfer/transferGeometry.d.ts +44 -0
  188. package/dist/types/components/GrTransfer/transferModel.d.ts +68 -0
  189. package/dist/types/components/GrTransfer/transferSelection.d.ts +36 -0
  190. package/dist/types/components/GrTransfer/useTransferDrag.d.ts +48 -0
  191. package/dist/types/granular-provider/shared.d.ts +3 -0
  192. package/dist/types/i18n/messages/en.d.ts +70 -0
  193. package/dist/types/i18n/messages/es.d.ts +70 -0
  194. package/dist/types/i18n/messages/ru.d.ts +70 -0
  195. package/dist/types/index.d.ts +3 -0
  196. package/dist/web-types.json +735 -287
  197. package/package.json +19 -3
  198. package/dist/chunks/config-DWL81-aM.js.map +0 -1
  199. package/dist/chunks/en-CuuLfNHX.js.map +0 -1
  200. package/dist/chunks/es-CSnmrcMw.js.map +0 -1
  201. package/dist/chunks/generated-B95IBXs6.js.map +0 -1
  202. package/dist/chunks/grKbdStyles-DENu8pUK.js.map +0 -1
  203. package/dist/chunks/granular-provider-BshNi2la.js.map +0 -1
  204. package/dist/chunks/ru-BKWafECI.js.map +0 -1
  205. package/dist/chunks/useDragSort-0l47h4yb.js +0 -265
  206. package/dist/chunks/useDragSort-0l47h4yb.js.map +0 -1
  207. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-DOpwY2EF.js.map +0 -1
  208. package/dist/components/GrDataTable/chunks/GrDataTable-DpyipOFx.js.map +0 -1
  209. package/dist/components/GrDelta/chunks/GrDelta-BpfqebEV.js.map +0 -1
  210. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-D8ANFpn_.js.map +0 -1
  211. package/dist/components/GrFilePreview/chunks/GrFilePreview-PabkLgYX.js.map +0 -1
  212. package/dist/components/GrInputTag/chunks/GrInputTag-3Au5HWZL.js.map +0 -1
  213. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-CDGOX3C0.js.map +0 -1
  214. package/dist/components/GrNumberInput/chunks/GrNumberInput-BqPydXpK.js.map +0 -1
  215. package/dist/components/GrSegmented/chunks/GrSegmented-NKTi9bMG.js.map +0 -1
  216. package/dist/components/GrSortableList/chunks/GrSortableList-CQCaWivn.js.map +0 -1
  217. package/dist/components/GrSteps/chunks/GrSteps-DXj7m-WO.js.map +0 -1
  218. package/dist/components/GrTabs/chunks/GrTabs-DHfv67cp.js.map +0 -1
  219. package/dist/components/GrImageViewer/chunks/{GrImageViewer-Dd2gJ-j_.js → GrImageViewer-DK-iVHHC.js} +3 -3
  220. package/dist/components/GrSlider/chunks/{GrSlider-Db-jACXz.js → GrSlider-CO8N9SF6.js} +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrAffix-CWtC7yi8.js","names":["$attrs"],"sources":["../../../../src/components/GrAffix/affixState.ts","../../../../src/components/GrAffix/GrAffix.vue","../../../../src/components/GrAffix/GrAffix.vue"],"sourcesContent":["/**\n * Арифметика липкой панели. Без Vue и без DOM — проверяется без монтирования.\n *\n * Вынесено сюда всё, что в jsdom не проверяется в принципе: там нет раскладки,\n * `getBoundingClientRect` отдаёт нули, а `getComputedStyle(el).top` при классовой\n * вёрстке всегда `auto`, потому что UnoCSS в тестах не исполняется. Через\n * смонтированный компонент ни одна ветка ниже не достижима — здесь достижимы все.\n */\n\nexport const GR_AFFIX_PLACEMENTS = ['top', 'bottom'] as const\n\nexport type GrAffixPlacement = typeof GR_AFFIX_PLACEMENTS[number]\n\n/** Предок делает из себя скроллпорт и прокручивается: `sticky` внутри работает. */\nconst SCROLLABLE = new Set(['auto', 'scroll', 'overlay'])\n\n/** Предок делает из себя скроллпорт, но прокручивать его нечем: `sticky` внутри мёртв. */\nconst CLIPPING = new Set(['hidden', 'clip'])\n\n/**\n * Значение пропа `offset` в CSS-длину для инлайновой переменной.\n *\n * Строка уходит как есть и намеренно не валидируется: `4rem`,\n * `var(--gr-navbar-height)`, `calc(var(--gr-navbar-height) + 8px)` обязаны работать — иначе проп\n * проигрывает голому `style`. Отрицательное число зажимается в ноль: отрицательный\n * порог у `sticky` прячет панель за край, и это всегда ошибка, а не приём.\n *\n * `undefined` означает «не писать переменную вовсе» — тогда класс падает на\n * `var(--gr-affix-offset, 0px)`, то есть на каскад.\n */\nexport function affixOffsetLength(value: number | string | undefined): string | undefined {\n if (value == null)\n return undefined\n\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n return undefined\n\n // Число выносится в переменную, чтобы литерал остался одним токеном:\n // safelist-гейт разбирает шаблонные строки по пробелам и обломок вроде\n // `value)}px` принимает за утилиту UnoCSS — которой он, по совпадению, и\n // оказывается.\n const px = Math.max(0, value)\n\n return `${px}px`\n }\n\n const trimmed = value.trim()\n\n return trimmed === '' ? undefined : trimmed\n}\n\n/**\n * `rootMargin` наблюдателя: поджимает ровно тот край, к которому прилипаем, ровно\n * на отступ. Тогда `rootBounds` записи — это и есть линия прилипания, и состояние\n * читается сравнением двух чисел.\n *\n * Единицы только `px`: `rootMargin` процентов не по осям и произвольных длин не\n * принимает, поэтому отступ приходит сюда уже замеренным.\n */\nexport function affixRootMargin(placement: GrAffixPlacement, offsetPx: number): string {\n const px = Number.isFinite(offsetPx) ? Math.max(0, Math.round(offsetPx)) : 0\n const negative = -px\n const inset = `${negative}px`\n const zero = '0px'\n\n return placement === 'top'\n ? [inset, zero, zero, zero].join(' ')\n : [zero, zero, inset, zero].join(' ')\n}\n\n/** Прямоугольники одной записи наблюдателя — ровно то, что из неё читается. */\nexport interface GrAffixEntryGeometry {\n boundingClientRect: { top: number, bottom: number }\n rootBounds: { top: number, bottom: number } | null\n}\n\n/**\n * Прилипло ли — по одной записи наблюдателя.\n *\n * Считаем по прямоугольникам, а не по `isIntersecting`: тот означает сразу две\n * разные вещи — «сентинел ещё не доехал до линии» и «уже уехал за неё», — и\n * различает их только геометрия, которую запись и так несёт.\n *\n * `rootBounds` уже поджат `rootMargin`'ом (так определено спецификацией), поэтому\n * его край и есть линия прилипания.\n */\nexport function isAffixStuck(\n entry: GrAffixEntryGeometry,\n placement: GrAffixPlacement,\n previous: boolean,\n): boolean {\n const bounds = entry.rootBounds\n // Пустой `rootBounds` бывает в кросс-доменном фрейме. Гадать там не на чем, и\n // прошлое состояние честнее выдуманного.\n if (!bounds)\n return previous\n\n return placement === 'top'\n ? entry.boundingClientRect.top < bounds.top\n : entry.boundingClientRect.bottom > bounds.bottom\n}\n\n/** Один предок в том виде, в каком его видит компонент. */\nexport interface GrAffixAncestor {\n /** Что вернул `getComputedStyle(el).overflowY`. */\n overflowY: string\n /** Метка для текста предупреждения: тег плюс классы. */\n label: string\n}\n\nexport interface GrAffixScrollScan {\n /** Индекс предка-скроллера в переданном списке; `-1` — прокручивается вьюпорт. */\n scrollerIndex: number\n /** Предок, который стал скроллпортом раньше скроллера: внутри него `sticky` мёртв. */\n clipperLabel: string | null\n}\n\n/**\n * Один проход по цепочке предков, два ответа: root наблюдателя и повод для\n * dev-предупреждения.\n *\n * Читается вычисленный `overflow-y`, а не объявленный и не классы, и это не\n * придирка: при `overflow-x: hidden; overflow-y: visible` спецификация превращает\n * вычисленный `overflow-y` в `auto` — предок действительно становится рабочим\n * скроллпортом. Проверка по классу `overflow-x-hidden` дала бы здесь ложную\n * тревогу на совершенно исправной вёрстке.\n *\n * Обход останавливается на первом скроллере: всё выше него к прилипанию отношения\n * не имеет, поэтому и клипер над скроллером виновным не считается. Ровно такая\n * пара есть в витрине — внешняя панель `overflow-hidden`, внутри `overflow-y-auto`.\n */\nexport function scanAffixAncestors(ancestors: readonly GrAffixAncestor[]): GrAffixScrollScan {\n let clipperLabel: string | null = null\n\n for (let index = 0; index < ancestors.length; index += 1) {\n const { overflowY, label } = ancestors[index]\n\n if (SCROLLABLE.has(overflowY))\n return { scrollerIndex: index, clipperLabel }\n\n if (clipperLabel === null && CLIPPING.has(overflowY))\n clipperLabel = label\n }\n\n return { scrollerIndex: -1, clipperLabel }\n}\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nimport {\n type GrAffixAncestor,\n type GrAffixPlacement,\n affixOffsetLength,\n affixRootMargin,\n isAffixStuck,\n scanAffixAncestors,\n} from './affixState'\nimport { affixSentinelClass, grAffixRootClass } from './grAffixStyles'\n\n/**\n * GrAffix — панель, прилипающая к краю при прокрутке: заголовок раздела,\n * оглавление, кнопки «Сохранить/Отмена» под длинной формой.\n *\n * Позиционирует `position: sticky`; наблюдатель нужен только чтобы **узнать**,\n * прилипла ли панель, — от этого зависят фон, тень и содержимое. Отлипшая панель\n * стоит внутри формы и обязана выглядеть её частью, поэтому поверхность\n * включается вместе с состоянием, а не всегда, как у `GrNavbar` и `GrTable`.\n *\n * Корень компонента — сама липкая коробка, а не обёртка вокруг неё: `sticky`\n * зажат своим containing block, и обёртка высотой в коробку не дала бы ей ехать\n * вовсе. Сентинел — сосед коробки, отмечающий её место в потоке.\n */\nexport interface GrAffixProps {\n /** Край, к которому прилипает панель. */\n placement?: GrAffixPlacement\n /**\n * Отступ от края в прилипшем состоянии. Число — пиксели, строка — как есть\n * (`4rem`, `var(--gr-navbar-height)`, `calc(…)`).\n *\n * Общий отступ для группы панелей задаётся не пропом, а токеном\n * `--gr-affix-offset` на контейнере или на `:root`: наблюдатель читает\n * вычисленный стиль и подхватывает его так же, как значение пропа.\n */\n offset?: number | string\n /**\n * Прилипание выключено: разметка та же, `sticky` не ставится.\n *\n * Именно проп, а не `v-if` снаружи: размонтирование убило бы фокус на кнопке\n * панели и состояние вложенных контролов.\n */\n disabled?: boolean\n}\n\nexport interface GrAffixEmits {\n (e: 'stickyChange', stuck: boolean): void\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<GrAffixProps>(), {\n placement: 'top',\n offset: undefined,\n disabled: false,\n})\n\nconst emit = defineEmits<GrAffixEmits>()\n\ndefineSlots<{\n /** Содержимое панели. `stuck` позволяет менять его в прилипшем виде. */\n default?: (props: { stuck: boolean }) => unknown\n}>()\n\nconst boxEl = ref<HTMLElement | null>(null)\nconst sentinelTopEl = ref<HTMLElement | null>(null)\nconst sentinelBottomEl = ref<HTMLElement | null>(null)\n\nconst sentinelEl = computed(() => (\n props.placement === 'top' ? sentinelTopEl.value : sentinelBottomEl.value\n))\n\nconst stuck = ref(false)\n\n/**\n * Наблюдателя в этой среде нет вовсе (сервер, jsdom, старый движок). Тогда\n * `sticky` продолжает работать — его делает CSS, — но знание о состоянии\n * пропадает, и поверхность включается всегда. Прилипшая прозрачная панель\n * пропускает сквозь себя строки; всегда непрозрачная просто чуть более\n * декоративна, чем нужно. Из двух деградаций выбрана вторая.\n */\nconst observerMissing = ref(false)\n\nconst surfaceOn = computed(() => !props.disabled && (stuck.value || observerMissing.value))\n\nconst rootClass = computed(() => grAffixRootClass(props.placement, !props.disabled, surfaceOn.value))\n\nconst rootStyle = computed(() => {\n const length = affixOffsetLength(props.offset)\n\n return length === undefined ? undefined : { '--gr-affix-offset': length }\n})\n\nlet observer: IntersectionObserver | null = null\nlet appliedOffsetPx = 0\nlet warned = false\n\n/**\n * Отступ берётся из вычисленного стиля, а не из пропа, по трём причинам:\n * браузер уже разрешил `4rem`/`var()`/`calc()` в used value, и свой парсер CSS\n * не нужен; отступ может прийти не из пропа вовсе, а из каскада; у `sticky`\n * `getComputedStyle().top` возвращает заданный порог прилипания, а не смещённую\n * позицию, то есть ровно нужное число.\n */\nfunction measureOffsetPx(): number {\n const box = boxEl.value\n if (!box || typeof getComputedStyle !== 'function')\n return 0\n\n const parsed = Number.parseFloat(getComputedStyle(box)[props.placement])\n\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 0\n}\n\nfunction describeElement(el: HTMLElement): string {\n const tag = el.tagName.toLowerCase()\n const classes = el.getAttribute('class')?.trim().split(/\\s+/).slice(0, 2) ?? []\n\n return classes.length > 0 ? `<${tag} class=\"${classes.join(' ')}…\">` : `<${tag}>`\n}\n\n/**\n * Цепочка предков до `<body>`, не включая его.\n *\n * Верхняя граница выбрана не по вкусу: `useScrollLock` вешает\n * `overflow: hidden` на `body` на всё время открытой модалки, и дойди обход\n * туда — каждый аффикс внутри `GrModal` объявлялся бы сломанным, причём только\n * в этом состоянии, то есть через раз.\n */\nfunction collectAncestors(box: HTMLElement): { el: HTMLElement, info: GrAffixAncestor }[] {\n const chain: { el: HTMLElement, info: GrAffixAncestor }[] = []\n\n if (typeof getComputedStyle !== 'function')\n return chain\n\n let current = box.parentElement\n\n while (current && current !== document.body) {\n chain.push({\n el: current,\n info: { overflowY: getComputedStyle(current).overflowY, label: describeElement(current) },\n })\n current = current.parentElement\n }\n\n return chain\n}\n\nfunction detach(): void {\n observer?.disconnect()\n observer = null\n}\n\nfunction attach(): void {\n detach()\n\n if (props.disabled) {\n stuck.value = false\n return\n }\n\n if (typeof IntersectionObserver === 'undefined') {\n observerMissing.value = true\n return\n }\n\n const box = boxEl.value\n const sentinel = sentinelEl.value\n if (!box || !sentinel)\n return\n\n const chain = collectAncestors(box)\n const scan = scanAffixAncestors(chain.map(item => item.info))\n\n // `null`, а не `document.documentElement`: по спецификации это разные корни,\n // и Safari исторически расходился на втором.\n const root = scan.scrollerIndex >= 0 ? chain[scan.scrollerIndex].el : null\n\n appliedOffsetPx = measureOffsetPx()\n\n observer = new IntersectionObserver(handle, {\n root,\n rootMargin: affixRootMargin(props.placement, appliedOffsetPx),\n // Сентинел высотой в пиксель пересекает границу целиком — промежуточных\n // долей у него не бывает, и второй порог дал бы вдвое больше вызовов без\n // единой новой развилки.\n threshold: 0,\n })\n observer.observe(sentinel)\n\n if (__GR_DEV__ && !warned && scan.clipperLabel) {\n warned = true\n console.warn(\n `[granularity] GrAffix: предок ${scan.clipperLabel} задаёт \\`overflow\\`, отличный от `\n + '`visible`, и прокручивать его нечем — он становится скроллпортом, внутри которого '\n + '`position: sticky` не двигается. Снимите `overflow` с этого предка либо сделайте его '\n + 'настоящим скроллером (`overflow-y: auto` плюс ограничение высоты).',\n )\n }\n}\n\nfunction handle(entries: IntersectionObserverEntry[]): void {\n const entry = entries[entries.length - 1]\n if (!entry)\n return\n\n const next = isAffixStuck(entry, props.placement, stuck.value)\n\n // Дедуп по предыдущему булеву — единственная защита от дребезга у границы:\n // гистерезиса нет намеренно, любой эпсилон разошёлся бы с CSS, у которого его\n // нет, и дал бы кадр, где `data-stuck` уже стоит, а панель ещё едет.\n if (next !== stuck.value) {\n stuck.value = next\n emit('stickyChange', next)\n }\n\n // Самоизлечение: в dev-режиме UnoCSS отдаёт правила по требованию, и в момент\n // монтирования `top` мог ещё не разрешиться — тогда `rootMargin` собран из\n // нуля. Пересобираем наблюдателя, как только замер разошёлся с применённым;\n // повторный вызов даст то же число и цикла не будет.\n if (measureOffsetPx() !== appliedOffsetPx)\n attach()\n}\n\n/** Перечитать отступ и пересобрать наблюдателя: `vh` после ресайза, смена высоты шапки. */\nfunction remeasure(): void {\n attach()\n}\n\nonMounted(attach)\nonBeforeUnmount(detach)\n\n// `flush: 'post'` обязателен: при смене края сентинел переезжает на другую\n// сторону коробки, и до обновления DOM ссылка вела бы на снятый узел.\nwatch(() => [props.placement, props.offset, props.disabled] as const, attach, { flush: 'post' })\n\ndefineExpose({ stuck, remeasure })\n</script>\n\n<template>\n <div\n v-if=\"!disabled && placement === 'top'\"\n ref=\"sentinelTopEl\"\n data-gr-affix-sentinel\n aria-hidden=\"true\"\n :class=\"affixSentinelClass.top\"\n />\n\n <div\n ref=\"boxEl\"\n data-gr-affix\n :data-placement=\"placement\"\n :data-stuck=\"stuck ? 'true' : undefined\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n v-bind=\"$attrs\"\n >\n <slot :stuck=\"stuck\" />\n </div>\n\n <div\n v-if=\"!disabled && placement === 'bottom'\"\n ref=\"sentinelBottomEl\"\n data-gr-affix-sentinel\n aria-hidden=\"true\"\n :class=\"affixSentinelClass.bottom\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\n\nimport {\n type GrAffixAncestor,\n type GrAffixPlacement,\n affixOffsetLength,\n affixRootMargin,\n isAffixStuck,\n scanAffixAncestors,\n} from './affixState'\nimport { affixSentinelClass, grAffixRootClass } from './grAffixStyles'\n\n/**\n * GrAffix — панель, прилипающая к краю при прокрутке: заголовок раздела,\n * оглавление, кнопки «Сохранить/Отмена» под длинной формой.\n *\n * Позиционирует `position: sticky`; наблюдатель нужен только чтобы **узнать**,\n * прилипла ли панель, — от этого зависят фон, тень и содержимое. Отлипшая панель\n * стоит внутри формы и обязана выглядеть её частью, поэтому поверхность\n * включается вместе с состоянием, а не всегда, как у `GrNavbar` и `GrTable`.\n *\n * Корень компонента — сама липкая коробка, а не обёртка вокруг неё: `sticky`\n * зажат своим containing block, и обёртка высотой в коробку не дала бы ей ехать\n * вовсе. Сентинел — сосед коробки, отмечающий её место в потоке.\n */\nexport interface GrAffixProps {\n /** Край, к которому прилипает панель. */\n placement?: GrAffixPlacement\n /**\n * Отступ от края в прилипшем состоянии. Число — пиксели, строка — как есть\n * (`4rem`, `var(--gr-navbar-height)`, `calc(…)`).\n *\n * Общий отступ для группы панелей задаётся не пропом, а токеном\n * `--gr-affix-offset` на контейнере или на `:root`: наблюдатель читает\n * вычисленный стиль и подхватывает его так же, как значение пропа.\n */\n offset?: number | string\n /**\n * Прилипание выключено: разметка та же, `sticky` не ставится.\n *\n * Именно проп, а не `v-if` снаружи: размонтирование убило бы фокус на кнопке\n * панели и состояние вложенных контролов.\n */\n disabled?: boolean\n}\n\nexport interface GrAffixEmits {\n (e: 'stickyChange', stuck: boolean): void\n}\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = withDefaults(defineProps<GrAffixProps>(), {\n placement: 'top',\n offset: undefined,\n disabled: false,\n})\n\nconst emit = defineEmits<GrAffixEmits>()\n\ndefineSlots<{\n /** Содержимое панели. `stuck` позволяет менять его в прилипшем виде. */\n default?: (props: { stuck: boolean }) => unknown\n}>()\n\nconst boxEl = ref<HTMLElement | null>(null)\nconst sentinelTopEl = ref<HTMLElement | null>(null)\nconst sentinelBottomEl = ref<HTMLElement | null>(null)\n\nconst sentinelEl = computed(() => (\n props.placement === 'top' ? sentinelTopEl.value : sentinelBottomEl.value\n))\n\nconst stuck = ref(false)\n\n/**\n * Наблюдателя в этой среде нет вовсе (сервер, jsdom, старый движок). Тогда\n * `sticky` продолжает работать — его делает CSS, — но знание о состоянии\n * пропадает, и поверхность включается всегда. Прилипшая прозрачная панель\n * пропускает сквозь себя строки; всегда непрозрачная просто чуть более\n * декоративна, чем нужно. Из двух деградаций выбрана вторая.\n */\nconst observerMissing = ref(false)\n\nconst surfaceOn = computed(() => !props.disabled && (stuck.value || observerMissing.value))\n\nconst rootClass = computed(() => grAffixRootClass(props.placement, !props.disabled, surfaceOn.value))\n\nconst rootStyle = computed(() => {\n const length = affixOffsetLength(props.offset)\n\n return length === undefined ? undefined : { '--gr-affix-offset': length }\n})\n\nlet observer: IntersectionObserver | null = null\nlet appliedOffsetPx = 0\nlet warned = false\n\n/**\n * Отступ берётся из вычисленного стиля, а не из пропа, по трём причинам:\n * браузер уже разрешил `4rem`/`var()`/`calc()` в used value, и свой парсер CSS\n * не нужен; отступ может прийти не из пропа вовсе, а из каскада; у `sticky`\n * `getComputedStyle().top` возвращает заданный порог прилипания, а не смещённую\n * позицию, то есть ровно нужное число.\n */\nfunction measureOffsetPx(): number {\n const box = boxEl.value\n if (!box || typeof getComputedStyle !== 'function')\n return 0\n\n const parsed = Number.parseFloat(getComputedStyle(box)[props.placement])\n\n return Number.isFinite(parsed) ? Math.max(0, parsed) : 0\n}\n\nfunction describeElement(el: HTMLElement): string {\n const tag = el.tagName.toLowerCase()\n const classes = el.getAttribute('class')?.trim().split(/\\s+/).slice(0, 2) ?? []\n\n return classes.length > 0 ? `<${tag} class=\"${classes.join(' ')}…\">` : `<${tag}>`\n}\n\n/**\n * Цепочка предков до `<body>`, не включая его.\n *\n * Верхняя граница выбрана не по вкусу: `useScrollLock` вешает\n * `overflow: hidden` на `body` на всё время открытой модалки, и дойди обход\n * туда — каждый аффикс внутри `GrModal` объявлялся бы сломанным, причём только\n * в этом состоянии, то есть через раз.\n */\nfunction collectAncestors(box: HTMLElement): { el: HTMLElement, info: GrAffixAncestor }[] {\n const chain: { el: HTMLElement, info: GrAffixAncestor }[] = []\n\n if (typeof getComputedStyle !== 'function')\n return chain\n\n let current = box.parentElement\n\n while (current && current !== document.body) {\n chain.push({\n el: current,\n info: { overflowY: getComputedStyle(current).overflowY, label: describeElement(current) },\n })\n current = current.parentElement\n }\n\n return chain\n}\n\nfunction detach(): void {\n observer?.disconnect()\n observer = null\n}\n\nfunction attach(): void {\n detach()\n\n if (props.disabled) {\n stuck.value = false\n return\n }\n\n if (typeof IntersectionObserver === 'undefined') {\n observerMissing.value = true\n return\n }\n\n const box = boxEl.value\n const sentinel = sentinelEl.value\n if (!box || !sentinel)\n return\n\n const chain = collectAncestors(box)\n const scan = scanAffixAncestors(chain.map(item => item.info))\n\n // `null`, а не `document.documentElement`: по спецификации это разные корни,\n // и Safari исторически расходился на втором.\n const root = scan.scrollerIndex >= 0 ? chain[scan.scrollerIndex].el : null\n\n appliedOffsetPx = measureOffsetPx()\n\n observer = new IntersectionObserver(handle, {\n root,\n rootMargin: affixRootMargin(props.placement, appliedOffsetPx),\n // Сентинел высотой в пиксель пересекает границу целиком — промежуточных\n // долей у него не бывает, и второй порог дал бы вдвое больше вызовов без\n // единой новой развилки.\n threshold: 0,\n })\n observer.observe(sentinel)\n\n if (__GR_DEV__ && !warned && scan.clipperLabel) {\n warned = true\n console.warn(\n `[granularity] GrAffix: предок ${scan.clipperLabel} задаёт \\`overflow\\`, отличный от `\n + '`visible`, и прокручивать его нечем — он становится скроллпортом, внутри которого '\n + '`position: sticky` не двигается. Снимите `overflow` с этого предка либо сделайте его '\n + 'настоящим скроллером (`overflow-y: auto` плюс ограничение высоты).',\n )\n }\n}\n\nfunction handle(entries: IntersectionObserverEntry[]): void {\n const entry = entries[entries.length - 1]\n if (!entry)\n return\n\n const next = isAffixStuck(entry, props.placement, stuck.value)\n\n // Дедуп по предыдущему булеву — единственная защита от дребезга у границы:\n // гистерезиса нет намеренно, любой эпсилон разошёлся бы с CSS, у которого его\n // нет, и дал бы кадр, где `data-stuck` уже стоит, а панель ещё едет.\n if (next !== stuck.value) {\n stuck.value = next\n emit('stickyChange', next)\n }\n\n // Самоизлечение: в dev-режиме UnoCSS отдаёт правила по требованию, и в момент\n // монтирования `top` мог ещё не разрешиться — тогда `rootMargin` собран из\n // нуля. Пересобираем наблюдателя, как только замер разошёлся с применённым;\n // повторный вызов даст то же число и цикла не будет.\n if (measureOffsetPx() !== appliedOffsetPx)\n attach()\n}\n\n/** Перечитать отступ и пересобрать наблюдателя: `vh` после ресайза, смена высоты шапки. */\nfunction remeasure(): void {\n attach()\n}\n\nonMounted(attach)\nonBeforeUnmount(detach)\n\n// `flush: 'post'` обязателен: при смене края сентинел переезжает на другую\n// сторону коробки, и до обновления DOM ссылка вела бы на снятый узел.\nwatch(() => [props.placement, props.offset, props.disabled] as const, attach, { flush: 'post' })\n\ndefineExpose({ stuck, remeasure })\n</script>\n\n<template>\n <div\n v-if=\"!disabled && placement === 'top'\"\n ref=\"sentinelTopEl\"\n data-gr-affix-sentinel\n aria-hidden=\"true\"\n :class=\"affixSentinelClass.top\"\n />\n\n <div\n ref=\"boxEl\"\n data-gr-affix\n :data-placement=\"placement\"\n :data-stuck=\"stuck ? 'true' : undefined\"\n :class=\"rootClass\"\n :style=\"rootStyle\"\n v-bind=\"$attrs\"\n >\n <slot :stuck=\"stuck\" />\n </div>\n\n <div\n v-if=\"!disabled && placement === 'bottom'\"\n ref=\"sentinelBottomEl\"\n data-gr-affix-sentinel\n aria-hidden=\"true\"\n :class=\"affixSentinelClass.bottom\"\n />\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { t as GrAffix_default } from "./chunks/GrAffix-CWtC7yi8.js";
2
+ import { n as grAffixSafelist, t as grAffixConfig } from "../../chunks/config-Dg0bSoGw.js";
3
+ export { GrAffix_default as GrAffix, GrAffix_default as default, grAffixConfig, grAffixSafelist };
@@ -3,7 +3,7 @@ import { n as useGranularityTranslations } from "../../../chunks/granularityI18n
3
3
  import { t as GrLink_default } from "../../GrLink/chunks/GrLink-DwWErumU.js";
4
4
  import { n as iconTag, t as iconClass } from "../../../chunks/icon-Dag2tIMs.js";
5
5
  import { a as breadcrumbsItemIconClass, c as breadcrumbsLabelHiddenClass, d as breadcrumbsListWrapClass, f as breadcrumbsRootClass, g as resolveBreadcrumbsLayout, h as resolveBreadcrumbsFit, i as breadcrumbsEllipsisClass, l as breadcrumbsListClass, m as breadcrumbsSizeClassBySize, o as breadcrumbsItemWrapClass, p as breadcrumbsSeparatorClass, r as breadcrumbsCurrentClass, s as breadcrumbsLabelClass, u as breadcrumbsListNowrapClass } from "../../../chunks/config-C0Eu8jpG.js";
6
- import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, nextTick, normalizeClass, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, watch, withCtx } from "vue";
6
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, defineComponent, nextTick, normalizeClass, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, watch, watchEffect, withCtx } from "vue";
7
7
  //#region src/components/GrBreadcrumbs/GrBreadcrumbs.vue?vue&type=script&setup=true&lang.ts
8
8
  var _hoisted_1 = ["aria-label"];
9
9
  var _hoisted_2 = {
@@ -200,6 +200,9 @@ var GrBreadcrumbs_default = /* @__PURE__ */ defineComponent({
200
200
  const before = Math.max(0, Math.min(props.itemsBeforeCollapse, props.items.length));
201
201
  (rootEl.value?.querySelectorAll("[data-gr-breadcrumbs-item]"))?.[before]?.focus();
202
202
  }
203
+ if (process.env.NODE_ENV !== "production") watchEffect(() => {
204
+ if (!Array.isArray(props.items)) console.warn(`[granularity] GrBreadcrumbs: обязательный проп \`items\` должен быть массивом — получено ${String(props.items)}.`);
205
+ });
203
206
  return (_ctx, _cache) => {
204
207
  return openBlock(), createElementBlock("nav", {
205
208
  ref_key: "rootEl",
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrBreadcrumbs-D0qPry_R.js","names":[],"sources":["../../../../src/components/GrBreadcrumbs/GrBreadcrumbs.vue","../../../../src/components/GrBreadcrumbs/GrBreadcrumbs.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch, watchEffect } from 'vue'\n\nimport GrLink from '../GrLink/GrLink.vue'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { iconClass, iconTag } from '../shared/icon'\n\nimport {\n breadcrumbsCurrentClass,\n breadcrumbsEllipsisClass,\n breadcrumbsItemIconClass,\n breadcrumbsItemWrapClass,\n breadcrumbsLabelClass,\n breadcrumbsLabelHiddenClass,\n breadcrumbsListClass,\n breadcrumbsListNowrapClass,\n breadcrumbsListWrapClass,\n breadcrumbsRootClass,\n breadcrumbsSeparatorClass,\n breadcrumbsSizeClassBySize,\n type GrBreadcrumbItem,\n type GrBreadcrumbsLinkComponent,\n type GrBreadcrumbsSize,\n resolveBreadcrumbsFit,\n resolveBreadcrumbsLayout,\n} from './grBreadcrumbsStyles'\n\nexport type { GrBreadcrumbItem, GrBreadcrumbsSize } from './grBreadcrumbsStyles'\n\n/**\n * Путь до текущей страницы (WAI-ARIA breadcrumb): `<nav>` с именем, внутри\n * упорядоченный список ссылок, последний пункт — текущая страница.\n *\n * Ссылки рисует `GrLink`, поэтому роутер подключается тем же способом, что и\n * везде в пакете: `as` + `to`.\n */\nexport interface GrBreadcrumbsProps {\n /** Путь от корня к текущей странице. Последний пункт — текущая страница. */\n items: GrBreadcrumbItem[]\n /** Компонент ссылки для всех пунктов: `RouterLink`, `NuxtLink`, `Link` Inertia. */\n as?: GrBreadcrumbsLinkComponent\n /** Разделитель между пунктами. Декоративен: диктору не читается. */\n separator?: string\n size?: GrBreadcrumbsSize\n /**\n * С какого числа пунктов схлопывать середину в «…». `0`/не задано — показывать\n * путь целиком.\n */\n maxItems?: number\n /** Сколько пунктов оставить в начале при схлопывании. */\n itemsBeforeCollapse?: number\n /** Сколько пунктов оставить в конце при схлопывании. */\n itemsAfterCollapse?: number\n /** Имя лендмарка. Не задано — берётся из локали. */\n ariaLabel?: string\n /** Последний пункт остаётся ссылкой (текущая страница кликабельна). */\n linkCurrent?: boolean\n /**\n * Какой пункт — текущая страница. Не задан — последний.\n *\n * `-1` означает, что текущей страницы в пути нет: её имя стоит в `h1`, а\n * путь показывает только родителей. Тогда `aria-current` не получает никто,\n * и последний пункт остаётся обычной ссылкой.\n */\n currentIndex?: number\n /** i18n-метка кнопки раскрытия схлопнутого пути. */\n expandLabel?: string\n /**\n * Схлопывать по доступной ширине, а не по числу пунктов. Путь становится\n * однострочным, середина уходит под «…» ровно настолько, насколько не влезает.\n *\n * Без пропа поведение прежнее: список переносится на вторую строку, а порог\n * задаёт `maxItems`. Вместе пропы совместимы — `maxItems` остаётся жёстким\n * потолком, ширина ужимает дальше.\n */\n autoCollapse?: boolean\n}\n\nconst props = withDefaults(defineProps<GrBreadcrumbsProps>(), {\n as: undefined,\n separator: undefined,\n size: undefined,\n maxItems: undefined,\n itemsBeforeCollapse: 1,\n itemsAfterCollapse: 1,\n ariaLabel: undefined,\n linkCurrent: false,\n currentIndex: undefined,\n expandLabel: undefined,\n autoCollapse: false,\n})\n\ndefineSlots<{\n /** Содержимое пункта целиком (иконка и подпись). */\n item?: (props: { item: GrBreadcrumbItem, index: number, isCurrent: boolean }) => unknown\n /** Разделитель между пунктами. */\n separator?: () => unknown\n /** Кнопка раскрытия схлопнутой середины. */\n ellipsis?: (props: { hiddenCount: number, expand: () => void }) => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrBreadcrumbs' })\nconst resolvedSeparator = useGrComponentProp('GrBreadcrumbs', 'separator', () => props.separator, '/')\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.breadcrumbs.label', 'Breadcrumb'))\nconst resolvedExpandLabel = computed(() => props.expandLabel ?? t('gr.breadcrumbs.expand', 'Show hidden path'))\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst listEl = ref<HTMLElement | null>(null)\nconst expanded = ref(false)\n\n/**\n * Схлопывание по ширине: сколько пунктов хвоста влезает.\n *\n * `undefined` — ещё не мерили, показываем путь целиком. Первый кадр в режиме\n * `autoCollapse` намеренно полный: ширины снимаются с него, а посчитать их до\n * рендера неоткуда.\n */\nconst fitAfter = ref<number | undefined>(undefined)\n\n/** Ширины не зависят от контейнера, поэтому живут до смены самого пути. */\nlet measured: { items: number[], separator: number } | null = null\n/**\n * Ширина кнопки «…» узнаётся только когда она отрисована, то есть уже после\n * первого схлопывания. До этого считаем её нулевой: поправка может лишь\n * ужать хвост ещё на пункт, а не вернуть спрятанное, поэтому качелей не будет.\n */\nlet ellipsisWidth = 0\n/** Ширина, на которой считали в прошлый раз: по её смене раскрытый путь сворачивается. */\nlet lastAvailable = 0\n\n// Новый путь — новая страница: раскрытая середина прошлого пути к ней отношения\n// не имеет, а измеренные ширины относятся к прошлым подписям.\nwatch(() => props.items, () => {\n expanded.value = false\n measured = null\n ellipsisWidth = 0\n fitAfter.value = undefined\n void nextTick(measure)\n})\n\nconst lastIndex = computed(() => props.items.length - 1)\n\n/**\n * Схлопывание по ширине выражается через тот же `maxItems`: раскладку считает\n * одна функция, а режимы отличаются только тем, откуда взялось число.\n */\nconst autoMaxItems = computed(() => {\n if (!props.autoCollapse || fitAfter.value === undefined)\n return undefined\n if (fitAfter.value >= props.items.length)\n return undefined\n\n return props.items.length - 1\n})\n\nconst effectiveMaxItems = computed(() => {\n const limits = [props.maxItems, autoMaxItems.value].filter((value): value is number => typeof value === 'number' && value > 0)\n\n return limits.length > 0 ? Math.min(...limits) : undefined\n})\n\nconst effectiveAfter = computed(() => (\n props.autoCollapse && fitAfter.value !== undefined ? fitAfter.value : props.itemsAfterCollapse\n))\n\nconst entries = computed(() => resolveBreadcrumbsLayout({\n items: props.items,\n maxItems: effectiveMaxItems.value,\n itemsBeforeCollapse: props.itemsBeforeCollapse,\n itemsAfterCollapse: effectiveAfter.value,\n expanded: expanded.value,\n}))\n\nconst resolvedCurrentIndex = computed(() => props.currentIndex ?? lastIndex.value)\n\nfunction isCurrent(index: number): boolean {\n return index === resolvedCurrentIndex.value\n}\n\n/**\n * Класс подписи: у пункта-иконки она прячется визуально, но остаётся в\n * разметке — путь читают и поиском, и диктором.\n *\n * Без иконки поле игнорируется: спрятать подпись, не показав ничего взамен,\n * значит стереть пункт. Молчать тут нельзя — в разметке всё на месте, и\n * пропажу видно только глазами.\n */\nfunction labelClassFor(item: GrBreadcrumbItem): string {\n if (!item.iconOnly)\n return breadcrumbsLabelClass\n\n if (!item.icon) {\n if (__GR_DEV__) {\n console.warn(\n `[granularity] GrBreadcrumbs: у пункта «${item.label}» стоит \\`iconOnly\\` без \\`icon\\`. `\n + 'Подпись осталась видимой: прятать её, не показав иконку, значит стереть пункт.',\n )\n }\n\n return breadcrumbsLabelClass\n }\n\n return breadcrumbsLabelHiddenClass\n}\n\n/**\n * Ссылкой пункт становится, только если ведёт куда-то и не выключен.\n */\nfunction isLink(item: GrBreadcrumbItem, index: number): boolean {\n if (item.disabled)\n return false\n if (isCurrent(index) && !props.linkCurrent)\n return false\n return item.href !== undefined || item.to !== undefined\n}\n\nfunction widthOf(el: Element | null | undefined): number {\n // `scrollWidth`, а не прямоугольник: у подписи стоит `truncate`, и в узком\n // контейнере прямоугольник вернул бы уже ужатую ширину, а не собственную.\n return el ? (el as HTMLElement).scrollWidth : 0\n}\n\n/**\n * Снять ширины с полного пути и пересчитать, сколько пунктов хвоста влезает.\n *\n * Замер делается один раз на путь: подписи от ширины контейнера не зависят,\n * поэтому `resize` пересчитывает только арифметику.\n */\nfunction measure(): void {\n if (!props.autoCollapse)\n return\n\n const list = listEl.value\n if (!list)\n return\n\n const ellipsis = list.querySelector('[data-gr-breadcrumbs-ellipsis-item]')\n if (ellipsis)\n ellipsisWidth = widthOf(ellipsis)\n\n if (!measured) {\n // Ширины снимаем только с полного пути: спрятанных пунктов в DOM нет.\n if (fitAfter.value !== undefined)\n return\n\n const wraps = [...list.querySelectorAll('[data-gr-breadcrumbs-item-wrap]')]\n if (wraps.length !== props.items.length)\n return\n\n measured = {\n items: wraps.map(widthOf),\n separator: widthOf(list.querySelector('[data-gr-breadcrumbs-separator]')),\n }\n }\n\n const available = list.clientWidth\n // jsdom и скрытый контейнер отдают 0 — решать по такой ширине нечего.\n if (available <= 0)\n return\n\n lastAvailable = available\n\n fitAfter.value = resolveBreadcrumbsFit({\n itemWidths: measured.items,\n separatorWidth: measured.separator,\n ellipsisWidth,\n available,\n itemsBeforeCollapse: props.itemsBeforeCollapse,\n gapWidth: listGap(list),\n })\n}\n\n/** Зазор списка в пикселях: он задан классом, а не пропом, поэтому спрашиваем стиль. */\nfunction listGap(list: HTMLElement): number {\n if (typeof getComputedStyle !== 'function')\n return 0\n\n return Number.parseFloat(getComputedStyle(list).columnGap) || 0\n}\n\n/**\n * Ширина кнопки «…» известна только после того, как она отрисована, то есть\n * после первого схлопывания. Поэтому решение пересчитывается ещё раз: поправка\n * либо ничего не меняет, либо ужимает хвост на пункт. Цикла нет — второй проход\n * оставляет `fitAfter` прежним, и наблюдатель больше не срабатывает.\n */\nwatch(fitAfter, () => void nextTick(measure))\n\nlet observer: ResizeObserver | null = null\n\nwatch(() => props.autoCollapse, (enabled) => {\n if (enabled) {\n void nextTick(measure)\n return\n }\n\n measured = null\n ellipsisWidth = 0\n fitAfter.value = undefined\n})\n\nonMounted(() => {\n void nextTick(measure)\n\n // На сервере и в jsdom `ResizeObserver` отсутствует — измерять там нечего.\n if (typeof ResizeObserver === 'undefined')\n return\n\n observer = new ResizeObserver(() => {\n // Смена ширины — новая раскладка, и раскрытая руками середина относилась к\n // прежней. Свернуть её иначе нечем: в раскрытом пути кнопки «…» нет, то есть\n // поворот телефона оставлял бы путь развёрнутым навсегда. Высота меняется от\n // самого раскрытия (путь переносится на вторую строку) — на неё не реагируем.\n if (expanded.value && listEl.value && listEl.value.clientWidth !== lastAvailable)\n expanded.value = false\n\n measure()\n })\n if (listEl.value)\n observer.observe(listEl.value)\n})\n\nonBeforeUnmount(() => observer?.disconnect())\n\nasync function expand(): Promise<void> {\n expanded.value = true\n\n // Кнопка исчезает вместе со схлопыванием, и фокус ушёл бы на `<body>`.\n // Переводим его на первый раскрытый пункт — там, где кнопка и стояла. Пункты\n // без ссылки держат `tabindex=\"-1\"` именно ради этого случая.\n await nextTick()\n const before = Math.max(0, Math.min(props.itemsBeforeCollapse, props.items.length))\n const revealed = rootEl.value?.querySelectorAll<HTMLElement>('[data-gr-breadcrumbs-item]')\n revealed?.[before]?.focus()\n}\n\nif (__GR_DEV__) {\n watchEffect(() => {\n if (!Array.isArray(props.items)) {\n console.warn(\n `[granularity] GrBreadcrumbs: обязательный проп \\`items\\` должен быть массивом — получено ${String(props.items)}.`,\n )\n }\n })\n}\n</script>\n\n<template>\n <nav\n ref=\"rootEl\"\n data-gr-breadcrumbs\n :class=\"[breadcrumbsRootClass, breadcrumbsSizeClassBySize[resolvedSize]]\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <ol\n ref=\"listEl\"\n data-gr-breadcrumbs-list\n :class=\"[breadcrumbsListClass, autoCollapse && !expanded ? breadcrumbsListNowrapClass : breadcrumbsListWrapClass]\"\n >\n <template v-for=\"(entry, position) in entries\" :key=\"entry.kind === 'item' ? `item-${entry.index}` : 'ellipsis'\">\n <!--\n Разделитель — отдельный элемент списка и помечен `aria-hidden`:\n структуру пути диктору сообщает сам список, а «/» он бы читал вслух.\n -->\n <li\n v-if=\"position > 0\"\n data-gr-breadcrumbs-separator\n :class=\"breadcrumbsSeparatorClass\"\n aria-hidden=\"true\"\n >\n <slot name=\"separator\">\n {{ resolvedSeparator }}\n </slot>\n </li>\n\n <li v-if=\"entry.kind === 'ellipsis'\" data-gr-breadcrumbs-ellipsis-item class=\"min-w-0\">\n <slot name=\"ellipsis\" :hidden-count=\"entry.hiddenCount\" :expand=\"expand\">\n <button\n type=\"button\"\n data-gr-breadcrumbs-ellipsis\n data-testid=\"gr-breadcrumbs-ellipsis\"\n :class=\"breadcrumbsEllipsisClass\"\n :aria-label=\"resolvedExpandLabel\"\n @click=\"expand\"\n >\n …\n </button>\n </slot>\n </li>\n\n <li v-else data-gr-breadcrumbs-item-wrap :class=\"breadcrumbsItemWrapClass\">\n <GrLink\n v-if=\"isLink(entry.item, entry.index)\"\n :key=\"`link-${entry.index}`\"\n data-gr-breadcrumbs-item\n :as=\"as\"\n :href=\"entry.item.href\"\n :to=\"entry.item.to\"\n :size=\"resolvedSize\"\n :variant=\"isCurrent(entry.index) ? 'default' : 'muted'\"\n :aria-label=\"entry.item.ariaLabel\"\n :aria-current=\"isCurrent(entry.index) ? 'page' : undefined\"\n >\n <slot name=\"item\" :item=\"entry.item\" :index=\"entry.index\" :is-current=\"isCurrent(entry.index)\">\n <component\n :is=\"iconTag(entry.item.icon)\"\n v-if=\"entry.item.icon\"\n :class=\"[breadcrumbsItemIconClass, iconClass(entry.item.icon)]\"\n aria-hidden=\"true\"\n />\n <span :class=\"labelClassFor(entry.item)\">{{ entry.item.label }}</span>\n </slot>\n </GrLink>\n\n <!--\n Текущая страница и выключенный пункт — не ссылки. `aria-current`\n остаётся на текущем: именно он отвечает на вопрос «где я».\n -->\n <span\n v-else\n data-gr-breadcrumbs-item\n :class=\"breadcrumbsCurrentClass\"\n :aria-label=\"entry.item.ariaLabel\"\n :aria-current=\"isCurrent(entry.index) ? 'page' : undefined\"\n :aria-disabled=\"entry.item.disabled ? 'true' : undefined\"\n tabindex=\"-1\"\n >\n <slot name=\"item\" :item=\"entry.item\" :index=\"entry.index\" :is-current=\"isCurrent(entry.index)\">\n <component\n :is=\"iconTag(entry.item.icon)\"\n v-if=\"entry.item.icon\"\n :class=\"[breadcrumbsItemIconClass, iconClass(entry.item.icon)]\"\n aria-hidden=\"true\"\n />\n <span :class=\"labelClassFor(entry.item)\">{{ entry.item.label }}</span>\n </slot>\n </span>\n </li>\n </template>\n </ol>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch, watchEffect } from 'vue'\n\nimport GrLink from '../GrLink/GrLink.vue'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { iconClass, iconTag } from '../shared/icon'\n\nimport {\n breadcrumbsCurrentClass,\n breadcrumbsEllipsisClass,\n breadcrumbsItemIconClass,\n breadcrumbsItemWrapClass,\n breadcrumbsLabelClass,\n breadcrumbsLabelHiddenClass,\n breadcrumbsListClass,\n breadcrumbsListNowrapClass,\n breadcrumbsListWrapClass,\n breadcrumbsRootClass,\n breadcrumbsSeparatorClass,\n breadcrumbsSizeClassBySize,\n type GrBreadcrumbItem,\n type GrBreadcrumbsLinkComponent,\n type GrBreadcrumbsSize,\n resolveBreadcrumbsFit,\n resolveBreadcrumbsLayout,\n} from './grBreadcrumbsStyles'\n\nexport type { GrBreadcrumbItem, GrBreadcrumbsSize } from './grBreadcrumbsStyles'\n\n/**\n * Путь до текущей страницы (WAI-ARIA breadcrumb): `<nav>` с именем, внутри\n * упорядоченный список ссылок, последний пункт — текущая страница.\n *\n * Ссылки рисует `GrLink`, поэтому роутер подключается тем же способом, что и\n * везде в пакете: `as` + `to`.\n */\nexport interface GrBreadcrumbsProps {\n /** Путь от корня к текущей странице. Последний пункт — текущая страница. */\n items: GrBreadcrumbItem[]\n /** Компонент ссылки для всех пунктов: `RouterLink`, `NuxtLink`, `Link` Inertia. */\n as?: GrBreadcrumbsLinkComponent\n /** Разделитель между пунктами. Декоративен: диктору не читается. */\n separator?: string\n size?: GrBreadcrumbsSize\n /**\n * С какого числа пунктов схлопывать середину в «…». `0`/не задано — показывать\n * путь целиком.\n */\n maxItems?: number\n /** Сколько пунктов оставить в начале при схлопывании. */\n itemsBeforeCollapse?: number\n /** Сколько пунктов оставить в конце при схлопывании. */\n itemsAfterCollapse?: number\n /** Имя лендмарка. Не задано — берётся из локали. */\n ariaLabel?: string\n /** Последний пункт остаётся ссылкой (текущая страница кликабельна). */\n linkCurrent?: boolean\n /**\n * Какой пункт — текущая страница. Не задан — последний.\n *\n * `-1` означает, что текущей страницы в пути нет: её имя стоит в `h1`, а\n * путь показывает только родителей. Тогда `aria-current` не получает никто,\n * и последний пункт остаётся обычной ссылкой.\n */\n currentIndex?: number\n /** i18n-метка кнопки раскрытия схлопнутого пути. */\n expandLabel?: string\n /**\n * Схлопывать по доступной ширине, а не по числу пунктов. Путь становится\n * однострочным, середина уходит под «…» ровно настолько, насколько не влезает.\n *\n * Без пропа поведение прежнее: список переносится на вторую строку, а порог\n * задаёт `maxItems`. Вместе пропы совместимы — `maxItems` остаётся жёстким\n * потолком, ширина ужимает дальше.\n */\n autoCollapse?: boolean\n}\n\nconst props = withDefaults(defineProps<GrBreadcrumbsProps>(), {\n as: undefined,\n separator: undefined,\n size: undefined,\n maxItems: undefined,\n itemsBeforeCollapse: 1,\n itemsAfterCollapse: 1,\n ariaLabel: undefined,\n linkCurrent: false,\n currentIndex: undefined,\n expandLabel: undefined,\n autoCollapse: false,\n})\n\ndefineSlots<{\n /** Содержимое пункта целиком (иконка и подпись). */\n item?: (props: { item: GrBreadcrumbItem, index: number, isCurrent: boolean }) => unknown\n /** Разделитель между пунктами. */\n separator?: () => unknown\n /** Кнопка раскрытия схлопнутой середины. */\n ellipsis?: (props: { hiddenCount: number, expand: () => void }) => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrBreadcrumbs' })\nconst resolvedSeparator = useGrComponentProp('GrBreadcrumbs', 'separator', () => props.separator, '/')\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.breadcrumbs.label', 'Breadcrumb'))\nconst resolvedExpandLabel = computed(() => props.expandLabel ?? t('gr.breadcrumbs.expand', 'Show hidden path'))\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst listEl = ref<HTMLElement | null>(null)\nconst expanded = ref(false)\n\n/**\n * Схлопывание по ширине: сколько пунктов хвоста влезает.\n *\n * `undefined` — ещё не мерили, показываем путь целиком. Первый кадр в режиме\n * `autoCollapse` намеренно полный: ширины снимаются с него, а посчитать их до\n * рендера неоткуда.\n */\nconst fitAfter = ref<number | undefined>(undefined)\n\n/** Ширины не зависят от контейнера, поэтому живут до смены самого пути. */\nlet measured: { items: number[], separator: number } | null = null\n/**\n * Ширина кнопки «…» узнаётся только когда она отрисована, то есть уже после\n * первого схлопывания. До этого считаем её нулевой: поправка может лишь\n * ужать хвост ещё на пункт, а не вернуть спрятанное, поэтому качелей не будет.\n */\nlet ellipsisWidth = 0\n/** Ширина, на которой считали в прошлый раз: по её смене раскрытый путь сворачивается. */\nlet lastAvailable = 0\n\n// Новый путь — новая страница: раскрытая середина прошлого пути к ней отношения\n// не имеет, а измеренные ширины относятся к прошлым подписям.\nwatch(() => props.items, () => {\n expanded.value = false\n measured = null\n ellipsisWidth = 0\n fitAfter.value = undefined\n void nextTick(measure)\n})\n\nconst lastIndex = computed(() => props.items.length - 1)\n\n/**\n * Схлопывание по ширине выражается через тот же `maxItems`: раскладку считает\n * одна функция, а режимы отличаются только тем, откуда взялось число.\n */\nconst autoMaxItems = computed(() => {\n if (!props.autoCollapse || fitAfter.value === undefined)\n return undefined\n if (fitAfter.value >= props.items.length)\n return undefined\n\n return props.items.length - 1\n})\n\nconst effectiveMaxItems = computed(() => {\n const limits = [props.maxItems, autoMaxItems.value].filter((value): value is number => typeof value === 'number' && value > 0)\n\n return limits.length > 0 ? Math.min(...limits) : undefined\n})\n\nconst effectiveAfter = computed(() => (\n props.autoCollapse && fitAfter.value !== undefined ? fitAfter.value : props.itemsAfterCollapse\n))\n\nconst entries = computed(() => resolveBreadcrumbsLayout({\n items: props.items,\n maxItems: effectiveMaxItems.value,\n itemsBeforeCollapse: props.itemsBeforeCollapse,\n itemsAfterCollapse: effectiveAfter.value,\n expanded: expanded.value,\n}))\n\nconst resolvedCurrentIndex = computed(() => props.currentIndex ?? lastIndex.value)\n\nfunction isCurrent(index: number): boolean {\n return index === resolvedCurrentIndex.value\n}\n\n/**\n * Класс подписи: у пункта-иконки она прячется визуально, но остаётся в\n * разметке — путь читают и поиском, и диктором.\n *\n * Без иконки поле игнорируется: спрятать подпись, не показав ничего взамен,\n * значит стереть пункт. Молчать тут нельзя — в разметке всё на месте, и\n * пропажу видно только глазами.\n */\nfunction labelClassFor(item: GrBreadcrumbItem): string {\n if (!item.iconOnly)\n return breadcrumbsLabelClass\n\n if (!item.icon) {\n if (__GR_DEV__) {\n console.warn(\n `[granularity] GrBreadcrumbs: у пункта «${item.label}» стоит \\`iconOnly\\` без \\`icon\\`. `\n + 'Подпись осталась видимой: прятать её, не показав иконку, значит стереть пункт.',\n )\n }\n\n return breadcrumbsLabelClass\n }\n\n return breadcrumbsLabelHiddenClass\n}\n\n/**\n * Ссылкой пункт становится, только если ведёт куда-то и не выключен.\n */\nfunction isLink(item: GrBreadcrumbItem, index: number): boolean {\n if (item.disabled)\n return false\n if (isCurrent(index) && !props.linkCurrent)\n return false\n return item.href !== undefined || item.to !== undefined\n}\n\nfunction widthOf(el: Element | null | undefined): number {\n // `scrollWidth`, а не прямоугольник: у подписи стоит `truncate`, и в узком\n // контейнере прямоугольник вернул бы уже ужатую ширину, а не собственную.\n return el ? (el as HTMLElement).scrollWidth : 0\n}\n\n/**\n * Снять ширины с полного пути и пересчитать, сколько пунктов хвоста влезает.\n *\n * Замер делается один раз на путь: подписи от ширины контейнера не зависят,\n * поэтому `resize` пересчитывает только арифметику.\n */\nfunction measure(): void {\n if (!props.autoCollapse)\n return\n\n const list = listEl.value\n if (!list)\n return\n\n const ellipsis = list.querySelector('[data-gr-breadcrumbs-ellipsis-item]')\n if (ellipsis)\n ellipsisWidth = widthOf(ellipsis)\n\n if (!measured) {\n // Ширины снимаем только с полного пути: спрятанных пунктов в DOM нет.\n if (fitAfter.value !== undefined)\n return\n\n const wraps = [...list.querySelectorAll('[data-gr-breadcrumbs-item-wrap]')]\n if (wraps.length !== props.items.length)\n return\n\n measured = {\n items: wraps.map(widthOf),\n separator: widthOf(list.querySelector('[data-gr-breadcrumbs-separator]')),\n }\n }\n\n const available = list.clientWidth\n // jsdom и скрытый контейнер отдают 0 — решать по такой ширине нечего.\n if (available <= 0)\n return\n\n lastAvailable = available\n\n fitAfter.value = resolveBreadcrumbsFit({\n itemWidths: measured.items,\n separatorWidth: measured.separator,\n ellipsisWidth,\n available,\n itemsBeforeCollapse: props.itemsBeforeCollapse,\n gapWidth: listGap(list),\n })\n}\n\n/** Зазор списка в пикселях: он задан классом, а не пропом, поэтому спрашиваем стиль. */\nfunction listGap(list: HTMLElement): number {\n if (typeof getComputedStyle !== 'function')\n return 0\n\n return Number.parseFloat(getComputedStyle(list).columnGap) || 0\n}\n\n/**\n * Ширина кнопки «…» известна только после того, как она отрисована, то есть\n * после первого схлопывания. Поэтому решение пересчитывается ещё раз: поправка\n * либо ничего не меняет, либо ужимает хвост на пункт. Цикла нет — второй проход\n * оставляет `fitAfter` прежним, и наблюдатель больше не срабатывает.\n */\nwatch(fitAfter, () => void nextTick(measure))\n\nlet observer: ResizeObserver | null = null\n\nwatch(() => props.autoCollapse, (enabled) => {\n if (enabled) {\n void nextTick(measure)\n return\n }\n\n measured = null\n ellipsisWidth = 0\n fitAfter.value = undefined\n})\n\nonMounted(() => {\n void nextTick(measure)\n\n // На сервере и в jsdom `ResizeObserver` отсутствует — измерять там нечего.\n if (typeof ResizeObserver === 'undefined')\n return\n\n observer = new ResizeObserver(() => {\n // Смена ширины — новая раскладка, и раскрытая руками середина относилась к\n // прежней. Свернуть её иначе нечем: в раскрытом пути кнопки «…» нет, то есть\n // поворот телефона оставлял бы путь развёрнутым навсегда. Высота меняется от\n // самого раскрытия (путь переносится на вторую строку) — на неё не реагируем.\n if (expanded.value && listEl.value && listEl.value.clientWidth !== lastAvailable)\n expanded.value = false\n\n measure()\n })\n if (listEl.value)\n observer.observe(listEl.value)\n})\n\nonBeforeUnmount(() => observer?.disconnect())\n\nasync function expand(): Promise<void> {\n expanded.value = true\n\n // Кнопка исчезает вместе со схлопыванием, и фокус ушёл бы на `<body>`.\n // Переводим его на первый раскрытый пункт — там, где кнопка и стояла. Пункты\n // без ссылки держат `tabindex=\"-1\"` именно ради этого случая.\n await nextTick()\n const before = Math.max(0, Math.min(props.itemsBeforeCollapse, props.items.length))\n const revealed = rootEl.value?.querySelectorAll<HTMLElement>('[data-gr-breadcrumbs-item]')\n revealed?.[before]?.focus()\n}\n\nif (__GR_DEV__) {\n watchEffect(() => {\n if (!Array.isArray(props.items)) {\n console.warn(\n `[granularity] GrBreadcrumbs: обязательный проп \\`items\\` должен быть массивом — получено ${String(props.items)}.`,\n )\n }\n })\n}\n</script>\n\n<template>\n <nav\n ref=\"rootEl\"\n data-gr-breadcrumbs\n :class=\"[breadcrumbsRootClass, breadcrumbsSizeClassBySize[resolvedSize]]\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <ol\n ref=\"listEl\"\n data-gr-breadcrumbs-list\n :class=\"[breadcrumbsListClass, autoCollapse && !expanded ? breadcrumbsListNowrapClass : breadcrumbsListWrapClass]\"\n >\n <template v-for=\"(entry, position) in entries\" :key=\"entry.kind === 'item' ? `item-${entry.index}` : 'ellipsis'\">\n <!--\n Разделитель — отдельный элемент списка и помечен `aria-hidden`:\n структуру пути диктору сообщает сам список, а «/» он бы читал вслух.\n -->\n <li\n v-if=\"position > 0\"\n data-gr-breadcrumbs-separator\n :class=\"breadcrumbsSeparatorClass\"\n aria-hidden=\"true\"\n >\n <slot name=\"separator\">\n {{ resolvedSeparator }}\n </slot>\n </li>\n\n <li v-if=\"entry.kind === 'ellipsis'\" data-gr-breadcrumbs-ellipsis-item class=\"min-w-0\">\n <slot name=\"ellipsis\" :hidden-count=\"entry.hiddenCount\" :expand=\"expand\">\n <button\n type=\"button\"\n data-gr-breadcrumbs-ellipsis\n data-testid=\"gr-breadcrumbs-ellipsis\"\n :class=\"breadcrumbsEllipsisClass\"\n :aria-label=\"resolvedExpandLabel\"\n @click=\"expand\"\n >\n …\n </button>\n </slot>\n </li>\n\n <li v-else data-gr-breadcrumbs-item-wrap :class=\"breadcrumbsItemWrapClass\">\n <GrLink\n v-if=\"isLink(entry.item, entry.index)\"\n :key=\"`link-${entry.index}`\"\n data-gr-breadcrumbs-item\n :as=\"as\"\n :href=\"entry.item.href\"\n :to=\"entry.item.to\"\n :size=\"resolvedSize\"\n :variant=\"isCurrent(entry.index) ? 'default' : 'muted'\"\n :aria-label=\"entry.item.ariaLabel\"\n :aria-current=\"isCurrent(entry.index) ? 'page' : undefined\"\n >\n <slot name=\"item\" :item=\"entry.item\" :index=\"entry.index\" :is-current=\"isCurrent(entry.index)\">\n <component\n :is=\"iconTag(entry.item.icon)\"\n v-if=\"entry.item.icon\"\n :class=\"[breadcrumbsItemIconClass, iconClass(entry.item.icon)]\"\n aria-hidden=\"true\"\n />\n <span :class=\"labelClassFor(entry.item)\">{{ entry.item.label }}</span>\n </slot>\n </GrLink>\n\n <!--\n Текущая страница и выключенный пункт — не ссылки. `aria-current`\n остаётся на текущем: именно он отвечает на вопрос «где я».\n -->\n <span\n v-else\n data-gr-breadcrumbs-item\n :class=\"breadcrumbsCurrentClass\"\n :aria-label=\"entry.item.ariaLabel\"\n :aria-current=\"isCurrent(entry.index) ? 'page' : undefined\"\n :aria-disabled=\"entry.item.disabled ? 'true' : undefined\"\n tabindex=\"-1\"\n >\n <slot name=\"item\" :item=\"entry.item\" :index=\"entry.index\" :is-current=\"isCurrent(entry.index)\">\n <component\n :is=\"iconTag(entry.item.icon)\"\n v-if=\"entry.item.icon\"\n :class=\"[breadcrumbsItemIconClass, iconClass(entry.item.icon)]\"\n aria-hidden=\"true\"\n />\n <span :class=\"labelClassFor(entry.item)\">{{ entry.item.label }}</span>\n </slot>\n </span>\n </li>\n </template>\n </ol>\n </nav>\n</template>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { g as resolveBreadcrumbsLayout, h as resolveBreadcrumbsFit, n as grBreadcrumbsSafelist, t as grBreadcrumbsConfig } from "../../chunks/config-C0Eu8jpG.js";
2
- import { t as GrBreadcrumbs_default } from "./chunks/GrBreadcrumbs-DOpwY2EF.js";
2
+ import { t as GrBreadcrumbs_default } from "./chunks/GrBreadcrumbs-D0qPry_R.js";
3
3
  export { GrBreadcrumbs_default as GrBreadcrumbs, GrBreadcrumbs_default as default, grBreadcrumbsConfig, grBreadcrumbsSafelist, resolveBreadcrumbsFit, resolveBreadcrumbsLayout };