@feugene/granularity 0.30.0 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (274) hide show
  1. package/README.md +0 -1
  2. package/dist/chunks/adapter-CAOxmn2G.js.map +1 -1
  3. package/dist/chunks/{config-BHcS5Cwm.js → config-87fszqnD.js} +1 -1
  4. package/dist/chunks/{config-BHcS5Cwm.js.map → config-87fszqnD.js.map} +1 -1
  5. package/dist/chunks/config-A-bBiotF.js.map +1 -1
  6. package/dist/chunks/config-B3J0alyY.js.map +1 -1
  7. package/dist/chunks/config-BhfNgyWL.js.map +1 -1
  8. package/dist/chunks/config-Bjn30smH.js.map +1 -1
  9. package/dist/chunks/config-BqT6PMzO.js.map +1 -1
  10. package/dist/chunks/config-C0Ea9ePP.js.map +1 -1
  11. package/dist/chunks/config-C0Eu8jpG.js.map +1 -1
  12. package/dist/chunks/config-CDat1wXf.js.map +1 -1
  13. package/dist/chunks/{config-DO8mjeIo.js → config-CIkdsWUk.js} +6 -2
  14. package/dist/chunks/config-CIkdsWUk.js.map +1 -0
  15. package/dist/chunks/config-CQLNjc9X2.js.map +1 -1
  16. package/dist/chunks/config-CbEbLyDE.js.map +1 -1
  17. package/dist/chunks/{config-jyr6AIZt2.js → config-CuQmUkMw2.js} +2 -2
  18. package/dist/chunks/{config-jyr6AIZt2.js.map → config-CuQmUkMw2.js.map} +1 -1
  19. package/dist/chunks/config-DeyT9dJl.js.map +1 -1
  20. package/dist/chunks/config-DnF472Ox.js.map +1 -1
  21. package/dist/chunks/config-DwABJHEo.js.map +1 -1
  22. package/dist/chunks/{config-tiUtEn4Q.js → config-E1cTyRVV.js} +1 -1
  23. package/dist/chunks/{config-tiUtEn4Q.js.map → config-E1cTyRVV.js.map} +1 -1
  24. package/dist/chunks/config-MmPym-Z72.js.map +1 -1
  25. package/dist/chunks/config-T3-DMXYm.js.map +1 -1
  26. package/dist/chunks/config-Yy67uWHY.js.map +1 -1
  27. package/dist/chunks/config-_jbgsFpw.js.map +1 -1
  28. package/dist/chunks/config-g8-JGZ_Y.js.map +1 -1
  29. package/dist/chunks/config-mlheIMtV.js.map +1 -1
  30. package/dist/chunks/config-rLkc9Zn2.js.map +1 -1
  31. package/dist/chunks/config-uzUuosv7.js.map +1 -1
  32. package/dist/chunks/context-CTbuwcYs.js.map +1 -1
  33. package/dist/chunks/deltaTone-B5OoS1vo.js.map +1 -1
  34. package/dist/chunks/es-Do2CNrC2.js.map +1 -1
  35. package/dist/chunks/fileValidation-D5TFBhbv.js.map +1 -1
  36. package/dist/chunks/focusables-BkzK42SQ.js.map +1 -1
  37. package/dist/chunks/{generated-DJ2dJ__C.js → generated-CSyPsWtM.js} +1 -1
  38. package/dist/chunks/{generated-DJ2dJ__C.js.map → generated-CSyPsWtM.js.map} +1 -1
  39. package/dist/chunks/grBadgeStyles-D8Mz73B5.js.map +1 -1
  40. package/dist/chunks/{grButtonStyles-B_-YRE__.js → grButtonStyles-B3wRWW_i.js} +4 -4
  41. package/dist/chunks/grButtonStyles-B3wRWW_i.js.map +1 -0
  42. package/dist/chunks/{grInputStyles-CAk3xKIb.js → grInputStyles-DgQYjJvD.js} +17 -1
  43. package/dist/chunks/{grInputStyles-CAk3xKIb.js.map → grInputStyles-DgQYjJvD.js.map} +1 -1
  44. package/dist/chunks/grLinkStyles-FME_qMpi.js.map +1 -1
  45. package/dist/chunks/grLoadingStyles-CnQaf5ry.js.map +1 -1
  46. package/dist/chunks/{grRadioStyles-D4gnU65n.js → grRadioStyles-DGL2QLy6.js} +1 -1
  47. package/dist/chunks/{grRadioStyles-D4gnU65n.js.map → grRadioStyles-DGL2QLy6.js.map} +1 -1
  48. package/dist/chunks/grSelectStyles-Cdtd10eY.js.map +1 -1
  49. package/dist/chunks/{grSliderStyles-B5uNxNJq.js → grSliderStyles-kaz6VXZ3.js} +9 -1
  50. package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +1 -0
  51. package/dist/chunks/{granular-provider-CHFaw3wU.js → granular-provider-Da2CJO6j.js} +4 -4
  52. package/dist/chunks/{granular-provider-CHFaw3wU.js.map → granular-provider-Da2CJO6j.js.map} +1 -1
  53. package/dist/chunks/granularityI18n-BC5zsj_d.js.map +1 -1
  54. package/dist/chunks/icon-Dag2tIMs.js.map +1 -1
  55. package/dist/chunks/inert-DIHCCn_1.js.map +1 -1
  56. package/dist/chunks/keyboard-DE2yhz_b.js.map +1 -1
  57. package/dist/chunks/numericStep-Bq2lj4ew.js.map +1 -1
  58. package/dist/chunks/optionFilter-DYw9XPPx.js.map +1 -1
  59. package/dist/chunks/overlayStack-C8cfsqXa.js.map +1 -1
  60. package/dist/chunks/portalRoot-CVhCgdG6.js.map +1 -1
  61. package/dist/chunks/renamedProp-BwcN-SJg.js.map +1 -1
  62. package/dist/chunks/{safelist-BOq5Li7p.js → safelist-DxkMj5IW.js} +1 -1
  63. package/dist/chunks/{safelist-BOq5Li7p.js.map → safelist-DxkMj5IW.js.map} +1 -1
  64. package/dist/chunks/slotNodes-DxNXpC7v.js.map +1 -1
  65. package/dist/chunks/useControlAddons-asUr10Pf.js.map +1 -1
  66. package/dist/chunks/useControlledOpen-DV3SqLTP.js.map +1 -1
  67. package/dist/chunks/useDragSort-0l47h4yb.js.map +1 -1
  68. package/dist/chunks/useFilePreviews-DnwgdyBs.js.map +1 -1
  69. package/dist/chunks/useFocusWithin-BwHE0rzm.js.map +1 -1
  70. package/dist/chunks/useModalOverlay-Cv5hF63W.js.map +1 -1
  71. package/dist/chunks/usePortalTarget-C0p-mhaM.js.map +1 -1
  72. package/dist/chunks/validation-5HhpanPP.js.map +1 -1
  73. package/dist/components/GrAlert/chunks/GrAlert-FAVf-ksH.js.map +1 -1
  74. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-X6RlmiJQ.js → GrAutocomplete-rYEY15UI.js} +1 -1
  75. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-rYEY15UI.js.map +1 -0
  76. package/dist/components/GrAutocomplete/index.js +1 -1
  77. package/dist/components/GrAutocomplete/styles.css +1 -1
  78. package/dist/components/GrAvatar/chunks/GrAvatar-CNmLmgcr.js.map +1 -1
  79. package/dist/components/GrBadge/chunks/{GrBadge-BsoocpF-.js → GrBadge-D2MfThPz.js} +1 -1
  80. package/dist/components/GrBadge/chunks/GrBadge-D2MfThPz.js.map +1 -0
  81. package/dist/components/GrBadge/index.js +1 -1
  82. package/dist/components/GrBadge/styles.css +1 -1
  83. package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-B-A3PRkE.js.map +1 -1
  84. package/dist/components/GrBottomNav/chunks/GrBottomNav-wtFatLjB.js.map +1 -1
  85. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-DRDNan_n.js.map +1 -1
  86. package/dist/components/GrButton/chunks/{GrButton-Bw2AH4uX.js → GrButton-7GP0zObj.js} +1 -1
  87. package/dist/components/GrButton/chunks/GrButton-7GP0zObj.js.map +1 -0
  88. package/dist/components/GrButton/index.js +3 -3
  89. package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -1
  90. package/dist/components/GrCard/chunks/GrCard-BttXz1pQ.js.map +1 -1
  91. package/dist/components/GrCheckbox/chunks/GrCheckbox-CEcHIsXM.js.map +1 -1
  92. package/dist/components/GrCheckboxGroup/chunks/GrCheckboxGroup-BOwrVcFr.js.map +1 -1
  93. package/dist/components/GrChip/chunks/GrChip-C0vU69tf.js.map +1 -1
  94. package/dist/components/GrChipGroup/chunks/GrChipGroup-C78Vcwos.js.map +1 -1
  95. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dkvkr91t.js → GrCodeBlock-Dp0eEBTZ.js} +1 -1
  96. package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dp0eEBTZ.js.map +1 -0
  97. package/dist/components/GrCodeBlock/index.js +1 -1
  98. package/dist/components/GrCollapse/chunks/GrCollapse-BlW6ybdL.js.map +1 -1
  99. package/dist/components/GrColorPicker/chunks/{GrColorPicker-CE-xtNP-.js → GrColorPicker-B20gQ6AR.js} +2 -2
  100. package/dist/components/GrColorPicker/chunks/GrColorPicker-B20gQ6AR.js.map +1 -0
  101. package/dist/components/GrColorPicker/index.js +1 -1
  102. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-C5abL2Y7.js → GrCommandPalette-Cd0Yo3Dw.js} +1 -1
  103. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-Cd0Yo3Dw.js.map +1 -0
  104. package/dist/components/GrCommandPalette/index.js +1 -1
  105. package/dist/components/GrCommandPalette/styles.css +1 -1
  106. package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js.map +1 -1
  107. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-B9mIU78E.js → GrConfirmDialog-DOsbRhoZ.js} +3 -3
  108. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DOsbRhoZ.js.map +1 -0
  109. package/dist/components/GrConfirmDialog/index.js +1 -1
  110. package/dist/components/GrContextMenu/chunks/GrContextMenu-_FKwQvuQ.js.map +1 -1
  111. package/dist/components/GrDataTable/chunks/{GrDataTable-C8a9_nCg.js → GrDataTable-CAGgRk27.js} +5 -3
  112. package/dist/components/GrDataTable/chunks/GrDataTable-CAGgRk27.js.map +1 -0
  113. package/dist/components/GrDataTable/index.js +1 -1
  114. package/dist/components/GrDelta/chunks/GrDelta-BZwkgQW-.js.map +1 -1
  115. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-BMeCgFV3.js.map +1 -1
  116. package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js → GrDialog-S1Vl-OhX.js} +1 -1
  117. package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js.map → GrDialog-S1Vl-OhX.js.map} +1 -1
  118. package/dist/components/GrDialog/index.js +1 -1
  119. package/dist/components/GrDialogService/chunks/{GrDialogService-k4SYIv64.js → GrDialogService-Cuhc4YLp.js} +4 -4
  120. package/dist/components/GrDialogService/chunks/GrDialogService-Cuhc4YLp.js.map +1 -0
  121. package/dist/components/GrDialogService/index.js +1 -1
  122. package/dist/components/GrDivider/chunks/GrDivider-BXavGcMX.js.map +1 -1
  123. package/dist/components/GrDrawer/chunks/{GrDrawer-B7PiAcbU.js → GrDrawer-C0YqVE9e.js} +1 -1
  124. package/dist/components/GrDrawer/chunks/GrDrawer-C0YqVE9e.js.map +1 -0
  125. package/dist/components/GrDrawer/index.js +1 -1
  126. package/dist/components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js.map +1 -1
  127. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-GOzuAXsi.js.map +1 -1
  128. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js.map +1 -1
  129. package/dist/components/GrFilePreview/chunks/GrFilePreview-C9Z7hMK8.js.map +1 -1
  130. package/dist/components/GrFileUpload/chunks/GrFileUpload-NsHkRRIa.js.map +1 -1
  131. package/dist/components/GrForm/chunks/GrForm-CrnfCsgj.js.map +1 -1
  132. package/dist/components/GrFormField/chunks/GrFormField-DSylU7IU.js.map +1 -1
  133. package/dist/components/GrFormFile/chunks/{GrFormFile-CYtXU9HV.js → GrFormFile-B1jGZyIj.js} +2 -2
  134. package/dist/components/GrFormFile/chunks/GrFormFile-B1jGZyIj.js.map +1 -0
  135. package/dist/components/GrFormFile/index.js +1 -1
  136. package/dist/components/GrFormFile/styles.css +1 -1
  137. package/dist/components/GrIcon/chunks/GrIcon-Dmf0c9ba.js.map +1 -1
  138. package/dist/components/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js.map +1 -1
  139. package/dist/components/GrInput/chunks/{GrInput-BqqoEl1b.js → GrInput-BLywRZUN.js} +10 -6
  140. package/dist/components/GrInput/chunks/GrInput-BLywRZUN.js.map +1 -0
  141. package/dist/components/GrInput/index.js +2 -2
  142. package/dist/components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js.map +1 -1
  143. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-CgwjoUJt.js → GrJsonViewer-BCZ7lE2k.js} +3 -3
  144. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-BCZ7lE2k.js.map +1 -0
  145. package/dist/components/GrJsonViewer/index.js +1 -1
  146. package/dist/components/GrKbd/chunks/GrKbd-D2ga1H9i.js.map +1 -1
  147. package/dist/components/GrLink/chunks/GrLink-DYXw3W9w.js.map +1 -1
  148. package/dist/components/GrList/chunks/{GrList-DmT4qzLO.js → GrList-B_CRJB4c.js} +1 -1
  149. package/dist/components/GrList/chunks/GrList-B_CRJB4c.js.map +1 -0
  150. package/dist/components/GrList/index.js +1 -1
  151. package/dist/components/GrList/styles.css +1 -1
  152. package/dist/components/GrModal/chunks/GrModal-CCoWZuIl.js.map +1 -1
  153. package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js → GrNavbar-_rtHKwTf.js} +1 -1
  154. package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js.map → GrNavbar-_rtHKwTf.js.map} +1 -1
  155. package/dist/components/GrNavbar/index.js +1 -1
  156. package/dist/components/GrNumberInput/chunks/GrNumberInput-DQ59YICu.js.map +1 -1
  157. package/dist/components/GrPagination/chunks/{GrPagination-kYCx6PAS.js → GrPagination-B_kAhoAV.js} +2 -2
  158. package/dist/components/GrPagination/chunks/{GrPagination-kYCx6PAS.js.map → GrPagination-B_kAhoAV.js.map} +1 -1
  159. package/dist/components/GrPagination/index.js +1 -1
  160. package/dist/components/GrPopover/chunks/GrPopover-CofG-Tfe.js.map +1 -1
  161. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-D1ADRFxx.js → GrPromptDialog-BuJQMZLM.js} +5 -5
  162. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-BuJQMZLM.js.map +1 -0
  163. package/dist/components/GrPromptDialog/index.js +1 -1
  164. package/dist/components/GrRadio/chunks/{GrRadio-C_rESc5g.js → GrRadio-Aq3v8XgG.js} +1 -1
  165. package/dist/components/GrRadio/chunks/GrRadio-Aq3v8XgG.js.map +1 -0
  166. package/dist/components/GrRadio/index.js +2 -2
  167. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CdQO4G-U.js → GrRadioGroup-y9LVdTWh.js} +1 -1
  168. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-y9LVdTWh.js.map +1 -0
  169. package/dist/components/GrRadioGroup/index.js +1 -1
  170. package/dist/components/GrRating/chunks/GrRating-IEiTOdnF.js.map +1 -1
  171. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js → GrResponseErrorBanner-CBVRpgIG.js} +1 -1
  172. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js.map → GrResponseErrorBanner-CBVRpgIG.js.map} +1 -1
  173. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DudGc9LO.js → GrResponseErrorBanner-DMeOWlzj.js} +1 -1
  174. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js.map +1 -0
  175. package/dist/components/GrResponseErrorBanner/index.js +2 -2
  176. package/dist/components/GrSegmented/chunks/GrSegmented-CB-VR-yL.js.map +1 -1
  177. package/dist/components/GrSelect/chunks/{GrSelect-CBp0twbF.js → GrSelect-gCeRFgQo.js} +2 -2
  178. package/dist/components/GrSelect/chunks/GrSelect-gCeRFgQo.js.map +1 -0
  179. package/dist/components/GrSelect/index.js +1 -1
  180. package/dist/components/GrSelect/styles.css +1 -1
  181. package/dist/components/GrSidebar/chunks/{GrSidebar-B8EQIlfW.js → GrSidebar-alkwBUzL.js} +1 -1
  182. package/dist/components/GrSidebar/chunks/GrSidebar-alkwBUzL.js.map +1 -0
  183. package/dist/components/GrSidebar/index.js +1 -1
  184. package/dist/components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js.map +1 -1
  185. package/dist/components/GrSlider/chunks/{GrSlider-DJfeEl4h.js → GrSlider-DTTrZTHK.js} +3 -3
  186. package/dist/components/GrSlider/chunks/GrSlider-DTTrZTHK.js.map +1 -0
  187. package/dist/components/GrSlider/index.js +2 -2
  188. package/dist/components/GrSortableList/chunks/GrSortableList-HyKX--rO.js.map +1 -1
  189. package/dist/components/GrSplitter/chunks/GrSplitter-MltjaADn.js.map +1 -1
  190. package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +1 -1
  191. package/dist/components/GrSteps/chunks/GrSteps-C2jxpZoN.js.map +1 -1
  192. package/dist/components/GrSwitch/chunks/{GrSwitch-g_OOSkh7.js → GrSwitch-7Oe5QfQZ.js} +1 -1
  193. package/dist/components/GrSwitch/chunks/GrSwitch-7Oe5QfQZ.js.map +1 -0
  194. package/dist/components/GrSwitch/index.js +1 -1
  195. package/dist/components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js.map +1 -1
  196. package/dist/components/GrTable/chunks/GrTable-Zcdz2St_.js.map +1 -1
  197. package/dist/components/GrTextarea/chunks/{GrTextarea-KREK75Bu.js → GrTextarea-DinXG12-.js} +10 -10
  198. package/dist/components/GrTextarea/chunks/GrTextarea-DinXG12-.js.map +1 -0
  199. package/dist/components/GrTextarea/index.js +1 -1
  200. package/dist/components/GrTimeline/chunks/GrTimeline-BiHpArsg.js.map +1 -1
  201. package/dist/components/GrToaster/chunks/{GrToaster-Dp7-4B8k.js → GrToaster-COXIBKzq.js} +2 -2
  202. package/dist/components/GrToaster/chunks/GrToaster-COXIBKzq.js.map +1 -0
  203. package/dist/components/GrToaster/index.js +1 -1
  204. package/dist/components/GrToaster/styles.css +1 -1
  205. package/dist/components/GrTooltip/chunks/GrTooltip-uYETdbCD.js.map +1 -1
  206. package/dist/components/GrTree/chunks/{GrTree-DC89I4AP.js → GrTree-Ci6CZfKR.js} +5 -5
  207. package/dist/components/GrTree/chunks/GrTree-Ci6CZfKR.js.map +1 -0
  208. package/dist/components/GrTree/index.js +1 -1
  209. package/dist/components/GrTree/styles.css +1 -1
  210. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-CymO68Cv.js → GrTreeSelect-BHwgGJcT.js} +2 -2
  211. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHwgGJcT.js.map +1 -0
  212. package/dist/components/GrTreeSelect/index.js +1 -1
  213. package/dist/composables/useAnnouncer.js.map +1 -1
  214. package/dist/composables/useComboboxNavigation.js.map +1 -1
  215. package/dist/composables/useDragGesture.js.map +1 -1
  216. package/dist/composables/useFocusTrap.js.map +1 -1
  217. package/dist/composables/useOverlayLayer.js.map +1 -1
  218. package/dist/composables/useRovingFocus.js.map +1 -1
  219. package/dist/composables/useTheme.js.map +1 -1
  220. package/dist/composables/useToast.js.map +1 -1
  221. package/dist/composables/useVirtualList.js.map +1 -1
  222. package/dist/directives/autofocus.js.map +1 -1
  223. package/dist/directives/autosize.js.map +1 -1
  224. package/dist/directives/clickOutside.js.map +1 -1
  225. package/dist/directives/dropzone.js.map +1 -1
  226. package/dist/directives/hotkey.js.map +1 -1
  227. package/dist/directives/loading.js.map +1 -1
  228. package/dist/granular-provider-node.js +1 -1
  229. package/dist/granular-provider.js +1 -1
  230. package/dist/index.js +35 -35
  231. package/dist/testing.js +2 -2
  232. package/dist/testing.js.map +1 -1
  233. package/dist/theme-apply.js.map +1 -1
  234. package/dist/theme.js +1 -1
  235. package/dist/theme.js.map +1 -1
  236. package/dist/tokens.js +1 -1
  237. package/dist/types/components/GrCodeBlock/tokenizeJson.d.ts +1 -3
  238. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +1 -1
  239. package/dist/types/components/GrInput/GrInput.vue.d.ts +29 -13
  240. package/dist/types/components/GrInput/grInputStyles.d.ts +16 -0
  241. package/dist/types/components/GrSlider/grSliderStyles.d.ts +9 -1
  242. package/dist/types/components/GrTabPanels/GrTabPanel.vue.d.ts +3 -3
  243. package/dist/vue/index.js.map +1 -1
  244. package/dist/web-types.json +10 -1
  245. package/package.json +3 -3
  246. package/dist/chunks/config-DO8mjeIo.js.map +0 -1
  247. package/dist/chunks/grButtonStyles-B_-YRE__.js.map +0 -1
  248. package/dist/chunks/grSliderStyles-B5uNxNJq.js.map +0 -1
  249. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-X6RlmiJQ.js.map +0 -1
  250. package/dist/components/GrBadge/chunks/GrBadge-BsoocpF-.js.map +0 -1
  251. package/dist/components/GrButton/chunks/GrButton-Bw2AH4uX.js.map +0 -1
  252. package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dkvkr91t.js.map +0 -1
  253. package/dist/components/GrColorPicker/chunks/GrColorPicker-CE-xtNP-.js.map +0 -1
  254. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-C5abL2Y7.js.map +0 -1
  255. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-B9mIU78E.js.map +0 -1
  256. package/dist/components/GrDataTable/chunks/GrDataTable-C8a9_nCg.js.map +0 -1
  257. package/dist/components/GrDialogService/chunks/GrDialogService-k4SYIv64.js.map +0 -1
  258. package/dist/components/GrDrawer/chunks/GrDrawer-B7PiAcbU.js.map +0 -1
  259. package/dist/components/GrFormFile/chunks/GrFormFile-CYtXU9HV.js.map +0 -1
  260. package/dist/components/GrInput/chunks/GrInput-BqqoEl1b.js.map +0 -1
  261. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-CgwjoUJt.js.map +0 -1
  262. package/dist/components/GrList/chunks/GrList-DmT4qzLO.js.map +0 -1
  263. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-D1ADRFxx.js.map +0 -1
  264. package/dist/components/GrRadio/chunks/GrRadio-C_rESc5g.js.map +0 -1
  265. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-CdQO4G-U.js.map +0 -1
  266. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DudGc9LO.js.map +0 -1
  267. package/dist/components/GrSelect/chunks/GrSelect-CBp0twbF.js.map +0 -1
  268. package/dist/components/GrSidebar/chunks/GrSidebar-B8EQIlfW.js.map +0 -1
  269. package/dist/components/GrSlider/chunks/GrSlider-DJfeEl4h.js.map +0 -1
  270. package/dist/components/GrSwitch/chunks/GrSwitch-g_OOSkh7.js.map +0 -1
  271. package/dist/components/GrTextarea/chunks/GrTextarea-KREK75Bu.js.map +0 -1
  272. package/dist/components/GrToaster/chunks/GrToaster-Dp7-4B8k.js.map +0 -1
  273. package/dist/components/GrTree/chunks/GrTree-DC89I4AP.js.map +0 -1
  274. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-CymO68Cv.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"GrBottomNav-wtFatLjB.js","names":[],"sources":["../../../../src/components/GrBottomNav/GrBottomNav.vue","../../../../src/components/GrBottomNav/GrBottomNav.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, markRaw, type Component } from 'vue'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n\nimport {\n grBottomNavIconClass,\n grBottomNavItemClass,\n grBottomNavListClass,\n grBottomNavRootClass,\n itemBadgeClass,\n itemLabelClass,\n type GrBottomNavHideAbove,\n type GrBottomNavPosition,\n} from './grBottomNavStyles'\n\nimport './defaults'\n\nexport type { GrBottomNavHideAbove, GrBottomNavPosition } from './grBottomNavStyles'\n\n/** Пункт нижней навигации. Кроме подписи и значения всё опционально. */\nexport type GrBottomNavItem = {\n label: string\n value: string\n /** Иконка: класс UnoCSS-иконки (`'i-lucide-home'`) или Vue-компонент. Декоративна. */\n icon?: string | Component\n /** Счётчик поверх пункта. Число озвучивается словами, строка — как есть. */\n badge?: string | number\n /** Подпись счётчика для скринридера, сильнее локали. */\n badgeLabel?: string\n disabled?: boolean\n href?: string\n /** Цель роутерной ссылки: уезжает в компонент из `as`. */\n to?: unknown\n /** Доступное имя пункта, когда подписи недостаточно. */\n ariaLabel?: string\n}\n\n/**\n * GrBottomNav — нижняя навигация приложения: ряд разделов, прижатый к нижней\n * кромке экрана.\n *\n * Активный пункт объявлен `aria-current=\"page\"` и отличается не только цветом:\n * подложкой и весом подписи тоже.\n */\nexport interface GrBottomNavProps {\n modelValue: string\n items: GrBottomNavItem[]\n /** Компонент ссылки для пунктов с `to`: `RouterLink`, `NuxtLink`, `Link` Inertia. */\n as?: string | Component\n /** Брейкпоинт, начиная с которого панель скрывается. `none` — видна всегда. */\n hideAbove?: GrBottomNavHideAbove\n /** `static` вынимает панель из фиксированного слоя — для встраивания в макет. */\n position?: GrBottomNavPosition\n /** Имя лендмарка. Не задано — берётся из локали. */\n ariaLabel?: string\n /**\n * Ступень размера: высота полосы, глиф и кегль подписи. Тач-таргет пункта\n * остаётся 44×44 на любой ступени.\n */\n size?: GrComponentSize\n}\n\nexport interface GrBottomNavEmits {\n (e: 'update:modelValue', value: string): void\n}\n\nconst props = withDefaults(defineProps<GrBottomNavProps>(), {\n as: undefined,\n hideAbove: 'sm',\n position: 'fixed',\n ariaLabel: undefined,\n // `undefined`: «настоящий» дефолт живёт в `useGrComponentSize`, иначе\n // `GrConfigProvider` не отличит заданное значение от подставленного Vue.\n size: undefined,\n})\n\nconst emit = defineEmits<GrBottomNavEmits>()\n\ndefineSlots<{\n /**\n * Содержимое пункта вместо иконки, подписи и счётчика. Корень пункта —\n * тег, `aria-current`, `aria-disabled` и клик — остаётся за компонентом.\n */\n item?: (props: {\n item: GrBottomNavItem\n active: boolean\n disabled: boolean\n badgeLabel: string | undefined\n }) => any\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.bottomNav.label', 'Bottom navigation'))\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrBottomNav' })\n\nconst rootClass = computed(() => grBottomNavRootClass({\n position: props.position,\n hideAbove: props.hideAbove,\n}))\n\nconst linkComponent = computed(() => (props.as && typeof props.as !== 'string' ? markRaw(props.as) : props.as))\n\nfunction itemTag(item: GrBottomNavItem): string | Component {\n if (item.disabled) return 'span'\n if (item.to !== undefined && linkComponent.value) return linkComponent.value\n return item.href ? 'a' : 'button'\n}\n\n/**\n * Счётчик рисуется декоративно, а рядом идёт скрытая подпись: голое «3» без\n * единицы измерения диктору ничего не сообщает.\n */\nfunction badgeLabel(item: GrBottomNavItem): string | undefined {\n if (item.badge == null || item.badge === '') return undefined\n if (item.badgeLabel) return item.badgeLabel\n if (typeof item.badge === 'number') {\n return t('gr.bottomNav.badge', '{count} new', { count: item.badge, n: item.badge })\n }\n return String(item.badge)\n}\n\nfunction select(item: GrBottomNavItem): void {\n if (item.disabled) return\n emit('update:modelValue', item.value)\n}\n</script>\n\n<template>\n <nav :class=\"rootClass\" :aria-label=\"resolvedAriaLabel\">\n <div :class=\"grBottomNavListClass(resolvedSize)\">\n <component\n :is=\"itemTag(item)\"\n v-for=\"item in items\"\n :key=\"item.value\"\n data-gr-bottom-nav-item\n :type=\"itemTag(item) === 'button' ? 'button' : undefined\"\n :href=\"itemTag(item) === 'a' ? item.href : undefined\"\n :to=\"item.to !== undefined && linkComponent ? item.to : undefined\"\n :aria-current=\"item.value === modelValue ? 'page' : undefined\"\n :aria-disabled=\"item.disabled ? 'true' : undefined\"\n :aria-label=\"item.ariaLabel\"\n :class=\"grBottomNavItemClass({ active: item.value === modelValue, disabled: item.disabled ?? false, size: resolvedSize })\"\n @click=\"select(item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :active=\"item.value === modelValue\"\n :disabled=\"item.disabled ?? false\"\n :badge-label=\"badgeLabel(item)\"\n >\n <component :is=\"item.icon\" v-if=\"item.icon && typeof item.icon !== 'string'\" :class=\"grBottomNavIconClass(resolvedSize)\" aria-hidden=\"true\" />\n <span v-else-if=\"item.icon\" :class=\"[item.icon, grBottomNavIconClass(resolvedSize)]\" aria-hidden=\"true\" />\n\n <span :class=\"itemLabelClass\">{{ item.label }}</span>\n\n <template v-if=\"item.badge != null && item.badge !== ''\">\n <span data-gr-bottom-nav-badge :class=\"itemBadgeClass\" aria-hidden=\"true\">{{ item.badge }}</span>\n <span data-gr-bottom-nav-badge-label class=\"sr-only\">{{ badgeLabel(item) }}</span>\n </template>\n </slot>\n </component>\n </div>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, type Component } from 'vue'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n\nimport {\n grBottomNavIconClass,\n grBottomNavItemClass,\n grBottomNavListClass,\n grBottomNavRootClass,\n itemBadgeClass,\n itemLabelClass,\n type GrBottomNavHideAbove,\n type GrBottomNavPosition,\n} from './grBottomNavStyles'\n\nimport './defaults'\n\nexport type { GrBottomNavHideAbove, GrBottomNavPosition } from './grBottomNavStyles'\n\n/** Пункт нижней навигации. Кроме подписи и значения всё опционально. */\nexport type GrBottomNavItem = {\n label: string\n value: string\n /** Иконка: класс UnoCSS-иконки (`'i-lucide-home'`) или Vue-компонент. Декоративна. */\n icon?: string | Component\n /** Счётчик поверх пункта. Число озвучивается словами, строка — как есть. */\n badge?: string | number\n /** Подпись счётчика для скринридера, сильнее локали. */\n badgeLabel?: string\n disabled?: boolean\n href?: string\n /** Цель роутерной ссылки: уезжает в компонент из `as`. */\n to?: unknown\n /** Доступное имя пункта, когда подписи недостаточно. */\n ariaLabel?: string\n}\n\n/**\n * GrBottomNav — нижняя навигация приложения: ряд разделов, прижатый к нижней\n * кромке экрана.\n *\n * Активный пункт объявлен `aria-current=\"page\"` и отличается не только цветом:\n * подложкой и весом подписи тоже.\n */\nexport interface GrBottomNavProps {\n modelValue: string\n items: GrBottomNavItem[]\n /** Компонент ссылки для пунктов с `to`: `RouterLink`, `NuxtLink`, `Link` Inertia. */\n as?: string | Component\n /** Брейкпоинт, начиная с которого панель скрывается. `none` — видна всегда. */\n hideAbove?: GrBottomNavHideAbove\n /** `static` вынимает панель из фиксированного слоя — для встраивания в макет. */\n position?: GrBottomNavPosition\n /** Имя лендмарка. Не задано — берётся из локали. */\n ariaLabel?: string\n /**\n * Ступень размера: высота полосы, глиф и кегль подписи. Тач-таргет пункта\n * остаётся 44×44 на любой ступени.\n */\n size?: GrComponentSize\n}\n\nexport interface GrBottomNavEmits {\n (e: 'update:modelValue', value: string): void\n}\n\nconst props = withDefaults(defineProps<GrBottomNavProps>(), {\n as: undefined,\n hideAbove: 'sm',\n position: 'fixed',\n ariaLabel: undefined,\n // `undefined`: «настоящий» дефолт живёт в `useGrComponentSize`, иначе\n // `GrConfigProvider` не отличит заданное значение от подставленного Vue.\n size: undefined,\n})\n\nconst emit = defineEmits<GrBottomNavEmits>()\n\ndefineSlots<{\n /**\n * Содержимое пункта вместо иконки, подписи и счётчика. Корень пункта —\n * тег, `aria-current`, `aria-disabled` и клик — остаётся за компонентом.\n */\n item?: (props: {\n item: GrBottomNavItem\n active: boolean\n disabled: boolean\n badgeLabel: string | undefined\n }) => any\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.bottomNav.label', 'Bottom navigation'))\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrBottomNav' })\n\nconst rootClass = computed(() => grBottomNavRootClass({\n position: props.position,\n hideAbove: props.hideAbove,\n}))\n\nconst linkComponent = computed(() => (props.as && typeof props.as !== 'string' ? markRaw(props.as) : props.as))\n\nfunction itemTag(item: GrBottomNavItem): string | Component {\n if (item.disabled) return 'span'\n if (item.to !== undefined && linkComponent.value) return linkComponent.value\n return item.href ? 'a' : 'button'\n}\n\n/**\n * Счётчик рисуется декоративно, а рядом идёт скрытая подпись: голое «3» без\n * единицы измерения диктору ничего не сообщает.\n */\nfunction badgeLabel(item: GrBottomNavItem): string | undefined {\n if (item.badge == null || item.badge === '') return undefined\n if (item.badgeLabel) return item.badgeLabel\n if (typeof item.badge === 'number') {\n return t('gr.bottomNav.badge', '{count} new', { count: item.badge, n: item.badge })\n }\n return String(item.badge)\n}\n\nfunction select(item: GrBottomNavItem): void {\n if (item.disabled) return\n emit('update:modelValue', item.value)\n}\n</script>\n\n<template>\n <nav :class=\"rootClass\" :aria-label=\"resolvedAriaLabel\">\n <div :class=\"grBottomNavListClass(resolvedSize)\">\n <component\n :is=\"itemTag(item)\"\n v-for=\"item in items\"\n :key=\"item.value\"\n data-gr-bottom-nav-item\n :type=\"itemTag(item) === 'button' ? 'button' : undefined\"\n :href=\"itemTag(item) === 'a' ? item.href : undefined\"\n :to=\"item.to !== undefined && linkComponent ? item.to : undefined\"\n :aria-current=\"item.value === modelValue ? 'page' : undefined\"\n :aria-disabled=\"item.disabled ? 'true' : undefined\"\n :aria-label=\"item.ariaLabel\"\n :class=\"grBottomNavItemClass({ active: item.value === modelValue, disabled: item.disabled ?? false, size: resolvedSize })\"\n @click=\"select(item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :active=\"item.value === modelValue\"\n :disabled=\"item.disabled ?? false\"\n :badge-label=\"badgeLabel(item)\"\n >\n <component :is=\"item.icon\" v-if=\"item.icon && typeof item.icon !== 'string'\" :class=\"grBottomNavIconClass(resolvedSize)\" aria-hidden=\"true\" />\n <span v-else-if=\"item.icon\" :class=\"[item.icon, grBottomNavIconClass(resolvedSize)]\" aria-hidden=\"true\" />\n\n <span :class=\"itemLabelClass\">{{ item.label }}</span>\n\n <template v-if=\"item.badge != null && item.badge !== ''\">\n <span data-gr-bottom-nav-badge :class=\"itemBadgeClass\" aria-hidden=\"true\">{{ item.badge }}</span>\n <span data-gr-bottom-nav-badge-label class=\"sr-only\">{{ badgeLabel(item) }}</span>\n </template>\n </slot>\n </component>\n </div>\n </nav>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrBottomNav-wtFatLjB.js","names":[],"sources":["../../../../src/components/GrBottomNav/GrBottomNav.vue","../../../../src/components/GrBottomNav/GrBottomNav.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, markRaw, type Component } from 'vue'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n\nimport {\n grBottomNavIconClass,\n grBottomNavItemClass,\n grBottomNavListClass,\n grBottomNavRootClass,\n itemBadgeClass,\n itemLabelClass,\n type GrBottomNavHideAbove,\n type GrBottomNavPosition,\n} from './grBottomNavStyles'\n\nimport './defaults'\n\nexport type { GrBottomNavHideAbove, GrBottomNavPosition } from './grBottomNavStyles'\n\n/** Пункт нижней навигации. Кроме подписи и значения всё опционально. */\nexport type GrBottomNavItem = {\n label: string\n value: string\n /** Иконка: класс UnoCSS-иконки (`'i-lucide-home'`) или Vue-компонент. Декоративна. */\n icon?: string | Component\n /** Счётчик поверх пункта. Число озвучивается словами, строка — как есть. */\n badge?: string | number\n /** Подпись счётчика для скринридера, сильнее локали. */\n badgeLabel?: string\n disabled?: boolean\n href?: string\n /** Цель роутерной ссылки: уезжает в компонент из `as`. */\n to?: unknown\n /** Доступное имя пункта, когда подписи недостаточно. */\n ariaLabel?: string\n}\n\n/**\n * GrBottomNav — нижняя навигация приложения: ряд разделов, прижатый к нижней\n * кромке экрана.\n *\n * Активный пункт объявлен `aria-current=\"page\"` и отличается не только цветом:\n * подложкой и весом подписи тоже.\n */\nexport interface GrBottomNavProps {\n modelValue: string\n items: GrBottomNavItem[]\n /** Компонент ссылки для пунктов с `to`: `RouterLink`, `NuxtLink`, `Link` Inertia. */\n as?: string | Component\n /** Брейкпоинт, начиная с которого панель скрывается. `none` — видна всегда. */\n hideAbove?: GrBottomNavHideAbove\n /** `static` вынимает панель из фиксированного слоя — для встраивания в макет. */\n position?: GrBottomNavPosition\n /** Имя лендмарка. Не задано — берётся из локали. */\n ariaLabel?: string\n /**\n * Ступень размера: высота полосы, глиф и кегль подписи. Тач-таргет пункта\n * остаётся 44×44 на любой ступени.\n */\n size?: GrComponentSize\n}\n\nexport interface GrBottomNavEmits {\n (e: 'update:modelValue', value: string): void\n}\n\nconst props = withDefaults(defineProps<GrBottomNavProps>(), {\n as: undefined,\n hideAbove: 'sm',\n position: 'fixed',\n ariaLabel: undefined,\n // `undefined`: «настоящий» дефолт живёт в `useGrComponentSize`, иначе\n // `GrConfigProvider` не отличит заданное значение от подставленного Vue.\n size: undefined,\n})\n\nconst emit = defineEmits<GrBottomNavEmits>()\n\ndefineSlots<{\n /**\n * Содержимое пункта вместо иконки, подписи и счётчика. Корень пункта —\n * тег, `aria-current`, `aria-disabled` и клик — остаётся за компонентом.\n */\n item?: (props: {\n item: GrBottomNavItem\n active: boolean\n disabled: boolean\n badgeLabel: string | undefined\n }) => any\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.bottomNav.label', 'Bottom navigation'))\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrBottomNav' })\n\nconst rootClass = computed(() => grBottomNavRootClass({\n position: props.position,\n hideAbove: props.hideAbove,\n}))\n\nconst linkComponent = computed(() => (props.as && typeof props.as !== 'string' ? markRaw(props.as) : props.as))\n\nfunction itemTag(item: GrBottomNavItem): string | Component {\n if (item.disabled)\n return 'span'\n if (item.to !== undefined && linkComponent.value)\n return linkComponent.value\n return item.href ? 'a' : 'button'\n}\n\n/**\n * Счётчик рисуется декоративно, а рядом идёт скрытая подпись: голое «3» без\n * единицы измерения диктору ничего не сообщает.\n */\nfunction badgeLabel(item: GrBottomNavItem): string | undefined {\n if (item.badge == null || item.badge === '')\n return undefined\n if (item.badgeLabel)\n return item.badgeLabel\n if (typeof item.badge === 'number') {\n return t('gr.bottomNav.badge', '{count} new', { count: item.badge, n: item.badge })\n }\n return String(item.badge)\n}\n\nfunction select(item: GrBottomNavItem): void {\n if (item.disabled)\n return\n emit('update:modelValue', item.value)\n}\n</script>\n\n<template>\n <nav :class=\"rootClass\" :aria-label=\"resolvedAriaLabel\">\n <div :class=\"grBottomNavListClass(resolvedSize)\">\n <component\n :is=\"itemTag(item)\"\n v-for=\"item in items\"\n :key=\"item.value\"\n data-gr-bottom-nav-item\n :type=\"itemTag(item) === 'button' ? 'button' : undefined\"\n :href=\"itemTag(item) === 'a' ? item.href : undefined\"\n :to=\"item.to !== undefined && linkComponent ? item.to : undefined\"\n :aria-current=\"item.value === modelValue ? 'page' : undefined\"\n :aria-disabled=\"item.disabled ? 'true' : undefined\"\n :aria-label=\"item.ariaLabel\"\n :class=\"grBottomNavItemClass({ active: item.value === modelValue, disabled: item.disabled ?? false, size: resolvedSize })\"\n @click=\"select(item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :active=\"item.value === modelValue\"\n :disabled=\"item.disabled ?? false\"\n :badge-label=\"badgeLabel(item)\"\n >\n <component :is=\"item.icon\" v-if=\"item.icon && typeof item.icon !== 'string'\" :class=\"grBottomNavIconClass(resolvedSize)\" aria-hidden=\"true\" />\n <span v-else-if=\"item.icon\" :class=\"[item.icon, grBottomNavIconClass(resolvedSize)]\" aria-hidden=\"true\" />\n\n <span :class=\"itemLabelClass\">{{ item.label }}</span>\n\n <template v-if=\"item.badge != null && item.badge !== ''\">\n <span data-gr-bottom-nav-badge :class=\"itemBadgeClass\" aria-hidden=\"true\">{{ item.badge }}</span>\n <span data-gr-bottom-nav-badge-label class=\"sr-only\">{{ badgeLabel(item) }}</span>\n </template>\n </slot>\n </component>\n </div>\n </nav>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, type Component } from 'vue'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n\nimport {\n grBottomNavIconClass,\n grBottomNavItemClass,\n grBottomNavListClass,\n grBottomNavRootClass,\n itemBadgeClass,\n itemLabelClass,\n type GrBottomNavHideAbove,\n type GrBottomNavPosition,\n} from './grBottomNavStyles'\n\nimport './defaults'\n\nexport type { GrBottomNavHideAbove, GrBottomNavPosition } from './grBottomNavStyles'\n\n/** Пункт нижней навигации. Кроме подписи и значения всё опционально. */\nexport type GrBottomNavItem = {\n label: string\n value: string\n /** Иконка: класс UnoCSS-иконки (`'i-lucide-home'`) или Vue-компонент. Декоративна. */\n icon?: string | Component\n /** Счётчик поверх пункта. Число озвучивается словами, строка — как есть. */\n badge?: string | number\n /** Подпись счётчика для скринридера, сильнее локали. */\n badgeLabel?: string\n disabled?: boolean\n href?: string\n /** Цель роутерной ссылки: уезжает в компонент из `as`. */\n to?: unknown\n /** Доступное имя пункта, когда подписи недостаточно. */\n ariaLabel?: string\n}\n\n/**\n * GrBottomNav — нижняя навигация приложения: ряд разделов, прижатый к нижней\n * кромке экрана.\n *\n * Активный пункт объявлен `aria-current=\"page\"` и отличается не только цветом:\n * подложкой и весом подписи тоже.\n */\nexport interface GrBottomNavProps {\n modelValue: string\n items: GrBottomNavItem[]\n /** Компонент ссылки для пунктов с `to`: `RouterLink`, `NuxtLink`, `Link` Inertia. */\n as?: string | Component\n /** Брейкпоинт, начиная с которого панель скрывается. `none` — видна всегда. */\n hideAbove?: GrBottomNavHideAbove\n /** `static` вынимает панель из фиксированного слоя — для встраивания в макет. */\n position?: GrBottomNavPosition\n /** Имя лендмарка. Не задано — берётся из локали. */\n ariaLabel?: string\n /**\n * Ступень размера: высота полосы, глиф и кегль подписи. Тач-таргет пункта\n * остаётся 44×44 на любой ступени.\n */\n size?: GrComponentSize\n}\n\nexport interface GrBottomNavEmits {\n (e: 'update:modelValue', value: string): void\n}\n\nconst props = withDefaults(defineProps<GrBottomNavProps>(), {\n as: undefined,\n hideAbove: 'sm',\n position: 'fixed',\n ariaLabel: undefined,\n // `undefined`: «настоящий» дефолт живёт в `useGrComponentSize`, иначе\n // `GrConfigProvider` не отличит заданное значение от подставленного Vue.\n size: undefined,\n})\n\nconst emit = defineEmits<GrBottomNavEmits>()\n\ndefineSlots<{\n /**\n * Содержимое пункта вместо иконки, подписи и счётчика. Корень пункта —\n * тег, `aria-current`, `aria-disabled` и клик — остаётся за компонентом.\n */\n item?: (props: {\n item: GrBottomNavItem\n active: boolean\n disabled: boolean\n badgeLabel: string | undefined\n }) => any\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.bottomNav.label', 'Bottom navigation'))\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrBottomNav' })\n\nconst rootClass = computed(() => grBottomNavRootClass({\n position: props.position,\n hideAbove: props.hideAbove,\n}))\n\nconst linkComponent = computed(() => (props.as && typeof props.as !== 'string' ? markRaw(props.as) : props.as))\n\nfunction itemTag(item: GrBottomNavItem): string | Component {\n if (item.disabled)\n return 'span'\n if (item.to !== undefined && linkComponent.value)\n return linkComponent.value\n return item.href ? 'a' : 'button'\n}\n\n/**\n * Счётчик рисуется декоративно, а рядом идёт скрытая подпись: голое «3» без\n * единицы измерения диктору ничего не сообщает.\n */\nfunction badgeLabel(item: GrBottomNavItem): string | undefined {\n if (item.badge == null || item.badge === '')\n return undefined\n if (item.badgeLabel)\n return item.badgeLabel\n if (typeof item.badge === 'number') {\n return t('gr.bottomNav.badge', '{count} new', { count: item.badge, n: item.badge })\n }\n return String(item.badge)\n}\n\nfunction select(item: GrBottomNavItem): void {\n if (item.disabled)\n return\n emit('update:modelValue', item.value)\n}\n</script>\n\n<template>\n <nav :class=\"rootClass\" :aria-label=\"resolvedAriaLabel\">\n <div :class=\"grBottomNavListClass(resolvedSize)\">\n <component\n :is=\"itemTag(item)\"\n v-for=\"item in items\"\n :key=\"item.value\"\n data-gr-bottom-nav-item\n :type=\"itemTag(item) === 'button' ? 'button' : undefined\"\n :href=\"itemTag(item) === 'a' ? item.href : undefined\"\n :to=\"item.to !== undefined && linkComponent ? item.to : undefined\"\n :aria-current=\"item.value === modelValue ? 'page' : undefined\"\n :aria-disabled=\"item.disabled ? 'true' : undefined\"\n :aria-label=\"item.ariaLabel\"\n :class=\"grBottomNavItemClass({ active: item.value === modelValue, disabled: item.disabled ?? false, size: resolvedSize })\"\n @click=\"select(item)\"\n >\n <slot\n name=\"item\"\n :item=\"item\"\n :active=\"item.value === modelValue\"\n :disabled=\"item.disabled ?? false\"\n :badge-label=\"badgeLabel(item)\"\n >\n <component :is=\"item.icon\" v-if=\"item.icon && typeof item.icon !== 'string'\" :class=\"grBottomNavIconClass(resolvedSize)\" aria-hidden=\"true\" />\n <span v-else-if=\"item.icon\" :class=\"[item.icon, grBottomNavIconClass(resolvedSize)]\" aria-hidden=\"true\" />\n\n <span :class=\"itemLabelClass\">{{ item.label }}</span>\n\n <template v-if=\"item.badge != null && item.badge !== ''\">\n <span data-gr-bottom-nav-badge :class=\"itemBadgeClass\" aria-hidden=\"true\">{{ item.badge }}</span>\n <span data-gr-bottom-nav-badge-label class=\"sr-only\">{{ badgeLabel(item) }}</span>\n </template>\n </slot>\n </component>\n </div>\n </nav>\n</template>\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"GrBreadcrumbs-DRDNan_n.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 } 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) return undefined\n if (fitAfter.value >= props.items.length) 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) 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) return false\n if (isCurrent(index) && !props.linkCurrent) 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) return\n\n const list = listEl.value\n if (!list) return\n\n const ellipsis = list.querySelector('[data-gr-breadcrumbs-ellipsis-item]')\n if (ellipsis) ellipsisWidth = widthOf(ellipsis)\n\n if (!measured) {\n // Ширины снимаем только с полного пути: спрятанных пунктов в DOM нет.\n if (fitAfter.value !== undefined) return\n\n const wraps = [...list.querySelectorAll('[data-gr-breadcrumbs-item-wrap]')]\n if (wraps.length !== props.items.length) 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) 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') 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') 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) 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</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 } 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) return undefined\n if (fitAfter.value >= props.items.length) 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) 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) return false\n if (isCurrent(index) && !props.linkCurrent) 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) return\n\n const list = listEl.value\n if (!list) return\n\n const ellipsis = list.querySelector('[data-gr-breadcrumbs-ellipsis-item]')\n if (ellipsis) ellipsisWidth = widthOf(ellipsis)\n\n if (!measured) {\n // Ширины снимаем только с полного пути: спрятанных пунктов в DOM нет.\n if (fitAfter.value !== undefined) return\n\n const wraps = [...list.querySelectorAll('[data-gr-breadcrumbs-item-wrap]')]\n if (wraps.length !== props.items.length) 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) 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') 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') 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) 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</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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+EA,MAAM,QAAQ;EAuBd,MAAM,EAAE,MAAM,2BAA2B;EAEzC,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,gBAAgB,CAAC;EACxF,MAAM,oBAAoB,mBAAmB,iBAAiB,mBAAmB,MAAM,WAAW,GAAG;EAErG,MAAM,oBAAoB,eAAe,MAAM,aAAa,EAAE,wBAAwB,YAAY,CAAC;EACnG,MAAM,sBAAsB,eAAe,MAAM,eAAe,EAAE,yBAAyB,kBAAkB,CAAC;EAE9G,MAAM,SAAS,IAAwB,IAAI;EAC3C,MAAM,SAAS,IAAwB,IAAI;EAC3C,MAAM,WAAW,IAAI,KAAK;;;;;;;;EAS1B,MAAM,WAAW,IAAwB,KAAA,CAAS;;EAGlD,IAAI,WAA0D;;;;;;EAM9D,IAAI,gBAAgB;;EAEpB,IAAI,gBAAgB;EAIpB,YAAY,MAAM,aAAa;GAC7B,SAAS,QAAQ;GACjB,WAAW;GACX,gBAAgB;GAChB,SAAS,QAAQ,KAAA;GACjB,SAAc,OAAO;EACvB,CAAC;EAED,MAAM,YAAY,eAAe,MAAM,MAAM,SAAS,CAAC;;;;;EAMvD,MAAM,eAAe,eAAe;GAClC,IAAI,CAAC,MAAM,gBAAgB,SAAS,UAAU,KAAA,GAAW,OAAO,KAAA;GAChE,IAAI,SAAS,SAAS,MAAM,MAAM,QAAQ,OAAO,KAAA;GAEjD,OAAO,MAAM,MAAM,SAAS;EAC9B,CAAC;EAED,MAAM,oBAAoB,eAAe;GACvC,MAAM,SAAS,CAAC,MAAM,UAAU,aAAa,KAAK,CAAC,CAAC,QAAQ,UAA2B,OAAO,UAAU,YAAY,QAAQ,CAAC;GAE7H,OAAO,OAAO,SAAS,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,KAAA;EACnD,CAAC;EAED,MAAM,iBAAiB,eACrB,MAAM,gBAAgB,SAAS,UAAU,KAAA,IAAY,SAAS,QAAQ,MAAM,kBAC7E;EAED,MAAM,UAAU,eAAe,yBAAyB;GACtD,OAAO,MAAM;GACb,UAAU,kBAAkB;GAC5B,qBAAqB,MAAM;GAC3B,oBAAoB,eAAe;GACnC,UAAU,SAAS;EACrB,CAAC,CAAC;EAEF,MAAM,uBAAuB,eAAe,MAAM,gBAAgB,UAAU,KAAK;EAEjF,SAAS,UAAU,OAAwB;GACzC,OAAO,UAAU,qBAAqB;EACxC;;;;;;;;;EAUA,SAAS,cAAc,MAAgC;GACrD,IAAI,CAAC,KAAK,UAAU,OAAO;GAE3B,IAAI,CAAC,KAAK,MAAM;IACd,IAAA,OAAA,YAAA,eAAA,QAAA,IAAA,aAAA,cACE,QAAQ,KACN,0CAA0C,KAAK,MAAM,kHAEvD;IAGF,OAAO;GACT;GAEA,OAAO;EACT;;;;EAKA,SAAS,OAAO,MAAwB,OAAwB;GAC9D,IAAI,KAAK,UAAU,OAAO;GAC1B,IAAI,UAAU,KAAK,KAAK,CAAC,MAAM,aAAa,OAAO;GACnD,OAAO,KAAK,SAAS,KAAA,KAAa,KAAK,OAAO,KAAA;EAChD;EAEA,SAAS,QAAQ,IAAwC;GAGvD,OAAO,KAAM,GAAmB,cAAc;EAChD;;;;;;;EAQA,SAAS,UAAgB;GACvB,IAAI,CAAC,MAAM,cAAc;GAEzB,MAAM,OAAO,OAAO;GACpB,IAAI,CAAC,MAAM;GAEX,MAAM,WAAW,KAAK,cAAc,qCAAqC;GACzE,IAAI,UAAU,gBAAgB,QAAQ,QAAQ;GAE9C,IAAI,CAAC,UAAU;IAEb,IAAI,SAAS,UAAU,KAAA,GAAW;IAElC,MAAM,QAAQ,CAAC,GAAG,KAAK,iBAAiB,iCAAiC,CAAC;IAC1E,IAAI,MAAM,WAAW,MAAM,MAAM,QAAQ;IAEzC,WAAW;KACT,OAAO,MAAM,IAAI,OAAO;KACxB,WAAW,QAAQ,KAAK,cAAc,iCAAiC,CAAC;IAC1E;GACF;GAEA,MAAM,YAAY,KAAK;GAEvB,IAAI,aAAa,GAAG;GAEpB,gBAAgB;GAEhB,SAAS,QAAQ,sBAAsB;IACrC,YAAY,SAAS;IACrB,gBAAgB,SAAS;IACzB;IACA;IACA,qBAAqB,MAAM;IAC3B,UAAU,QAAQ,IAAI;GACxB,CAAC;EACH;;EAGA,SAAS,QAAQ,MAA2B;GAC1C,IAAI,OAAO,qBAAqB,YAAY,OAAO;GAEnD,OAAO,OAAO,WAAW,iBAAiB,IAAI,CAAC,CAAC,SAAS,KAAK;EAChE;;;;;;;EAQA,MAAM,gBAAgB,KAAK,SAAS,OAAO,CAAC;EAE5C,IAAI,WAAkC;EAEtC,YAAY,MAAM,eAAe,YAAY;GAC3C,IAAI,SAAS;IACX,SAAc,OAAO;IACrB;GACF;GAEA,WAAW;GACX,gBAAgB;GAChB,SAAS,QAAQ,KAAA;EACnB,CAAC;EAED,gBAAgB;GACd,SAAc,OAAO;GAGrB,IAAI,OAAO,mBAAmB,aAAa;GAE3C,WAAW,IAAI,qBAAqB;IAKlC,IAAI,SAAS,SAAS,OAAO,SAAS,OAAO,MAAM,gBAAgB,eACjE,SAAS,QAAQ;IAEnB,QAAQ;GACV,CAAC;GACD,IAAI,OAAO,OAAO,SAAS,QAAQ,OAAO,KAAK;EACjD,CAAC;EAED,sBAAsB,UAAU,WAAW,CAAC;EAE5C,eAAe,SAAwB;GACrC,SAAS,QAAQ;GAKjB,MAAM,SAAS;GACf,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,qBAAqB,MAAM,MAAM,MAAM,CAAC;GAElF,CADiB,OAAO,OAAO,iBAA8B,4BAA4B,EAAA,GAC9E,OAAO,EAAE,MAAM;EAC5B;;uBAIE,mBA4FM,OAAA;aA3FA;IAAJ,KAAI;IACJ,uBAAA;IACC,OAAK,eAAA,CAAG,MAAA,oBAAA,GAAsB,MAAA,0BAAA,CAA0B,CAAC,MAAA,YAAA,EAAY,CAAA;IACrE,cAAY,kBAAA;OAEb,mBAqFK,MAAA;aApFC;IAAJ,KAAI;IACJ,4BAAA;IACC,OAAK,eAAA,CAAG,MAAA,oBAAA,GAAsB,QAAA,gBAAY,CAAK,SAAA,QAAW,MAAA,0BAAA,IAA6B,MAAA,wBAAA,CAAwB,CAAA;yBAEhH,mBA+EW,UAAA,MAAA,WA/E2B,QAAA,QAApB,OAAO,aAAQ;4DAAoB,MAAM,SAAI,SAAA,QAAsB,MAAM,UAAK,WAAA,GAAA,CAMtF,WAAQ,KAAA,UAAA,GADhB,mBASK,MAAA;;KAPH,iCAAA;KACC,OAAK,eAAE,MAAA,yBAAA,CAAyB;KACjC,eAAY;QAEZ,WAEO,KAAA,QAAA,aAAA,CAAA,SAAA,CAAA,gBAAA,gBADF,MAAA,iBAAA,CAAiB,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAId,MAAM,SAAI,cAAA,UAAA,GAApB,mBAaK,MAbL,YAaK,CAZH,WAWO,KAAA,QAAA,YAAA;KAXgB,aAAc,MAAM;KAAsB;aAW1D,CAVL,mBASS,UAAA;KARP,MAAK;KACL,gCAAA;KACA,eAAY;KACX,OAAK,eAAE,MAAA,wBAAA,CAAwB;KAC/B,cAAY,oBAAA;KACZ,SAAO;OACT,OAED,IAAA,UAAA,CAAA,CAAA,CAAA,CAAA,MAAA,UAAA,GAIJ,mBA+CK,MAAA;;KA/CM,iCAAA;KAA+B,OAAK,eAAE,MAAA,wBAAA,CAAwB;QAE/D,OAAO,MAAM,MAAM,MAAM,KAAK,KAAA,UAAA,GADtC,YAqBS,gBAAA;KAnBN,KAAG,QAAU,MAAM;KACpB,4BAAA;KACC,IAAI,QAAA;KACJ,MAAM,MAAM,KAAK;KACjB,IAAI,MAAM,KAAK;KACf,MAAM,MAAA,YAAA;KACN,SAAS,UAAU,MAAM,KAAK,IAAA,YAAA;KAC9B,cAAY,MAAM,KAAK;KACvB,gBAAc,UAAU,MAAM,KAAK,IAAA,SAAa,KAAA;;4BAU1C,CARP,WAQO,KAAA,QAAA,QAAA;MARY,MAAM,MAAM;MAAO,OAAO,MAAM;MAAQ,WAAY,UAAU,MAAM,KAAK;cAQrF,CALG,MAAM,KAAK,QAAA,UAAA,GAFnB,YAKE,wBAJK,MAAA,OAAA,CAAO,CAAC,MAAM,KAAK,IAAI,CAAA,GAAA;;MAE3B,OAAK,eAAA,CAAG,MAAA,wBAAA,GAA0B,MAAA,SAAA,CAAS,CAAC,MAAM,KAAK,IAAI,CAAA,CAAA;MAC5D,eAAY;6DAEd,mBAAsE,QAAA,EAA/D,OAAK,eAAE,cAAc,MAAM,IAAI,CAAA,EAAA,GAAA,gBAAM,MAAM,KAAK,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;wBAQhE,mBAkBO,QAAA;;KAhBL,4BAAA;KACC,OAAK,eAAE,MAAA,uBAAA,CAAuB;KAC9B,cAAY,MAAM,KAAK;KACvB,gBAAc,UAAU,MAAM,KAAK,IAAA,SAAa,KAAA;KAChD,iBAAe,MAAM,KAAK,WAAQ,SAAY,KAAA;KAC/C,UAAS;QAET,WAQO,KAAA,QAAA,QAAA;KARY,MAAM,MAAM;KAAO,OAAO,MAAM;KAAQ,WAAY,UAAU,MAAM,KAAK;aAQrF,CALG,MAAM,KAAK,QAAA,UAAA,GAFnB,YAKE,wBAJK,MAAA,OAAA,CAAO,CAAC,MAAM,KAAK,IAAI,CAAA,GAAA;;KAE3B,OAAK,eAAA,CAAG,MAAA,wBAAA,GAA0B,MAAA,SAAA,CAAS,CAAC,MAAM,KAAK,IAAI,CAAA,CAAA;KAC5D,eAAY;4DAEd,mBAAsE,QAAA,EAA/D,OAAK,eAAE,cAAc,MAAM,IAAI,CAAA,EAAA,GAAA,gBAAM,MAAM,KAAK,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,IAAA,UAAA,EAAA,GAAA,CAAA,EAAA,GAAA,EAAA"}
1
+ {"version":3,"file":"GrBreadcrumbs-DRDNan_n.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 } 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</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 } 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</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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+EA,MAAM,QAAQ;EAuBd,MAAM,EAAE,MAAM,2BAA2B;EAEzC,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,gBAAgB,CAAC;EACxF,MAAM,oBAAoB,mBAAmB,iBAAiB,mBAAmB,MAAM,WAAW,GAAG;EAErG,MAAM,oBAAoB,eAAe,MAAM,aAAa,EAAE,wBAAwB,YAAY,CAAC;EACnG,MAAM,sBAAsB,eAAe,MAAM,eAAe,EAAE,yBAAyB,kBAAkB,CAAC;EAE9G,MAAM,SAAS,IAAwB,IAAI;EAC3C,MAAM,SAAS,IAAwB,IAAI;EAC3C,MAAM,WAAW,IAAI,KAAK;;;;;;;;EAS1B,MAAM,WAAW,IAAwB,KAAA,CAAS;;EAGlD,IAAI,WAA0D;;;;;;EAM9D,IAAI,gBAAgB;;EAEpB,IAAI,gBAAgB;EAIpB,YAAY,MAAM,aAAa;GAC7B,SAAS,QAAQ;GACjB,WAAW;GACX,gBAAgB;GAChB,SAAS,QAAQ,KAAA;GACjB,SAAc,OAAO;EACvB,CAAC;EAED,MAAM,YAAY,eAAe,MAAM,MAAM,SAAS,CAAC;;;;;EAMvD,MAAM,eAAe,eAAe;GAClC,IAAI,CAAC,MAAM,gBAAgB,SAAS,UAAU,KAAA,GAC5C,OAAO,KAAA;GACT,IAAI,SAAS,SAAS,MAAM,MAAM,QAChC,OAAO,KAAA;GAET,OAAO,MAAM,MAAM,SAAS;EAC9B,CAAC;EAED,MAAM,oBAAoB,eAAe;GACvC,MAAM,SAAS,CAAC,MAAM,UAAU,aAAa,KAAK,CAAC,CAAC,QAAQ,UAA2B,OAAO,UAAU,YAAY,QAAQ,CAAC;GAE7H,OAAO,OAAO,SAAS,IAAI,KAAK,IAAI,GAAG,MAAM,IAAI,KAAA;EACnD,CAAC;EAED,MAAM,iBAAiB,eACrB,MAAM,gBAAgB,SAAS,UAAU,KAAA,IAAY,SAAS,QAAQ,MAAM,kBAC7E;EAED,MAAM,UAAU,eAAe,yBAAyB;GACtD,OAAO,MAAM;GACb,UAAU,kBAAkB;GAC5B,qBAAqB,MAAM;GAC3B,oBAAoB,eAAe;GACnC,UAAU,SAAS;EACrB,CAAC,CAAC;EAEF,MAAM,uBAAuB,eAAe,MAAM,gBAAgB,UAAU,KAAK;EAEjF,SAAS,UAAU,OAAwB;GACzC,OAAO,UAAU,qBAAqB;EACxC;;;;;;;;;EAUA,SAAS,cAAc,MAAgC;GACrD,IAAI,CAAC,KAAK,UACR,OAAO;GAET,IAAI,CAAC,KAAK,MAAM;IACd,IAAA,OAAA,YAAA,eAAA,QAAA,IAAA,aAAA,cACE,QAAQ,KACN,0CAA0C,KAAK,MAAM,kHAEvD;IAGF,OAAO;GACT;GAEA,OAAO;EACT;;;;EAKA,SAAS,OAAO,MAAwB,OAAwB;GAC9D,IAAI,KAAK,UACP,OAAO;GACT,IAAI,UAAU,KAAK,KAAK,CAAC,MAAM,aAC7B,OAAO;GACT,OAAO,KAAK,SAAS,KAAA,KAAa,KAAK,OAAO,KAAA;EAChD;EAEA,SAAS,QAAQ,IAAwC;GAGvD,OAAO,KAAM,GAAmB,cAAc;EAChD;;;;;;;EAQA,SAAS,UAAgB;GACvB,IAAI,CAAC,MAAM,cACT;GAEF,MAAM,OAAO,OAAO;GACpB,IAAI,CAAC,MACH;GAEF,MAAM,WAAW,KAAK,cAAc,qCAAqC;GACzE,IAAI,UACF,gBAAgB,QAAQ,QAAQ;GAElC,IAAI,CAAC,UAAU;IAEb,IAAI,SAAS,UAAU,KAAA,GACrB;IAEF,MAAM,QAAQ,CAAC,GAAG,KAAK,iBAAiB,iCAAiC,CAAC;IAC1E,IAAI,MAAM,WAAW,MAAM,MAAM,QAC/B;IAEF,WAAW;KACT,OAAO,MAAM,IAAI,OAAO;KACxB,WAAW,QAAQ,KAAK,cAAc,iCAAiC,CAAC;IAC1E;GACF;GAEA,MAAM,YAAY,KAAK;GAEvB,IAAI,aAAa,GACf;GAEF,gBAAgB;GAEhB,SAAS,QAAQ,sBAAsB;IACrC,YAAY,SAAS;IACrB,gBAAgB,SAAS;IACzB;IACA;IACA,qBAAqB,MAAM;IAC3B,UAAU,QAAQ,IAAI;GACxB,CAAC;EACH;;EAGA,SAAS,QAAQ,MAA2B;GAC1C,IAAI,OAAO,qBAAqB,YAC9B,OAAO;GAET,OAAO,OAAO,WAAW,iBAAiB,IAAI,CAAC,CAAC,SAAS,KAAK;EAChE;;;;;;;EAQA,MAAM,gBAAgB,KAAK,SAAS,OAAO,CAAC;EAE5C,IAAI,WAAkC;EAEtC,YAAY,MAAM,eAAe,YAAY;GAC3C,IAAI,SAAS;IACX,SAAc,OAAO;IACrB;GACF;GAEA,WAAW;GACX,gBAAgB;GAChB,SAAS,QAAQ,KAAA;EACnB,CAAC;EAED,gBAAgB;GACd,SAAc,OAAO;GAGrB,IAAI,OAAO,mBAAmB,aAC5B;GAEF,WAAW,IAAI,qBAAqB;IAKlC,IAAI,SAAS,SAAS,OAAO,SAAS,OAAO,MAAM,gBAAgB,eACjE,SAAS,QAAQ;IAEnB,QAAQ;GACV,CAAC;GACD,IAAI,OAAO,OACT,SAAS,QAAQ,OAAO,KAAK;EACjC,CAAC;EAED,sBAAsB,UAAU,WAAW,CAAC;EAE5C,eAAe,SAAwB;GACrC,SAAS,QAAQ;GAKjB,MAAM,SAAS;GACf,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,qBAAqB,MAAM,MAAM,MAAM,CAAC;GAElF,CADiB,OAAO,OAAO,iBAA8B,4BAA4B,EAAA,GAC9E,OAAO,EAAE,MAAM;EAC5B;;uBAIE,mBA4FM,OAAA;aA3FA;IAAJ,KAAI;IACJ,uBAAA;IACC,OAAK,eAAA,CAAG,MAAA,oBAAA,GAAsB,MAAA,0BAAA,CAA0B,CAAC,MAAA,YAAA,EAAY,CAAA;IACrE,cAAY,kBAAA;OAEb,mBAqFK,MAAA;aApFC;IAAJ,KAAI;IACJ,4BAAA;IACC,OAAK,eAAA,CAAG,MAAA,oBAAA,GAAsB,QAAA,gBAAY,CAAK,SAAA,QAAW,MAAA,0BAAA,IAA6B,MAAA,wBAAA,CAAwB,CAAA;yBAEhH,mBA+EW,UAAA,MAAA,WA/E2B,QAAA,QAApB,OAAO,aAAQ;4DAAoB,MAAM,SAAI,SAAA,QAAsB,MAAM,UAAK,WAAA,GAAA,CAMtF,WAAQ,KAAA,UAAA,GADhB,mBASK,MAAA;;KAPH,iCAAA;KACC,OAAK,eAAE,MAAA,yBAAA,CAAyB;KACjC,eAAY;QAEZ,WAEO,KAAA,QAAA,aAAA,CAAA,SAAA,CAAA,gBAAA,gBADF,MAAA,iBAAA,CAAiB,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAId,MAAM,SAAI,cAAA,UAAA,GAApB,mBAaK,MAbL,YAaK,CAZH,WAWO,KAAA,QAAA,YAAA;KAXgB,aAAc,MAAM;KAAsB;aAW1D,CAVL,mBASS,UAAA;KARP,MAAK;KACL,gCAAA;KACA,eAAY;KACX,OAAK,eAAE,MAAA,wBAAA,CAAwB;KAC/B,cAAY,oBAAA;KACZ,SAAO;OACT,OAED,IAAA,UAAA,CAAA,CAAA,CAAA,CAAA,MAAA,UAAA,GAIJ,mBA+CK,MAAA;;KA/CM,iCAAA;KAA+B,OAAK,eAAE,MAAA,wBAAA,CAAwB;QAE/D,OAAO,MAAM,MAAM,MAAM,KAAK,KAAA,UAAA,GADtC,YAqBS,gBAAA;KAnBN,KAAG,QAAU,MAAM;KACpB,4BAAA;KACC,IAAI,QAAA;KACJ,MAAM,MAAM,KAAK;KACjB,IAAI,MAAM,KAAK;KACf,MAAM,MAAA,YAAA;KACN,SAAS,UAAU,MAAM,KAAK,IAAA,YAAA;KAC9B,cAAY,MAAM,KAAK;KACvB,gBAAc,UAAU,MAAM,KAAK,IAAA,SAAa,KAAA;;4BAU1C,CARP,WAQO,KAAA,QAAA,QAAA;MARY,MAAM,MAAM;MAAO,OAAO,MAAM;MAAQ,WAAY,UAAU,MAAM,KAAK;cAQrF,CALG,MAAM,KAAK,QAAA,UAAA,GAFnB,YAKE,wBAJK,MAAA,OAAA,CAAO,CAAC,MAAM,KAAK,IAAI,CAAA,GAAA;;MAE3B,OAAK,eAAA,CAAG,MAAA,wBAAA,GAA0B,MAAA,SAAA,CAAS,CAAC,MAAM,KAAK,IAAI,CAAA,CAAA;MAC5D,eAAY;6DAEd,mBAAsE,QAAA,EAA/D,OAAK,eAAE,cAAc,MAAM,IAAI,CAAA,EAAA,GAAA,gBAAM,MAAM,KAAK,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;wBAQhE,mBAkBO,QAAA;;KAhBL,4BAAA;KACC,OAAK,eAAE,MAAA,uBAAA,CAAuB;KAC9B,cAAY,MAAM,KAAK;KACvB,gBAAc,UAAU,MAAM,KAAK,IAAA,SAAa,KAAA;KAChD,iBAAe,MAAM,KAAK,WAAQ,SAAY,KAAA;KAC/C,UAAS;QAET,WAQO,KAAA,QAAA,QAAA;KARY,MAAM,MAAM;KAAO,OAAO,MAAM;KAAQ,WAAY,UAAU,MAAM,KAAK;aAQrF,CALG,MAAM,KAAK,QAAA,UAAA,GAFnB,YAKE,wBAJK,MAAA,OAAA,CAAO,CAAC,MAAM,KAAK,IAAI,CAAA,GAAA;;KAE3B,OAAK,eAAA,CAAG,MAAA,wBAAA,GAA0B,MAAA,SAAA,CAAS,CAAC,MAAM,KAAK,IAAI,CAAA,CAAA;KAC5D,eAAY;4DAEd,mBAAsE,QAAA,EAA/D,OAAK,eAAE,cAAc,MAAM,IAAI,CAAA,EAAA,GAAA,gBAAM,MAAM,KAAK,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,IAAA,UAAA,EAAA,GAAA,CAAA,EAAA,GAAA,EAAA"}
@@ -2,7 +2,7 @@ import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunk
2
2
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
3
  import { t as loader_circle_default } from "../../../chunks/loader-circle-CfVLz7lb.js";
4
4
  import { n as useGrButtonGroup } from "../../../chunks/context-BfIQv7m1.js";
5
- import { a as grButtonClass, i as grButtonBaseClass } from "../../../chunks/grButtonStyles-B_-YRE__.js";
5
+ import { a as grButtonClass, i as grButtonBaseClass } from "../../../chunks/grButtonStyles-B3wRWW_i.js";
6
6
  import { computed, createBlock, createCommentVNode, createElementBlock, defineComponent, markRaw, normalizeClass, openBlock, ref, renderSlot, resolveDynamicComponent, toDisplayString, unref, withCtx } from "vue";
7
7
  //#region src/components/GrButton/GrButton.vue?vue&type=script&setup=true&lang.ts
8
8
  var _hoisted_1 = {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrButton-7GP0zObj.js","names":[],"sources":["../../../../src/components/GrButton/GrButton.vue","../../../../src/components/GrButton/GrButton.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, markRaw, ref, type Component } from 'vue'\n\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrButtonGroup } from '../GrButtonGroup/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n\nexport type { GrButtonSize, GrButtonTone, GrButtonVariant } from './grButtonStyles'\n\nimport {\n grButtonBaseClass,\n grButtonClass,\n type GrButtonSize,\n type GrButtonTone,\n type GrButtonVariant,\n} from './grButtonStyles'\n\nexport interface GrButtonProps {\n variant?: GrButtonVariant\n tone?: GrButtonTone\n size?: GrButtonSize\n loading?: boolean\n /** i18n: что именно грузится. `aria-busy` сам по себе часть AT не объявляет. */\n loadingText?: string\n disabled?: boolean\n square?: boolean\n /** Кнопка на всю ширину контейнера. */\n block?: boolean\n type?: 'button' | 'submit' | 'reset'\n ariaLabel?: string\n /** Полиморфизм: кастомный корневой тег/компонент (например, RouterLink). */\n as?: string | Component\n /** Рендерит кнопку как `<a href>` (если не задан `as`). */\n href?: string\n target?: string\n rel?: string\n external?: boolean\n}\n\nconst props = withDefaults(\n defineProps<GrButtonProps>(),\n {\n // `variant`/`tone`/`size`/`square` настраиваются через `GrConfigProvider`,\n // поэтому их дефолты живут в резолверах ниже, а не здесь: Vue подставил бы\n // дефолт до того, как компонент успеет заглянуть в конфиг.\n variant: undefined,\n tone: undefined,\n size: undefined,\n loading: false,\n loadingText: undefined,\n disabled: false,\n square: undefined,\n block: false,\n type: 'button',\n ariaLabel: undefined,\n as: undefined,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n },\n)\n\n// Эффективные значения: проп кнопки → группа → `GrConfigProvider` → дефолт.\n// Группа ближе к кнопке, чем глобальный провайдер, поэтому она подставляется\n// как «локальное» значение — и побеждает конфиг, но не собственный проп.\nconst group = useGrButtonGroup()\n\nconst resolvedSize = useGrComponentSize(() => props.size ?? group?.size.value, { component: 'GrButton' })\nconst resolvedVariant = useGrComponentProp('GrButton', 'variant', () => props.variant ?? group?.variant.value, 'primary')\nconst resolvedTone = useGrComponentProp('GrButton', 'tone', () => props.tone ?? group?.tone.value, 'primary')\nconst isSquare = useGrComponentProp('GrButton', 'square', () => props.square, false)\n\nconst { t } = useGranularityTranslations()\nconst resolvedLoadingText = computed(() => props.loadingText ?? t('gr.button.loading', 'Loading…'))\n\n// Полиморфный корень: `as` → `<a href>` → `<button>`.\nconst isLink = computed(() => Boolean(props.as || props.href))\nconst renderAs = computed<string | Component>(() => {\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n return props.href ? 'a' : 'button'\n})\n\n// Неинтерактивно при явном `disabled` ИЛИ во время `loading`.\nconst blocked = computed(() => props.disabled || props.loading)\n\n// Ключевое: `loading` НЕ ставит нативный `disabled` (элемент бы выпал из фокуса и\n// скринридер потерял бы контекст) — вместо этого `aria-disabled` + перехват клика.\n// Нативный `disabled` (только у `<button>`) оставляем лишь для явного `disabled`.\nconst nativeDisabled = computed(() => (renderAs.value === 'button' && props.disabled) ? true : undefined)\nconst ariaDisabled = computed(() => (props.loading || (isLink.value && props.disabled)) ? 'true' : undefined)\n\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() => props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined))\n\nfunction onClickCapture(e: MouseEvent): void {\n // Блокируем и дефолт (submit/навигация), и внешние обработчики (в т.ч. по Enter/Space),\n // сохраняя фокус на элементе.\n if (blocked.value) {\n e.preventDefault()\n e.stopImmediatePropagation()\n }\n}\n\n// Корень динамический (`as` принимает и тег, и компонент), поэтому ref может\n// оказаться как элементом, так и инстансом — например роутерной ссылкой.\nconst rootEl = ref<HTMLElement | { $el?: HTMLElement } | null>(null)\n\n/**\n * Фокус на кнопку из кода. Нужен там, где окно обязано открываться с фокусом\n * на конкретном действии (`GrConfirmDialog`), и потребителю не должно быть\n * важно, тегом или компонентом отрисован корень.\n */\nfunction focus(): void {\n const root = rootEl.value\n const el = root instanceof HTMLElement ? root : root?.$el\n el?.focus?.()\n}\n\nfunction blur(): void {\n const root = rootEl.value\n const el = root instanceof HTMLElement ? root : root?.$el\n el?.blur?.()\n}\n\ndefineExpose({ focus, blur })\n\nconst className = computed(() => {\n return grButtonClass({\n variant: resolvedVariant.value,\n tone: resolvedTone.value,\n size: resolvedSize.value,\n square: isSquare.value,\n disabled: props.disabled,\n block: props.block,\n })\n})\n\ndefineSlots<{\n /** Содержимое кнопки. */\n default?: () => any\n /** Аддон слева: иконка, счётчик. В состоянии загрузки уступает место спиннеру. */\n prefix?: () => any\n /** Аддон справа: шеврон, счётчик. */\n suffix?: () => any\n}>()\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n ref=\"rootEl\"\n data-gr-button\n :data-gr-variant=\"resolvedVariant\"\n :data-gr-tone=\"resolvedTone\"\n :type=\"renderAs === 'button' ? props.type : undefined\"\n :disabled=\"nativeDisabled\"\n :href=\"isLink && !props.disabled ? props.href : undefined\"\n :target=\"isLink && !props.disabled ? resolvedTarget : undefined\"\n :rel=\"isLink && !props.disabled ? resolvedRel : undefined\"\n :aria-busy=\"props.loading ? 'true' : undefined\"\n :aria-disabled=\"ariaDisabled\"\n :aria-label=\"props.ariaLabel\"\n :tabindex=\"isLink && props.disabled ? -1 : undefined\"\n :class=\"[grButtonBaseClass, className, blocked ? 'cursor-not-allowed' : '']\"\n @click.capture=\"onClickCapture\"\n >\n <!-- Спиннер занимает место префикса: две иконки рядом читались бы как ошибка. -->\n <IconLoader v-if=\"props.loading\" class=\"h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n <slot v-else name=\"prefix\" />\n\n <slot />\n\n <slot name=\"suffix\" />\n\n <span v-if=\"props.loading\" class=\"sr-only\">{{ resolvedLoadingText }}</span>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, ref, type Component } from 'vue'\n\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrButtonGroup } from '../GrButtonGroup/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n\nexport type { GrButtonSize, GrButtonTone, GrButtonVariant } from './grButtonStyles'\n\nimport {\n grButtonBaseClass,\n grButtonClass,\n type GrButtonSize,\n type GrButtonTone,\n type GrButtonVariant,\n} from './grButtonStyles'\n\nexport interface GrButtonProps {\n variant?: GrButtonVariant\n tone?: GrButtonTone\n size?: GrButtonSize\n loading?: boolean\n /** i18n: что именно грузится. `aria-busy` сам по себе часть AT не объявляет. */\n loadingText?: string\n disabled?: boolean\n square?: boolean\n /** Кнопка на всю ширину контейнера. */\n block?: boolean\n type?: 'button' | 'submit' | 'reset'\n ariaLabel?: string\n /** Полиморфизм: кастомный корневой тег/компонент (например, RouterLink). */\n as?: string | Component\n /** Рендерит кнопку как `<a href>` (если не задан `as`). */\n href?: string\n target?: string\n rel?: string\n external?: boolean\n}\n\nconst props = withDefaults(\n defineProps<GrButtonProps>(),\n {\n // `variant`/`tone`/`size`/`square` настраиваются через `GrConfigProvider`,\n // поэтому их дефолты живут в резолверах ниже, а не здесь: Vue подставил бы\n // дефолт до того, как компонент успеет заглянуть в конфиг.\n variant: undefined,\n tone: undefined,\n size: undefined,\n loading: false,\n loadingText: undefined,\n disabled: false,\n square: undefined,\n block: false,\n type: 'button',\n ariaLabel: undefined,\n as: undefined,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n },\n)\n\n// Эффективные значения: проп кнопки → группа → `GrConfigProvider` → дефолт.\n// Группа ближе к кнопке, чем глобальный провайдер, поэтому она подставляется\n// как «локальное» значение — и побеждает конфиг, но не собственный проп.\nconst group = useGrButtonGroup()\n\nconst resolvedSize = useGrComponentSize(() => props.size ?? group?.size.value, { component: 'GrButton' })\nconst resolvedVariant = useGrComponentProp('GrButton', 'variant', () => props.variant ?? group?.variant.value, 'primary')\nconst resolvedTone = useGrComponentProp('GrButton', 'tone', () => props.tone ?? group?.tone.value, 'primary')\nconst isSquare = useGrComponentProp('GrButton', 'square', () => props.square, false)\n\nconst { t } = useGranularityTranslations()\nconst resolvedLoadingText = computed(() => props.loadingText ?? t('gr.button.loading', 'Loading…'))\n\n// Полиморфный корень: `as` → `<a href>` → `<button>`.\nconst isLink = computed(() => Boolean(props.as || props.href))\nconst renderAs = computed<string | Component>(() => {\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n return props.href ? 'a' : 'button'\n})\n\n// Неинтерактивно при явном `disabled` ИЛИ во время `loading`.\nconst blocked = computed(() => props.disabled || props.loading)\n\n// Ключевое: `loading` НЕ ставит нативный `disabled` (элемент бы выпал из фокуса и\n// скринридер потерял бы контекст) — вместо этого `aria-disabled` + перехват клика.\n// Нативный `disabled` (только у `<button>`) оставляем лишь для явного `disabled`.\nconst nativeDisabled = computed(() => (renderAs.value === 'button' && props.disabled) ? true : undefined)\nconst ariaDisabled = computed(() => (props.loading || (isLink.value && props.disabled)) ? 'true' : undefined)\n\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() => props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined))\n\nfunction onClickCapture(e: MouseEvent): void {\n // Блокируем и дефолт (submit/навигация), и внешние обработчики (в т.ч. по Enter/Space),\n // сохраняя фокус на элементе.\n if (blocked.value) {\n e.preventDefault()\n e.stopImmediatePropagation()\n }\n}\n\n// Корень динамический (`as` принимает и тег, и компонент), поэтому ref может\n// оказаться как элементом, так и инстансом — например роутерной ссылкой.\nconst rootEl = ref<HTMLElement | { $el?: HTMLElement } | null>(null)\n\n/**\n * Фокус на кнопку из кода. Нужен там, где окно обязано открываться с фокусом\n * на конкретном действии (`GrConfirmDialog`), и потребителю не должно быть\n * важно, тегом или компонентом отрисован корень.\n */\nfunction focus(): void {\n const root = rootEl.value\n const el = root instanceof HTMLElement ? root : root?.$el\n el?.focus?.()\n}\n\nfunction blur(): void {\n const root = rootEl.value\n const el = root instanceof HTMLElement ? root : root?.$el\n el?.blur?.()\n}\n\ndefineExpose({ focus, blur })\n\nconst className = computed(() => {\n return grButtonClass({\n variant: resolvedVariant.value,\n tone: resolvedTone.value,\n size: resolvedSize.value,\n square: isSquare.value,\n disabled: props.disabled,\n block: props.block,\n })\n})\n\ndefineSlots<{\n /** Содержимое кнопки. */\n default?: () => any\n /** Аддон слева: иконка, счётчик. В состоянии загрузки уступает место спиннеру. */\n prefix?: () => any\n /** Аддон справа: шеврон, счётчик. */\n suffix?: () => any\n}>()\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n ref=\"rootEl\"\n data-gr-button\n :data-gr-variant=\"resolvedVariant\"\n :data-gr-tone=\"resolvedTone\"\n :type=\"renderAs === 'button' ? props.type : undefined\"\n :disabled=\"nativeDisabled\"\n :href=\"isLink && !props.disabled ? props.href : undefined\"\n :target=\"isLink && !props.disabled ? resolvedTarget : undefined\"\n :rel=\"isLink && !props.disabled ? resolvedRel : undefined\"\n :aria-busy=\"props.loading ? 'true' : undefined\"\n :aria-disabled=\"ariaDisabled\"\n :aria-label=\"props.ariaLabel\"\n :tabindex=\"isLink && props.disabled ? -1 : undefined\"\n :class=\"[grButtonBaseClass, className, blocked ? 'cursor-not-allowed' : '']\"\n @click.capture=\"onClickCapture\"\n >\n <!-- Спиннер занимает место префикса: две иконки рядом читались бы как ошибка. -->\n <IconLoader v-if=\"props.loading\" class=\"h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n <slot v-else name=\"prefix\" />\n\n <slot />\n\n <slot name=\"suffix\" />\n\n <span v-if=\"props.loading\" class=\"sr-only\">{{ resolvedLoadingText }}</span>\n </component>\n</template>\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { t as GrButton_default } from "./chunks/GrButton-Bw2AH4uX.js";
2
- import { t as grButtonSafelist } from "../../chunks/safelist-BOq5Li7p.js";
3
- import { t as grButtonConfig } from "../../chunks/config-BHcS5Cwm.js";
1
+ import { t as GrButton_default } from "./chunks/GrButton-7GP0zObj.js";
2
+ import { t as grButtonSafelist } from "../../chunks/safelist-DxkMj5IW.js";
3
+ import { t as grButtonConfig } from "../../chunks/config-87fszqnD.js";
4
4
  export { GrButton_default as GrButton, GrButton_default as default, grButtonConfig, grButtonSafelist };
@@ -1 +1 @@
1
- {"version":3,"file":"GrButtonGroup-CKyiAV8K.js","names":[],"sources":["../../../../src/components/GrButtonGroup/GrButtonGroup.vue","../../../../src/components/GrButtonGroup/GrButtonGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton/grButtonStyles'\nimport { provideGrButtonGroup } from './context'\n\nexport type GrButtonGroupOrientation = 'horizontal' | 'vertical'\n\nexport interface GrButtonGroupProps {\n /** Доступное имя группы: без него кнопки читаются как несвязанные. */\n ariaLabel?: string\n orientation?: GrButtonGroupOrientation\n /**\n * Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая\n * кнопка сохраняет свои радиусы и границы.\n */\n attached?: boolean\n /** Оформление, общее для кнопок группы. Проп самой кнопки сильнее. */\n size?: GrButtonSize\n variant?: GrButtonVariant\n tone?: GrButtonTone\n}\n\nconst props = withDefaults(defineProps<GrButtonGroupProps>(), {\n ariaLabel: undefined,\n orientation: 'horizontal',\n attached: true,\n size: undefined,\n variant: undefined,\n tone: undefined,\n})\n\nprovideGrButtonGroup({\n size: computed(() => props.size),\n variant: computed(() => props.variant),\n tone: computed(() => props.tone),\n})\n\ndefineSlots<{\n /** Кнопки группы. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-button-group\n class=\"inline-flex\"\n :class=\"[\n orientation === 'vertical' ? 'flex-col items-stretch' : 'items-stretch',\n attached ? '' : 'gap-2',\n ]\"\n :data-orientation=\"orientation\"\n :data-attached=\"attached ? '' : undefined\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n >\n <slot />\n </div>\n</template>\n\n<style>\n/*\n * Склейка держится на понятии «звено группы» — прямом потомке, который сам\n * кнопка или содержит кнопку. Обёртка (тултип, `<span v-if>`, роутерная\n * ссылка) поэтому не разрывает ряд, а не-кнопочный потомок (разделитель,\n * подпись) в склейку не попадает и скругление себе не забирает.\n *\n * Края считаются от соседства звеньев, а не от `:first-child`/`:last-child`:\n * ведущий край гасится у звена, перед которым уже было звено, ведомый — у\n * звена, за которым звено ещё будет.\n */\n[data-gr-button-group] {\n --gr-button-group-radius: var(--gr-button-radius, 0.375rem);\n}\n\n[data-gr-button-group][data-attached] [data-gr-button] {\n border-radius: var(--gr-button-group-radius);\n position: relative;\n}\n\n/* Кнопка под курсором или с фокусом — поверх соседей: иначе её граница и\n фокус-кольцо срезаются наложением. */\n[data-gr-button-group] [data-gr-button]:hover,\n[data-gr-button-group] [data-gr-button]:focus-visible {\n z-index: 1;\n}\n\n/* ————— Горизонтальная группа. */\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-inline-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n}\n\n/* ————— Вертикальная группа: та же логика, другая ось. */\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-block-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-start-end-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-end-start-radius: 0;\n border-end-end-radius: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton/grButtonStyles'\nimport { provideGrButtonGroup } from './context'\n\nexport type GrButtonGroupOrientation = 'horizontal' | 'vertical'\n\nexport interface GrButtonGroupProps {\n /** Доступное имя группы: без него кнопки читаются как несвязанные. */\n ariaLabel?: string\n orientation?: GrButtonGroupOrientation\n /**\n * Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая\n * кнопка сохраняет свои радиусы и границы.\n */\n attached?: boolean\n /** Оформление, общее для кнопок группы. Проп самой кнопки сильнее. */\n size?: GrButtonSize\n variant?: GrButtonVariant\n tone?: GrButtonTone\n}\n\nconst props = withDefaults(defineProps<GrButtonGroupProps>(), {\n ariaLabel: undefined,\n orientation: 'horizontal',\n attached: true,\n size: undefined,\n variant: undefined,\n tone: undefined,\n})\n\nprovideGrButtonGroup({\n size: computed(() => props.size),\n variant: computed(() => props.variant),\n tone: computed(() => props.tone),\n})\n\ndefineSlots<{\n /** Кнопки группы. */\n default?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-button-group\n class=\"inline-flex\"\n :class=\"[\n orientation === 'vertical' ? 'flex-col items-stretch' : 'items-stretch',\n attached ? '' : 'gap-2',\n ]\"\n :data-orientation=\"orientation\"\n :data-attached=\"attached ? '' : undefined\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n >\n <slot />\n </div>\n</template>\n\n<style>\n/*\n * Склейка держится на понятии «звено группы» — прямом потомке, который сам\n * кнопка или содержит кнопку. Обёртка (тултип, `<span v-if>`, роутерная\n * ссылка) поэтому не разрывает ряд, а не-кнопочный потомок (разделитель,\n * подпись) в склейку не попадает и скругление себе не забирает.\n *\n * Края считаются от соседства звеньев, а не от `:first-child`/`:last-child`:\n * ведущий край гасится у звена, перед которым уже было звено, ведомый — у\n * звена, за которым звено ещё будет.\n */\n[data-gr-button-group] {\n --gr-button-group-radius: var(--gr-button-radius, 0.375rem);\n}\n\n[data-gr-button-group][data-attached] [data-gr-button] {\n border-radius: var(--gr-button-group-radius);\n position: relative;\n}\n\n/* Кнопка под курсором или с фокусом — поверх соседей: иначе её граница и\n фокус-кольцо срезаются наложением. */\n[data-gr-button-group] [data-gr-button]:hover,\n[data-gr-button-group] [data-gr-button]:focus-visible {\n z-index: 1;\n}\n\n/* ————— Горизонтальная группа. */\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-inline-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n}\n\n/* ————— Вертикальная группа: та же логика, другая ось. */\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-block-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-start-end-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-end-start-radius: 0;\n border-end-end-radius: 0;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;EAuBA,MAAM,QAAQ;EASd,qBAAqB;GACnB,MAAM,eAAe,MAAM,IAAI;GAC/B,SAAS,eAAe,MAAM,OAAO;GACrC,MAAM,eAAe,MAAM,IAAI;EACjC,CAAC;;uBAUC,mBAaM,OAAA;IAZJ,wBAAA;IACA,OAAK,eAAA,CAAC,eAAa,CACH,QAAA,gBAAW,aAAA,2BAAA,iBAAoE,QAAA,WAAQ,KAAA,OAAA,CAAA,CAAA;IAItG,oBAAkB,QAAA;IAClB,iBAAe,QAAA,WAAQ,KAAQ,KAAA;IAChC,MAAK;IACJ,cAAY,QAAA;OAEb,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA"}
1
+ {"version":3,"file":"GrButtonGroup-CKyiAV8K.js","names":[],"sources":["../../../../src/components/GrButtonGroup/GrButtonGroup.vue","../../../../src/components/GrButtonGroup/GrButtonGroup.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton/grButtonStyles'\nimport { provideGrButtonGroup } from './context'\n\nexport type GrButtonGroupOrientation = 'horizontal' | 'vertical'\n\nexport interface GrButtonGroupProps {\n /** Доступное имя группы: без него кнопки читаются как несвязанные. */\n ariaLabel?: string\n orientation?: GrButtonGroupOrientation\n /**\n * Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая\n * кнопка сохраняет свои радиусы и границы.\n */\n attached?: boolean\n /** Оформление, общее для кнопок группы. Проп самой кнопки сильнее. */\n size?: GrButtonSize\n variant?: GrButtonVariant\n tone?: GrButtonTone\n}\n\nconst props = withDefaults(defineProps<GrButtonGroupProps>(), {\n ariaLabel: undefined,\n orientation: 'horizontal',\n attached: true,\n size: undefined,\n variant: undefined,\n tone: undefined,\n})\n\nprovideGrButtonGroup({\n size: computed(() => props.size),\n variant: computed(() => props.variant),\n tone: computed(() => props.tone),\n})\n\ndefineSlots<{\n /** Кнопки группы. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-button-group\n class=\"inline-flex\"\n :class=\"[\n orientation === 'vertical' ? 'flex-col items-stretch' : 'items-stretch',\n attached ? '' : 'gap-2',\n ]\"\n :data-orientation=\"orientation\"\n :data-attached=\"attached ? '' : undefined\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n >\n <slot />\n </div>\n</template>\n\n<style>\n/*\n * Склейка держится на понятии «звено группы» — прямом потомке, который сам\n * кнопка или содержит кнопку. Обёртка (тултип, `<span v-if>`, роутерная\n * ссылка) поэтому не разрывает ряд, а не-кнопочный потомок (разделитель,\n * подпись) в склейку не попадает и скругление себе не забирает.\n *\n * Края считаются от соседства звеньев, а не от `:first-child`/`:last-child`:\n * ведущий край гасится у звена, перед которым уже было звено, ведомый — у\n * звена, за которым звено ещё будет.\n */\n[data-gr-button-group] {\n --gr-button-group-radius: var(--gr-button-radius, 0.375rem);\n}\n\n[data-gr-button-group][data-attached] [data-gr-button] {\n border-radius: var(--gr-button-group-radius);\n position: relative;\n}\n\n/* Кнопка под курсором или с фокусом — поверх соседей: иначе её граница и\n фокус-кольцо срезаются наложением. */\n[data-gr-button-group] [data-gr-button]:hover,\n[data-gr-button-group] [data-gr-button]:focus-visible {\n z-index: 1;\n}\n\n/* ————— Горизонтальная группа. */\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-inline-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n}\n\n/* ————— Вертикальная группа: та же логика, другая ось. */\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-block-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-start-end-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-end-start-radius: 0;\n border-end-end-radius: 0;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton/grButtonStyles'\nimport { provideGrButtonGroup } from './context'\n\nexport type GrButtonGroupOrientation = 'horizontal' | 'vertical'\n\nexport interface GrButtonGroupProps {\n /** Доступное имя группы: без него кнопки читаются как несвязанные. */\n ariaLabel?: string\n orientation?: GrButtonGroupOrientation\n /**\n * Склеивать кнопки в один блок. `false` — обычный ряд с зазором: каждая\n * кнопка сохраняет свои радиусы и границы.\n */\n attached?: boolean\n /** Оформление, общее для кнопок группы. Проп самой кнопки сильнее. */\n size?: GrButtonSize\n variant?: GrButtonVariant\n tone?: GrButtonTone\n}\n\nconst props = withDefaults(defineProps<GrButtonGroupProps>(), {\n ariaLabel: undefined,\n orientation: 'horizontal',\n attached: true,\n size: undefined,\n variant: undefined,\n tone: undefined,\n})\n\nprovideGrButtonGroup({\n size: computed(() => props.size),\n variant: computed(() => props.variant),\n tone: computed(() => props.tone),\n})\n\ndefineSlots<{\n /** Кнопки группы. */\n default?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-button-group\n class=\"inline-flex\"\n :class=\"[\n orientation === 'vertical' ? 'flex-col items-stretch' : 'items-stretch',\n attached ? '' : 'gap-2',\n ]\"\n :data-orientation=\"orientation\"\n :data-attached=\"attached ? '' : undefined\"\n role=\"group\"\n :aria-label=\"ariaLabel\"\n >\n <slot />\n </div>\n</template>\n\n<style>\n/*\n * Склейка держится на понятии «звено группы» — прямом потомке, который сам\n * кнопка или содержит кнопку. Обёртка (тултип, `<span v-if>`, роутерная\n * ссылка) поэтому не разрывает ряд, а не-кнопочный потомок (разделитель,\n * подпись) в склейку не попадает и скругление себе не забирает.\n *\n * Края считаются от соседства звеньев, а не от `:first-child`/`:last-child`:\n * ведущий край гасится у звена, перед которым уже было звено, ведомый — у\n * звена, за которым звено ещё будет.\n */\n[data-gr-button-group] {\n --gr-button-group-radius: var(--gr-button-radius, 0.375rem);\n}\n\n[data-gr-button-group][data-attached] [data-gr-button] {\n border-radius: var(--gr-button-group-radius);\n position: relative;\n}\n\n/* Кнопка под курсором или с фокусом — поверх соседей: иначе её граница и\n фокус-кольцо срезаются наложением. */\n[data-gr-button-group] [data-gr-button]:hover,\n[data-gr-button-group] [data-gr-button]:focus-visible {\n z-index: 1;\n}\n\n/* ————— Горизонтальная группа. */\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-inline-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-end-start-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='horizontal'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-start-end-radius: 0;\n border-end-end-radius: 0;\n}\n\n/* ————— Вертикальная группа: та же логика, другая ось. */\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :is([data-gr-button], :has([data-gr-button])) {\n margin-block-start: -1px;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ [data-gr-button],\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :is([data-gr-button], :has([data-gr-button])) ~ :has([data-gr-button]) [data-gr-button] {\n border-start-start-radius: 0;\n border-start-end-radius: 0;\n}\n\n[data-gr-button-group][data-attached][data-orientation='vertical'] > [data-gr-button]:has(~ :is([data-gr-button], :has([data-gr-button]))),\n[data-gr-button-group][data-attached][data-orientation='vertical'] > :has([data-gr-button]):has(~ :is([data-gr-button], :has([data-gr-button]))) [data-gr-button] {\n border-end-start-radius: 0;\n border-end-end-radius: 0;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;EAuBA,MAAM,QAAQ;EASd,qBAAqB;GACnB,MAAM,eAAe,MAAM,IAAI;GAC/B,SAAS,eAAe,MAAM,OAAO;GACrC,MAAM,eAAe,MAAM,IAAI;EACjC,CAAC;;uBASC,mBAaM,OAAA;IAZJ,wBAAA;IACA,OAAK,eAAA,CAAC,eAAa,CACH,QAAA,gBAAW,aAAA,2BAAA,iBAAoE,QAAA,WAAQ,KAAA,OAAA,CAAA,CAAA;IAItG,oBAAkB,QAAA;IAClB,iBAAe,QAAA,WAAQ,KAAQ,KAAA;IAChC,MAAK;IACJ,cAAY,QAAA;OAEb,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"GrCard-BttXz1pQ.js","names":["$slots"],"sources":["../../../../src/components/GrCard/GrCard.vue","../../../../src/components/GrCard/GrCard.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, markRaw, useId, useSlots, type Component } from 'vue'\n\nimport { useGrComponentProp } from '../GrConfigProvider/context'\n\nimport {\n headerActionsClass,\n headerRowClass,\n cardDescriptionClass,\n cardTitleClass,\n grCardRootClass,\n ownHeaderPaddingClass,\n paddingClass,\n sectionDividerBottomClass,\n sectionDividerTopClass,\n type GrCardHeadingLevel,\n type GrCardPadding,\n type GrCardVariant,\n} from './grCardStyles'\n\nexport type { GrCardHeadingLevel, GrCardPadding, GrCardVariant } from './grCardStyles'\n\nexport interface GrCardProps {\n /**\n * Внутренние отступы. По умолчанию `none`: карточка — поверхность, а её\n * содержимое (`GrCollapse`, `GrList`) само знает про свои отступы.\n */\n padding?: GrCardPadding\n /** `elevated` — рамка, фон и тень; `outlined` — без тени; `ghost` — без рамки. */\n variant?: GrCardVariant\n /** Свой корневой тег (`RouterLink`, `Link` от Inertia). Сильнее `href`. */\n as?: string | Component\n /** Карточка-ссылка. */\n href?: string\n /** Карточка-кнопка: интерактивна вся поверхность. */\n clickable?: boolean\n /** Подсветка при наведении без интерактивности. */\n hoverable?: boolean\n /** Классы обёртки тела — она появляется вместе с секциями. */\n bodyClass?: string\n /**\n * Заголовок карточки — настоящий `h2`…`h6`, а не жирная строка: отчёт из\n * шести карточек иначе не обойти по структуре, после `h1` страницы в нём\n * нет ни одного заголовка.\n */\n title?: string\n /** Пояснение под заголовком. */\n description?: string\n /** Уровень заголовка под структуру страницы. Не задан — из `GrConfigProvider`, иначе `3`. */\n headingLevel?: GrCardHeadingLevel\n}\n\nexport interface GrCardEmits {\n (e: 'click', event: MouseEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCardProps>(), {\n // Настраивается через `GrConfigProvider`; дефолты — в резолверах ниже.\n padding: undefined,\n variant: undefined,\n as: undefined,\n href: undefined,\n clickable: false,\n hoverable: false,\n bodyClass: undefined,\n title: undefined,\n description: undefined,\n headingLevel: undefined,\n})\n\nconst emit = defineEmits<GrCardEmits>()\n\nconst slots = useSlots()\n\nconst resolvedPadding = useGrComponentProp('GrCard', 'padding', () => props.padding, 'none')\nconst resolvedVariant = useGrComponentProp('GrCard', 'variant', () => props.variant, 'elevated')\n\nconst isInteractive = computed(() => !!props.as || !!props.href || props.clickable)\n\nconst rootTag = computed<string | Component>(() => {\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n\n if (props.href)\n return 'a'\n\n return props.clickable ? 'button' : 'div'\n})\n\n/**\n * Компонент-ссылка (`Link` от Inertia, `RouterLink`) рендерит `<a>` сам, и без\n * `href` он ведёт в никуда. Строковый тег, кроме `a`, атрибут не понимает —\n * там он и гасится.\n */\nconst rootHref = computed(() => (\n typeof rootTag.value === 'string' && rootTag.value !== 'a' ? undefined : props.href\n))\n\nconst headingLevel = useGrComponentProp('GrCard', 'headingLevel', () => props.headingLevel, 3)\n\n/**\n * Заголовок внутри `<button>` невалиден: контент-модель кнопки — phrasing\n * content. Кликабельная карточка печатает подпись `<span>`, а структура\n * страницы в этом случае собирается ссылкой в заголовке рядом с `hoverable`.\n */\nlet headingInButtonWarned = false\n\nconst headingTag = computed(() => {\n if (rootTag.value !== 'button') return `h${headingLevel.value}`\n\n if (!headingInButtonWarned && __GR_DEV__) {\n headingInButtonWarned = true\n console.warn(\n '[GrCard] `title` внутри `clickable` печатается `<span>`: заголовок в '\n + '`<button>` невалиден по HTML. Нужен заголовок в структуре страницы — '\n + 'замените `clickable` на `hoverable` и поставьте ссылку в сам заголовок.',\n )\n }\n\n return 'span'\n})\n\nconst titleId = useId()\nconst descriptionId = useId()\n\n// `#header` сильнее пропов: нестандартная шапка не обязана объяснять, почему\n// она не `title`.\nconst hasOwnHeader = computed(() => Boolean(slots.header))\nconst hasTitle = computed(() => !hasOwnHeader.value && Boolean(props.title))\nconst hasDescription = computed(() => !hasOwnHeader.value && Boolean(props.description))\n/**\n * Действия рисуются в **собственной** шапке карточки и включают её наравне с\n * заголовком. Без этого слота карточке с кнопкой приходилось забирать `#header`\n * целиком — а вместе с ним заново писать заголовок, его уровень и отступы. К\n * этому обходу независимо пришли `GrDashboardItem` в этом же кольце и обёртки\n * потребителей; оба теряли настоящий `h2…h6` и шкалу отступов.\n */\nconst hasActions = computed(() => !hasOwnHeader.value && Boolean(slots.actions))\nconst hasHeadingBlock = computed(() => hasTitle.value || hasDescription.value || hasActions.value)\n\n/**\n * Обёртки появляются, только когда их попросили: карточка без секций остаётся\n * одним `<div>` со слотом внутри — ровно тем, что рендерили `GrCollapse` и\n * `GrList` до появления пропов.\n */\nconst hasSections = computed(() => Boolean(\n slots.header || slots.footer || slots.actions || props.bodyClass || hasHeadingBlock.value,\n))\n\n/**\n * Имя карточки-ссылки. Без него доступным именем становится всё содержимое\n * подряд — заголовок, описание и тело одной строкой.\n */\nconst rootLabelledBy = computed(() => (isInteractive.value && hasTitle.value ? titleId : undefined))\nconst rootDescribedBy = computed(() => (isInteractive.value && hasDescription.value ? descriptionId : undefined))\n\nconst rootClass = computed(() => grCardRootClass({\n variant: resolvedVariant.value,\n // С секциями отступ принадлежит каждой из них, а не поверхности целиком.\n padding: hasSections.value ? 'none' : resolvedPadding.value,\n interactive: isInteractive.value,\n hoverable: props.hoverable,\n}))\n\nconst sectionPaddingClass = computed(() => paddingClass[resolvedPadding.value])\n\n/**\n * Карточка отбивает то, что рисует сама. Шапка из `title` — её собственная, и\n * отступ ей полагается независимо от `padding`. Слот `#header` сильнее пропов и\n * заменяет шапку целиком: там отступы принадлежат тому, кто её наполнил, —\n * иначе потребитель со своими отступами внутри слота получил бы двойные.\n */\nconst headerClass = computed(() => [\n hasOwnHeader.value ? sectionPaddingClass.value : ownHeaderPaddingClass,\n sectionDividerBottomClass,\n].filter(Boolean).join(' '))\nconst footerClass = computed(() => [sectionPaddingClass.value, sectionDividerTopClass].filter(Boolean).join(' '))\nconst bodySectionClass = computed(() => [sectionPaddingClass.value, props.bodyClass].filter(Boolean).join(' '))\n\nfunction onClick(event: MouseEvent): void {\n emit('click', event)\n}\n\ndefineSlots<{\n /** Содержимое карточки. */\n default?: () => any\n /** Шапка вместо пропов `title` и `description`. */\n header?: () => any\n /**\n * Действия справа в собственной шапке карточки: «⋯», «Обновить»,\n * переключатель периода. Включают шапку так же, как `title`.\n *\n * Со слотом `#header` не сочетается: тот заменяет шапку целиком, и всё, что в\n * ней есть, рисует потребитель.\n */\n actions?: () => any\n /** Подвал: действия, сводка, пагинация. */\n footer?: () => any\n}>()\n\n</script>\n\n<template>\n <component\n :is=\"rootTag\"\n data-gr-card\n :type=\"rootTag === 'button' ? 'button' : undefined\"\n :href=\"rootHref\"\n :class=\"rootClass\"\n :aria-labelledby=\"rootLabelledBy\"\n :aria-describedby=\"rootDescribedBy\"\n @click=\"onClick\"\n >\n <template v-if=\"hasSections\">\n <div v-if=\"hasOwnHeader || hasHeadingBlock\" data-gr-card-header :class=\"headerClass\">\n <slot name=\"header\">\n <div :class=\"hasActions ? headerRowClass : undefined\">\n <div class=\"min-w-0\">\n <component\n :is=\"headingTag\"\n v-if=\"hasTitle\"\n :id=\"titleId\"\n data-gr-card-title\n :class=\"cardTitleClass\"\n >\n {{ title }}\n </component>\n\n <p\n v-if=\"hasDescription\"\n :id=\"descriptionId\"\n data-gr-card-description\n :class=\"cardDescriptionClass\"\n >\n {{ description }}\n </p>\n </div>\n\n <div v-if=\"hasActions\" data-gr-card-actions :class=\"headerActionsClass\">\n <slot name=\"actions\" />\n </div>\n </div>\n </slot>\n </div>\n\n <div data-gr-card-body :class=\"bodySectionClass\">\n <slot />\n </div>\n\n <div v-if=\"$slots.footer\" data-gr-card-footer :class=\"footerClass\">\n <slot name=\"footer\" />\n </div>\n </template>\n\n <slot v-else />\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, useId, useSlots, type Component } from 'vue'\n\nimport { useGrComponentProp } from '../GrConfigProvider/context'\n\nimport {\n headerActionsClass,\n headerRowClass,\n cardDescriptionClass,\n cardTitleClass,\n grCardRootClass,\n ownHeaderPaddingClass,\n paddingClass,\n sectionDividerBottomClass,\n sectionDividerTopClass,\n type GrCardHeadingLevel,\n type GrCardPadding,\n type GrCardVariant,\n} from './grCardStyles'\n\nexport type { GrCardHeadingLevel, GrCardPadding, GrCardVariant } from './grCardStyles'\n\nexport interface GrCardProps {\n /**\n * Внутренние отступы. По умолчанию `none`: карточка — поверхность, а её\n * содержимое (`GrCollapse`, `GrList`) само знает про свои отступы.\n */\n padding?: GrCardPadding\n /** `elevated` — рамка, фон и тень; `outlined` — без тени; `ghost` — без рамки. */\n variant?: GrCardVariant\n /** Свой корневой тег (`RouterLink`, `Link` от Inertia). Сильнее `href`. */\n as?: string | Component\n /** Карточка-ссылка. */\n href?: string\n /** Карточка-кнопка: интерактивна вся поверхность. */\n clickable?: boolean\n /** Подсветка при наведении без интерактивности. */\n hoverable?: boolean\n /** Классы обёртки тела — она появляется вместе с секциями. */\n bodyClass?: string\n /**\n * Заголовок карточки — настоящий `h2`…`h6`, а не жирная строка: отчёт из\n * шести карточек иначе не обойти по структуре, после `h1` страницы в нём\n * нет ни одного заголовка.\n */\n title?: string\n /** Пояснение под заголовком. */\n description?: string\n /** Уровень заголовка под структуру страницы. Не задан — из `GrConfigProvider`, иначе `3`. */\n headingLevel?: GrCardHeadingLevel\n}\n\nexport interface GrCardEmits {\n (e: 'click', event: MouseEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCardProps>(), {\n // Настраивается через `GrConfigProvider`; дефолты — в резолверах ниже.\n padding: undefined,\n variant: undefined,\n as: undefined,\n href: undefined,\n clickable: false,\n hoverable: false,\n bodyClass: undefined,\n title: undefined,\n description: undefined,\n headingLevel: undefined,\n})\n\nconst emit = defineEmits<GrCardEmits>()\n\nconst slots = useSlots()\n\nconst resolvedPadding = useGrComponentProp('GrCard', 'padding', () => props.padding, 'none')\nconst resolvedVariant = useGrComponentProp('GrCard', 'variant', () => props.variant, 'elevated')\n\nconst isInteractive = computed(() => !!props.as || !!props.href || props.clickable)\n\nconst rootTag = computed<string | Component>(() => {\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n\n if (props.href)\n return 'a'\n\n return props.clickable ? 'button' : 'div'\n})\n\n/**\n * Компонент-ссылка (`Link` от Inertia, `RouterLink`) рендерит `<a>` сам, и без\n * `href` он ведёт в никуда. Строковый тег, кроме `a`, атрибут не понимает —\n * там он и гасится.\n */\nconst rootHref = computed(() => (\n typeof rootTag.value === 'string' && rootTag.value !== 'a' ? undefined : props.href\n))\n\nconst headingLevel = useGrComponentProp('GrCard', 'headingLevel', () => props.headingLevel, 3)\n\n/**\n * Заголовок внутри `<button>` невалиден: контент-модель кнопки — phrasing\n * content. Кликабельная карточка печатает подпись `<span>`, а структура\n * страницы в этом случае собирается ссылкой в заголовке рядом с `hoverable`.\n */\nlet headingInButtonWarned = false\n\nconst headingTag = computed(() => {\n if (rootTag.value !== 'button') return `h${headingLevel.value}`\n\n if (!headingInButtonWarned && __GR_DEV__) {\n headingInButtonWarned = true\n console.warn(\n '[GrCard] `title` внутри `clickable` печатается `<span>`: заголовок в '\n + '`<button>` невалиден по HTML. Нужен заголовок в структуре страницы — '\n + 'замените `clickable` на `hoverable` и поставьте ссылку в сам заголовок.',\n )\n }\n\n return 'span'\n})\n\nconst titleId = useId()\nconst descriptionId = useId()\n\n// `#header` сильнее пропов: нестандартная шапка не обязана объяснять, почему\n// она не `title`.\nconst hasOwnHeader = computed(() => Boolean(slots.header))\nconst hasTitle = computed(() => !hasOwnHeader.value && Boolean(props.title))\nconst hasDescription = computed(() => !hasOwnHeader.value && Boolean(props.description))\n/**\n * Действия рисуются в **собственной** шапке карточки и включают её наравне с\n * заголовком. Без этого слота карточке с кнопкой приходилось забирать `#header`\n * целиком — а вместе с ним заново писать заголовок, его уровень и отступы. К\n * этому обходу независимо пришли `GrDashboardItem` в этом же кольце и обёртки\n * потребителей; оба теряли настоящий `h2…h6` и шкалу отступов.\n */\nconst hasActions = computed(() => !hasOwnHeader.value && Boolean(slots.actions))\nconst hasHeadingBlock = computed(() => hasTitle.value || hasDescription.value || hasActions.value)\n\n/**\n * Обёртки появляются, только когда их попросили: карточка без секций остаётся\n * одним `<div>` со слотом внутри — ровно тем, что рендерили `GrCollapse` и\n * `GrList` до появления пропов.\n */\nconst hasSections = computed(() => Boolean(\n slots.header || slots.footer || slots.actions || props.bodyClass || hasHeadingBlock.value,\n))\n\n/**\n * Имя карточки-ссылки. Без него доступным именем становится всё содержимое\n * подряд — заголовок, описание и тело одной строкой.\n */\nconst rootLabelledBy = computed(() => (isInteractive.value && hasTitle.value ? titleId : undefined))\nconst rootDescribedBy = computed(() => (isInteractive.value && hasDescription.value ? descriptionId : undefined))\n\nconst rootClass = computed(() => grCardRootClass({\n variant: resolvedVariant.value,\n // С секциями отступ принадлежит каждой из них, а не поверхности целиком.\n padding: hasSections.value ? 'none' : resolvedPadding.value,\n interactive: isInteractive.value,\n hoverable: props.hoverable,\n}))\n\nconst sectionPaddingClass = computed(() => paddingClass[resolvedPadding.value])\n\n/**\n * Карточка отбивает то, что рисует сама. Шапка из `title` — её собственная, и\n * отступ ей полагается независимо от `padding`. Слот `#header` сильнее пропов и\n * заменяет шапку целиком: там отступы принадлежат тому, кто её наполнил, —\n * иначе потребитель со своими отступами внутри слота получил бы двойные.\n */\nconst headerClass = computed(() => [\n hasOwnHeader.value ? sectionPaddingClass.value : ownHeaderPaddingClass,\n sectionDividerBottomClass,\n].filter(Boolean).join(' '))\nconst footerClass = computed(() => [sectionPaddingClass.value, sectionDividerTopClass].filter(Boolean).join(' '))\nconst bodySectionClass = computed(() => [sectionPaddingClass.value, props.bodyClass].filter(Boolean).join(' '))\n\nfunction onClick(event: MouseEvent): void {\n emit('click', event)\n}\n\ndefineSlots<{\n /** Содержимое карточки. */\n default?: () => any\n /** Шапка вместо пропов `title` и `description`. */\n header?: () => any\n /**\n * Действия справа в собственной шапке карточки: «⋯», «Обновить»,\n * переключатель периода. Включают шапку так же, как `title`.\n *\n * Со слотом `#header` не сочетается: тот заменяет шапку целиком, и всё, что в\n * ней есть, рисует потребитель.\n */\n actions?: () => any\n /** Подвал: действия, сводка, пагинация. */\n footer?: () => any\n}>()\n\n</script>\n\n<template>\n <component\n :is=\"rootTag\"\n data-gr-card\n :type=\"rootTag === 'button' ? 'button' : undefined\"\n :href=\"rootHref\"\n :class=\"rootClass\"\n :aria-labelledby=\"rootLabelledBy\"\n :aria-describedby=\"rootDescribedBy\"\n @click=\"onClick\"\n >\n <template v-if=\"hasSections\">\n <div v-if=\"hasOwnHeader || hasHeadingBlock\" data-gr-card-header :class=\"headerClass\">\n <slot name=\"header\">\n <div :class=\"hasActions ? headerRowClass : undefined\">\n <div class=\"min-w-0\">\n <component\n :is=\"headingTag\"\n v-if=\"hasTitle\"\n :id=\"titleId\"\n data-gr-card-title\n :class=\"cardTitleClass\"\n >\n {{ title }}\n </component>\n\n <p\n v-if=\"hasDescription\"\n :id=\"descriptionId\"\n data-gr-card-description\n :class=\"cardDescriptionClass\"\n >\n {{ description }}\n </p>\n </div>\n\n <div v-if=\"hasActions\" data-gr-card-actions :class=\"headerActionsClass\">\n <slot name=\"actions\" />\n </div>\n </div>\n </slot>\n </div>\n\n <div data-gr-card-body :class=\"bodySectionClass\">\n <slot />\n </div>\n\n <div v-if=\"$slots.footer\" data-gr-card-footer :class=\"footerClass\">\n <slot name=\"footer\" />\n </div>\n </template>\n\n <slot v-else />\n </component>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrCard-BttXz1pQ.js","names":["$slots"],"sources":["../../../../src/components/GrCard/GrCard.vue","../../../../src/components/GrCard/GrCard.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, markRaw, useId, useSlots, type Component } from 'vue'\n\nimport { useGrComponentProp } from '../GrConfigProvider/context'\n\nimport {\n headerActionsClass,\n headerRowClass,\n cardDescriptionClass,\n cardTitleClass,\n grCardRootClass,\n ownHeaderPaddingClass,\n paddingClass,\n sectionDividerBottomClass,\n sectionDividerTopClass,\n type GrCardHeadingLevel,\n type GrCardPadding,\n type GrCardVariant,\n} from './grCardStyles'\n\nexport type { GrCardHeadingLevel, GrCardPadding, GrCardVariant } from './grCardStyles'\n\nexport interface GrCardProps {\n /**\n * Внутренние отступы. По умолчанию `none`: карточка — поверхность, а её\n * содержимое (`GrCollapse`, `GrList`) само знает про свои отступы.\n */\n padding?: GrCardPadding\n /** `elevated` — рамка, фон и тень; `outlined` — без тени; `ghost` — без рамки. */\n variant?: GrCardVariant\n /** Свой корневой тег (`RouterLink`, `Link` от Inertia). Сильнее `href`. */\n as?: string | Component\n /** Карточка-ссылка. */\n href?: string\n /** Карточка-кнопка: интерактивна вся поверхность. */\n clickable?: boolean\n /** Подсветка при наведении без интерактивности. */\n hoverable?: boolean\n /** Классы обёртки тела — она появляется вместе с секциями. */\n bodyClass?: string\n /**\n * Заголовок карточки — настоящий `h2`…`h6`, а не жирная строка: отчёт из\n * шести карточек иначе не обойти по структуре, после `h1` страницы в нём\n * нет ни одного заголовка.\n */\n title?: string\n /** Пояснение под заголовком. */\n description?: string\n /** Уровень заголовка под структуру страницы. Не задан — из `GrConfigProvider`, иначе `3`. */\n headingLevel?: GrCardHeadingLevel\n}\n\nexport interface GrCardEmits {\n (e: 'click', event: MouseEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCardProps>(), {\n // Настраивается через `GrConfigProvider`; дефолты — в резолверах ниже.\n padding: undefined,\n variant: undefined,\n as: undefined,\n href: undefined,\n clickable: false,\n hoverable: false,\n bodyClass: undefined,\n title: undefined,\n description: undefined,\n headingLevel: undefined,\n})\n\nconst emit = defineEmits<GrCardEmits>()\n\nconst slots = useSlots()\n\nconst resolvedPadding = useGrComponentProp('GrCard', 'padding', () => props.padding, 'none')\nconst resolvedVariant = useGrComponentProp('GrCard', 'variant', () => props.variant, 'elevated')\n\nconst isInteractive = computed(() => !!props.as || !!props.href || props.clickable)\n\nconst rootTag = computed<string | Component>(() => {\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n\n if (props.href)\n return 'a'\n\n return props.clickable ? 'button' : 'div'\n})\n\n/**\n * Компонент-ссылка (`Link` от Inertia, `RouterLink`) рендерит `<a>` сам, и без\n * `href` он ведёт в никуда. Строковый тег, кроме `a`, атрибут не понимает —\n * там он и гасится.\n */\nconst rootHref = computed(() => (\n typeof rootTag.value === 'string' && rootTag.value !== 'a' ? undefined : props.href\n))\n\nconst headingLevel = useGrComponentProp('GrCard', 'headingLevel', () => props.headingLevel, 3)\n\n/**\n * Заголовок внутри `<button>` невалиден: контент-модель кнопки — phrasing\n * content. Кликабельная карточка печатает подпись `<span>`, а структура\n * страницы в этом случае собирается ссылкой в заголовке рядом с `hoverable`.\n */\nlet headingInButtonWarned = false\n\nconst headingTag = computed(() => {\n if (rootTag.value !== 'button')\n return `h${headingLevel.value}`\n\n if (!headingInButtonWarned && __GR_DEV__) {\n headingInButtonWarned = true\n console.warn(\n '[GrCard] `title` внутри `clickable` печатается `<span>`: заголовок в '\n + '`<button>` невалиден по HTML. Нужен заголовок в структуре страницы — '\n + 'замените `clickable` на `hoverable` и поставьте ссылку в сам заголовок.',\n )\n }\n\n return 'span'\n})\n\nconst titleId = useId()\nconst descriptionId = useId()\n\n// `#header` сильнее пропов: нестандартная шапка не обязана объяснять, почему\n// она не `title`.\nconst hasOwnHeader = computed(() => Boolean(slots.header))\nconst hasTitle = computed(() => !hasOwnHeader.value && Boolean(props.title))\nconst hasDescription = computed(() => !hasOwnHeader.value && Boolean(props.description))\n/**\n * Действия рисуются в **собственной** шапке карточки и включают её наравне с\n * заголовком. Без этого слота карточке с кнопкой приходилось забирать `#header`\n * целиком — а вместе с ним заново писать заголовок, его уровень и отступы. К\n * этому обходу независимо пришли `GrDashboardItem` в этом же кольце и обёртки\n * потребителей; оба теряли настоящий `h2…h6` и шкалу отступов.\n */\nconst hasActions = computed(() => !hasOwnHeader.value && Boolean(slots.actions))\nconst hasHeadingBlock = computed(() => hasTitle.value || hasDescription.value || hasActions.value)\n\n/**\n * Обёртки появляются, только когда их попросили: карточка без секций остаётся\n * одним `<div>` со слотом внутри — ровно тем, что рендерили `GrCollapse` и\n * `GrList` до появления пропов.\n */\nconst hasSections = computed(() => Boolean(\n slots.header || slots.footer || slots.actions || props.bodyClass || hasHeadingBlock.value,\n))\n\n/**\n * Имя карточки-ссылки. Без него доступным именем становится всё содержимое\n * подряд — заголовок, описание и тело одной строкой.\n */\nconst rootLabelledBy = computed(() => (isInteractive.value && hasTitle.value ? titleId : undefined))\nconst rootDescribedBy = computed(() => (isInteractive.value && hasDescription.value ? descriptionId : undefined))\n\nconst rootClass = computed(() => grCardRootClass({\n variant: resolvedVariant.value,\n // С секциями отступ принадлежит каждой из них, а не поверхности целиком.\n padding: hasSections.value ? 'none' : resolvedPadding.value,\n interactive: isInteractive.value,\n hoverable: props.hoverable,\n}))\n\nconst sectionPaddingClass = computed(() => paddingClass[resolvedPadding.value])\n\n/**\n * Карточка отбивает то, что рисует сама. Шапка из `title` — её собственная, и\n * отступ ей полагается независимо от `padding`. Слот `#header` сильнее пропов и\n * заменяет шапку целиком: там отступы принадлежат тому, кто её наполнил, —\n * иначе потребитель со своими отступами внутри слота получил бы двойные.\n */\nconst headerClass = computed(() => [\n hasOwnHeader.value ? sectionPaddingClass.value : ownHeaderPaddingClass,\n sectionDividerBottomClass,\n].filter(Boolean).join(' '))\nconst footerClass = computed(() => [sectionPaddingClass.value, sectionDividerTopClass].filter(Boolean).join(' '))\nconst bodySectionClass = computed(() => [sectionPaddingClass.value, props.bodyClass].filter(Boolean).join(' '))\n\nfunction onClick(event: MouseEvent): void {\n emit('click', event)\n}\n\ndefineSlots<{\n /** Содержимое карточки. */\n default?: () => any\n /** Шапка вместо пропов `title` и `description`. */\n header?: () => any\n /**\n * Действия справа в собственной шапке карточки: «⋯», «Обновить»,\n * переключатель периода. Включают шапку так же, как `title`.\n *\n * Со слотом `#header` не сочетается: тот заменяет шапку целиком, и всё, что в\n * ней есть, рисует потребитель.\n */\n actions?: () => any\n /** Подвал: действия, сводка, пагинация. */\n footer?: () => any\n}>()\n</script>\n\n<template>\n <component\n :is=\"rootTag\"\n data-gr-card\n :type=\"rootTag === 'button' ? 'button' : undefined\"\n :href=\"rootHref\"\n :class=\"rootClass\"\n :aria-labelledby=\"rootLabelledBy\"\n :aria-describedby=\"rootDescribedBy\"\n @click=\"onClick\"\n >\n <template v-if=\"hasSections\">\n <div v-if=\"hasOwnHeader || hasHeadingBlock\" data-gr-card-header :class=\"headerClass\">\n <slot name=\"header\">\n <div :class=\"hasActions ? headerRowClass : undefined\">\n <div class=\"min-w-0\">\n <component\n :is=\"headingTag\"\n v-if=\"hasTitle\"\n :id=\"titleId\"\n data-gr-card-title\n :class=\"cardTitleClass\"\n >\n {{ title }}\n </component>\n\n <p\n v-if=\"hasDescription\"\n :id=\"descriptionId\"\n data-gr-card-description\n :class=\"cardDescriptionClass\"\n >\n {{ description }}\n </p>\n </div>\n\n <div v-if=\"hasActions\" data-gr-card-actions :class=\"headerActionsClass\">\n <slot name=\"actions\" />\n </div>\n </div>\n </slot>\n </div>\n\n <div data-gr-card-body :class=\"bodySectionClass\">\n <slot />\n </div>\n\n <div v-if=\"$slots.footer\" data-gr-card-footer :class=\"footerClass\">\n <slot name=\"footer\" />\n </div>\n </template>\n\n <slot v-else />\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, markRaw, useId, useSlots, type Component } from 'vue'\n\nimport { useGrComponentProp } from '../GrConfigProvider/context'\n\nimport {\n headerActionsClass,\n headerRowClass,\n cardDescriptionClass,\n cardTitleClass,\n grCardRootClass,\n ownHeaderPaddingClass,\n paddingClass,\n sectionDividerBottomClass,\n sectionDividerTopClass,\n type GrCardHeadingLevel,\n type GrCardPadding,\n type GrCardVariant,\n} from './grCardStyles'\n\nexport type { GrCardHeadingLevel, GrCardPadding, GrCardVariant } from './grCardStyles'\n\nexport interface GrCardProps {\n /**\n * Внутренние отступы. По умолчанию `none`: карточка — поверхность, а её\n * содержимое (`GrCollapse`, `GrList`) само знает про свои отступы.\n */\n padding?: GrCardPadding\n /** `elevated` — рамка, фон и тень; `outlined` — без тени; `ghost` — без рамки. */\n variant?: GrCardVariant\n /** Свой корневой тег (`RouterLink`, `Link` от Inertia). Сильнее `href`. */\n as?: string | Component\n /** Карточка-ссылка. */\n href?: string\n /** Карточка-кнопка: интерактивна вся поверхность. */\n clickable?: boolean\n /** Подсветка при наведении без интерактивности. */\n hoverable?: boolean\n /** Классы обёртки тела — она появляется вместе с секциями. */\n bodyClass?: string\n /**\n * Заголовок карточки — настоящий `h2`…`h6`, а не жирная строка: отчёт из\n * шести карточек иначе не обойти по структуре, после `h1` страницы в нём\n * нет ни одного заголовка.\n */\n title?: string\n /** Пояснение под заголовком. */\n description?: string\n /** Уровень заголовка под структуру страницы. Не задан — из `GrConfigProvider`, иначе `3`. */\n headingLevel?: GrCardHeadingLevel\n}\n\nexport interface GrCardEmits {\n (e: 'click', event: MouseEvent): void\n}\n\nconst props = withDefaults(defineProps<GrCardProps>(), {\n // Настраивается через `GrConfigProvider`; дефолты — в резолверах ниже.\n padding: undefined,\n variant: undefined,\n as: undefined,\n href: undefined,\n clickable: false,\n hoverable: false,\n bodyClass: undefined,\n title: undefined,\n description: undefined,\n headingLevel: undefined,\n})\n\nconst emit = defineEmits<GrCardEmits>()\n\nconst slots = useSlots()\n\nconst resolvedPadding = useGrComponentProp('GrCard', 'padding', () => props.padding, 'none')\nconst resolvedVariant = useGrComponentProp('GrCard', 'variant', () => props.variant, 'elevated')\n\nconst isInteractive = computed(() => !!props.as || !!props.href || props.clickable)\n\nconst rootTag = computed<string | Component>(() => {\n if (props.as)\n return typeof props.as === 'string' ? props.as : markRaw(props.as)\n\n if (props.href)\n return 'a'\n\n return props.clickable ? 'button' : 'div'\n})\n\n/**\n * Компонент-ссылка (`Link` от Inertia, `RouterLink`) рендерит `<a>` сам, и без\n * `href` он ведёт в никуда. Строковый тег, кроме `a`, атрибут не понимает —\n * там он и гасится.\n */\nconst rootHref = computed(() => (\n typeof rootTag.value === 'string' && rootTag.value !== 'a' ? undefined : props.href\n))\n\nconst headingLevel = useGrComponentProp('GrCard', 'headingLevel', () => props.headingLevel, 3)\n\n/**\n * Заголовок внутри `<button>` невалиден: контент-модель кнопки — phrasing\n * content. Кликабельная карточка печатает подпись `<span>`, а структура\n * страницы в этом случае собирается ссылкой в заголовке рядом с `hoverable`.\n */\nlet headingInButtonWarned = false\n\nconst headingTag = computed(() => {\n if (rootTag.value !== 'button')\n return `h${headingLevel.value}`\n\n if (!headingInButtonWarned && __GR_DEV__) {\n headingInButtonWarned = true\n console.warn(\n '[GrCard] `title` внутри `clickable` печатается `<span>`: заголовок в '\n + '`<button>` невалиден по HTML. Нужен заголовок в структуре страницы — '\n + 'замените `clickable` на `hoverable` и поставьте ссылку в сам заголовок.',\n )\n }\n\n return 'span'\n})\n\nconst titleId = useId()\nconst descriptionId = useId()\n\n// `#header` сильнее пропов: нестандартная шапка не обязана объяснять, почему\n// она не `title`.\nconst hasOwnHeader = computed(() => Boolean(slots.header))\nconst hasTitle = computed(() => !hasOwnHeader.value && Boolean(props.title))\nconst hasDescription = computed(() => !hasOwnHeader.value && Boolean(props.description))\n/**\n * Действия рисуются в **собственной** шапке карточки и включают её наравне с\n * заголовком. Без этого слота карточке с кнопкой приходилось забирать `#header`\n * целиком — а вместе с ним заново писать заголовок, его уровень и отступы. К\n * этому обходу независимо пришли `GrDashboardItem` в этом же кольце и обёртки\n * потребителей; оба теряли настоящий `h2…h6` и шкалу отступов.\n */\nconst hasActions = computed(() => !hasOwnHeader.value && Boolean(slots.actions))\nconst hasHeadingBlock = computed(() => hasTitle.value || hasDescription.value || hasActions.value)\n\n/**\n * Обёртки появляются, только когда их попросили: карточка без секций остаётся\n * одним `<div>` со слотом внутри — ровно тем, что рендерили `GrCollapse` и\n * `GrList` до появления пропов.\n */\nconst hasSections = computed(() => Boolean(\n slots.header || slots.footer || slots.actions || props.bodyClass || hasHeadingBlock.value,\n))\n\n/**\n * Имя карточки-ссылки. Без него доступным именем становится всё содержимое\n * подряд — заголовок, описание и тело одной строкой.\n */\nconst rootLabelledBy = computed(() => (isInteractive.value && hasTitle.value ? titleId : undefined))\nconst rootDescribedBy = computed(() => (isInteractive.value && hasDescription.value ? descriptionId : undefined))\n\nconst rootClass = computed(() => grCardRootClass({\n variant: resolvedVariant.value,\n // С секциями отступ принадлежит каждой из них, а не поверхности целиком.\n padding: hasSections.value ? 'none' : resolvedPadding.value,\n interactive: isInteractive.value,\n hoverable: props.hoverable,\n}))\n\nconst sectionPaddingClass = computed(() => paddingClass[resolvedPadding.value])\n\n/**\n * Карточка отбивает то, что рисует сама. Шапка из `title` — её собственная, и\n * отступ ей полагается независимо от `padding`. Слот `#header` сильнее пропов и\n * заменяет шапку целиком: там отступы принадлежат тому, кто её наполнил, —\n * иначе потребитель со своими отступами внутри слота получил бы двойные.\n */\nconst headerClass = computed(() => [\n hasOwnHeader.value ? sectionPaddingClass.value : ownHeaderPaddingClass,\n sectionDividerBottomClass,\n].filter(Boolean).join(' '))\nconst footerClass = computed(() => [sectionPaddingClass.value, sectionDividerTopClass].filter(Boolean).join(' '))\nconst bodySectionClass = computed(() => [sectionPaddingClass.value, props.bodyClass].filter(Boolean).join(' '))\n\nfunction onClick(event: MouseEvent): void {\n emit('click', event)\n}\n\ndefineSlots<{\n /** Содержимое карточки. */\n default?: () => any\n /** Шапка вместо пропов `title` и `description`. */\n header?: () => any\n /**\n * Действия справа в собственной шапке карточки: «⋯», «Обновить»,\n * переключатель периода. Включают шапку так же, как `title`.\n *\n * Со слотом `#header` не сочетается: тот заменяет шапку целиком, и всё, что в\n * ней есть, рисует потребитель.\n */\n actions?: () => any\n /** Подвал: действия, сводка, пагинация. */\n footer?: () => any\n}>()\n</script>\n\n<template>\n <component\n :is=\"rootTag\"\n data-gr-card\n :type=\"rootTag === 'button' ? 'button' : undefined\"\n :href=\"rootHref\"\n :class=\"rootClass\"\n :aria-labelledby=\"rootLabelledBy\"\n :aria-describedby=\"rootDescribedBy\"\n @click=\"onClick\"\n >\n <template v-if=\"hasSections\">\n <div v-if=\"hasOwnHeader || hasHeadingBlock\" data-gr-card-header :class=\"headerClass\">\n <slot name=\"header\">\n <div :class=\"hasActions ? headerRowClass : undefined\">\n <div class=\"min-w-0\">\n <component\n :is=\"headingTag\"\n v-if=\"hasTitle\"\n :id=\"titleId\"\n data-gr-card-title\n :class=\"cardTitleClass\"\n >\n {{ title }}\n </component>\n\n <p\n v-if=\"hasDescription\"\n :id=\"descriptionId\"\n data-gr-card-description\n :class=\"cardDescriptionClass\"\n >\n {{ description }}\n </p>\n </div>\n\n <div v-if=\"hasActions\" data-gr-card-actions :class=\"headerActionsClass\">\n <slot name=\"actions\" />\n </div>\n </div>\n </slot>\n </div>\n\n <div data-gr-card-body :class=\"bodySectionClass\">\n <slot />\n </div>\n\n <div v-if=\"$slots.footer\" data-gr-card-footer :class=\"footerClass\">\n <slot name=\"footer\" />\n </div>\n </template>\n\n <slot v-else />\n </component>\n</template>\n"],"mappings":"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"}