@feugene/granularity 0.31.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 (265) 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-CQLNjc9X2.js.map +1 -1
  14. package/dist/chunks/config-CbEbLyDE.js.map +1 -1
  15. package/dist/chunks/{config-jyr6AIZt2.js → config-CuQmUkMw2.js} +2 -2
  16. package/dist/chunks/{config-jyr6AIZt2.js.map → config-CuQmUkMw2.js.map} +1 -1
  17. package/dist/chunks/config-DeyT9dJl.js.map +1 -1
  18. package/dist/chunks/config-DnF472Ox.js.map +1 -1
  19. package/dist/chunks/config-DwABJHEo.js.map +1 -1
  20. package/dist/chunks/{config-tiUtEn4Q.js → config-E1cTyRVV.js} +1 -1
  21. package/dist/chunks/{config-tiUtEn4Q.js.map → config-E1cTyRVV.js.map} +1 -1
  22. package/dist/chunks/config-MmPym-Z72.js.map +1 -1
  23. package/dist/chunks/config-T3-DMXYm.js.map +1 -1
  24. package/dist/chunks/config-Yy67uWHY.js.map +1 -1
  25. package/dist/chunks/config-_jbgsFpw.js.map +1 -1
  26. package/dist/chunks/config-g8-JGZ_Y.js.map +1 -1
  27. package/dist/chunks/config-mlheIMtV.js.map +1 -1
  28. package/dist/chunks/config-rLkc9Zn2.js.map +1 -1
  29. package/dist/chunks/config-uzUuosv7.js.map +1 -1
  30. package/dist/chunks/context-CTbuwcYs.js.map +1 -1
  31. package/dist/chunks/deltaTone-B5OoS1vo.js.map +1 -1
  32. package/dist/chunks/es-Do2CNrC2.js.map +1 -1
  33. package/dist/chunks/fileValidation-D5TFBhbv.js.map +1 -1
  34. package/dist/chunks/focusables-BkzK42SQ.js.map +1 -1
  35. package/dist/chunks/{generated-DJ2dJ__C.js → generated-CSyPsWtM.js} +1 -1
  36. package/dist/chunks/{generated-DJ2dJ__C.js.map → generated-CSyPsWtM.js.map} +1 -1
  37. package/dist/chunks/grBadgeStyles-D8Mz73B5.js.map +1 -1
  38. package/dist/chunks/{grButtonStyles-B_-YRE__.js → grButtonStyles-B3wRWW_i.js} +4 -4
  39. package/dist/chunks/grButtonStyles-B3wRWW_i.js.map +1 -0
  40. package/dist/chunks/grLinkStyles-FME_qMpi.js.map +1 -1
  41. package/dist/chunks/grLoadingStyles-CnQaf5ry.js.map +1 -1
  42. package/dist/chunks/{grRadioStyles-D4gnU65n.js → grRadioStyles-DGL2QLy6.js} +1 -1
  43. package/dist/chunks/{grRadioStyles-D4gnU65n.js.map → grRadioStyles-DGL2QLy6.js.map} +1 -1
  44. package/dist/chunks/grSelectStyles-Cdtd10eY.js.map +1 -1
  45. package/dist/chunks/{grSliderStyles-B5uNxNJq.js → grSliderStyles-kaz6VXZ3.js} +9 -1
  46. package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +1 -0
  47. package/dist/chunks/{granular-provider-yJNX1g1G.js → granular-provider-Da2CJO6j.js} +3 -3
  48. package/dist/chunks/{granular-provider-yJNX1g1G.js.map → granular-provider-Da2CJO6j.js.map} +1 -1
  49. package/dist/chunks/granularityI18n-BC5zsj_d.js.map +1 -1
  50. package/dist/chunks/icon-Dag2tIMs.js.map +1 -1
  51. package/dist/chunks/inert-DIHCCn_1.js.map +1 -1
  52. package/dist/chunks/keyboard-DE2yhz_b.js.map +1 -1
  53. package/dist/chunks/numericStep-Bq2lj4ew.js.map +1 -1
  54. package/dist/chunks/optionFilter-DYw9XPPx.js.map +1 -1
  55. package/dist/chunks/overlayStack-C8cfsqXa.js.map +1 -1
  56. package/dist/chunks/portalRoot-CVhCgdG6.js.map +1 -1
  57. package/dist/chunks/renamedProp-BwcN-SJg.js.map +1 -1
  58. package/dist/chunks/{safelist-BOq5Li7p.js → safelist-DxkMj5IW.js} +1 -1
  59. package/dist/chunks/{safelist-BOq5Li7p.js.map → safelist-DxkMj5IW.js.map} +1 -1
  60. package/dist/chunks/slotNodes-DxNXpC7v.js.map +1 -1
  61. package/dist/chunks/useControlAddons-asUr10Pf.js.map +1 -1
  62. package/dist/chunks/useControlledOpen-DV3SqLTP.js.map +1 -1
  63. package/dist/chunks/useDragSort-0l47h4yb.js.map +1 -1
  64. package/dist/chunks/useFilePreviews-DnwgdyBs.js.map +1 -1
  65. package/dist/chunks/useFocusWithin-BwHE0rzm.js.map +1 -1
  66. package/dist/chunks/useModalOverlay-Cv5hF63W.js.map +1 -1
  67. package/dist/chunks/usePortalTarget-C0p-mhaM.js.map +1 -1
  68. package/dist/chunks/validation-5HhpanPP.js.map +1 -1
  69. package/dist/components/GrAlert/chunks/GrAlert-FAVf-ksH.js.map +1 -1
  70. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-X6RlmiJQ.js → GrAutocomplete-rYEY15UI.js} +1 -1
  71. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-rYEY15UI.js.map +1 -0
  72. package/dist/components/GrAutocomplete/index.js +1 -1
  73. package/dist/components/GrAutocomplete/styles.css +1 -1
  74. package/dist/components/GrAvatar/chunks/GrAvatar-CNmLmgcr.js.map +1 -1
  75. package/dist/components/GrBadge/chunks/{GrBadge-BsoocpF-.js → GrBadge-D2MfThPz.js} +1 -1
  76. package/dist/components/GrBadge/chunks/GrBadge-D2MfThPz.js.map +1 -0
  77. package/dist/components/GrBadge/index.js +1 -1
  78. package/dist/components/GrBadge/styles.css +1 -1
  79. package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-B-A3PRkE.js.map +1 -1
  80. package/dist/components/GrBottomNav/chunks/GrBottomNav-wtFatLjB.js.map +1 -1
  81. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-DRDNan_n.js.map +1 -1
  82. package/dist/components/GrButton/chunks/{GrButton-Bw2AH4uX.js → GrButton-7GP0zObj.js} +1 -1
  83. package/dist/components/GrButton/chunks/GrButton-7GP0zObj.js.map +1 -0
  84. package/dist/components/GrButton/index.js +3 -3
  85. package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -1
  86. package/dist/components/GrCard/chunks/GrCard-BttXz1pQ.js.map +1 -1
  87. package/dist/components/GrCheckbox/chunks/GrCheckbox-CEcHIsXM.js.map +1 -1
  88. package/dist/components/GrCheckboxGroup/chunks/GrCheckboxGroup-BOwrVcFr.js.map +1 -1
  89. package/dist/components/GrChip/chunks/GrChip-C0vU69tf.js.map +1 -1
  90. package/dist/components/GrChipGroup/chunks/GrChipGroup-C78Vcwos.js.map +1 -1
  91. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dkvkr91t.js → GrCodeBlock-Dp0eEBTZ.js} +1 -1
  92. package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dp0eEBTZ.js.map +1 -0
  93. package/dist/components/GrCodeBlock/index.js +1 -1
  94. package/dist/components/GrCollapse/chunks/GrCollapse-BlW6ybdL.js.map +1 -1
  95. package/dist/components/GrColorPicker/chunks/{GrColorPicker-C7ifyQ0R.js → GrColorPicker-B20gQ6AR.js} +1 -1
  96. package/dist/components/GrColorPicker/chunks/GrColorPicker-B20gQ6AR.js.map +1 -0
  97. package/dist/components/GrColorPicker/index.js +1 -1
  98. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-C5abL2Y7.js → GrCommandPalette-Cd0Yo3Dw.js} +1 -1
  99. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-Cd0Yo3Dw.js.map +1 -0
  100. package/dist/components/GrCommandPalette/index.js +1 -1
  101. package/dist/components/GrCommandPalette/styles.css +1 -1
  102. package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js.map +1 -1
  103. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-B9mIU78E.js → GrConfirmDialog-DOsbRhoZ.js} +3 -3
  104. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-DOsbRhoZ.js.map +1 -0
  105. package/dist/components/GrConfirmDialog/index.js +1 -1
  106. package/dist/components/GrContextMenu/chunks/GrContextMenu-_FKwQvuQ.js.map +1 -1
  107. package/dist/components/GrDataTable/chunks/{GrDataTable-C8a9_nCg.js → GrDataTable-CAGgRk27.js} +5 -3
  108. package/dist/components/GrDataTable/chunks/GrDataTable-CAGgRk27.js.map +1 -0
  109. package/dist/components/GrDataTable/index.js +1 -1
  110. package/dist/components/GrDelta/chunks/GrDelta-BZwkgQW-.js.map +1 -1
  111. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-BMeCgFV3.js.map +1 -1
  112. package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js → GrDialog-S1Vl-OhX.js} +1 -1
  113. package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js.map → GrDialog-S1Vl-OhX.js.map} +1 -1
  114. package/dist/components/GrDialog/index.js +1 -1
  115. package/dist/components/GrDialogService/chunks/{GrDialogService-6s2cQ-_6.js → GrDialogService-Cuhc4YLp.js} +4 -4
  116. package/dist/components/GrDialogService/chunks/GrDialogService-Cuhc4YLp.js.map +1 -0
  117. package/dist/components/GrDialogService/index.js +1 -1
  118. package/dist/components/GrDivider/chunks/GrDivider-BXavGcMX.js.map +1 -1
  119. package/dist/components/GrDrawer/chunks/{GrDrawer-B7PiAcbU.js → GrDrawer-C0YqVE9e.js} +1 -1
  120. package/dist/components/GrDrawer/chunks/GrDrawer-C0YqVE9e.js.map +1 -0
  121. package/dist/components/GrDrawer/index.js +1 -1
  122. package/dist/components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js.map +1 -1
  123. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-GOzuAXsi.js.map +1 -1
  124. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js.map +1 -1
  125. package/dist/components/GrFilePreview/chunks/GrFilePreview-C9Z7hMK8.js.map +1 -1
  126. package/dist/components/GrFileUpload/chunks/GrFileUpload-NsHkRRIa.js.map +1 -1
  127. package/dist/components/GrForm/chunks/GrForm-CrnfCsgj.js.map +1 -1
  128. package/dist/components/GrFormField/chunks/GrFormField-DSylU7IU.js.map +1 -1
  129. package/dist/components/GrFormFile/chunks/{GrFormFile-CYtXU9HV.js → GrFormFile-B1jGZyIj.js} +2 -2
  130. package/dist/components/GrFormFile/chunks/GrFormFile-B1jGZyIj.js.map +1 -0
  131. package/dist/components/GrFormFile/index.js +1 -1
  132. package/dist/components/GrFormFile/styles.css +1 -1
  133. package/dist/components/GrIcon/chunks/GrIcon-Dmf0c9ba.js.map +1 -1
  134. package/dist/components/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js.map +1 -1
  135. package/dist/components/GrInput/chunks/GrInput-BLywRZUN.js.map +1 -1
  136. package/dist/components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js.map +1 -1
  137. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-Cy2bknHO.js → GrJsonViewer-BCZ7lE2k.js} +2 -2
  138. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-BCZ7lE2k.js.map +1 -0
  139. package/dist/components/GrJsonViewer/index.js +1 -1
  140. package/dist/components/GrKbd/chunks/GrKbd-D2ga1H9i.js.map +1 -1
  141. package/dist/components/GrLink/chunks/GrLink-DYXw3W9w.js.map +1 -1
  142. package/dist/components/GrList/chunks/{GrList-DmT4qzLO.js → GrList-B_CRJB4c.js} +1 -1
  143. package/dist/components/GrList/chunks/GrList-B_CRJB4c.js.map +1 -0
  144. package/dist/components/GrList/index.js +1 -1
  145. package/dist/components/GrList/styles.css +1 -1
  146. package/dist/components/GrModal/chunks/GrModal-CCoWZuIl.js.map +1 -1
  147. package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js → GrNavbar-_rtHKwTf.js} +1 -1
  148. package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js.map → GrNavbar-_rtHKwTf.js.map} +1 -1
  149. package/dist/components/GrNavbar/index.js +1 -1
  150. package/dist/components/GrNumberInput/chunks/GrNumberInput-DQ59YICu.js.map +1 -1
  151. package/dist/components/GrPagination/chunks/{GrPagination-Cw3R21dp.js → GrPagination-B_kAhoAV.js} +2 -2
  152. package/dist/components/GrPagination/chunks/{GrPagination-Cw3R21dp.js.map → GrPagination-B_kAhoAV.js.map} +1 -1
  153. package/dist/components/GrPagination/index.js +1 -1
  154. package/dist/components/GrPopover/chunks/GrPopover-CofG-Tfe.js.map +1 -1
  155. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-DLcl1xiq.js → GrPromptDialog-BuJQMZLM.js} +4 -4
  156. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-BuJQMZLM.js.map +1 -0
  157. package/dist/components/GrPromptDialog/index.js +1 -1
  158. package/dist/components/GrRadio/chunks/{GrRadio-C_rESc5g.js → GrRadio-Aq3v8XgG.js} +1 -1
  159. package/dist/components/GrRadio/chunks/GrRadio-Aq3v8XgG.js.map +1 -0
  160. package/dist/components/GrRadio/index.js +2 -2
  161. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CdQO4G-U.js → GrRadioGroup-y9LVdTWh.js} +1 -1
  162. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-y9LVdTWh.js.map +1 -0
  163. package/dist/components/GrRadioGroup/index.js +1 -1
  164. package/dist/components/GrRating/chunks/GrRating-IEiTOdnF.js.map +1 -1
  165. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js → GrResponseErrorBanner-CBVRpgIG.js} +1 -1
  166. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js.map → GrResponseErrorBanner-CBVRpgIG.js.map} +1 -1
  167. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DudGc9LO.js → GrResponseErrorBanner-DMeOWlzj.js} +1 -1
  168. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js.map +1 -0
  169. package/dist/components/GrResponseErrorBanner/index.js +2 -2
  170. package/dist/components/GrSegmented/chunks/GrSegmented-CB-VR-yL.js.map +1 -1
  171. package/dist/components/GrSelect/chunks/{GrSelect-BiUrSSxc.js → GrSelect-gCeRFgQo.js} +1 -1
  172. package/dist/components/GrSelect/chunks/GrSelect-gCeRFgQo.js.map +1 -0
  173. package/dist/components/GrSelect/index.js +1 -1
  174. package/dist/components/GrSelect/styles.css +1 -1
  175. package/dist/components/GrSidebar/chunks/{GrSidebar-B8EQIlfW.js → GrSidebar-alkwBUzL.js} +1 -1
  176. package/dist/components/GrSidebar/chunks/GrSidebar-alkwBUzL.js.map +1 -0
  177. package/dist/components/GrSidebar/index.js +1 -1
  178. package/dist/components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js.map +1 -1
  179. package/dist/components/GrSlider/chunks/{GrSlider-DJfeEl4h.js → GrSlider-DTTrZTHK.js} +3 -3
  180. package/dist/components/GrSlider/chunks/GrSlider-DTTrZTHK.js.map +1 -0
  181. package/dist/components/GrSlider/index.js +2 -2
  182. package/dist/components/GrSortableList/chunks/GrSortableList-HyKX--rO.js.map +1 -1
  183. package/dist/components/GrSplitter/chunks/GrSplitter-MltjaADn.js.map +1 -1
  184. package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +1 -1
  185. package/dist/components/GrSteps/chunks/GrSteps-C2jxpZoN.js.map +1 -1
  186. package/dist/components/GrSwitch/chunks/{GrSwitch-g_OOSkh7.js → GrSwitch-7Oe5QfQZ.js} +1 -1
  187. package/dist/components/GrSwitch/chunks/GrSwitch-7Oe5QfQZ.js.map +1 -0
  188. package/dist/components/GrSwitch/index.js +1 -1
  189. package/dist/components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js.map +1 -1
  190. package/dist/components/GrTable/chunks/GrTable-Zcdz2St_.js.map +1 -1
  191. package/dist/components/GrTextarea/chunks/{GrTextarea-KREK75Bu.js → GrTextarea-DinXG12-.js} +10 -10
  192. package/dist/components/GrTextarea/chunks/GrTextarea-DinXG12-.js.map +1 -0
  193. package/dist/components/GrTextarea/index.js +1 -1
  194. package/dist/components/GrTimeline/chunks/GrTimeline-BiHpArsg.js.map +1 -1
  195. package/dist/components/GrToaster/chunks/{GrToaster-Dp7-4B8k.js → GrToaster-COXIBKzq.js} +2 -2
  196. package/dist/components/GrToaster/chunks/GrToaster-COXIBKzq.js.map +1 -0
  197. package/dist/components/GrToaster/index.js +1 -1
  198. package/dist/components/GrToaster/styles.css +1 -1
  199. package/dist/components/GrTooltip/chunks/GrTooltip-uYETdbCD.js.map +1 -1
  200. package/dist/components/GrTree/chunks/{GrTree-DC89I4AP.js → GrTree-Ci6CZfKR.js} +5 -5
  201. package/dist/components/GrTree/chunks/GrTree-Ci6CZfKR.js.map +1 -0
  202. package/dist/components/GrTree/index.js +1 -1
  203. package/dist/components/GrTree/styles.css +1 -1
  204. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-iJnMl2t9.js → GrTreeSelect-BHwgGJcT.js} +1 -1
  205. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHwgGJcT.js.map +1 -0
  206. package/dist/components/GrTreeSelect/index.js +1 -1
  207. package/dist/composables/useAnnouncer.js.map +1 -1
  208. package/dist/composables/useComboboxNavigation.js.map +1 -1
  209. package/dist/composables/useDragGesture.js.map +1 -1
  210. package/dist/composables/useFocusTrap.js.map +1 -1
  211. package/dist/composables/useOverlayLayer.js.map +1 -1
  212. package/dist/composables/useRovingFocus.js.map +1 -1
  213. package/dist/composables/useTheme.js.map +1 -1
  214. package/dist/composables/useToast.js.map +1 -1
  215. package/dist/composables/useVirtualList.js.map +1 -1
  216. package/dist/directives/autofocus.js.map +1 -1
  217. package/dist/directives/autosize.js.map +1 -1
  218. package/dist/directives/clickOutside.js.map +1 -1
  219. package/dist/directives/dropzone.js.map +1 -1
  220. package/dist/directives/hotkey.js.map +1 -1
  221. package/dist/directives/loading.js.map +1 -1
  222. package/dist/granular-provider-node.js +1 -1
  223. package/dist/granular-provider.js +1 -1
  224. package/dist/index.js +33 -33
  225. package/dist/testing.js +2 -2
  226. package/dist/testing.js.map +1 -1
  227. package/dist/theme-apply.js.map +1 -1
  228. package/dist/theme.js +1 -1
  229. package/dist/theme.js.map +1 -1
  230. package/dist/tokens.js +1 -1
  231. package/dist/types/components/GrCodeBlock/tokenizeJson.d.ts +1 -3
  232. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +1 -1
  233. package/dist/types/components/GrInput/GrInput.vue.d.ts +24 -24
  234. package/dist/types/components/GrSlider/grSliderStyles.d.ts +9 -1
  235. package/dist/types/components/GrTabPanels/GrTabPanel.vue.d.ts +3 -3
  236. package/dist/vue/index.js.map +1 -1
  237. package/dist/web-types.json +1 -1
  238. package/package.json +3 -3
  239. package/dist/chunks/grButtonStyles-B_-YRE__.js.map +0 -1
  240. package/dist/chunks/grSliderStyles-B5uNxNJq.js.map +0 -1
  241. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-X6RlmiJQ.js.map +0 -1
  242. package/dist/components/GrBadge/chunks/GrBadge-BsoocpF-.js.map +0 -1
  243. package/dist/components/GrButton/chunks/GrButton-Bw2AH4uX.js.map +0 -1
  244. package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dkvkr91t.js.map +0 -1
  245. package/dist/components/GrColorPicker/chunks/GrColorPicker-C7ifyQ0R.js.map +0 -1
  246. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-C5abL2Y7.js.map +0 -1
  247. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-B9mIU78E.js.map +0 -1
  248. package/dist/components/GrDataTable/chunks/GrDataTable-C8a9_nCg.js.map +0 -1
  249. package/dist/components/GrDialogService/chunks/GrDialogService-6s2cQ-_6.js.map +0 -1
  250. package/dist/components/GrDrawer/chunks/GrDrawer-B7PiAcbU.js.map +0 -1
  251. package/dist/components/GrFormFile/chunks/GrFormFile-CYtXU9HV.js.map +0 -1
  252. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-Cy2bknHO.js.map +0 -1
  253. package/dist/components/GrList/chunks/GrList-DmT4qzLO.js.map +0 -1
  254. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-DLcl1xiq.js.map +0 -1
  255. package/dist/components/GrRadio/chunks/GrRadio-C_rESc5g.js.map +0 -1
  256. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-CdQO4G-U.js.map +0 -1
  257. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DudGc9LO.js.map +0 -1
  258. package/dist/components/GrSelect/chunks/GrSelect-BiUrSSxc.js.map +0 -1
  259. package/dist/components/GrSidebar/chunks/GrSidebar-B8EQIlfW.js.map +0 -1
  260. package/dist/components/GrSlider/chunks/GrSlider-DJfeEl4h.js.map +0 -1
  261. package/dist/components/GrSwitch/chunks/GrSwitch-g_OOSkh7.js.map +0 -1
  262. package/dist/components/GrTextarea/chunks/GrTextarea-KREK75Bu.js.map +0 -1
  263. package/dist/components/GrToaster/chunks/GrToaster-Dp7-4B8k.js.map +0 -1
  264. package/dist/components/GrTree/chunks/GrTree-DC89I4AP.js.map +0 -1
  265. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-iJnMl2t9.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"GrPagination-Cw3R21dp.js","names":[],"sources":["../../../../src/components/GrPagination/GrPagination.vue","../../../../src/components/GrPagination/GrPagination.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrSelect from '../GrSelect/GrSelect.vue'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport {\n type GrPaginationSize,\n ellipsisSizes,\n jumperSizes,\n labelSizes,\n navButtonSizes,\n pageListGaps,\n pageSizes,\n pageSizeSelectWidths,\n rowGaps,\n} from './grPaginationStyles'\n\n/**\n * Пропы пагинации.\n *\n * `total` интерпретируется как общее количество элементов; число страниц\n * вычисляется из `total` и `pageSize`. Номера усекаются многоточием\n * (алгоритм boundary/sibling, как у MUI): всегда видны первая/последняя страница\n * и `siblingCount` соседей вокруг текущей.\n */\nexport interface GrPaginationProps {\n page: number\n pageSize: number\n total: number\n pageSizes?: number[]\n /** Сколько соседних страниц показывать вокруг текущей. По умолчанию `1`. */\n siblingCount?: number\n /** Сколько крайних страниц всегда показывать с каждого края. По умолчанию `1`. */\n boundaryCount?: number\n /**\n * Компактный вариант: вместо нумерованных страниц показывается индикатор\n * «текущая / всего» — удобно для узких мест (мобайл, тулбары таблиц).\n */\n compact?: boolean\n /** Показывать поле «перейти к странице» с быстрым переходом по вводу номера. */\n showJumper?: boolean\n /** Показывать селект размера страницы. */\n showPageSize?: boolean\n /** Показывать диапазон показанных элементов — «1–20 из 137». Слот `#total` сильнее. */\n showTotal?: boolean\n /** i18n-подпись перед полем перехода. По умолчанию — `gr.pagination.jumpTo`. */\n jumperLabel?: string\n /**\n * Имя навигационного лендмарка. По умолчанию — `gr.pagination.label`; задавать\n * стоит там, где пагинаций на странице несколько и их надо различать.\n */\n ariaLabel?: string\n /** Гасит всю пагинацию: номера, кнопки, селект размера и поле перехода. */\n disabled?: boolean\n size?: GrPaginationSize\n}\n\nexport interface GrPaginationEmits {\n (e: 'update:page', value: number): void\n (e: 'update:pageSize', value: number): void\n}\n\nconst { t } = useGranularityTranslations()\n\nconst props = withDefaults(defineProps<GrPaginationProps>(), {\n pageSizes: () => [10, 20, 50],\n siblingCount: 1,\n boundaryCount: 1,\n compact: false,\n showJumper: false,\n showPageSize: false,\n showTotal: false,\n jumperLabel: undefined,\n ariaLabel: undefined,\n disabled: false,\n size: undefined,\n})\n\ndefineSlots<{\n /** Диапазон показанных элементов целиком — вместо строки из локали. */\n total?: (props: { from: number, to: number, total: number }) => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPagination' })\n\nconst rowClass = computed(() => rowGaps[resolvedSize.value])\nconst pageListClass = computed(() => pageListGaps[resolvedSize.value])\nconst pageClass = computed(() => pageSizes[resolvedSize.value])\nconst jumperClass = computed(() => jumperSizes[resolvedSize.value])\nconst ellipsisClass = computed(() => ellipsisSizes[resolvedSize.value])\nconst labelClass = computed(() => labelSizes[resolvedSize.value])\nconst selectWrapClass = computed(() => pageSizeSelectWidths[resolvedSize.value])\nconst navButtonSize = computed(() => navButtonSizes[resolvedSize.value])\n\nconst emit = defineEmits<GrPaginationEmits>()\n\n// Делитель клампится: `pageSize: 0` дал бы `Infinity` страниц и бесконечный\n// цикл в `range()`.\nconst resolvedPageSize = computed(() => Math.max(1, Math.trunc(props.pageSize)))\nconst pageCount = computed(() => Math.max(1, Math.ceil(props.total / resolvedPageSize.value)))\n\n// Рендер идёт от зажатого номера: вотчер ниже просит родителя подтянуть `page`,\n// но на первом рендере он молчит, и без клампа пагинация осталась бы вовсе без\n// активной страницы.\nconst currentPage = computed(() => Math.min(Math.max(Math.trunc(props.page), 1), pageCount.value))\n\n// Контролируемый компонент: если `total`/`pageSize` уменьшились и текущая `page`\n// вышла за диапазон — просим родителя подтянуть её к последней странице.\nwatch(pageCount, (count) => {\n if (props.page > count)\n emit('update:page', count)\n})\n\nconst pageSizeModel = computed({\n get: () => String(props.pageSize),\n set: (value: string) => emit('update:pageSize', Number(value)),\n})\n\nconst pageSizeOptions = computed(() =>\n props.pageSizes.map(pageSize => ({\n value: String(pageSize),\n label: String(pageSize),\n })),\n)\n\nconst rangeFrom = computed(() => (props.total === 0 ? 0 : (currentPage.value - 1) * resolvedPageSize.value + 1))\nconst rangeTo = computed(() => Math.min(currentPage.value * resolvedPageSize.value, props.total))\n\ntype PaginationItem = number | 'ellipsis-start' | 'ellipsis-end'\n\nfunction range(start: number, end: number): number[] {\n const list: number[] = []\n for (let page = start; page <= end; page += 1)\n list.push(page)\n return list\n}\n\n// Алгоритм usePagination как в MUI: крайние `boundaryCount` страниц + `siblingCount`\n// соседей вокруг текущей, разрывы схлопываются в многоточие. Одиночный «пропущенный»\n// номер показываем как номер, а не как «…» (визуально ровнее).\nconst items = computed<PaginationItem[]>(() => {\n const count = pageCount.value\n const current = currentPage.value\n const boundaryCount = Math.max(0, props.boundaryCount)\n const siblingCount = Math.max(0, props.siblingCount)\n\n const startPages = range(1, Math.min(boundaryCount, count))\n const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count)\n\n const siblingsStart = Math.max(\n Math.min(current - siblingCount, count - boundaryCount - siblingCount * 2 - 1),\n boundaryCount + 2,\n )\n const siblingsEnd = Math.min(\n Math.max(current + siblingCount, boundaryCount + siblingCount * 2 + 2),\n endPages.length > 0 ? endPages[0] - 2 : count - 1,\n )\n\n return [\n ...startPages,\n ...(siblingsStart > boundaryCount + 2\n ? ['ellipsis-start' as const]\n : boundaryCount + 1 < count - boundaryCount\n ? [boundaryCount + 1]\n : []),\n ...range(siblingsStart, siblingsEnd),\n ...(siblingsEnd < count - boundaryCount - 1\n ? ['ellipsis-end' as const]\n : count - boundaryCount > boundaryCount\n ? [count - boundaryCount]\n : []),\n ...endPages,\n ]\n})\n\nfunction goTo(page: number): void {\n if (props.disabled)\n return\n\n emit('update:page', page)\n}\n\nfunction prev(): void {\n goTo(Math.max(1, currentPage.value - 1))\n}\n\nfunction next(): void {\n goTo(Math.min(pageCount.value, currentPage.value + 1))\n}\n\nfunction first(): void {\n goTo(1)\n}\n\nfunction last(): void {\n goTo(pageCount.value)\n}\n\n// «Перейти к странице»: клампим введённый номер к диапазону [1, pageCount]\n// и сбрасываем поле после перехода.\nconst jumperValue = ref('')\n\nfunction submitJumper(): void {\n const parsed = Number.parseInt(jumperValue.value, 10)\n jumperValue.value = ''\n if (Number.isNaN(parsed))\n return\n\n goTo(Math.min(pageCount.value, Math.max(1, parsed)))\n}\n\nconst resolvedJumperLabel = computed(() => props.jumperLabel ?? t('gr.pagination.jumpTo', 'Go to'))\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.pagination.label', 'Pagination'))\nconst statusText = computed(() =>\n t('gr.pagination.status', 'Page {page} of {count}', { page: currentPage.value, count: pageCount.value }),\n)\nconst totalText = computed(() =>\n t('gr.pagination.total', '{from}–{to} of {total}', { from: rangeFrom.value, to: rangeTo.value, total: props.total }),\n)\n</script>\n\n<template>\n <div\n class=\"flex flex-wrap items-center justify-end\"\n :class=\"rowClass\"\n data-gr-pagination\n role=\"navigation\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <div\n v-if=\"showTotal\"\n data-gr-pagination-total\n class=\"text-[var(--gr-muted-fg)] tabular-nums\"\n :class=\"labelClass\"\n >\n <slot name=\"total\" :from=\"rangeFrom\" :to=\"rangeTo\" :total=\"total\">\n {{ totalText }}\n </slot>\n </div>\n\n <div v-if=\"showPageSize\" :class=\"selectWrapClass\">\n <GrSelect\n v-model=\"pageSizeModel\"\n :options=\"pageSizeOptions\"\n :size=\"resolvedSize\"\n :disabled=\"disabled\"\n :aria-label=\"t('gr.pagination.pageSize', 'Page size')\"\n />\n </div>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" :aria-label=\"t('gr.pagination.first', 'First page')\" data-gr-pagination-first @click=\"first\">\n «\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" data-gr-pagination-prev @click=\"prev\">\n {{ t('gr.pagination.prev', 'Prev') }}\n </GrButton>\n\n <!-- Компактный вариант: индикатор «текущая / всего» вместо нумерованных страниц. -->\n <div\n v-if=\"compact\"\n data-gr-pagination-compact\n class=\"px-2 text-[var(--gr-fg)] tabular-nums\"\n :class=\"labelClass\"\n role=\"status\"\n >\n {{ currentPage }} / {{ pageCount }}\n </div>\n\n <template v-else>\n <ul class=\"flex items-center [list-style:none]\" :class=\"pageListClass\" data-gr-pagination-pages role=\"list\">\n <li v-for=\"(item, index) in items\" :key=\"index\" :aria-hidden=\"typeof item === 'string' ? 'true' : undefined\">\n <span\n v-if=\"item === 'ellipsis-start' || item === 'ellipsis-end'\"\n data-gr-pagination-ellipsis\n class=\"grid place-items-center text-[var(--gr-muted-fg)]\"\n :class=\"ellipsisClass\"\n >…</span>\n <button\n v-else\n type=\"button\"\n data-gr-pagination-page\n :disabled=\"disabled\"\n :aria-current=\"item === currentPage ? 'page' : undefined\"\n :aria-label=\"t('gr.pagination.page', 'Page {n}', { n: item })\"\n class=\"rounded-[var(--gr-radius-control)] font-600 transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"[\n pageClass,\n item === currentPage\n ? 'bg-[var(--gr-primary)] text-[var(--gr-primary-fg)]'\n // Подложка тональная, а не `--gr-muted`: серый на белом фоне даёт\n // 1.10:1 и на светлой теме hover был практически не виден, хотя у\n // соседних «назад/вперёд» (ghost-кнопки) он тонирован. Ряд обязан\n // читаться одним контролом.\n : 'text-[var(--gr-muted-fg)] hover:bg-[var(--gr-accent)] hover:text-[var(--gr-accent-fg)]',\n ]\"\n @click=\"goTo(item)\"\n >\n {{ item }}\n </button>\n </li>\n </ul>\n\n <!-- В компактном режиме смену страницы объявляет видимый индикатор. -->\n <div data-gr-pagination-status role=\"status\" class=\"sr-only\">\n {{ statusText }}\n </div>\n </template>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" data-gr-pagination-next @click=\"next\">\n {{ t('gr.pagination.next', 'Next') }}\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" :aria-label=\"t('gr.pagination.last', 'Last page')\" data-gr-pagination-last @click=\"last\">\n »\n </GrButton>\n\n <!-- «Перейти к странице»: Enter или blur применяют введённый номер. -->\n <div v-if=\"showJumper\" class=\"flex items-center gap-2 text-[var(--gr-muted-fg)]\" :class=\"labelClass\">\n <span>{{ resolvedJumperLabel }}</span>\n <input\n v-model=\"jumperValue\"\n type=\"number\"\n min=\"1\"\n :max=\"pageCount\"\n inputmode=\"numeric\"\n data-gr-pagination-jumper\n :disabled=\"disabled\"\n :aria-label=\"resolvedJumperLabel\"\n class=\"rounded-[var(--gr-radius-control)] border border-[var(--gr-brd)] bg-[var(--gr-bg)] px-2 text-center text-[var(--gr-fg)] tabular-nums transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"jumperClass\"\n @keydown.enter=\"submitJumper\"\n @blur=\"submitJumper\"\n >\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrSelect from '../GrSelect/GrSelect.vue'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport {\n type GrPaginationSize,\n ellipsisSizes,\n jumperSizes,\n labelSizes,\n navButtonSizes,\n pageListGaps,\n pageSizes,\n pageSizeSelectWidths,\n rowGaps,\n} from './grPaginationStyles'\n\n/**\n * Пропы пагинации.\n *\n * `total` интерпретируется как общее количество элементов; число страниц\n * вычисляется из `total` и `pageSize`. Номера усекаются многоточием\n * (алгоритм boundary/sibling, как у MUI): всегда видны первая/последняя страница\n * и `siblingCount` соседей вокруг текущей.\n */\nexport interface GrPaginationProps {\n page: number\n pageSize: number\n total: number\n pageSizes?: number[]\n /** Сколько соседних страниц показывать вокруг текущей. По умолчанию `1`. */\n siblingCount?: number\n /** Сколько крайних страниц всегда показывать с каждого края. По умолчанию `1`. */\n boundaryCount?: number\n /**\n * Компактный вариант: вместо нумерованных страниц показывается индикатор\n * «текущая / всего» — удобно для узких мест (мобайл, тулбары таблиц).\n */\n compact?: boolean\n /** Показывать поле «перейти к странице» с быстрым переходом по вводу номера. */\n showJumper?: boolean\n /** Показывать селект размера страницы. */\n showPageSize?: boolean\n /** Показывать диапазон показанных элементов — «1–20 из 137». Слот `#total` сильнее. */\n showTotal?: boolean\n /** i18n-подпись перед полем перехода. По умолчанию — `gr.pagination.jumpTo`. */\n jumperLabel?: string\n /**\n * Имя навигационного лендмарка. По умолчанию — `gr.pagination.label`; задавать\n * стоит там, где пагинаций на странице несколько и их надо различать.\n */\n ariaLabel?: string\n /** Гасит всю пагинацию: номера, кнопки, селект размера и поле перехода. */\n disabled?: boolean\n size?: GrPaginationSize\n}\n\nexport interface GrPaginationEmits {\n (e: 'update:page', value: number): void\n (e: 'update:pageSize', value: number): void\n}\n\nconst { t } = useGranularityTranslations()\n\nconst props = withDefaults(defineProps<GrPaginationProps>(), {\n pageSizes: () => [10, 20, 50],\n siblingCount: 1,\n boundaryCount: 1,\n compact: false,\n showJumper: false,\n showPageSize: false,\n showTotal: false,\n jumperLabel: undefined,\n ariaLabel: undefined,\n disabled: false,\n size: undefined,\n})\n\ndefineSlots<{\n /** Диапазон показанных элементов целиком — вместо строки из локали. */\n total?: (props: { from: number, to: number, total: number }) => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPagination' })\n\nconst rowClass = computed(() => rowGaps[resolvedSize.value])\nconst pageListClass = computed(() => pageListGaps[resolvedSize.value])\nconst pageClass = computed(() => pageSizes[resolvedSize.value])\nconst jumperClass = computed(() => jumperSizes[resolvedSize.value])\nconst ellipsisClass = computed(() => ellipsisSizes[resolvedSize.value])\nconst labelClass = computed(() => labelSizes[resolvedSize.value])\nconst selectWrapClass = computed(() => pageSizeSelectWidths[resolvedSize.value])\nconst navButtonSize = computed(() => navButtonSizes[resolvedSize.value])\n\nconst emit = defineEmits<GrPaginationEmits>()\n\n// Делитель клампится: `pageSize: 0` дал бы `Infinity` страниц и бесконечный\n// цикл в `range()`.\nconst resolvedPageSize = computed(() => Math.max(1, Math.trunc(props.pageSize)))\nconst pageCount = computed(() => Math.max(1, Math.ceil(props.total / resolvedPageSize.value)))\n\n// Рендер идёт от зажатого номера: вотчер ниже просит родителя подтянуть `page`,\n// но на первом рендере он молчит, и без клампа пагинация осталась бы вовсе без\n// активной страницы.\nconst currentPage = computed(() => Math.min(Math.max(Math.trunc(props.page), 1), pageCount.value))\n\n// Контролируемый компонент: если `total`/`pageSize` уменьшились и текущая `page`\n// вышла за диапазон — просим родителя подтянуть её к последней странице.\nwatch(pageCount, (count) => {\n if (props.page > count)\n emit('update:page', count)\n})\n\nconst pageSizeModel = computed({\n get: () => String(props.pageSize),\n set: (value: string) => emit('update:pageSize', Number(value)),\n})\n\nconst pageSizeOptions = computed(() =>\n props.pageSizes.map(pageSize => ({\n value: String(pageSize),\n label: String(pageSize),\n })),\n)\n\nconst rangeFrom = computed(() => (props.total === 0 ? 0 : (currentPage.value - 1) * resolvedPageSize.value + 1))\nconst rangeTo = computed(() => Math.min(currentPage.value * resolvedPageSize.value, props.total))\n\ntype PaginationItem = number | 'ellipsis-start' | 'ellipsis-end'\n\nfunction range(start: number, end: number): number[] {\n const list: number[] = []\n for (let page = start; page <= end; page += 1)\n list.push(page)\n return list\n}\n\n// Алгоритм usePagination как в MUI: крайние `boundaryCount` страниц + `siblingCount`\n// соседей вокруг текущей, разрывы схлопываются в многоточие. Одиночный «пропущенный»\n// номер показываем как номер, а не как «…» (визуально ровнее).\nconst items = computed<PaginationItem[]>(() => {\n const count = pageCount.value\n const current = currentPage.value\n const boundaryCount = Math.max(0, props.boundaryCount)\n const siblingCount = Math.max(0, props.siblingCount)\n\n const startPages = range(1, Math.min(boundaryCount, count))\n const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count)\n\n const siblingsStart = Math.max(\n Math.min(current - siblingCount, count - boundaryCount - siblingCount * 2 - 1),\n boundaryCount + 2,\n )\n const siblingsEnd = Math.min(\n Math.max(current + siblingCount, boundaryCount + siblingCount * 2 + 2),\n endPages.length > 0 ? endPages[0] - 2 : count - 1,\n )\n\n return [\n ...startPages,\n ...(siblingsStart > boundaryCount + 2\n ? ['ellipsis-start' as const]\n : boundaryCount + 1 < count - boundaryCount\n ? [boundaryCount + 1]\n : []),\n ...range(siblingsStart, siblingsEnd),\n ...(siblingsEnd < count - boundaryCount - 1\n ? ['ellipsis-end' as const]\n : count - boundaryCount > boundaryCount\n ? [count - boundaryCount]\n : []),\n ...endPages,\n ]\n})\n\nfunction goTo(page: number): void {\n if (props.disabled)\n return\n\n emit('update:page', page)\n}\n\nfunction prev(): void {\n goTo(Math.max(1, currentPage.value - 1))\n}\n\nfunction next(): void {\n goTo(Math.min(pageCount.value, currentPage.value + 1))\n}\n\nfunction first(): void {\n goTo(1)\n}\n\nfunction last(): void {\n goTo(pageCount.value)\n}\n\n// «Перейти к странице»: клампим введённый номер к диапазону [1, pageCount]\n// и сбрасываем поле после перехода.\nconst jumperValue = ref('')\n\nfunction submitJumper(): void {\n const parsed = Number.parseInt(jumperValue.value, 10)\n jumperValue.value = ''\n if (Number.isNaN(parsed))\n return\n\n goTo(Math.min(pageCount.value, Math.max(1, parsed)))\n}\n\nconst resolvedJumperLabel = computed(() => props.jumperLabel ?? t('gr.pagination.jumpTo', 'Go to'))\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.pagination.label', 'Pagination'))\nconst statusText = computed(() =>\n t('gr.pagination.status', 'Page {page} of {count}', { page: currentPage.value, count: pageCount.value }),\n)\nconst totalText = computed(() =>\n t('gr.pagination.total', '{from}–{to} of {total}', { from: rangeFrom.value, to: rangeTo.value, total: props.total }),\n)\n</script>\n\n<template>\n <div\n class=\"flex flex-wrap items-center justify-end\"\n :class=\"rowClass\"\n data-gr-pagination\n role=\"navigation\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <div\n v-if=\"showTotal\"\n data-gr-pagination-total\n class=\"text-[var(--gr-muted-fg)] tabular-nums\"\n :class=\"labelClass\"\n >\n <slot name=\"total\" :from=\"rangeFrom\" :to=\"rangeTo\" :total=\"total\">\n {{ totalText }}\n </slot>\n </div>\n\n <div v-if=\"showPageSize\" :class=\"selectWrapClass\">\n <GrSelect\n v-model=\"pageSizeModel\"\n :options=\"pageSizeOptions\"\n :size=\"resolvedSize\"\n :disabled=\"disabled\"\n :aria-label=\"t('gr.pagination.pageSize', 'Page size')\"\n />\n </div>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" :aria-label=\"t('gr.pagination.first', 'First page')\" data-gr-pagination-first @click=\"first\">\n «\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" data-gr-pagination-prev @click=\"prev\">\n {{ t('gr.pagination.prev', 'Prev') }}\n </GrButton>\n\n <!-- Компактный вариант: индикатор «текущая / всего» вместо нумерованных страниц. -->\n <div\n v-if=\"compact\"\n data-gr-pagination-compact\n class=\"px-2 text-[var(--gr-fg)] tabular-nums\"\n :class=\"labelClass\"\n role=\"status\"\n >\n {{ currentPage }} / {{ pageCount }}\n </div>\n\n <template v-else>\n <ul class=\"flex items-center [list-style:none]\" :class=\"pageListClass\" data-gr-pagination-pages role=\"list\">\n <li v-for=\"(item, index) in items\" :key=\"index\" :aria-hidden=\"typeof item === 'string' ? 'true' : undefined\">\n <span\n v-if=\"item === 'ellipsis-start' || item === 'ellipsis-end'\"\n data-gr-pagination-ellipsis\n class=\"grid place-items-center text-[var(--gr-muted-fg)]\"\n :class=\"ellipsisClass\"\n >…</span>\n <button\n v-else\n type=\"button\"\n data-gr-pagination-page\n :disabled=\"disabled\"\n :aria-current=\"item === currentPage ? 'page' : undefined\"\n :aria-label=\"t('gr.pagination.page', 'Page {n}', { n: item })\"\n class=\"rounded-[var(--gr-radius-control)] font-600 transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"[\n pageClass,\n item === currentPage\n ? 'bg-[var(--gr-primary)] text-[var(--gr-primary-fg)]'\n // Подложка тональная, а не `--gr-muted`: серый на белом фоне даёт\n // 1.10:1 и на светлой теме hover был практически не виден, хотя у\n // соседних «назад/вперёд» (ghost-кнопки) он тонирован. Ряд обязан\n // читаться одним контролом.\n : 'text-[var(--gr-muted-fg)] hover:bg-[var(--gr-accent)] hover:text-[var(--gr-accent-fg)]',\n ]\"\n @click=\"goTo(item)\"\n >\n {{ item }}\n </button>\n </li>\n </ul>\n\n <!-- В компактном режиме смену страницы объявляет видимый индикатор. -->\n <div data-gr-pagination-status role=\"status\" class=\"sr-only\">\n {{ statusText }}\n </div>\n </template>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" data-gr-pagination-next @click=\"next\">\n {{ t('gr.pagination.next', 'Next') }}\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" :aria-label=\"t('gr.pagination.last', 'Last page')\" data-gr-pagination-last @click=\"last\">\n »\n </GrButton>\n\n <!-- «Перейти к странице»: Enter или blur применяют введённый номер. -->\n <div v-if=\"showJumper\" class=\"flex items-center gap-2 text-[var(--gr-muted-fg)]\" :class=\"labelClass\">\n <span>{{ resolvedJumperLabel }}</span>\n <input\n v-model=\"jumperValue\"\n type=\"number\"\n min=\"1\"\n :max=\"pageCount\"\n inputmode=\"numeric\"\n data-gr-pagination-jumper\n :disabled=\"disabled\"\n :aria-label=\"resolvedJumperLabel\"\n class=\"rounded-[var(--gr-radius-control)] border border-[var(--gr-brd)] bg-[var(--gr-bg)] px-2 text-center text-[var(--gr-fg)] tabular-nums transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"jumperClass\"\n @keydown.enter=\"submitJumper\"\n @blur=\"submitJumper\"\n >\n </div>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrPagination-B_kAhoAV.js","names":[],"sources":["../../../../src/components/GrPagination/GrPagination.vue","../../../../src/components/GrPagination/GrPagination.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrSelect from '../GrSelect/GrSelect.vue'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport {\n type GrPaginationSize,\n ellipsisSizes,\n jumperSizes,\n labelSizes,\n navButtonSizes,\n pageListGaps,\n pageSizes,\n pageSizeSelectWidths,\n rowGaps,\n} from './grPaginationStyles'\n\n/**\n * Пропы пагинации.\n *\n * `total` интерпретируется как общее количество элементов; число страниц\n * вычисляется из `total` и `pageSize`. Номера усекаются многоточием\n * (алгоритм boundary/sibling, как у MUI): всегда видны первая/последняя страница\n * и `siblingCount` соседей вокруг текущей.\n */\nexport interface GrPaginationProps {\n page: number\n pageSize: number\n total: number\n pageSizes?: number[]\n /** Сколько соседних страниц показывать вокруг текущей. По умолчанию `1`. */\n siblingCount?: number\n /** Сколько крайних страниц всегда показывать с каждого края. По умолчанию `1`. */\n boundaryCount?: number\n /**\n * Компактный вариант: вместо нумерованных страниц показывается индикатор\n * «текущая / всего» — удобно для узких мест (мобайл, тулбары таблиц).\n */\n compact?: boolean\n /** Показывать поле «перейти к странице» с быстрым переходом по вводу номера. */\n showJumper?: boolean\n /** Показывать селект размера страницы. */\n showPageSize?: boolean\n /** Показывать диапазон показанных элементов — «1–20 из 137». Слот `#total` сильнее. */\n showTotal?: boolean\n /** i18n-подпись перед полем перехода. По умолчанию — `gr.pagination.jumpTo`. */\n jumperLabel?: string\n /**\n * Имя навигационного лендмарка. По умолчанию — `gr.pagination.label`; задавать\n * стоит там, где пагинаций на странице несколько и их надо различать.\n */\n ariaLabel?: string\n /** Гасит всю пагинацию: номера, кнопки, селект размера и поле перехода. */\n disabled?: boolean\n size?: GrPaginationSize\n}\n\nexport interface GrPaginationEmits {\n (e: 'update:page', value: number): void\n (e: 'update:pageSize', value: number): void\n}\n\nconst { t } = useGranularityTranslations()\n\nconst props = withDefaults(defineProps<GrPaginationProps>(), {\n pageSizes: () => [10, 20, 50],\n siblingCount: 1,\n boundaryCount: 1,\n compact: false,\n showJumper: false,\n showPageSize: false,\n showTotal: false,\n jumperLabel: undefined,\n ariaLabel: undefined,\n disabled: false,\n size: undefined,\n})\n\ndefineSlots<{\n /** Диапазон показанных элементов целиком — вместо строки из локали. */\n total?: (props: { from: number, to: number, total: number }) => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPagination' })\n\nconst rowClass = computed(() => rowGaps[resolvedSize.value])\nconst pageListClass = computed(() => pageListGaps[resolvedSize.value])\nconst pageClass = computed(() => pageSizes[resolvedSize.value])\nconst jumperClass = computed(() => jumperSizes[resolvedSize.value])\nconst ellipsisClass = computed(() => ellipsisSizes[resolvedSize.value])\nconst labelClass = computed(() => labelSizes[resolvedSize.value])\nconst selectWrapClass = computed(() => pageSizeSelectWidths[resolvedSize.value])\nconst navButtonSize = computed(() => navButtonSizes[resolvedSize.value])\n\nconst emit = defineEmits<GrPaginationEmits>()\n\n// Делитель клампится: `pageSize: 0` дал бы `Infinity` страниц и бесконечный\n// цикл в `range()`.\nconst resolvedPageSize = computed(() => Math.max(1, Math.trunc(props.pageSize)))\nconst pageCount = computed(() => Math.max(1, Math.ceil(props.total / resolvedPageSize.value)))\n\n// Рендер идёт от зажатого номера: вотчер ниже просит родителя подтянуть `page`,\n// но на первом рендере он молчит, и без клампа пагинация осталась бы вовсе без\n// активной страницы.\nconst currentPage = computed(() => Math.min(Math.max(Math.trunc(props.page), 1), pageCount.value))\n\n// Контролируемый компонент: если `total`/`pageSize` уменьшились и текущая `page`\n// вышла за диапазон — просим родителя подтянуть её к последней странице.\nwatch(pageCount, (count) => {\n if (props.page > count)\n emit('update:page', count)\n})\n\nconst pageSizeModel = computed({\n get: () => String(props.pageSize),\n set: (value: string) => emit('update:pageSize', Number(value)),\n})\n\nconst pageSizeOptions = computed(() =>\n props.pageSizes.map(pageSize => ({\n value: String(pageSize),\n label: String(pageSize),\n })),\n)\n\nconst rangeFrom = computed(() => (props.total === 0 ? 0 : (currentPage.value - 1) * resolvedPageSize.value + 1))\nconst rangeTo = computed(() => Math.min(currentPage.value * resolvedPageSize.value, props.total))\n\ntype PaginationItem = number | 'ellipsis-start' | 'ellipsis-end'\n\nfunction range(start: number, end: number): number[] {\n const list: number[] = []\n for (let page = start; page <= end; page += 1)\n list.push(page)\n return list\n}\n\n// Алгоритм usePagination как в MUI: крайние `boundaryCount` страниц + `siblingCount`\n// соседей вокруг текущей, разрывы схлопываются в многоточие. Одиночный «пропущенный»\n// номер показываем как номер, а не как «…» (визуально ровнее).\nconst items = computed<PaginationItem[]>(() => {\n const count = pageCount.value\n const current = currentPage.value\n const boundaryCount = Math.max(0, props.boundaryCount)\n const siblingCount = Math.max(0, props.siblingCount)\n\n const startPages = range(1, Math.min(boundaryCount, count))\n const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count)\n\n const siblingsStart = Math.max(\n Math.min(current - siblingCount, count - boundaryCount - siblingCount * 2 - 1),\n boundaryCount + 2,\n )\n const siblingsEnd = Math.min(\n Math.max(current + siblingCount, boundaryCount + siblingCount * 2 + 2),\n endPages.length > 0 ? endPages[0] - 2 : count - 1,\n )\n\n return [\n ...startPages,\n ...(siblingsStart > boundaryCount + 2\n ? ['ellipsis-start' as const]\n : boundaryCount + 1 < count - boundaryCount\n ? [boundaryCount + 1]\n : []),\n ...range(siblingsStart, siblingsEnd),\n ...(siblingsEnd < count - boundaryCount - 1\n ? ['ellipsis-end' as const]\n : count - boundaryCount > boundaryCount\n ? [count - boundaryCount]\n : []),\n ...endPages,\n ]\n})\n\nfunction goTo(page: number): void {\n if (props.disabled)\n return\n\n emit('update:page', page)\n}\n\nfunction prev(): void {\n goTo(Math.max(1, currentPage.value - 1))\n}\n\nfunction next(): void {\n goTo(Math.min(pageCount.value, currentPage.value + 1))\n}\n\nfunction first(): void {\n goTo(1)\n}\n\nfunction last(): void {\n goTo(pageCount.value)\n}\n\n// «Перейти к странице»: клампим введённый номер к диапазону [1, pageCount]\n// и сбрасываем поле после перехода.\nconst jumperValue = ref('')\n\nfunction submitJumper(): void {\n const parsed = Number.parseInt(jumperValue.value, 10)\n jumperValue.value = ''\n if (Number.isNaN(parsed))\n return\n\n goTo(Math.min(pageCount.value, Math.max(1, parsed)))\n}\n\nconst resolvedJumperLabel = computed(() => props.jumperLabel ?? t('gr.pagination.jumpTo', 'Go to'))\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.pagination.label', 'Pagination'))\nconst statusText = computed(() =>\n t('gr.pagination.status', 'Page {page} of {count}', { page: currentPage.value, count: pageCount.value }),\n)\nconst totalText = computed(() =>\n t('gr.pagination.total', '{from}–{to} of {total}', { from: rangeFrom.value, to: rangeTo.value, total: props.total }),\n)\n</script>\n\n<template>\n <div\n class=\"flex flex-wrap items-center justify-end\"\n :class=\"rowClass\"\n data-gr-pagination\n role=\"navigation\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <div\n v-if=\"showTotal\"\n data-gr-pagination-total\n class=\"text-[var(--gr-muted-fg)] tabular-nums\"\n :class=\"labelClass\"\n >\n <slot name=\"total\" :from=\"rangeFrom\" :to=\"rangeTo\" :total=\"total\">\n {{ totalText }}\n </slot>\n </div>\n\n <div v-if=\"showPageSize\" :class=\"selectWrapClass\">\n <GrSelect\n v-model=\"pageSizeModel\"\n :options=\"pageSizeOptions\"\n :size=\"resolvedSize\"\n :disabled=\"disabled\"\n :aria-label=\"t('gr.pagination.pageSize', 'Page size')\"\n />\n </div>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" :aria-label=\"t('gr.pagination.first', 'First page')\" data-gr-pagination-first @click=\"first\">\n «\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" data-gr-pagination-prev @click=\"prev\">\n {{ t('gr.pagination.prev', 'Prev') }}\n </GrButton>\n\n <!-- Компактный вариант: индикатор «текущая / всего» вместо нумерованных страниц. -->\n <div\n v-if=\"compact\"\n data-gr-pagination-compact\n class=\"px-2 text-[var(--gr-fg)] tabular-nums\"\n :class=\"labelClass\"\n role=\"status\"\n >\n {{ currentPage }} / {{ pageCount }}\n </div>\n\n <template v-else>\n <ul class=\"flex items-center [list-style:none]\" :class=\"pageListClass\" data-gr-pagination-pages role=\"list\">\n <li v-for=\"(item, index) in items\" :key=\"index\" :aria-hidden=\"typeof item === 'string' ? 'true' : undefined\">\n <span\n v-if=\"item === 'ellipsis-start' || item === 'ellipsis-end'\"\n data-gr-pagination-ellipsis\n class=\"grid place-items-center text-[var(--gr-muted-fg)]\"\n :class=\"ellipsisClass\"\n >…</span>\n <button\n v-else\n type=\"button\"\n data-gr-pagination-page\n :disabled=\"disabled\"\n :aria-current=\"item === currentPage ? 'page' : undefined\"\n :aria-label=\"t('gr.pagination.page', 'Page {n}', { n: item })\"\n class=\"rounded-[var(--gr-radius-control)] font-600 transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"[\n pageClass,\n item === currentPage\n ? 'bg-[var(--gr-primary)] text-[var(--gr-primary-fg)]'\n // Подложка тональная, а не `--gr-muted`: серый на белом фоне даёт\n // 1.10:1 и на светлой теме hover был практически не виден, хотя у\n // соседних «назад/вперёд» (ghost-кнопки) он тонирован. Ряд обязан\n // читаться одним контролом.\n : 'text-[var(--gr-muted-fg)] hover:bg-[var(--gr-accent)] hover:text-[var(--gr-accent-fg)]',\n ]\"\n @click=\"goTo(item)\"\n >\n {{ item }}\n </button>\n </li>\n </ul>\n\n <!-- В компактном режиме смену страницы объявляет видимый индикатор. -->\n <div data-gr-pagination-status role=\"status\" class=\"sr-only\">\n {{ statusText }}\n </div>\n </template>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" data-gr-pagination-next @click=\"next\">\n {{ t('gr.pagination.next', 'Next') }}\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" :aria-label=\"t('gr.pagination.last', 'Last page')\" data-gr-pagination-last @click=\"last\">\n »\n </GrButton>\n\n <!-- «Перейти к странице»: Enter или blur применяют введённый номер. -->\n <div v-if=\"showJumper\" class=\"flex items-center gap-2 text-[var(--gr-muted-fg)]\" :class=\"labelClass\">\n <span>{{ resolvedJumperLabel }}</span>\n <input\n v-model=\"jumperValue\"\n type=\"number\"\n min=\"1\"\n :max=\"pageCount\"\n inputmode=\"numeric\"\n data-gr-pagination-jumper\n :disabled=\"disabled\"\n :aria-label=\"resolvedJumperLabel\"\n class=\"rounded-[var(--gr-radius-control)] border border-[var(--gr-brd)] bg-[var(--gr-bg)] px-2 text-center text-[var(--gr-fg)] tabular-nums transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"jumperClass\"\n @keydown.enter=\"submitJumper\"\n @blur=\"submitJumper\"\n >\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrSelect from '../GrSelect/GrSelect.vue'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport {\n type GrPaginationSize,\n ellipsisSizes,\n jumperSizes,\n labelSizes,\n navButtonSizes,\n pageListGaps,\n pageSizes,\n pageSizeSelectWidths,\n rowGaps,\n} from './grPaginationStyles'\n\n/**\n * Пропы пагинации.\n *\n * `total` интерпретируется как общее количество элементов; число страниц\n * вычисляется из `total` и `pageSize`. Номера усекаются многоточием\n * (алгоритм boundary/sibling, как у MUI): всегда видны первая/последняя страница\n * и `siblingCount` соседей вокруг текущей.\n */\nexport interface GrPaginationProps {\n page: number\n pageSize: number\n total: number\n pageSizes?: number[]\n /** Сколько соседних страниц показывать вокруг текущей. По умолчанию `1`. */\n siblingCount?: number\n /** Сколько крайних страниц всегда показывать с каждого края. По умолчанию `1`. */\n boundaryCount?: number\n /**\n * Компактный вариант: вместо нумерованных страниц показывается индикатор\n * «текущая / всего» — удобно для узких мест (мобайл, тулбары таблиц).\n */\n compact?: boolean\n /** Показывать поле «перейти к странице» с быстрым переходом по вводу номера. */\n showJumper?: boolean\n /** Показывать селект размера страницы. */\n showPageSize?: boolean\n /** Показывать диапазон показанных элементов — «1–20 из 137». Слот `#total` сильнее. */\n showTotal?: boolean\n /** i18n-подпись перед полем перехода. По умолчанию — `gr.pagination.jumpTo`. */\n jumperLabel?: string\n /**\n * Имя навигационного лендмарка. По умолчанию — `gr.pagination.label`; задавать\n * стоит там, где пагинаций на странице несколько и их надо различать.\n */\n ariaLabel?: string\n /** Гасит всю пагинацию: номера, кнопки, селект размера и поле перехода. */\n disabled?: boolean\n size?: GrPaginationSize\n}\n\nexport interface GrPaginationEmits {\n (e: 'update:page', value: number): void\n (e: 'update:pageSize', value: number): void\n}\n\nconst { t } = useGranularityTranslations()\n\nconst props = withDefaults(defineProps<GrPaginationProps>(), {\n pageSizes: () => [10, 20, 50],\n siblingCount: 1,\n boundaryCount: 1,\n compact: false,\n showJumper: false,\n showPageSize: false,\n showTotal: false,\n jumperLabel: undefined,\n ariaLabel: undefined,\n disabled: false,\n size: undefined,\n})\n\ndefineSlots<{\n /** Диапазон показанных элементов целиком — вместо строки из локали. */\n total?: (props: { from: number, to: number, total: number }) => unknown\n}>()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPagination' })\n\nconst rowClass = computed(() => rowGaps[resolvedSize.value])\nconst pageListClass = computed(() => pageListGaps[resolvedSize.value])\nconst pageClass = computed(() => pageSizes[resolvedSize.value])\nconst jumperClass = computed(() => jumperSizes[resolvedSize.value])\nconst ellipsisClass = computed(() => ellipsisSizes[resolvedSize.value])\nconst labelClass = computed(() => labelSizes[resolvedSize.value])\nconst selectWrapClass = computed(() => pageSizeSelectWidths[resolvedSize.value])\nconst navButtonSize = computed(() => navButtonSizes[resolvedSize.value])\n\nconst emit = defineEmits<GrPaginationEmits>()\n\n// Делитель клампится: `pageSize: 0` дал бы `Infinity` страниц и бесконечный\n// цикл в `range()`.\nconst resolvedPageSize = computed(() => Math.max(1, Math.trunc(props.pageSize)))\nconst pageCount = computed(() => Math.max(1, Math.ceil(props.total / resolvedPageSize.value)))\n\n// Рендер идёт от зажатого номера: вотчер ниже просит родителя подтянуть `page`,\n// но на первом рендере он молчит, и без клампа пагинация осталась бы вовсе без\n// активной страницы.\nconst currentPage = computed(() => Math.min(Math.max(Math.trunc(props.page), 1), pageCount.value))\n\n// Контролируемый компонент: если `total`/`pageSize` уменьшились и текущая `page`\n// вышла за диапазон — просим родителя подтянуть её к последней странице.\nwatch(pageCount, (count) => {\n if (props.page > count)\n emit('update:page', count)\n})\n\nconst pageSizeModel = computed({\n get: () => String(props.pageSize),\n set: (value: string) => emit('update:pageSize', Number(value)),\n})\n\nconst pageSizeOptions = computed(() =>\n props.pageSizes.map(pageSize => ({\n value: String(pageSize),\n label: String(pageSize),\n })),\n)\n\nconst rangeFrom = computed(() => (props.total === 0 ? 0 : (currentPage.value - 1) * resolvedPageSize.value + 1))\nconst rangeTo = computed(() => Math.min(currentPage.value * resolvedPageSize.value, props.total))\n\ntype PaginationItem = number | 'ellipsis-start' | 'ellipsis-end'\n\nfunction range(start: number, end: number): number[] {\n const list: number[] = []\n for (let page = start; page <= end; page += 1)\n list.push(page)\n return list\n}\n\n// Алгоритм usePagination как в MUI: крайние `boundaryCount` страниц + `siblingCount`\n// соседей вокруг текущей, разрывы схлопываются в многоточие. Одиночный «пропущенный»\n// номер показываем как номер, а не как «…» (визуально ровнее).\nconst items = computed<PaginationItem[]>(() => {\n const count = pageCount.value\n const current = currentPage.value\n const boundaryCount = Math.max(0, props.boundaryCount)\n const siblingCount = Math.max(0, props.siblingCount)\n\n const startPages = range(1, Math.min(boundaryCount, count))\n const endPages = range(Math.max(count - boundaryCount + 1, boundaryCount + 1), count)\n\n const siblingsStart = Math.max(\n Math.min(current - siblingCount, count - boundaryCount - siblingCount * 2 - 1),\n boundaryCount + 2,\n )\n const siblingsEnd = Math.min(\n Math.max(current + siblingCount, boundaryCount + siblingCount * 2 + 2),\n endPages.length > 0 ? endPages[0] - 2 : count - 1,\n )\n\n return [\n ...startPages,\n ...(siblingsStart > boundaryCount + 2\n ? ['ellipsis-start' as const]\n : boundaryCount + 1 < count - boundaryCount\n ? [boundaryCount + 1]\n : []),\n ...range(siblingsStart, siblingsEnd),\n ...(siblingsEnd < count - boundaryCount - 1\n ? ['ellipsis-end' as const]\n : count - boundaryCount > boundaryCount\n ? [count - boundaryCount]\n : []),\n ...endPages,\n ]\n})\n\nfunction goTo(page: number): void {\n if (props.disabled)\n return\n\n emit('update:page', page)\n}\n\nfunction prev(): void {\n goTo(Math.max(1, currentPage.value - 1))\n}\n\nfunction next(): void {\n goTo(Math.min(pageCount.value, currentPage.value + 1))\n}\n\nfunction first(): void {\n goTo(1)\n}\n\nfunction last(): void {\n goTo(pageCount.value)\n}\n\n// «Перейти к странице»: клампим введённый номер к диапазону [1, pageCount]\n// и сбрасываем поле после перехода.\nconst jumperValue = ref('')\n\nfunction submitJumper(): void {\n const parsed = Number.parseInt(jumperValue.value, 10)\n jumperValue.value = ''\n if (Number.isNaN(parsed))\n return\n\n goTo(Math.min(pageCount.value, Math.max(1, parsed)))\n}\n\nconst resolvedJumperLabel = computed(() => props.jumperLabel ?? t('gr.pagination.jumpTo', 'Go to'))\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.pagination.label', 'Pagination'))\nconst statusText = computed(() =>\n t('gr.pagination.status', 'Page {page} of {count}', { page: currentPage.value, count: pageCount.value }),\n)\nconst totalText = computed(() =>\n t('gr.pagination.total', '{from}–{to} of {total}', { from: rangeFrom.value, to: rangeTo.value, total: props.total }),\n)\n</script>\n\n<template>\n <div\n class=\"flex flex-wrap items-center justify-end\"\n :class=\"rowClass\"\n data-gr-pagination\n role=\"navigation\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <div\n v-if=\"showTotal\"\n data-gr-pagination-total\n class=\"text-[var(--gr-muted-fg)] tabular-nums\"\n :class=\"labelClass\"\n >\n <slot name=\"total\" :from=\"rangeFrom\" :to=\"rangeTo\" :total=\"total\">\n {{ totalText }}\n </slot>\n </div>\n\n <div v-if=\"showPageSize\" :class=\"selectWrapClass\">\n <GrSelect\n v-model=\"pageSizeModel\"\n :options=\"pageSizeOptions\"\n :size=\"resolvedSize\"\n :disabled=\"disabled\"\n :aria-label=\"t('gr.pagination.pageSize', 'Page size')\"\n />\n </div>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" :aria-label=\"t('gr.pagination.first', 'First page')\" data-gr-pagination-first @click=\"first\">\n «\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage <= 1\" data-gr-pagination-prev @click=\"prev\">\n {{ t('gr.pagination.prev', 'Prev') }}\n </GrButton>\n\n <!-- Компактный вариант: индикатор «текущая / всего» вместо нумерованных страниц. -->\n <div\n v-if=\"compact\"\n data-gr-pagination-compact\n class=\"px-2 text-[var(--gr-fg)] tabular-nums\"\n :class=\"labelClass\"\n role=\"status\"\n >\n {{ currentPage }} / {{ pageCount }}\n </div>\n\n <template v-else>\n <ul class=\"flex items-center [list-style:none]\" :class=\"pageListClass\" data-gr-pagination-pages role=\"list\">\n <li v-for=\"(item, index) in items\" :key=\"index\" :aria-hidden=\"typeof item === 'string' ? 'true' : undefined\">\n <span\n v-if=\"item === 'ellipsis-start' || item === 'ellipsis-end'\"\n data-gr-pagination-ellipsis\n class=\"grid place-items-center text-[var(--gr-muted-fg)]\"\n :class=\"ellipsisClass\"\n >…</span>\n <button\n v-else\n type=\"button\"\n data-gr-pagination-page\n :disabled=\"disabled\"\n :aria-current=\"item === currentPage ? 'page' : undefined\"\n :aria-label=\"t('gr.pagination.page', 'Page {n}', { n: item })\"\n class=\"rounded-[var(--gr-radius-control)] font-600 transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"[\n pageClass,\n item === currentPage\n ? 'bg-[var(--gr-primary)] text-[var(--gr-primary-fg)]'\n // Подложка тональная, а не `--gr-muted`: серый на белом фоне даёт\n // 1.10:1 и на светлой теме hover был практически не виден, хотя у\n // соседних «назад/вперёд» (ghost-кнопки) он тонирован. Ряд обязан\n // читаться одним контролом.\n : 'text-[var(--gr-muted-fg)] hover:bg-[var(--gr-accent)] hover:text-[var(--gr-accent-fg)]',\n ]\"\n @click=\"goTo(item)\"\n >\n {{ item }}\n </button>\n </li>\n </ul>\n\n <!-- В компактном режиме смену страницы объявляет видимый индикатор. -->\n <div data-gr-pagination-status role=\"status\" class=\"sr-only\">\n {{ statusText }}\n </div>\n </template>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" data-gr-pagination-next @click=\"next\">\n {{ t('gr.pagination.next', 'Next') }}\n </GrButton>\n\n <GrButton variant=\"ghost\" :size=\"navButtonSize\" :disabled=\"disabled || currentPage >= pageCount\" :aria-label=\"t('gr.pagination.last', 'Last page')\" data-gr-pagination-last @click=\"last\">\n »\n </GrButton>\n\n <!-- «Перейти к странице»: Enter или blur применяют введённый номер. -->\n <div v-if=\"showJumper\" class=\"flex items-center gap-2 text-[var(--gr-muted-fg)]\" :class=\"labelClass\">\n <span>{{ resolvedJumperLabel }}</span>\n <input\n v-model=\"jumperValue\"\n type=\"number\"\n min=\"1\"\n :max=\"pageCount\"\n inputmode=\"numeric\"\n data-gr-pagination-jumper\n :disabled=\"disabled\"\n :aria-label=\"resolvedJumperLabel\"\n class=\"rounded-[var(--gr-radius-control)] border border-[var(--gr-brd)] bg-[var(--gr-bg)] px-2 text-center text-[var(--gr-fg)] tabular-nums transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)] disabled:cursor-not-allowed\"\n :class=\"jumperClass\"\n @keydown.enter=\"submitJumper\"\n @blur=\"submitJumper\"\n >\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { n as grPaginationSafelist, t as grPaginationConfig } from "../../chunks/config-CjKpUcmy.js";
2
- import { t as GrPagination_default } from "./chunks/GrPagination-Cw3R21dp.js";
2
+ import { t as GrPagination_default } from "./chunks/GrPagination-B_kAhoAV.js";
3
3
  export { GrPagination_default as GrPagination, GrPagination_default as default, grPaginationConfig, grPaginationSafelist };
@@ -1 +1 @@
1
- {"version":3,"file":"GrPopover-CofG-Tfe.js","names":[],"sources":["../../../../src/components/GrPopover/GrPopover.vue","../../../../src/components/GrPopover/GrPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrPopover — якорный немодальный оверлей с произвольным содержимым.\n *\n * Роль «универсального поповера» до сих пор насильно исполнял `GrDropdown`, но\n * он про меню: жёстко объявляет `role=\"menu\"`, `aria-haspopup=\"menu\"` и водит\n * фокус по пунктам. Для формы, подтверждения или палитры это неверная семантика.\n *\n * Здесь наоборот: позиционирование, слой и закрытие берёт на себя примитив, а\n * клавиатурный паттерн внутри панели остаётся за потребителем — поэтому `role`\n * задаётся пропом. На этом собираются `GrMenu` / `GrContextMenu` /\n * `GrColorPicker` / Popconfirm.\n *\n * A11y:\n * - триггер получает `aria-haspopup`/`aria-expanded`/`aria-controls` через\n * `triggerProps` (биндится на реальный фокусируемый элемент в слоте);\n * - панель — `role=\"dialog\"` по умолчанию и обязательное доступное имя\n * (`ariaLabel` либо `aria-labelledby` через `labelledBy`);\n * - Esc закрывает верхний слой стека, клик вне — закрывает по точке попадания;\n * - **по умолчанию фокус-ловушки нет намеренно**: Tab обязан уводить фокус\n * наружу, иначе немодальный слой запирает пользователя на странице, которая\n * не заблокирована. Проп `modal` включает второй режим — см. ниже.\n */\nimport { computed, nextTick, ref, useId, useSlots, watch } from 'vue'\n\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useModalOverlay } from '../../composables/internal/useModalOverlay'\nimport { createFloatingAnchor, type GrFloatingAnchorRect, useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { vClickOutside } from '../../directives'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\nimport {\n type GrPopoverPadding,\n type GrPopoverRole,\n type GrPopoverSize,\n grPopoverPanelClass,\n} from './grPopoverStyles'\n\nexport interface GrPopoverProps {\n /**\n * Открыт ли поповер. Без этого пропа компонент ведёт состояние сам\n * (uncontrolled), с ним — слушайте `update:open`.\n */\n open?: boolean\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offsetPx?: number\n size?: GrPopoverSize\n /** Роль панели. Меняется теми, кто строит поверх примитива своё меню/список. */\n role?: GrPopoverRole\n /**\n * Модальный режим: фон уходит в `inert`, Tab ходит по кругу внутри панели,\n * скролл страницы блокируется, а слой встаёт в стек модальным — как окно.\n * Нужен поповеру с формой или подтверждением внутри: без изоляции фона\n * пользователь уводит фокус на страницу, к которой поповер и относится.\n *\n * В этом режиме фокус переносится в панель независимо от `autoFocus`: фон\n * недоступен, и слой без фокуса внутри стал бы клавиатурной ловушкой.\n */\n modal?: boolean\n /** Доступное имя панели. Обязательно для `role=\"dialog\"` без видимого заголовка. */\n ariaLabel?: string\n /** `id` видимого заголовка внутри панели — альтернатива `ariaLabel`. */\n labelledBy?: string\n /**\n * `manual` — открывать только программно (через `v-model:open`). Нужно для\n * контекстного меню и подтверждений, где момент открытия решает потребитель.\n */\n trigger?: 'click' | 'manual'\n closeOnEsc?: boolean\n closeOnClickOutside?: boolean\n /** Закрывать по клику внутри панели — удобно для меню, вредно для формы. */\n closeOnContentClick?: boolean\n /**\n * Переносить фокус на панель при открытии. Именно на панель, а не на первый\n * контрол внутри: сфокусировать поле ввода за пользователя — решение\n * содержимого, а не оболочки.\n */\n autoFocus?: boolean\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n contentClass?: string\n disabled?: boolean\n /**\n * Якорь-прямоугольник в координатах вьюпорта вместо обёртки слота `#trigger`:\n * панель встаёт у точки курсора или у строки списка. Нужен контекстному меню,\n * у которого триггера-элемента нет вовсе.\n *\n * `triggerProps` в этом режиме некому потребить, и своих ARIA-атрибутов\n * поповер никуда не вешает: `aria-haspopup` невалиден вне интерактивного\n * элемента, а `aria-expanded` без хозяина — шум. Связь с содержимым страницы\n * объявляет тот, кто открывает.\n */\n anchor?: GrFloatingAnchorRect | null\n /** Поле панели. `none` — содержимое рисует своё (меню, список опций). */\n padding?: GrPopoverPadding\n}\n\nexport interface GrPopoverEmits {\n (e: 'update:open', value: boolean): void\n}\n\nconst props = withDefaults(defineProps<GrPopoverProps>(), {\n open: undefined,\n placement: 'bottom-start',\n offsetPx: 8,\n size: undefined,\n role: 'dialog',\n modal: false,\n ariaLabel: undefined,\n labelledBy: undefined,\n trigger: 'click',\n closeOnEsc: true,\n closeOnClickOutside: true,\n closeOnContentClick: false,\n autoFocus: true,\n teleportTo: undefined,\n contentClass: undefined,\n disabled: false,\n anchor: undefined,\n padding: 'default',\n})\n\nconst emit = defineEmits<GrPopoverEmits>()\n\nconst slots = useSlots()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPopover' })\n\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst panelId = useId()\n\nconst clickOutsideExclude = [() => panelEl.value]\n\nfunction open(): void {\n if (props.disabled) return\n setOpen(true)\n}\n\nfunction close(): void {\n setOpen(false)\n}\n\nfunction toggle(): void {\n isOpen.value ? close() : open()\n}\n\n/**\n * Якорь создаётся один раз и читает координаты геттером: `useFloating`\n * пересоздаёт подписку при смене самой ссылки, а точка меняется на каждый\n * вызов — новый объект рвал бы `autoUpdate` без нужды.\n */\nconst anchorEl = createFloatingAnchor(() => props.anchor)\n\n/** Обёртка триггера существует только вместе со слотом — см. проп `anchor`. */\nconst hasTrigger = computed(() => Boolean(slots.trigger))\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n () => (props.anchor ? anchorEl : rootEl.value),\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n offsetPx: props.offsetPx,\n // Своего слоя у поповера нет намеренно: он и дропдаун — один класс якорных\n // немодальных оверлеев и обязаны лежать на одной высоте, иначе начнут\n // перекрывать друг друга в зависимости от порядка открытия.\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\nwatch(() => props.placement, () => {\n if (isOpen.value) updateFloatingPosition()\n})\n\n// Объект якоря стабилен, поэтому смену координат `useFloating` сам не заметит:\n// повторный вызов у другой точки — это пересчёт позиции, а не переоткрытие.\nwatch(() => props.anchor, () => {\n if (isOpen.value) updateFloatingPosition()\n}, { deep: true })\n\n/**\n * Слой стека оверлеев: очередь Esc общая с модалками, поэтому поповер, открытый\n * внутри модалки, по Esc закрывает себя, а не её. Возврат фокуса на триггер\n * тоже отсюда — по правилу «только если на момент закрытия фокус ещё внутри».\n *\n * Модальность включается пропом и приходит той же сборкой, что у окна и drawer'а\n * (`useModalOverlay`): ловушка фокуса, `inert` фона, блокировка скролла. При\n * `modal: false` не включается ничего из этого — дефолтный поповер немодален.\n *\n * Корень слоя и панель здесь один элемент: якорный оверлей уезжает в портал сам,\n * без обёртки.\n */\nconst { inertAttr, portalTarget, teleportEnabled, themeAttrs } = useModalOverlay(isOpen, close, {\n modal: () => props.modal,\n closeOnEscape: () => props.closeOnEsc,\n panel: panelEl,\n root: panelEl,\n teleportTo: () => props.teleportTo,\n initialFocus: () => panelEl.value,\n})\n\n// Фокус переносим после отрисовки панели: до `nextTick` её ещё нет в DOM.\n// В модальном режиме перенос обязателен: фон в `inert`, и фокус, оставленный\n// снаружи, попал бы в недоступное поддерево.\nwatch(isOpen, async (next) => {\n if (!next || !(props.autoFocus || props.modal)) return\n\n await nextTick()\n panelEl.value?.focus()\n})\n\n/** Роли, которые `aria-haspopup` действительно понимает. */\nconst HASPOPUP_ROLES = ['dialog', 'menu', 'listbox', 'grid'] as const\n\n/**\n * Пропсы для реального фокусируемого триггера: `<button v-bind=\"triggerProps\">`.\n * Клик вешается на обёртку, а ARIA — сюда, потому что `aria-expanded` обязан\n * жить на самом интерактивном элементе, а не на `div` вокруг него.\n */\nconst triggerProps = computed(() => ({\n // `aria-haspopup` принимает не любую роль: `group` в его списке нет, и\n // объявленный им триггер отдавал бы невалидный атрибут, который AT просто\n // отбрасывает. Роли вне списка сообщают о панели только через `aria-expanded`.\n 'aria-haspopup': HASPOPUP_ROLES.includes(props.role as (typeof HASPOPUP_ROLES)[number])\n ? (props.role as (typeof HASPOPUP_ROLES)[number])\n : undefined,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'disabled': props.disabled || undefined,\n}))\n\nfunction onTriggerClick(): void {\n if (props.trigger === 'click') toggle()\n}\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) close()\n}\n\nconst panelClasses = computed(() =>\n grPopoverPanelClass(resolvedSize.value, resolvedPlacement.value, props.contentClass, props.padding),\n)\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое панели. */\n content?: (props: { close: () => void }) => any\n}>()\n\n</script>\n\n<template>\n <div data-gr-popover>\n <div\n v-if=\"hasTrigger\"\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside, exclude: clickOutsideExclude }\"\n data-gr-popover-trigger\n class=\"inline-block max-w-full\"\n @click=\"onTriggerClick\"\n >\n <slot\n name=\"trigger\"\n :open=\"isOpen\"\n :toggle=\"toggle\"\n :close=\"close\"\n :trigger-props=\"triggerProps\"\n />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside && !hasTrigger }\"\n v-bind=\"themeAttrs\"\n data-gr-popover-panel\n data-gr-overlay-root\n :role=\"role === 'none' ? undefined : role\"\n :aria-modal=\"modal ? 'true' : undefined\"\n :inert=\"inertAttr\"\n :aria-label=\"labelledBy ? undefined : ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"floatingStyle\"\n @click=\"onContentClick\"\n >\n <slot name=\"content\" :close=\"close\" />\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrPopover — якорный немодальный оверлей с произвольным содержимым.\n *\n * Роль «универсального поповера» до сих пор насильно исполнял `GrDropdown`, но\n * он про меню: жёстко объявляет `role=\"menu\"`, `aria-haspopup=\"menu\"` и водит\n * фокус по пунктам. Для формы, подтверждения или палитры это неверная семантика.\n *\n * Здесь наоборот: позиционирование, слой и закрытие берёт на себя примитив, а\n * клавиатурный паттерн внутри панели остаётся за потребителем — поэтому `role`\n * задаётся пропом. На этом собираются `GrMenu` / `GrContextMenu` /\n * `GrColorPicker` / Popconfirm.\n *\n * A11y:\n * - триггер получает `aria-haspopup`/`aria-expanded`/`aria-controls` через\n * `triggerProps` (биндится на реальный фокусируемый элемент в слоте);\n * - панель — `role=\"dialog\"` по умолчанию и обязательное доступное имя\n * (`ariaLabel` либо `aria-labelledby` через `labelledBy`);\n * - Esc закрывает верхний слой стека, клик вне — закрывает по точке попадания;\n * - **по умолчанию фокус-ловушки нет намеренно**: Tab обязан уводить фокус\n * наружу, иначе немодальный слой запирает пользователя на странице, которая\n * не заблокирована. Проп `modal` включает второй режим — см. ниже.\n */\nimport { computed, nextTick, ref, useId, useSlots, watch } from 'vue'\n\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useModalOverlay } from '../../composables/internal/useModalOverlay'\nimport { createFloatingAnchor, type GrFloatingAnchorRect, useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { vClickOutside } from '../../directives'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\nimport {\n type GrPopoverPadding,\n type GrPopoverRole,\n type GrPopoverSize,\n grPopoverPanelClass,\n} from './grPopoverStyles'\n\nexport interface GrPopoverProps {\n /**\n * Открыт ли поповер. Без этого пропа компонент ведёт состояние сам\n * (uncontrolled), с ним — слушайте `update:open`.\n */\n open?: boolean\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offsetPx?: number\n size?: GrPopoverSize\n /** Роль панели. Меняется теми, кто строит поверх примитива своё меню/список. */\n role?: GrPopoverRole\n /**\n * Модальный режим: фон уходит в `inert`, Tab ходит по кругу внутри панели,\n * скролл страницы блокируется, а слой встаёт в стек модальным — как окно.\n * Нужен поповеру с формой или подтверждением внутри: без изоляции фона\n * пользователь уводит фокус на страницу, к которой поповер и относится.\n *\n * В этом режиме фокус переносится в панель независимо от `autoFocus`: фон\n * недоступен, и слой без фокуса внутри стал бы клавиатурной ловушкой.\n */\n modal?: boolean\n /** Доступное имя панели. Обязательно для `role=\"dialog\"` без видимого заголовка. */\n ariaLabel?: string\n /** `id` видимого заголовка внутри панели — альтернатива `ariaLabel`. */\n labelledBy?: string\n /**\n * `manual` — открывать только программно (через `v-model:open`). Нужно для\n * контекстного меню и подтверждений, где момент открытия решает потребитель.\n */\n trigger?: 'click' | 'manual'\n closeOnEsc?: boolean\n closeOnClickOutside?: boolean\n /** Закрывать по клику внутри панели — удобно для меню, вредно для формы. */\n closeOnContentClick?: boolean\n /**\n * Переносить фокус на панель при открытии. Именно на панель, а не на первый\n * контрол внутри: сфокусировать поле ввода за пользователя — решение\n * содержимого, а не оболочки.\n */\n autoFocus?: boolean\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n contentClass?: string\n disabled?: boolean\n /**\n * Якорь-прямоугольник в координатах вьюпорта вместо обёртки слота `#trigger`:\n * панель встаёт у точки курсора или у строки списка. Нужен контекстному меню,\n * у которого триггера-элемента нет вовсе.\n *\n * `triggerProps` в этом режиме некому потребить, и своих ARIA-атрибутов\n * поповер никуда не вешает: `aria-haspopup` невалиден вне интерактивного\n * элемента, а `aria-expanded` без хозяина — шум. Связь с содержимым страницы\n * объявляет тот, кто открывает.\n */\n anchor?: GrFloatingAnchorRect | null\n /** Поле панели. `none` — содержимое рисует своё (меню, список опций). */\n padding?: GrPopoverPadding\n}\n\nexport interface GrPopoverEmits {\n (e: 'update:open', value: boolean): void\n}\n\nconst props = withDefaults(defineProps<GrPopoverProps>(), {\n open: undefined,\n placement: 'bottom-start',\n offsetPx: 8,\n size: undefined,\n role: 'dialog',\n modal: false,\n ariaLabel: undefined,\n labelledBy: undefined,\n trigger: 'click',\n closeOnEsc: true,\n closeOnClickOutside: true,\n closeOnContentClick: false,\n autoFocus: true,\n teleportTo: undefined,\n contentClass: undefined,\n disabled: false,\n anchor: undefined,\n padding: 'default',\n})\n\nconst emit = defineEmits<GrPopoverEmits>()\n\nconst slots = useSlots()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPopover' })\n\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst panelId = useId()\n\nconst clickOutsideExclude = [() => panelEl.value]\n\nfunction open(): void {\n if (props.disabled) return\n setOpen(true)\n}\n\nfunction close(): void {\n setOpen(false)\n}\n\nfunction toggle(): void {\n isOpen.value ? close() : open()\n}\n\n/**\n * Якорь создаётся один раз и читает координаты геттером: `useFloating`\n * пересоздаёт подписку при смене самой ссылки, а точка меняется на каждый\n * вызов — новый объект рвал бы `autoUpdate` без нужды.\n */\nconst anchorEl = createFloatingAnchor(() => props.anchor)\n\n/** Обёртка триггера существует только вместе со слотом — см. проп `anchor`. */\nconst hasTrigger = computed(() => Boolean(slots.trigger))\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n () => (props.anchor ? anchorEl : rootEl.value),\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n offsetPx: props.offsetPx,\n // Своего слоя у поповера нет намеренно: он и дропдаун — один класс якорных\n // немодальных оверлеев и обязаны лежать на одной высоте, иначе начнут\n // перекрывать друг друга в зависимости от порядка открытия.\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\nwatch(() => props.placement, () => {\n if (isOpen.value) updateFloatingPosition()\n})\n\n// Объект якоря стабилен, поэтому смену координат `useFloating` сам не заметит:\n// повторный вызов у другой точки — это пересчёт позиции, а не переоткрытие.\nwatch(() => props.anchor, () => {\n if (isOpen.value) updateFloatingPosition()\n}, { deep: true })\n\n/**\n * Слой стека оверлеев: очередь Esc общая с модалками, поэтому поповер, открытый\n * внутри модалки, по Esc закрывает себя, а не её. Возврат фокуса на триггер\n * тоже отсюда — по правилу «только если на момент закрытия фокус ещё внутри».\n *\n * Модальность включается пропом и приходит той же сборкой, что у окна и drawer'а\n * (`useModalOverlay`): ловушка фокуса, `inert` фона, блокировка скролла. При\n * `modal: false` не включается ничего из этого — дефолтный поповер немодален.\n *\n * Корень слоя и панель здесь один элемент: якорный оверлей уезжает в портал сам,\n * без обёртки.\n */\nconst { inertAttr, portalTarget, teleportEnabled, themeAttrs } = useModalOverlay(isOpen, close, {\n modal: () => props.modal,\n closeOnEscape: () => props.closeOnEsc,\n panel: panelEl,\n root: panelEl,\n teleportTo: () => props.teleportTo,\n initialFocus: () => panelEl.value,\n})\n\n// Фокус переносим после отрисовки панели: до `nextTick` её ещё нет в DOM.\n// В модальном режиме перенос обязателен: фон в `inert`, и фокус, оставленный\n// снаружи, попал бы в недоступное поддерево.\nwatch(isOpen, async (next) => {\n if (!next || !(props.autoFocus || props.modal)) return\n\n await nextTick()\n panelEl.value?.focus()\n})\n\n/** Роли, которые `aria-haspopup` действительно понимает. */\nconst HASPOPUP_ROLES = ['dialog', 'menu', 'listbox', 'grid'] as const\n\n/**\n * Пропсы для реального фокусируемого триггера: `<button v-bind=\"triggerProps\">`.\n * Клик вешается на обёртку, а ARIA — сюда, потому что `aria-expanded` обязан\n * жить на самом интерактивном элементе, а не на `div` вокруг него.\n */\nconst triggerProps = computed(() => ({\n // `aria-haspopup` принимает не любую роль: `group` в его списке нет, и\n // объявленный им триггер отдавал бы невалидный атрибут, который AT просто\n // отбрасывает. Роли вне списка сообщают о панели только через `aria-expanded`.\n 'aria-haspopup': HASPOPUP_ROLES.includes(props.role as (typeof HASPOPUP_ROLES)[number])\n ? (props.role as (typeof HASPOPUP_ROLES)[number])\n : undefined,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'disabled': props.disabled || undefined,\n}))\n\nfunction onTriggerClick(): void {\n if (props.trigger === 'click') toggle()\n}\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) close()\n}\n\nconst panelClasses = computed(() =>\n grPopoverPanelClass(resolvedSize.value, resolvedPlacement.value, props.contentClass, props.padding),\n)\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое панели. */\n content?: (props: { close: () => void }) => any\n}>()\n\n</script>\n\n<template>\n <div data-gr-popover>\n <div\n v-if=\"hasTrigger\"\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside, exclude: clickOutsideExclude }\"\n data-gr-popover-trigger\n class=\"inline-block max-w-full\"\n @click=\"onTriggerClick\"\n >\n <slot\n name=\"trigger\"\n :open=\"isOpen\"\n :toggle=\"toggle\"\n :close=\"close\"\n :trigger-props=\"triggerProps\"\n />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside && !hasTrigger }\"\n v-bind=\"themeAttrs\"\n data-gr-popover-panel\n data-gr-overlay-root\n :role=\"role === 'none' ? undefined : role\"\n :aria-modal=\"modal ? 'true' : undefined\"\n :inert=\"inertAttr\"\n :aria-label=\"labelledBy ? undefined : ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"floatingStyle\"\n @click=\"onContentClick\"\n >\n <slot name=\"content\" :close=\"close\" />\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrPopover-CofG-Tfe.js","names":[],"sources":["../../../../src/components/GrPopover/GrPopover.vue","../../../../src/components/GrPopover/GrPopover.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrPopover — якорный немодальный оверлей с произвольным содержимым.\n *\n * Роль «универсального поповера» до сих пор насильно исполнял `GrDropdown`, но\n * он про меню: жёстко объявляет `role=\"menu\"`, `aria-haspopup=\"menu\"` и водит\n * фокус по пунктам. Для формы, подтверждения или палитры это неверная семантика.\n *\n * Здесь наоборот: позиционирование, слой и закрытие берёт на себя примитив, а\n * клавиатурный паттерн внутри панели остаётся за потребителем — поэтому `role`\n * задаётся пропом. На этом собираются `GrMenu` / `GrContextMenu` /\n * `GrColorPicker` / Popconfirm.\n *\n * A11y:\n * - триггер получает `aria-haspopup`/`aria-expanded`/`aria-controls` через\n * `triggerProps` (биндится на реальный фокусируемый элемент в слоте);\n * - панель — `role=\"dialog\"` по умолчанию и обязательное доступное имя\n * (`ariaLabel` либо `aria-labelledby` через `labelledBy`);\n * - Esc закрывает верхний слой стека, клик вне — закрывает по точке попадания;\n * - **по умолчанию фокус-ловушки нет намеренно**: Tab обязан уводить фокус\n * наружу, иначе немодальный слой запирает пользователя на странице, которая\n * не заблокирована. Проп `modal` включает второй режим — см. ниже.\n */\nimport { computed, nextTick, ref, useId, useSlots, watch } from 'vue'\n\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useModalOverlay } from '../../composables/internal/useModalOverlay'\nimport { createFloatingAnchor, type GrFloatingAnchorRect, useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { vClickOutside } from '../../directives'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\nimport {\n type GrPopoverPadding,\n type GrPopoverRole,\n type GrPopoverSize,\n grPopoverPanelClass,\n} from './grPopoverStyles'\n\nexport interface GrPopoverProps {\n /**\n * Открыт ли поповер. Без этого пропа компонент ведёт состояние сам\n * (uncontrolled), с ним — слушайте `update:open`.\n */\n open?: boolean\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offsetPx?: number\n size?: GrPopoverSize\n /** Роль панели. Меняется теми, кто строит поверх примитива своё меню/список. */\n role?: GrPopoverRole\n /**\n * Модальный режим: фон уходит в `inert`, Tab ходит по кругу внутри панели,\n * скролл страницы блокируется, а слой встаёт в стек модальным — как окно.\n * Нужен поповеру с формой или подтверждением внутри: без изоляции фона\n * пользователь уводит фокус на страницу, к которой поповер и относится.\n *\n * В этом режиме фокус переносится в панель независимо от `autoFocus`: фон\n * недоступен, и слой без фокуса внутри стал бы клавиатурной ловушкой.\n */\n modal?: boolean\n /** Доступное имя панели. Обязательно для `role=\"dialog\"` без видимого заголовка. */\n ariaLabel?: string\n /** `id` видимого заголовка внутри панели — альтернатива `ariaLabel`. */\n labelledBy?: string\n /**\n * `manual` — открывать только программно (через `v-model:open`). Нужно для\n * контекстного меню и подтверждений, где момент открытия решает потребитель.\n */\n trigger?: 'click' | 'manual'\n closeOnEsc?: boolean\n closeOnClickOutside?: boolean\n /** Закрывать по клику внутри панели — удобно для меню, вредно для формы. */\n closeOnContentClick?: boolean\n /**\n * Переносить фокус на панель при открытии. Именно на панель, а не на первый\n * контрол внутри: сфокусировать поле ввода за пользователя — решение\n * содержимого, а не оболочки.\n */\n autoFocus?: boolean\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n contentClass?: string\n disabled?: boolean\n /**\n * Якорь-прямоугольник в координатах вьюпорта вместо обёртки слота `#trigger`:\n * панель встаёт у точки курсора или у строки списка. Нужен контекстному меню,\n * у которого триггера-элемента нет вовсе.\n *\n * `triggerProps` в этом режиме некому потребить, и своих ARIA-атрибутов\n * поповер никуда не вешает: `aria-haspopup` невалиден вне интерактивного\n * элемента, а `aria-expanded` без хозяина — шум. Связь с содержимым страницы\n * объявляет тот, кто открывает.\n */\n anchor?: GrFloatingAnchorRect | null\n /** Поле панели. `none` — содержимое рисует своё (меню, список опций). */\n padding?: GrPopoverPadding\n}\n\nexport interface GrPopoverEmits {\n (e: 'update:open', value: boolean): void\n}\n\nconst props = withDefaults(defineProps<GrPopoverProps>(), {\n open: undefined,\n placement: 'bottom-start',\n offsetPx: 8,\n size: undefined,\n role: 'dialog',\n modal: false,\n ariaLabel: undefined,\n labelledBy: undefined,\n trigger: 'click',\n closeOnEsc: true,\n closeOnClickOutside: true,\n closeOnContentClick: false,\n autoFocus: true,\n teleportTo: undefined,\n contentClass: undefined,\n disabled: false,\n anchor: undefined,\n padding: 'default',\n})\n\nconst emit = defineEmits<GrPopoverEmits>()\n\nconst slots = useSlots()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPopover' })\n\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst panelId = useId()\n\nconst clickOutsideExclude = [() => panelEl.value]\n\nfunction open(): void {\n if (props.disabled)\n return\n setOpen(true)\n}\n\nfunction close(): void {\n setOpen(false)\n}\n\nfunction toggle(): void {\n isOpen.value ? close() : open()\n}\n\n/**\n * Якорь создаётся один раз и читает координаты геттером: `useFloating`\n * пересоздаёт подписку при смене самой ссылки, а точка меняется на каждый\n * вызов — новый объект рвал бы `autoUpdate` без нужды.\n */\nconst anchorEl = createFloatingAnchor(() => props.anchor)\n\n/** Обёртка триггера существует только вместе со слотом — см. проп `anchor`. */\nconst hasTrigger = computed(() => Boolean(slots.trigger))\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n () => (props.anchor ? anchorEl : rootEl.value),\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n offsetPx: props.offsetPx,\n // Своего слоя у поповера нет намеренно: он и дропдаун — один класс якорных\n // немодальных оверлеев и обязаны лежать на одной высоте, иначе начнут\n // перекрывать друг друга в зависимости от порядка открытия.\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\nwatch(() => props.placement, () => {\n if (isOpen.value)\n updateFloatingPosition()\n})\n\n// Объект якоря стабилен, поэтому смену координат `useFloating` сам не заметит:\n// повторный вызов у другой точки — это пересчёт позиции, а не переоткрытие.\nwatch(() => props.anchor, () => {\n if (isOpen.value)\n updateFloatingPosition()\n}, { deep: true })\n\n/**\n * Слой стека оверлеев: очередь Esc общая с модалками, поэтому поповер, открытый\n * внутри модалки, по Esc закрывает себя, а не её. Возврат фокуса на триггер\n * тоже отсюда — по правилу «только если на момент закрытия фокус ещё внутри».\n *\n * Модальность включается пропом и приходит той же сборкой, что у окна и drawer'а\n * (`useModalOverlay`): ловушка фокуса, `inert` фона, блокировка скролла. При\n * `modal: false` не включается ничего из этого — дефолтный поповер немодален.\n *\n * Корень слоя и панель здесь один элемент: якорный оверлей уезжает в портал сам,\n * без обёртки.\n */\nconst { inertAttr, portalTarget, teleportEnabled, themeAttrs } = useModalOverlay(isOpen, close, {\n modal: () => props.modal,\n closeOnEscape: () => props.closeOnEsc,\n panel: panelEl,\n root: panelEl,\n teleportTo: () => props.teleportTo,\n initialFocus: () => panelEl.value,\n})\n\n// Фокус переносим после отрисовки панели: до `nextTick` её ещё нет в DOM.\n// В модальном режиме перенос обязателен: фон в `inert`, и фокус, оставленный\n// снаружи, попал бы в недоступное поддерево.\nwatch(isOpen, async (next) => {\n if (!next || !(props.autoFocus || props.modal))\n return\n\n await nextTick()\n panelEl.value?.focus()\n})\n\n/** Роли, которые `aria-haspopup` действительно понимает. */\nconst HASPOPUP_ROLES = ['dialog', 'menu', 'listbox', 'grid'] as const\n\n/**\n * Пропсы для реального фокусируемого триггера: `<button v-bind=\"triggerProps\">`.\n * Клик вешается на обёртку, а ARIA — сюда, потому что `aria-expanded` обязан\n * жить на самом интерактивном элементе, а не на `div` вокруг него.\n */\nconst triggerProps = computed(() => ({\n // `aria-haspopup` принимает не любую роль: `group` в его списке нет, и\n // объявленный им триггер отдавал бы невалидный атрибут, который AT просто\n // отбрасывает. Роли вне списка сообщают о панели только через `aria-expanded`.\n 'aria-haspopup': HASPOPUP_ROLES.includes(props.role as (typeof HASPOPUP_ROLES)[number])\n ? (props.role as (typeof HASPOPUP_ROLES)[number])\n : undefined,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'disabled': props.disabled || undefined,\n}))\n\nfunction onTriggerClick(): void {\n if (props.trigger === 'click')\n toggle()\n}\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick)\n close()\n}\n\nconst panelClasses = computed(() =>\n grPopoverPanelClass(resolvedSize.value, resolvedPlacement.value, props.contentClass, props.padding),\n)\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое панели. */\n content?: (props: { close: () => void }) => any\n}>()\n</script>\n\n<template>\n <div data-gr-popover>\n <div\n v-if=\"hasTrigger\"\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside, exclude: clickOutsideExclude }\"\n data-gr-popover-trigger\n class=\"inline-block max-w-full\"\n @click=\"onTriggerClick\"\n >\n <slot\n name=\"trigger\"\n :open=\"isOpen\"\n :toggle=\"toggle\"\n :close=\"close\"\n :trigger-props=\"triggerProps\"\n />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside && !hasTrigger }\"\n v-bind=\"themeAttrs\"\n data-gr-popover-panel\n data-gr-overlay-root\n :role=\"role === 'none' ? undefined : role\"\n :aria-modal=\"modal ? 'true' : undefined\"\n :inert=\"inertAttr\"\n :aria-label=\"labelledBy ? undefined : ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"floatingStyle\"\n @click=\"onContentClick\"\n >\n <slot name=\"content\" :close=\"close\" />\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrPopover — якорный немодальный оверлей с произвольным содержимым.\n *\n * Роль «универсального поповера» до сих пор насильно исполнял `GrDropdown`, но\n * он про меню: жёстко объявляет `role=\"menu\"`, `aria-haspopup=\"menu\"` и водит\n * фокус по пунктам. Для формы, подтверждения или палитры это неверная семантика.\n *\n * Здесь наоборот: позиционирование, слой и закрытие берёт на себя примитив, а\n * клавиатурный паттерн внутри панели остаётся за потребителем — поэтому `role`\n * задаётся пропом. На этом собираются `GrMenu` / `GrContextMenu` /\n * `GrColorPicker` / Popconfirm.\n *\n * A11y:\n * - триггер получает `aria-haspopup`/`aria-expanded`/`aria-controls` через\n * `triggerProps` (биндится на реальный фокусируемый элемент в слоте);\n * - панель — `role=\"dialog\"` по умолчанию и обязательное доступное имя\n * (`ariaLabel` либо `aria-labelledby` через `labelledBy`);\n * - Esc закрывает верхний слой стека, клик вне — закрывает по точке попадания;\n * - **по умолчанию фокус-ловушки нет намеренно**: Tab обязан уводить фокус\n * наружу, иначе немодальный слой запирает пользователя на странице, которая\n * не заблокирована. Проп `modal` включает второй режим — см. ниже.\n */\nimport { computed, nextTick, ref, useId, useSlots, watch } from 'vue'\n\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useModalOverlay } from '../../composables/internal/useModalOverlay'\nimport { createFloatingAnchor, type GrFloatingAnchorRect, useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { vClickOutside } from '../../directives'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { panelPopTransition } from '../shared/overlayTransition'\nimport {\n type GrPopoverPadding,\n type GrPopoverRole,\n type GrPopoverSize,\n grPopoverPanelClass,\n} from './grPopoverStyles'\n\nexport interface GrPopoverProps {\n /**\n * Открыт ли поповер. Без этого пропа компонент ведёт состояние сам\n * (uncontrolled), с ним — слушайте `update:open`.\n */\n open?: boolean\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offsetPx?: number\n size?: GrPopoverSize\n /** Роль панели. Меняется теми, кто строит поверх примитива своё меню/список. */\n role?: GrPopoverRole\n /**\n * Модальный режим: фон уходит в `inert`, Tab ходит по кругу внутри панели,\n * скролл страницы блокируется, а слой встаёт в стек модальным — как окно.\n * Нужен поповеру с формой или подтверждением внутри: без изоляции фона\n * пользователь уводит фокус на страницу, к которой поповер и относится.\n *\n * В этом режиме фокус переносится в панель независимо от `autoFocus`: фон\n * недоступен, и слой без фокуса внутри стал бы клавиатурной ловушкой.\n */\n modal?: boolean\n /** Доступное имя панели. Обязательно для `role=\"dialog\"` без видимого заголовка. */\n ariaLabel?: string\n /** `id` видимого заголовка внутри панели — альтернатива `ariaLabel`. */\n labelledBy?: string\n /**\n * `manual` — открывать только программно (через `v-model:open`). Нужно для\n * контекстного меню и подтверждений, где момент открытия решает потребитель.\n */\n trigger?: 'click' | 'manual'\n closeOnEsc?: boolean\n closeOnClickOutside?: boolean\n /** Закрывать по клику внутри панели — удобно для меню, вредно для формы. */\n closeOnContentClick?: boolean\n /**\n * Переносить фокус на панель при открытии. Именно на панель, а не на первый\n * контрол внутри: сфокусировать поле ввода за пользователя — решение\n * содержимого, а не оболочки.\n */\n autoFocus?: boolean\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n contentClass?: string\n disabled?: boolean\n /**\n * Якорь-прямоугольник в координатах вьюпорта вместо обёртки слота `#trigger`:\n * панель встаёт у точки курсора или у строки списка. Нужен контекстному меню,\n * у которого триггера-элемента нет вовсе.\n *\n * `triggerProps` в этом режиме некому потребить, и своих ARIA-атрибутов\n * поповер никуда не вешает: `aria-haspopup` невалиден вне интерактивного\n * элемента, а `aria-expanded` без хозяина — шум. Связь с содержимым страницы\n * объявляет тот, кто открывает.\n */\n anchor?: GrFloatingAnchorRect | null\n /** Поле панели. `none` — содержимое рисует своё (меню, список опций). */\n padding?: GrPopoverPadding\n}\n\nexport interface GrPopoverEmits {\n (e: 'update:open', value: boolean): void\n}\n\nconst props = withDefaults(defineProps<GrPopoverProps>(), {\n open: undefined,\n placement: 'bottom-start',\n offsetPx: 8,\n size: undefined,\n role: 'dialog',\n modal: false,\n ariaLabel: undefined,\n labelledBy: undefined,\n trigger: 'click',\n closeOnEsc: true,\n closeOnClickOutside: true,\n closeOnContentClick: false,\n autoFocus: true,\n teleportTo: undefined,\n contentClass: undefined,\n disabled: false,\n anchor: undefined,\n padding: 'default',\n})\n\nconst emit = defineEmits<GrPopoverEmits>()\n\nconst slots = useSlots()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrPopover' })\n\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst panelId = useId()\n\nconst clickOutsideExclude = [() => panelEl.value]\n\nfunction open(): void {\n if (props.disabled)\n return\n setOpen(true)\n}\n\nfunction close(): void {\n setOpen(false)\n}\n\nfunction toggle(): void {\n isOpen.value ? close() : open()\n}\n\n/**\n * Якорь создаётся один раз и читает координаты геттером: `useFloating`\n * пересоздаёт подписку при смене самой ссылки, а точка меняется на каждый\n * вызов — новый объект рвал бы `autoUpdate` без нужды.\n */\nconst anchorEl = createFloatingAnchor(() => props.anchor)\n\n/** Обёртка триггера существует только вместе со слотом — см. проп `anchor`. */\nconst hasTrigger = computed(() => Boolean(slots.trigger))\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n () => (props.anchor ? anchorEl : rootEl.value),\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n offsetPx: props.offsetPx,\n // Своего слоя у поповера нет намеренно: он и дропдаун — один класс якорных\n // немодальных оверлеев и обязаны лежать на одной высоте, иначе начнут\n // перекрывать друг друга в зависимости от порядка открытия.\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\nwatch(() => props.placement, () => {\n if (isOpen.value)\n updateFloatingPosition()\n})\n\n// Объект якоря стабилен, поэтому смену координат `useFloating` сам не заметит:\n// повторный вызов у другой точки — это пересчёт позиции, а не переоткрытие.\nwatch(() => props.anchor, () => {\n if (isOpen.value)\n updateFloatingPosition()\n}, { deep: true })\n\n/**\n * Слой стека оверлеев: очередь Esc общая с модалками, поэтому поповер, открытый\n * внутри модалки, по Esc закрывает себя, а не её. Возврат фокуса на триггер\n * тоже отсюда — по правилу «только если на момент закрытия фокус ещё внутри».\n *\n * Модальность включается пропом и приходит той же сборкой, что у окна и drawer'а\n * (`useModalOverlay`): ловушка фокуса, `inert` фона, блокировка скролла. При\n * `modal: false` не включается ничего из этого — дефолтный поповер немодален.\n *\n * Корень слоя и панель здесь один элемент: якорный оверлей уезжает в портал сам,\n * без обёртки.\n */\nconst { inertAttr, portalTarget, teleportEnabled, themeAttrs } = useModalOverlay(isOpen, close, {\n modal: () => props.modal,\n closeOnEscape: () => props.closeOnEsc,\n panel: panelEl,\n root: panelEl,\n teleportTo: () => props.teleportTo,\n initialFocus: () => panelEl.value,\n})\n\n// Фокус переносим после отрисовки панели: до `nextTick` её ещё нет в DOM.\n// В модальном режиме перенос обязателен: фон в `inert`, и фокус, оставленный\n// снаружи, попал бы в недоступное поддерево.\nwatch(isOpen, async (next) => {\n if (!next || !(props.autoFocus || props.modal))\n return\n\n await nextTick()\n panelEl.value?.focus()\n})\n\n/** Роли, которые `aria-haspopup` действительно понимает. */\nconst HASPOPUP_ROLES = ['dialog', 'menu', 'listbox', 'grid'] as const\n\n/**\n * Пропсы для реального фокусируемого триггера: `<button v-bind=\"triggerProps\">`.\n * Клик вешается на обёртку, а ARIA — сюда, потому что `aria-expanded` обязан\n * жить на самом интерактивном элементе, а не на `div` вокруг него.\n */\nconst triggerProps = computed(() => ({\n // `aria-haspopup` принимает не любую роль: `group` в его списке нет, и\n // объявленный им триггер отдавал бы невалидный атрибут, который AT просто\n // отбрасывает. Роли вне списка сообщают о панели только через `aria-expanded`.\n 'aria-haspopup': HASPOPUP_ROLES.includes(props.role as (typeof HASPOPUP_ROLES)[number])\n ? (props.role as (typeof HASPOPUP_ROLES)[number])\n : undefined,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'disabled': props.disabled || undefined,\n}))\n\nfunction onTriggerClick(): void {\n if (props.trigger === 'click')\n toggle()\n}\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick)\n close()\n}\n\nconst panelClasses = computed(() =>\n grPopoverPanelClass(resolvedSize.value, resolvedPlacement.value, props.contentClass, props.padding),\n)\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /**\n * Триггер панели. `triggerProps` обязаны попасть на сам интерактивный\n * элемент, а не на обёртку вокруг него: `aria-expanded` и `aria-controls`\n * читаются с того узла, который получает фокус.\n */\n trigger?: (props: {\n open: boolean\n toggle: () => void\n close: () => void\n triggerProps: Record<string, unknown>\n }) => any\n /** Содержимое панели. */\n content?: (props: { close: () => void }) => any\n}>()\n</script>\n\n<template>\n <div data-gr-popover>\n <div\n v-if=\"hasTrigger\"\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside, exclude: clickOutsideExclude }\"\n data-gr-popover-trigger\n class=\"inline-block max-w-full\"\n @click=\"onTriggerClick\"\n >\n <slot\n name=\"trigger\"\n :open=\"isOpen\"\n :toggle=\"toggle\"\n :close=\"close\"\n :trigger-props=\"triggerProps\"\n />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen && closeOnClickOutside && !hasTrigger }\"\n v-bind=\"themeAttrs\"\n data-gr-popover-panel\n data-gr-overlay-root\n :role=\"role === 'none' ? undefined : role\"\n :aria-modal=\"modal ? 'true' : undefined\"\n :inert=\"inertAttr\"\n :aria-label=\"labelledBy ? undefined : ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"floatingStyle\"\n @click=\"onContentClick\"\n >\n <slot name=\"content\" :close=\"close\" />\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1,11 +1,11 @@
1
1
  import { i as useGrComponentProp } from "../../../chunks/context-CTbuwcYs.js";
2
2
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
- import { t as GrButton_default } from "../../GrButton/chunks/GrButton-Bw2AH4uX.js";
3
+ import { t as GrButton_default } from "../../GrButton/chunks/GrButton-7GP0zObj.js";
4
4
  import { t as GrInput_default } from "../../GrInput/chunks/GrInput-BLywRZUN.js";
5
- import { t as GrDialog_default } from "../../GrDialog/chunks/GrDialog-bOUDYfmh.js";
6
- import { t as GrResponseErrorBanner_default } from "../../GrResponseErrorBanner/chunks/GrResponseErrorBanner-DudGc9LO.js";
5
+ import { t as GrDialog_default } from "../../GrDialog/chunks/GrDialog-S1Vl-OhX.js";
6
+ import { t as GrResponseErrorBanner_default } from "../../GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js";
7
7
  import { t as GrFormField_default } from "../../GrFormField/chunks/GrFormField-DSylU7IU.js";
8
- import { t as GrTextarea_default } from "../../GrTextarea/chunks/GrTextarea-KREK75Bu.js";
8
+ import { t as GrTextarea_default } from "../../GrTextarea/chunks/GrTextarea-DinXG12-.js";
9
9
  import { i as rulesForTrigger, o as runFieldRules, t as createGrFormMessageResolver } from "../../../chunks/validation-5HhpanPP.js";
10
10
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, renderSlot, toDisplayString, unref, watch, withCtx, withKeys } from "vue";
11
11
  //#region src/components/GrPromptDialog/GrPromptDialog.vue?vue&type=script&setup=true&lang.ts
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrPromptDialog-BuJQMZLM.js","names":[],"sources":["../../../../src/components/GrPromptDialog/GrPromptDialog.vue","../../../../src/components/GrPromptDialog/GrPromptDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrPromptDialog — GR-примитив диалога ввода значения поверх `GrDialog`.\n *\n * Синхронизирован с `GrDialog` по набору проп-проксирования:\n * `size`, `closeOnBackdrop`, `closeOnEsc`, `showHeader`, `showCloseButton`,\n * `headerConfig`, `footerConfig`, `bodyConfig`, `closeLabel`.\n *\n * Поведение `required=true` (по умолчанию): пустое значение подсвечивается\n * ошибкой только после первого «касания» (blur или попытка confirm),\n * чтобы не шуметь при открытии.\n *\n * Проверки сверх `required` описываются пропом `rules` — тем же движком, что и\n * у `GrForm`: третий частный случай валидации в пакете заводить незачем.\n */\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { computed, ref, watch } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrDialog from '../GrDialog/GrDialog.vue'\nimport GrFormField from '../GrFormField/GrFormField.vue'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrTextarea from '../GrTextarea/GrTextarea.vue'\nimport GrResponseErrorBanner from '../GrResponseErrorBanner/GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n// Именованные импорты чистых функций: разметки не тянут, поэтому в\n// `config.dependencies` не объявляются (см. правило про зависимости).\nimport { createGrFormMessageResolver, rulesForTrigger, runFieldRules } from '../GrForm/validation'\nimport type { GrFormRule, GrFormTrigger } from '../GrForm/validation'\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton'\nimport type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog'\n\n/**\n * Тип поля выводим из самого `GrInput`, а не заводим ему именованный алиас:\n * алиас в пропе `GrInput` заменил бы в таблице API витрины список допустимых\n * значений на своё имя — документация стала бы беднее ради удобства обёртки.\n */\ntype GrInputType = NonNullable<InstanceType<typeof GrInput>['$props']['type']>\nimport type { ResponseErrorInfo } from '../GrResponseErrorBanner'\nimport type { InputHTMLAttributes } from 'vue'\n\nexport interface GrPromptDialogProps {\n modelValue: boolean\n value: string\n title?: string\n description?: string\n label?: string\n placeholder?: string\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n showHeader?: boolean\n showCloseButton?: boolean\n size?: GrDialogSize\n headerConfig?: GrDialogSectionConfig\n footerConfig?: GrDialogSectionConfig\n bodyConfig?: GrDialogSectionConfig\n /** A11y-лейбл кнопки закрытия (i18n). */\n closeLabel?: string\n buttonSize?: GrButtonSize\n confirmText?: string\n cancelText?: string\n /** Текст ошибки для пустого значения при `required=true` (i18n). */\n requiredErrorText?: string\n confirmVariant?: GrButtonVariant\n confirmTone?: GrButtonTone\n required?: boolean\n /** Тип однострочного поля. В многострочном режиме не применяется. */\n inputType?: GrInputType\n /** Программная клавиатура на мобильных. */\n inputmode?: InputHTMLAttributes['inputmode']\n /** Ограничение длины; со `showCount` рисуется счётчик. */\n maxlength?: number\n showCount?: boolean\n /** Многострочный ввод: вместо `GrInput` рисуется `GrTextarea`. */\n multiline?: boolean\n /** Высота многострочного поля в строках. */\n rows?: number\n /** Автоподбор высоты многострочного поля под содержимое. */\n autosize?: boolean\n /**\n * Правила проверки значения — те же, что у `GrForm` (`required`, `type`,\n * `min`/`max`/`len`, `pattern`, свой в т.ч. асинхронный `validator`).\n * Прогоняются на blur (после первого касания) и на подтверждении.\n */\n rules?: GrFormRule | GrFormRule[]\n /**\n * Структура ошибки ответа сервера для показа общим блоком в теле диалога\n * (через `GrResponseErrorBanner`). `null` — блок скрыт.\n */\n error?: ResponseErrorInfo | null\n /**\n * Внешняя ошибка поля ввода (например, серверная валидация). Имеет приоритет\n * над встроенной проверкой. `null`/`undefined` — нет внешней ошибки.\n */\n fieldError?: string | null\n /** Состояние загрузки кнопки Confirm (async-`onConfirm` in-flight). */\n confirmLoading?: boolean\n /** Принудительно дизейблит кнопку Confirm. */\n confirmDisabled?: boolean\n /**\n * Закрывать ли диалог автоматически по клику Confirm. По умолчанию `true`.\n * `false` — отдаёт управление закрытием наружу (нужно `useDialogService`).\n */\n closeOnConfirm?: boolean\n /**\n * Запрет закрытия «мягкими» способами (Esc, клик по бэкдропу), пока идёт\n * подтверждение или проверка `rules`. Кнопка закрытия и «Отмена» остаются:\n * окно без единого выхода — ловушка.\n */\n persistent?: boolean\n}\n\nexport interface GrPromptDialogEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'update:value', value: string): void\n (e: 'confirm', value: string): void\n (e: 'cancel'): void\n}\n\nimport './defaults'\n\nconst props = withDefaults(defineProps<GrPromptDialogProps>(), {\n title: undefined,\n description: undefined,\n label: undefined,\n placeholder: undefined,\n closeOnBackdrop: true,\n closeOnEsc: true,\n showHeader: true,\n showCloseButton: true,\n // Дефолт `size` живёт в резолвере ниже, а не здесь: Vue подставил бы его\n // до того, как компонент заглянет в `GrConfigProvider`.\n size: undefined,\n headerConfig: undefined,\n footerConfig: undefined,\n bodyConfig: undefined,\n closeLabel: undefined,\n buttonSize: undefined,\n confirmText: undefined,\n cancelText: undefined,\n requiredErrorText: undefined,\n confirmVariant: 'primary',\n confirmTone: 'primary',\n required: true,\n inputType: 'text',\n inputmode: undefined,\n maxlength: undefined,\n showCount: false,\n multiline: false,\n rows: undefined,\n autosize: false,\n rules: undefined,\n error: null,\n fieldError: null,\n confirmLoading: false,\n confirmDisabled: false,\n closeOnConfirm: true,\n persistent: false,\n})\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentProp('GrPromptDialog', 'size', () => props.size, 'md')\n\nconst emit = defineEmits<GrPromptDialogEmits>()\n\n// Дефолты берём из общего i18n-блока пакета (fallback — англ.), а не хардкодим.\nconst { t } = useGranularityTranslations()\nconst resolvedTitle = computed(() => props.title ?? t('gr.dialog.prompt.title', 'Prompt'))\nconst resolvedLabel = computed(() => props.label ?? t('gr.dialog.prompt.label', 'Value'))\nconst resolvedRequiredErrorText = computed(() => props.requiredErrorText ?? t('gr.dialog.prompt.required', 'Enter a value.'))\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? t('gr.common.close', 'Close'))\nconst resolvedConfirmText = computed(() => props.confirmText ?? t('gr.common.confirm', 'Confirm'))\nconst resolvedCancelText = computed(() => props.cancelText ?? t('gr.common.cancel', 'Cancel'))\n\nconst open = computed({\n get: () => props.modelValue,\n set: (v: boolean) => emit('update:modelValue', v),\n})\n\nconst valueModel = computed({\n get: () => props.value,\n set: (v: string) => emit('update:value', v),\n})\n\nconst touched = ref(false)\nconst inputRef = ref<InstanceType<typeof GrInput> | null>(null)\nconst textareaRef = ref<InstanceType<typeof GrTextarea> | null>(null)\n\n/** Ошибка последнего прогона `rules`; `required` считается отдельно и мгновенно. */\nconst ruleError = ref<string | undefined>(undefined)\nconst validating = ref(false)\n\n// Сторож устаревших прогонов: асинхронное правило может ответить после того,\n// как значение уже сменилось, и дописать чужую ошибку.\nlet validationRun = 0\n\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (!isOpen)\n return\n\n touched.value = false\n ruleError.value = undefined\n validationRun += 1\n },\n)\n\nconst resolveMessage = createGrFormMessageResolver(t)\n\nconst normalizedRules = computed<GrFormRule[]>(() => {\n if (!props.rules)\n return []\n return Array.isArray(props.rules) ? props.rules : [props.rules]\n})\n\nconst requiredError = computed(() => {\n if (!props.required)\n return undefined\n return valueModel.value.trim().length > 0 ? undefined : resolvedRequiredErrorText.value\n})\n\nconst canConfirm = computed(() => !requiredError.value)\n\nconst validationError = computed(() => {\n if (!touched.value)\n return undefined\n return requiredError.value ?? ruleError.value\n})\n\n// Внешняя ошибка поля (серверная валидация) имеет приоритет над встроенной.\nconst fieldErrorMessage = computed(() => props.fieldError ?? validationError.value ?? undefined)\n\n/**\n * Прогоняет `rules` для триггера. Возвращает сообщение или `undefined`.\n * `required` здесь не участвует: он синхронный и считается отдельно, чтобы\n * пустое поле блокировало кнопку без похода в асинхронный движок.\n */\nasync function runRules(trigger: GrFormTrigger): Promise<string | undefined> {\n const rules = rulesForTrigger(normalizedRules.value, trigger)\n if (!rules.length)\n return undefined\n\n const run = ++validationRun\n validating.value = true\n try {\n const message = await runFieldRules(valueModel.value, rules, { value: valueModel.value }, resolveMessage)\n // Ответ устарел — значение или сам диалог успели смениться.\n if (run !== validationRun)\n return undefined\n\n ruleError.value = message\n return message\n }\n finally {\n if (run === validationRun)\n validating.value = false\n }\n}\n\nfunction onBlur(): void {\n touched.value = true\n void runRules('blur')\n}\n\n// Пока подтверждение или проверка в полёте, случайное движение не должно\n// оборвать операцию.\nconst softCloseBlocked = computed(() => props.persistent && (props.confirmLoading || validating.value))\nconst resolvedCloseOnBackdrop = computed(() => (softCloseBlocked.value ? false : props.closeOnBackdrop))\nconst resolvedCloseOnEsc = computed(() => (softCloseBlocked.value ? false : props.closeOnEsc))\n\nfunction onCancel(): void {\n emit('cancel')\n emit('update:modelValue', false)\n}\n\nfunction focusField(): void {\n if (props.multiline)\n textareaRef.value?.focus()\n else inputRef.value?.focus()\n}\n\nasync function onConfirm(): Promise<void> {\n touched.value = true\n\n if (!canConfirm.value) {\n focusField()\n return\n }\n\n if (await runRules('submit')) {\n focusField()\n return\n }\n\n emit('confirm', valueModel.value)\n if (props.closeOnConfirm)\n emit('update:modelValue', false)\n}\n\n/**\n * `Enter` подтверждает — базовое ожидание от окна, единственный смысл которого\n * ввести одно значение. В многострочном режиме `Enter` остаётся переводом\n * строки, поэтому обработчик висит только на однострочном поле.\n */\nfunction onEnter(): void {\n void onConfirm()\n}\n\n// Фокус в поле, а не на панель: диалог существует ровно ради ввода.\n//\n// Через `initialFocus` у `GrModal` это не решается: элемент рождается внутри\n// поддерева диалога, и возврат его же пропом наверх замыкает рендер в цикл\n// («Maximum recursive updates» — проверено). Поэтому фокус ставит содержимое,\n// после отрисовки (`flush: 'post'` + кадр), то есть заведомо позже, чем\n// ловушка фокуса `GrModal` переводит фокус на панель.\n// Источник — не только `modelValue`, но и само поле: содержимое панели\n// появляется на такт позже открытия, и фокус по фиксированному `nextTick`\n// приходился на момент, когда фокусировать ещё нечего.\nwatch(\n [() => props.modelValue, inputRef, textareaRef],\n () => {\n if (!props.modelValue)\n return\n focusField()\n },\n // `immediate`: окно могут смонтировать уже открытым — тогда смены пропа не\n // будет вовсе, и без этого фокус остался бы на панели.\n { immediate: true, flush: 'post' },\n)\n\ndefineSlots<{\n /** Содержимое диалога вместо пропа `message`. */\n default?: () => any\n /** Разбор ошибки вместо встроенного баннера. */\n error?: (props: { error: ResponseErrorInfo | null }) => any\n /** Кнопки диалога вместо пары «отмена и подтверждение». */\n footer?: () => any\n}>()\n</script>\n\n<template>\n <GrDialog\n v-model=\"open\"\n :title=\"resolvedTitle\"\n :size=\"resolvedSize\"\n :close-on-backdrop=\"resolvedCloseOnBackdrop\"\n :close-on-esc=\"resolvedCloseOnEsc\"\n :show-header=\"showHeader\"\n :show-close-button=\"showCloseButton\"\n :header-config=\"headerConfig\"\n :footer-config=\"footerConfig\"\n :body-config=\"bodyConfig\"\n :close-label=\"resolvedCloseLabel\"\n >\n <div class=\"grid gap-4\">\n <slot>\n <div v-if=\"description\" class=\"text-[length:var(--gr-control-text-md)] leading-[var(--gr-control-leading-md)] text-[var(--gr-muted-fg)]\">\n {{ description }}\n </div>\n </slot>\n\n <!-- `id` полю не задаём: `GrFormField` генерирует его сам, а поле читает\n из контекста. Литеральный id ломал два открытых диалога сразу. -->\n <GrFormField :label=\"resolvedLabel\" :error=\"fieldErrorMessage\">\n <GrTextarea\n v-if=\"multiline\"\n ref=\"textareaRef\"\n v-model=\"valueModel\"\n data-testid=\"gr-prompt-input\"\n :placeholder=\"placeholder\"\n :rows=\"rows\"\n :autosize=\"autosize\"\n :maxlength=\"maxlength\"\n :show-count=\"showCount\"\n :invalid=\"!!fieldErrorMessage\"\n @blur=\"onBlur\"\n />\n <GrInput\n v-else\n ref=\"inputRef\"\n v-model=\"valueModel\"\n data-testid=\"gr-prompt-input\"\n :type=\"inputType\"\n :inputmode=\"inputmode\"\n :placeholder=\"placeholder\"\n :maxlength=\"maxlength\"\n :show-count=\"showCount\"\n :invalid=\"!!fieldErrorMessage\"\n @blur=\"onBlur\"\n @keydown.enter=\"onEnter\"\n />\n </GrFormField>\n\n <slot name=\"error\" :error=\"error\">\n <GrResponseErrorBanner v-if=\"error\" :error=\"error\" :can-dismiss=\"false\" />\n </slot>\n </div>\n\n <template #footer>\n <slot name=\"footer\">\n <div class=\"flex items-center justify-end gap-3\">\n <GrButton data-testid=\"gr-prompt-cancel\" variant=\"outline\" :size=\"buttonSize\" @click=\"onCancel\">\n {{ resolvedCancelText }}\n </GrButton>\n <GrButton\n data-testid=\"gr-prompt-confirm\"\n :variant=\"confirmVariant\"\n :tone=\"confirmTone\"\n :size=\"buttonSize\"\n :loading=\"confirmLoading || validating\"\n :disabled=\"confirmDisabled || (touched && !canConfirm)\"\n @click=\"onConfirm\"\n >\n {{ resolvedConfirmText }}\n </GrButton>\n </div>\n </slot>\n </template>\n </GrDialog>\n</template>\n","<script setup lang=\"ts\">\n/**\n * GrPromptDialog — GR-примитив диалога ввода значения поверх `GrDialog`.\n *\n * Синхронизирован с `GrDialog` по набору проп-проксирования:\n * `size`, `closeOnBackdrop`, `closeOnEsc`, `showHeader`, `showCloseButton`,\n * `headerConfig`, `footerConfig`, `bodyConfig`, `closeLabel`.\n *\n * Поведение `required=true` (по умолчанию): пустое значение подсвечивается\n * ошибкой только после первого «касания» (blur или попытка confirm),\n * чтобы не шуметь при открытии.\n *\n * Проверки сверх `required` описываются пропом `rules` — тем же движком, что и\n * у `GrForm`: третий частный случай валидации в пакете заводить незачем.\n */\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { computed, ref, watch } from 'vue'\n\nimport GrButton from '../GrButton/GrButton.vue'\nimport GrDialog from '../GrDialog/GrDialog.vue'\nimport GrFormField from '../GrFormField/GrFormField.vue'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrTextarea from '../GrTextarea/GrTextarea.vue'\nimport GrResponseErrorBanner from '../GrResponseErrorBanner/GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\n// Именованные импорты чистых функций: разметки не тянут, поэтому в\n// `config.dependencies` не объявляются (см. правило про зависимости).\nimport { createGrFormMessageResolver, rulesForTrigger, runFieldRules } from '../GrForm/validation'\nimport type { GrFormRule, GrFormTrigger } from '../GrForm/validation'\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton'\nimport type { GrDialogSectionConfig, GrDialogSize } from '../GrDialog'\n\n/**\n * Тип поля выводим из самого `GrInput`, а не заводим ему именованный алиас:\n * алиас в пропе `GrInput` заменил бы в таблице API витрины список допустимых\n * значений на своё имя — документация стала бы беднее ради удобства обёртки.\n */\ntype GrInputType = NonNullable<InstanceType<typeof GrInput>['$props']['type']>\nimport type { ResponseErrorInfo } from '../GrResponseErrorBanner'\nimport type { InputHTMLAttributes } from 'vue'\n\nexport interface GrPromptDialogProps {\n modelValue: boolean\n value: string\n title?: string\n description?: string\n label?: string\n placeholder?: string\n closeOnBackdrop?: boolean\n closeOnEsc?: boolean\n showHeader?: boolean\n showCloseButton?: boolean\n size?: GrDialogSize\n headerConfig?: GrDialogSectionConfig\n footerConfig?: GrDialogSectionConfig\n bodyConfig?: GrDialogSectionConfig\n /** A11y-лейбл кнопки закрытия (i18n). */\n closeLabel?: string\n buttonSize?: GrButtonSize\n confirmText?: string\n cancelText?: string\n /** Текст ошибки для пустого значения при `required=true` (i18n). */\n requiredErrorText?: string\n confirmVariant?: GrButtonVariant\n confirmTone?: GrButtonTone\n required?: boolean\n /** Тип однострочного поля. В многострочном режиме не применяется. */\n inputType?: GrInputType\n /** Программная клавиатура на мобильных. */\n inputmode?: InputHTMLAttributes['inputmode']\n /** Ограничение длины; со `showCount` рисуется счётчик. */\n maxlength?: number\n showCount?: boolean\n /** Многострочный ввод: вместо `GrInput` рисуется `GrTextarea`. */\n multiline?: boolean\n /** Высота многострочного поля в строках. */\n rows?: number\n /** Автоподбор высоты многострочного поля под содержимое. */\n autosize?: boolean\n /**\n * Правила проверки значения — те же, что у `GrForm` (`required`, `type`,\n * `min`/`max`/`len`, `pattern`, свой в т.ч. асинхронный `validator`).\n * Прогоняются на blur (после первого касания) и на подтверждении.\n */\n rules?: GrFormRule | GrFormRule[]\n /**\n * Структура ошибки ответа сервера для показа общим блоком в теле диалога\n * (через `GrResponseErrorBanner`). `null` — блок скрыт.\n */\n error?: ResponseErrorInfo | null\n /**\n * Внешняя ошибка поля ввода (например, серверная валидация). Имеет приоритет\n * над встроенной проверкой. `null`/`undefined` — нет внешней ошибки.\n */\n fieldError?: string | null\n /** Состояние загрузки кнопки Confirm (async-`onConfirm` in-flight). */\n confirmLoading?: boolean\n /** Принудительно дизейблит кнопку Confirm. */\n confirmDisabled?: boolean\n /**\n * Закрывать ли диалог автоматически по клику Confirm. По умолчанию `true`.\n * `false` — отдаёт управление закрытием наружу (нужно `useDialogService`).\n */\n closeOnConfirm?: boolean\n /**\n * Запрет закрытия «мягкими» способами (Esc, клик по бэкдропу), пока идёт\n * подтверждение или проверка `rules`. Кнопка закрытия и «Отмена» остаются:\n * окно без единого выхода — ловушка.\n */\n persistent?: boolean\n}\n\nexport interface GrPromptDialogEmits {\n (e: 'update:modelValue', value: boolean): void\n (e: 'update:value', value: string): void\n (e: 'confirm', value: string): void\n (e: 'cancel'): void\n}\n\nimport './defaults'\n\nconst props = withDefaults(defineProps<GrPromptDialogProps>(), {\n title: undefined,\n description: undefined,\n label: undefined,\n placeholder: undefined,\n closeOnBackdrop: true,\n closeOnEsc: true,\n showHeader: true,\n showCloseButton: true,\n // Дефолт `size` живёт в резолвере ниже, а не здесь: Vue подставил бы его\n // до того, как компонент заглянет в `GrConfigProvider`.\n size: undefined,\n headerConfig: undefined,\n footerConfig: undefined,\n bodyConfig: undefined,\n closeLabel: undefined,\n buttonSize: undefined,\n confirmText: undefined,\n cancelText: undefined,\n requiredErrorText: undefined,\n confirmVariant: 'primary',\n confirmTone: 'primary',\n required: true,\n inputType: 'text',\n inputmode: undefined,\n maxlength: undefined,\n showCount: false,\n multiline: false,\n rows: undefined,\n autosize: false,\n rules: undefined,\n error: null,\n fieldError: null,\n confirmLoading: false,\n confirmDisabled: false,\n closeOnConfirm: true,\n persistent: false,\n})\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentProp('GrPromptDialog', 'size', () => props.size, 'md')\n\nconst emit = defineEmits<GrPromptDialogEmits>()\n\n// Дефолты берём из общего i18n-блока пакета (fallback — англ.), а не хардкодим.\nconst { t } = useGranularityTranslations()\nconst resolvedTitle = computed(() => props.title ?? t('gr.dialog.prompt.title', 'Prompt'))\nconst resolvedLabel = computed(() => props.label ?? t('gr.dialog.prompt.label', 'Value'))\nconst resolvedRequiredErrorText = computed(() => props.requiredErrorText ?? t('gr.dialog.prompt.required', 'Enter a value.'))\nconst resolvedCloseLabel = computed(() => props.closeLabel ?? t('gr.common.close', 'Close'))\nconst resolvedConfirmText = computed(() => props.confirmText ?? t('gr.common.confirm', 'Confirm'))\nconst resolvedCancelText = computed(() => props.cancelText ?? t('gr.common.cancel', 'Cancel'))\n\nconst open = computed({\n get: () => props.modelValue,\n set: (v: boolean) => emit('update:modelValue', v),\n})\n\nconst valueModel = computed({\n get: () => props.value,\n set: (v: string) => emit('update:value', v),\n})\n\nconst touched = ref(false)\nconst inputRef = ref<InstanceType<typeof GrInput> | null>(null)\nconst textareaRef = ref<InstanceType<typeof GrTextarea> | null>(null)\n\n/** Ошибка последнего прогона `rules`; `required` считается отдельно и мгновенно. */\nconst ruleError = ref<string | undefined>(undefined)\nconst validating = ref(false)\n\n// Сторож устаревших прогонов: асинхронное правило может ответить после того,\n// как значение уже сменилось, и дописать чужую ошибку.\nlet validationRun = 0\n\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (!isOpen)\n return\n\n touched.value = false\n ruleError.value = undefined\n validationRun += 1\n },\n)\n\nconst resolveMessage = createGrFormMessageResolver(t)\n\nconst normalizedRules = computed<GrFormRule[]>(() => {\n if (!props.rules)\n return []\n return Array.isArray(props.rules) ? props.rules : [props.rules]\n})\n\nconst requiredError = computed(() => {\n if (!props.required)\n return undefined\n return valueModel.value.trim().length > 0 ? undefined : resolvedRequiredErrorText.value\n})\n\nconst canConfirm = computed(() => !requiredError.value)\n\nconst validationError = computed(() => {\n if (!touched.value)\n return undefined\n return requiredError.value ?? ruleError.value\n})\n\n// Внешняя ошибка поля (серверная валидация) имеет приоритет над встроенной.\nconst fieldErrorMessage = computed(() => props.fieldError ?? validationError.value ?? undefined)\n\n/**\n * Прогоняет `rules` для триггера. Возвращает сообщение или `undefined`.\n * `required` здесь не участвует: он синхронный и считается отдельно, чтобы\n * пустое поле блокировало кнопку без похода в асинхронный движок.\n */\nasync function runRules(trigger: GrFormTrigger): Promise<string | undefined> {\n const rules = rulesForTrigger(normalizedRules.value, trigger)\n if (!rules.length)\n return undefined\n\n const run = ++validationRun\n validating.value = true\n try {\n const message = await runFieldRules(valueModel.value, rules, { value: valueModel.value }, resolveMessage)\n // Ответ устарел — значение или сам диалог успели смениться.\n if (run !== validationRun)\n return undefined\n\n ruleError.value = message\n return message\n }\n finally {\n if (run === validationRun)\n validating.value = false\n }\n}\n\nfunction onBlur(): void {\n touched.value = true\n void runRules('blur')\n}\n\n// Пока подтверждение или проверка в полёте, случайное движение не должно\n// оборвать операцию.\nconst softCloseBlocked = computed(() => props.persistent && (props.confirmLoading || validating.value))\nconst resolvedCloseOnBackdrop = computed(() => (softCloseBlocked.value ? false : props.closeOnBackdrop))\nconst resolvedCloseOnEsc = computed(() => (softCloseBlocked.value ? false : props.closeOnEsc))\n\nfunction onCancel(): void {\n emit('cancel')\n emit('update:modelValue', false)\n}\n\nfunction focusField(): void {\n if (props.multiline)\n textareaRef.value?.focus()\n else inputRef.value?.focus()\n}\n\nasync function onConfirm(): Promise<void> {\n touched.value = true\n\n if (!canConfirm.value) {\n focusField()\n return\n }\n\n if (await runRules('submit')) {\n focusField()\n return\n }\n\n emit('confirm', valueModel.value)\n if (props.closeOnConfirm)\n emit('update:modelValue', false)\n}\n\n/**\n * `Enter` подтверждает — базовое ожидание от окна, единственный смысл которого\n * ввести одно значение. В многострочном режиме `Enter` остаётся переводом\n * строки, поэтому обработчик висит только на однострочном поле.\n */\nfunction onEnter(): void {\n void onConfirm()\n}\n\n// Фокус в поле, а не на панель: диалог существует ровно ради ввода.\n//\n// Через `initialFocus` у `GrModal` это не решается: элемент рождается внутри\n// поддерева диалога, и возврат его же пропом наверх замыкает рендер в цикл\n// («Maximum recursive updates» — проверено). Поэтому фокус ставит содержимое,\n// после отрисовки (`flush: 'post'` + кадр), то есть заведомо позже, чем\n// ловушка фокуса `GrModal` переводит фокус на панель.\n// Источник — не только `modelValue`, но и само поле: содержимое панели\n// появляется на такт позже открытия, и фокус по фиксированному `nextTick`\n// приходился на момент, когда фокусировать ещё нечего.\nwatch(\n [() => props.modelValue, inputRef, textareaRef],\n () => {\n if (!props.modelValue)\n return\n focusField()\n },\n // `immediate`: окно могут смонтировать уже открытым — тогда смены пропа не\n // будет вовсе, и без этого фокус остался бы на панели.\n { immediate: true, flush: 'post' },\n)\n\ndefineSlots<{\n /** Содержимое диалога вместо пропа `message`. */\n default?: () => any\n /** Разбор ошибки вместо встроенного баннера. */\n error?: (props: { error: ResponseErrorInfo | null }) => any\n /** Кнопки диалога вместо пары «отмена и подтверждение». */\n footer?: () => any\n}>()\n</script>\n\n<template>\n <GrDialog\n v-model=\"open\"\n :title=\"resolvedTitle\"\n :size=\"resolvedSize\"\n :close-on-backdrop=\"resolvedCloseOnBackdrop\"\n :close-on-esc=\"resolvedCloseOnEsc\"\n :show-header=\"showHeader\"\n :show-close-button=\"showCloseButton\"\n :header-config=\"headerConfig\"\n :footer-config=\"footerConfig\"\n :body-config=\"bodyConfig\"\n :close-label=\"resolvedCloseLabel\"\n >\n <div class=\"grid gap-4\">\n <slot>\n <div v-if=\"description\" class=\"text-[length:var(--gr-control-text-md)] leading-[var(--gr-control-leading-md)] text-[var(--gr-muted-fg)]\">\n {{ description }}\n </div>\n </slot>\n\n <!-- `id` полю не задаём: `GrFormField` генерирует его сам, а поле читает\n из контекста. Литеральный id ломал два открытых диалога сразу. -->\n <GrFormField :label=\"resolvedLabel\" :error=\"fieldErrorMessage\">\n <GrTextarea\n v-if=\"multiline\"\n ref=\"textareaRef\"\n v-model=\"valueModel\"\n data-testid=\"gr-prompt-input\"\n :placeholder=\"placeholder\"\n :rows=\"rows\"\n :autosize=\"autosize\"\n :maxlength=\"maxlength\"\n :show-count=\"showCount\"\n :invalid=\"!!fieldErrorMessage\"\n @blur=\"onBlur\"\n />\n <GrInput\n v-else\n ref=\"inputRef\"\n v-model=\"valueModel\"\n data-testid=\"gr-prompt-input\"\n :type=\"inputType\"\n :inputmode=\"inputmode\"\n :placeholder=\"placeholder\"\n :maxlength=\"maxlength\"\n :show-count=\"showCount\"\n :invalid=\"!!fieldErrorMessage\"\n @blur=\"onBlur\"\n @keydown.enter=\"onEnter\"\n />\n </GrFormField>\n\n <slot name=\"error\" :error=\"error\">\n <GrResponseErrorBanner v-if=\"error\" :error=\"error\" :can-dismiss=\"false\" />\n </slot>\n </div>\n\n <template #footer>\n <slot name=\"footer\">\n <div class=\"flex items-center justify-end gap-3\">\n <GrButton data-testid=\"gr-prompt-cancel\" variant=\"outline\" :size=\"buttonSize\" @click=\"onCancel\">\n {{ resolvedCancelText }}\n </GrButton>\n <GrButton\n data-testid=\"gr-prompt-confirm\"\n :variant=\"confirmVariant\"\n :tone=\"confirmTone\"\n :size=\"buttonSize\"\n :loading=\"confirmLoading || validating\"\n :disabled=\"confirmDisabled || (touched && !canConfirm)\"\n @click=\"onConfirm\"\n >\n {{ resolvedConfirmText }}\n </GrButton>\n </div>\n </slot>\n </template>\n </GrDialog>\n</template>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrPromptDialog_default } from "./chunks/GrPromptDialog-DLcl1xiq.js";
1
+ import { t as GrPromptDialog_default } from "./chunks/GrPromptDialog-BuJQMZLM.js";
2
2
  import { t as grPromptDialogConfig } from "../../chunks/config-C0Ea9ePP.js";
3
3
  export { GrPromptDialog_default as GrPromptDialog, GrPromptDialog_default as default, grPromptDialogConfig };
@@ -1,5 +1,5 @@
1
1
  import { a as useGrComponentSize } from "../../../chunks/context-CTbuwcYs.js";
2
- import { S as grRadioRootClass, a as grRadioControlClass, d as grRadioDotBaseClass, h as grRadioDotSizes, p as grRadioDotClass, t as grRadioButtonClass, u as grRadioDescriptionSizes, y as grRadioLabelClassFor } from "../../../chunks/grRadioStyles-D4gnU65n.js";
2
+ import { S as grRadioRootClass, a as grRadioControlClass, d as grRadioDotBaseClass, h as grRadioDotSizes, p as grRadioDotClass, t as grRadioButtonClass, u as grRadioDescriptionSizes, y as grRadioLabelClassFor } from "../../../chunks/grRadioStyles-DGL2QLy6.js";
3
3
  import { computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, inject, normalizeClass, onUnmounted, openBlock, ref, renderSlot, unref, useId, useSlots, withKeys, withModifiers } from "vue";
4
4
  //#region src/components/GrRadio/grRadioGroupContext.ts
5
5
  var GR_RADIO_GROUP_CONTEXT = Symbol("GR_RADIO_GROUP_CONTEXT");
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrRadio-Aq3v8XgG.js","names":[],"sources":["../../../../src/components/GrRadio/grRadioGroupContext.ts","../../../../src/components/GrRadio/GrRadio.vue","../../../../src/components/GrRadio/GrRadio.vue"],"sourcesContent":["import type { ComputedRef, InjectionKey } from 'vue'\n\nimport type { GrButtonSize } from '../GrButton/grButtonStyles'\n\n/**\n * Значение переключателя. Не только строка: перечисления в реальных формах —\n * это id числом или флаг. Объекты сюда намеренно не входят: значение уходит в\n * `data-value` и в скрытый input нативной формы, а значит должно иметь\n * однозначное строковое представление.\n */\nexport type GrRadioValue = string | number | boolean\n\nexport type GrRadioEntry = {\n value: () => GrRadioValue\n disabled: () => boolean\n /**\n * Корневой узел переключателя. Геттер, а не значение: регистрация идёт в\n * `setup`, когда элемента ещё нет. Благодаря ему группа переносит фокус, не\n * обходя DOM селекторами.\n */\n el: () => HTMLElement | null\n}\n\nexport type GrRadioGroupContext = {\n modelValue: ComputedRef<GrRadioValue>\n name: ComputedRef<string | undefined>\n disabled: ComputedRef<boolean>\n /**\n * Только для чтения: выбор видно, но он не меняется. У роли `radio` нет\n * `aria-readonly` — состояние объявляет сама группа, переключателю остаётся\n * не прикидываться кликабельным.\n */\n readonly: ComputedRef<boolean>\n /** Ошибка группы: до вида переключателя она доходит только через контекст. */\n invalid: ComputedRef<boolean>\n size: ComputedRef<GrButtonSize>\n setValue: (value: GrRadioValue) => void\n /**\n * Регистрация переключателя в группе. Порядок регистрации совпадает с\n * порядком в документе (setup детей идёт сверху вниз), поэтому группа знает\n * состав и в slot-режиме, и на сервере — без обхода DOM.\n */\n register: (entry: GrRadioEntry) => () => void\n /**\n * Значение переключателя, который держит `tabindex=\"0\"`. Roving tabindex\n * WAI-ARIA: группа — одна остановка Tab, внутрь попадают стрелками. Если не\n * выбрано ничего, остановкой становится первый доступный переключатель.\n */\n rovingValue: ComputedRef<GrRadioValue | undefined>\n /**\n * Стрелки, `Home`, `End`: переносят выбор и фокус на соседний доступный\n * переключатель. Вернул `true` — клавиша обработана (с `preventDefault`).\n * Кольцо ведёт группа, а не переключатель: только она знает состав.\n */\n handleNavigationKeys: (event: KeyboardEvent) => boolean\n}\n\nexport const GR_RADIO_GROUP_CONTEXT: InjectionKey<GrRadioGroupContext> = Symbol('GR_RADIO_GROUP_CONTEXT')\n","<script setup lang=\"ts\">\nimport { computed, inject, onUnmounted, ref, useId, useSlots } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\n\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton'\n\nimport {\n grRadioButtonClass,\n grRadioControlClass,\n grRadioDescriptionSizes,\n grRadioDotBaseClass,\n grRadioDotClass,\n grRadioDotSizes,\n grRadioLabelClassFor,\n grRadioRootClass,\n type GrRadioVariant,\n} from './grRadioStyles'\nimport { GR_RADIO_GROUP_CONTEXT, type GrRadioValue } from './grRadioGroupContext'\n\nexport type { GrRadioValue } from './grRadioGroupContext'\n\n/**\n * GrRadio — одиночный элемент группы выбора.\n *\n * Может работать автономно (через `v-model`) либо внутри `GrRadioGroup`\n * (тогда `modelValue`/`disabled`/`size`/`name`/`invalid` приходят через `inject`).\n *\n * @prop value — значение этого элемента, сравнивается с `modelValue` группы.\n * @prop variant — визуальное представление: `radiobox` (круг+dot) или `button` (стиль `GrButton`).\n *\n * Доступным контролом является сам элемент с `role=\"radio\"`: он держит фокус,\n * `aria-checked` и клавиатуру. Внутрь него ничего интерактивного не вкладывается —\n * `role=\"radio\"` объявляет потомков презентационными, и вложенный native `<input>`\n * (даже скрытый и с `tabindex=\"-1\"`) ломает виджет для скринридеров и падает\n * в axe на `nested-interactive`. Для отправки нативной формой рядом рендерится\n * `input[type=\"hidden\"]` — он не фокусируется и не является интерактивным.\n */\nexport interface GrRadioProps {\n value: GrRadioValue\n modelValue?: GrRadioValue\n disabled?: boolean\n /** Визуальное и ARIA-состояние ошибки. Складывается с `invalid` группы. */\n invalid?: boolean\n name?: string\n required?: boolean\n form?: string\n id?: string\n size?: GrButtonSize\n variant?: GrRadioVariant\n buttonVariant?: GrButtonVariant\n buttonTone?: GrButtonTone\n selectedButtonVariant?: GrButtonVariant\n selectedButtonTone?: GrButtonTone\n ariaLabel?: string\n}\n\nexport interface GrRadioEmits {\n (e: 'update:modelValue', value: GrRadioValue): void\n}\n\nconst props = withDefaults(defineProps<GrRadioProps>(), {\n modelValue: undefined,\n disabled: undefined,\n invalid: false,\n name: undefined,\n required: false,\n form: undefined,\n id: undefined,\n size: undefined,\n variant: 'radiobox',\n buttonVariant: 'outline',\n buttonTone: 'neutral',\n selectedButtonVariant: 'primary',\n selectedButtonTone: 'primary',\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrRadioEmits>()\n\nconst slots = useSlots()\nconst group = inject(GR_RADIO_GROUP_CONTEXT, null)\n\nconst resolvedModelValue = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n return group?.modelValue.value ?? ''\n})\n\nconst resolvedDisabled = computed(() => {\n if (props.disabled !== undefined)\n return props.disabled\n\n return group?.disabled.value ?? false\n})\n\nconst resolvedReadonly = computed(() => group?.readonly.value ?? false)\n\n// «Или», а не `??`: ошибку может объявить и группа, и сам переключатель.\nconst resolvedInvalid = computed(() => props.invalid || (group?.invalid.value ?? false))\n\nconst resolvedName = computed(() => {\n if (props.name)\n return props.name\n\n return group?.name.value\n})\n\n// Приоритет: локальный проп → размер группы → `GrConfigProvider` → `md`.\n// Группа специфичнее конфига, поэтому её значение подаётся как «локальное».\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrRadio' },\n)\n\nconst checked = computed(() => resolvedModelValue.value === props.value)\n\n/** В DOM значение живёт строкой: `data-value` и скрытый input иначе не умеют. */\nconst domValue = computed(() => String(props.value))\n\n// Нативная форма получает значение только от выбранного и не-disabled элемента —\n// ровно как поступил бы native radio. Без `name` отправлять нечего.\nconst submitsValue = computed(\n () => checked.value && !resolvedDisabled.value && Boolean(resolvedName.value),\n)\n\nconst descriptionId = useId()\nconst hasDescription = computed(() => Boolean(slots.description))\n\nconst buttonClassName = computed(() => {\n return grRadioButtonClass({\n checked: checked.value,\n disabled: resolvedDisabled.value,\n readonly: resolvedReadonly.value,\n size: resolvedSize.value,\n buttonVariant: props.buttonVariant,\n buttonTone: props.buttonTone,\n selectedButtonVariant: props.selectedButtonVariant,\n selectedButtonTone: props.selectedButtonTone,\n })\n})\n\nconst rootClassName = computed(() => grRadioRootClass({\n disabled: resolvedDisabled.value,\n readonly: resolvedReadonly.value,\n}))\nconst controlClassName = computed(() => grRadioControlClass({\n size: resolvedSize.value,\n checked: checked.value,\n disabled: resolvedDisabled.value,\n invalid: resolvedInvalid.value,\n}))\nconst dotClassName = computed(() => grRadioDotClass({\n checked: checked.value,\n disabled: resolvedDisabled.value,\n}))\nconst labelClassName = computed(() => grRadioLabelClassFor(resolvedSize.value, checked.value))\nconst dotSizeClassName = computed(() => grRadioDotSizes[resolvedSize.value])\nconst descriptionClassName = computed(() => grRadioDescriptionSizes[resolvedSize.value])\n\nfunction setValue(next: GrRadioValue): void {\n if (resolvedDisabled.value)\n return\n\n if (props.modelValue !== undefined) {\n emit('update:modelValue', next)\n return\n }\n\n group?.setValue(next)\n}\n\nfunction onButtonClick(): void {\n setValue(props.value)\n}\n\n// Паттерн radiogroup: группа — одна остановка Tab, внутрь попадают стрелками.\n// Вне группы (одиночный `GrRadio`) переключатель остаётся обычной остановкой.\nconst rovingTabindex = computed(() => {\n if (resolvedDisabled.value)\n return -1\n if (!group)\n return 0\n return group.rovingValue.value === props.value ? 0 : -1\n})\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n/** Кольцо ведёт группа: только она знает состав и порядок. */\nfunction onKeydown(event: KeyboardEvent): void {\n if (!group || resolvedDisabled.value)\n return\n\n group.handleNavigationKeys(event)\n}\n\nconst unregister = group?.register({\n value: () => props.value,\n disabled: () => resolvedDisabled.value,\n el: () => rootEl.value,\n})\n\nonUnmounted(() => unregister?.())\n\ndefineSlots<{\n /** Подпись переключателя вместо пропа `label`. */\n default?: () => any\n /** Пояснение под подписью. */\n description?: () => any\n}>()\n</script>\n\n<template>\n <div\n v-if=\"variant === 'button'\"\n :id=\"id\"\n ref=\"rootEl\"\n data-gr-button\n data-gr-radio\n role=\"radio\"\n :aria-checked=\"checked ? 'true' : 'false'\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-invalid=\"resolvedInvalid ? 'true' : undefined\"\n :aria-required=\"required ? 'true' : undefined\"\n :data-value=\"domValue\"\n :tabindex=\"rovingTabindex\"\n :class=\"buttonClassName\"\n @click=\"onButtonClick\"\n @keydown.space.prevent=\"onButtonClick\"\n @keydown.enter.prevent=\"onButtonClick\"\n @keydown=\"onKeydown\"\n >\n <input\n v-if=\"submitsValue\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"domValue\"\n :form=\"form\"\n >\n\n <slot />\n </div>\n\n <div\n v-else\n :id=\"id\"\n ref=\"rootEl\"\n data-gr-radio\n role=\"radio\"\n :aria-checked=\"checked ? 'true' : 'false'\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-invalid=\"resolvedInvalid ? 'true' : undefined\"\n :aria-required=\"required ? 'true' : undefined\"\n :aria-describedby=\"hasDescription ? descriptionId : undefined\"\n :data-value=\"domValue\"\n :tabindex=\"rovingTabindex\"\n class=\"inline-flex items-start gap-2 select-none focus-visible:outline-none focus-visible:rounded-[var(--gr-radius-md)] focus-visible:shadow-[0_0_0_2px_var(--gr-ring),0_0_0_4px_var(--gr-bg)]\"\n :class=\"rootClassName\"\n @click=\"onButtonClick\"\n @keydown.space.prevent=\"onButtonClick\"\n @keydown.enter.prevent=\"onButtonClick\"\n @keydown=\"onKeydown\"\n >\n <input\n v-if=\"submitsValue\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"domValue\"\n :form=\"form\"\n >\n\n <span\n data-gr-radio-control\n aria-hidden=\"true\"\n class=\"mt-0.5 shrink-0 rounded-[var(--gr-radius-full)] border flex items-center justify-center transition-colors duration-[var(--gr-duration-fast)]\"\n :class=\"controlClassName\"\n >\n <span\n data-gr-radio-dot\n :class=\"[grRadioDotBaseClass, dotSizeClassName, dotClassName]\"\n />\n </span>\n\n <span class=\"grid gap-0.5\">\n <span data-gr-radio-label :class=\"labelClassName\">\n <slot />\n </span>\n\n <span\n v-if=\"hasDescription\"\n :id=\"descriptionId\"\n data-gr-radio-description\n :class=\"descriptionClassName\"\n >\n <slot name=\"description\" />\n </span>\n </span>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, onUnmounted, ref, useId, useSlots } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\n\nimport type { GrButtonSize, GrButtonTone, GrButtonVariant } from '../GrButton'\n\nimport {\n grRadioButtonClass,\n grRadioControlClass,\n grRadioDescriptionSizes,\n grRadioDotBaseClass,\n grRadioDotClass,\n grRadioDotSizes,\n grRadioLabelClassFor,\n grRadioRootClass,\n type GrRadioVariant,\n} from './grRadioStyles'\nimport { GR_RADIO_GROUP_CONTEXT, type GrRadioValue } from './grRadioGroupContext'\n\nexport type { GrRadioValue } from './grRadioGroupContext'\n\n/**\n * GrRadio — одиночный элемент группы выбора.\n *\n * Может работать автономно (через `v-model`) либо внутри `GrRadioGroup`\n * (тогда `modelValue`/`disabled`/`size`/`name`/`invalid` приходят через `inject`).\n *\n * @prop value — значение этого элемента, сравнивается с `modelValue` группы.\n * @prop variant — визуальное представление: `radiobox` (круг+dot) или `button` (стиль `GrButton`).\n *\n * Доступным контролом является сам элемент с `role=\"radio\"`: он держит фокус,\n * `aria-checked` и клавиатуру. Внутрь него ничего интерактивного не вкладывается —\n * `role=\"radio\"` объявляет потомков презентационными, и вложенный native `<input>`\n * (даже скрытый и с `tabindex=\"-1\"`) ломает виджет для скринридеров и падает\n * в axe на `nested-interactive`. Для отправки нативной формой рядом рендерится\n * `input[type=\"hidden\"]` — он не фокусируется и не является интерактивным.\n */\nexport interface GrRadioProps {\n value: GrRadioValue\n modelValue?: GrRadioValue\n disabled?: boolean\n /** Визуальное и ARIA-состояние ошибки. Складывается с `invalid` группы. */\n invalid?: boolean\n name?: string\n required?: boolean\n form?: string\n id?: string\n size?: GrButtonSize\n variant?: GrRadioVariant\n buttonVariant?: GrButtonVariant\n buttonTone?: GrButtonTone\n selectedButtonVariant?: GrButtonVariant\n selectedButtonTone?: GrButtonTone\n ariaLabel?: string\n}\n\nexport interface GrRadioEmits {\n (e: 'update:modelValue', value: GrRadioValue): void\n}\n\nconst props = withDefaults(defineProps<GrRadioProps>(), {\n modelValue: undefined,\n disabled: undefined,\n invalid: false,\n name: undefined,\n required: false,\n form: undefined,\n id: undefined,\n size: undefined,\n variant: 'radiobox',\n buttonVariant: 'outline',\n buttonTone: 'neutral',\n selectedButtonVariant: 'primary',\n selectedButtonTone: 'primary',\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrRadioEmits>()\n\nconst slots = useSlots()\nconst group = inject(GR_RADIO_GROUP_CONTEXT, null)\n\nconst resolvedModelValue = computed(() => {\n if (props.modelValue !== undefined)\n return props.modelValue\n\n return group?.modelValue.value ?? ''\n})\n\nconst resolvedDisabled = computed(() => {\n if (props.disabled !== undefined)\n return props.disabled\n\n return group?.disabled.value ?? false\n})\n\nconst resolvedReadonly = computed(() => group?.readonly.value ?? false)\n\n// «Или», а не `??`: ошибку может объявить и группа, и сам переключатель.\nconst resolvedInvalid = computed(() => props.invalid || (group?.invalid.value ?? false))\n\nconst resolvedName = computed(() => {\n if (props.name)\n return props.name\n\n return group?.name.value\n})\n\n// Приоритет: локальный проп → размер группы → `GrConfigProvider` → `md`.\n// Группа специфичнее конфига, поэтому её значение подаётся как «локальное».\nconst resolvedSize = useGrComponentSize(\n () => props.size ?? group?.size.value,\n { component: 'GrRadio' },\n)\n\nconst checked = computed(() => resolvedModelValue.value === props.value)\n\n/** В DOM значение живёт строкой: `data-value` и скрытый input иначе не умеют. */\nconst domValue = computed(() => String(props.value))\n\n// Нативная форма получает значение только от выбранного и не-disabled элемента —\n// ровно как поступил бы native radio. Без `name` отправлять нечего.\nconst submitsValue = computed(\n () => checked.value && !resolvedDisabled.value && Boolean(resolvedName.value),\n)\n\nconst descriptionId = useId()\nconst hasDescription = computed(() => Boolean(slots.description))\n\nconst buttonClassName = computed(() => {\n return grRadioButtonClass({\n checked: checked.value,\n disabled: resolvedDisabled.value,\n readonly: resolvedReadonly.value,\n size: resolvedSize.value,\n buttonVariant: props.buttonVariant,\n buttonTone: props.buttonTone,\n selectedButtonVariant: props.selectedButtonVariant,\n selectedButtonTone: props.selectedButtonTone,\n })\n})\n\nconst rootClassName = computed(() => grRadioRootClass({\n disabled: resolvedDisabled.value,\n readonly: resolvedReadonly.value,\n}))\nconst controlClassName = computed(() => grRadioControlClass({\n size: resolvedSize.value,\n checked: checked.value,\n disabled: resolvedDisabled.value,\n invalid: resolvedInvalid.value,\n}))\nconst dotClassName = computed(() => grRadioDotClass({\n checked: checked.value,\n disabled: resolvedDisabled.value,\n}))\nconst labelClassName = computed(() => grRadioLabelClassFor(resolvedSize.value, checked.value))\nconst dotSizeClassName = computed(() => grRadioDotSizes[resolvedSize.value])\nconst descriptionClassName = computed(() => grRadioDescriptionSizes[resolvedSize.value])\n\nfunction setValue(next: GrRadioValue): void {\n if (resolvedDisabled.value)\n return\n\n if (props.modelValue !== undefined) {\n emit('update:modelValue', next)\n return\n }\n\n group?.setValue(next)\n}\n\nfunction onButtonClick(): void {\n setValue(props.value)\n}\n\n// Паттерн radiogroup: группа — одна остановка Tab, внутрь попадают стрелками.\n// Вне группы (одиночный `GrRadio`) переключатель остаётся обычной остановкой.\nconst rovingTabindex = computed(() => {\n if (resolvedDisabled.value)\n return -1\n if (!group)\n return 0\n return group.rovingValue.value === props.value ? 0 : -1\n})\n\nconst rootEl = ref<HTMLElement | null>(null)\n\n/** Кольцо ведёт группа: только она знает состав и порядок. */\nfunction onKeydown(event: KeyboardEvent): void {\n if (!group || resolvedDisabled.value)\n return\n\n group.handleNavigationKeys(event)\n}\n\nconst unregister = group?.register({\n value: () => props.value,\n disabled: () => resolvedDisabled.value,\n el: () => rootEl.value,\n})\n\nonUnmounted(() => unregister?.())\n\ndefineSlots<{\n /** Подпись переключателя вместо пропа `label`. */\n default?: () => any\n /** Пояснение под подписью. */\n description?: () => any\n}>()\n</script>\n\n<template>\n <div\n v-if=\"variant === 'button'\"\n :id=\"id\"\n ref=\"rootEl\"\n data-gr-button\n data-gr-radio\n role=\"radio\"\n :aria-checked=\"checked ? 'true' : 'false'\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-invalid=\"resolvedInvalid ? 'true' : undefined\"\n :aria-required=\"required ? 'true' : undefined\"\n :data-value=\"domValue\"\n :tabindex=\"rovingTabindex\"\n :class=\"buttonClassName\"\n @click=\"onButtonClick\"\n @keydown.space.prevent=\"onButtonClick\"\n @keydown.enter.prevent=\"onButtonClick\"\n @keydown=\"onKeydown\"\n >\n <input\n v-if=\"submitsValue\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"domValue\"\n :form=\"form\"\n >\n\n <slot />\n </div>\n\n <div\n v-else\n :id=\"id\"\n ref=\"rootEl\"\n data-gr-radio\n role=\"radio\"\n :aria-checked=\"checked ? 'true' : 'false'\"\n :aria-label=\"ariaLabel\"\n :aria-disabled=\"resolvedDisabled ? 'true' : undefined\"\n :aria-invalid=\"resolvedInvalid ? 'true' : undefined\"\n :aria-required=\"required ? 'true' : undefined\"\n :aria-describedby=\"hasDescription ? descriptionId : undefined\"\n :data-value=\"domValue\"\n :tabindex=\"rovingTabindex\"\n class=\"inline-flex items-start gap-2 select-none focus-visible:outline-none focus-visible:rounded-[var(--gr-radius-md)] focus-visible:shadow-[0_0_0_2px_var(--gr-ring),0_0_0_4px_var(--gr-bg)]\"\n :class=\"rootClassName\"\n @click=\"onButtonClick\"\n @keydown.space.prevent=\"onButtonClick\"\n @keydown.enter.prevent=\"onButtonClick\"\n @keydown=\"onKeydown\"\n >\n <input\n v-if=\"submitsValue\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"domValue\"\n :form=\"form\"\n >\n\n <span\n data-gr-radio-control\n aria-hidden=\"true\"\n class=\"mt-0.5 shrink-0 rounded-[var(--gr-radius-full)] border flex items-center justify-center transition-colors duration-[var(--gr-duration-fast)]\"\n :class=\"controlClassName\"\n >\n <span\n data-gr-radio-dot\n :class=\"[grRadioDotBaseClass, dotSizeClassName, dotClassName]\"\n />\n </span>\n\n <span class=\"grid gap-0.5\">\n <span data-gr-radio-label :class=\"labelClassName\">\n <slot />\n </span>\n\n <span\n v-if=\"hasDescription\"\n :id=\"descriptionId\"\n data-gr-radio-description\n :class=\"descriptionClassName\"\n >\n <slot name=\"description\" />\n </span>\n </span>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrRadio_default } from "./chunks/GrRadio-C_rESc5g.js";
2
- import { n as grRadioSafelist, t as grRadioConfig } from "../../chunks/config-jyr6AIZt2.js";
1
+ import { t as GrRadio_default } from "./chunks/GrRadio-Aq3v8XgG.js";
2
+ import { n as grRadioSafelist, t as grRadioConfig } from "../../chunks/config-CuQmUkMw2.js";
3
3
  export { GrRadio_default as GrRadio, GrRadio_default as default, grRadioConfig, grRadioSafelist };
@@ -4,7 +4,7 @@ import { useGrFormControl } from "../../../composables/useGrFormControl.js";
4
4
  import { t as useFocusWithin } from "../../../chunks/useFocusWithin-BwHE0rzm.js";
5
5
  import { useRovingFocus } from "../../../composables/useRovingFocus.js";
6
6
  import { t as GrButtonGroup_default } from "../../GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js";
7
- import { n as GR_RADIO_GROUP_CONTEXT, t as GrRadio_default } from "../../GrRadio/chunks/GrRadio-C_rESc5g.js";
7
+ import { n as GR_RADIO_GROUP_CONTEXT, t as GrRadio_default } from "../../GrRadio/chunks/GrRadio-Aq3v8XgG.js";
8
8
  import { Fragment, computed, createBlock, createElementBlock, createSlots, createTextVNode, defineComponent, nextTick, normalizeClass, openBlock, provide, ref, renderList, renderSlot, toDisplayString, unref, withCtx } from "vue";
9
9
  //#region src/components/GrRadioGroup/GrRadioGroup.vue?vue&type=script&setup=true&lang.ts
10
10
  var _hoisted_1 = [