@feugene/granularity 0.35.0 → 0.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (377) hide show
  1. package/dist/chunks/config-2ZHRsdOc.js.map +1 -1
  2. package/dist/chunks/config-2vrOFn2f.js.map +1 -1
  3. package/dist/chunks/config-3bQeQvqd.js.map +1 -1
  4. package/dist/chunks/config-87fszqnD.js.map +1 -1
  5. package/dist/chunks/config-8Pcutu1j.js.map +1 -1
  6. package/dist/chunks/config-A-bBiotF.js.map +1 -1
  7. package/dist/chunks/config-B0uvcTPH.js.map +1 -1
  8. package/dist/chunks/config-B3J0alyY.js.map +1 -1
  9. package/dist/chunks/config-B5SBUa6u.js.map +1 -1
  10. package/dist/chunks/config-B7W9VlZ7.js.map +1 -1
  11. package/dist/chunks/config-BDSaD-5p.js.map +1 -1
  12. package/dist/chunks/config-BEO7brpO.js.map +1 -1
  13. package/dist/chunks/config-BNu8lFQB.js.map +1 -1
  14. package/dist/chunks/config-BRESvs9g.js.map +1 -1
  15. package/dist/chunks/config-BTmfQFwi.js.map +1 -1
  16. package/dist/chunks/{config-CuQmUkMw2.js → config-BUNxHnEz.js} +1 -1
  17. package/dist/chunks/config-BUNxHnEz.js.map +1 -0
  18. package/dist/chunks/config-BaWANzzB.js.map +1 -1
  19. package/dist/chunks/config-BcXX7S7B.js.map +1 -1
  20. package/dist/chunks/config-Bd7QfiGj.js.map +1 -1
  21. package/dist/chunks/config-BhfNgyWL.js.map +1 -1
  22. package/dist/chunks/config-Bjn30smH.js.map +1 -1
  23. package/dist/chunks/config-BlJa1Mj9.js.map +1 -1
  24. package/dist/chunks/config-BoUI0t-t.js.map +1 -1
  25. package/dist/chunks/config-BqT6PMzO.js.map +1 -1
  26. package/dist/chunks/config-BscVxZR3.js.map +1 -1
  27. package/dist/chunks/config-BuGlNPE9.js.map +1 -1
  28. package/dist/chunks/config-C0Ea9ePP.js.map +1 -1
  29. package/dist/chunks/config-C0Eu8jpG.js.map +1 -1
  30. package/dist/chunks/config-CDat1wXf.js.map +1 -1
  31. package/dist/chunks/config-CIkdsWUk.js.map +1 -1
  32. package/dist/chunks/config-CJzmDHfI.js.map +1 -1
  33. package/dist/chunks/config-CLjjjPZj.js.map +1 -1
  34. package/dist/chunks/config-CMNfZO7S.js.map +1 -1
  35. package/dist/chunks/config-CQLNjc9X.js.map +1 -0
  36. package/dist/chunks/config-CT4lP6S4.js.map +1 -1
  37. package/dist/chunks/config-CWtfxkM9.js.map +1 -1
  38. package/dist/chunks/config-CYthTVK2.js.map +1 -1
  39. package/dist/chunks/config-CZPDPJlg.js.map +1 -1
  40. package/dist/chunks/config-CbEbLyDE.js.map +1 -1
  41. package/dist/chunks/config-ChPg-BQv.js.map +1 -1
  42. package/dist/chunks/config-CjKpUcmy.js.map +1 -1
  43. package/dist/chunks/config-CjWOTgLL.js.map +1 -1
  44. package/dist/chunks/config-CjXjhphs.js.map +1 -1
  45. package/dist/chunks/config-CnYdE3HZ.js.map +1 -0
  46. package/dist/chunks/config-CsCUuukB.js.map +1 -1
  47. package/dist/chunks/config-CvbVM4ep.js.map +1 -1
  48. package/dist/chunks/config-D0NzGYaE.js.map +1 -1
  49. package/dist/chunks/config-D0W8mGFD.js.map +1 -1
  50. package/dist/chunks/config-D82r782v.js.map +1 -1
  51. package/dist/chunks/{config-mlheIMtV.js → config-DBi0GVce.js} +2 -2
  52. package/dist/chunks/config-DBi0GVce.js.map +1 -0
  53. package/dist/chunks/config-DBmdgoVf.js.map +1 -0
  54. package/dist/chunks/config-DCq4JySZ.js.map +1 -1
  55. package/dist/chunks/config-DGC00bTp.js.map +1 -1
  56. package/dist/chunks/config-DIDz_E5m.js.map +1 -1
  57. package/dist/chunks/config-DM0lsduD.js.map +1 -1
  58. package/dist/chunks/config-DNDgp9bB.js.map +1 -1
  59. package/dist/chunks/config-DOYz_SVK.js.map +1 -1
  60. package/dist/chunks/config-DRbojEzO.js.map +1 -1
  61. package/dist/chunks/config-DUNH02Fg.js.map +1 -1
  62. package/dist/chunks/config-DUbbGcfw.js.map +1 -1
  63. package/dist/chunks/config-DVCNvhIG.js.map +1 -0
  64. package/dist/chunks/config-DWL81-aM.js.map +1 -1
  65. package/dist/chunks/config-DZCUPHPU.js.map +1 -1
  66. package/dist/chunks/config-DeyT9dJl.js.map +1 -1
  67. package/dist/chunks/config-DolULhjJ.js.map +1 -1
  68. package/dist/chunks/config-DpAYidyY.js.map +1 -0
  69. package/dist/chunks/config-Droqn55j.js.map +1 -1
  70. package/dist/chunks/config-DwABJHEo.js.map +1 -1
  71. package/dist/chunks/config-E1cTyRVV.js.map +1 -1
  72. package/dist/chunks/config-MmPym-Z7.js.map +1 -0
  73. package/dist/chunks/config-QaIc_gRa.js.map +1 -1
  74. package/dist/chunks/config-Yy67uWHY.js.map +1 -1
  75. package/dist/chunks/config-Z5LeUXys.js.map +1 -1
  76. package/dist/chunks/config-_jbgsFpw.js.map +1 -1
  77. package/dist/chunks/config-eXB87DOi.js.map +1 -1
  78. package/dist/chunks/config-rLkc9Zn2.js.map +1 -1
  79. package/dist/chunks/{context-CTbuwcYs.js → context-CPMRfwVr.js} +1 -1
  80. package/dist/chunks/{context-CTbuwcYs.js.map → context-CPMRfwVr.js.map} +1 -1
  81. package/dist/chunks/{grModalStyles-EZfuEiw_.js → grModalStyles-BEkiFal_.js} +10 -1
  82. package/dist/chunks/grModalStyles-BEkiFal_.js.map +1 -0
  83. package/dist/chunks/{grRadioStyles-DGL2QLy6.js → grRadioStyles-BwRyCjQQ.js} +4 -2
  84. package/dist/chunks/{grRadioStyles-DGL2QLy6.js.map → grRadioStyles-BwRyCjQQ.js.map} +1 -1
  85. package/dist/chunks/{granular-provider-DCn6fgEs.js → granular-provider-DP2gk0oa.js} +10 -9
  86. package/dist/chunks/{granular-provider-DCn6fgEs.js.map → granular-provider-DP2gk0oa.js.map} +1 -1
  87. package/dist/chunks/{overlayStack-0CZS99Da.js → overlayStack-B_UFaFzk.js} +65 -24
  88. package/dist/chunks/overlayStack-B_UFaFzk.js.map +1 -0
  89. package/dist/chunks/{renamedProp-BwcN-SJg.js → renamedProp-Dy96tT-F.js} +1 -1
  90. package/dist/chunks/{renamedProp-BwcN-SJg.js.map → renamedProp-Dy96tT-F.js.map} +1 -1
  91. package/dist/chunks/{useModalOverlay-BnAGZpcI.js → useModalOverlay-BwX8WEcI.js} +3 -3
  92. package/dist/chunks/{useModalOverlay-BnAGZpcI.js.map → useModalOverlay-BwX8WEcI.js.map} +1 -1
  93. package/dist/chunks/{usePortalTarget-C0p-mhaM.js → usePortalTarget-BhrRgdqW.js} +1 -1
  94. package/dist/chunks/{usePortalTarget-C0p-mhaM.js.map → usePortalTarget-BhrRgdqW.js.map} +1 -1
  95. package/dist/chunks/{validation-5HhpanPP.js → validation-BDjqsuGB.js} +1 -1
  96. package/dist/chunks/{validation-5HhpanPP.js.map → validation-BDjqsuGB.js.map} +1 -1
  97. package/dist/components/GrAlert/chunks/{GrAlert-FAVf-ksH.js → GrAlert-D72y1IEh.js} +1 -1
  98. package/dist/components/GrAlert/chunks/{GrAlert-FAVf-ksH.js.map → GrAlert-D72y1IEh.js.map} +1 -1
  99. package/dist/components/GrAlert/index.js +1 -1
  100. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-BQsSE7sj.js → GrAutocomplete-BpmFmpKs.js} +4 -6
  101. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-BQsSE7sj.js.map → GrAutocomplete-BpmFmpKs.js.map} +1 -1
  102. package/dist/components/GrAutocomplete/index.js +1 -1
  103. package/dist/components/GrAvatar/chunks/{GrAvatar-CNmLmgcr.js → GrAvatar-dWEXiCJG.js} +1 -1
  104. package/dist/components/GrAvatar/chunks/{GrAvatar-CNmLmgcr.js.map → GrAvatar-dWEXiCJG.js.map} +1 -1
  105. package/dist/components/GrAvatar/index.js +1 -1
  106. package/dist/components/GrBadge/chunks/{GrBadge-DpUDXKbq.js → GrBadge-DBeQXEir.js} +2 -2
  107. package/dist/components/GrBadge/chunks/{GrBadge-DpUDXKbq.js.map → GrBadge-DBeQXEir.js.map} +1 -1
  108. package/dist/components/GrBadge/index.js +1 -1
  109. package/dist/components/GrBadgeWrap/chunks/{GrBadgeWrap-B-A3PRkE.js → GrBadgeWrap-wdfxaXiu.js} +3 -1
  110. package/dist/components/GrBadgeWrap/chunks/{GrBadgeWrap-B-A3PRkE.js.map → GrBadgeWrap-wdfxaXiu.js.map} +1 -1
  111. package/dist/components/GrBadgeWrap/index.js +1 -1
  112. package/dist/components/GrBottomNav/chunks/{GrBottomNav-wtFatLjB.js → GrBottomNav-nE08pVUJ.js} +1 -1
  113. package/dist/components/GrBottomNav/chunks/{GrBottomNav-wtFatLjB.js.map → GrBottomNav-nE08pVUJ.js.map} +1 -1
  114. package/dist/components/GrBottomNav/index.js +1 -1
  115. package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-DRDNan_n.js → GrBreadcrumbs-DOpwY2EF.js} +3 -3
  116. package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-DRDNan_n.js.map → GrBreadcrumbs-DOpwY2EF.js.map} +1 -1
  117. package/dist/components/GrBreadcrumbs/index.js +1 -1
  118. package/dist/components/GrButton/chunks/{GrButton-7GP0zObj.js → GrButton-CS4TqMtG.js} +1 -1
  119. package/dist/components/GrButton/chunks/{GrButton-7GP0zObj.js.map → GrButton-CS4TqMtG.js.map} +1 -1
  120. package/dist/components/GrButton/index.js +1 -1
  121. package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -1
  122. package/dist/components/GrButtonGroup/index.js +1 -1
  123. package/dist/components/GrCard/chunks/{GrCard-BttXz1pQ.js → GrCard-Ck5--lMF.js} +2 -2
  124. package/dist/components/GrCard/chunks/{GrCard-BttXz1pQ.js.map → GrCard-Ck5--lMF.js.map} +1 -1
  125. package/dist/components/GrCard/index.js +1 -1
  126. package/dist/components/GrCheckbox/chunks/{GrCheckbox-CEcHIsXM.js → GrCheckbox-Dp201frb.js} +1 -1
  127. package/dist/components/GrCheckbox/chunks/{GrCheckbox-CEcHIsXM.js.map → GrCheckbox-Dp201frb.js.map} +1 -1
  128. package/dist/components/GrCheckbox/index.js +1 -1
  129. package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-BOwrVcFr.js → GrCheckboxGroup-IpqG5qwm.js} +2 -2
  130. package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-BOwrVcFr.js.map → GrCheckboxGroup-IpqG5qwm.js.map} +1 -1
  131. package/dist/components/GrCheckboxGroup/index.js +1 -1
  132. package/dist/components/GrChip/chunks/{GrChip-BTivtwff.js → GrChip-CKqyzYcv.js} +10 -7
  133. package/dist/components/GrChip/chunks/{GrChip-BTivtwff.js.map → GrChip-CKqyzYcv.js.map} +1 -1
  134. package/dist/components/GrChip/index.js +1 -1
  135. package/dist/components/GrChipGroup/chunks/{GrChipGroup-C78Vcwos.js → GrChipGroup-dDGwnC04.js} +1 -1
  136. package/dist/components/GrChipGroup/chunks/{GrChipGroup-C78Vcwos.js.map → GrChipGroup-dDGwnC04.js.map} +1 -1
  137. package/dist/components/GrChipGroup/index.js +1 -1
  138. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dp0eEBTZ.js → GrCodeBlock-BUOwKwQE.js} +2 -2
  139. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dp0eEBTZ.js.map → GrCodeBlock-BUOwKwQE.js.map} +1 -1
  140. package/dist/components/GrCodeBlock/index.js +1 -1
  141. package/dist/components/GrCollapse/chunks/{GrCollapse-BlW6ybdL.js → GrCollapse-DWH3QAnU.js} +6 -5
  142. package/dist/components/GrCollapse/chunks/{GrCollapse-BlW6ybdL.js.map → GrCollapse-DWH3QAnU.js.map} +1 -1
  143. package/dist/components/GrCollapse/index.js +1 -1
  144. package/dist/components/GrColorPicker/chunks/{GrColorPicker-CIgdPXHn.js → GrColorPicker-BNtpj_P6.js} +4 -4
  145. package/dist/components/GrColorPicker/chunks/{GrColorPicker-CIgdPXHn.js.map → GrColorPicker-BNtpj_P6.js.map} +1 -1
  146. package/dist/components/GrColorPicker/index.js +1 -1
  147. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BZHUKlux.js → GrCommandPalette-BVZEd4yy.js} +7 -7
  148. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BZHUKlux.js.map → GrCommandPalette-BVZEd4yy.js.map} +1 -1
  149. package/dist/components/GrCommandPalette/index.js +1 -1
  150. package/dist/components/GrConfigProvider/chunks/{GrConfigProvider-BF7R3hgg.js → GrConfigProvider-t9x2UToH.js} +13 -12
  151. package/dist/components/GrConfigProvider/chunks/{GrConfigProvider-BF7R3hgg.js.map → GrConfigProvider-t9x2UToH.js.map} +1 -1
  152. package/dist/components/GrConfigProvider/index.js +2 -2
  153. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-jRDs_E6C.js → GrConfirmDialog-K5ht2cYq.js} +4 -4
  154. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-jRDs_E6C.js.map → GrConfirmDialog-K5ht2cYq.js.map} +1 -1
  155. package/dist/components/GrConfirmDialog/index.js +1 -1
  156. package/dist/components/GrContextMenu/chunks/{GrContextMenu-DlFWm0eW.js → GrContextMenu-Dd2tgMoL.js} +1 -1
  157. package/dist/components/GrContextMenu/chunks/{GrContextMenu-DlFWm0eW.js.map → GrContextMenu-Dd2tgMoL.js.map} +1 -1
  158. package/dist/components/GrContextMenu/index.js +1 -1
  159. package/dist/components/GrDataTable/chunks/{GrDataTable-4JAgOQ-7.js → GrDataTable-BYYG_XZA.js} +5 -5
  160. package/dist/components/GrDataTable/chunks/{GrDataTable-4JAgOQ-7.js.map → GrDataTable-BYYG_XZA.js.map} +1 -1
  161. package/dist/components/GrDataTable/index.js +1 -1
  162. package/dist/components/GrDelta/chunks/{GrDelta-BZwkgQW-.js → GrDelta-BpfqebEV.js} +0 -0
  163. package/dist/components/GrDelta/chunks/{GrDelta-BZwkgQW-.js.map → GrDelta-BpfqebEV.js.map} +1 -1
  164. package/dist/components/GrDelta/index.js +1 -1
  165. package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-BMeCgFV3.js → GrDescriptionList-D8ANFpn_.js} +2 -2
  166. package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-BMeCgFV3.js.map → GrDescriptionList-D8ANFpn_.js.map} +1 -1
  167. package/dist/components/GrDescriptionList/index.js +2 -2
  168. package/dist/components/GrDialog/chunks/{GrDialog-C01Hhk6G.js → GrDialog-CeJubnKJ.js} +3 -3
  169. package/dist/components/GrDialog/chunks/{GrDialog-C01Hhk6G.js.map → GrDialog-CeJubnKJ.js.map} +1 -1
  170. package/dist/components/GrDialog/index.js +1 -1
  171. package/dist/components/GrDialogService/chunks/{GrDialogService-CmsJNUmM.js → GrDialogService-BArvw1DV.js} +9 -8
  172. package/dist/components/GrDialogService/chunks/{GrDialogService-CmsJNUmM.js.map → GrDialogService-BArvw1DV.js.map} +1 -1
  173. package/dist/components/GrDialogService/index.js +1 -1
  174. package/dist/components/GrDivider/chunks/{GrDivider-BXavGcMX.js → GrDivider-DxA-zV25.js} +1 -1
  175. package/dist/components/GrDivider/chunks/{GrDivider-BXavGcMX.js.map → GrDivider-DxA-zV25.js.map} +1 -1
  176. package/dist/components/GrDivider/index.js +1 -1
  177. package/dist/components/GrDrawer/chunks/{GrDrawer-xfoy-MCj.js → GrDrawer-BBHNgeH0.js} +5 -5
  178. package/dist/components/GrDrawer/chunks/{GrDrawer-xfoy-MCj.js.map → GrDrawer-BBHNgeH0.js.map} +1 -1
  179. package/dist/components/GrDrawer/index.js +1 -1
  180. package/dist/components/GrDropdown/chunks/{GrDropdown-7r772-Cq.js → GrDropdown-CUlviqMi.js} +6 -8
  181. package/dist/components/GrDropdown/chunks/{GrDropdown-7r772-Cq.js.map → GrDropdown-CUlviqMi.js.map} +1 -1
  182. package/dist/components/GrDropdown/index.js +1 -1
  183. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-DNurbsWc.js → GrDropdownMenu-COOR1LCs.js} +1 -1
  184. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-DNurbsWc.js.map → GrDropdownMenu-COOR1LCs.js.map} +1 -1
  185. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js.map +1 -1
  186. package/dist/components/GrDropdownMenu/index.js +1 -1
  187. package/dist/components/GrEmptyState/chunks/{GrEmptyState-RqsWvgI9.js → GrEmptyState-BbvwE-E0.js} +2 -2
  188. package/dist/components/GrEmptyState/chunks/{GrEmptyState-RqsWvgI9.js.map → GrEmptyState-BbvwE-E0.js.map} +1 -1
  189. package/dist/components/GrEmptyState/index.js +1 -1
  190. package/dist/components/GrFilePreview/chunks/{GrFilePreview-C9Z7hMK8.js → GrFilePreview-PabkLgYX.js} +1 -1
  191. package/dist/components/GrFilePreview/chunks/{GrFilePreview-C9Z7hMK8.js.map → GrFilePreview-PabkLgYX.js.map} +1 -1
  192. package/dist/components/GrFilePreview/index.js +1 -1
  193. package/dist/components/GrFileUpload/chunks/{GrFileUpload-LL8RZvC0.js → GrFileUpload-BwMR71zN.js} +4 -4
  194. package/dist/components/GrFileUpload/chunks/{GrFileUpload-LL8RZvC0.js.map → GrFileUpload-BwMR71zN.js.map} +1 -1
  195. package/dist/components/GrFileUpload/index.js +1 -1
  196. package/dist/components/GrForm/chunks/{GrForm-CrnfCsgj.js → GrForm-xTtavR-K.js} +1 -1
  197. package/dist/components/GrForm/chunks/{GrForm-CrnfCsgj.js.map → GrForm-xTtavR-K.js.map} +1 -1
  198. package/dist/components/GrForm/index.js +2 -2
  199. package/dist/components/GrFormField/chunks/{GrFormField-DSylU7IU.js → GrFormField-DO61vxpS.js} +2 -2
  200. package/dist/components/GrFormField/chunks/{GrFormField-DSylU7IU.js.map → GrFormField-DO61vxpS.js.map} +1 -1
  201. package/dist/components/GrFormField/index.js +1 -1
  202. package/dist/components/GrFormFile/chunks/{GrFormFile-B1jGZyIj.js → GrFormFile-Dlxx-9zi.js} +3 -3
  203. package/dist/components/GrFormFile/chunks/{GrFormFile-B1jGZyIj.js.map → GrFormFile-Dlxx-9zi.js.map} +1 -1
  204. package/dist/components/GrFormFile/index.js +1 -1
  205. package/dist/components/GrFormSection/chunks/{GrFormSection-ejieOg9H.js → GrFormSection-DV1S6R_N.js} +1 -1
  206. package/dist/components/GrFormSection/chunks/{GrFormSection-ejieOg9H.js.map → GrFormSection-DV1S6R_N.js.map} +1 -1
  207. package/dist/components/GrFormSection/index.js +1 -1
  208. package/dist/components/GrIcon/chunks/{GrIcon-Dmf0c9ba.js → GrIcon-DTZIgmje.js} +1 -1
  209. package/dist/components/GrIcon/chunks/{GrIcon-Dmf0c9ba.js.map → GrIcon-DTZIgmje.js.map} +1 -1
  210. package/dist/components/GrIcon/index.js +1 -1
  211. package/dist/components/GrImageViewer/chunks/{GrImageViewer--BU8yrfx.js → GrImageViewer-BjYw-uTF.js} +2 -4
  212. package/dist/components/GrImageViewer/chunks/{GrImageViewer--BU8yrfx.js.map → GrImageViewer-BjYw-uTF.js.map} +1 -1
  213. package/dist/components/GrImageViewer/index.js +1 -1
  214. package/dist/components/GrInput/chunks/{GrInput-BLywRZUN.js → GrInput-TFeBm3gQ.js} +2 -1
  215. package/dist/components/GrInput/chunks/{GrInput-BLywRZUN.js.map → GrInput-TFeBm3gQ.js.map} +1 -1
  216. package/dist/components/GrInput/index.js +1 -1
  217. package/dist/components/GrInputTag/chunks/{GrInputTag-ByD9NugQ.js → GrInputTag-DhfUNOA5.js} +3 -3
  218. package/dist/components/GrInputTag/chunks/{GrInputTag-ByD9NugQ.js.map → GrInputTag-DhfUNOA5.js.map} +1 -1
  219. package/dist/components/GrInputTag/index.js +1 -1
  220. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BCZ7lE2k.js → GrJsonViewer-CdtmUpZ3.js} +6 -6
  221. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-BCZ7lE2k.js.map → GrJsonViewer-CdtmUpZ3.js.map} +1 -1
  222. package/dist/components/GrJsonViewer/index.js +2 -2
  223. package/dist/components/GrKbd/chunks/{GrKbd-D2ga1H9i.js → GrKbd-D_a1mPLe.js} +1 -1
  224. package/dist/components/GrKbd/chunks/{GrKbd-D2ga1H9i.js.map → GrKbd-D_a1mPLe.js.map} +1 -1
  225. package/dist/components/GrKbd/index.js +1 -1
  226. package/dist/components/GrLink/chunks/{GrLink-DYXw3W9w.js → GrLink-DwWErumU.js} +2 -2
  227. package/dist/components/GrLink/chunks/{GrLink-DYXw3W9w.js.map → GrLink-DwWErumU.js.map} +1 -1
  228. package/dist/components/GrLink/index.js +2 -2
  229. package/dist/components/GrList/chunks/{GrList-B_CRJB4c.js → GrList-Unya-LXb.js} +3 -3
  230. package/dist/components/GrList/chunks/{GrList-B_CRJB4c.js.map → GrList-Unya-LXb.js.map} +1 -1
  231. package/dist/components/GrList/index.js +1 -1
  232. package/dist/components/GrLoading/chunks/{GrLoading-CMD3Ri9P.js → GrLoading-BDrlrup_.js} +1 -1
  233. package/dist/components/GrLoading/chunks/{GrLoading-CMD3Ri9P.js.map → GrLoading-BDrlrup_.js.map} +1 -1
  234. package/dist/components/GrLoading/index.js +1 -1
  235. package/dist/components/GrModal/chunks/{GrModal-_JrDhon-.js → GrModal-xIWaJozo.js} +7 -6
  236. package/dist/components/GrModal/chunks/GrModal-xIWaJozo.js.map +1 -0
  237. package/dist/components/GrModal/index.js +2 -2
  238. package/dist/components/GrNavbar/chunks/{GrNavbar-Dr8e5kW-.js → GrNavbar-BRGuksiy.js} +3 -3
  239. package/dist/components/GrNavbar/chunks/{GrNavbar-Dr8e5kW-.js.map → GrNavbar-BRGuksiy.js.map} +1 -1
  240. package/dist/components/GrNavbar/index.js +1 -1
  241. package/dist/components/GrNumberInput/chunks/{GrNumberInput-DQ59YICu.js → GrNumberInput-BqPydXpK.js} +7 -9
  242. package/dist/components/GrNumberInput/chunks/{GrNumberInput-DQ59YICu.js.map → GrNumberInput-BqPydXpK.js.map} +1 -1
  243. package/dist/components/GrNumberInput/index.js +2 -2
  244. package/dist/components/GrPagination/chunks/{GrPagination-gBoWVHk6.js → GrPagination-DhbNZHEF.js} +26 -11
  245. package/dist/components/GrPagination/chunks/GrPagination-DhbNZHEF.js.map +1 -0
  246. package/dist/components/GrPagination/index.js +1 -1
  247. package/dist/components/GrPopover/chunks/{GrPopover-DEFxDffj.js → GrPopover-BakLcWkX.js} +3 -3
  248. package/dist/components/GrPopover/chunks/{GrPopover-DEFxDffj.js.map → GrPopover-BakLcWkX.js.map} +1 -1
  249. package/dist/components/GrPopover/index.js +2 -2
  250. package/dist/components/GrProgressBar/chunks/{GrProgressBar-hszUOC8f.js → GrProgressBar-C3NRBqIP.js} +6 -3
  251. package/dist/components/GrProgressBar/chunks/GrProgressBar-C3NRBqIP.js.map +1 -0
  252. package/dist/components/GrProgressBar/index.js +1 -1
  253. package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-D3yWXYDa.js → GrProgressCircle-CdvbINQc.js} +2 -2
  254. package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-D3yWXYDa.js.map → GrProgressCircle-CdvbINQc.js.map} +1 -1
  255. package/dist/components/GrProgressCircle/index.js +1 -1
  256. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-CailXSqW.js → GrPromptDialog-C9Y1ifE_.js} +8 -8
  257. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-CailXSqW.js.map → GrPromptDialog-C9Y1ifE_.js.map} +1 -1
  258. package/dist/components/GrPromptDialog/index.js +1 -1
  259. package/dist/components/GrRadio/chunks/{GrRadio-Aq3v8XgG.js → GrRadio-B1776V9D.js} +2 -2
  260. package/dist/components/GrRadio/chunks/{GrRadio-Aq3v8XgG.js.map → GrRadio-B1776V9D.js.map} +1 -1
  261. package/dist/components/GrRadio/index.js +2 -2
  262. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-y9LVdTWh.js → GrRadioGroup-UgitrBFl.js} +2 -2
  263. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-y9LVdTWh.js.map → GrRadioGroup-UgitrBFl.js.map} +1 -1
  264. package/dist/components/GrRadioGroup/index.js +1 -1
  265. package/dist/components/GrRating/chunks/{GrRating-IEiTOdnF.js → GrRating-DTriyyqG.js} +1 -1
  266. package/dist/components/GrRating/chunks/{GrRating-IEiTOdnF.js.map → GrRating-DTriyyqG.js.map} +1 -1
  267. package/dist/components/GrRating/index.js +1 -1
  268. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DMeOWlzj.js → GrResponseErrorBanner-NEEJZ8zi.js} +2 -2
  269. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DMeOWlzj.js.map → GrResponseErrorBanner-NEEJZ8zi.js.map} +1 -1
  270. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CBVRpgIG.js → GrResponseErrorBanner-ZvBvEQDZ.js} +1 -1
  271. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-CBVRpgIG.js.map → GrResponseErrorBanner-ZvBvEQDZ.js.map} +1 -1
  272. package/dist/components/GrResponseErrorBanner/index.js +2 -2
  273. package/dist/components/GrSegmented/chunks/{GrSegmented-CB-VR-yL.js → GrSegmented-NKTi9bMG.js} +1 -1
  274. package/dist/components/GrSegmented/chunks/{GrSegmented-CB-VR-yL.js.map → GrSegmented-NKTi9bMG.js.map} +1 -1
  275. package/dist/components/GrSegmented/index.js +1 -1
  276. package/dist/components/GrSelect/chunks/{GrSelect-CZqV1Eg4.js → GrSelect-Do1iAyp1.js} +8 -12
  277. package/dist/components/GrSelect/chunks/GrSelect-Do1iAyp1.js.map +1 -0
  278. package/dist/components/GrSelect/index.js +1 -1
  279. package/dist/components/GrSelect/styles.css +1 -1
  280. package/dist/components/GrSidebar/chunks/{GrSidebar-alkwBUzL.js → GrSidebar-DoKLlHSw.js} +2 -2
  281. package/dist/components/GrSidebar/chunks/{GrSidebar-alkwBUzL.js.map → GrSidebar-DoKLlHSw.js.map} +1 -1
  282. package/dist/components/GrSidebar/index.js +1 -1
  283. package/dist/components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js.map +1 -1
  284. package/dist/components/GrSlider/chunks/{GrSlider-DTTrZTHK.js → GrSlider-Db-jACXz.js} +14 -6
  285. package/dist/components/GrSlider/chunks/GrSlider-Db-jACXz.js.map +1 -0
  286. package/dist/components/GrSlider/index.js +1 -1
  287. package/dist/components/GrSortableList/chunks/{GrSortableList-HyKX--rO.js → GrSortableList-CQCaWivn.js} +1 -1
  288. package/dist/components/GrSortableList/chunks/{GrSortableList-HyKX--rO.js.map → GrSortableList-CQCaWivn.js.map} +1 -1
  289. package/dist/components/GrSortableList/index.js +1 -1
  290. package/dist/components/GrSplitter/chunks/{GrSplitter-MltjaADn.js → GrSplitter-C-XQzq7q.js} +1 -1
  291. package/dist/components/GrSplitter/chunks/{GrSplitter-MltjaADn.js.map → GrSplitter-C-XQzq7q.js.map} +1 -1
  292. package/dist/components/GrSplitter/index.js +1 -1
  293. package/dist/components/GrStatistic/chunks/{GrStatistic-qHVasK37.js → GrStatistic-C1_nY4Gc.js} +8 -4
  294. package/dist/components/GrStatistic/chunks/GrStatistic-C1_nY4Gc.js.map +1 -0
  295. package/dist/components/GrStatistic/index.js +1 -1
  296. package/dist/components/GrSteps/chunks/{GrSteps-C2jxpZoN.js → GrSteps-DXj7m-WO.js} +2 -2
  297. package/dist/components/GrSteps/chunks/{GrSteps-C2jxpZoN.js.map → GrSteps-DXj7m-WO.js.map} +1 -1
  298. package/dist/components/GrSteps/index.js +1 -1
  299. package/dist/components/GrSwitch/chunks/{GrSwitch-7Oe5QfQZ.js → GrSwitch-CriHWT2A.js} +1 -1
  300. package/dist/components/GrSwitch/chunks/{GrSwitch-7Oe5QfQZ.js.map → GrSwitch-CriHWT2A.js.map} +1 -1
  301. package/dist/components/GrSwitch/index.js +1 -1
  302. package/dist/components/GrTabPanels/chunks/{GrTabPanels-BZQS8-JM.js → GrTabPanels-5zsbqS1v.js} +1 -1
  303. package/dist/components/GrTabPanels/chunks/{GrTabPanels-BZQS8-JM.js.map → GrTabPanels-5zsbqS1v.js.map} +1 -1
  304. package/dist/components/GrTabPanels/index.js +1 -1
  305. package/dist/components/GrTable/chunks/{GrTable-jhUTczjv.js → GrTable-iwzHvlMC.js} +1 -1
  306. package/dist/components/GrTable/chunks/{GrTable-jhUTczjv.js.map → GrTable-iwzHvlMC.js.map} +1 -1
  307. package/dist/components/GrTable/index.js +1 -1
  308. package/dist/components/GrTabs/chunks/{GrTabs-CT2nk_HV.js → GrTabs-DHfv67cp.js} +1 -1
  309. package/dist/components/GrTabs/chunks/{GrTabs-CT2nk_HV.js.map → GrTabs-DHfv67cp.js.map} +1 -1
  310. package/dist/components/GrTabs/index.js +1 -1
  311. package/dist/components/GrTextarea/chunks/{GrTextarea-DinXG12-.js → GrTextarea-BII3w61K.js} +1 -1
  312. package/dist/components/GrTextarea/chunks/{GrTextarea-DinXG12-.js.map → GrTextarea-BII3w61K.js.map} +1 -1
  313. package/dist/components/GrTextarea/index.js +1 -1
  314. package/dist/components/GrTimeline/chunks/{GrTimeline-BiHpArsg.js → GrTimeline-Bs60huw0.js} +2 -2
  315. package/dist/components/GrTimeline/chunks/{GrTimeline-BiHpArsg.js.map → GrTimeline-Bs60huw0.js.map} +1 -1
  316. package/dist/components/GrTimeline/index.js +1 -1
  317. package/dist/components/GrToaster/chunks/{GrToaster-COXIBKzq.js → GrToaster-D-sV-9of.js} +4 -4
  318. package/dist/components/GrToaster/chunks/{GrToaster-COXIBKzq.js.map → GrToaster-D-sV-9of.js.map} +1 -1
  319. package/dist/components/GrToaster/index.js +1 -1
  320. package/dist/components/GrTooltip/chunks/{GrTooltip-uYETdbCD.js → GrTooltip-BUiTbROv.js} +3 -3
  321. package/dist/components/GrTooltip/chunks/{GrTooltip-uYETdbCD.js.map → GrTooltip-BUiTbROv.js.map} +1 -1
  322. package/dist/components/GrTooltip/index.js +1 -1
  323. package/dist/components/GrTree/chunks/{GrTree-Ci6CZfKR.js → GrTree-CkELQwR8.js} +1 -2
  324. package/dist/components/GrTree/chunks/{GrTree-Ci6CZfKR.js.map → GrTree-CkELQwR8.js.map} +1 -1
  325. package/dist/components/GrTree/index.js +1 -1
  326. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DOXcpWq2.js → GrTreeSelect-DurwZ7Cz.js} +4 -4
  327. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DOXcpWq2.js.map → GrTreeSelect-DurwZ7Cz.js.map} +1 -1
  328. package/dist/components/GrTreeSelect/index.js +1 -1
  329. package/dist/components/GrValue/chunks/GrValue-ezkQM05Q.js.map +1 -1
  330. package/dist/composables/useFloating.js +1 -1
  331. package/dist/composables/useGrComponentConfig.js +1 -1
  332. package/dist/composables/useOverlayLayer.js +1 -1
  333. package/dist/composables/usePortalTarget.js +1 -1
  334. package/dist/composables/useTheme.js +1 -1
  335. package/dist/composables/useTheme.js.map +1 -1
  336. package/dist/composables/useToast.js +1 -1
  337. package/dist/composables/useToast.js.map +1 -1
  338. package/dist/composables/useVirtualList.js +3 -5
  339. package/dist/composables/useVirtualList.js.map +1 -1
  340. package/dist/directives/loading.js +1 -1
  341. package/dist/granular-provider-node.js +1 -1
  342. package/dist/granular-provider.js +1 -1
  343. package/dist/index.js +87 -87
  344. package/dist/testing.js +1 -1
  345. package/dist/testing.js.map +1 -1
  346. package/dist/types/components/GrDialog/GrDialog.vue.d.ts +1 -1
  347. package/dist/types/components/GrDrawer/GrDrawer.vue.d.ts +1 -1
  348. package/dist/types/components/GrModal/GrModal.vue.d.ts +1 -1
  349. package/dist/types/components/GrModal/grModalStyles.d.ts +9 -0
  350. package/dist/types/components/GrProgressBar/GrProgressBar.vue.d.ts +1 -1
  351. package/dist/types/internal/devHook.d.ts +53 -0
  352. package/dist/vue/index.js +2 -2
  353. package/dist/vue/index.js.map +1 -1
  354. package/dist/web-types.json +2 -2
  355. package/package.json +17 -17
  356. package/dist/chunks/config-CQLNjc9X2.js.map +0 -1
  357. package/dist/chunks/config-CnYdE3HZ2.js.map +0 -1
  358. package/dist/chunks/config-CuQmUkMw2.js.map +0 -1
  359. package/dist/chunks/config-DBmdgoVf2.js.map +0 -1
  360. package/dist/chunks/config-DVCNvhIG2.js.map +0 -1
  361. package/dist/chunks/config-DpAYidyY2.js.map +0 -1
  362. package/dist/chunks/config-MmPym-Z72.js.map +0 -1
  363. package/dist/chunks/config-mlheIMtV.js.map +0 -1
  364. package/dist/chunks/grModalStyles-EZfuEiw_.js.map +0 -1
  365. package/dist/chunks/overlayStack-0CZS99Da.js.map +0 -1
  366. package/dist/components/GrModal/chunks/GrModal-_JrDhon-.js.map +0 -1
  367. package/dist/components/GrPagination/chunks/GrPagination-gBoWVHk6.js.map +0 -1
  368. package/dist/components/GrProgressBar/chunks/GrProgressBar-hszUOC8f.js.map +0 -1
  369. package/dist/components/GrSelect/chunks/GrSelect-CZqV1Eg4.js.map +0 -1
  370. package/dist/components/GrSlider/chunks/GrSlider-DTTrZTHK.js.map +0 -1
  371. package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +0 -1
  372. /package/dist/chunks/{config-CQLNjc9X2.js → config-CQLNjc9X.js} +0 -0
  373. /package/dist/chunks/{config-CnYdE3HZ2.js → config-CnYdE3HZ.js} +0 -0
  374. /package/dist/chunks/{config-DBmdgoVf2.js → config-DBmdgoVf.js} +0 -0
  375. /package/dist/chunks/{config-DVCNvhIG2.js → config-DVCNvhIG.js} +0 -0
  376. /package/dist/chunks/{config-DpAYidyY2.js → config-DpAYidyY.js} +0 -0
  377. /package/dist/chunks/{config-MmPym-Z72.js → config-MmPym-Z7.js} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"GrResponseErrorBanner-CBVRpgIG.js","names":[],"sources":["../../../../src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/GrFormErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/GrFormErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/useResponseError.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «загрузка файлов»:\n *\n * - Включена кнопка «Повторить» по умолчанию (`canRetry=true`).\n * - Тексты сдвинуты под загрузку файлов.\n * - Опциональный prop `files` пробрасывает контекст наружу через `retry`.\n *\n * Парсеры/нормализация — те же, что у базового баннера. Если нужны кастомные\n * парсеры — используйте напрямую `GrResponseErrorBanner` + `useResponseError`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrUploadErrorBannerProps {\n error: ResponseErrorInfo | null\n /** Файлы, которые пытались загрузить — пробрасываются в `retry` payload. */\n files?: File[]\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrUploadErrorBannerEmits {\n (e: 'retry', payload: { error: ResponseErrorInfo, files: File[] }): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrUploadErrorBannerProps>(), {\n files: () => [],\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n canRetry: true,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'upload-error',\n})\n\nconst emit = defineEmits<GrUploadErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под загрузку файлов» резолвятся через i18n (fallback — англ. строки), иначе\n// перекрыли бы i18n базового баннера как `props.texts`.\nconst uploadTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n networkTitle: t('gr.uploadErrorBanner.networkTitle', 'Failed to upload files'),\n networkMessage: t('gr.uploadErrorBanner.networkMessage', 'Check your connection and try again.'),\n validationTitle: t('gr.uploadErrorBanner.validationTitle', 'Files did not pass validation'),\n validationMessage: t('gr.uploadErrorBanner.validationMessage', 'Some of the files do not meet the requirements.'),\n serverTitle: t('gr.uploadErrorBanner.serverTitle', 'Upload error on the server'),\n serverMessage: t('gr.uploadErrorBanner.serverMessage', 'The server could not process the upload. Please try again.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...uploadTexts.value,\n ...props.texts,\n}))\n\nfunction onRetry(info: ResponseErrorInfo): void {\n emit('retry', { error: info, files: props.files })\n}\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"onRetry\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «загрузка файлов»:\n *\n * - Включена кнопка «Повторить» по умолчанию (`canRetry=true`).\n * - Тексты сдвинуты под загрузку файлов.\n * - Опциональный prop `files` пробрасывает контекст наружу через `retry`.\n *\n * Парсеры/нормализация — те же, что у базового баннера. Если нужны кастомные\n * парсеры — используйте напрямую `GrResponseErrorBanner` + `useResponseError`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrUploadErrorBannerProps {\n error: ResponseErrorInfo | null\n /** Файлы, которые пытались загрузить — пробрасываются в `retry` payload. */\n files?: File[]\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrUploadErrorBannerEmits {\n (e: 'retry', payload: { error: ResponseErrorInfo, files: File[] }): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrUploadErrorBannerProps>(), {\n files: () => [],\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n canRetry: true,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'upload-error',\n})\n\nconst emit = defineEmits<GrUploadErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под загрузку файлов» резолвятся через i18n (fallback — англ. строки), иначе\n// перекрыли бы i18n базового баннера как `props.texts`.\nconst uploadTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n networkTitle: t('gr.uploadErrorBanner.networkTitle', 'Failed to upload files'),\n networkMessage: t('gr.uploadErrorBanner.networkMessage', 'Check your connection and try again.'),\n validationTitle: t('gr.uploadErrorBanner.validationTitle', 'Files did not pass validation'),\n validationMessage: t('gr.uploadErrorBanner.validationMessage', 'Some of the files do not meet the requirements.'),\n serverTitle: t('gr.uploadErrorBanner.serverTitle', 'Upload error on the server'),\n serverMessage: t('gr.uploadErrorBanner.serverMessage', 'The server could not process the upload. Please try again.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...uploadTexts.value,\n ...props.texts,\n}))\n\nfunction onRetry(info: ResponseErrorInfo): void {\n emit('retry', { error: info, files: props.files })\n}\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"onRetry\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «валидация формы»:\n *\n * - `showFieldLabels=true` — рисуются подписи `field:` перед каждой строкой.\n * - `canRetry=false` — обычно пользователь правит поля сам, retry не нужен.\n * - `toneByKind.validation = 'warning'` — визуально «исправь», не «упало».\n * - Тексты сдвинуты под формы.\n *\n * Для кастомных парсеров используйте напрямую `GrResponseErrorBanner` +\n * `useResponseError({ parsers: () => extendDefaultParsers([myParser]) })`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrFormErrorBannerProps {\n error: ResponseErrorInfo | null\n fieldLabels?: Record<string, string>\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrFormErrorBannerEmits {\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrFormErrorBannerProps>(), {\n fieldLabels: () => ({}),\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({ validation: 'warning' }),\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'form-error',\n})\n\nconst emit = defineEmits<GrFormErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под формы» резолвятся через i18n (fallback — англ. строки). Иначе они бы,\n// как `props.texts`, перекрывали i18n базового баннера и форсили английский.\nconst formTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n validationTitle: t('gr.formErrorBanner.validationTitle', 'Check the form fields'),\n validationMessage: t('gr.formErrorBanner.validationMessage', 'The server rejected the data. Fix the highlighted fields and try again.'),\n clientTitle: t('gr.formErrorBanner.clientTitle', 'Failed to save'),\n serverTitle: t('gr.formErrorBanner.serverTitle', 'Save error'),\n serverMessage: t('gr.formErrorBanner.serverMessage', 'Could not save the data. Please try again later.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...formTexts.value,\n ...props.texts,\n}))\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :field-labels=\"props.fieldLabels\"\n show-field-labels\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"(info) => emit('retry', info)\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «валидация формы»:\n *\n * - `showFieldLabels=true` — рисуются подписи `field:` перед каждой строкой.\n * - `canRetry=false` — обычно пользователь правит поля сам, retry не нужен.\n * - `toneByKind.validation = 'warning'` — визуально «исправь», не «упало».\n * - Тексты сдвинуты под формы.\n *\n * Для кастомных парсеров используйте напрямую `GrResponseErrorBanner` +\n * `useResponseError({ parsers: () => extendDefaultParsers([myParser]) })`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrFormErrorBannerProps {\n error: ResponseErrorInfo | null\n fieldLabels?: Record<string, string>\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrFormErrorBannerEmits {\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrFormErrorBannerProps>(), {\n fieldLabels: () => ({}),\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({ validation: 'warning' }),\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'form-error',\n})\n\nconst emit = defineEmits<GrFormErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под формы» резолвятся через i18n (fallback — англ. строки). Иначе они бы,\n// как `props.texts`, перекрывали i18n базового баннера и форсили английский.\nconst formTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n validationTitle: t('gr.formErrorBanner.validationTitle', 'Check the form fields'),\n validationMessage: t('gr.formErrorBanner.validationMessage', 'The server rejected the data. Fix the highlighted fields and try again.'),\n clientTitle: t('gr.formErrorBanner.clientTitle', 'Failed to save'),\n serverTitle: t('gr.formErrorBanner.serverTitle', 'Save error'),\n serverMessage: t('gr.formErrorBanner.serverMessage', 'Could not save the data. Please try again later.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...formTexts.value,\n ...props.texts,\n}))\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :field-labels=\"props.fieldLabels\"\n show-field-labels\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"(info) => emit('retry', info)\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","import { computed, shallowRef } from 'vue'\nimport type { ComputedRef, Ref } from 'vue'\n\nimport { createResponseErrorClassifier, defaultResponseErrorParsers } from './parsers/createResponseErrorClassifier'\nimport { DEFAULT_AUTO_HIDE_KINDS, DEFAULT_RESPONSE_ERROR_TEXTS } from './responseError.defaults'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorParser,\n ResponseErrorTexts,\n} from './responseError.types'\n\n/**\n * Опции для `useResponseError`. Все поля опциональны и поддерживают\n * **реактивные геттеры** (`() => value`) — чтобы пробрасывать пропсы\n * родителя без потери реактивности.\n */\nexport type UseResponseErrorOptions = {\n /** Цепочка парсеров. По умолчанию — `defaultResponseErrorParsers`. */\n parsers?: () => ResponseErrorParser[] | undefined\n /** Частичный override текстов баннера. */\n texts?: () => Partial<ResponseErrorTexts> | undefined\n /**\n * `kind`'ы, которые **не** выставляются в state (баннер останется скрытым).\n * По умолчанию пусто — `aborted` показывается info-плашкой. Передайте\n * `['aborted']`, если хотите тихо проглатывать отмены.\n */\n autoHideKinds?: () => ResponseErrorKind[] | undefined\n /** Имя поля основного сообщения в body (для `plainMessageParser`). */\n messageKey?: () => string | undefined\n /** Контекст, который попадёт в `ctx.meta` каждого парсера (`{ files, formId, ... }`). */\n meta?: () => Record<string, unknown> | undefined\n /** Побочка после успешной классификации (логирование, sentry). */\n onClassify?: (info: ResponseErrorInfo) => void\n}\n\n/** Публичный возвращаемый API. */\nexport type UseResponseErrorReturn = {\n /** Текущее состояние ошибки. `null` — баннер скрыт. */\n currentError: Ref<ResponseErrorInfo | null>\n /** `currentError.value !== null`. */\n isVisible: ComputedRef<boolean>\n /** Последний «сырой» вход (для retry/логов). */\n lastRaw: Ref<unknown>\n\n /**\n * Главное API: классифицирует raw, сохраняет в state, возвращает info\n * (или `null`, если `kind` в `autoHideKinds`). Возвращает Promise,\n * т.к. нормализатор поддерживает `Response.json()` (async).\n */\n setRaw: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo | null>\n\n /** Установить готовый info, не пропуская через парсеры. */\n setError: (info: ResponseErrorInfo) => void\n\n /** Чистая классификация без записи в state — для предпросмотра. */\n classify: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo>\n\n /** Сбросить state (скрыть баннер). */\n dismiss: () => void\n /** Алиас `dismiss`. */\n reset: () => void\n\n /**\n * Хелпер: вызывает `handler(currentError)`. Если handler завершился без\n * исключения — сбрасывает state. Если кинул — оставляет state, поднимает.\n * Удобно бинать к кнопке «Повторить».\n */\n retry: (handler: (info: ResponseErrorInfo) => void | Promise<void>) => Promise<void>\n}\n\n/**\n * Stateful-композабл вокруг `createResponseErrorClassifier`. Хранит\n * `currentError`, инкапсулирует setRaw/retry/dismiss. Подходит для типичного\n * сценария «поймал ошибку запроса → показал баннер → ретрай/скрыть».\n */\nexport function useResponseError(options: UseResponseErrorOptions = {}): UseResponseErrorReturn {\n const currentError = shallowRef<ResponseErrorInfo | null>(null)\n // `shallowRef`, а не `ref`: сырая ошибка отдаётся потребителю как есть.\n // Глубокая реактивность обернула бы её в прокси — сравнение по ссылке\n // перестало бы работать, а `Response` уронил бы `clone()` на чужом `this`.\n const lastRaw = shallowRef<unknown>(null)\n\n function getClassifier() {\n return createResponseErrorClassifier({\n parsers: options.parsers?.() ?? defaultResponseErrorParsers,\n texts: options.texts?.() ?? {},\n messageKey: options.messageKey?.(),\n })\n }\n\n function isAutoHidden(kind: ResponseErrorKind): boolean {\n const list = options.autoHideKinds?.() ?? DEFAULT_AUTO_HIDE_KINDS\n return list.includes(kind)\n }\n\n async function classify(raw: unknown, extra?: Record<string, unknown>): Promise<ResponseErrorInfo> {\n const classifier = getClassifier()\n const meta = { ...(options.meta?.() ?? {}), ...(extra ?? {}) }\n const info = await classifier(raw, meta)\n options.onClassify?.(info)\n return info\n }\n\n async function setRaw(raw: unknown, extra?: Record<string, unknown>): Promise<ResponseErrorInfo | null> {\n lastRaw.value = raw\n const info = await classify(raw, extra)\n if (isAutoHidden(info.kind)) {\n currentError.value = null\n return null\n }\n currentError.value = info\n return info\n }\n\n function setError(info: ResponseErrorInfo): void {\n currentError.value = info\n }\n\n function dismiss(): void {\n currentError.value = null\n }\n\n async function retry(handler: (info: ResponseErrorInfo) => void | Promise<void>): Promise<void> {\n const info = currentError.value\n if (!info)\n return\n await handler(info)\n currentError.value = null\n }\n\n return {\n currentError,\n isVisible: computed(() => currentError.value !== null),\n lastRaw,\n setRaw,\n setError,\n classify,\n dismiss,\n reset: dismiss,\n retry,\n }\n}\n\nexport { DEFAULT_RESPONSE_ERROR_TEXTS }\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrResponseErrorBanner-ZvBvEQDZ.js","names":[],"sources":["../../../../src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/GrUploadErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/GrFormErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/GrFormErrorBanner.vue","../../../../src/components/GrResponseErrorBanner/useResponseError.ts"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «загрузка файлов»:\n *\n * - Включена кнопка «Повторить» по умолчанию (`canRetry=true`).\n * - Тексты сдвинуты под загрузку файлов.\n * - Опциональный prop `files` пробрасывает контекст наружу через `retry`.\n *\n * Парсеры/нормализация — те же, что у базового баннера. Если нужны кастомные\n * парсеры — используйте напрямую `GrResponseErrorBanner` + `useResponseError`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrUploadErrorBannerProps {\n error: ResponseErrorInfo | null\n /** Файлы, которые пытались загрузить — пробрасываются в `retry` payload. */\n files?: File[]\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrUploadErrorBannerEmits {\n (e: 'retry', payload: { error: ResponseErrorInfo, files: File[] }): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrUploadErrorBannerProps>(), {\n files: () => [],\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n canRetry: true,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'upload-error',\n})\n\nconst emit = defineEmits<GrUploadErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под загрузку файлов» резолвятся через i18n (fallback — англ. строки), иначе\n// перекрыли бы i18n базового баннера как `props.texts`.\nconst uploadTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n networkTitle: t('gr.uploadErrorBanner.networkTitle', 'Failed to upload files'),\n networkMessage: t('gr.uploadErrorBanner.networkMessage', 'Check your connection and try again.'),\n validationTitle: t('gr.uploadErrorBanner.validationTitle', 'Files did not pass validation'),\n validationMessage: t('gr.uploadErrorBanner.validationMessage', 'Some of the files do not meet the requirements.'),\n serverTitle: t('gr.uploadErrorBanner.serverTitle', 'Upload error on the server'),\n serverMessage: t('gr.uploadErrorBanner.serverMessage', 'The server could not process the upload. Please try again.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...uploadTexts.value,\n ...props.texts,\n}))\n\nfunction onRetry(info: ResponseErrorInfo): void {\n emit('retry', { error: info, files: props.files })\n}\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"onRetry\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «загрузка файлов»:\n *\n * - Включена кнопка «Повторить» по умолчанию (`canRetry=true`).\n * - Тексты сдвинуты под загрузку файлов.\n * - Опциональный prop `files` пробрасывает контекст наружу через `retry`.\n *\n * Парсеры/нормализация — те же, что у базового баннера. Если нужны кастомные\n * парсеры — используйте напрямую `GrResponseErrorBanner` + `useResponseError`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrUploadErrorBannerProps {\n error: ResponseErrorInfo | null\n /** Файлы, которые пытались загрузить — пробрасываются в `retry` payload. */\n files?: File[]\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrUploadErrorBannerEmits {\n (e: 'retry', payload: { error: ResponseErrorInfo, files: File[] }): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrUploadErrorBannerProps>(), {\n files: () => [],\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({}),\n canRetry: true,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'upload-error',\n})\n\nconst emit = defineEmits<GrUploadErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под загрузку файлов» резолвятся через i18n (fallback — англ. строки), иначе\n// перекрыли бы i18n базового баннера как `props.texts`.\nconst uploadTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n networkTitle: t('gr.uploadErrorBanner.networkTitle', 'Failed to upload files'),\n networkMessage: t('gr.uploadErrorBanner.networkMessage', 'Check your connection and try again.'),\n validationTitle: t('gr.uploadErrorBanner.validationTitle', 'Files did not pass validation'),\n validationMessage: t('gr.uploadErrorBanner.validationMessage', 'Some of the files do not meet the requirements.'),\n serverTitle: t('gr.uploadErrorBanner.serverTitle', 'Upload error on the server'),\n serverMessage: t('gr.uploadErrorBanner.serverMessage', 'The server could not process the upload. Please try again.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...uploadTexts.value,\n ...props.texts,\n}))\n\nfunction onRetry(info: ResponseErrorInfo): void {\n emit('retry', { error: info, files: props.files })\n}\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"onRetry\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «валидация формы»:\n *\n * - `showFieldLabels=true` — рисуются подписи `field:` перед каждой строкой.\n * - `canRetry=false` — обычно пользователь правит поля сам, retry не нужен.\n * - `toneByKind.validation = 'warning'` — визуально «исправь», не «упало».\n * - Тексты сдвинуты под формы.\n *\n * Для кастомных парсеров используйте напрямую `GrResponseErrorBanner` +\n * `useResponseError({ parsers: () => extendDefaultParsers([myParser]) })`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrFormErrorBannerProps {\n error: ResponseErrorInfo | null\n fieldLabels?: Record<string, string>\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrFormErrorBannerEmits {\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrFormErrorBannerProps>(), {\n fieldLabels: () => ({}),\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({ validation: 'warning' }),\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'form-error',\n})\n\nconst emit = defineEmits<GrFormErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под формы» резолвятся через i18n (fallback — англ. строки). Иначе они бы,\n// как `props.texts`, перекрывали i18n базового баннера и форсили английский.\nconst formTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n validationTitle: t('gr.formErrorBanner.validationTitle', 'Check the form fields'),\n validationMessage: t('gr.formErrorBanner.validationMessage', 'The server rejected the data. Fix the highlighted fields and try again.'),\n clientTitle: t('gr.formErrorBanner.clientTitle', 'Failed to save'),\n serverTitle: t('gr.formErrorBanner.serverTitle', 'Save error'),\n serverMessage: t('gr.formErrorBanner.serverMessage', 'Could not save the data. Please try again later.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...formTexts.value,\n ...props.texts,\n}))\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :field-labels=\"props.fieldLabels\"\n show-field-labels\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"(info) => emit('retry', info)\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Тонкая обёртка над `GrResponseErrorBanner` с предсетами для сценария\n * «валидация формы»:\n *\n * - `showFieldLabels=true` — рисуются подписи `field:` перед каждой строкой.\n * - `canRetry=false` — обычно пользователь правит поля сам, retry не нужен.\n * - `toneByKind.validation = 'warning'` — визуально «исправь», не «упало».\n * - Тексты сдвинуты под формы.\n *\n * Для кастомных парсеров используйте напрямую `GrResponseErrorBanner` +\n * `useResponseError({ parsers: () => extendDefaultParsers([myParser]) })`.\n */\nimport { computed } from 'vue'\n\nimport GrResponseErrorBanner from './GrResponseErrorBanner.vue'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorTexts,\n ResponseErrorTone,\n} from './responseError.types'\n\nexport interface GrFormErrorBannerProps {\n error: ResponseErrorInfo | null\n fieldLabels?: Record<string, string>\n texts?: Partial<ResponseErrorTexts>\n tone?: ResponseErrorTone\n toneByKind?: Partial<Record<ResponseErrorKind, ResponseErrorTone>>\n canRetry?: boolean\n canDismiss?: boolean\n autoHideKinds?: ResponseErrorKind[]\n testIdPrefix?: string\n}\n\nexport interface GrFormErrorBannerEmits {\n (e: 'retry', error: ResponseErrorInfo): void\n (e: 'dismiss'): void\n}\n\nconst props = withDefaults(defineProps<GrFormErrorBannerProps>(), {\n fieldLabels: () => ({}),\n texts: () => ({}),\n tone: undefined,\n toneByKind: () => ({ validation: 'warning' }),\n canRetry: false,\n canDismiss: true,\n autoHideKinds: () => [],\n testIdPrefix: 'form-error',\n})\n\nconst emit = defineEmits<GrFormErrorBannerEmits>()\n\nconst { t } = useGranularityTranslations()\n\n// Пресеты «под формы» резолвятся через i18n (fallback — англ. строки). Иначе они бы,\n// как `props.texts`, перекрывали i18n базового баннера и форсили английский.\nconst formTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n validationTitle: t('gr.formErrorBanner.validationTitle', 'Check the form fields'),\n validationMessage: t('gr.formErrorBanner.validationMessage', 'The server rejected the data. Fix the highlighted fields and try again.'),\n clientTitle: t('gr.formErrorBanner.clientTitle', 'Failed to save'),\n serverTitle: t('gr.formErrorBanner.serverTitle', 'Save error'),\n serverMessage: t('gr.formErrorBanner.serverMessage', 'Could not save the data. Please try again later.'),\n}))\n\nconst mergedTexts = computed<Partial<ResponseErrorTexts>>(() => ({\n ...formTexts.value,\n ...props.texts,\n}))\n</script>\n\n<template>\n <GrResponseErrorBanner\n :error=\"props.error\"\n :texts=\"mergedTexts\"\n :tone=\"props.tone\"\n :tone-by-kind=\"props.toneByKind\"\n :field-labels=\"props.fieldLabels\"\n show-field-labels\n :can-retry=\"props.canRetry\"\n :can-dismiss=\"props.canDismiss\"\n :auto-hide-kinds=\"props.autoHideKinds\"\n :test-id-prefix=\"props.testIdPrefix\"\n @retry=\"(info) => emit('retry', info)\"\n @dismiss=\"emit('dismiss')\"\n />\n</template>\n","import { computed, shallowRef } from 'vue'\nimport type { ComputedRef, Ref } from 'vue'\n\nimport { createResponseErrorClassifier, defaultResponseErrorParsers } from './parsers/createResponseErrorClassifier'\nimport { DEFAULT_AUTO_HIDE_KINDS, DEFAULT_RESPONSE_ERROR_TEXTS } from './responseError.defaults'\nimport type {\n ResponseErrorInfo,\n ResponseErrorKind,\n ResponseErrorParser,\n ResponseErrorTexts,\n} from './responseError.types'\n\n/**\n * Опции для `useResponseError`. Все поля опциональны и поддерживают\n * **реактивные геттеры** (`() => value`) — чтобы пробрасывать пропсы\n * родителя без потери реактивности.\n */\nexport type UseResponseErrorOptions = {\n /** Цепочка парсеров. По умолчанию — `defaultResponseErrorParsers`. */\n parsers?: () => ResponseErrorParser[] | undefined\n /** Частичный override текстов баннера. */\n texts?: () => Partial<ResponseErrorTexts> | undefined\n /**\n * `kind`'ы, которые **не** выставляются в state (баннер останется скрытым).\n * По умолчанию пусто — `aborted` показывается info-плашкой. Передайте\n * `['aborted']`, если хотите тихо проглатывать отмены.\n */\n autoHideKinds?: () => ResponseErrorKind[] | undefined\n /** Имя поля основного сообщения в body (для `plainMessageParser`). */\n messageKey?: () => string | undefined\n /** Контекст, который попадёт в `ctx.meta` каждого парсера (`{ files, formId, ... }`). */\n meta?: () => Record<string, unknown> | undefined\n /** Побочка после успешной классификации (логирование, sentry). */\n onClassify?: (info: ResponseErrorInfo) => void\n}\n\n/** Публичный возвращаемый API. */\nexport type UseResponseErrorReturn = {\n /** Текущее состояние ошибки. `null` — баннер скрыт. */\n currentError: Ref<ResponseErrorInfo | null>\n /** `currentError.value !== null`. */\n isVisible: ComputedRef<boolean>\n /** Последний «сырой» вход (для retry/логов). */\n lastRaw: Ref<unknown>\n\n /**\n * Главное API: классифицирует raw, сохраняет в state, возвращает info\n * (или `null`, если `kind` в `autoHideKinds`). Возвращает Promise,\n * т.к. нормализатор поддерживает `Response.json()` (async).\n */\n setRaw: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo | null>\n\n /** Установить готовый info, не пропуская через парсеры. */\n setError: (info: ResponseErrorInfo) => void\n\n /** Чистая классификация без записи в state — для предпросмотра. */\n classify: (raw: unknown, meta?: Record<string, unknown>) => Promise<ResponseErrorInfo>\n\n /** Сбросить state (скрыть баннер). */\n dismiss: () => void\n /** Алиас `dismiss`. */\n reset: () => void\n\n /**\n * Хелпер: вызывает `handler(currentError)`. Если handler завершился без\n * исключения — сбрасывает state. Если кинул — оставляет state, поднимает.\n * Удобно бинать к кнопке «Повторить».\n */\n retry: (handler: (info: ResponseErrorInfo) => void | Promise<void>) => Promise<void>\n}\n\n/**\n * Stateful-композабл вокруг `createResponseErrorClassifier`. Хранит\n * `currentError`, инкапсулирует setRaw/retry/dismiss. Подходит для типичного\n * сценария «поймал ошибку запроса → показал баннер → ретрай/скрыть».\n */\nexport function useResponseError(options: UseResponseErrorOptions = {}): UseResponseErrorReturn {\n const currentError = shallowRef<ResponseErrorInfo | null>(null)\n // `shallowRef`, а не `ref`: сырая ошибка отдаётся потребителю как есть.\n // Глубокая реактивность обернула бы её в прокси — сравнение по ссылке\n // перестало бы работать, а `Response` уронил бы `clone()` на чужом `this`.\n const lastRaw = shallowRef<unknown>(null)\n\n function getClassifier() {\n return createResponseErrorClassifier({\n parsers: options.parsers?.() ?? defaultResponseErrorParsers,\n texts: options.texts?.() ?? {},\n messageKey: options.messageKey?.(),\n })\n }\n\n function isAutoHidden(kind: ResponseErrorKind): boolean {\n const list = options.autoHideKinds?.() ?? DEFAULT_AUTO_HIDE_KINDS\n return list.includes(kind)\n }\n\n async function classify(raw: unknown, extra?: Record<string, unknown>): Promise<ResponseErrorInfo> {\n const classifier = getClassifier()\n const meta = { ...(options.meta?.() ?? {}), ...(extra ?? {}) }\n const info = await classifier(raw, meta)\n options.onClassify?.(info)\n return info\n }\n\n async function setRaw(raw: unknown, extra?: Record<string, unknown>): Promise<ResponseErrorInfo | null> {\n lastRaw.value = raw\n const info = await classify(raw, extra)\n if (isAutoHidden(info.kind)) {\n currentError.value = null\n return null\n }\n currentError.value = info\n return info\n }\n\n function setError(info: ResponseErrorInfo): void {\n currentError.value = info\n }\n\n function dismiss(): void {\n currentError.value = null\n }\n\n async function retry(handler: (info: ResponseErrorInfo) => void | Promise<void>): Promise<void> {\n const info = currentError.value\n if (!info)\n return\n await handler(info)\n currentError.value = null\n }\n\n return {\n currentError,\n isVisible: computed(() => currentError.value !== null),\n lastRaw,\n setRaw,\n setError,\n classify,\n dismiss,\n reset: dismiss,\n retry,\n }\n}\n\nexport { DEFAULT_RESPONSE_ERROR_TEXTS }\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { a as extendDefaultParsers, n as coreResponseErrorParsers, r as createResponseErrorClassifier, s as normalizeError, t as GrResponseErrorBanner_default } from "./chunks/GrResponseErrorBanner-DMeOWlzj.js";
2
- import { n as GrFormErrorBanner_default, r as GrUploadErrorBanner_default, t as useResponseError } from "./chunks/GrResponseErrorBanner-CBVRpgIG.js";
1
+ import { a as extendDefaultParsers, n as coreResponseErrorParsers, r as createResponseErrorClassifier, s as normalizeError, t as GrResponseErrorBanner_default } from "./chunks/GrResponseErrorBanner-NEEJZ8zi.js";
2
+ import { n as GrFormErrorBanner_default, r as GrUploadErrorBanner_default, t as useResponseError } from "./chunks/GrResponseErrorBanner-ZvBvEQDZ.js";
3
3
  export { GrFormErrorBanner_default as GrFormErrorBanner, GrResponseErrorBanner_default as GrResponseErrorBanner, GrResponseErrorBanner_default as default, GrUploadErrorBanner_default as GrUploadErrorBanner, coreResponseErrorParsers, createResponseErrorClassifier, extendDefaultParsers, normalizeError, useResponseError };
@@ -1,4 +1,4 @@
1
- import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunks/context-CTbuwcYs.js";
1
+ import { a as useGrComponentSize, i as useGrComponentProp } from "../../../chunks/context-CPMRfwVr.js";
2
2
  import { t as loader_circle_default } from "../../../chunks/loader-circle-CfVLz7lb.js";
3
3
  import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js";
4
4
  import { useGrFormControl } from "../../../composables/useGrFormControl.js";
@@ -1 +1 @@
1
- {"version":3,"file":"GrSegmented-CB-VR-yL.js","names":[],"sources":["../../../../src/components/shared/truncationTitle.ts","../../../../src/components/GrSegmented/GrSegmented.vue","../../../../src/components/GrSegmented/GrSegmented.vue"],"sourcesContent":["/**\n * Полный текст обрезанной строки — нативной подсказкой по наведению.\n *\n * `truncate` прячет хвост **визуально**: в DOM и для скринридера подпись\n * остаётся целой, поэтому теряет её ровно один читатель — тот, кто смотрит\n * глазами. Он видит «Включе…» и узнать остальное не может ничем.\n *\n * Подсказка ставится **по факту обрезки**, а не всегда: тултип, дублирующий\n * видимую целиком подпись, — шум, которого никто не просил. Замер делается на\n * самом наведении, поэтому ни наблюдателей, ни подписок заводить не нужно.\n *\n * Ширина сравнивается с запасом в пиксель: браузеры считают `scrollWidth`\n * округлением вверх, и у необрезанной строки он бывает на единицу больше\n * `clientWidth` — без запаса подсказка появлялась бы на ровном месте.\n */\nexport function titleWhenTruncated(event: Event): void {\n const element = event.currentTarget\n\n if (!(element instanceof HTMLElement))\n return\n\n // У поля ввода видимая строка живёт в `value`, а не в содержимом узла.\n const source = element instanceof HTMLInputElement ? element.value : element.textContent\n const text = source?.trim() ?? ''\n\n if (text && element.scrollWidth > element.clientWidth + 1)\n element.setAttribute('title', text)\n else\n element.removeAttribute('title')\n}\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { titleWhenTruncated } from '../shared/truncationTitle'\n\nimport type { ComponentPublicInstance } from 'vue'\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport {\n grSegmentedIndicatorClass,\n grSegmentedItemClass,\n grSegmentedItemIconClass,\n grSegmentedItemLabelClass,\n grSegmentedItemSpinnerClass,\n grSegmentedRootClass,\n grSegmentedRootStyle,\n type GrSegmentedOption,\n type GrSegmentedOrientation,\n type GrSegmentedSize,\n type GrSegmentedValue,\n type GrSegmentedVariant,\n} from './grSegmentedStyles'\n\ntype IndicatorGeometry = {\n width: number\n height: number\n x: number\n y: number\n}\n\n/**\n * Пропсы публичного GR-примитива «Segmented».\n */\nexport interface GrSegmentedProps {\n modelValue: GrSegmentedValue\n options: GrSegmentedOption[]\n variant?: GrSegmentedVariant\n size?: GrSegmentedSize\n /**\n * Направление ряда. Вертикаль — боковые фильтры; индикатор к ней готов по\n * построению, он двумерный.\n */\n orientation?: GrSegmentedOrientation\n /** Длительность анимации индикатора в мс. */\n indicatorDuration?: number\n /** Растягивать сегмент на всю ширину контейнера. */\n block?: boolean\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Имя скрытого поля, которым выбранное значение уходит в нативную форму. */\n name?: string\n ariaLabel?: string\n}\n\nexport interface GrSegmentedEmits {\n (e: 'update:modelValue', value: GrSegmentedValue): void\n (e: 'change', value: GrSegmentedValue, option: GrSegmentedOption): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrSegmentedProps>(),\n {\n variant: undefined,\n size: undefined,\n orientation: 'horizontal',\n indicatorDuration: 300,\n block: false,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n name: undefined,\n ariaLabel: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrSegmented' })\nconst resolvedVariant = useGrComponentProp('GrSegmented', 'variant', () => props.variant, 'pills')\n\nconst emit = defineEmits<GrSegmentedEmits>()\ndefineSlots<{\n /** Содержимое сегмента вместо подписи из `options`. */\n default?: (props: {\n option: GrSegmentedOption\n selected: boolean\n disabled: boolean\n loading: boolean\n }) => any\n}>()\n\n// `useId()` стабилен между сервером и клиентом, в отличие от `instance.uid`.\nconst fallbackName = `gr-segmented-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst rootRef = ref<HTMLElement | null>(null)\n\n// Фокус ходит между сегментами: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootRef, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\nconst itemRefs = ref(new Map<string, HTMLElement>())\nconst indicatorGeometry = ref<IndicatorGeometry | null>(null)\nconst indicatorReady = ref(false)\n\nlet resizeObserver: ResizeObserver | null = null\nlet observedRoot: HTMLElement | null = null\nlet observedItem: HTMLElement | null = null\nlet scheduled = false\n\nconst selectedIndex = computed(() => props.options.findIndex(option => option.value === props.modelValue))\nconst selectedOption = computed(() => props.options[selectedIndex.value] ?? null)\nconst indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)))\nconst isVertical = computed(() => props.orientation === 'vertical')\nconst rootClassName = computed(() => grSegmentedRootClass({\n variant: resolvedVariant.value,\n orientation: props.orientation,\n block: props.block,\n disabled: isDisabled.value,\n}))\n\n/**\n * Раскладка задаётся треками, а не классами: число сегментов известно только в\n * рантайме. По вертикали колонка одна — сегменты одинаковой ширины по\n * построению, и `block` решает лишь, занимать ли ширину контейнера.\n */\nconst rootStyle = computed<Record<string, string>>(() => {\n const empty = props.options.length === 0\n const track = () => props.block && !isVertical.value ? 'minmax(0,1fr)' : 'minmax(0,max-content)'\n\n return {\n ...grSegmentedRootStyle({\n variant: resolvedVariant.value,\n size: resolvedSize.value,\n orientation: props.orientation,\n }),\n gridTemplateColumns: isVertical.value\n ? 'minmax(0,1fr)'\n : empty ? 'none' : props.options.map(track).join(' '),\n ...(isVertical.value\n ? { gridTemplateRows: empty ? 'none' : props.options.map(track).join(' ') }\n : {}),\n }\n})\nconst indicatorClassName = computed(() => grSegmentedIndicatorClass(resolvedVariant.value))\nconst resolvedName = computed(() => props.name ?? fallbackName)\nconst hasIndicator = computed(() => selectedIndex.value !== -1 && indicatorGeometry.value !== null)\n\nconst indicatorStyle = computed<Record<string, string>>(() => {\n const geometry = indicatorGeometry.value\n if (!geometry) {\n return {\n opacity: '0',\n width: '0px',\n height: '0px',\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: 'translate3d(0px, 0px, 0px)',\n }\n }\n\n return {\n opacity: indicatorReady.value ? '1' : '0',\n width: `${geometry.width}px`,\n height: `${geometry.height}px`,\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`,\n }\n})\n\nfunction getOptionKey(value: GrSegmentedValue): string {\n return String(value)\n}\n\nfunction resolveOptionDisabled(option: GrSegmentedOption): boolean {\n return isDisabled.value || Boolean(option.disabled)\n}\n\n/**\n * Занятый сегмент не «недоступен», а работает: нативный `disabled` и\n * `aria-disabled` ему не ставим — состояние несёт `aria-busy`. Но выбор он не\n * принимает, поэтому блокировка считается отдельно от `disabled`.\n */\nfunction isOptionBusy(option: GrSegmentedOption): boolean {\n return Boolean(option.loading)\n}\n\nfunction isOptionBlocked(option: GrSegmentedOption): boolean {\n return resolveOptionDisabled(option) || isOptionBusy(option)\n}\n\nfunction isOptionSelected(option: GrSegmentedOption): boolean {\n return option.value === props.modelValue\n}\n\nfunction isIconOnlyOption(option: GrSegmentedOption): boolean {\n return Boolean(option.icon) && !option.label\n}\n\nfunction setItemRef(value: GrSegmentedValue, element: Element | ComponentPublicInstance | null): void {\n const key = getOptionKey(value)\n\n if (!(element instanceof HTMLElement)) {\n itemRefs.value.delete(key)\n return\n }\n\n itemRefs.value.set(key, element)\n}\n\nfunction isSameGeometry(left: IndicatorGeometry | null, right: IndicatorGeometry | null): boolean {\n if (left === right) {\n return true\n }\n\n if (!left || !right) {\n return false\n }\n\n return left.width === right.width\n && left.height === right.height\n && left.x === right.x\n && left.y === right.y\n}\n\nfunction measureIndicator(): void {\n const root = rootRef.value\n const option = selectedOption.value\n if (!root || !option) {\n if (indicatorGeometry.value !== null)\n indicatorGeometry.value = null\n\n if (indicatorReady.value)\n indicatorReady.value = false\n\n return\n }\n\n const selectedItem = itemRefs.value.get(getOptionKey(option.value))\n if (!selectedItem) {\n return\n }\n\n const rootRect = root.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const nextGeometry = {\n width: Math.max(Math.round(itemRect.width), 0),\n height: Math.max(Math.round(itemRect.height), 0),\n x: Math.round(itemRect.left - rootRect.left),\n y: Math.max(Math.round(itemRect.top - rootRect.top) - 1, 0),\n } satisfies IndicatorGeometry\n\n if (!isSameGeometry(indicatorGeometry.value, nextGeometry)) {\n indicatorGeometry.value = nextGeometry\n }\n\n const nextReady = nextGeometry.width > 0 && nextGeometry.height > 0\n if (indicatorReady.value !== nextReady) {\n indicatorReady.value = nextReady\n }\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n const root = rootRef.value\n const option = selectedOption.value\n const selectedItem = option\n ? itemRefs.value.get(getOptionKey(option.value)) ?? null\n : null\n\n if (!resizeObserver) {\n resizeObserver = new ResizeObserver(() => scheduleMeasure())\n }\n\n if (!root) {\n resizeObserver.disconnect()\n observedRoot = null\n observedItem = null\n return\n }\n\n if (observedRoot === root && observedItem === selectedItem) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver.observe(root)\n\n if (selectedItem) {\n resizeObserver.observe(selectedItem)\n }\n\n observedRoot = root\n observedItem = selectedItem\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) {\n return\n }\n\n scheduled = true\n void nextTick(() => {\n scheduled = false\n measureIndicator()\n refreshObserver()\n })\n}\n\nfunction emitValue(option: GrSegmentedOption): void {\n // Один guard на все пути: проверяй `readonly` только клавиатура, и клик по\n // сегменту менял бы значение вопреки заявленному контракту.\n if (isReadonly.value || isOptionBlocked(option) || option.value === props.modelValue) {\n return\n }\n\n emit('update:modelValue', option.value)\n emit('change', option.value, option)\n}\n\nfunction optionOf(value: GrSegmentedValue): GrSegmentedOption | undefined {\n return props.options.find(option => option.value === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента\n * описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —\n * вертикальный набор листается и стрелками влево/вправо.\n */\nconst roving = useRovingFocus<GrSegmentedValue>({\n items: () => props.options.map(option => option.value),\n elementFor: value => itemRefs.value.get(getOptionKey(value)),\n isDisabled: (value) => {\n const option = optionOf(value)\n return option ? isOptionBlocked(option) : true\n },\n orientation: () => 'both',\n skipDisabled: () => true,\n /**\n * Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём\n * стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся\n * остановку сохраняет: он не «недоступен», а занят.\n */\n initialKey: () => {\n const selected = selectedOption.value\n return selected && !resolveOptionDisabled(selected) ? selected.value : undefined\n },\n // Стрелка в `radiogroup` переносит и выбор, а не только фокус.\n onMove: (value) => {\n const option = optionOf(value)\n if (option)\n emitValue(option)\n },\n})\n\nfunction onItemClick(option: GrSegmentedOption): void {\n emitValue(option)\n // Клик тоже переносит остановку `Tab`: иначе она осталась бы там, куда её\n // увела последняя стрелка.\n if (!isOptionBlocked(option))\n roving.setActive(option.value)\n}\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */\nfunction rovingElement(): HTMLElement | undefined {\n const key = roving.rovingKey.value\n return key === undefined ? undefined : itemRefs.value.get(getOptionKey(key))\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number): void {\n if (isDisabled.value || isReadonly.value) {\n return\n }\n\n if (roving.handleNavigationKeys(event)) {\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n const option = props.options[index]\n if (option) {\n emitValue(option)\n }\n }\n}\n\nwatch(() => props.modelValue, () => scheduleMeasure())\nwatch(() => props.options, () => scheduleMeasure(), { deep: true })\nwatch(resolvedVariant, () => scheduleMeasure())\nwatch(resolvedSize, () => scheduleMeasure())\nwatch(() => props.block, () => scheduleMeasure())\n// Смена ориентации переставляет сегменты: без пересчёта индикатор остался бы в\n// координатах прежней раскладки.\nwatch(() => props.orientation, () => scheduleMeasure())\n\nonMounted(() => scheduleMeasure())\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n observedRoot = null\n observedItem = null\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootRef\"\n data-gr-segmented\n :data-variant=\"resolvedVariant\"\n role=\"radiogroup\"\n :aria-orientation=\"orientation\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :class=\"rootClassName\"\n :style=\"rootStyle\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Значение для нативной формы уходит одним скрытым полем рядом с\n сегментами, а не вложенным в каждый `role=\"radio\"`: роль объявляет своих\n потомков презентационными, и вложенный интерактивный контрол ломает\n виджет для скринридеров (axe: `nested-interactive`). Скрытое поле не\n фокусируется и интерактивным не считается. -->\n <input\n v-if=\"selectedOption && !resolveOptionDisabled(selectedOption)\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"String(selectedOption.value)\"\n >\n\n <span\n v-if=\"hasIndicator\"\n data-gr-segmented-indicator\n aria-hidden=\"true\"\n :class=\"indicatorClassName\"\n :style=\"indicatorStyle\"\n />\n\n <button\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :ref=\"element => setItemRef(option.value, element)\"\n data-gr-segmented-item\n :data-value=\"String(option.value)\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"option.ariaLabel\"\n :aria-checked=\"isOptionSelected(option) ? 'true' : 'false'\"\n :aria-disabled=\"resolveOptionDisabled(option) ? 'true' : undefined\"\n :aria-busy=\"isOptionBusy(option) ? 'true' : undefined\"\n :disabled=\"resolveOptionDisabled(option)\"\n :tabindex=\"roving.tabindexFor(option.value)\"\n :class=\"grSegmentedItemClass({\n variant: resolvedVariant,\n selected: isOptionSelected(option),\n disabled: resolveOptionDisabled(option),\n iconOnly: isIconOnlyOption(option),\n })\"\n @click=\"onItemClick(option)\"\n @keydown=\"onKeydown($event, index)\"\n >\n <slot\n :option=\"option\"\n :selected=\"isOptionSelected(option)\"\n :disabled=\"resolveOptionDisabled(option)\"\n :loading=\"isOptionBusy(option)\"\n >\n <!-- Спиннер занимает место иконки: две крутилки рядом читались бы как ошибка. -->\n <IconLoader\n v-if=\"isOptionBusy(option)\"\n data-gr-segmented-spinner\n aria-hidden=\"true\"\n :class=\"grSegmentedItemSpinnerClass\"\n />\n <component\n :is=\"option.icon\"\n v-else-if=\"option.icon\"\n aria-hidden=\"true\"\n :class=\"grSegmentedItemIconClass\"\n />\n <!-- Подпись сегмента обрезается по ширине трека, и «Включе…» без\n подсказки прочитать нечем: полный текст отдаётся по наведению. -->\n <span\n v-if=\"option.label\"\n :class=\"grSegmentedItemLabelClass\"\n @pointerenter=\"titleWhenTruncated\"\n >\n {{ option.label }}\n </span>\n </slot>\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { titleWhenTruncated } from '../shared/truncationTitle'\n\nimport type { ComponentPublicInstance } from 'vue'\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport {\n grSegmentedIndicatorClass,\n grSegmentedItemClass,\n grSegmentedItemIconClass,\n grSegmentedItemLabelClass,\n grSegmentedItemSpinnerClass,\n grSegmentedRootClass,\n grSegmentedRootStyle,\n type GrSegmentedOption,\n type GrSegmentedOrientation,\n type GrSegmentedSize,\n type GrSegmentedValue,\n type GrSegmentedVariant,\n} from './grSegmentedStyles'\n\ntype IndicatorGeometry = {\n width: number\n height: number\n x: number\n y: number\n}\n\n/**\n * Пропсы публичного GR-примитива «Segmented».\n */\nexport interface GrSegmentedProps {\n modelValue: GrSegmentedValue\n options: GrSegmentedOption[]\n variant?: GrSegmentedVariant\n size?: GrSegmentedSize\n /**\n * Направление ряда. Вертикаль — боковые фильтры; индикатор к ней готов по\n * построению, он двумерный.\n */\n orientation?: GrSegmentedOrientation\n /** Длительность анимации индикатора в мс. */\n indicatorDuration?: number\n /** Растягивать сегмент на всю ширину контейнера. */\n block?: boolean\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Имя скрытого поля, которым выбранное значение уходит в нативную форму. */\n name?: string\n ariaLabel?: string\n}\n\nexport interface GrSegmentedEmits {\n (e: 'update:modelValue', value: GrSegmentedValue): void\n (e: 'change', value: GrSegmentedValue, option: GrSegmentedOption): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrSegmentedProps>(),\n {\n variant: undefined,\n size: undefined,\n orientation: 'horizontal',\n indicatorDuration: 300,\n block: false,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n name: undefined,\n ariaLabel: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrSegmented' })\nconst resolvedVariant = useGrComponentProp('GrSegmented', 'variant', () => props.variant, 'pills')\n\nconst emit = defineEmits<GrSegmentedEmits>()\ndefineSlots<{\n /** Содержимое сегмента вместо подписи из `options`. */\n default?: (props: {\n option: GrSegmentedOption\n selected: boolean\n disabled: boolean\n loading: boolean\n }) => any\n}>()\n\n// `useId()` стабилен между сервером и клиентом, в отличие от `instance.uid`.\nconst fallbackName = `gr-segmented-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst rootRef = ref<HTMLElement | null>(null)\n\n// Фокус ходит между сегментами: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootRef, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\nconst itemRefs = ref(new Map<string, HTMLElement>())\nconst indicatorGeometry = ref<IndicatorGeometry | null>(null)\nconst indicatorReady = ref(false)\n\nlet resizeObserver: ResizeObserver | null = null\nlet observedRoot: HTMLElement | null = null\nlet observedItem: HTMLElement | null = null\nlet scheduled = false\n\nconst selectedIndex = computed(() => props.options.findIndex(option => option.value === props.modelValue))\nconst selectedOption = computed(() => props.options[selectedIndex.value] ?? null)\nconst indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)))\nconst isVertical = computed(() => props.orientation === 'vertical')\nconst rootClassName = computed(() => grSegmentedRootClass({\n variant: resolvedVariant.value,\n orientation: props.orientation,\n block: props.block,\n disabled: isDisabled.value,\n}))\n\n/**\n * Раскладка задаётся треками, а не классами: число сегментов известно только в\n * рантайме. По вертикали колонка одна — сегменты одинаковой ширины по\n * построению, и `block` решает лишь, занимать ли ширину контейнера.\n */\nconst rootStyle = computed<Record<string, string>>(() => {\n const empty = props.options.length === 0\n const track = () => props.block && !isVertical.value ? 'minmax(0,1fr)' : 'minmax(0,max-content)'\n\n return {\n ...grSegmentedRootStyle({\n variant: resolvedVariant.value,\n size: resolvedSize.value,\n orientation: props.orientation,\n }),\n gridTemplateColumns: isVertical.value\n ? 'minmax(0,1fr)'\n : empty ? 'none' : props.options.map(track).join(' '),\n ...(isVertical.value\n ? { gridTemplateRows: empty ? 'none' : props.options.map(track).join(' ') }\n : {}),\n }\n})\nconst indicatorClassName = computed(() => grSegmentedIndicatorClass(resolvedVariant.value))\nconst resolvedName = computed(() => props.name ?? fallbackName)\nconst hasIndicator = computed(() => selectedIndex.value !== -1 && indicatorGeometry.value !== null)\n\nconst indicatorStyle = computed<Record<string, string>>(() => {\n const geometry = indicatorGeometry.value\n if (!geometry) {\n return {\n opacity: '0',\n width: '0px',\n height: '0px',\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: 'translate3d(0px, 0px, 0px)',\n }\n }\n\n return {\n opacity: indicatorReady.value ? '1' : '0',\n width: `${geometry.width}px`,\n height: `${geometry.height}px`,\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`,\n }\n})\n\nfunction getOptionKey(value: GrSegmentedValue): string {\n return String(value)\n}\n\nfunction resolveOptionDisabled(option: GrSegmentedOption): boolean {\n return isDisabled.value || Boolean(option.disabled)\n}\n\n/**\n * Занятый сегмент не «недоступен», а работает: нативный `disabled` и\n * `aria-disabled` ему не ставим — состояние несёт `aria-busy`. Но выбор он не\n * принимает, поэтому блокировка считается отдельно от `disabled`.\n */\nfunction isOptionBusy(option: GrSegmentedOption): boolean {\n return Boolean(option.loading)\n}\n\nfunction isOptionBlocked(option: GrSegmentedOption): boolean {\n return resolveOptionDisabled(option) || isOptionBusy(option)\n}\n\nfunction isOptionSelected(option: GrSegmentedOption): boolean {\n return option.value === props.modelValue\n}\n\nfunction isIconOnlyOption(option: GrSegmentedOption): boolean {\n return Boolean(option.icon) && !option.label\n}\n\nfunction setItemRef(value: GrSegmentedValue, element: Element | ComponentPublicInstance | null): void {\n const key = getOptionKey(value)\n\n if (!(element instanceof HTMLElement)) {\n itemRefs.value.delete(key)\n return\n }\n\n itemRefs.value.set(key, element)\n}\n\nfunction isSameGeometry(left: IndicatorGeometry | null, right: IndicatorGeometry | null): boolean {\n if (left === right) {\n return true\n }\n\n if (!left || !right) {\n return false\n }\n\n return left.width === right.width\n && left.height === right.height\n && left.x === right.x\n && left.y === right.y\n}\n\nfunction measureIndicator(): void {\n const root = rootRef.value\n const option = selectedOption.value\n if (!root || !option) {\n if (indicatorGeometry.value !== null)\n indicatorGeometry.value = null\n\n if (indicatorReady.value)\n indicatorReady.value = false\n\n return\n }\n\n const selectedItem = itemRefs.value.get(getOptionKey(option.value))\n if (!selectedItem) {\n return\n }\n\n const rootRect = root.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const nextGeometry = {\n width: Math.max(Math.round(itemRect.width), 0),\n height: Math.max(Math.round(itemRect.height), 0),\n x: Math.round(itemRect.left - rootRect.left),\n y: Math.max(Math.round(itemRect.top - rootRect.top) - 1, 0),\n } satisfies IndicatorGeometry\n\n if (!isSameGeometry(indicatorGeometry.value, nextGeometry)) {\n indicatorGeometry.value = nextGeometry\n }\n\n const nextReady = nextGeometry.width > 0 && nextGeometry.height > 0\n if (indicatorReady.value !== nextReady) {\n indicatorReady.value = nextReady\n }\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n const root = rootRef.value\n const option = selectedOption.value\n const selectedItem = option\n ? itemRefs.value.get(getOptionKey(option.value)) ?? null\n : null\n\n if (!resizeObserver) {\n resizeObserver = new ResizeObserver(() => scheduleMeasure())\n }\n\n if (!root) {\n resizeObserver.disconnect()\n observedRoot = null\n observedItem = null\n return\n }\n\n if (observedRoot === root && observedItem === selectedItem) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver.observe(root)\n\n if (selectedItem) {\n resizeObserver.observe(selectedItem)\n }\n\n observedRoot = root\n observedItem = selectedItem\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) {\n return\n }\n\n scheduled = true\n void nextTick(() => {\n scheduled = false\n measureIndicator()\n refreshObserver()\n })\n}\n\nfunction emitValue(option: GrSegmentedOption): void {\n // Один guard на все пути: проверяй `readonly` только клавиатура, и клик по\n // сегменту менял бы значение вопреки заявленному контракту.\n if (isReadonly.value || isOptionBlocked(option) || option.value === props.modelValue) {\n return\n }\n\n emit('update:modelValue', option.value)\n emit('change', option.value, option)\n}\n\nfunction optionOf(value: GrSegmentedValue): GrSegmentedOption | undefined {\n return props.options.find(option => option.value === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента\n * описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —\n * вертикальный набор листается и стрелками влево/вправо.\n */\nconst roving = useRovingFocus<GrSegmentedValue>({\n items: () => props.options.map(option => option.value),\n elementFor: value => itemRefs.value.get(getOptionKey(value)),\n isDisabled: (value) => {\n const option = optionOf(value)\n return option ? isOptionBlocked(option) : true\n },\n orientation: () => 'both',\n skipDisabled: () => true,\n /**\n * Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём\n * стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся\n * остановку сохраняет: он не «недоступен», а занят.\n */\n initialKey: () => {\n const selected = selectedOption.value\n return selected && !resolveOptionDisabled(selected) ? selected.value : undefined\n },\n // Стрелка в `radiogroup` переносит и выбор, а не только фокус.\n onMove: (value) => {\n const option = optionOf(value)\n if (option)\n emitValue(option)\n },\n})\n\nfunction onItemClick(option: GrSegmentedOption): void {\n emitValue(option)\n // Клик тоже переносит остановку `Tab`: иначе она осталась бы там, куда её\n // увела последняя стрелка.\n if (!isOptionBlocked(option))\n roving.setActive(option.value)\n}\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */\nfunction rovingElement(): HTMLElement | undefined {\n const key = roving.rovingKey.value\n return key === undefined ? undefined : itemRefs.value.get(getOptionKey(key))\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number): void {\n if (isDisabled.value || isReadonly.value) {\n return\n }\n\n if (roving.handleNavigationKeys(event)) {\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n const option = props.options[index]\n if (option) {\n emitValue(option)\n }\n }\n}\n\nwatch(() => props.modelValue, () => scheduleMeasure())\nwatch(() => props.options, () => scheduleMeasure(), { deep: true })\nwatch(resolvedVariant, () => scheduleMeasure())\nwatch(resolvedSize, () => scheduleMeasure())\nwatch(() => props.block, () => scheduleMeasure())\n// Смена ориентации переставляет сегменты: без пересчёта индикатор остался бы в\n// координатах прежней раскладки.\nwatch(() => props.orientation, () => scheduleMeasure())\n\nonMounted(() => scheduleMeasure())\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n observedRoot = null\n observedItem = null\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootRef\"\n data-gr-segmented\n :data-variant=\"resolvedVariant\"\n role=\"radiogroup\"\n :aria-orientation=\"orientation\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :class=\"rootClassName\"\n :style=\"rootStyle\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Значение для нативной формы уходит одним скрытым полем рядом с\n сегментами, а не вложенным в каждый `role=\"radio\"`: роль объявляет своих\n потомков презентационными, и вложенный интерактивный контрол ломает\n виджет для скринридеров (axe: `nested-interactive`). Скрытое поле не\n фокусируется и интерактивным не считается. -->\n <input\n v-if=\"selectedOption && !resolveOptionDisabled(selectedOption)\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"String(selectedOption.value)\"\n >\n\n <span\n v-if=\"hasIndicator\"\n data-gr-segmented-indicator\n aria-hidden=\"true\"\n :class=\"indicatorClassName\"\n :style=\"indicatorStyle\"\n />\n\n <button\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :ref=\"element => setItemRef(option.value, element)\"\n data-gr-segmented-item\n :data-value=\"String(option.value)\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"option.ariaLabel\"\n :aria-checked=\"isOptionSelected(option) ? 'true' : 'false'\"\n :aria-disabled=\"resolveOptionDisabled(option) ? 'true' : undefined\"\n :aria-busy=\"isOptionBusy(option) ? 'true' : undefined\"\n :disabled=\"resolveOptionDisabled(option)\"\n :tabindex=\"roving.tabindexFor(option.value)\"\n :class=\"grSegmentedItemClass({\n variant: resolvedVariant,\n selected: isOptionSelected(option),\n disabled: resolveOptionDisabled(option),\n iconOnly: isIconOnlyOption(option),\n })\"\n @click=\"onItemClick(option)\"\n @keydown=\"onKeydown($event, index)\"\n >\n <slot\n :option=\"option\"\n :selected=\"isOptionSelected(option)\"\n :disabled=\"resolveOptionDisabled(option)\"\n :loading=\"isOptionBusy(option)\"\n >\n <!-- Спиннер занимает место иконки: две крутилки рядом читались бы как ошибка. -->\n <IconLoader\n v-if=\"isOptionBusy(option)\"\n data-gr-segmented-spinner\n aria-hidden=\"true\"\n :class=\"grSegmentedItemSpinnerClass\"\n />\n <component\n :is=\"option.icon\"\n v-else-if=\"option.icon\"\n aria-hidden=\"true\"\n :class=\"grSegmentedItemIconClass\"\n />\n <!-- Подпись сегмента обрезается по ширине трека, и «Включе…» без\n подсказки прочитать нечем: полный текст отдаётся по наведению. -->\n <span\n v-if=\"option.label\"\n :class=\"grSegmentedItemLabelClass\"\n @pointerenter=\"titleWhenTruncated\"\n >\n {{ option.label }}\n </span>\n </slot>\n </button>\n </div>\n</template>\n"],"mappings":"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"}
1
+ {"version":3,"file":"GrSegmented-NKTi9bMG.js","names":[],"sources":["../../../../src/components/shared/truncationTitle.ts","../../../../src/components/GrSegmented/GrSegmented.vue","../../../../src/components/GrSegmented/GrSegmented.vue"],"sourcesContent":["/**\n * Полный текст обрезанной строки — нативной подсказкой по наведению.\n *\n * `truncate` прячет хвост **визуально**: в DOM и для скринридера подпись\n * остаётся целой, поэтому теряет её ровно один читатель — тот, кто смотрит\n * глазами. Он видит «Включе…» и узнать остальное не может ничем.\n *\n * Подсказка ставится **по факту обрезки**, а не всегда: тултип, дублирующий\n * видимую целиком подпись, — шум, которого никто не просил. Замер делается на\n * самом наведении, поэтому ни наблюдателей, ни подписок заводить не нужно.\n *\n * Ширина сравнивается с запасом в пиксель: браузеры считают `scrollWidth`\n * округлением вверх, и у необрезанной строки он бывает на единицу больше\n * `clientWidth` — без запаса подсказка появлялась бы на ровном месте.\n */\nexport function titleWhenTruncated(event: Event): void {\n const element = event.currentTarget\n\n if (!(element instanceof HTMLElement))\n return\n\n // У поля ввода видимая строка живёт в `value`, а не в содержимом узла.\n const source = element instanceof HTMLInputElement ? element.value : element.textContent\n const text = source?.trim() ?? ''\n\n if (text && element.scrollWidth > element.clientWidth + 1)\n element.setAttribute('title', text)\n else\n element.removeAttribute('title')\n}\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { titleWhenTruncated } from '../shared/truncationTitle'\n\nimport type { ComponentPublicInstance } from 'vue'\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport {\n grSegmentedIndicatorClass,\n grSegmentedItemClass,\n grSegmentedItemIconClass,\n grSegmentedItemLabelClass,\n grSegmentedItemSpinnerClass,\n grSegmentedRootClass,\n grSegmentedRootStyle,\n type GrSegmentedOption,\n type GrSegmentedOrientation,\n type GrSegmentedSize,\n type GrSegmentedValue,\n type GrSegmentedVariant,\n} from './grSegmentedStyles'\n\ntype IndicatorGeometry = {\n width: number\n height: number\n x: number\n y: number\n}\n\n/**\n * Пропсы публичного GR-примитива «Segmented».\n */\nexport interface GrSegmentedProps {\n modelValue: GrSegmentedValue\n options: GrSegmentedOption[]\n variant?: GrSegmentedVariant\n size?: GrSegmentedSize\n /**\n * Направление ряда. Вертикаль — боковые фильтры; индикатор к ней готов по\n * построению, он двумерный.\n */\n orientation?: GrSegmentedOrientation\n /** Длительность анимации индикатора в мс. */\n indicatorDuration?: number\n /** Растягивать сегмент на всю ширину контейнера. */\n block?: boolean\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Имя скрытого поля, которым выбранное значение уходит в нативную форму. */\n name?: string\n ariaLabel?: string\n}\n\nexport interface GrSegmentedEmits {\n (e: 'update:modelValue', value: GrSegmentedValue): void\n (e: 'change', value: GrSegmentedValue, option: GrSegmentedOption): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrSegmentedProps>(),\n {\n variant: undefined,\n size: undefined,\n orientation: 'horizontal',\n indicatorDuration: 300,\n block: false,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n name: undefined,\n ariaLabel: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrSegmented' })\nconst resolvedVariant = useGrComponentProp('GrSegmented', 'variant', () => props.variant, 'pills')\n\nconst emit = defineEmits<GrSegmentedEmits>()\ndefineSlots<{\n /** Содержимое сегмента вместо подписи из `options`. */\n default?: (props: {\n option: GrSegmentedOption\n selected: boolean\n disabled: boolean\n loading: boolean\n }) => any\n}>()\n\n// `useId()` стабилен между сервером и клиентом, в отличие от `instance.uid`.\nconst fallbackName = `gr-segmented-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst rootRef = ref<HTMLElement | null>(null)\n\n// Фокус ходит между сегментами: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootRef, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\nconst itemRefs = ref(new Map<string, HTMLElement>())\nconst indicatorGeometry = ref<IndicatorGeometry | null>(null)\nconst indicatorReady = ref(false)\n\nlet resizeObserver: ResizeObserver | null = null\nlet observedRoot: HTMLElement | null = null\nlet observedItem: HTMLElement | null = null\nlet scheduled = false\n\nconst selectedIndex = computed(() => props.options.findIndex(option => option.value === props.modelValue))\nconst selectedOption = computed(() => props.options[selectedIndex.value] ?? null)\nconst indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)))\nconst isVertical = computed(() => props.orientation === 'vertical')\nconst rootClassName = computed(() => grSegmentedRootClass({\n variant: resolvedVariant.value,\n orientation: props.orientation,\n block: props.block,\n disabled: isDisabled.value,\n}))\n\n/**\n * Раскладка задаётся треками, а не классами: число сегментов известно только в\n * рантайме. По вертикали колонка одна — сегменты одинаковой ширины по\n * построению, и `block` решает лишь, занимать ли ширину контейнера.\n */\nconst rootStyle = computed<Record<string, string>>(() => {\n const empty = props.options.length === 0\n const track = () => props.block && !isVertical.value ? 'minmax(0,1fr)' : 'minmax(0,max-content)'\n\n return {\n ...grSegmentedRootStyle({\n variant: resolvedVariant.value,\n size: resolvedSize.value,\n orientation: props.orientation,\n }),\n gridTemplateColumns: isVertical.value\n ? 'minmax(0,1fr)'\n : empty ? 'none' : props.options.map(track).join(' '),\n ...(isVertical.value\n ? { gridTemplateRows: empty ? 'none' : props.options.map(track).join(' ') }\n : {}),\n }\n})\nconst indicatorClassName = computed(() => grSegmentedIndicatorClass(resolvedVariant.value))\nconst resolvedName = computed(() => props.name ?? fallbackName)\nconst hasIndicator = computed(() => selectedIndex.value !== -1 && indicatorGeometry.value !== null)\n\nconst indicatorStyle = computed<Record<string, string>>(() => {\n const geometry = indicatorGeometry.value\n if (!geometry) {\n return {\n opacity: '0',\n width: '0px',\n height: '0px',\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: 'translate3d(0px, 0px, 0px)',\n }\n }\n\n return {\n opacity: indicatorReady.value ? '1' : '0',\n width: `${geometry.width}px`,\n height: `${geometry.height}px`,\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`,\n }\n})\n\nfunction getOptionKey(value: GrSegmentedValue): string {\n return String(value)\n}\n\nfunction resolveOptionDisabled(option: GrSegmentedOption): boolean {\n return isDisabled.value || Boolean(option.disabled)\n}\n\n/**\n * Занятый сегмент не «недоступен», а работает: нативный `disabled` и\n * `aria-disabled` ему не ставим — состояние несёт `aria-busy`. Но выбор он не\n * принимает, поэтому блокировка считается отдельно от `disabled`.\n */\nfunction isOptionBusy(option: GrSegmentedOption): boolean {\n return Boolean(option.loading)\n}\n\nfunction isOptionBlocked(option: GrSegmentedOption): boolean {\n return resolveOptionDisabled(option) || isOptionBusy(option)\n}\n\nfunction isOptionSelected(option: GrSegmentedOption): boolean {\n return option.value === props.modelValue\n}\n\nfunction isIconOnlyOption(option: GrSegmentedOption): boolean {\n return Boolean(option.icon) && !option.label\n}\n\nfunction setItemRef(value: GrSegmentedValue, element: Element | ComponentPublicInstance | null): void {\n const key = getOptionKey(value)\n\n if (!(element instanceof HTMLElement)) {\n itemRefs.value.delete(key)\n return\n }\n\n itemRefs.value.set(key, element)\n}\n\nfunction isSameGeometry(left: IndicatorGeometry | null, right: IndicatorGeometry | null): boolean {\n if (left === right) {\n return true\n }\n\n if (!left || !right) {\n return false\n }\n\n return left.width === right.width\n && left.height === right.height\n && left.x === right.x\n && left.y === right.y\n}\n\nfunction measureIndicator(): void {\n const root = rootRef.value\n const option = selectedOption.value\n if (!root || !option) {\n if (indicatorGeometry.value !== null)\n indicatorGeometry.value = null\n\n if (indicatorReady.value)\n indicatorReady.value = false\n\n return\n }\n\n const selectedItem = itemRefs.value.get(getOptionKey(option.value))\n if (!selectedItem) {\n return\n }\n\n const rootRect = root.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const nextGeometry = {\n width: Math.max(Math.round(itemRect.width), 0),\n height: Math.max(Math.round(itemRect.height), 0),\n x: Math.round(itemRect.left - rootRect.left),\n y: Math.max(Math.round(itemRect.top - rootRect.top) - 1, 0),\n } satisfies IndicatorGeometry\n\n if (!isSameGeometry(indicatorGeometry.value, nextGeometry)) {\n indicatorGeometry.value = nextGeometry\n }\n\n const nextReady = nextGeometry.width > 0 && nextGeometry.height > 0\n if (indicatorReady.value !== nextReady) {\n indicatorReady.value = nextReady\n }\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n const root = rootRef.value\n const option = selectedOption.value\n const selectedItem = option\n ? itemRefs.value.get(getOptionKey(option.value)) ?? null\n : null\n\n if (!resizeObserver) {\n resizeObserver = new ResizeObserver(() => scheduleMeasure())\n }\n\n if (!root) {\n resizeObserver.disconnect()\n observedRoot = null\n observedItem = null\n return\n }\n\n if (observedRoot === root && observedItem === selectedItem) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver.observe(root)\n\n if (selectedItem) {\n resizeObserver.observe(selectedItem)\n }\n\n observedRoot = root\n observedItem = selectedItem\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) {\n return\n }\n\n scheduled = true\n void nextTick(() => {\n scheduled = false\n measureIndicator()\n refreshObserver()\n })\n}\n\nfunction emitValue(option: GrSegmentedOption): void {\n // Один guard на все пути: проверяй `readonly` только клавиатура, и клик по\n // сегменту менял бы значение вопреки заявленному контракту.\n if (isReadonly.value || isOptionBlocked(option) || option.value === props.modelValue) {\n return\n }\n\n emit('update:modelValue', option.value)\n emit('change', option.value, option)\n}\n\nfunction optionOf(value: GrSegmentedValue): GrSegmentedOption | undefined {\n return props.options.find(option => option.value === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента\n * описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —\n * вертикальный набор листается и стрелками влево/вправо.\n */\nconst roving = useRovingFocus<GrSegmentedValue>({\n items: () => props.options.map(option => option.value),\n elementFor: value => itemRefs.value.get(getOptionKey(value)),\n isDisabled: (value) => {\n const option = optionOf(value)\n return option ? isOptionBlocked(option) : true\n },\n orientation: () => 'both',\n skipDisabled: () => true,\n /**\n * Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём\n * стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся\n * остановку сохраняет: он не «недоступен», а занят.\n */\n initialKey: () => {\n const selected = selectedOption.value\n return selected && !resolveOptionDisabled(selected) ? selected.value : undefined\n },\n // Стрелка в `radiogroup` переносит и выбор, а не только фокус.\n onMove: (value) => {\n const option = optionOf(value)\n if (option)\n emitValue(option)\n },\n})\n\nfunction onItemClick(option: GrSegmentedOption): void {\n emitValue(option)\n // Клик тоже переносит остановку `Tab`: иначе она осталась бы там, куда её\n // увела последняя стрелка.\n if (!isOptionBlocked(option))\n roving.setActive(option.value)\n}\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */\nfunction rovingElement(): HTMLElement | undefined {\n const key = roving.rovingKey.value\n return key === undefined ? undefined : itemRefs.value.get(getOptionKey(key))\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number): void {\n if (isDisabled.value || isReadonly.value) {\n return\n }\n\n if (roving.handleNavigationKeys(event)) {\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n const option = props.options[index]\n if (option) {\n emitValue(option)\n }\n }\n}\n\nwatch(() => props.modelValue, () => scheduleMeasure())\nwatch(() => props.options, () => scheduleMeasure(), { deep: true })\nwatch(resolvedVariant, () => scheduleMeasure())\nwatch(resolvedSize, () => scheduleMeasure())\nwatch(() => props.block, () => scheduleMeasure())\n// Смена ориентации переставляет сегменты: без пересчёта индикатор остался бы в\n// координатах прежней раскладки.\nwatch(() => props.orientation, () => scheduleMeasure())\n\nonMounted(() => scheduleMeasure())\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n observedRoot = null\n observedItem = null\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootRef\"\n data-gr-segmented\n :data-variant=\"resolvedVariant\"\n role=\"radiogroup\"\n :aria-orientation=\"orientation\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :class=\"rootClassName\"\n :style=\"rootStyle\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Значение для нативной формы уходит одним скрытым полем рядом с\n сегментами, а не вложенным в каждый `role=\"radio\"`: роль объявляет своих\n потомков презентационными, и вложенный интерактивный контрол ломает\n виджет для скринридеров (axe: `nested-interactive`). Скрытое поле не\n фокусируется и интерактивным не считается. -->\n <input\n v-if=\"selectedOption && !resolveOptionDisabled(selectedOption)\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"String(selectedOption.value)\"\n >\n\n <span\n v-if=\"hasIndicator\"\n data-gr-segmented-indicator\n aria-hidden=\"true\"\n :class=\"indicatorClassName\"\n :style=\"indicatorStyle\"\n />\n\n <button\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :ref=\"element => setItemRef(option.value, element)\"\n data-gr-segmented-item\n :data-value=\"String(option.value)\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"option.ariaLabel\"\n :aria-checked=\"isOptionSelected(option) ? 'true' : 'false'\"\n :aria-disabled=\"resolveOptionDisabled(option) ? 'true' : undefined\"\n :aria-busy=\"isOptionBusy(option) ? 'true' : undefined\"\n :disabled=\"resolveOptionDisabled(option)\"\n :tabindex=\"roving.tabindexFor(option.value)\"\n :class=\"grSegmentedItemClass({\n variant: resolvedVariant,\n selected: isOptionSelected(option),\n disabled: resolveOptionDisabled(option),\n iconOnly: isIconOnlyOption(option),\n })\"\n @click=\"onItemClick(option)\"\n @keydown=\"onKeydown($event, index)\"\n >\n <slot\n :option=\"option\"\n :selected=\"isOptionSelected(option)\"\n :disabled=\"resolveOptionDisabled(option)\"\n :loading=\"isOptionBusy(option)\"\n >\n <!-- Спиннер занимает место иконки: две крутилки рядом читались бы как ошибка. -->\n <IconLoader\n v-if=\"isOptionBusy(option)\"\n data-gr-segmented-spinner\n aria-hidden=\"true\"\n :class=\"grSegmentedItemSpinnerClass\"\n />\n <component\n :is=\"option.icon\"\n v-else-if=\"option.icon\"\n aria-hidden=\"true\"\n :class=\"grSegmentedItemIconClass\"\n />\n <!-- Подпись сегмента обрезается по ширине трека, и «Включе…» без\n подсказки прочитать нечем: полный текст отдаётся по наведению. -->\n <span\n v-if=\"option.label\"\n :class=\"grSegmentedItemLabelClass\"\n @pointerenter=\"titleWhenTruncated\"\n >\n {{ option.label }}\n </span>\n </slot>\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { titleWhenTruncated } from '../shared/truncationTitle'\n\nimport type { ComponentPublicInstance } from 'vue'\nimport IconLoader from '~icons/lucide/loader-circle'\n\nimport {\n grSegmentedIndicatorClass,\n grSegmentedItemClass,\n grSegmentedItemIconClass,\n grSegmentedItemLabelClass,\n grSegmentedItemSpinnerClass,\n grSegmentedRootClass,\n grSegmentedRootStyle,\n type GrSegmentedOption,\n type GrSegmentedOrientation,\n type GrSegmentedSize,\n type GrSegmentedValue,\n type GrSegmentedVariant,\n} from './grSegmentedStyles'\n\ntype IndicatorGeometry = {\n width: number\n height: number\n x: number\n y: number\n}\n\n/**\n * Пропсы публичного GR-примитива «Segmented».\n */\nexport interface GrSegmentedProps {\n modelValue: GrSegmentedValue\n options: GrSegmentedOption[]\n variant?: GrSegmentedVariant\n size?: GrSegmentedSize\n /**\n * Направление ряда. Вертикаль — боковые фильтры; индикатор к ней готов по\n * построению, он двумерный.\n */\n orientation?: GrSegmentedOrientation\n /** Длительность анимации индикатора в мс. */\n indicatorDuration?: number\n /** Растягивать сегмент на всю ширину контейнера. */\n block?: boolean\n disabled?: boolean\n /** Только для чтения: выбор видно, но он не меняется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n /** Имя скрытого поля, которым выбранное значение уходит в нативную форму. */\n name?: string\n ariaLabel?: string\n}\n\nexport interface GrSegmentedEmits {\n (e: 'update:modelValue', value: GrSegmentedValue): void\n (e: 'change', value: GrSegmentedValue, option: GrSegmentedOption): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrSegmentedProps>(),\n {\n variant: undefined,\n size: undefined,\n orientation: 'horizontal',\n indicatorDuration: 300,\n block: false,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n name: undefined,\n ariaLabel: undefined,\n },\n)\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrSegmented' })\nconst resolvedVariant = useGrComponentProp('GrSegmented', 'variant', () => props.variant, 'pills')\n\nconst emit = defineEmits<GrSegmentedEmits>()\ndefineSlots<{\n /** Содержимое сегмента вместо подписи из `options`. */\n default?: (props: {\n option: GrSegmentedOption\n selected: boolean\n disabled: boolean\n loading: boolean\n }) => any\n}>()\n\n// `useId()` стабилен между сервером и клиентом, в отличие от `instance.uid`.\nconst fallbackName = `gr-segmented-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst labelledBy = computed(() => (props.ariaLabel ? undefined : field?.labelId.value))\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\nconst rootRef = ref<HTMLElement | null>(null)\n\n// Фокус ходит между сегментами: без границы каждая стрелка давала бы\n// потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootRef, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\n\ndefineExpose({ focus, blur })\nconst itemRefs = ref(new Map<string, HTMLElement>())\nconst indicatorGeometry = ref<IndicatorGeometry | null>(null)\nconst indicatorReady = ref(false)\n\nlet resizeObserver: ResizeObserver | null = null\nlet observedRoot: HTMLElement | null = null\nlet observedItem: HTMLElement | null = null\nlet scheduled = false\n\nconst selectedIndex = computed(() => props.options.findIndex(option => option.value === props.modelValue))\nconst selectedOption = computed(() => props.options[selectedIndex.value] ?? null)\nconst indicatorDuration = computed(() => Math.max(0, Math.round(props.indicatorDuration)))\nconst isVertical = computed(() => props.orientation === 'vertical')\nconst rootClassName = computed(() => grSegmentedRootClass({\n variant: resolvedVariant.value,\n orientation: props.orientation,\n block: props.block,\n disabled: isDisabled.value,\n}))\n\n/**\n * Раскладка задаётся треками, а не классами: число сегментов известно только в\n * рантайме. По вертикали колонка одна — сегменты одинаковой ширины по\n * построению, и `block` решает лишь, занимать ли ширину контейнера.\n */\nconst rootStyle = computed<Record<string, string>>(() => {\n const empty = props.options.length === 0\n const track = () => props.block && !isVertical.value ? 'minmax(0,1fr)' : 'minmax(0,max-content)'\n\n return {\n ...grSegmentedRootStyle({\n variant: resolvedVariant.value,\n size: resolvedSize.value,\n orientation: props.orientation,\n }),\n gridTemplateColumns: isVertical.value\n ? 'minmax(0,1fr)'\n : empty ? 'none' : props.options.map(track).join(' '),\n ...(isVertical.value\n ? { gridTemplateRows: empty ? 'none' : props.options.map(track).join(' ') }\n : {}),\n }\n})\nconst indicatorClassName = computed(() => grSegmentedIndicatorClass(resolvedVariant.value))\nconst resolvedName = computed(() => props.name ?? fallbackName)\nconst hasIndicator = computed(() => selectedIndex.value !== -1 && indicatorGeometry.value !== null)\n\nconst indicatorStyle = computed<Record<string, string>>(() => {\n const geometry = indicatorGeometry.value\n if (!geometry) {\n return {\n opacity: '0',\n width: '0px',\n height: '0px',\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: 'translate3d(0px, 0px, 0px)',\n }\n }\n\n return {\n opacity: indicatorReady.value ? '1' : '0',\n width: `${geometry.width}px`,\n height: `${geometry.height}px`,\n transitionDuration: `${indicatorDuration.value}ms`,\n transform: `translate3d(${geometry.x}px, ${geometry.y}px, 0)`,\n }\n})\n\nfunction getOptionKey(value: GrSegmentedValue): string {\n return String(value)\n}\n\nfunction resolveOptionDisabled(option: GrSegmentedOption): boolean {\n return isDisabled.value || Boolean(option.disabled)\n}\n\n/**\n * Занятый сегмент не «недоступен», а работает: нативный `disabled` и\n * `aria-disabled` ему не ставим — состояние несёт `aria-busy`. Но выбор он не\n * принимает, поэтому блокировка считается отдельно от `disabled`.\n */\nfunction isOptionBusy(option: GrSegmentedOption): boolean {\n return Boolean(option.loading)\n}\n\nfunction isOptionBlocked(option: GrSegmentedOption): boolean {\n return resolveOptionDisabled(option) || isOptionBusy(option)\n}\n\nfunction isOptionSelected(option: GrSegmentedOption): boolean {\n return option.value === props.modelValue\n}\n\nfunction isIconOnlyOption(option: GrSegmentedOption): boolean {\n return Boolean(option.icon) && !option.label\n}\n\nfunction setItemRef(value: GrSegmentedValue, element: Element | ComponentPublicInstance | null): void {\n const key = getOptionKey(value)\n\n if (!(element instanceof HTMLElement)) {\n itemRefs.value.delete(key)\n return\n }\n\n itemRefs.value.set(key, element)\n}\n\nfunction isSameGeometry(left: IndicatorGeometry | null, right: IndicatorGeometry | null): boolean {\n if (left === right) {\n return true\n }\n\n if (!left || !right) {\n return false\n }\n\n return left.width === right.width\n && left.height === right.height\n && left.x === right.x\n && left.y === right.y\n}\n\nfunction measureIndicator(): void {\n const root = rootRef.value\n const option = selectedOption.value\n if (!root || !option) {\n if (indicatorGeometry.value !== null)\n indicatorGeometry.value = null\n\n if (indicatorReady.value)\n indicatorReady.value = false\n\n return\n }\n\n const selectedItem = itemRefs.value.get(getOptionKey(option.value))\n if (!selectedItem) {\n return\n }\n\n const rootRect = root.getBoundingClientRect()\n const itemRect = selectedItem.getBoundingClientRect()\n\n const nextGeometry = {\n width: Math.max(Math.round(itemRect.width), 0),\n height: Math.max(Math.round(itemRect.height), 0),\n x: Math.round(itemRect.left - rootRect.left),\n y: Math.max(Math.round(itemRect.top - rootRect.top) - 1, 0),\n } satisfies IndicatorGeometry\n\n if (!isSameGeometry(indicatorGeometry.value, nextGeometry)) {\n indicatorGeometry.value = nextGeometry\n }\n\n const nextReady = nextGeometry.width > 0 && nextGeometry.height > 0\n if (indicatorReady.value !== nextReady) {\n indicatorReady.value = nextReady\n }\n}\n\nfunction refreshObserver(): void {\n if (typeof ResizeObserver === 'undefined') {\n return\n }\n\n const root = rootRef.value\n const option = selectedOption.value\n const selectedItem = option\n ? itemRefs.value.get(getOptionKey(option.value)) ?? null\n : null\n\n if (!resizeObserver) {\n resizeObserver = new ResizeObserver(() => scheduleMeasure())\n }\n\n if (!root) {\n resizeObserver.disconnect()\n observedRoot = null\n observedItem = null\n return\n }\n\n if (observedRoot === root && observedItem === selectedItem) {\n return\n }\n\n resizeObserver.disconnect()\n resizeObserver.observe(root)\n\n if (selectedItem) {\n resizeObserver.observe(selectedItem)\n }\n\n observedRoot = root\n observedItem = selectedItem\n}\n\nfunction scheduleMeasure(): void {\n if (scheduled) {\n return\n }\n\n scheduled = true\n void nextTick(() => {\n scheduled = false\n measureIndicator()\n refreshObserver()\n })\n}\n\nfunction emitValue(option: GrSegmentedOption): void {\n // Один guard на все пути: проверяй `readonly` только клавиатура, и клик по\n // сегменту менял бы значение вопреки заявленному контракту.\n if (isReadonly.value || isOptionBlocked(option) || option.value === props.modelValue) {\n return\n }\n\n emit('update:modelValue', option.value)\n emit('change', option.value, option)\n}\n\nfunction optionOf(value: GrSegmentedValue): GrSegmentedOption | undefined {\n return props.options.find(option => option.value === value)\n}\n\n/**\n * Кольцо roving-фокуса. Обе оси работают всегда: `orientation` у сегмента\n * описывает раскладку и уходит в `aria-orientation`, а не сужает клавиатуру —\n * вертикальный набор листается и стрелками влево/вправо.\n */\nconst roving = useRovingFocus<GrSegmentedValue>({\n items: () => props.options.map(option => option.value),\n elementFor: value => itemRefs.value.get(getOptionKey(value)),\n isDisabled: (value) => {\n const option = optionOf(value)\n return option ? isOptionBlocked(option) : true\n },\n orientation: () => 'both',\n skipDisabled: () => true,\n /**\n * Выбранный сегмент держит остановку `Tab` — кроме выключенного: на нём\n * стоит нативный `disabled`, и фокус на него не встанет вовсе. Загружающийся\n * остановку сохраняет: он не «недоступен», а занят.\n */\n initialKey: () => {\n const selected = selectedOption.value\n return selected && !resolveOptionDisabled(selected) ? selected.value : undefined\n },\n // Стрелка в `radiogroup` переносит и выбор, а не только фокус.\n onMove: (value) => {\n const option = optionOf(value)\n if (option)\n emitValue(option)\n },\n})\n\nfunction onItemClick(option: GrSegmentedOption): void {\n emitValue(option)\n // Клик тоже переносит остановку `Tab`: иначе она осталась бы там, куда её\n // увела последняя стрелка.\n if (!isOptionBlocked(option))\n roving.setActive(option.value)\n}\n\n/** Императивный фокус ведёт на текущую остановку `Tab`, а не на первый сегмент. */\nfunction rovingElement(): HTMLElement | undefined {\n const key = roving.rovingKey.value\n return key === undefined ? undefined : itemRefs.value.get(getOptionKey(key))\n}\n\nfunction focus(): void {\n rovingElement()?.focus()\n}\n\nfunction blur(): void {\n rovingElement()?.blur()\n}\n\nfunction onKeydown(event: KeyboardEvent, index: number): void {\n if (isDisabled.value || isReadonly.value) {\n return\n }\n\n if (roving.handleNavigationKeys(event)) {\n return\n }\n\n if (event.key === ' ' || event.key === 'Enter') {\n event.preventDefault()\n const option = props.options[index]\n if (option) {\n emitValue(option)\n }\n }\n}\n\nwatch(() => props.modelValue, () => scheduleMeasure())\nwatch(() => props.options, () => scheduleMeasure(), { deep: true })\nwatch(resolvedVariant, () => scheduleMeasure())\nwatch(resolvedSize, () => scheduleMeasure())\nwatch(() => props.block, () => scheduleMeasure())\n// Смена ориентации переставляет сегменты: без пересчёта индикатор остался бы в\n// координатах прежней раскладки.\nwatch(() => props.orientation, () => scheduleMeasure())\n\nonMounted(() => scheduleMeasure())\nonBeforeUnmount(() => {\n resizeObserver?.disconnect()\n observedRoot = null\n observedItem = null\n})\n</script>\n\n<template>\n <div\n :id=\"fieldId\"\n ref=\"rootRef\"\n data-gr-segmented\n :data-variant=\"resolvedVariant\"\n role=\"radiogroup\"\n :aria-orientation=\"orientation\"\n :aria-label=\"ariaLabel\"\n :aria-labelledby=\"labelledBy\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-disabled=\"isDisabled ? 'true' : undefined\"\n :class=\"rootClassName\"\n :style=\"rootStyle\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Значение для нативной формы уходит одним скрытым полем рядом с\n сегментами, а не вложенным в каждый `role=\"radio\"`: роль объявляет своих\n потомков презентационными, и вложенный интерактивный контрол ломает\n виджет для скринридеров (axe: `nested-interactive`). Скрытое поле не\n фокусируется и интерактивным не считается. -->\n <input\n v-if=\"selectedOption && !resolveOptionDisabled(selectedOption)\"\n type=\"hidden\"\n :name=\"resolvedName\"\n :value=\"String(selectedOption.value)\"\n >\n\n <span\n v-if=\"hasIndicator\"\n data-gr-segmented-indicator\n aria-hidden=\"true\"\n :class=\"indicatorClassName\"\n :style=\"indicatorStyle\"\n />\n\n <button\n v-for=\"(option, index) in options\"\n :key=\"option.value\"\n :ref=\"element => setItemRef(option.value, element)\"\n data-gr-segmented-item\n :data-value=\"String(option.value)\"\n type=\"button\"\n role=\"radio\"\n :aria-label=\"option.ariaLabel\"\n :aria-checked=\"isOptionSelected(option) ? 'true' : 'false'\"\n :aria-disabled=\"resolveOptionDisabled(option) ? 'true' : undefined\"\n :aria-busy=\"isOptionBusy(option) ? 'true' : undefined\"\n :disabled=\"resolveOptionDisabled(option)\"\n :tabindex=\"roving.tabindexFor(option.value)\"\n :class=\"grSegmentedItemClass({\n variant: resolvedVariant,\n selected: isOptionSelected(option),\n disabled: resolveOptionDisabled(option),\n iconOnly: isIconOnlyOption(option),\n })\"\n @click=\"onItemClick(option)\"\n @keydown=\"onKeydown($event, index)\"\n >\n <slot\n :option=\"option\"\n :selected=\"isOptionSelected(option)\"\n :disabled=\"resolveOptionDisabled(option)\"\n :loading=\"isOptionBusy(option)\"\n >\n <!-- Спиннер занимает место иконки: две крутилки рядом читались бы как ошибка. -->\n <IconLoader\n v-if=\"isOptionBusy(option)\"\n data-gr-segmented-spinner\n aria-hidden=\"true\"\n :class=\"grSegmentedItemSpinnerClass\"\n />\n <component\n :is=\"option.icon\"\n v-else-if=\"option.icon\"\n aria-hidden=\"true\"\n :class=\"grSegmentedItemIconClass\"\n />\n <!-- Подпись сегмента обрезается по ширине трека, и «Включе…» без\n подсказки прочитать нечем: полный текст отдаётся по наведению. -->\n <span\n v-if=\"option.label\"\n :class=\"grSegmentedItemLabelClass\"\n @pointerenter=\"titleWhenTruncated\"\n >\n {{ option.label }}\n </span>\n </slot>\n </button>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAeA,SAAgB,mBAAmB,OAAoB;CACrD,MAAM,UAAU,MAAM;CAEtB,IAAI,EAAE,mBAAmB,cACvB;CAIF,MAAM,QADS,mBAAmB,mBAAmB,QAAQ,QAAQ,QAAQ,YAAA,EACxD,KAAK,KAAK;CAE/B,IAAI,QAAQ,QAAQ,cAAc,QAAQ,cAAc,GACtD,QAAQ,aAAa,SAAS,IAAI;MAElC,QAAQ,gBAAgB,OAAO;AACnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC0CA,MAAM,QAAQ;EAkBd,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,cAAc,CAAC;EACtF,MAAM,kBAAkB,mBAAmB,eAAe,iBAAiB,MAAM,SAAS,OAAO;EAEjG,MAAM,OAAO;EAYb,MAAM,eAAe,gBAAgB,MAAM;EAG3C,MAAM,QAAQ,sBAAsB;EACpC,MAAM,UAAU,eAAe,OAAO,GAAG,KAAK;EAC9C,MAAM,cAAc,eAAe,OAAO,cAAc,KAAK;EAC7D,MAAM,aAAa,eAAgB,MAAM,YAAY,KAAA,IAAY,OAAO,QAAQ,KAAM;EACtF,MAAM,EACJ,UAAU,YACV,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;EAEhC,MAAM,UAAU,IAAwB,IAAI;EAI5C,MAAM,EAAE,WAAW,eAAe,eAAe,SAAS;GACxD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;EACpC,CAAC;EAED,SAAa;GAAE;GAAO;EAAK,CAAC;EAC5B,MAAM,WAAW,oBAAI,IAAI,IAAyB,CAAC;EACnD,MAAM,oBAAoB,IAA8B,IAAI;EAC5D,MAAM,iBAAiB,IAAI,KAAK;EAEhC,IAAI,iBAAwC;EAC5C,IAAI,eAAmC;EACvC,IAAI,eAAmC;EACvC,IAAI,YAAY;EAEhB,MAAM,gBAAgB,eAAe,MAAM,QAAQ,WAAU,WAAU,OAAO,UAAU,MAAM,UAAU,CAAC;EACzG,MAAM,iBAAiB,eAAe,MAAM,QAAQ,cAAc,UAAU,IAAI;EAChF,MAAM,oBAAoB,eAAe,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,iBAAiB,CAAC,CAAC;EACzF,MAAM,aAAa,eAAe,MAAM,gBAAgB,UAAU;EAClE,MAAM,gBAAgB,eAAe,qBAAqB;GACxD,SAAS,gBAAgB;GACzB,aAAa,MAAM;GACnB,OAAO,MAAM;GACb,UAAU,WAAW;EACvB,CAAC,CAAC;;;;;;EAOF,MAAM,YAAY,eAAuC;GACvD,MAAM,QAAQ,MAAM,QAAQ,WAAW;GACvC,MAAM,cAAc,MAAM,SAAS,CAAC,WAAW,QAAQ,kBAAkB;GAEzE,OAAO;IACL,GAAG,qBAAqB;KACtB,SAAS,gBAAgB;KACzB,MAAM,aAAa;KACnB,aAAa,MAAM;IACrB,CAAC;IACD,qBAAqB,WAAW,QAC5B,kBACA,QAAQ,SAAS,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,KAAK,GAAG;IACtD,GAAI,WAAW,QACX,EAAE,kBAAkB,QAAQ,SAAS,MAAM,QAAQ,IAAI,KAAK,CAAC,CAAC,KAAK,GAAG,EAAE,IACxE,CAAC;GACP;EACF,CAAC;EACD,MAAM,qBAAqB,eAAe,0BAA0B,gBAAgB,KAAK,CAAC;EAC1F,MAAM,eAAe,eAAe,MAAM,QAAQ,YAAY;EAC9D,MAAM,eAAe,eAAe,cAAc,UAAU,MAAM,kBAAkB,UAAU,IAAI;EAElG,MAAM,iBAAiB,eAAuC;GAC5D,MAAM,WAAW,kBAAkB;GACnC,IAAI,CAAC,UACH,OAAO;IACL,SAAS;IACT,OAAO;IACP,QAAQ;IACR,oBAAoB,GAAG,kBAAkB,MAAM;IAC/C,WAAW;GACb;GAGF,OAAO;IACL,SAAS,eAAe,QAAQ,MAAM;IACtC,OAAO,GAAG,SAAS,MAAM;IACzB,QAAQ,GAAG,SAAS,OAAO;IAC3B,oBAAoB,GAAG,kBAAkB,MAAM;IAC/C,WAAW,eAAe,SAAS,EAAE,MAAM,SAAS,EAAE;GACxD;EACF,CAAC;EAED,SAAS,aAAa,OAAiC;GACrD,OAAO,OAAO,KAAK;EACrB;EAEA,SAAS,sBAAsB,QAAoC;GACjE,OAAO,WAAW,SAAS,QAAQ,OAAO,QAAQ;EACpD;;;;;;EAOA,SAAS,aAAa,QAAoC;GACxD,OAAO,QAAQ,OAAO,OAAO;EAC/B;EAEA,SAAS,gBAAgB,QAAoC;GAC3D,OAAO,sBAAsB,MAAM,KAAK,aAAa,MAAM;EAC7D;EAEA,SAAS,iBAAiB,QAAoC;GAC5D,OAAO,OAAO,UAAU,MAAM;EAChC;EAEA,SAAS,iBAAiB,QAAoC;GAC5D,OAAO,QAAQ,OAAO,IAAI,KAAK,CAAC,OAAO;EACzC;EAEA,SAAS,WAAW,OAAyB,SAAyD;GACpG,MAAM,MAAM,aAAa,KAAK;GAE9B,IAAI,EAAE,mBAAmB,cAAc;IACrC,SAAS,MAAM,OAAO,GAAG;IACzB;GACF;GAEA,SAAS,MAAM,IAAI,KAAK,OAAO;EACjC;EAEA,SAAS,eAAe,MAAgC,OAA0C;GAChG,IAAI,SAAS,OACX,OAAO;GAGT,IAAI,CAAC,QAAQ,CAAC,OACZ,OAAO;GAGT,OAAO,KAAK,UAAU,MAAM,SACvB,KAAK,WAAW,MAAM,UACtB,KAAK,MAAM,MAAM,KACjB,KAAK,MAAM,MAAM;EACxB;EAEA,SAAS,mBAAyB;GAChC,MAAM,OAAO,QAAQ;GACrB,MAAM,SAAS,eAAe;GAC9B,IAAI,CAAC,QAAQ,CAAC,QAAQ;IACpB,IAAI,kBAAkB,UAAU,MAC9B,kBAAkB,QAAQ;IAE5B,IAAI,eAAe,OACjB,eAAe,QAAQ;IAEzB;GACF;GAEA,MAAM,eAAe,SAAS,MAAM,IAAI,aAAa,OAAO,KAAK,CAAC;GAClE,IAAI,CAAC,cACH;GAGF,MAAM,WAAW,KAAK,sBAAsB;GAC5C,MAAM,WAAW,aAAa,sBAAsB;GAEpD,MAAM,eAAe;IACnB,OAAO,KAAK,IAAI,KAAK,MAAM,SAAS,KAAK,GAAG,CAAC;IAC7C,QAAQ,KAAK,IAAI,KAAK,MAAM,SAAS,MAAM,GAAG,CAAC;IAC/C,GAAG,KAAK,MAAM,SAAS,OAAO,SAAS,IAAI;IAC3C,GAAG,KAAK,IAAI,KAAK,MAAM,SAAS,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;GAC5D;GAEA,IAAI,CAAC,eAAe,kBAAkB,OAAO,YAAY,GACvD,kBAAkB,QAAQ;GAG5B,MAAM,YAAY,aAAa,QAAQ,KAAK,aAAa,SAAS;GAClE,IAAI,eAAe,UAAU,WAC3B,eAAe,QAAQ;EAE3B;EAEA,SAAS,kBAAwB;GAC/B,IAAI,OAAO,mBAAmB,aAC5B;GAGF,MAAM,OAAO,QAAQ;GACrB,MAAM,SAAS,eAAe;GAC9B,MAAM,eAAe,SACjB,SAAS,MAAM,IAAI,aAAa,OAAO,KAAK,CAAC,KAAK,OAClD;GAEJ,IAAI,CAAC,gBACH,iBAAiB,IAAI,qBAAqB,gBAAgB,CAAC;GAG7D,IAAI,CAAC,MAAM;IACT,eAAe,WAAW;IAC1B,eAAe;IACf,eAAe;IACf;GACF;GAEA,IAAI,iBAAiB,QAAQ,iBAAiB,cAC5C;GAGF,eAAe,WAAW;GAC1B,eAAe,QAAQ,IAAI;GAE3B,IAAI,cACF,eAAe,QAAQ,YAAY;GAGrC,eAAe;GACf,eAAe;EACjB;EAEA,SAAS,kBAAwB;GAC/B,IAAI,WACF;GAGF,YAAY;GACZ,eAAoB;IAClB,YAAY;IACZ,iBAAiB;IACjB,gBAAgB;GAClB,CAAC;EACH;EAEA,SAAS,UAAU,QAAiC;GAGlD,IAAI,WAAW,SAAS,gBAAgB,MAAM,KAAK,OAAO,UAAU,MAAM,YACxE;GAGF,KAAK,qBAAqB,OAAO,KAAK;GACtC,KAAK,UAAU,OAAO,OAAO,MAAM;EACrC;EAEA,SAAS,SAAS,OAAwD;GACxE,OAAO,MAAM,QAAQ,MAAK,WAAU,OAAO,UAAU,KAAK;EAC5D;;;;;;EAOA,MAAM,SAAS,eAAiC;GAC9C,aAAa,MAAM,QAAQ,KAAI,WAAU,OAAO,KAAK;GACrD,aAAY,UAAS,SAAS,MAAM,IAAI,aAAa,KAAK,CAAC;GAC3D,aAAa,UAAU;IACrB,MAAM,SAAS,SAAS,KAAK;IAC7B,OAAO,SAAS,gBAAgB,MAAM,IAAI;GAC5C;GACA,mBAAmB;GACnB,oBAAoB;;;;;;GAMpB,kBAAkB;IAChB,MAAM,WAAW,eAAe;IAChC,OAAO,YAAY,CAAC,sBAAsB,QAAQ,IAAI,SAAS,QAAQ,KAAA;GACzE;GAEA,SAAS,UAAU;IACjB,MAAM,SAAS,SAAS,KAAK;IAC7B,IAAI,QACF,UAAU,MAAM;GACpB;EACF,CAAC;EAED,SAAS,YAAY,QAAiC;GACpD,UAAU,MAAM;GAGhB,IAAI,CAAC,gBAAgB,MAAM,GACzB,OAAO,UAAU,OAAO,KAAK;EACjC;;EAGA,SAAS,gBAAyC;GAChD,MAAM,MAAM,OAAO,UAAU;GAC7B,OAAO,QAAQ,KAAA,IAAY,KAAA,IAAY,SAAS,MAAM,IAAI,aAAa,GAAG,CAAC;EAC7E;EAEA,SAAS,QAAc;GACrB,cAAc,CAAC,EAAE,MAAM;EACzB;EAEA,SAAS,OAAa;GACpB,cAAc,CAAC,EAAE,KAAK;EACxB;EAEA,SAAS,UAAU,OAAsB,OAAqB;GAC5D,IAAI,WAAW,SAAS,WAAW,OACjC;GAGF,IAAI,OAAO,qBAAqB,KAAK,GACnC;GAGF,IAAI,MAAM,QAAQ,OAAO,MAAM,QAAQ,SAAS;IAC9C,MAAM,eAAe;IACrB,MAAM,SAAS,MAAM,QAAQ;IAC7B,IAAI,QACF,UAAU,MAAM;GAEpB;EACF;EAEA,YAAY,MAAM,kBAAkB,gBAAgB,CAAC;EACrD,YAAY,MAAM,eAAe,gBAAgB,GAAG,EAAE,MAAM,KAAK,CAAC;EAClE,MAAM,uBAAuB,gBAAgB,CAAC;EAC9C,MAAM,oBAAoB,gBAAgB,CAAC;EAC3C,YAAY,MAAM,aAAa,gBAAgB,CAAC;EAGhD,YAAY,MAAM,mBAAmB,gBAAgB,CAAC;EAEtD,gBAAgB,gBAAgB,CAAC;EACjC,sBAAsB;GACpB,gBAAgB,WAAW;GAC3B,eAAe;GACf,eAAe;EACjB,CAAC;;GAIC,OAAA,UAAA,GAAA,mBA4FM,OAAA;IA3FH,IAAI,QAAA;IACD,SAAA;IAAJ,KAAI;IACJ,qBAAA;IACC,gBAAc,MAAA,eAAA;IACf,MAAK;IACJ,oBAAkB,QAAA;IAClB,cAAY,QAAA;IACZ,mBAAiB,WAAA;IACjB,oBAAkB,YAAA;IAClB,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;IACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;IACrC,OAAK,eAAE,cAAA,KAAa;IACpB,OAAK,eAAE,UAAA,KAAS;IAChB,WAAO,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACT,YAAQ,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;;IAQH,eAAA,SAAc,CAAK,sBAAsB,eAAA,KAAc,KAD/D,UAAA,GAAA,mBAKC,SAAA;;KAHC,MAAK;KACJ,MAAM,aAAA;KACN,OAAO,OAAO,eAAA,MAAe,KAAK;;IAI7B,aAAA,SADR,UAAA,GAAA,mBAME,QAAA;;KAJA,+BAAA;KACA,eAAY;KACX,OAAK,eAAE,mBAAA,KAAkB;KACzB,OAAK,eAAE,eAAA,KAAc;;KAGxB,UAAA,IAAA,GAAA,mBAoDS,UAAA,MAAA,WAnDmB,QAAA,UAAlB,QAAQ,UAAK;KADvB,OAAA,UAAA,GAAA,mBAoDS,UAAA;MAlDN,KAAK,OAAO;;MACZ,MAAK,YAAW,WAAW,OAAO,OAAO,OAAO;MACjD,0BAAA;MACC,cAAY,OAAO,OAAO,KAAK;MAChC,MAAK;MACL,MAAK;MACJ,cAAY,OAAO;MACnB,gBAAc,iBAAiB,MAAM,IAAA,SAAA;MACrC,iBAAe,sBAAsB,MAAM,IAAA,SAAa,KAAA;MACxD,aAAW,aAAa,MAAM,IAAA,SAAa,KAAA;MAC3C,UAAU,sBAAsB,MAAM;MACtC,UAAU,MAAA,MAAA,CAAM,CAAC,YAAY,OAAO,KAAK;MACzC,OAAK,eAAE,MAAA,oBAAA,CAAoB,CAAA;OAAoB,SAAA,MAAA,eAAA;OAAmC,UAAA,iBAAiB,MAAM;OAAqB,UAAA,sBAAsB,MAAM;OAAqB,UAAA,iBAAiB,MAAM;;MAMtM,UAAK,WAAE,YAAY,MAAM;MACzB,YAAO,WAAE,UAAU,QAAQ,KAAK;KAEjC,GAAA,CAAA,WA4BO,KAAA,QAAA,WAAA;MA3BI;MACR,UAAU,iBAAiB,MAAM;MACjC,UAAU,sBAAsB,MAAM;MACtC,SAAS,aAAa,MAAM;KAJ/B,SA4BO,CApBG,aAAa,MAAM,KAD3B,UAAA,GAAA,YAKE,MAAA,qBAAA,GAAA;;MAHA,6BAAA;MACA,eAAY;MACX,OAAK,eAAE,MAAA,2BAAA,CAA2B;KAIxB,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,KAAA,OAAO,QAFpB,UAAA,GAAA,YAKE,wBAJK,OAAO,IAAI,GAAA;;MAEhB,eAAY;MACX,OAAK,eAAE,MAAA,wBAAA,CAAwB;KAK1B,GAAA,MAAA,GAAA,CAAA,OAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAAA,OAAO,SADf,UAAA,GAAA,mBAMO,QAAA;;MAJJ,OAAK,eAAE,MAAA,yBAAA,CAAyB;MAChC,gBAAY,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,kBAAA,KAAA,MAAA,kBAAA,CAAA,CAAA,GAAA,IAAA;KAEZ,GAAA,gBAAA,OAAO,KAAK,GAAA,EAAA,KAAA,mBAAA,IAAA,IAAA,CAAA,CAAA,CAAA,GAAA,IAAA,UAAA"}
@@ -1,3 +1,3 @@
1
- import { t as GrSegmented_default } from "./chunks/GrSegmented-CB-VR-yL.js";
1
+ import { t as GrSegmented_default } from "./chunks/GrSegmented-NKTi9bMG.js";
2
2
  import { n as grSegmentedSafelist, t as grSegmentedConfig } from "../../chunks/config-rLkc9Zn2.js";
3
3
  export { GrSegmented_default as GrSegmented, GrSegmented_default as default, grSegmentedConfig, grSegmentedSafelist };
@@ -1,7 +1,7 @@
1
1
  import { t as x_default } from "../../../chunks/x-2KXnqxiD.js";
2
- import { a as useGrComponentSize, i as useGrComponentProp, s as useGrThemeAttrs } from "../../../chunks/context-CTbuwcYs.js";
2
+ import { a as useGrComponentSize, i as useGrComponentProp, s as useGrThemeAttrs } from "../../../chunks/context-CPMRfwVr.js";
3
3
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
4
- import { t as usePortalTarget } from "../../../chunks/usePortalTarget-C0p-mhaM.js";
4
+ import { t as usePortalTarget } from "../../../chunks/usePortalTarget-BhrRgdqW.js";
5
5
  import { vClickOutside } from "../../../directives/clickOutside.js";
6
6
  import { r as isComposingEvent } from "../../../chunks/keyboard-DE2yhz_b.js";
7
7
  import { t as loader_circle_default } from "../../../chunks/loader-circle-CfVLz7lb.js";
@@ -16,12 +16,12 @@ import { useComboboxNavigation } from "../../../composables/useComboboxNavigatio
16
16
  import { a as resolveSelectedOptions, i as normalizeOptionQuery, n as matchesOptionQuery } from "../../../chunks/optionFilter-DYw9XPPx.js";
17
17
  import { t as useControlAddons } from "../../../chunks/useControlAddons-asUr10Pf.js";
18
18
  import { d as chipSizeForBadgeScale } from "../../../chunks/grChipStyles-DcDyxAL0.js";
19
- import { t as GrChip_default } from "../../GrChip/chunks/GrChip-BTivtwff.js";
19
+ import { t as GrChip_default } from "../../GrChip/chunks/GrChip-CKqyzYcv.js";
20
20
  import { n as panelPopTransition } from "../../../chunks/overlayPanelSurface-BKeMhRx4.js";
21
21
  import { t as check_default } from "../../../chunks/check-BZI24Qs4.js";
22
22
  import { t as chevron_down_default } from "../../../chunks/chevron-down-CQS2OG_s.js";
23
23
  import { t as _plugin_vue_export_helper_default } from "../../../chunks/_plugin-vue_export-helper-BOaGB7Aw.js";
24
- import { t as GrInput_default } from "../../GrInput/chunks/GrInput-BLywRZUN.js";
24
+ import { t as GrInput_default } from "../../GrInput/chunks/GrInput-TFeBm3gQ.js";
25
25
  import { t as useTypeahead } from "../../../chunks/useTypeahead-mxPtPBf2.js";
26
26
  import { c as grSelectNativeClass, d as grSelectTriggerClass, i as grSelectLinkNativeLabelClass, l as grSelectOptionClass, n as defaultBaseClass, p as linkBaseClass, s as grSelectLinkNativeOverlayClass, u as grSelectPanelClasses } from "../../../chunks/grSelectStyles-D9EQ-pgK.js";
27
27
  import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, toDisplayString, unref, useId, useSlots, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
@@ -400,7 +400,7 @@ function useSelectVirtualization(options) {
400
400
  function selectValueKey(value, valueKey) {
401
401
  if (value !== null && typeof value === "object") {
402
402
  const own = valueKey ? value[valueKey] : void 0;
403
- if (own === void 0 && typeof process !== "undefined" && process.env.NODE_ENV !== "production") console.warn("[granularity] GrSelect: объектные значения требуют `valueKey` с именем поля-идентификатора; без него опции неотличимы друг от друга.");
403
+ if (own === void 0 && process.env.NODE_ENV !== "production") console.warn("[granularity] GrSelect: объектные значения требуют `valueKey` с именем поля-идентификатора; без него опции неотличимы друг от друга.");
404
404
  return String(own ?? JSON.stringify(value));
405
405
  }
406
406
  return String(value);
@@ -913,7 +913,7 @@ var GrSelect_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
913
913
  enabled: () => props.virtual && effectiveOptionsView.value === "panel",
914
914
  maxHeight: () => props.dropdownMaxHeight
915
915
  });
916
- if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
916
+ if (process.env.NODE_ENV !== "production") {
917
917
  const slots = useSlots();
918
918
  watch(() => [Boolean(slots.prefix || slots.suffix), effectiveOptionsView.value], ([hasAddon, view]) => {
919
919
  if (hasAddon && view !== "panel") console.warn("[granularity] GrSelect: слоты `prefix`/`suffix` работают только с `optionsView=\"panel\"` — внутрь нативного `<select>` разметку положить нельзя.");
@@ -1032,11 +1032,7 @@ var GrSelect_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
1032
1032
  else el.value = modelSingle.value === "" ? "" : keyOf(modelSingle.value);
1033
1033
  return;
1034
1034
  }
1035
- if (props.multiple) {
1036
- emit("update:modelValue", Array.from(el.selectedOptions, (o) => fromDomValue(o.value)));
1037
- return;
1038
- }
1039
- emit("update:modelValue", el.value === "" ? "" : fromDomValue(el.value));
1035
+ emitValue(props.multiple ? Array.from(el.selectedOptions, (o) => fromDomValue(o.value)) : el.value === "" ? "" : fromDomValue(el.value));
1040
1036
  }
1041
1037
  function clearSelection() {
1042
1038
  if (locked.value) return;
@@ -1402,6 +1398,6 @@ var GrSelect_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PUR
1402
1398
  }]]);
1403
1399
  };
1404
1400
  }
1405
- }), [["__scopeId", "data-v-f9c12bab"]]);
1401
+ }), [["__scopeId", "data-v-fdc466bb"]]);
1406
1402
  //#endregion
1407
1403
  export { GrSelect_default as t };