@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrCodeBlock-Dp0eEBTZ.js","names":[],"sources":["../../../../src/components/GrCodeBlock/serializeCode.ts","../../../../src/components/GrCodeBlock/tokenizeJson.ts","../../../../src/components/GrCodeBlock/GrCodeBlock.vue","../../../../src/components/GrCodeBlock/GrCodeBlock.vue"],"sourcesContent":["/**\n * Приведение произвольного значения к тексту для показа.\n *\n * Компонент показывает данные из БД, и они бывают любыми: `unknown`-поле ответа\n * модели, `meta` запуска, тело ошибки. Поэтому сериализация обязана пережить всё\n * — уронить страницу она права не имеет.\n */\n\n/** Маркер повторной ссылки. Показывается вместо ветки, которая уже встречалась выше. */\nexport const CIRCULAR_MARKER = '[Circular]'\n\n/** Что печатается, когда сериализовать не удалось вовсе. */\nexport const UNSERIALIZABLE_MARKER = '[Unserializable]'\n\n/**\n * Замена значений, на которых штатный `JSON.stringify` спотыкается.\n *\n * Маркером помечается **повторная ссылка**, а не только настоящий цикл: объект,\n * положенный в дерево дважды, тоже её получит. Отличить одно от другого можно\n * лишь стеком предков, а `replacer` его не отдаёт — узнать, что обход вышел из\n * ветки, изнутри нечем. Размен осознанный: показать `[Circular]` там, где данные\n * просто переиспользуют объект, — неточность; зациклиться на настоящем цикле —\n * зависшая вкладка.\n */\nfunction createSafeReplacer(): (key: string, value: unknown) => unknown {\n const seen = new WeakSet<object>()\n\n return function safeReplacer(_key: string, value: unknown): unknown {\n // `BigInt` не имеет представления в JSON, и `stringify` на нём бросает.\n if (typeof value === 'bigint')\n return `${value}n`\n\n if (typeof value !== 'object' || value === null)\n return value\n\n if (seen.has(value))\n return CIRCULAR_MARKER\n\n seen.add(value)\n return value\n }\n}\n\n/**\n * Значение → текст.\n *\n * Строка проходит как есть: это уже готовый текст, и оборачивать его в кавычки\n * значило бы показать не то, что пришло. `undefined` даёт пустую строку —\n * показывать нечего. Всё остальное сериализуется с отступом.\n */\nexport function serializeCode(value: unknown, indent = 2): string {\n if (typeof value === 'string')\n return value\n if (value === undefined)\n return ''\n\n try {\n const serialized = JSON.stringify(value, createSafeReplacer(), indent)\n // `stringify` отдаёт `undefined` на функции и символе — печатать «undefined»\n // строкой было бы враньём про содержимое.\n return serialized ?? ''\n }\n catch {\n return UNSERIALIZABLE_MARKER\n }\n}\n","/**\n * Токенизация JSON для подсветки.\n *\n * Своя, а не библиотечная: тянуть highlight.js ради четырёх ролей несоразмерно\n * — компонент показывает JSON и обычный текст, а не произвольные языки.\n *\n * Разбор посимвольный и **ничего не теряет**: пробелы, переносы и запятые тоже\n * становятся токенами. Отсюда инвариант, который держит тест: склейка `text`\n * всех токенов равна исходной строке. Любая потеря символа — сдвиг разметки.\n */\n\nexport type GrCodeTokenKind\n /** Имя поля объекта: строка, за которой идёт двоеточие. */\n = | 'key'\n | 'string'\n | 'number'\n /** `true`, `false`, `null`. */\n | 'literal'\n /** Скобки, запятые, двоеточия. */\n | 'punctuation'\n /** Пробелы, переносы и всё, что не опознано. */\n | 'plain'\n\nexport interface GrCodeToken {\n text: string\n kind: GrCodeTokenKind\n}\n\nconst PUNCTUATION = new Set(['{', '}', '[', ']', ',', ':'])\nconst LITERALS = ['true', 'false', 'null'] as const\n\n/** Строка от открывающей кавычки до закрывающей, с учётом экранирования. */\nfunction readString(source: string, start: number): number {\n let index = start + 1\n\n while (index < source.length) {\n const char = source[index]\n\n // Экранированная кавычка не закрывает строку: `\"a\\\":b\"` — одно значение,\n // а не строка плюс мусор.\n if (char === '\\\\') {\n index += 2\n continue\n }\n\n index += 1\n if (char === '\"')\n break\n }\n\n return index\n}\n\n/** Число целиком: знак, дробная часть, экспонента. */\nfunction readNumber(source: string, start: number): number {\n let index = start\n\n if (source[index] === '-')\n index += 1\n while (index < source.length && /[\\d.eE+-]/.test(source[index])) index += 1\n\n return index\n}\n\n/** Первый непробельный символ после позиции — по нему строка отличается от ключа. */\nfunction nextMeaningful(source: string, from: number): string | undefined {\n for (let index = from; index < source.length; index += 1) {\n if (!/\\s/.test(source[index]))\n return source[index]\n }\n\n return undefined\n}\n\nexport function tokenizeJson(source: string): GrCodeToken[] {\n const tokens: GrCodeToken[] = []\n let index = 0\n let plainStart = 0\n\n const flushPlain = (until: number): void => {\n if (until > plainStart)\n tokens.push({ text: source.slice(plainStart, until), kind: 'plain' })\n }\n\n while (index < source.length) {\n const char = source[index]\n\n if (char === '\"') {\n flushPlain(index)\n const end = readString(source, index)\n // Ключ от строки отличает только идущее следом двоеточие.\n const kind: GrCodeTokenKind = nextMeaningful(source, end) === ':' ? 'key' : 'string'\n tokens.push({ text: source.slice(index, end), kind })\n index = end\n plainStart = index\n continue\n }\n\n if (PUNCTUATION.has(char)) {\n flushPlain(index)\n tokens.push({ text: char, kind: 'punctuation' })\n index += 1\n plainStart = index\n continue\n }\n\n if (char === '-' || (char >= '0' && char <= '9')) {\n flushPlain(index)\n const end = readNumber(source, index)\n tokens.push({ text: source.slice(index, end), kind: 'number' })\n index = end\n plainStart = index\n continue\n }\n\n const literal = LITERALS.find(candidate => source.startsWith(candidate, index))\n if (literal) {\n flushPlain(index)\n tokens.push({ text: literal, kind: 'literal' })\n index += literal.length\n plainStart = index\n continue\n }\n\n index += 1\n }\n\n flushPlain(source.length)\n\n return tokens\n}\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconCopy from '~icons/lucide/copy'\n\nimport { serializeCode } from './serializeCode'\nimport { tokenizeJson, type GrCodeToken } from './tokenizeJson'\nimport {\n codeBlockCopyClass,\n codeBlockGutterClass,\n codeBlockHookClass,\n codeBlockNowrapClass,\n codeBlockNumberedClass as numberedClass,\n codeBlockPaddings,\n codeBlockRootClass,\n codeBlockScrollClass,\n codeBlockSurfaceClass,\n codeBlockTextSizes,\n codeBlockWrapClass,\n codeTokenClass,\n} from './grCodeBlockStyles'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nexport type { GrCodeToken, GrCodeTokenKind } from './tokenizeJson'\n\n/** Язык подсветки. Кроме JSON компонент ничего не разбирает — и не должен. */\nexport type GrCodeBlockLanguage = 'json' | 'text'\n\n/**\n * Блок сырого текста или JSON: моноширинный, с подсветкой, номерами строк и\n * копированием в буфер.\n *\n * Показывает, а не редактирует и не сворачивает узлы. Свёртка по узлам — задача\n * `GrJsonViewer`, дерево выбора — `GrTree`.\n */\nexport interface GrCodeBlockProps {\n /** Строка или значение: объект сериализуется с отступом. */\n code: unknown\n language?: GrCodeBlockLanguage\n /** Высота, после которой включается вертикальный скролл. */\n maxHeight?: string | number\n /** Кнопка копирования. Без защищённого контекста не рисуется вовсе. */\n copyable?: boolean\n /** Переносить длинные строки вместо горизонтальной прокрутки. */\n wrap?: boolean\n lineNumbers?: boolean\n /** Имя области прокрутки. Безымянную скринридер объявляет просто «регион». */\n ariaLabel?: string\n size?: GrComponentSize\n}\n\nexport interface GrCodeBlockEmits {\n /** Текст скопирован. Тост показывает потребитель: у блока своего места для него нет. */\n (e: 'copy', code: string): void\n}\n\nconst props = withDefaults(defineProps<GrCodeBlockProps>(), {\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем компонент\n // заглянет в `GrConfigProvider`.\n language: 'json',\n maxHeight: undefined,\n copyable: undefined,\n wrap: undefined,\n lineNumbers: undefined,\n ariaLabel: undefined,\n size: undefined,\n})\n\nconst emit = defineEmits<GrCodeBlockEmits>()\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCodeBlock' })\nconst resolvedCopyable = useGrComponentProp('GrCodeBlock', 'copyable', () => props.copyable, true)\nconst resolvedWrap = useGrComponentProp('GrCodeBlock', 'wrap', () => props.wrap, false)\nconst resolvedLineNumbers = useGrComponentProp('GrCodeBlock', 'lineNumbers', () => props.lineNumbers, false)\n\n/** Единственный источник текста: он же рендерится, он же уходит в буфер. */\nconst source = computed(() => serializeCode(props.code))\n\n/**\n * Разбор идёт по строкам, а не по всему тексту: номер строки — CSS-счётчик, а\n * счётчику нужен элемент на строку. JSON-строка перенос не содержит (он в ней\n * экранирован), поэтому построчная токенизация ничего не рвёт.\n */\nconst lines = computed<GrCodeToken[][]>(() => {\n const rows = source.value.split('\\n')\n\n if (props.language !== 'json')\n return rows.map(row => [{ text: row, kind: 'plain' as const }])\n\n return rows.map(row => tokenizeJson(row))\n})\n\n/**\n * Блок — скроллер по конструкции, а не по замеру. Замер здесь означал бы\n * мигающую остановку `Tab` на каждой смене данных и загрузке шрифта; ни один\n * компонент пакета так не делает.\n */\nconst isScroller = computed(() => props.maxHeight !== undefined || !resolvedWrap.value)\n\nconst scrollStyle = computed(() => {\n if (props.maxHeight === undefined)\n return undefined\n\n return { maxHeight: typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight }\n})\n\nconst preClass = computed(() => [\n codeBlockHookClass,\n codeBlockSurfaceClass,\n codeBlockPaddings[resolvedSize.value],\n codeBlockTextSizes[resolvedSize.value],\n resolvedWrap.value ? codeBlockWrapClass : codeBlockNowrapClass,\n isScroller.value ? codeBlockScrollClass : '',\n].filter(Boolean).join(' '))\n\n/**\n * Наличие буфера уточняется после монтирования: `navigator` в теле `setup` либо\n * роняет серверный рендер, либо расходится с ним. До этого момента кнопки нет —\n * ровно то же, что отдаёт сервер, поэтому гидрация совпадает.\n */\nconst canCopy = ref(false)\n\nonMounted(() => {\n canCopy.value = typeof navigator !== 'undefined' && typeof navigator.clipboard?.writeText === 'function'\n})\n\nconst showCopy = computed(() => resolvedCopyable.value && canCopy.value)\n\nconst copied = ref(false)\nlet copiedTimer: number | null = null\n\nfunction resetCopiedTimer(): void {\n if (copiedTimer !== null) {\n clearTimeout(copiedTimer)\n copiedTimer = null\n }\n}\n\nonBeforeUnmount(resetCopiedTimer)\n\nasync function copy(): Promise<void> {\n try {\n // Копируется исходный текст, а не разметка: номера строк — CSS-счётчик,\n // а мягкие переносы принадлежат показу, и вставить их обратно нельзя.\n await navigator.clipboard.writeText(source.value)\n }\n catch {\n announce(t('gr.codeBlock.copyFailed', 'Could not copy code'))\n return\n }\n\n copied.value = true\n resetCopiedTimer()\n copiedTimer = window.setTimeout(() => {\n copied.value = false\n copiedTimer = null\n }, 1200)\n\n announce(t('gr.codeBlock.copied', 'Code copied'))\n emit('copy', source.value)\n}\n\nconst copyLabel = computed(() => (\n copied.value ? t('gr.codeBlock.copied', 'Code copied') : t('gr.codeBlock.copy', 'Copy code')\n))\n</script>\n\n<template>\n <div data-gr-code-block :class=\"[codeBlockRootClass, showCopy ? codeBlockGutterClass : '']\">\n <GrButton\n v-if=\"showCopy\"\n data-gr-code-block-copy\n variant=\"ghost\"\n size=\"xs\"\n square\n :class=\"codeBlockCopyClass\"\n :aria-label=\"copyLabel\"\n :title=\"copyLabel\"\n @click=\"copy\"\n >\n <component :is=\"copied ? IconCheck : IconCopy\" class=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </GrButton>\n\n <!--\n Внутри `<pre>` пробелы значимы, и компилятор Vue их здесь не схлопывает:\n любой перенос между тегами стал бы пустой строкой в коде. Поэтому\n содержимое блока записано без переносов — строки разделяет `display: block`\n у `.gr-code-block__line`, а не текстовый `\\n`.\n -->\n <pre\n data-gr-code-block-scroll\n :class=\"[preClass, resolvedLineNumbers ? numberedClass : '']\"\n :style=\"scrollStyle\"\n :tabindex=\"isScroller ? 0 : undefined\"\n :role=\"ariaLabel ? 'region' : undefined\"\n :aria-label=\"ariaLabel\"\n ><code data-gr-code-block-code><span v-for=\"(tokens, index) in lines\" :key=\"index\" data-gr-code-block-line class=\"gr-code-block__line\"><span v-for=\"(token, tokenIndex) in tokens\" :key=\"tokenIndex\" :class=\"codeTokenClass[token.kind]\">{{ token.text }}</span></span></code></pre>\n </div>\n</template>\n\n<style>\n/*\n * Номер строки — CSS-счётчик, а не текст в разметке. Разница не косметическая:\n * узел со `<span>2</span>` попадает в выделение мышью, и в буфер уезжает то,\n * что нельзя вставить обратно как код. У `::before` содержимого в DOM нет.\n *\n * Стиль глобальный, а не scoped: правило адресует псевдоэлемент строки, и\n * scoped-атрибут пришлось бы вешать на каждый из них.\n */\n:where(.gr-code-block__line) {\n display: block;\n}\n\n:where(.gr-code-block--numbered) {\n counter-reset: gr-code-line;\n}\n\n/*\n * Висячий отступ: строка сдвинута на ширину колонки номеров, а первая строка\n * возвращена назад отрицательным `text-indent` — туда и встаёт номер. Без этого\n * перенесённая при `wrap` строка начиналась бы под номером, а не под кодом.\n */\n:where(.gr-code-block--numbered .gr-code-block__line) {\n padding-left: calc(var(--gr-code-block-line-number-width, 2.5em) + 1em);\n text-indent: calc(-1 * (var(--gr-code-block-line-number-width, 2.5em) + 1em));\n}\n\n:where(.gr-code-block--numbered .gr-code-block__line)::before {\n counter-increment: gr-code-line;\n content: counter(gr-code-line);\n display: inline-block;\n width: var(--gr-code-block-line-number-width, 2.5em);\n margin-right: 1em;\n text-align: right;\n text-indent: 0;\n color: var(--gr-code-block-line-number, var(--gr-muted-fg));\n user-select: none;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconCopy from '~icons/lucide/copy'\n\nimport { serializeCode } from './serializeCode'\nimport { tokenizeJson, type GrCodeToken } from './tokenizeJson'\nimport {\n codeBlockCopyClass,\n codeBlockGutterClass,\n codeBlockHookClass,\n codeBlockNowrapClass,\n codeBlockNumberedClass as numberedClass,\n codeBlockPaddings,\n codeBlockRootClass,\n codeBlockScrollClass,\n codeBlockSurfaceClass,\n codeBlockTextSizes,\n codeBlockWrapClass,\n codeTokenClass,\n} from './grCodeBlockStyles'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nexport type { GrCodeToken, GrCodeTokenKind } from './tokenizeJson'\n\n/** Язык подсветки. Кроме JSON компонент ничего не разбирает — и не должен. */\nexport type GrCodeBlockLanguage = 'json' | 'text'\n\n/**\n * Блок сырого текста или JSON: моноширинный, с подсветкой, номерами строк и\n * копированием в буфер.\n *\n * Показывает, а не редактирует и не сворачивает узлы. Свёртка по узлам — задача\n * `GrJsonViewer`, дерево выбора — `GrTree`.\n */\nexport interface GrCodeBlockProps {\n /** Строка или значение: объект сериализуется с отступом. */\n code: unknown\n language?: GrCodeBlockLanguage\n /** Высота, после которой включается вертикальный скролл. */\n maxHeight?: string | number\n /** Кнопка копирования. Без защищённого контекста не рисуется вовсе. */\n copyable?: boolean\n /** Переносить длинные строки вместо горизонтальной прокрутки. */\n wrap?: boolean\n lineNumbers?: boolean\n /** Имя области прокрутки. Безымянную скринридер объявляет просто «регион». */\n ariaLabel?: string\n size?: GrComponentSize\n}\n\nexport interface GrCodeBlockEmits {\n /** Текст скопирован. Тост показывает потребитель: у блока своего места для него нет. */\n (e: 'copy', code: string): void\n}\n\nconst props = withDefaults(defineProps<GrCodeBlockProps>(), {\n // Дефолты живут в резолверах ниже: Vue подставил бы свой раньше, чем компонент\n // заглянет в `GrConfigProvider`.\n language: 'json',\n maxHeight: undefined,\n copyable: undefined,\n wrap: undefined,\n lineNumbers: undefined,\n ariaLabel: undefined,\n size: undefined,\n})\n\nconst emit = defineEmits<GrCodeBlockEmits>()\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCodeBlock' })\nconst resolvedCopyable = useGrComponentProp('GrCodeBlock', 'copyable', () => props.copyable, true)\nconst resolvedWrap = useGrComponentProp('GrCodeBlock', 'wrap', () => props.wrap, false)\nconst resolvedLineNumbers = useGrComponentProp('GrCodeBlock', 'lineNumbers', () => props.lineNumbers, false)\n\n/** Единственный источник текста: он же рендерится, он же уходит в буфер. */\nconst source = computed(() => serializeCode(props.code))\n\n/**\n * Разбор идёт по строкам, а не по всему тексту: номер строки — CSS-счётчик, а\n * счётчику нужен элемент на строку. JSON-строка перенос не содержит (он в ней\n * экранирован), поэтому построчная токенизация ничего не рвёт.\n */\nconst lines = computed<GrCodeToken[][]>(() => {\n const rows = source.value.split('\\n')\n\n if (props.language !== 'json')\n return rows.map(row => [{ text: row, kind: 'plain' as const }])\n\n return rows.map(row => tokenizeJson(row))\n})\n\n/**\n * Блок — скроллер по конструкции, а не по замеру. Замер здесь означал бы\n * мигающую остановку `Tab` на каждой смене данных и загрузке шрифта; ни один\n * компонент пакета так не делает.\n */\nconst isScroller = computed(() => props.maxHeight !== undefined || !resolvedWrap.value)\n\nconst scrollStyle = computed(() => {\n if (props.maxHeight === undefined)\n return undefined\n\n return { maxHeight: typeof props.maxHeight === 'number' ? `${props.maxHeight}px` : props.maxHeight }\n})\n\nconst preClass = computed(() => [\n codeBlockHookClass,\n codeBlockSurfaceClass,\n codeBlockPaddings[resolvedSize.value],\n codeBlockTextSizes[resolvedSize.value],\n resolvedWrap.value ? codeBlockWrapClass : codeBlockNowrapClass,\n isScroller.value ? codeBlockScrollClass : '',\n].filter(Boolean).join(' '))\n\n/**\n * Наличие буфера уточняется после монтирования: `navigator` в теле `setup` либо\n * роняет серверный рендер, либо расходится с ним. До этого момента кнопки нет —\n * ровно то же, что отдаёт сервер, поэтому гидрация совпадает.\n */\nconst canCopy = ref(false)\n\nonMounted(() => {\n canCopy.value = typeof navigator !== 'undefined' && typeof navigator.clipboard?.writeText === 'function'\n})\n\nconst showCopy = computed(() => resolvedCopyable.value && canCopy.value)\n\nconst copied = ref(false)\nlet copiedTimer: number | null = null\n\nfunction resetCopiedTimer(): void {\n if (copiedTimer !== null) {\n clearTimeout(copiedTimer)\n copiedTimer = null\n }\n}\n\nonBeforeUnmount(resetCopiedTimer)\n\nasync function copy(): Promise<void> {\n try {\n // Копируется исходный текст, а не разметка: номера строк — CSS-счётчик,\n // а мягкие переносы принадлежат показу, и вставить их обратно нельзя.\n await navigator.clipboard.writeText(source.value)\n }\n catch {\n announce(t('gr.codeBlock.copyFailed', 'Could not copy code'))\n return\n }\n\n copied.value = true\n resetCopiedTimer()\n copiedTimer = window.setTimeout(() => {\n copied.value = false\n copiedTimer = null\n }, 1200)\n\n announce(t('gr.codeBlock.copied', 'Code copied'))\n emit('copy', source.value)\n}\n\nconst copyLabel = computed(() => (\n copied.value ? t('gr.codeBlock.copied', 'Code copied') : t('gr.codeBlock.copy', 'Copy code')\n))\n</script>\n\n<template>\n <div data-gr-code-block :class=\"[codeBlockRootClass, showCopy ? codeBlockGutterClass : '']\">\n <GrButton\n v-if=\"showCopy\"\n data-gr-code-block-copy\n variant=\"ghost\"\n size=\"xs\"\n square\n :class=\"codeBlockCopyClass\"\n :aria-label=\"copyLabel\"\n :title=\"copyLabel\"\n @click=\"copy\"\n >\n <component :is=\"copied ? IconCheck : IconCopy\" class=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </GrButton>\n\n <!--\n Внутри `<pre>` пробелы значимы, и компилятор Vue их здесь не схлопывает:\n любой перенос между тегами стал бы пустой строкой в коде. Поэтому\n содержимое блока записано без переносов — строки разделяет `display: block`\n у `.gr-code-block__line`, а не текстовый `\\n`.\n -->\n <pre\n data-gr-code-block-scroll\n :class=\"[preClass, resolvedLineNumbers ? numberedClass : '']\"\n :style=\"scrollStyle\"\n :tabindex=\"isScroller ? 0 : undefined\"\n :role=\"ariaLabel ? 'region' : undefined\"\n :aria-label=\"ariaLabel\"\n ><code data-gr-code-block-code><span v-for=\"(tokens, index) in lines\" :key=\"index\" data-gr-code-block-line class=\"gr-code-block__line\"><span v-for=\"(token, tokenIndex) in tokens\" :key=\"tokenIndex\" :class=\"codeTokenClass[token.kind]\">{{ token.text }}</span></span></code></pre>\n </div>\n</template>\n\n<style>\n/*\n * Номер строки — CSS-счётчик, а не текст в разметке. Разница не косметическая:\n * узел со `<span>2</span>` попадает в выделение мышью, и в буфер уезжает то,\n * что нельзя вставить обратно как код. У `::before` содержимого в DOM нет.\n *\n * Стиль глобальный, а не scoped: правило адресует псевдоэлемент строки, и\n * scoped-атрибут пришлось бы вешать на каждый из них.\n */\n:where(.gr-code-block__line) {\n display: block;\n}\n\n:where(.gr-code-block--numbered) {\n counter-reset: gr-code-line;\n}\n\n/*\n * Висячий отступ: строка сдвинута на ширину колонки номеров, а первая строка\n * возвращена назад отрицательным `text-indent` — туда и встаёт номер. Без этого\n * перенесённая при `wrap` строка начиналась бы под номером, а не под кодом.\n */\n:where(.gr-code-block--numbered .gr-code-block__line) {\n padding-left: calc(var(--gr-code-block-line-number-width, 2.5em) + 1em);\n text-indent: calc(-1 * (var(--gr-code-block-line-number-width, 2.5em) + 1em));\n}\n\n:where(.gr-code-block--numbered .gr-code-block__line)::before {\n counter-increment: gr-code-line;\n content: counter(gr-code-line);\n display: inline-block;\n width: var(--gr-code-block-line-number-width, 2.5em);\n margin-right: 1em;\n text-align: right;\n text-indent: 0;\n color: var(--gr-code-block-line-number, var(--gr-muted-fg));\n user-select: none;\n}\n</style>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrCodeBlock_default } from "./chunks/GrCodeBlock-Dkvkr91t.js";
1
+ import { t as GrCodeBlock_default } from "./chunks/GrCodeBlock-Dp0eEBTZ.js";
2
2
  import { n as grCodeBlockSafelist, t as grCodeBlockConfig } from "../../chunks/config-DolULhjJ.js";
3
3
  export { GrCodeBlock_default as GrCodeBlock, GrCodeBlock_default as default, grCodeBlockConfig, grCodeBlockSafelist };
@@ -1 +1 @@
1
- {"version":3,"file":"GrCollapse-BlW6ybdL.js","names":["$slots"],"sources":["../../../../src/components/GrCollapse/grCollapseContext.ts","../../../../src/components/GrCollapse/GrCollapse.vue","../../../../src/components/GrCollapse/GrCollapse.vue","../../../../src/components/GrCollapse/GrCollapseItem.vue","../../../../src/components/GrCollapse/GrCollapseItem.vue"],"sourcesContent":["import type { ComputedRef, InjectionKey } from 'vue'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nexport type GrCollapseValue = string | number\n\nexport type GrCollapseModelValue = GrCollapseValue | GrCollapseValue[] | undefined\n\n/**\n * Уровень заголовка секции. APG для accordion требует, чтобы он соответствовал\n * структуре страницы: аккордеон в разделе `<h4>` с захардкоженным `<h3>` рвёт\n * навигацию по заголовкам.\n */\nexport const GR_COLLAPSE_HEADING_LEVELS = [2, 3, 4, 5, 6] as const\n\nexport type GrCollapseHeadingLevel = typeof GR_COLLAPSE_HEADING_LEVELS[number]\n\n/** Сторона шеврона относительно заголовка — логическая, не физическая (RTL). */\nexport const GR_COLLAPSE_ICON_POSITIONS = ['start', 'end'] as const\n\nexport type GrCollapseIconPosition = typeof GR_COLLAPSE_ICON_POSITIONS[number]\n\n/**\n * Async-guard на переключение секции: `false` отменяет его. Второй аргумент —\n * куда идёт секция (`true` — раскрывается), чтобы «сохранить изменения?»\n * спрашивалось только на сворачивании.\n */\nexport type GrCollapseBeforeChange = (\n name: GrCollapseValue,\n expanding: boolean,\n) => boolean | void | Promise<boolean | void>\n\nexport type GrCollapseContext = {\n accordion: ComputedRef<boolean>\n disabled: ComputedRef<boolean>\n size: ComputedRef<GrComponentSize>\n headingLevel: ComputedRef<GrCollapseHeadingLevel>\n expandIconPosition: ComputedRef<GrCollapseIconPosition>\n isActive: (name: GrCollapseValue) => boolean\n toggle: (name: GrCollapseValue) => void\n}\n\nexport const GR_COLLAPSE_CONTEXT: InjectionKey<GrCollapseContext> = Symbol('GR_COLLAPSE_CONTEXT')\n","<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\n\nimport GrCard from '../GrCard'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { hasMeaningfulSlotContent } from '../shared/slotNodes'\nimport { grCollapseEmptyClass } from './grCollapseStyles'\n\nimport {\n GR_COLLAPSE_CONTEXT,\n type GrCollapseBeforeChange,\n type GrCollapseContext,\n type GrCollapseHeadingLevel,\n type GrCollapseIconPosition,\n type GrCollapseModelValue,\n type GrCollapseValue,\n} from './grCollapseContext'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport './defaults'\n\n/**\n * GrCollapse — контейнер секций `GrCollapseItem`.\n *\n * @prop modelValue — открытые секции. В `accordion`-режиме — `string|number|undefined`, иначе — массив значений.\n * @prop accordion — режим, когда одновременно может быть открыта только одна секция.\n * @prop disabled — блокирует взаимодействие со всеми секциями.\n * @prop divided — разделители между секциями.\n * @prop borderless — без обёртки в `GrCard`: аккордеон внутри карточки или сайдбара\n * иначе получает вторую рамку и вторую тень.\n * @prop beforeChange — async-guard: `false` отменяет переключение.\n */\nexport interface GrCollapseProps {\n modelValue?: GrCollapseModelValue\n accordion?: boolean\n disabled?: boolean\n divided?: boolean\n borderless?: boolean\n /** Уровень заголовков секций (`h2`…`h6`) — под структуру страницы. */\n headingLevel?: GrCollapseHeadingLevel\n /** Сторона шеврона относительно заголовка. */\n expandIconPosition?: GrCollapseIconPosition\n beforeChange?: GrCollapseBeforeChange\n /** Размер секций. Не задан — берётся из `GrConfigProvider`, иначе `md`. */\n size?: GrComponentSize\n /**\n * Пусто ли. Не задан — считается по содержимому: аккордеон без секций\n * показывает заглушку вместо пустой рамки. `false` подавляет автоопределение —\n * например, когда секции приезжают асинхронно и мигать текстом не надо.\n */\n empty?: boolean\n /** Текст пустого состояния. Слот `#empty` сильнее. */\n emptyText?: string\n}\n\nexport interface GrCollapseEmits {\n (e: 'update:modelValue', value: GrCollapseModelValue): void\n (e: 'change', value: GrCollapseModelValue): void\n}\n\n// Дефолты оформления намеренно `undefined`: «настоящий» дефолт живёт в\n// `useGrComponentProp`, иначе `GrConfigProvider` не отличит заданный пользователем\n// проп от подставленного Vue.\nconst props = withDefaults(defineProps<GrCollapseProps>(), {\n modelValue: undefined,\n accordion: false,\n disabled: false,\n divided: undefined,\n borderless: undefined,\n headingLevel: undefined,\n expandIconPosition: undefined,\n beforeChange: undefined,\n size: undefined,\n empty: undefined,\n emptyText: undefined,\n})\n\nconst emit = defineEmits<GrCollapseEmits>()\n\ndefineSlots<{\n /** Секции аккордеона (`GrCollapseItem`). */\n default?: () => any\n /** Содержимое пустого состояния вместо текста по умолчанию. */\n empty?: () => any\n}>()\n\nconst slots = useSlots()\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCollapse' })\nconst divided = useGrComponentProp('GrCollapse', 'divided', () => props.divided, true)\nconst borderless = useGrComponentProp('GrCollapse', 'borderless', () => props.borderless, false)\nconst headingLevel = useGrComponentProp('GrCollapse', 'headingLevel', () => props.headingLevel, 3)\nconst expandIconPosition = useGrComponentProp('GrCollapse', 'expandIconPosition', () => props.expandIconPosition, 'end')\n\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.collapse.empty', 'Nothing here yet'))\n\n/**\n * Пустоту считает общий разборщик слота: `v-for` приходит фрагментом, `v-if`\n * оставляет после себя комментарий, а шаблон — переносы строк, и всё это не\n * содержимое.\n */\nconst isEmpty = computed(() => {\n if (props.empty !== undefined) return props.empty\n\n return !hasMeaningfulSlotContent(slots.default?.() ?? [])\n})\n\nconst activeSet = computed(() => {\n const value = props.modelValue\n\n if (props.accordion) {\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n }\n\n if (Array.isArray(value)) {\n return new Set<GrCollapseValue>(value)\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n})\n\nfunction setModelValue(next: GrCollapseModelValue): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction applyToggle(name: GrCollapseValue): void {\n if (props.accordion) {\n const next = activeSet.value.has(name) ? undefined : name\n setModelValue(next)\n return\n }\n\n const current = Array.isArray(props.modelValue)\n ? [...props.modelValue]\n : typeof props.modelValue === 'string' || typeof props.modelValue === 'number'\n ? [props.modelValue]\n : []\n\n const exists = current.includes(name)\n const next = exists\n ? current.filter(x => x !== name)\n : [...current, name]\n\n setModelValue(next)\n}\n\n// Секции, у которых guard ещё не ответил. Без этого повторный клик по заголовку\n// уходил бы во второй `beforeChange`, и после двух «да» состояние переключилось\n// бы дважды — то есть вернулось бы к исходному.\nconst awaitingGuard = new Set<GrCollapseValue>()\n\nasync function toggle(name: GrCollapseValue): Promise<void> {\n if (props.disabled || awaitingGuard.has(name))\n return\n\n if (!props.beforeChange) {\n applyToggle(name)\n return\n }\n\n awaitingGuard.add(name)\n try {\n if (await props.beforeChange(name, !activeSet.value.has(name)) === false)\n return\n\n applyToggle(name)\n }\n finally {\n awaitingGuard.delete(name)\n }\n}\n\nconst context: GrCollapseContext = {\n accordion: computed(() => props.accordion),\n disabled: computed(() => props.disabled),\n size: resolvedSize,\n headingLevel,\n expandIconPosition,\n isActive: name => activeSet.value.has(name),\n toggle: (name) => { void toggle(name) },\n}\n\nprovide(GR_COLLAPSE_CONTEXT, context)\n</script>\n\n<template>\n <GrCard v-if=\"!borderless\" data-gr-collapse>\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <div v-else :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\">\n <slot />\n </div>\n </GrCard>\n\n <!-- Разделители остаются на корне: без обёртки в карточку он и есть список\n секций, и лишний уровень вложенности сдвинул бы вёрстку потребителя. -->\n <div\n v-else\n data-gr-collapse\n :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\"\n >\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <slot v-else />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\n\nimport GrCard from '../GrCard'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { hasMeaningfulSlotContent } from '../shared/slotNodes'\nimport { grCollapseEmptyClass } from './grCollapseStyles'\n\nimport {\n GR_COLLAPSE_CONTEXT,\n type GrCollapseBeforeChange,\n type GrCollapseContext,\n type GrCollapseHeadingLevel,\n type GrCollapseIconPosition,\n type GrCollapseModelValue,\n type GrCollapseValue,\n} from './grCollapseContext'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport './defaults'\n\n/**\n * GrCollapse — контейнер секций `GrCollapseItem`.\n *\n * @prop modelValue — открытые секции. В `accordion`-режиме — `string|number|undefined`, иначе — массив значений.\n * @prop accordion — режим, когда одновременно может быть открыта только одна секция.\n * @prop disabled — блокирует взаимодействие со всеми секциями.\n * @prop divided — разделители между секциями.\n * @prop borderless — без обёртки в `GrCard`: аккордеон внутри карточки или сайдбара\n * иначе получает вторую рамку и вторую тень.\n * @prop beforeChange — async-guard: `false` отменяет переключение.\n */\nexport interface GrCollapseProps {\n modelValue?: GrCollapseModelValue\n accordion?: boolean\n disabled?: boolean\n divided?: boolean\n borderless?: boolean\n /** Уровень заголовков секций (`h2`…`h6`) — под структуру страницы. */\n headingLevel?: GrCollapseHeadingLevel\n /** Сторона шеврона относительно заголовка. */\n expandIconPosition?: GrCollapseIconPosition\n beforeChange?: GrCollapseBeforeChange\n /** Размер секций. Не задан — берётся из `GrConfigProvider`, иначе `md`. */\n size?: GrComponentSize\n /**\n * Пусто ли. Не задан — считается по содержимому: аккордеон без секций\n * показывает заглушку вместо пустой рамки. `false` подавляет автоопределение —\n * например, когда секции приезжают асинхронно и мигать текстом не надо.\n */\n empty?: boolean\n /** Текст пустого состояния. Слот `#empty` сильнее. */\n emptyText?: string\n}\n\nexport interface GrCollapseEmits {\n (e: 'update:modelValue', value: GrCollapseModelValue): void\n (e: 'change', value: GrCollapseModelValue): void\n}\n\n// Дефолты оформления намеренно `undefined`: «настоящий» дефолт живёт в\n// `useGrComponentProp`, иначе `GrConfigProvider` не отличит заданный пользователем\n// проп от подставленного Vue.\nconst props = withDefaults(defineProps<GrCollapseProps>(), {\n modelValue: undefined,\n accordion: false,\n disabled: false,\n divided: undefined,\n borderless: undefined,\n headingLevel: undefined,\n expandIconPosition: undefined,\n beforeChange: undefined,\n size: undefined,\n empty: undefined,\n emptyText: undefined,\n})\n\nconst emit = defineEmits<GrCollapseEmits>()\n\ndefineSlots<{\n /** Секции аккордеона (`GrCollapseItem`). */\n default?: () => any\n /** Содержимое пустого состояния вместо текста по умолчанию. */\n empty?: () => any\n}>()\n\nconst slots = useSlots()\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCollapse' })\nconst divided = useGrComponentProp('GrCollapse', 'divided', () => props.divided, true)\nconst borderless = useGrComponentProp('GrCollapse', 'borderless', () => props.borderless, false)\nconst headingLevel = useGrComponentProp('GrCollapse', 'headingLevel', () => props.headingLevel, 3)\nconst expandIconPosition = useGrComponentProp('GrCollapse', 'expandIconPosition', () => props.expandIconPosition, 'end')\n\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.collapse.empty', 'Nothing here yet'))\n\n/**\n * Пустоту считает общий разборщик слота: `v-for` приходит фрагментом, `v-if`\n * оставляет после себя комментарий, а шаблон — переносы строк, и всё это не\n * содержимое.\n */\nconst isEmpty = computed(() => {\n if (props.empty !== undefined) return props.empty\n\n return !hasMeaningfulSlotContent(slots.default?.() ?? [])\n})\n\nconst activeSet = computed(() => {\n const value = props.modelValue\n\n if (props.accordion) {\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n }\n\n if (Array.isArray(value)) {\n return new Set<GrCollapseValue>(value)\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n})\n\nfunction setModelValue(next: GrCollapseModelValue): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction applyToggle(name: GrCollapseValue): void {\n if (props.accordion) {\n const next = activeSet.value.has(name) ? undefined : name\n setModelValue(next)\n return\n }\n\n const current = Array.isArray(props.modelValue)\n ? [...props.modelValue]\n : typeof props.modelValue === 'string' || typeof props.modelValue === 'number'\n ? [props.modelValue]\n : []\n\n const exists = current.includes(name)\n const next = exists\n ? current.filter(x => x !== name)\n : [...current, name]\n\n setModelValue(next)\n}\n\n// Секции, у которых guard ещё не ответил. Без этого повторный клик по заголовку\n// уходил бы во второй `beforeChange`, и после двух «да» состояние переключилось\n// бы дважды — то есть вернулось бы к исходному.\nconst awaitingGuard = new Set<GrCollapseValue>()\n\nasync function toggle(name: GrCollapseValue): Promise<void> {\n if (props.disabled || awaitingGuard.has(name))\n return\n\n if (!props.beforeChange) {\n applyToggle(name)\n return\n }\n\n awaitingGuard.add(name)\n try {\n if (await props.beforeChange(name, !activeSet.value.has(name)) === false)\n return\n\n applyToggle(name)\n }\n finally {\n awaitingGuard.delete(name)\n }\n}\n\nconst context: GrCollapseContext = {\n accordion: computed(() => props.accordion),\n disabled: computed(() => props.disabled),\n size: resolvedSize,\n headingLevel,\n expandIconPosition,\n isActive: name => activeSet.value.has(name),\n toggle: (name) => { void toggle(name) },\n}\n\nprovide(GR_COLLAPSE_CONTEXT, context)\n</script>\n\n<template>\n <GrCard v-if=\"!borderless\" data-gr-collapse>\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <div v-else :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\">\n <slot />\n </div>\n </GrCard>\n\n <!-- Разделители остаются на корне: без обёртки в карточку он и есть список\n секций, и лишний уровень вложенности сдвинул бы вёрстку потребителя. -->\n <div\n v-else\n data-gr-collapse\n :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\"\n >\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <slot v-else />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ChevronDownIcon from '~icons/lucide/chevron-down'\nimport { computed, inject, ref, useId } from 'vue'\n\nimport GrIcon from '../GrIcon'\n\nimport { GR_COLLAPSE_CONTEXT, type GrCollapseValue } from './grCollapseContext'\nimport {\n collapseChevronSizes,\n collapseExtraPaddings,\n grCollapseBodyClass,\n grCollapseChevronClass,\n grCollapseHeaderClass,\n grCollapseRowClass,\n grCollapseTitleClass,\n} from './grCollapseStyles'\n\n/**\n * GrCollapseItem — одна секция `GrCollapse`. Должна использоваться строго внутри `GrCollapse`.\n *\n * @prop name — уникальный идентификатор секции (для `v-model` у `GrCollapse`); по умолчанию генерируется из `uid`.\n * @prop title — текст заголовка; можно заменить слотом `#title`.\n * @prop disabled — запрещает раскрытие/сворачивание секции.\n *\n * Слот `#extra` (счётчик, бейдж, кнопка) рендерится **рядом с** триггером, а не\n * внутри него: `<button>` внутри `<button>` — невалидная разметка, а axe ловит\n * это как `nested-interactive`.\n */\nexport interface GrCollapseItemProps {\n name?: GrCollapseValue\n title?: string\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<GrCollapseItemProps>(), {\n name: undefined,\n title: undefined,\n disabled: false,\n})\n\nconst collapse = inject(GR_COLLAPSE_CONTEXT)\n\nif (!collapse) {\n throw new Error('GrCollapseItem must be used inside GrCollapse')\n}\n\nconst collapseContext = collapse\n\nconst uid = useId()\n\nconst resolvedName = computed<GrCollapseValue>(() => {\n if (typeof props.name === 'string' || typeof props.name === 'number')\n return props.name\n\n return uid\n})\n\nconst resolvedDisabled = computed(() => collapseContext.disabled.value || props.disabled)\nconst expanded = computed(() => collapseContext.isActive(resolvedName.value))\n\nconst headingTag = computed(() => `h${collapseContext.headingLevel.value}`)\nconst iconAtStart = computed(() => collapseContext.expandIconPosition.value === 'start')\n\nconst rowClassName = computed(() => grCollapseRowClass(resolvedDisabled.value))\nconst headerClassName = computed(() => grCollapseHeaderClass({\n size: collapseContext.size.value,\n disabled: resolvedDisabled.value,\n}))\nconst extraClassName = computed(() => collapseExtraPaddings[collapseContext.size.value])\nconst titleClassName = computed(() => grCollapseTitleClass(collapseContext.size.value))\nconst bodyClassName = computed(() => grCollapseBodyClass(collapseContext.size.value))\nconst chevronClassName = computed(() => grCollapseChevronClass(expanded.value))\nconst chevronSize = computed(() => collapseChevronSizes[collapseContext.size.value])\n\n// Свёрнутая панель схлопывается визуально (`grid-rows-[0fr]`), но это не\n// скрытие: без `inert` ссылки и кнопки внутри неё ловятся Tab'ом, фокус уезжает\n// в невидимую область нулевой высоты, а скринридер читает содержимое всех\n// закрытых секций подряд — прямо вопреки `aria-expanded=\"false\"` на триггере.\n// `inert` убирает поддерево и из таб-порядка, и из дерева доступности, при этом\n// (в отличие от `hidden`/`display:none`) не ломает анимацию раскрытия.\nconst headerId = `gr-collapse-header-${uid}`\nconst panelId = `gr-collapse-panel-${uid}`\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction onToggle(): void {\n if (resolvedDisabled.value)\n return\n\n collapseContext.toggle(resolvedName.value)\n}\n\n/**\n * Только заголовки **своего** аккордеона: вложенный `GrCollapse` внутри\n * раскрытой панели тоже помечен `[data-gr-collapse]`, и без фильтра стрелки\n * внешнего аккордеона перескакивали бы на заголовки внутреннего.\n */\nfunction getAllTriggers(): HTMLElement[] {\n const root = triggerEl.value?.closest('[data-gr-collapse]')\n if (!root)\n return []\n\n const triggers = Array.prototype.slice.call(\n root.querySelectorAll<HTMLElement>('[data-gr-collapse-trigger]'),\n ) as HTMLElement[]\n\n return triggers.filter(trigger => trigger.closest('[data-gr-collapse]') === root)\n}\n\nfunction focusRelative(direction: 1 | -1): void {\n const current = triggerEl.value\n if (!current)\n return\n\n const triggers = getAllTriggers()\n const index = triggers.indexOf(current)\n if (index === -1 || triggers.length === 0)\n return\n\n const nextIndex = (index + direction + triggers.length) % triggers.length\n triggers[nextIndex]?.focus()\n}\n\nfunction focusEdge(edge: 'start' | 'end'): void {\n const triggers = getAllTriggers()\n if (triggers.length === 0)\n return\n\n ;(edge === 'start' ? triggers[0] : triggers.at(-1))?.focus()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n focusRelative(1)\n return\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n focusRelative(-1)\n return\n }\n\n if (event.key === 'Home') {\n event.preventDefault()\n focusEdge('start')\n return\n }\n\n if (event.key === 'End') {\n event.preventDefault()\n focusEdge('end')\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n onToggle()\n }\n}\n\ndefineSlots<{\n /** Содержимое секции. */\n default?: () => any\n /** Заголовок секции вместо пропа `title`. */\n title?: () => any\n /** Иконка-указатель вместо шеврона. */\n icon?: () => any\n /** Управление справа в заголовке: счётчик, переключатель, кнопка. */\n extra?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-collapse-item\n class=\"text-[var(--gr-fg)]\"\n >\n <div :class=\"rowClassName\">\n <component\n :is=\"headingTag\"\n class=\"m-0 min-w-0 flex-1\"\n >\n <button\n :id=\"headerId\"\n ref=\"triggerEl\"\n data-gr-collapse-trigger\n type=\"button\"\n :aria-expanded=\"expanded ? 'true' : 'false'\"\n :aria-controls=\"panelId\"\n :disabled=\"resolvedDisabled\"\n :class=\"headerClassName\"\n @click=\"onToggle\"\n @keydown=\"onKeydown\"\n >\n <GrIcon\n v-if=\"iconAtStart\"\n :size=\"chevronSize\"\n \n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n\n <span :class=\"titleClassName\">\n <slot name=\"title\">\n <span class=\"font-600\">\n {{ title }}\n </span>\n </slot>\n </span>\n\n <GrIcon\n v-if=\"!iconAtStart\"\n :size=\"chevronSize\"\n \n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n </button>\n </component>\n\n <div\n v-if=\"$slots.extra\"\n data-gr-collapse-extra\n class=\"shrink-0\"\n :class=\"extraClassName\"\n >\n <slot name=\"extra\" />\n </div>\n </div>\n\n <div\n :id=\"panelId\"\n role=\"region\"\n :aria-labelledby=\"headerId\"\n :inert=\"expanded ? undefined : true\"\n class=\"grid transition-[grid-template-rows] duration-[var(--gr-duration-base)]\"\n :class=\"expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'\"\n >\n <div class=\"overflow-hidden\">\n <div :class=\"bodyClassName\">\n <slot />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ChevronDownIcon from '~icons/lucide/chevron-down'\nimport { computed, inject, ref, useId } from 'vue'\n\nimport GrIcon from '../GrIcon'\n\nimport { GR_COLLAPSE_CONTEXT, type GrCollapseValue } from './grCollapseContext'\nimport {\n collapseChevronSizes,\n collapseExtraPaddings,\n grCollapseBodyClass,\n grCollapseChevronClass,\n grCollapseHeaderClass,\n grCollapseRowClass,\n grCollapseTitleClass,\n} from './grCollapseStyles'\n\n/**\n * GrCollapseItem — одна секция `GrCollapse`. Должна использоваться строго внутри `GrCollapse`.\n *\n * @prop name — уникальный идентификатор секции (для `v-model` у `GrCollapse`); по умолчанию генерируется из `uid`.\n * @prop title — текст заголовка; можно заменить слотом `#title`.\n * @prop disabled — запрещает раскрытие/сворачивание секции.\n *\n * Слот `#extra` (счётчик, бейдж, кнопка) рендерится **рядом с** триггером, а не\n * внутри него: `<button>` внутри `<button>` — невалидная разметка, а axe ловит\n * это как `nested-interactive`.\n */\nexport interface GrCollapseItemProps {\n name?: GrCollapseValue\n title?: string\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<GrCollapseItemProps>(), {\n name: undefined,\n title: undefined,\n disabled: false,\n})\n\nconst collapse = inject(GR_COLLAPSE_CONTEXT)\n\nif (!collapse) {\n throw new Error('GrCollapseItem must be used inside GrCollapse')\n}\n\nconst collapseContext = collapse\n\nconst uid = useId()\n\nconst resolvedName = computed<GrCollapseValue>(() => {\n if (typeof props.name === 'string' || typeof props.name === 'number')\n return props.name\n\n return uid\n})\n\nconst resolvedDisabled = computed(() => collapseContext.disabled.value || props.disabled)\nconst expanded = computed(() => collapseContext.isActive(resolvedName.value))\n\nconst headingTag = computed(() => `h${collapseContext.headingLevel.value}`)\nconst iconAtStart = computed(() => collapseContext.expandIconPosition.value === 'start')\n\nconst rowClassName = computed(() => grCollapseRowClass(resolvedDisabled.value))\nconst headerClassName = computed(() => grCollapseHeaderClass({\n size: collapseContext.size.value,\n disabled: resolvedDisabled.value,\n}))\nconst extraClassName = computed(() => collapseExtraPaddings[collapseContext.size.value])\nconst titleClassName = computed(() => grCollapseTitleClass(collapseContext.size.value))\nconst bodyClassName = computed(() => grCollapseBodyClass(collapseContext.size.value))\nconst chevronClassName = computed(() => grCollapseChevronClass(expanded.value))\nconst chevronSize = computed(() => collapseChevronSizes[collapseContext.size.value])\n\n// Свёрнутая панель схлопывается визуально (`grid-rows-[0fr]`), но это не\n// скрытие: без `inert` ссылки и кнопки внутри неё ловятся Tab'ом, фокус уезжает\n// в невидимую область нулевой высоты, а скринридер читает содержимое всех\n// закрытых секций подряд — прямо вопреки `aria-expanded=\"false\"` на триггере.\n// `inert` убирает поддерево и из таб-порядка, и из дерева доступности, при этом\n// (в отличие от `hidden`/`display:none`) не ломает анимацию раскрытия.\nconst headerId = `gr-collapse-header-${uid}`\nconst panelId = `gr-collapse-panel-${uid}`\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction onToggle(): void {\n if (resolvedDisabled.value)\n return\n\n collapseContext.toggle(resolvedName.value)\n}\n\n/**\n * Только заголовки **своего** аккордеона: вложенный `GrCollapse` внутри\n * раскрытой панели тоже помечен `[data-gr-collapse]`, и без фильтра стрелки\n * внешнего аккордеона перескакивали бы на заголовки внутреннего.\n */\nfunction getAllTriggers(): HTMLElement[] {\n const root = triggerEl.value?.closest('[data-gr-collapse]')\n if (!root)\n return []\n\n const triggers = Array.prototype.slice.call(\n root.querySelectorAll<HTMLElement>('[data-gr-collapse-trigger]'),\n ) as HTMLElement[]\n\n return triggers.filter(trigger => trigger.closest('[data-gr-collapse]') === root)\n}\n\nfunction focusRelative(direction: 1 | -1): void {\n const current = triggerEl.value\n if (!current)\n return\n\n const triggers = getAllTriggers()\n const index = triggers.indexOf(current)\n if (index === -1 || triggers.length === 0)\n return\n\n const nextIndex = (index + direction + triggers.length) % triggers.length\n triggers[nextIndex]?.focus()\n}\n\nfunction focusEdge(edge: 'start' | 'end'): void {\n const triggers = getAllTriggers()\n if (triggers.length === 0)\n return\n\n ;(edge === 'start' ? triggers[0] : triggers.at(-1))?.focus()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n focusRelative(1)\n return\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n focusRelative(-1)\n return\n }\n\n if (event.key === 'Home') {\n event.preventDefault()\n focusEdge('start')\n return\n }\n\n if (event.key === 'End') {\n event.preventDefault()\n focusEdge('end')\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n onToggle()\n }\n}\n\ndefineSlots<{\n /** Содержимое секции. */\n default?: () => any\n /** Заголовок секции вместо пропа `title`. */\n title?: () => any\n /** Иконка-указатель вместо шеврона. */\n icon?: () => any\n /** Управление справа в заголовке: счётчик, переключатель, кнопка. */\n extra?: () => any\n}>()\n\n</script>\n\n<template>\n <div\n data-gr-collapse-item\n class=\"text-[var(--gr-fg)]\"\n >\n <div :class=\"rowClassName\">\n <component\n :is=\"headingTag\"\n class=\"m-0 min-w-0 flex-1\"\n >\n <button\n :id=\"headerId\"\n ref=\"triggerEl\"\n data-gr-collapse-trigger\n type=\"button\"\n :aria-expanded=\"expanded ? 'true' : 'false'\"\n :aria-controls=\"panelId\"\n :disabled=\"resolvedDisabled\"\n :class=\"headerClassName\"\n @click=\"onToggle\"\n @keydown=\"onKeydown\"\n >\n <GrIcon\n v-if=\"iconAtStart\"\n :size=\"chevronSize\"\n \n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n\n <span :class=\"titleClassName\">\n <slot name=\"title\">\n <span class=\"font-600\">\n {{ title }}\n </span>\n </slot>\n </span>\n\n <GrIcon\n v-if=\"!iconAtStart\"\n :size=\"chevronSize\"\n \n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n </button>\n </component>\n\n <div\n v-if=\"$slots.extra\"\n data-gr-collapse-extra\n class=\"shrink-0\"\n :class=\"extraClassName\"\n >\n <slot name=\"extra\" />\n </div>\n </div>\n\n <div\n :id=\"panelId\"\n role=\"region\"\n :aria-labelledby=\"headerId\"\n :inert=\"expanded ? undefined : true\"\n class=\"grid transition-[grid-template-rows] duration-[var(--gr-duration-base)]\"\n :class=\"expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'\"\n >\n <div class=\"overflow-hidden\">\n <div :class=\"bodyClassName\">\n <slot />\n </div>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrCollapse-BlW6ybdL.js","names":["$slots"],"sources":["../../../../src/components/GrCollapse/grCollapseContext.ts","../../../../src/components/GrCollapse/GrCollapse.vue","../../../../src/components/GrCollapse/GrCollapse.vue","../../../../src/components/GrCollapse/GrCollapseItem.vue","../../../../src/components/GrCollapse/GrCollapseItem.vue"],"sourcesContent":["import type { ComputedRef, InjectionKey } from 'vue'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nexport type GrCollapseValue = string | number\n\nexport type GrCollapseModelValue = GrCollapseValue | GrCollapseValue[] | undefined\n\n/**\n * Уровень заголовка секции. APG для accordion требует, чтобы он соответствовал\n * структуре страницы: аккордеон в разделе `<h4>` с захардкоженным `<h3>` рвёт\n * навигацию по заголовкам.\n */\nexport const GR_COLLAPSE_HEADING_LEVELS = [2, 3, 4, 5, 6] as const\n\nexport type GrCollapseHeadingLevel = typeof GR_COLLAPSE_HEADING_LEVELS[number]\n\n/** Сторона шеврона относительно заголовка — логическая, не физическая (RTL). */\nexport const GR_COLLAPSE_ICON_POSITIONS = ['start', 'end'] as const\n\nexport type GrCollapseIconPosition = typeof GR_COLLAPSE_ICON_POSITIONS[number]\n\n/**\n * Async-guard на переключение секции: `false` отменяет его. Второй аргумент —\n * куда идёт секция (`true` — раскрывается), чтобы «сохранить изменения?»\n * спрашивалось только на сворачивании.\n */\nexport type GrCollapseBeforeChange = (\n name: GrCollapseValue,\n expanding: boolean,\n) => boolean | void | Promise<boolean | void>\n\nexport type GrCollapseContext = {\n accordion: ComputedRef<boolean>\n disabled: ComputedRef<boolean>\n size: ComputedRef<GrComponentSize>\n headingLevel: ComputedRef<GrCollapseHeadingLevel>\n expandIconPosition: ComputedRef<GrCollapseIconPosition>\n isActive: (name: GrCollapseValue) => boolean\n toggle: (name: GrCollapseValue) => void\n}\n\nexport const GR_COLLAPSE_CONTEXT: InjectionKey<GrCollapseContext> = Symbol('GR_COLLAPSE_CONTEXT')\n","<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\n\nimport GrCard from '../GrCard'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { hasMeaningfulSlotContent } from '../shared/slotNodes'\nimport { grCollapseEmptyClass } from './grCollapseStyles'\n\nimport {\n GR_COLLAPSE_CONTEXT,\n type GrCollapseBeforeChange,\n type GrCollapseContext,\n type GrCollapseHeadingLevel,\n type GrCollapseIconPosition,\n type GrCollapseModelValue,\n type GrCollapseValue,\n} from './grCollapseContext'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport './defaults'\n\n/**\n * GrCollapse — контейнер секций `GrCollapseItem`.\n *\n * @prop modelValue — открытые секции. В `accordion`-режиме — `string|number|undefined`, иначе — массив значений.\n * @prop accordion — режим, когда одновременно может быть открыта только одна секция.\n * @prop disabled — блокирует взаимодействие со всеми секциями.\n * @prop divided — разделители между секциями.\n * @prop borderless — без обёртки в `GrCard`: аккордеон внутри карточки или сайдбара\n * иначе получает вторую рамку и вторую тень.\n * @prop beforeChange — async-guard: `false` отменяет переключение.\n */\nexport interface GrCollapseProps {\n modelValue?: GrCollapseModelValue\n accordion?: boolean\n disabled?: boolean\n divided?: boolean\n borderless?: boolean\n /** Уровень заголовков секций (`h2`…`h6`) — под структуру страницы. */\n headingLevel?: GrCollapseHeadingLevel\n /** Сторона шеврона относительно заголовка. */\n expandIconPosition?: GrCollapseIconPosition\n beforeChange?: GrCollapseBeforeChange\n /** Размер секций. Не задан — берётся из `GrConfigProvider`, иначе `md`. */\n size?: GrComponentSize\n /**\n * Пусто ли. Не задан — считается по содержимому: аккордеон без секций\n * показывает заглушку вместо пустой рамки. `false` подавляет автоопределение —\n * например, когда секции приезжают асинхронно и мигать текстом не надо.\n */\n empty?: boolean\n /** Текст пустого состояния. Слот `#empty` сильнее. */\n emptyText?: string\n}\n\nexport interface GrCollapseEmits {\n (e: 'update:modelValue', value: GrCollapseModelValue): void\n (e: 'change', value: GrCollapseModelValue): void\n}\n\n// Дефолты оформления намеренно `undefined`: «настоящий» дефолт живёт в\n// `useGrComponentProp`, иначе `GrConfigProvider` не отличит заданный пользователем\n// проп от подставленного Vue.\nconst props = withDefaults(defineProps<GrCollapseProps>(), {\n modelValue: undefined,\n accordion: false,\n disabled: false,\n divided: undefined,\n borderless: undefined,\n headingLevel: undefined,\n expandIconPosition: undefined,\n beforeChange: undefined,\n size: undefined,\n empty: undefined,\n emptyText: undefined,\n})\n\nconst emit = defineEmits<GrCollapseEmits>()\n\ndefineSlots<{\n /** Секции аккордеона (`GrCollapseItem`). */\n default?: () => any\n /** Содержимое пустого состояния вместо текста по умолчанию. */\n empty?: () => any\n}>()\n\nconst slots = useSlots()\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCollapse' })\nconst divided = useGrComponentProp('GrCollapse', 'divided', () => props.divided, true)\nconst borderless = useGrComponentProp('GrCollapse', 'borderless', () => props.borderless, false)\nconst headingLevel = useGrComponentProp('GrCollapse', 'headingLevel', () => props.headingLevel, 3)\nconst expandIconPosition = useGrComponentProp('GrCollapse', 'expandIconPosition', () => props.expandIconPosition, 'end')\n\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.collapse.empty', 'Nothing here yet'))\n\n/**\n * Пустоту считает общий разборщик слота: `v-for` приходит фрагментом, `v-if`\n * оставляет после себя комментарий, а шаблон — переносы строк, и всё это не\n * содержимое.\n */\nconst isEmpty = computed(() => {\n if (props.empty !== undefined)\n return props.empty\n\n return !hasMeaningfulSlotContent(slots.default?.() ?? [])\n})\n\nconst activeSet = computed(() => {\n const value = props.modelValue\n\n if (props.accordion) {\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n }\n\n if (Array.isArray(value)) {\n return new Set<GrCollapseValue>(value)\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n})\n\nfunction setModelValue(next: GrCollapseModelValue): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction applyToggle(name: GrCollapseValue): void {\n if (props.accordion) {\n const next = activeSet.value.has(name) ? undefined : name\n setModelValue(next)\n return\n }\n\n const current = Array.isArray(props.modelValue)\n ? [...props.modelValue]\n : typeof props.modelValue === 'string' || typeof props.modelValue === 'number'\n ? [props.modelValue]\n : []\n\n const exists = current.includes(name)\n const next = exists\n ? current.filter(x => x !== name)\n : [...current, name]\n\n setModelValue(next)\n}\n\n// Секции, у которых guard ещё не ответил. Без этого повторный клик по заголовку\n// уходил бы во второй `beforeChange`, и после двух «да» состояние переключилось\n// бы дважды — то есть вернулось бы к исходному.\nconst awaitingGuard = new Set<GrCollapseValue>()\n\nasync function toggle(name: GrCollapseValue): Promise<void> {\n if (props.disabled || awaitingGuard.has(name))\n return\n\n if (!props.beforeChange) {\n applyToggle(name)\n return\n }\n\n awaitingGuard.add(name)\n try {\n if (await props.beforeChange(name, !activeSet.value.has(name)) === false)\n return\n\n applyToggle(name)\n }\n finally {\n awaitingGuard.delete(name)\n }\n}\n\nconst context: GrCollapseContext = {\n accordion: computed(() => props.accordion),\n disabled: computed(() => props.disabled),\n size: resolvedSize,\n headingLevel,\n expandIconPosition,\n isActive: name => activeSet.value.has(name),\n toggle: (name) => { void toggle(name) },\n}\n\nprovide(GR_COLLAPSE_CONTEXT, context)\n</script>\n\n<template>\n <GrCard v-if=\"!borderless\" data-gr-collapse>\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <div v-else :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\">\n <slot />\n </div>\n </GrCard>\n\n <!-- Разделители остаются на корне: без обёртки в карточку он и есть список\n секций, и лишний уровень вложенности сдвинул бы вёрстку потребителя. -->\n <div\n v-else\n data-gr-collapse\n :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\"\n >\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <slot v-else />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, provide, useSlots } from 'vue'\n\nimport GrCard from '../GrCard'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { hasMeaningfulSlotContent } from '../shared/slotNodes'\nimport { grCollapseEmptyClass } from './grCollapseStyles'\n\nimport {\n GR_COLLAPSE_CONTEXT,\n type GrCollapseBeforeChange,\n type GrCollapseContext,\n type GrCollapseHeadingLevel,\n type GrCollapseIconPosition,\n type GrCollapseModelValue,\n type GrCollapseValue,\n} from './grCollapseContext'\n\nimport type { GrComponentSize } from '../shared/sizes'\n\nimport './defaults'\n\n/**\n * GrCollapse — контейнер секций `GrCollapseItem`.\n *\n * @prop modelValue — открытые секции. В `accordion`-режиме — `string|number|undefined`, иначе — массив значений.\n * @prop accordion — режим, когда одновременно может быть открыта только одна секция.\n * @prop disabled — блокирует взаимодействие со всеми секциями.\n * @prop divided — разделители между секциями.\n * @prop borderless — без обёртки в `GrCard`: аккордеон внутри карточки или сайдбара\n * иначе получает вторую рамку и вторую тень.\n * @prop beforeChange — async-guard: `false` отменяет переключение.\n */\nexport interface GrCollapseProps {\n modelValue?: GrCollapseModelValue\n accordion?: boolean\n disabled?: boolean\n divided?: boolean\n borderless?: boolean\n /** Уровень заголовков секций (`h2`…`h6`) — под структуру страницы. */\n headingLevel?: GrCollapseHeadingLevel\n /** Сторона шеврона относительно заголовка. */\n expandIconPosition?: GrCollapseIconPosition\n beforeChange?: GrCollapseBeforeChange\n /** Размер секций. Не задан — берётся из `GrConfigProvider`, иначе `md`. */\n size?: GrComponentSize\n /**\n * Пусто ли. Не задан — считается по содержимому: аккордеон без секций\n * показывает заглушку вместо пустой рамки. `false` подавляет автоопределение —\n * например, когда секции приезжают асинхронно и мигать текстом не надо.\n */\n empty?: boolean\n /** Текст пустого состояния. Слот `#empty` сильнее. */\n emptyText?: string\n}\n\nexport interface GrCollapseEmits {\n (e: 'update:modelValue', value: GrCollapseModelValue): void\n (e: 'change', value: GrCollapseModelValue): void\n}\n\n// Дефолты оформления намеренно `undefined`: «настоящий» дефолт живёт в\n// `useGrComponentProp`, иначе `GrConfigProvider` не отличит заданный пользователем\n// проп от подставленного Vue.\nconst props = withDefaults(defineProps<GrCollapseProps>(), {\n modelValue: undefined,\n accordion: false,\n disabled: false,\n divided: undefined,\n borderless: undefined,\n headingLevel: undefined,\n expandIconPosition: undefined,\n beforeChange: undefined,\n size: undefined,\n empty: undefined,\n emptyText: undefined,\n})\n\nconst emit = defineEmits<GrCollapseEmits>()\n\ndefineSlots<{\n /** Секции аккордеона (`GrCollapseItem`). */\n default?: () => any\n /** Содержимое пустого состояния вместо текста по умолчанию. */\n empty?: () => any\n}>()\n\nconst slots = useSlots()\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrCollapse' })\nconst divided = useGrComponentProp('GrCollapse', 'divided', () => props.divided, true)\nconst borderless = useGrComponentProp('GrCollapse', 'borderless', () => props.borderless, false)\nconst headingLevel = useGrComponentProp('GrCollapse', 'headingLevel', () => props.headingLevel, 3)\nconst expandIconPosition = useGrComponentProp('GrCollapse', 'expandIconPosition', () => props.expandIconPosition, 'end')\n\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.collapse.empty', 'Nothing here yet'))\n\n/**\n * Пустоту считает общий разборщик слота: `v-for` приходит фрагментом, `v-if`\n * оставляет после себя комментарий, а шаблон — переносы строк, и всё это не\n * содержимое.\n */\nconst isEmpty = computed(() => {\n if (props.empty !== undefined)\n return props.empty\n\n return !hasMeaningfulSlotContent(slots.default?.() ?? [])\n})\n\nconst activeSet = computed(() => {\n const value = props.modelValue\n\n if (props.accordion) {\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n }\n\n if (Array.isArray(value)) {\n return new Set<GrCollapseValue>(value)\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n return new Set<GrCollapseValue>([value])\n }\n\n return new Set<GrCollapseValue>()\n})\n\nfunction setModelValue(next: GrCollapseModelValue): void {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction applyToggle(name: GrCollapseValue): void {\n if (props.accordion) {\n const next = activeSet.value.has(name) ? undefined : name\n setModelValue(next)\n return\n }\n\n const current = Array.isArray(props.modelValue)\n ? [...props.modelValue]\n : typeof props.modelValue === 'string' || typeof props.modelValue === 'number'\n ? [props.modelValue]\n : []\n\n const exists = current.includes(name)\n const next = exists\n ? current.filter(x => x !== name)\n : [...current, name]\n\n setModelValue(next)\n}\n\n// Секции, у которых guard ещё не ответил. Без этого повторный клик по заголовку\n// уходил бы во второй `beforeChange`, и после двух «да» состояние переключилось\n// бы дважды — то есть вернулось бы к исходному.\nconst awaitingGuard = new Set<GrCollapseValue>()\n\nasync function toggle(name: GrCollapseValue): Promise<void> {\n if (props.disabled || awaitingGuard.has(name))\n return\n\n if (!props.beforeChange) {\n applyToggle(name)\n return\n }\n\n awaitingGuard.add(name)\n try {\n if (await props.beforeChange(name, !activeSet.value.has(name)) === false)\n return\n\n applyToggle(name)\n }\n finally {\n awaitingGuard.delete(name)\n }\n}\n\nconst context: GrCollapseContext = {\n accordion: computed(() => props.accordion),\n disabled: computed(() => props.disabled),\n size: resolvedSize,\n headingLevel,\n expandIconPosition,\n isActive: name => activeSet.value.has(name),\n toggle: (name) => { void toggle(name) },\n}\n\nprovide(GR_COLLAPSE_CONTEXT, context)\n</script>\n\n<template>\n <GrCard v-if=\"!borderless\" data-gr-collapse>\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <div v-else :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\">\n <slot />\n </div>\n </GrCard>\n\n <!-- Разделители остаются на корне: без обёртки в карточку он и есть список\n секций, и лишний уровень вложенности сдвинул бы вёрстку потребителя. -->\n <div\n v-else\n data-gr-collapse\n :class=\"divided ? 'divide-y divide-[var(--gr-brd)]' : ''\"\n >\n <div\n v-if=\"isEmpty\"\n data-gr-collapse-empty\n :class=\"grCollapseEmptyClass(resolvedSize)\"\n >\n <slot name=\"empty\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <slot v-else />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ChevronDownIcon from '~icons/lucide/chevron-down'\nimport { computed, inject, ref, useId } from 'vue'\n\nimport GrIcon from '../GrIcon'\n\nimport { GR_COLLAPSE_CONTEXT, type GrCollapseValue } from './grCollapseContext'\nimport {\n collapseChevronSizes,\n collapseExtraPaddings,\n grCollapseBodyClass,\n grCollapseChevronClass,\n grCollapseHeaderClass,\n grCollapseRowClass,\n grCollapseTitleClass,\n} from './grCollapseStyles'\n\n/**\n * GrCollapseItem — одна секция `GrCollapse`. Должна использоваться строго внутри `GrCollapse`.\n *\n * @prop name — уникальный идентификатор секции (для `v-model` у `GrCollapse`); по умолчанию генерируется из `uid`.\n * @prop title — текст заголовка; можно заменить слотом `#title`.\n * @prop disabled — запрещает раскрытие/сворачивание секции.\n *\n * Слот `#extra` (счётчик, бейдж, кнопка) рендерится **рядом с** триггером, а не\n * внутри него: `<button>` внутри `<button>` — невалидная разметка, а axe ловит\n * это как `nested-interactive`.\n */\nexport interface GrCollapseItemProps {\n name?: GrCollapseValue\n title?: string\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<GrCollapseItemProps>(), {\n name: undefined,\n title: undefined,\n disabled: false,\n})\n\nconst collapse = inject(GR_COLLAPSE_CONTEXT)\n\nif (!collapse) {\n throw new Error('GrCollapseItem must be used inside GrCollapse')\n}\n\nconst collapseContext = collapse\n\nconst uid = useId()\n\nconst resolvedName = computed<GrCollapseValue>(() => {\n if (typeof props.name === 'string' || typeof props.name === 'number')\n return props.name\n\n return uid\n})\n\nconst resolvedDisabled = computed(() => collapseContext.disabled.value || props.disabled)\nconst expanded = computed(() => collapseContext.isActive(resolvedName.value))\n\nconst headingTag = computed(() => `h${collapseContext.headingLevel.value}`)\nconst iconAtStart = computed(() => collapseContext.expandIconPosition.value === 'start')\n\nconst rowClassName = computed(() => grCollapseRowClass(resolvedDisabled.value))\nconst headerClassName = computed(() => grCollapseHeaderClass({\n size: collapseContext.size.value,\n disabled: resolvedDisabled.value,\n}))\nconst extraClassName = computed(() => collapseExtraPaddings[collapseContext.size.value])\nconst titleClassName = computed(() => grCollapseTitleClass(collapseContext.size.value))\nconst bodyClassName = computed(() => grCollapseBodyClass(collapseContext.size.value))\nconst chevronClassName = computed(() => grCollapseChevronClass(expanded.value))\nconst chevronSize = computed(() => collapseChevronSizes[collapseContext.size.value])\n\n// Свёрнутая панель схлопывается визуально (`grid-rows-[0fr]`), но это не\n// скрытие: без `inert` ссылки и кнопки внутри неё ловятся Tab'ом, фокус уезжает\n// в невидимую область нулевой высоты, а скринридер читает содержимое всех\n// закрытых секций подряд — прямо вопреки `aria-expanded=\"false\"` на триггере.\n// `inert` убирает поддерево и из таб-порядка, и из дерева доступности, при этом\n// (в отличие от `hidden`/`display:none`) не ломает анимацию раскрытия.\nconst headerId = `gr-collapse-header-${uid}`\nconst panelId = `gr-collapse-panel-${uid}`\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction onToggle(): void {\n if (resolvedDisabled.value)\n return\n\n collapseContext.toggle(resolvedName.value)\n}\n\n/**\n * Только заголовки **своего** аккордеона: вложенный `GrCollapse` внутри\n * раскрытой панели тоже помечен `[data-gr-collapse]`, и без фильтра стрелки\n * внешнего аккордеона перескакивали бы на заголовки внутреннего.\n */\nfunction getAllTriggers(): HTMLElement[] {\n const root = triggerEl.value?.closest('[data-gr-collapse]')\n if (!root)\n return []\n\n const triggers = Array.prototype.slice.call(\n root.querySelectorAll<HTMLElement>('[data-gr-collapse-trigger]'),\n ) as HTMLElement[]\n\n return triggers.filter(trigger => trigger.closest('[data-gr-collapse]') === root)\n}\n\nfunction focusRelative(direction: 1 | -1): void {\n const current = triggerEl.value\n if (!current)\n return\n\n const triggers = getAllTriggers()\n const index = triggers.indexOf(current)\n if (index === -1 || triggers.length === 0)\n return\n\n const nextIndex = (index + direction + triggers.length) % triggers.length\n triggers[nextIndex]?.focus()\n}\n\nfunction focusEdge(edge: 'start' | 'end'): void {\n const triggers = getAllTriggers()\n if (triggers.length === 0) {\n return\n }\n\n const target = edge === 'start' ? triggers[0] : triggers.at(-1)\n target?.focus()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n focusRelative(1)\n return\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n focusRelative(-1)\n return\n }\n\n if (event.key === 'Home') {\n event.preventDefault()\n focusEdge('start')\n return\n }\n\n if (event.key === 'End') {\n event.preventDefault()\n focusEdge('end')\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n onToggle()\n }\n}\n\ndefineSlots<{\n /** Содержимое секции. */\n default?: () => any\n /** Заголовок секции вместо пропа `title`. */\n title?: () => any\n /** Иконка-указатель вместо шеврона. */\n icon?: () => any\n /** Управление справа в заголовке: счётчик, переключатель, кнопка. */\n extra?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-collapse-item\n class=\"text-[var(--gr-fg)]\"\n >\n <div :class=\"rowClassName\">\n <component\n :is=\"headingTag\"\n class=\"m-0 min-w-0 flex-1\"\n >\n <button\n :id=\"headerId\"\n ref=\"triggerEl\"\n data-gr-collapse-trigger\n type=\"button\"\n :aria-expanded=\"expanded ? 'true' : 'false'\"\n :aria-controls=\"panelId\"\n :disabled=\"resolvedDisabled\"\n :class=\"headerClassName\"\n @click=\"onToggle\"\n @keydown=\"onKeydown\"\n >\n <GrIcon\n v-if=\"iconAtStart\"\n :size=\"chevronSize\"\n\n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n\n <span :class=\"titleClassName\">\n <slot name=\"title\">\n <span class=\"font-600\">\n {{ title }}\n </span>\n </slot>\n </span>\n\n <GrIcon\n v-if=\"!iconAtStart\"\n :size=\"chevronSize\"\n\n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n </button>\n </component>\n\n <div\n v-if=\"$slots.extra\"\n data-gr-collapse-extra\n class=\"shrink-0\"\n :class=\"extraClassName\"\n >\n <slot name=\"extra\" />\n </div>\n </div>\n\n <div\n :id=\"panelId\"\n role=\"region\"\n :aria-labelledby=\"headerId\"\n :inert=\"expanded ? undefined : true\"\n class=\"grid transition-[grid-template-rows] duration-[var(--gr-duration-base)]\"\n :class=\"expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'\"\n >\n <div class=\"overflow-hidden\">\n <div :class=\"bodyClassName\">\n <slot />\n </div>\n </div>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport ChevronDownIcon from '~icons/lucide/chevron-down'\nimport { computed, inject, ref, useId } from 'vue'\n\nimport GrIcon from '../GrIcon'\n\nimport { GR_COLLAPSE_CONTEXT, type GrCollapseValue } from './grCollapseContext'\nimport {\n collapseChevronSizes,\n collapseExtraPaddings,\n grCollapseBodyClass,\n grCollapseChevronClass,\n grCollapseHeaderClass,\n grCollapseRowClass,\n grCollapseTitleClass,\n} from './grCollapseStyles'\n\n/**\n * GrCollapseItem — одна секция `GrCollapse`. Должна использоваться строго внутри `GrCollapse`.\n *\n * @prop name — уникальный идентификатор секции (для `v-model` у `GrCollapse`); по умолчанию генерируется из `uid`.\n * @prop title — текст заголовка; можно заменить слотом `#title`.\n * @prop disabled — запрещает раскрытие/сворачивание секции.\n *\n * Слот `#extra` (счётчик, бейдж, кнопка) рендерится **рядом с** триггером, а не\n * внутри него: `<button>` внутри `<button>` — невалидная разметка, а axe ловит\n * это как `nested-interactive`.\n */\nexport interface GrCollapseItemProps {\n name?: GrCollapseValue\n title?: string\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<GrCollapseItemProps>(), {\n name: undefined,\n title: undefined,\n disabled: false,\n})\n\nconst collapse = inject(GR_COLLAPSE_CONTEXT)\n\nif (!collapse) {\n throw new Error('GrCollapseItem must be used inside GrCollapse')\n}\n\nconst collapseContext = collapse\n\nconst uid = useId()\n\nconst resolvedName = computed<GrCollapseValue>(() => {\n if (typeof props.name === 'string' || typeof props.name === 'number')\n return props.name\n\n return uid\n})\n\nconst resolvedDisabled = computed(() => collapseContext.disabled.value || props.disabled)\nconst expanded = computed(() => collapseContext.isActive(resolvedName.value))\n\nconst headingTag = computed(() => `h${collapseContext.headingLevel.value}`)\nconst iconAtStart = computed(() => collapseContext.expandIconPosition.value === 'start')\n\nconst rowClassName = computed(() => grCollapseRowClass(resolvedDisabled.value))\nconst headerClassName = computed(() => grCollapseHeaderClass({\n size: collapseContext.size.value,\n disabled: resolvedDisabled.value,\n}))\nconst extraClassName = computed(() => collapseExtraPaddings[collapseContext.size.value])\nconst titleClassName = computed(() => grCollapseTitleClass(collapseContext.size.value))\nconst bodyClassName = computed(() => grCollapseBodyClass(collapseContext.size.value))\nconst chevronClassName = computed(() => grCollapseChevronClass(expanded.value))\nconst chevronSize = computed(() => collapseChevronSizes[collapseContext.size.value])\n\n// Свёрнутая панель схлопывается визуально (`grid-rows-[0fr]`), но это не\n// скрытие: без `inert` ссылки и кнопки внутри неё ловятся Tab'ом, фокус уезжает\n// в невидимую область нулевой высоты, а скринридер читает содержимое всех\n// закрытых секций подряд — прямо вопреки `aria-expanded=\"false\"` на триггере.\n// `inert` убирает поддерево и из таб-порядка, и из дерева доступности, при этом\n// (в отличие от `hidden`/`display:none`) не ломает анимацию раскрытия.\nconst headerId = `gr-collapse-header-${uid}`\nconst panelId = `gr-collapse-panel-${uid}`\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction onToggle(): void {\n if (resolvedDisabled.value)\n return\n\n collapseContext.toggle(resolvedName.value)\n}\n\n/**\n * Только заголовки **своего** аккордеона: вложенный `GrCollapse` внутри\n * раскрытой панели тоже помечен `[data-gr-collapse]`, и без фильтра стрелки\n * внешнего аккордеона перескакивали бы на заголовки внутреннего.\n */\nfunction getAllTriggers(): HTMLElement[] {\n const root = triggerEl.value?.closest('[data-gr-collapse]')\n if (!root)\n return []\n\n const triggers = Array.prototype.slice.call(\n root.querySelectorAll<HTMLElement>('[data-gr-collapse-trigger]'),\n ) as HTMLElement[]\n\n return triggers.filter(trigger => trigger.closest('[data-gr-collapse]') === root)\n}\n\nfunction focusRelative(direction: 1 | -1): void {\n const current = triggerEl.value\n if (!current)\n return\n\n const triggers = getAllTriggers()\n const index = triggers.indexOf(current)\n if (index === -1 || triggers.length === 0)\n return\n\n const nextIndex = (index + direction + triggers.length) % triggers.length\n triggers[nextIndex]?.focus()\n}\n\nfunction focusEdge(edge: 'start' | 'end'): void {\n const triggers = getAllTriggers()\n if (triggers.length === 0) {\n return\n }\n\n const target = edge === 'start' ? triggers[0] : triggers.at(-1)\n target?.focus()\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n focusRelative(1)\n return\n }\n\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n focusRelative(-1)\n return\n }\n\n if (event.key === 'Home') {\n event.preventDefault()\n focusEdge('start')\n return\n }\n\n if (event.key === 'End') {\n event.preventDefault()\n focusEdge('end')\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n onToggle()\n }\n}\n\ndefineSlots<{\n /** Содержимое секции. */\n default?: () => any\n /** Заголовок секции вместо пропа `title`. */\n title?: () => any\n /** Иконка-указатель вместо шеврона. */\n icon?: () => any\n /** Управление справа в заголовке: счётчик, переключатель, кнопка. */\n extra?: () => any\n}>()\n</script>\n\n<template>\n <div\n data-gr-collapse-item\n class=\"text-[var(--gr-fg)]\"\n >\n <div :class=\"rowClassName\">\n <component\n :is=\"headingTag\"\n class=\"m-0 min-w-0 flex-1\"\n >\n <button\n :id=\"headerId\"\n ref=\"triggerEl\"\n data-gr-collapse-trigger\n type=\"button\"\n :aria-expanded=\"expanded ? 'true' : 'false'\"\n :aria-controls=\"panelId\"\n :disabled=\"resolvedDisabled\"\n :class=\"headerClassName\"\n @click=\"onToggle\"\n @keydown=\"onKeydown\"\n >\n <GrIcon\n v-if=\"iconAtStart\"\n :size=\"chevronSize\"\n\n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n\n <span :class=\"titleClassName\">\n <slot name=\"title\">\n <span class=\"font-600\">\n {{ title }}\n </span>\n </slot>\n </span>\n\n <GrIcon\n v-if=\"!iconAtStart\"\n :size=\"chevronSize\"\n\n data-gr-collapse-chevron\n :class=\"chevronClassName\"\n >\n <slot name=\"icon\">\n <ChevronDownIcon />\n </slot>\n </GrIcon>\n </button>\n </component>\n\n <div\n v-if=\"$slots.extra\"\n data-gr-collapse-extra\n class=\"shrink-0\"\n :class=\"extraClassName\"\n >\n <slot name=\"extra\" />\n </div>\n </div>\n\n <div\n :id=\"panelId\"\n role=\"region\"\n :aria-labelledby=\"headerId\"\n :inert=\"expanded ? undefined : true\"\n class=\"grid transition-[grid-template-rows] duration-[var(--gr-duration-base)]\"\n :class=\"expanded ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'\"\n >\n <div class=\"overflow-hidden\">\n <div :class=\"bodyClassName\">\n <slot />\n </div>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -2,9 +2,9 @@ import { a as useGrComponentSize } from "../../../chunks/context-CTbuwcYs.js";
2
2
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
3
  import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js";
4
4
  import { useGrFormControl } from "../../../composables/useGrFormControl.js";
5
- import { t as GrInput_default } from "../../GrInput/chunks/GrInput-BqqoEl1b.js";
5
+ import { t as GrInput_default } from "../../GrInput/chunks/GrInput-BLywRZUN.js";
6
6
  import { t as GrPopover_default } from "../../GrPopover/chunks/GrPopover-CofG-Tfe.js";
7
- import { t as GrSlider_default } from "../../GrSlider/chunks/GrSlider-DJfeEl4h.js";
7
+ import { t as GrSlider_default } from "../../GrSlider/chunks/GrSlider-DTTrZTHK.js";
8
8
  import { a as grColorPickerPresetClass, c as previewClass, d as rowValueClass, f as swatchBaseClass, h as triggerValueClass, i as grColorPickerPanelClass, l as rowClass, m as triggerSwatchSizeBySize, o as grColorPickerTriggerClass, p as swatchFillClass, r as checkerClass, s as presetsGridClass, u as rowLabelClass } from "../../../chunks/config-DIDz_E5m.js";
9
9
  import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, isRef, mergeProps, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, toDisplayString, unref, useId, watch, withCtx, withKeys } from "vue";
10
10
  import '../styles.css';//#region src/components/GrColorPicker/color.ts
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrColorPicker-B20gQ6AR.js","names":[],"sources":["../../../../src/components/GrColorPicker/color.ts","../../../../src/components/GrColorPicker/GrColorPicker.vue","../../../../src/components/GrColorPicker/GrColorPicker.vue"],"sourcesContent":["/**\n * Арифметика цвета для `GrColorPicker` — чистый модуль без Vue.\n *\n * Модель компонента — hex-строка (в такой форме цвет лежит в токенах темы),\n * а панель работает в HSL: у оттенка, насыщенности и светлоты есть шкала, по\n * которой можно вести слайдер, а у каналов RGB её нет.\n *\n * Свой парсер, а не `__tests__/cssContrast.ts`: тот — инфраструктура гейтов, и\n * тянуть тестовый модуль в поставляемый код нельзя.\n */\n\nexport type GrHsla = {\n /** Оттенок, 0…359 (круговой: 360 — это 0). */\n h: number\n /** Насыщенность, 0…100. */\n s: number\n /** Светлота, 0…100. */\n l: number\n /** Непрозрачность, 0…1. */\n a: number\n}\n\ntype Rgb = { r: number, g: number, b: number }\n\nconst HEX_PATTERN = /^#?([0-9a-f]{3,8})$/i\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\n/**\n * Оттенок цикличен: 360° — тот же цвет, что 0°.\n *\n * Округления здесь нет намеренно: `#3b82f6` даёт 217.22°, и округлив его до\n * целого, обратное преобразование вернуло бы `#3b83f6` — компонент молча\n * переписывал бы чужой цвет при первом же открытии панели. Целые градусы\n * появляются там, где они и нужны, — на шкале слайдера (`normalizeHsla`).\n */\nfunction normalizeHue(hue: number): number {\n if (!Number.isFinite(hue))\n return 0\n return ((hue % 360) + 360) % 360\n}\n\n/** Короткая форма `#abc` разворачивается в `#aabbcc` — так её читает и CSS. */\nfunction expandShorthand(hex: string): string | null {\n if (hex.length === 3 || hex.length === 4)\n return [...hex].map(char => char + char).join('')\n\n if (hex.length === 6 || hex.length === 8)\n return hex\n\n return null\n}\n\nfunction rgbToHsl({ r, g, b }: Rgb): { h: number, s: number, l: number } {\n const red = r / 255\n const green = g / 255\n const blue = b / 255\n\n const max = Math.max(red, green, blue)\n const min = Math.min(red, green, blue)\n const delta = max - min\n const lightness = (max + min) / 2\n\n if (delta === 0)\n return { h: 0, s: 0, l: lightness * 100 }\n\n const saturation = delta / (1 - Math.abs(2 * lightness - 1))\n\n let hue: number\n if (max === red)\n hue = ((green - blue) / delta) % 6\n else if (max === green)\n hue = (blue - red) / delta + 2\n else hue = (red - green) / delta + 4\n\n return { h: normalizeHue(hue * 60), s: saturation * 100, l: lightness * 100 }\n}\n\nfunction hslToRgb({ h, s, l }: Omit<GrHsla, 'a'>): Rgb {\n const saturation = clamp(s, 0, 100) / 100\n const lightness = clamp(l, 0, 100) / 100\n const hue = normalizeHue(h)\n\n const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation\n const second = chroma * (1 - Math.abs(((hue / 60) % 2) - 1))\n const match = lightness - chroma / 2\n\n const [red, green, blue] = ((): [number, number, number] => {\n if (hue < 60)\n return [chroma, second, 0]\n if (hue < 120)\n return [second, chroma, 0]\n if (hue < 180)\n return [0, chroma, second]\n if (hue < 240)\n return [0, second, chroma]\n if (hue < 300)\n return [second, 0, chroma]\n return [chroma, 0, second]\n })()\n\n return {\n r: Math.round((red + match) * 255),\n g: Math.round((green + match) * 255),\n b: Math.round((blue + match) * 255),\n }\n}\n\nfunction toHexPair(value: number): string {\n return clamp(Math.round(value), 0, 255).toString(16).padStart(2, '0')\n}\n\n/**\n * Разбирает hex любой из четырёх форм (`#abc`, `#abcd`, `#aabbcc`, `#aabbccdd`),\n * регистр и решётка необязательны.\n *\n * Мусор возвращает `null`, а не бросает: значение приходит из модели снаружи и\n * из поля ввода, и упавший компонент — худший ответ на опечатку.\n */\nexport function parseHexColor(value: unknown): GrHsla | null {\n if (typeof value !== 'string')\n return null\n\n const match = HEX_PATTERN.exec(value.trim())\n if (!match)\n return null\n\n const hex = expandShorthand(match[1])\n if (!hex)\n return null\n\n const rgb: Rgb = {\n r: Number.parseInt(hex.slice(0, 2), 16),\n g: Number.parseInt(hex.slice(2, 4), 16),\n b: Number.parseInt(hex.slice(4, 6), 16),\n }\n\n const alpha = hex.length === 8 ? Number.parseInt(hex.slice(6, 8), 16) / 255 : 1\n\n return { ...rgbToHsl(rgb), a: alpha }\n}\n\n/**\n * Собирает hex обратно. `withAlpha: false` альфу отбрасывает, а не округляет до\n * непрозрачного: компонент без пропа `alpha` не вправе отдавать восьмизначную\n * форму, которую потребитель не ждёт.\n */\nexport function formatHexColor(color: GrHsla, withAlpha = false): string {\n const { r, g, b } = hslToRgb(color)\n const base = `#${toHexPair(r)}${toHexPair(g)}${toHexPair(b)}`\n\n if (!withAlpha)\n return base\n\n return `${base}${toHexPair(clamp(color.a, 0, 1) * 255)}`\n}\n\n/** Короткая запись числа: целое остаётся целым, дробь обрезается до сотых. */\nfunction trim(value: number): number {\n return Math.round(value * 100) / 100\n}\n\n/** CSS-запись цвета для превью и градиентов. */\nexport function hslaToCss(color: GrHsla): string {\n const h = trim(normalizeHue(color.h))\n const s = trim(clamp(color.s, 0, 100))\n const l = trim(clamp(color.l, 0, 100))\n\n return `hsl(${h} ${s}% ${l}% / ${trim(clamp(color.a, 0, 1))})`\n}\n\n/** Приводит произвольный объект к валидному диапазону каналов. */\nexport function normalizeHsla(color: GrHsla): GrHsla {\n return {\n h: Math.round(normalizeHue(color.h)) % 360,\n s: clamp(Math.round(color.s), 0, 100),\n l: clamp(Math.round(color.l), 0, 100),\n a: clamp(color.a, 0, 1),\n }\n}\n","<script setup lang=\"ts\">\n/**\n * GrColorPicker — поле выбора цвета: образец с текущим значением, панель с\n * оттенком, насыщенностью, светлотой и прозрачностью, поле hex и палитра.\n *\n * Прямой сценарий — настройки темы и брендирования, поэтому модель хранит hex:\n * в такой форме цвет лежит в токенах и его понимает CSS.\n *\n * A11y: каждый канал — отдельный `GrSlider`, то есть настоящий `role=\"slider\"`\n * с полной клавиатурой и `aria-valuetext`. Двумерная область saturation/value\n * не берётся намеренно: это свой виджет со своей клавиатурой по двум осям, и\n * доступность там пришлось бы собирать с нуля.\n */\nimport { computed, nextTick, ref, useId, watch } from 'vue'\n\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrPopover from '../GrPopover/GrPopover.vue'\nimport GrSlider from '../GrSlider/GrSlider.vue'\n\nimport { formatHexColor, hslaToCss, normalizeHsla, parseHexColor, type GrHsla } from './color'\nimport {\n checkerClass,\n grColorPickerPanelClass,\n grColorPickerPresetClass,\n grColorPickerTriggerClass,\n presetsGridClass,\n previewClass,\n rowClass,\n rowLabelClass,\n rowValueClass,\n swatchBaseClass,\n swatchFillClass,\n triggerSwatchSizeBySize,\n triggerValueClass,\n type GrColorPickerSize,\n} from './grColorPickerStyles'\n\nexport type { GrColorPickerSize } from './grColorPickerStyles'\n\nexport interface GrColorPickerProps {\n /** Цвет в hex: `#RRGGBB`, а при `alpha` — `#RRGGBBAA`. Мусор не роняет компонент. */\n modelValue: string\n /** Четвёртый слайдер и восьмизначная форма hex. */\n alpha?: boolean\n /** Палитра быстрого выбора. Пусто — блок не рендерится. */\n presets?: string[]\n size?: GrColorPickerSize\n /** Контролируемое состояние панели (`v-model:open`). */\n open?: boolean\n /** Сторона, с которой раскрывается панель. */\n placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n /** Имя для нативной формы: значение уходит скрытым полем. */\n name?: string\n disabled?: boolean\n /** Только для чтения: цвет видно, панель открывается, но значение не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n ariaLabel?: string\n}\n\nexport interface GrColorPickerEmits {\n (e: 'update:modelValue', value: string): void\n (e: 'change', value: string): void\n (e: 'update:open', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrColorPickerProps>(), {\n alpha: false,\n presets: () => [],\n // Дефолт живёт в резолвере: Vue подставил бы свой раньше, чем компонент\n // заглянет в `GrConfigProvider`.\n size: undefined,\n open: undefined,\n placement: 'bottom-start',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrColorPickerEmits>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrColorPicker' })\n\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n // «Ввод не принимается» — `disabled` или `readonly`: значение видно, но не меняется.\n locked: isLocked,\n} = useGrFormControl(() => props)\n\n/**\n * `aria-required` и `aria-readonly` роль `button` не поддерживает — axe роняет\n * это как critical `aria-allowed-attr`. Состояния уходят в описание триггера:\n * иначе они пропали бы для диктора совсем (маркер `*` у `GrFormField`\n * декоративен и скрыт).\n */\nconst stateHintId = useId()\nconst stateHint = computed(() => [\n isRequired.value ? t('gr.form.required', 'This field is required') : undefined,\n isReadonly.value ? t('gr.form.readonly', 'Read only') : undefined,\n].filter(Boolean).join('. ') || undefined)\n\nconst describedBy = computed(() => [\n field?.describedById.value,\n stateHint.value ? stateHintId : undefined,\n].filter(Boolean).join(' ') || undefined)\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction focus(): void {\n triggerEl.value?.focus()\n}\n\nfunction blur(): void {\n triggerEl.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nconst FALLBACK: GrHsla = { h: 0, s: 0, l: 0, a: 1 }\n\n/**\n * Рабочее состояние панели.\n *\n * Держать его отдельно от модели обязательно: hex — проекция с потерями. У\n * серого нет оттенка, и без собственного состояния бегунок оттенка прыгал бы\n * обратно на 0° при каждом движении.\n */\nconst state = ref<GrHsla>(parseHexColor(props.modelValue) ?? FALLBACK)\n\n/** Последнее отданное значение: вернувшись в проп, оно не должно сбрасывать состояние. */\nlet lastEmitted = ''\n\nwatch(() => props.modelValue, (next) => {\n if (next === lastEmitted)\n return\n\n const parsed = parseHexColor(next)\n if (parsed)\n state.value = parsed\n})\n\nconst cssColor = computed(() => hslaToCss(state.value))\nconst hexValue = computed(() => formatHexColor(state.value, props.alpha))\n\nfunction commit(next: GrHsla): void {\n if (isLocked.value)\n return\n\n state.value = normalizeHsla(next)\n\n const hex = formatHexColor(state.value, props.alpha)\n lastEmitted = hex\n emit('update:modelValue', hex)\n emit('change', hex)\n}\n\n/** Канал панели: слайдер читает состояние и коммитит новое значение целиком. */\nfunction channel(key: 'h' | 's' | 'l' | 'a', scale = 1) {\n return computed<number>({\n get: () => Math.round(state.value[key] * scale),\n set: value => commit({ ...state.value, [key]: value / scale }),\n })\n}\n\nconst hue = channel('h')\nconst saturation = channel('s')\nconst lightness = channel('l')\n// Альфа хранится долей, а слайдер ходит по процентам — иначе шаг был бы 0.01.\nconst opacity = channel('a', 100)\n\nconst degrees = (value: number): string => `${value}°`\nconst percent = (value: number): string => `${value}%`\n\n/** Текст поля hex редактируется свободно и коммитится только валидным. */\nconst hexDraft = ref(hexValue.value)\n\nwatch(hexValue, (next) => {\n hexDraft.value = next\n})\n\nfunction commitHex(): void {\n const parsed = parseHexColor(hexDraft.value)\n\n // Мусор откатывается к текущему значению: держать в поле невалидный текст\n // после коммита — значит показывать цвет, которого нет.\n //\n // Откат идёт следующим тиком намеренно: вернув значение синхронно, мы отдали\n // бы Vue то же самое, что он уже отрисовал, — патча не случилось бы, и в поле\n // остался бы набранный мусор.\n if (!parsed) {\n void nextTick(() => {\n hexDraft.value = hexValue.value\n })\n return\n }\n\n commit(props.alpha ? parsed : { ...parsed, a: state.value.a })\n}\n\nconst isOpen = ref(false)\nconst panelOpen = computed({\n get: () => props.open ?? isOpen.value,\n set: (value) => {\n isOpen.value = value\n emit('update:open', value)\n },\n})\n\nconst presetList = computed(() => props.presets.filter(preset => parseHexColor(preset) !== null))\n\nfunction isPresetSelected(preset: string): boolean {\n const parsed = parseHexColor(preset)\n return parsed ? formatHexColor(parsed, props.alpha) === hexValue.value : false\n}\n\nfunction selectPreset(preset: string): void {\n const parsed = parseHexColor(preset)\n if (parsed)\n commit(parsed)\n}\n\nconst triggerClass = computed(() => grColorPickerTriggerClass({\n size: resolvedSize.value,\n disabled: isDisabled.value,\n invalid: isInvalid.value,\n}))\n\nconst panelClass = computed(() => grColorPickerPanelClass(resolvedSize.value))\nconst swatchSizeClass = computed(() => triggerSwatchSizeBySize[resolvedSize.value])\n\n/**\n * Градиенты дорожек. Через `--gr-slider-rail` их не подать: хук уходит в\n * `background-color`, а градиент там не работает — поэтому значения приезжают\n * переменными, а красит дорожки собственный `<style>` компонента.\n *\n * Переменные висят на самой панели, а не на корне: панель уезжает в портал, и\n * наследование от корня до неё не доходит.\n */\nconst trackVars = computed<Record<string, string>>(() => {\n const { h, s, l } = state.value\n const solid = hslaToCss({ h, s, l, a: 1 })\n\n return {\n '--gr-color-picker-track-hue': 'linear-gradient(to right, hsl(0 100% 50%), hsl(60 100% 50%), hsl(120 100% 50%), hsl(180 100% 50%), hsl(240 100% 50%), hsl(300 100% 50%), hsl(360 100% 50%))',\n '--gr-color-picker-track-saturation': `linear-gradient(to right, hsl(${Math.round(h)} 0% ${Math.round(l)}%), hsl(${Math.round(h)} 100% ${Math.round(l)}%))`,\n '--gr-color-picker-track-lightness': `linear-gradient(to right, hsl(${Math.round(h)} ${Math.round(s)}% 0%), hsl(${Math.round(h)} ${Math.round(s)}% 50%), hsl(${Math.round(h)} ${Math.round(s)}% 100%))`,\n '--gr-color-picker-track-alpha': `linear-gradient(to right, transparent, ${solid})`,\n }\n})\n</script>\n\n<template>\n <div data-gr-color-picker>\n <!-- Значение для нативной формы уходит скрытым полем: интерактивного\n контрола внутри виджета быть не должно. -->\n <input v-if=\"name\" type=\"hidden\" :name=\"name\" :value=\"hexValue\">\n\n <span v-if=\"stateHint\" :id=\"stateHintId\" class=\"sr-only\">{{ stateHint }}</span>\n\n <GrPopover\n v-model:open=\"panelOpen\"\n :size=\"resolvedSize\"\n :placement=\"placement\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.panelLabel', 'Color picker')\"\n :close-on-content-click=\"false\"\n >\n <template #trigger=\"{ triggerProps }\">\n <button\n :id=\"fieldId\"\n ref=\"triggerEl\"\n v-bind=\"triggerProps\"\n data-gr-color-picker-trigger\n type=\"button\"\n :class=\"triggerClass\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <span\n data-gr-color-picker-swatch\n aria-hidden=\"true\"\n :class=\"[swatchBaseClass, swatchSizeClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </span>\n\n <span :class=\"triggerValueClass\">{{ hexValue }}</span>\n </button>\n </template>\n\n <template #content>\n <div data-gr-color-picker-panel :class=\"panelClass\" :style=\"trackVars\">\n <div\n data-gr-color-picker-preview\n aria-hidden=\"true\"\n :class=\"[previewClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </div>\n\n <div data-gr-color-picker-channel=\"hue\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">H</span>\n <GrSlider\n v-model=\"hue\"\n :min=\"0\"\n :max=\"359\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"degrees\"\n :aria-label=\"t('gr.colorPicker.hue', 'Hue')\"\n />\n <span :class=\"rowValueClass\">{{ degrees(hue) }}</span>\n </div>\n\n <div data-gr-color-picker-channel=\"saturation\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">S</span>\n <GrSlider\n v-model=\"saturation\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.saturation', 'Saturation')\"\n />\n <span :class=\"rowValueClass\">{{ percent(saturation) }}</span>\n </div>\n\n <div data-gr-color-picker-channel=\"lightness\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">L</span>\n <GrSlider\n v-model=\"lightness\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.lightness', 'Lightness')\"\n />\n <span :class=\"rowValueClass\">{{ percent(lightness) }}</span>\n </div>\n\n <div v-if=\"alpha\" data-gr-color-picker-channel=\"alpha\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">A</span>\n <GrSlider\n v-model=\"opacity\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.opacity', 'Opacity')\"\n />\n <span :class=\"rowValueClass\">{{ percent(opacity) }}</span>\n </div>\n\n <GrInput\n v-model=\"hexDraft\"\n data-gr-color-picker-hex\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :aria-label=\"t('gr.colorPicker.hexLabel', 'Hex value')\"\n @change=\"commitHex\"\n @keydown.enter=\"commitHex\"\n />\n\n <div\n v-if=\"presetList.length\"\n data-gr-color-picker-presets\n :class=\"presetsGridClass\"\n role=\"group\"\n :aria-label=\"t('gr.colorPicker.presetsLabel', 'Color presets')\"\n >\n <button\n v-for=\"preset in presetList\"\n :key=\"preset\"\n data-gr-color-picker-preset\n type=\"button\"\n :class=\"[grColorPickerPresetClass(isPresetSelected(preset)), checkerClass]\"\n :aria-label=\"t('gr.colorPicker.swatchLabel', 'Color {color}', { color: preset })\"\n :aria-pressed=\"isPresetSelected(preset) ? 'true' : 'false'\"\n :disabled=\"isLocked\"\n @click=\"selectPreset(preset)\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: preset }\" />\n </button>\n </div>\n </div>\n </template>\n </GrPopover>\n </div>\n</template>\n\n<style>\n/*\n * Шахматка под прозрачным цветом. Двумя `conic-gradient` — в утилите такое не\n * выражается, а без подложки прозрачный образец сливается с панелью.\n */\n.gr-color-picker-checker {\n background-image:\n conic-gradient(\n from 90deg,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 25%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0 50%,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 75%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0\n );\n background-size:\n calc(var(--gr-color-picker-checker-size, 6px) * 2)\n calc(var(--gr-color-picker-checker-size, 6px) * 2);\n /* Рамка образца полупрозрачна, и без обрезки шахматка просвечивает сквозь неё. */\n background-clip: padding-box;\n}\n\n/*\n * Дорожки каналов. Красим `[data-gr-slider-track]` потому, что хук\n * `--gr-slider-rail` уходит в `background-color`, а градиент там не работает.\n * Сами градиенты компонент подаёт переменными — CSS остаётся статичной.\n */\n[data-gr-color-picker-channel] [data-gr-slider-track] {\n border-radius: var(--gr-radius-full);\n}\n\n[data-gr-color-picker-channel='hue'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-hue);\n}\n\n[data-gr-color-picker-channel='saturation'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-saturation);\n}\n\n[data-gr-color-picker-channel='lightness'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-lightness);\n}\n\n[data-gr-color-picker-channel='alpha'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-alpha);\n}\n\n/* Заливка канала прозрачна: шкалу показывает сама дорожка. */\n[data-gr-color-picker-channel] [data-gr-slider-fill] {\n background-color: transparent;\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * GrColorPicker — поле выбора цвета: образец с текущим значением, панель с\n * оттенком, насыщенностью, светлотой и прозрачностью, поле hex и палитра.\n *\n * Прямой сценарий — настройки темы и брендирования, поэтому модель хранит hex:\n * в такой форме цвет лежит в токенах и его понимает CSS.\n *\n * A11y: каждый канал — отдельный `GrSlider`, то есть настоящий `role=\"slider\"`\n * с полной клавиатурой и `aria-valuetext`. Двумерная область saturation/value\n * не берётся намеренно: это свой виджет со своей клавиатурой по двум осям, и\n * доступность там пришлось бы собирать с нуля.\n */\nimport { computed, nextTick, ref, useId, watch } from 'vue'\n\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrPopover from '../GrPopover/GrPopover.vue'\nimport GrSlider from '../GrSlider/GrSlider.vue'\n\nimport { formatHexColor, hslaToCss, normalizeHsla, parseHexColor, type GrHsla } from './color'\nimport {\n checkerClass,\n grColorPickerPanelClass,\n grColorPickerPresetClass,\n grColorPickerTriggerClass,\n presetsGridClass,\n previewClass,\n rowClass,\n rowLabelClass,\n rowValueClass,\n swatchBaseClass,\n swatchFillClass,\n triggerSwatchSizeBySize,\n triggerValueClass,\n type GrColorPickerSize,\n} from './grColorPickerStyles'\n\nexport type { GrColorPickerSize } from './grColorPickerStyles'\n\nexport interface GrColorPickerProps {\n /** Цвет в hex: `#RRGGBB`, а при `alpha` — `#RRGGBBAA`. Мусор не роняет компонент. */\n modelValue: string\n /** Четвёртый слайдер и восьмизначная форма hex. */\n alpha?: boolean\n /** Палитра быстрого выбора. Пусто — блок не рендерится. */\n presets?: string[]\n size?: GrColorPickerSize\n /** Контролируемое состояние панели (`v-model:open`). */\n open?: boolean\n /** Сторона, с которой раскрывается панель. */\n placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n /** Имя для нативной формы: значение уходит скрытым полем. */\n name?: string\n disabled?: boolean\n /** Только для чтения: цвет видно, панель открывается, но значение не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n ariaLabel?: string\n}\n\nexport interface GrColorPickerEmits {\n (e: 'update:modelValue', value: string): void\n (e: 'change', value: string): void\n (e: 'update:open', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrColorPickerProps>(), {\n alpha: false,\n presets: () => [],\n // Дефолт живёт в резолвере: Vue подставил бы свой раньше, чем компонент\n // заглянет в `GrConfigProvider`.\n size: undefined,\n open: undefined,\n placement: 'bottom-start',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrColorPickerEmits>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrColorPicker' })\n\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n // «Ввод не принимается» — `disabled` или `readonly`: значение видно, но не меняется.\n locked: isLocked,\n} = useGrFormControl(() => props)\n\n/**\n * `aria-required` и `aria-readonly` роль `button` не поддерживает — axe роняет\n * это как critical `aria-allowed-attr`. Состояния уходят в описание триггера:\n * иначе они пропали бы для диктора совсем (маркер `*` у `GrFormField`\n * декоративен и скрыт).\n */\nconst stateHintId = useId()\nconst stateHint = computed(() => [\n isRequired.value ? t('gr.form.required', 'This field is required') : undefined,\n isReadonly.value ? t('gr.form.readonly', 'Read only') : undefined,\n].filter(Boolean).join('. ') || undefined)\n\nconst describedBy = computed(() => [\n field?.describedById.value,\n stateHint.value ? stateHintId : undefined,\n].filter(Boolean).join(' ') || undefined)\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction focus(): void {\n triggerEl.value?.focus()\n}\n\nfunction blur(): void {\n triggerEl.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nconst FALLBACK: GrHsla = { h: 0, s: 0, l: 0, a: 1 }\n\n/**\n * Рабочее состояние панели.\n *\n * Держать его отдельно от модели обязательно: hex — проекция с потерями. У\n * серого нет оттенка, и без собственного состояния бегунок оттенка прыгал бы\n * обратно на 0° при каждом движении.\n */\nconst state = ref<GrHsla>(parseHexColor(props.modelValue) ?? FALLBACK)\n\n/** Последнее отданное значение: вернувшись в проп, оно не должно сбрасывать состояние. */\nlet lastEmitted = ''\n\nwatch(() => props.modelValue, (next) => {\n if (next === lastEmitted)\n return\n\n const parsed = parseHexColor(next)\n if (parsed)\n state.value = parsed\n})\n\nconst cssColor = computed(() => hslaToCss(state.value))\nconst hexValue = computed(() => formatHexColor(state.value, props.alpha))\n\nfunction commit(next: GrHsla): void {\n if (isLocked.value)\n return\n\n state.value = normalizeHsla(next)\n\n const hex = formatHexColor(state.value, props.alpha)\n lastEmitted = hex\n emit('update:modelValue', hex)\n emit('change', hex)\n}\n\n/** Канал панели: слайдер читает состояние и коммитит новое значение целиком. */\nfunction channel(key: 'h' | 's' | 'l' | 'a', scale = 1) {\n return computed<number>({\n get: () => Math.round(state.value[key] * scale),\n set: value => commit({ ...state.value, [key]: value / scale }),\n })\n}\n\nconst hue = channel('h')\nconst saturation = channel('s')\nconst lightness = channel('l')\n// Альфа хранится долей, а слайдер ходит по процентам — иначе шаг был бы 0.01.\nconst opacity = channel('a', 100)\n\nconst degrees = (value: number): string => `${value}°`\nconst percent = (value: number): string => `${value}%`\n\n/** Текст поля hex редактируется свободно и коммитится только валидным. */\nconst hexDraft = ref(hexValue.value)\n\nwatch(hexValue, (next) => {\n hexDraft.value = next\n})\n\nfunction commitHex(): void {\n const parsed = parseHexColor(hexDraft.value)\n\n // Мусор откатывается к текущему значению: держать в поле невалидный текст\n // после коммита — значит показывать цвет, которого нет.\n //\n // Откат идёт следующим тиком намеренно: вернув значение синхронно, мы отдали\n // бы Vue то же самое, что он уже отрисовал, — патча не случилось бы, и в поле\n // остался бы набранный мусор.\n if (!parsed) {\n void nextTick(() => {\n hexDraft.value = hexValue.value\n })\n return\n }\n\n commit(props.alpha ? parsed : { ...parsed, a: state.value.a })\n}\n\nconst isOpen = ref(false)\nconst panelOpen = computed({\n get: () => props.open ?? isOpen.value,\n set: (value) => {\n isOpen.value = value\n emit('update:open', value)\n },\n})\n\nconst presetList = computed(() => props.presets.filter(preset => parseHexColor(preset) !== null))\n\nfunction isPresetSelected(preset: string): boolean {\n const parsed = parseHexColor(preset)\n return parsed ? formatHexColor(parsed, props.alpha) === hexValue.value : false\n}\n\nfunction selectPreset(preset: string): void {\n const parsed = parseHexColor(preset)\n if (parsed)\n commit(parsed)\n}\n\nconst triggerClass = computed(() => grColorPickerTriggerClass({\n size: resolvedSize.value,\n disabled: isDisabled.value,\n invalid: isInvalid.value,\n}))\n\nconst panelClass = computed(() => grColorPickerPanelClass(resolvedSize.value))\nconst swatchSizeClass = computed(() => triggerSwatchSizeBySize[resolvedSize.value])\n\n/**\n * Градиенты дорожек. Через `--gr-slider-rail` их не подать: хук уходит в\n * `background-color`, а градиент там не работает — поэтому значения приезжают\n * переменными, а красит дорожки собственный `<style>` компонента.\n *\n * Переменные висят на самой панели, а не на корне: панель уезжает в портал, и\n * наследование от корня до неё не доходит.\n */\nconst trackVars = computed<Record<string, string>>(() => {\n const { h, s, l } = state.value\n const solid = hslaToCss({ h, s, l, a: 1 })\n\n return {\n '--gr-color-picker-track-hue': 'linear-gradient(to right, hsl(0 100% 50%), hsl(60 100% 50%), hsl(120 100% 50%), hsl(180 100% 50%), hsl(240 100% 50%), hsl(300 100% 50%), hsl(360 100% 50%))',\n '--gr-color-picker-track-saturation': `linear-gradient(to right, hsl(${Math.round(h)} 0% ${Math.round(l)}%), hsl(${Math.round(h)} 100% ${Math.round(l)}%))`,\n '--gr-color-picker-track-lightness': `linear-gradient(to right, hsl(${Math.round(h)} ${Math.round(s)}% 0%), hsl(${Math.round(h)} ${Math.round(s)}% 50%), hsl(${Math.round(h)} ${Math.round(s)}% 100%))`,\n '--gr-color-picker-track-alpha': `linear-gradient(to right, transparent, ${solid})`,\n }\n})\n</script>\n\n<template>\n <div data-gr-color-picker>\n <!-- Значение для нативной формы уходит скрытым полем: интерактивного\n контрола внутри виджета быть не должно. -->\n <input v-if=\"name\" type=\"hidden\" :name=\"name\" :value=\"hexValue\">\n\n <span v-if=\"stateHint\" :id=\"stateHintId\" class=\"sr-only\">{{ stateHint }}</span>\n\n <GrPopover\n v-model:open=\"panelOpen\"\n :size=\"resolvedSize\"\n :placement=\"placement\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.panelLabel', 'Color picker')\"\n :close-on-content-click=\"false\"\n >\n <template #trigger=\"{ triggerProps }\">\n <button\n :id=\"fieldId\"\n ref=\"triggerEl\"\n v-bind=\"triggerProps\"\n data-gr-color-picker-trigger\n type=\"button\"\n :class=\"triggerClass\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <span\n data-gr-color-picker-swatch\n aria-hidden=\"true\"\n :class=\"[swatchBaseClass, swatchSizeClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </span>\n\n <span :class=\"triggerValueClass\">{{ hexValue }}</span>\n </button>\n </template>\n\n <template #content>\n <div data-gr-color-picker-panel :class=\"panelClass\" :style=\"trackVars\">\n <div\n data-gr-color-picker-preview\n aria-hidden=\"true\"\n :class=\"[previewClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </div>\n\n <div data-gr-color-picker-channel=\"hue\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">H</span>\n <GrSlider\n v-model=\"hue\"\n :min=\"0\"\n :max=\"359\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"degrees\"\n :aria-label=\"t('gr.colorPicker.hue', 'Hue')\"\n />\n <span :class=\"rowValueClass\">{{ degrees(hue) }}</span>\n </div>\n\n <div data-gr-color-picker-channel=\"saturation\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">S</span>\n <GrSlider\n v-model=\"saturation\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.saturation', 'Saturation')\"\n />\n <span :class=\"rowValueClass\">{{ percent(saturation) }}</span>\n </div>\n\n <div data-gr-color-picker-channel=\"lightness\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">L</span>\n <GrSlider\n v-model=\"lightness\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.lightness', 'Lightness')\"\n />\n <span :class=\"rowValueClass\">{{ percent(lightness) }}</span>\n </div>\n\n <div v-if=\"alpha\" data-gr-color-picker-channel=\"alpha\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">A</span>\n <GrSlider\n v-model=\"opacity\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.opacity', 'Opacity')\"\n />\n <span :class=\"rowValueClass\">{{ percent(opacity) }}</span>\n </div>\n\n <GrInput\n v-model=\"hexDraft\"\n data-gr-color-picker-hex\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :aria-label=\"t('gr.colorPicker.hexLabel', 'Hex value')\"\n @change=\"commitHex\"\n @keydown.enter=\"commitHex\"\n />\n\n <div\n v-if=\"presetList.length\"\n data-gr-color-picker-presets\n :class=\"presetsGridClass\"\n role=\"group\"\n :aria-label=\"t('gr.colorPicker.presetsLabel', 'Color presets')\"\n >\n <button\n v-for=\"preset in presetList\"\n :key=\"preset\"\n data-gr-color-picker-preset\n type=\"button\"\n :class=\"[grColorPickerPresetClass(isPresetSelected(preset)), checkerClass]\"\n :aria-label=\"t('gr.colorPicker.swatchLabel', 'Color {color}', { color: preset })\"\n :aria-pressed=\"isPresetSelected(preset) ? 'true' : 'false'\"\n :disabled=\"isLocked\"\n @click=\"selectPreset(preset)\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: preset }\" />\n </button>\n </div>\n </div>\n </template>\n </GrPopover>\n </div>\n</template>\n\n<style>\n/*\n * Шахматка под прозрачным цветом. Двумя `conic-gradient` — в утилите такое не\n * выражается, а без подложки прозрачный образец сливается с панелью.\n */\n.gr-color-picker-checker {\n background-image:\n conic-gradient(\n from 90deg,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 25%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0 50%,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 75%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0\n );\n background-size:\n calc(var(--gr-color-picker-checker-size, 6px) * 2)\n calc(var(--gr-color-picker-checker-size, 6px) * 2);\n /* Рамка образца полупрозрачна, и без обрезки шахматка просвечивает сквозь неё. */\n background-clip: padding-box;\n}\n\n/*\n * Дорожки каналов. Красим `[data-gr-slider-track]` потому, что хук\n * `--gr-slider-rail` уходит в `background-color`, а градиент там не работает.\n * Сами градиенты компонент подаёт переменными — CSS остаётся статичной.\n */\n[data-gr-color-picker-channel] [data-gr-slider-track] {\n border-radius: var(--gr-radius-full);\n}\n\n[data-gr-color-picker-channel='hue'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-hue);\n}\n\n[data-gr-color-picker-channel='saturation'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-saturation);\n}\n\n[data-gr-color-picker-channel='lightness'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-lightness);\n}\n\n[data-gr-color-picker-channel='alpha'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-alpha);\n}\n\n/* Заливка канала прозрачна: шкалу показывает сама дорожка. */\n[data-gr-color-picker-channel] [data-gr-slider-fill] {\n background-color: transparent;\n}\n</style>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrColorPicker_default } from "./chunks/GrColorPicker-CE-xtNP-.js";
1
+ import { t as GrColorPicker_default } from "./chunks/GrColorPicker-B20gQ6AR.js";
2
2
  import { n as grColorPickerSafelist, t as grColorPickerConfig } from "../../chunks/config-DIDz_E5m.js";
3
3
  export { GrColorPicker_default as GrColorPicker, GrColorPicker_default as default, grColorPickerConfig, grColorPickerSafelist };
@@ -586,6 +586,6 @@ var GrCommandPalette_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/
586
586
  }, 8, ["model-value", "size"]);
587
587
  };
588
588
  }
589
- }), [["__scopeId", "data-v-dcf84986"]]);
589
+ }), [["__scopeId", "data-v-041dfab7"]]);
590
590
  //#endregion
591
591
  export { GrCommandPalette_default as t };