@feugene/granularity 0.49.0 → 0.50.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 (368) hide show
  1. package/README.md +3 -3
  2. package/dist/chunks/chevron-up-BhW6hi8L.js +23 -0
  3. package/dist/chunks/chevron-up-BhW6hi8L.js.map +1 -0
  4. package/dist/chunks/{config-E1cTyRVV.js → config-8n1VR0ju.js} +1 -1
  5. package/dist/chunks/{config-E1cTyRVV.js.map → config-8n1VR0ju.js.map} +1 -1
  6. package/dist/chunks/{config-DIDz_E5m.js → config-B34mkd53.js} +66 -1
  7. package/dist/chunks/config-B34mkd53.js.map +1 -0
  8. package/dist/chunks/{config-B5SBUa6u.js → config-B7qZqiUB.js} +28 -1
  9. package/dist/chunks/config-B7qZqiUB.js.map +1 -0
  10. package/dist/chunks/config-BBrPUEye.js +8 -0
  11. package/dist/chunks/config-BBrPUEye.js.map +1 -0
  12. package/dist/chunks/{config-CT4lP6S4.js → config-BOCzHqWh.js} +2 -2
  13. package/dist/chunks/{config-CT4lP6S4.js.map → config-BOCzHqWh.js.map} +1 -1
  14. package/dist/chunks/{config-iemgzS4x.js → config-BP1ktzwh.js} +2 -24
  15. package/dist/chunks/config-BP1ktzwh.js.map +1 -0
  16. package/dist/chunks/config-BTxmdRzT.js +28 -0
  17. package/dist/chunks/config-BTxmdRzT.js.map +1 -0
  18. package/dist/chunks/{config-CjWOTgLL.js → config-Bk52xd5l.js} +12 -5
  19. package/dist/chunks/config-Bk52xd5l.js.map +1 -0
  20. package/dist/chunks/{config-D3HOuHDe.js → config-C3SqBqSQ.js} +3 -1
  21. package/dist/chunks/config-C3SqBqSQ.js.map +1 -0
  22. package/dist/chunks/{config-2ZHRsdOc.js → config-C3uqd-sW.js} +1 -1
  23. package/dist/chunks/config-C3uqd-sW.js.map +1 -0
  24. package/dist/chunks/{config-BXRmsn3t.js → config-CPhcZzHi.js} +72 -10
  25. package/dist/chunks/config-CPhcZzHi.js.map +1 -0
  26. package/dist/chunks/config-CWtfxkM9.js.map +1 -1
  27. package/dist/chunks/{config--t2dxj0t.js → config-CmLTCmY9.js} +2 -2
  28. package/dist/chunks/{config--t2dxj0t.js.map → config-CmLTCmY9.js.map} +1 -1
  29. package/dist/chunks/{config-BAse0laT.js → config-CvtqB4ki.js} +8 -3
  30. package/dist/chunks/config-CvtqB4ki.js.map +1 -0
  31. package/dist/chunks/{config-BcXX7S7B.js → config-D-JgqV0J.js} +5 -1
  32. package/dist/chunks/{config-BcXX7S7B.js.map → config-D-JgqV0J.js.map} +1 -1
  33. package/dist/chunks/{config-BHLMTJaR.js → config-D1oVht-E.js} +8 -3
  34. package/dist/chunks/config-D1oVht-E.js.map +1 -0
  35. package/dist/chunks/{config-B42iJ48O.js → config-DG41PD9i.js} +13 -1
  36. package/dist/chunks/config-DG41PD9i.js.map +1 -0
  37. package/dist/chunks/{config-Bs1HwUcx.js → config-DPJ3jtiB.js} +12 -2
  38. package/dist/chunks/config-DPJ3jtiB.js.map +1 -0
  39. package/dist/chunks/{config-tNqtapcT.js → config-DpqjlCfB.js} +2 -2
  40. package/dist/chunks/{config-tNqtapcT.js.map → config-DpqjlCfB.js.map} +1 -1
  41. package/dist/chunks/{config-DNDgp9bB.js → config-DpzFoSIh.js} +64 -2
  42. package/dist/chunks/config-DpzFoSIh.js.map +1 -0
  43. package/dist/chunks/config-SPugeaHT.js +37 -0
  44. package/dist/chunks/config-SPugeaHT.js.map +1 -0
  45. package/dist/chunks/{en-CsQUoBS2.js → en-mIFywnV2.js} +22 -6
  46. package/dist/chunks/en-mIFywnV2.js.map +1 -0
  47. package/dist/chunks/{es-9nbkPvdA.js → es-CvthYwtB.js} +22 -6
  48. package/dist/chunks/es-CvthYwtB.js.map +1 -0
  49. package/dist/chunks/{es-DrUz5J6I.js → es-DlGd6Mrj.js} +3 -3
  50. package/dist/chunks/{es-DrUz5J6I.js.map → es-DlGd6Mrj.js.map} +1 -1
  51. package/dist/chunks/{generated-CxvC5O0V.js → generated-Cx4C7GRN.js} +84 -0
  52. package/dist/chunks/{generated-CxvC5O0V.js.map → generated-Cx4C7GRN.js.map} +1 -1
  53. package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js → grPopoverStyles-CncEkiPu.js} +1 -1
  54. package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js.map → grPopoverStyles-CncEkiPu.js.map} +1 -1
  55. package/dist/chunks/{grSelectStyles-D9EQ-pgK.js → grSelectStyles-Cam-IG9s.js} +3 -2
  56. package/dist/chunks/grSelectStyles-Cam-IG9s.js.map +1 -0
  57. package/dist/chunks/{grSliderStyles-kaz6VXZ3.js → grSliderStyles-CqzV0hll.js} +1 -1
  58. package/dist/chunks/grSliderStyles-CqzV0hll.js.map +1 -0
  59. package/dist/chunks/{config-CbEbLyDE.js → grSortableListStyles-CxieDmpe.js} +1 -27
  60. package/dist/chunks/grSortableListStyles-CxieDmpe.js.map +1 -0
  61. package/dist/chunks/grTableStyles-CPSxDTOW.js +66 -0
  62. package/dist/chunks/grTableStyles-CPSxDTOW.js.map +1 -0
  63. package/dist/chunks/{config-CMNfZO7S.js → grTabsStyles-DIz2VdIm.js} +1 -36
  64. package/dist/chunks/grTabsStyles-DIz2VdIm.js.map +1 -0
  65. package/dist/chunks/grTooltipStyles-CtbGEEGV.js +24 -0
  66. package/dist/chunks/grTooltipStyles-CtbGEEGV.js.map +1 -0
  67. package/dist/chunks/{granular-provider-B6xomapW.js → granular-provider-cv5vaM1a.js} +21 -19
  68. package/dist/chunks/granular-provider-cv5vaM1a.js.map +1 -0
  69. package/dist/chunks/hotkeySequence-BTHIM_5A.js +46 -0
  70. package/dist/chunks/hotkeySequence-BTHIM_5A.js.map +1 -0
  71. package/dist/chunks/{keyboard-DE2yhz_b.js → keyboard-BiFSgWLt.js} +70 -1
  72. package/dist/chunks/keyboard-BiFSgWLt.js.map +1 -0
  73. package/dist/chunks/optionPanel-DvY7Tv_4.js +182 -0
  74. package/dist/chunks/optionPanel-DvY7Tv_4.js.map +1 -0
  75. package/dist/chunks/overlayListPanel-D91jBCHU.js +21 -0
  76. package/dist/chunks/overlayListPanel-D91jBCHU.js.map +1 -0
  77. package/dist/chunks/{overlayStack-DH4Z7am1.js → overlayStack-DCkCgXZP.js} +1 -1
  78. package/dist/chunks/{overlayStack-DH4Z7am1.js.map → overlayStack-DCkCgXZP.js.map} +1 -1
  79. package/dist/chunks/{overlayPanelSurface-BKeMhRx4.js → overlayTransition-C0FDMx7Q.js} +24 -24
  80. package/dist/chunks/overlayTransition-C0FDMx7Q.js.map +1 -0
  81. package/dist/chunks/{ru-88i1WG0b.js → ru-CQKDR-kD.js} +22 -6
  82. package/dist/chunks/ru-CQKDR-kD.js.map +1 -0
  83. package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js → useMenuItemsFocus-C031blYS.js} +1 -1
  84. package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js.map → useMenuItemsFocus-C031blYS.js.map} +1 -1
  85. package/dist/chunks/{useModalOverlay-ACRkflzx.js → useModalOverlay-CKCQkGdB.js} +1 -1
  86. package/dist/chunks/{useModalOverlay-ACRkflzx.js.map → useModalOverlay-CKCQkGdB.js.map} +1 -1
  87. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-Chhw65pI.js → GrAutocomplete-Cyr1-ENw.js} +181 -123
  88. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-Cyr1-ENw.js.map +1 -0
  89. package/dist/components/GrAutocomplete/index.js +2 -2
  90. package/dist/components/GrAutocomplete/styles.css +1 -1
  91. package/dist/components/GrCarousel/chunks/{GrCarousel-ByuughtI.js → GrCarousel-CBj-PEPB.js} +186 -37
  92. package/dist/components/GrCarousel/chunks/GrCarousel-CBj-PEPB.js.map +1 -0
  93. package/dist/components/GrCarousel/index.js +2 -2
  94. package/dist/components/GrCarousel/styles.css +1 -1
  95. package/dist/components/GrCheckbox/chunks/{GrCheckbox-Dp201frb.js → GrCheckbox-B4NJc7Ur.js} +2 -1
  96. package/dist/components/GrCheckbox/chunks/GrCheckbox-B4NJc7Ur.js.map +1 -0
  97. package/dist/components/GrCheckbox/index.js +1 -1
  98. package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js → GrCheckboxGroup-qZHpNFCX.js} +1 -1
  99. package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js.map → GrCheckboxGroup-qZHpNFCX.js.map} +1 -1
  100. package/dist/components/GrCheckboxGroup/index.js +1 -1
  101. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BRM_4lyI.js → GrColorPicker-vGSgpUV9.js} +353 -38
  102. package/dist/components/GrColorPicker/chunks/GrColorPicker-vGSgpUV9.js.map +1 -0
  103. package/dist/components/GrColorPicker/index.js +2 -2
  104. package/dist/components/GrColorPicker/styles.css +1 -1
  105. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BJHmkDQv.js → GrCommandPalette-CAHgj0Aa.js} +23 -7
  106. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-CAHgj0Aa.js.map +1 -0
  107. package/dist/components/GrCommandPalette/index.js +1 -1
  108. package/dist/components/GrCommandPalette/styles.css +1 -1
  109. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js → GrConfirmDialog-dg021BMd.js} +1 -1
  110. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js.map → GrConfirmDialog-dg021BMd.js.map} +1 -1
  111. package/dist/components/GrConfirmDialog/index.js +1 -1
  112. package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js → GrContextMenu-bQ1Vvy2c.js} +3 -3
  113. package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js.map → GrContextMenu-bQ1Vvy2c.js.map} +1 -1
  114. package/dist/components/GrContextMenu/index.js +1 -1
  115. package/dist/components/GrDataTable/chunks/{GrDataTable-DQxYYgQk.js → GrDataTable-Bb2jWnRG.js} +576 -136
  116. package/dist/components/GrDataTable/chunks/GrDataTable-Bb2jWnRG.js.map +1 -0
  117. package/dist/components/GrDataTable/index.js +2 -2
  118. package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js → GrDelta-BSv1KdMy.js} +0 -0
  119. package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js.map → GrDelta-BSv1KdMy.js.map} +1 -1
  120. package/dist/components/GrDelta/index.js +2 -2
  121. package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js → GrDialog-C9Zu72jB.js} +1 -1
  122. package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js.map → GrDialog-C9Zu72jB.js.map} +1 -1
  123. package/dist/components/GrDialog/index.js +1 -1
  124. package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js → GrDialogService-DLBifO61.js} +2 -2
  125. package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js.map → GrDialogService-DLBifO61.js.map} +1 -1
  126. package/dist/components/GrDialogService/index.js +1 -1
  127. package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js → GrDrawer-DOcRTE8G.js} +1 -1
  128. package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js.map → GrDrawer-DOcRTE8G.js.map} +1 -1
  129. package/dist/components/GrDrawer/index.js +1 -1
  130. package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js → GrDropdown-kxwmgfSe.js} +2 -2
  131. package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js.map → GrDropdown-kxwmgfSe.js.map} +1 -1
  132. package/dist/components/GrDropdown/index.js +2 -2
  133. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-Dxkz_ry4.js → GrDropdownMenu--VoK3VY0.js} +3 -34
  134. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu--VoK3VY0.js.map +1 -0
  135. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js +34 -0
  136. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js.map +1 -0
  137. package/dist/components/GrDropdownMenu/index.js +2 -1
  138. package/dist/components/GrEmptyState/chunks/{GrEmptyState-BbvwE-E0.js → GrEmptyState-Bz6-_ED4.js} +42 -6
  139. package/dist/components/GrEmptyState/chunks/GrEmptyState-Bz6-_ED4.js.map +1 -0
  140. package/dist/components/GrEmptyState/index.js +1 -1
  141. package/dist/components/GrFileUpload/chunks/{GrFileUpload-BwMR71zN.js → GrFileUpload-Bgdfnkd8.js} +5 -2
  142. package/dist/components/GrFileUpload/chunks/GrFileUpload-Bgdfnkd8.js.map +1 -0
  143. package/dist/components/GrFileUpload/index.js +1 -1
  144. package/dist/components/GrFormFile/chunks/{GrFormFile-Dlxx-9zi.js → GrFormFile-Ctq1isz-.js} +78 -11
  145. package/dist/components/GrFormFile/chunks/GrFormFile-Ctq1isz-.js.map +1 -0
  146. package/dist/components/GrFormFile/index.js +2 -2
  147. package/dist/components/GrFormFile/styles.css +1 -1
  148. package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js → GrImageViewer-Bnql_dNP.js} +1 -1
  149. package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js.map → GrImageViewer-Bnql_dNP.js.map} +1 -1
  150. package/dist/components/GrImageViewer/index.js +1 -1
  151. package/dist/components/GrInput/chunks/{GrInput-DV4gMWPR.js → GrInput-CoaFLpaU.js} +43 -22
  152. package/dist/components/GrInput/chunks/GrInput-CoaFLpaU.js.map +1 -0
  153. package/dist/components/GrInput/index.js +1 -1
  154. package/dist/components/GrInputTag/chunks/{GrInputTag-qnRdAZnn.js → GrInputTag-BzzNRBe3.js} +245 -18
  155. package/dist/components/GrInputTag/chunks/GrInputTag-BzzNRBe3.js.map +1 -0
  156. package/dist/components/GrInputTag/index.js +2 -2
  157. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js → GrJsonViewer-B6ZJ3GFH.js} +2 -2
  158. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js.map → GrJsonViewer-B6ZJ3GFH.js.map} +1 -1
  159. package/dist/components/GrJsonViewer/index.js +1 -1
  160. package/dist/components/GrKbd/chunks/{GrKbd-BNMeoaLV.js → GrKbd-D2rHDkQv.js} +42 -37
  161. package/dist/components/GrKbd/chunks/GrKbd-D2rHDkQv.js.map +1 -0
  162. package/dist/components/GrKbd/index.js +1 -1
  163. package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js → GrModal-SHb1U2qx.js} +1 -1
  164. package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js.map → GrModal-SHb1U2qx.js.map} +1 -1
  165. package/dist/components/GrModal/index.js +1 -1
  166. package/dist/components/GrNavbar/chunks/{GrNavbar-BRGuksiy.js → GrNavbar-IEIHC5Vt.js} +10 -4
  167. package/dist/components/GrNavbar/chunks/GrNavbar-IEIHC5Vt.js.map +1 -0
  168. package/dist/components/GrNavbar/index.js +2 -2
  169. package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js → GrNumberInput-CmnUDaKi.js} +2 -22
  170. package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js.map → GrNumberInput-CmnUDaKi.js.map} +1 -1
  171. package/dist/components/GrNumberInput/index.js +1 -1
  172. package/dist/components/GrPagination/chunks/{GrPagination-CMrLPzvL.js → GrPagination-AMbn5D8I.js} +1 -1
  173. package/dist/components/GrPagination/chunks/{GrPagination-CMrLPzvL.js.map → GrPagination-AMbn5D8I.js.map} +1 -1
  174. package/dist/components/GrPagination/index.js +1 -1
  175. package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js → GrPopover-DjVxt8bf.js} +3 -3
  176. package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js.map → GrPopover-DjVxt8bf.js.map} +1 -1
  177. package/dist/components/GrPopover/index.js +2 -2
  178. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js → GrPromptDialog-BhbIZP1f.js} +3 -3
  179. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js.map → GrPromptDialog-BhbIZP1f.js.map} +1 -1
  180. package/dist/components/GrPromptDialog/index.js +1 -1
  181. package/dist/components/GrSelect/chunks/{GrSelect-DvSq-nV-.js → GrSelect-B-ykrHpL.js} +24 -180
  182. package/dist/components/GrSelect/chunks/GrSelect-B-ykrHpL.js.map +1 -0
  183. package/dist/components/GrSelect/index.js +2 -2
  184. package/dist/components/GrSelect/styles.css +1 -1
  185. package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js +543 -0
  186. package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js.map +1 -0
  187. package/dist/components/GrSidebar/index.js +2 -2
  188. package/dist/components/GrSlider/chunks/{GrSlider-CO8N9SF6.js → GrSlider-DF2Cq0rV.js} +29 -4
  189. package/dist/components/GrSlider/chunks/GrSlider-DF2Cq0rV.js.map +1 -0
  190. package/dist/components/GrSlider/index.js +2 -2
  191. package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js → GrSortableList-ChH9nQBv.js} +1 -1
  192. package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js.map → GrSortableList-ChH9nQBv.js.map} +1 -1
  193. package/dist/components/GrSortableList/index.js +2 -2
  194. package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js +30 -0
  195. package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js.map +1 -0
  196. package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js +83 -0
  197. package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js.map +1 -0
  198. package/dist/components/GrTabPanels/index.js +2 -1
  199. package/dist/components/GrTable/chunks/{GrTable-CKJ-HrsN.js → GrTable-BQitSDep.js} +52 -16
  200. package/dist/components/GrTable/chunks/GrTable-BQitSDep.js.map +1 -0
  201. package/dist/components/GrTable/index.js +2 -2
  202. package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js → GrTabs-DVC6nfWB.js} +1 -1
  203. package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js.map → GrTabs-DVC6nfWB.js.map} +1 -1
  204. package/dist/components/GrTabs/index.js +2 -2
  205. package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js +98 -0
  206. package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js.map +1 -0
  207. package/dist/components/GrTabsWithPanels/index.js +3 -0
  208. package/dist/components/GrTextarea/chunks/{GrTextarea-Bfgc0DD2.js → GrTextarea-BFwyqcHB.js} +22 -5
  209. package/dist/components/GrTextarea/chunks/GrTextarea-BFwyqcHB.js.map +1 -0
  210. package/dist/components/GrTextarea/index.js +1 -1
  211. package/dist/components/GrToaster/chunks/{GrToaster-CZixNk0l.js → GrToaster-OzT1VKcp.js} +163 -32
  212. package/dist/components/GrToaster/chunks/GrToaster-OzT1VKcp.js.map +1 -0
  213. package/dist/components/GrToaster/index.js +2 -2
  214. package/dist/components/GrToaster/styles.css +1 -1
  215. package/dist/components/GrTooltip/chunks/{GrTooltip-DkMMM0uq.js → GrTooltip-BDcFycvW.js} +26 -13
  216. package/dist/components/GrTooltip/chunks/GrTooltip-BDcFycvW.js.map +1 -0
  217. package/dist/components/GrTooltip/index.js +2 -2
  218. package/dist/components/GrTransfer/chunks/{GrTransfer-DdfBUf35.js → GrTransfer-CV7BL5UK.js} +114 -12
  219. package/dist/components/GrTransfer/chunks/GrTransfer-CV7BL5UK.js.map +1 -0
  220. package/dist/components/GrTransfer/index.js +1 -1
  221. package/dist/components/GrTransfer/styles.css +1 -1
  222. package/dist/components/GrTree/chunks/{GrTree-6yZrncJE.js → GrTree-DpgaP8hk.js} +39 -1
  223. package/dist/components/GrTree/chunks/GrTree-DpgaP8hk.js.map +1 -0
  224. package/dist/components/GrTree/index.js +1 -1
  225. package/dist/components/GrTree/styles.css +1 -1
  226. package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js → GrTreeSections-BeOj__44.js} +1 -1
  227. package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js.map → GrTreeSections-BeOj__44.js.map} +1 -1
  228. package/dist/components/GrTreeSections/index.js +1 -1
  229. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-B6KoDYiZ.js → GrTreeSelect-BHq-T8wH.js} +113 -14
  230. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHq-T8wH.js.map +1 -0
  231. package/dist/components/GrTreeSelect/index.js +2 -2
  232. package/dist/composables/useFloating.js +1 -1
  233. package/dist/composables/useHotkeys.js +89 -0
  234. package/dist/composables/useHotkeys.js.map +1 -0
  235. package/dist/composables/useOverlayLayer.js +1 -1
  236. package/dist/directives/hotkey.js +19 -46
  237. package/dist/directives/hotkey.js.map +1 -1
  238. package/dist/granular-provider-node.js +1 -1
  239. package/dist/granular-provider.js +1 -1
  240. package/dist/i18n/all.js +1 -1
  241. package/dist/i18n/index.js +1 -1
  242. package/dist/index.js +71 -63
  243. package/dist/theme.js +1 -1
  244. package/dist/tokens.js +1 -1
  245. package/dist/types/components/GrAutocomplete/GrAutocomplete.vue.d.ts +4 -4
  246. package/dist/types/components/GrAutocomplete/composables/useAutocompleteNavigation.d.ts +12 -3
  247. package/dist/types/components/GrAutocomplete/composables/useAutocompletePanel.d.ts +12 -2
  248. package/dist/types/components/GrAutocomplete/composables/useAutocompleteValues.d.ts +7 -4
  249. package/dist/types/components/GrAutocomplete/composables/useRemoteOptions.d.ts +4 -4
  250. package/dist/types/components/GrAutocomplete/grAutocompleteStyles.d.ts +15 -1
  251. package/dist/types/components/GrAutocomplete/index.d.ts +1 -1
  252. package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +29 -1
  253. package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +5 -0
  254. package/dist/types/components/GrCarousel/grCarouselContext.d.ts +21 -0
  255. package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +39 -9
  256. package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +13 -0
  257. package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +18 -2
  258. package/dist/types/components/GrColorPicker/color.d.ts +13 -1
  259. package/dist/types/components/GrColorPicker/colorArea.d.ts +59 -0
  260. package/dist/types/components/GrColorPicker/defaults.d.ts +3 -1
  261. package/dist/types/components/GrColorPicker/eyeDropper.d.ts +21 -0
  262. package/dist/types/components/GrColorPicker/grColorPickerStyles.d.ts +42 -0
  263. package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +10 -1
  264. package/dist/types/components/GrDataTable/GrDataTable.vue.d.ts +41 -1
  265. package/dist/types/components/GrDataTable/composables/useDataTableGridNavigation.d.ts +53 -0
  266. package/dist/types/components/GrDataTable/grDataTableStyles.d.ts +8 -0
  267. package/dist/types/components/GrDataTable/index.d.ts +1 -1
  268. package/dist/types/components/GrDelta/grDeltaStyles.d.ts +10 -3
  269. package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +11 -2
  270. package/dist/types/components/GrEmptyState/grEmptyStateStyles.d.ts +10 -0
  271. package/dist/types/components/GrEmptyState/index.d.ts +1 -1
  272. package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +2 -1
  273. package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +10 -0
  274. package/dist/types/components/GrInput/GrInput.vue.d.ts +15 -0
  275. package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +16 -0
  276. package/dist/types/components/GrInputTag/grInputTagStyles.d.ts +11 -0
  277. package/dist/types/components/GrKbd/GrKbd.vue.d.ts +14 -0
  278. package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +18 -0
  279. package/dist/types/components/GrNavbar/grNavbarStyles.d.ts +10 -1
  280. package/dist/types/components/GrNavbar/index.d.ts +1 -0
  281. package/dist/types/components/GrSelect/composables/useSelectPanelItems.d.ts +8 -34
  282. package/dist/types/components/GrSelect/composables/useSelectVirtualization.d.ts +7 -0
  283. package/dist/types/components/GrSelect/grSelectStyles.d.ts +1 -1
  284. package/dist/types/components/GrSidebar/GrSidebar.vue.d.ts +20 -0
  285. package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +39 -5
  286. package/dist/types/components/GrSidebar/grSidebarStyles.d.ts +32 -0
  287. package/dist/types/components/GrSidebar/index.d.ts +1 -1
  288. package/dist/types/components/GrSidebar/sidebarContext.d.ts +23 -1
  289. package/dist/types/components/GrSlider/GrSlider.vue.d.ts +39 -1
  290. package/dist/types/components/GrSlider/grSliderStyles.d.ts +1 -1
  291. package/dist/types/components/GrTabPanels/context.d.ts +6 -0
  292. package/dist/types/components/GrTable/GrTable.vue.d.ts +37 -0
  293. package/dist/types/components/GrTable/grTableStyles.d.ts +16 -7
  294. package/dist/types/components/GrTabsWithPanels/GrTabsWithPanels.vue.d.ts +77 -0
  295. package/dist/types/components/GrTabsWithPanels/config.d.ts +1 -0
  296. package/dist/types/components/GrTabsWithPanels/index.d.ts +4 -0
  297. package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +19 -1
  298. package/dist/types/components/GrToaster/GrToaster.vue.d.ts +12 -0
  299. package/dist/types/components/GrToaster/grToasterStyles.d.ts +26 -0
  300. package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +22 -0
  301. package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +23 -0
  302. package/dist/types/components/GrTreeSelect/grTreeSelectStyles.d.ts +1 -1
  303. package/dist/types/components/GrTreeSelect/grTreeSelectTypes.d.ts +20 -0
  304. package/dist/types/components/shared/hotkey.d.ts +8 -9
  305. package/dist/types/components/shared/optionPanel.d.ts +100 -0
  306. package/dist/types/components/shared/overlayListPanel.d.ts +18 -0
  307. package/dist/types/composables/useHotkeys.d.ts +43 -0
  308. package/dist/types/granular-provider/shared.d.ts +1 -0
  309. package/dist/types/i18n/messages/en.d.ts +28 -0
  310. package/dist/types/i18n/messages/es.d.ts +28 -0
  311. package/dist/types/i18n/messages/ru.d.ts +28 -0
  312. package/dist/types/index.d.ts +3 -0
  313. package/dist/types/internal/hotkeySequence.d.ts +22 -0
  314. package/dist/types/internal/keyboard.d.ts +45 -0
  315. package/dist/web-types.json +463 -26
  316. package/package.json +9 -1
  317. package/dist/chunks/config-2ZHRsdOc.js.map +0 -1
  318. package/dist/chunks/config-B42iJ48O.js.map +0 -1
  319. package/dist/chunks/config-B5SBUa6u.js.map +0 -1
  320. package/dist/chunks/config-BAse0laT.js.map +0 -1
  321. package/dist/chunks/config-BHLMTJaR.js.map +0 -1
  322. package/dist/chunks/config-BXRmsn3t.js.map +0 -1
  323. package/dist/chunks/config-Bs1HwUcx.js.map +0 -1
  324. package/dist/chunks/config-CMNfZO7S.js.map +0 -1
  325. package/dist/chunks/config-CbEbLyDE.js.map +0 -1
  326. package/dist/chunks/config-CjWOTgLL.js.map +0 -1
  327. package/dist/chunks/config-D3HOuHDe.js.map +0 -1
  328. package/dist/chunks/config-DIDz_E5m.js.map +0 -1
  329. package/dist/chunks/config-DNDgp9bB.js.map +0 -1
  330. package/dist/chunks/config-iemgzS4x.js.map +0 -1
  331. package/dist/chunks/en-CsQUoBS2.js.map +0 -1
  332. package/dist/chunks/es-9nbkPvdA.js.map +0 -1
  333. package/dist/chunks/grSelectStyles-D9EQ-pgK.js.map +0 -1
  334. package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +0 -1
  335. package/dist/chunks/grTableStyles-DkQPMfx9.js +0 -39
  336. package/dist/chunks/grTableStyles-DkQPMfx9.js.map +0 -1
  337. package/dist/chunks/granular-provider-B6xomapW.js.map +0 -1
  338. package/dist/chunks/keyboard-DE2yhz_b.js.map +0 -1
  339. package/dist/chunks/overlayPanelSurface-BKeMhRx4.js.map +0 -1
  340. package/dist/chunks/ru-88i1WG0b.js.map +0 -1
  341. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-Chhw65pI.js.map +0 -1
  342. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +0 -1
  343. package/dist/components/GrCheckbox/chunks/GrCheckbox-Dp201frb.js.map +0 -1
  344. package/dist/components/GrColorPicker/chunks/GrColorPicker-BRM_4lyI.js.map +0 -1
  345. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BJHmkDQv.js.map +0 -1
  346. package/dist/components/GrDataTable/chunks/GrDataTable-DQxYYgQk.js.map +0 -1
  347. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-Dxkz_ry4.js.map +0 -1
  348. package/dist/components/GrEmptyState/chunks/GrEmptyState-BbvwE-E0.js.map +0 -1
  349. package/dist/components/GrFileUpload/chunks/GrFileUpload-BwMR71zN.js.map +0 -1
  350. package/dist/components/GrFormFile/chunks/GrFormFile-Dlxx-9zi.js.map +0 -1
  351. package/dist/components/GrInput/chunks/GrInput-DV4gMWPR.js.map +0 -1
  352. package/dist/components/GrInputTag/chunks/GrInputTag-qnRdAZnn.js.map +0 -1
  353. package/dist/components/GrKbd/chunks/GrKbd-BNMeoaLV.js.map +0 -1
  354. package/dist/components/GrNavbar/chunks/GrNavbar-BRGuksiy.js.map +0 -1
  355. package/dist/components/GrSelect/chunks/GrSelect-DvSq-nV-.js.map +0 -1
  356. package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js +0 -264
  357. package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js.map +0 -1
  358. package/dist/components/GrSlider/chunks/GrSlider-CO8N9SF6.js.map +0 -1
  359. package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js +0 -92
  360. package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js.map +0 -1
  361. package/dist/components/GrTable/chunks/GrTable-CKJ-HrsN.js.map +0 -1
  362. package/dist/components/GrTextarea/chunks/GrTextarea-Bfgc0DD2.js.map +0 -1
  363. package/dist/components/GrToaster/chunks/GrToaster-CZixNk0l.js.map +0 -1
  364. package/dist/components/GrTooltip/chunks/GrTooltip-DkMMM0uq.js.map +0 -1
  365. package/dist/components/GrTransfer/chunks/GrTransfer-DdfBUf35.js.map +0 -1
  366. package/dist/components/GrTree/chunks/GrTree-6yZrncJE.js.map +0 -1
  367. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-B6KoDYiZ.js.map +0 -1
  368. package/dist/types/components/GrAutocomplete/composables/useAutocompleteVirtual.d.ts +0 -33
@@ -1 +0,0 @@
1
- {"version":3,"file":"granular-provider-B6xomapW.js","names":[],"sources":["../../src/components/GrDialog/config.ts","../../src/components/GrResponseErrorBanner/config.ts","../../src/granular-provider/shared.ts","../../src/granular-provider/index.ts"],"sourcesContent":["import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nimport { grDialogSafelist } from './safelist'\n\nexport const grDialogConfig = defineGranularComponent(import.meta.url, {\n name: 'GrDialog',\n dependencies: ['GrButton', 'GrModal'],\n safelist: grDialogSafelist,\n})\n","import { defineGranularComponent } from '@feugene/unocss-preset-granular/contract'\n\nexport const grResponseErrorBannerConfig = defineGranularComponent(import.meta.url, {\n name: 'GrResponseErrorBanner',\n dependencies: ['GrAlert', 'GrButton'],\n})\n","// `id`, `theme.*`, `packageBaseUrl` и реестр компонентов провайдера.\n//\n// Все `new URL('../styles/...', import.meta.url)` обязаны лежать именно здесь:\n// `shared.ts` в одной директории с `index.ts` / `node.ts`, поэтому\n// относительные пути совпадают. Для браузера безопасно — бандлеры\n// транслируют такие литералы в статические asset-URL.\n//\n// `apps/showcase/scripts/generate-component-api.mjs` читает список компонентов\n// из `Object.keys(granularityComponentConfigs)` через vite SSR.\nimport {\n defineGranularProvider,\n type GranularComponentDescriptor,\n type GranularProvider,\n resolvePackageBaseUrl,\n} from '@feugene/unocss-preset-granular/contract'\n// <granularity:components:imports> — блок генерируется `yarn generate:registry`\nimport { grAffixConfig } from '../components/GrAffix/config'\nimport { grAlertConfig } from '../components/GrAlert/config'\nimport { grAutocompleteConfig } from '../components/GrAutocomplete/config'\nimport { grAvatarConfig } from '../components/GrAvatar/config'\nimport { grBadgeConfig } from '../components/GrBadge/config'\nimport { grBadgeWrapConfig } from '../components/GrBadgeWrap/config'\nimport { grBottomNavConfig } from '../components/GrBottomNav/config'\nimport { grBreadcrumbsConfig } from '../components/GrBreadcrumbs/config'\nimport { grButtonConfig } from '../components/GrButton/config'\nimport { grButtonGroupConfig } from '../components/GrButtonGroup/config'\nimport { grCardConfig } from '../components/GrCard/config'\nimport { grCarouselConfig } from '../components/GrCarousel/config'\nimport { grCheckboxConfig } from '../components/GrCheckbox/config'\nimport { grCheckboxGroupConfig } from '../components/GrCheckboxGroup/config'\nimport { grChipConfig } from '../components/GrChip/config'\nimport { grChipGroupConfig } from '../components/GrChipGroup/config'\nimport { grCollapseConfig } from '../components/GrCollapse/config'\nimport { grColorPickerConfig } from '../components/GrColorPicker/config'\nimport { grCommandPaletteConfig } from '../components/GrCommandPalette/config'\nimport { grConfigProviderConfig } from '../components/GrConfigProvider/config'\nimport { grConfirmDialogConfig } from '../components/GrConfirmDialog/config'\nimport { grContextMenuConfig } from '../components/GrContextMenu/config'\nimport { grDataTableConfig } from '../components/GrDataTable/config'\nimport { grDeltaConfig } from '../components/GrDelta/config'\nimport { grDescriptionListConfig } from '../components/GrDescriptionList/config'\nimport { grDialogConfig } from '../components/GrDialog/config'\nimport { grDialogServiceConfig } from '../components/GrDialogService/config'\nimport { grDividerConfig } from '../components/GrDivider/config'\nimport { grDrawerConfig } from '../components/GrDrawer/config'\nimport { grDropdownConfig } from '../components/GrDropdown/config'\nimport { grDropdownMenuConfig } from '../components/GrDropdownMenu/config'\nimport { grEmptyStateConfig } from '../components/GrEmptyState/config'\nimport { grFilePreviewConfig } from '../components/GrFilePreview/config'\nimport { grFileUploadConfig } from '../components/GrFileUpload/config'\nimport { grFormConfig } from '../components/GrForm/config'\nimport { grFormFieldConfig } from '../components/GrFormField/config'\nimport { grFormFileConfig } from '../components/GrFormFile/config'\nimport { grFormSectionConfig } from '../components/GrFormSection/config'\nimport { grIconConfig } from '../components/GrIcon/config'\nimport { grImageViewerConfig } from '../components/GrImageViewer/config'\nimport { grInputConfig } from '../components/GrInput/config'\nimport { grInputTagConfig } from '../components/GrInputTag/config'\nimport { grJsonViewerConfig } from '../components/GrJsonViewer/config'\nimport { grKbdConfig } from '../components/GrKbd/config'\nimport { grLinkConfig } from '../components/GrLink/config'\nimport { grListConfig } from '../components/GrList/config'\nimport { grLoadingConfig } from '../components/GrLoading/config'\nimport { grModalConfig } from '../components/GrModal/config'\nimport { grNavbarConfig } from '../components/GrNavbar/config'\nimport { grNumberInputConfig } from '../components/GrNumberInput/config'\nimport { grOtpInputConfig } from '../components/GrOtpInput/config'\nimport { grPaginationConfig } from '../components/GrPagination/config'\nimport { grPopoverConfig } from '../components/GrPopover/config'\nimport { grProgressBarConfig } from '../components/GrProgressBar/config'\nimport { grProgressCircleConfig } from '../components/GrProgressCircle/config'\nimport { grPromptDialogConfig } from '../components/GrPromptDialog/config'\nimport { grRadioConfig } from '../components/GrRadio/config'\nimport { grRadioGroupConfig } from '../components/GrRadioGroup/config'\nimport { grRatingConfig } from '../components/GrRating/config'\nimport { grResponseErrorBannerConfig } from '../components/GrResponseErrorBanner/config'\nimport { grScrollSpyConfig } from '../components/GrScrollSpy/config'\nimport { grSegmentedConfig } from '../components/GrSegmented/config'\nimport { grSelectConfig } from '../components/GrSelect/config'\nimport { grSidebarConfig } from '../components/GrSidebar/config'\nimport { grSkeletonConfig } from '../components/GrSkeleton/config'\nimport { grSliderConfig } from '../components/GrSlider/config'\nimport { grSortableListConfig } from '../components/GrSortableList/config'\nimport { grSplitterConfig } from '../components/GrSplitter/config'\nimport { grStatisticConfig } from '../components/GrStatistic/config'\nimport { grStepsConfig } from '../components/GrSteps/config'\nimport { grSwitchConfig } from '../components/GrSwitch/config'\nimport { grTableConfig } from '../components/GrTable/config'\nimport { grTabPanelsConfig } from '../components/GrTabPanels/config'\nimport { grTabsConfig } from '../components/GrTabs/config'\nimport { grTextareaConfig } from '../components/GrTextarea/config'\nimport { grTimelineConfig } from '../components/GrTimeline/config'\nimport { grToasterConfig } from '../components/GrToaster/config'\nimport { grTooltipConfig } from '../components/GrTooltip/config'\nimport { grTransferConfig } from '../components/GrTransfer/config'\nimport { grTreeConfig } from '../components/GrTree/config'\nimport { grTreeSectionsConfig } from '../components/GrTreeSections/config'\nimport { grTreeSelectConfig } from '../components/GrTreeSelect/config'\nimport { grValueConfig } from '../components/GrValue/config'\n// </granularity:components:imports>\n\n/** Идентификатор провайдера — совпадает с именем пакета. */\nexport const GRANULARITY_PROVIDER_ID = '@feugene/granularity'\n\n// Не заменять на `new URL('..', import.meta.url)`: Vite и rolldown распознают\n// этот литерал и подставляют `data:`-URL, после чего scan-директории пустеют.\nconst packageBaseUrl = resolvePackageBaseUrl(import.meta.url)\n\n/** Встроенные темы пакета. Единственный источник правды о списке тем. */\nexport const granularityThemeNames = ['light', 'dark'] as const\nexport type GranularityThemeName = (typeof granularityThemeNames)[number]\n\n/** Темы, активные по умолчанию, если окружение не переопределяет выбор. */\nexport const granularityDefaultThemes: readonly GranularityThemeName[] = ['light']\n\nconst theme = {\n baseCssUrl: new URL('../styles/base.css', import.meta.url).href,\n tokensCssUrl: new URL('../styles/tokens.css', import.meta.url).href,\n themes: {\n light: new URL('../styles/themes/light.css', import.meta.url).href,\n dark: new URL('../styles/themes/dark.css', import.meta.url).href,\n },\n defaultThemes: granularityDefaultThemes,\n} as const\n\n/**\n * Реестр публичных компонентов. Ключи совпадают с subpath-экспортом\n * `@feugene/granularity/components/<Name>`.\n */\nexport const granularityComponentConfigs = {\n // <granularity:components:registry> — блок генерируется `yarn generate:registry`\n GrAffix: grAffixConfig,\n GrAlert: grAlertConfig,\n GrAutocomplete: grAutocompleteConfig,\n GrAvatar: grAvatarConfig,\n GrBadge: grBadgeConfig,\n GrBadgeWrap: grBadgeWrapConfig,\n GrBottomNav: grBottomNavConfig,\n GrBreadcrumbs: grBreadcrumbsConfig,\n GrButton: grButtonConfig,\n GrButtonGroup: grButtonGroupConfig,\n GrCard: grCardConfig,\n GrCarousel: grCarouselConfig,\n GrCheckbox: grCheckboxConfig,\n GrCheckboxGroup: grCheckboxGroupConfig,\n GrChip: grChipConfig,\n GrChipGroup: grChipGroupConfig,\n GrCollapse: grCollapseConfig,\n GrColorPicker: grColorPickerConfig,\n GrCommandPalette: grCommandPaletteConfig,\n GrConfigProvider: grConfigProviderConfig,\n GrConfirmDialog: grConfirmDialogConfig,\n GrContextMenu: grContextMenuConfig,\n GrDataTable: grDataTableConfig,\n GrDelta: grDeltaConfig,\n GrDescriptionList: grDescriptionListConfig,\n GrDialog: grDialogConfig,\n GrDialogService: grDialogServiceConfig,\n GrDivider: grDividerConfig,\n GrDrawer: grDrawerConfig,\n GrDropdown: grDropdownConfig,\n GrDropdownMenu: grDropdownMenuConfig,\n GrEmptyState: grEmptyStateConfig,\n GrFilePreview: grFilePreviewConfig,\n GrFileUpload: grFileUploadConfig,\n GrForm: grFormConfig,\n GrFormField: grFormFieldConfig,\n GrFormFile: grFormFileConfig,\n GrFormSection: grFormSectionConfig,\n GrIcon: grIconConfig,\n GrImageViewer: grImageViewerConfig,\n GrInput: grInputConfig,\n GrInputTag: grInputTagConfig,\n GrJsonViewer: grJsonViewerConfig,\n GrKbd: grKbdConfig,\n GrLink: grLinkConfig,\n GrList: grListConfig,\n GrLoading: grLoadingConfig,\n GrModal: grModalConfig,\n GrNavbar: grNavbarConfig,\n GrNumberInput: grNumberInputConfig,\n GrOtpInput: grOtpInputConfig,\n GrPagination: grPaginationConfig,\n GrPopover: grPopoverConfig,\n GrProgressBar: grProgressBarConfig,\n GrProgressCircle: grProgressCircleConfig,\n GrPromptDialog: grPromptDialogConfig,\n GrRadio: grRadioConfig,\n GrRadioGroup: grRadioGroupConfig,\n GrRating: grRatingConfig,\n GrResponseErrorBanner: grResponseErrorBannerConfig,\n GrScrollSpy: grScrollSpyConfig,\n GrSegmented: grSegmentedConfig,\n GrSelect: grSelectConfig,\n GrSidebar: grSidebarConfig,\n GrSkeleton: grSkeletonConfig,\n GrSlider: grSliderConfig,\n GrSortableList: grSortableListConfig,\n GrSplitter: grSplitterConfig,\n GrStatistic: grStatisticConfig,\n GrSteps: grStepsConfig,\n GrSwitch: grSwitchConfig,\n GrTable: grTableConfig,\n GrTabPanels: grTabPanelsConfig,\n GrTabs: grTabsConfig,\n GrTextarea: grTextareaConfig,\n GrTimeline: grTimelineConfig,\n GrToaster: grToasterConfig,\n GrTooltip: grTooltipConfig,\n GrTransfer: grTransferConfig,\n GrTree: grTreeConfig,\n GrTreeSections: grTreeSectionsConfig,\n GrTreeSelect: grTreeSelectConfig,\n GrValue: grValueConfig,\n // </granularity:components:registry>\n}\n\nexport type GranularityComponentName = keyof typeof granularityComponentConfigs\n\n/** Базовый набор компонентов в порядке реестра. */\nconst baseComponents: readonly GranularComponentDescriptor[] = Object.values(\n granularityComponentConfigs,\n)\n\n/**\n * Собирает granular-provider пакета.\n *\n * `overrides` — точка расширения для потребителя: дескриптор с именем из\n * базового реестра заменяет его, остальные дописываются в конец.\n */\nexport function createGranularityProvider(\n overrides: readonly GranularComponentDescriptor[] = [],\n): GranularProvider {\n const overrideByName = new Map(\n overrides.map(component => [component.name, component]),\n )\n const components: GranularComponentDescriptor[] = [\n ...baseComponents.map(component => overrideByName.get(component.name) ?? component),\n ...overrides.filter(component => !baseComponents.some(base => base.name === component.name)),\n ]\n\n return defineGranularProvider({\n id: GRANULARITY_PROVIDER_ID,\n contractVersion: 1,\n packageBaseUrl,\n components,\n theme,\n })\n}\n","import { createGranularityProvider } from './shared'\n\nexport * from './shared'\n\nexport const granularityProvider = createGranularityProvider()\n\nexport default granularityProvider\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAIA,IAAa,iBAAiB,wBAAwB,YAAY,KAAK;CACrE,MAAM;CACN,cAAc,CAAC,YAAY,SAAS;CACpC,UAAU;AACZ,CAAC;;;ACND,IAAa,8BAA8B,wBAAwB,YAAY,KAAK;CAClF,MAAM;CACN,cAAc,CAAC,WAAW,UAAU;AACtC,CAAC;;;;ACiGD,IAAa,0BAA0B;AAIvC,IAAM,iBAAiB,sBAAsB,YAAY,GAAG;;AAG5D,IAAa,wBAAwB,CAAC,SAAS,MAAM;;AAIrD,IAAa,2BAA4D,CAAC,OAAO;AAEjF,IAAM,QAAQ;CACZ,YAAY,IAAA,IAAA,q5KAAA,KAAA,YAAA,GAAA,CAA8C,CAAC;CAC3D,cAAc,IAAA,IAAA,65YAAA,KAAA,YAAA,GAAA,CAAgD,CAAC;CAC/D,QAAQ;EACN,OAAO,IAAA,IAAA,iyYAAA,KAAA,YAAA,GAAA,CAAsD,CAAC;EAC9D,MAAM,IAAA,IAAA,y/SAAA,KAAA,YAAA,GAAA,CAAqD,CAAC;CAC9D;CACA,eAAe;AACjB;;;;;AAMA,IAAa,8BAA8B;CAEzC,SAAS;CACT,SAAS;CACT,gBAAgB;CAChB,UAAU;CACV,SAAS;CACT,aAAa;CACb,aAAa;CACb,eAAe;CACf,UAAU;CACV,eAAe;CACf,QAAQ;CACR,YAAY;CACZ,YAAY;CACZ,iBAAiB;CACjB,QAAQ;CACR,aAAa;CACb,YAAY;CACZ,eAAe;CACf,kBAAkB;CAClB,kBAAkB;CAClB,iBAAiB;CACjB,eAAe;CACf,aAAa;CACb,SAAS;CACT,mBAAmB;CACnB,UAAU;CACV,iBAAiB;CACjB,WAAW;CACX,UAAU;CACV,YAAY;CACZ,gBAAgB;CAChB,cAAc;CACd,eAAe;CACf,cAAc;CACd,QAAQ;CACR,aAAa;CACb,YAAY;CACZ,eAAe;CACf,QAAQ;CACR,eAAe;CACf,SAAS;CACT,YAAY;CACZ,cAAc;CACd,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,WAAW;CACX,SAAS;CACT,UAAU;CACV,eAAe;CACf,YAAY;CACZ,cAAc;CACd,WAAW;CACX,eAAe;CACf,kBAAkB;CAClB,gBAAgB;CAChB,SAAS;CACT,cAAc;CACd,UAAU;CACV,uBAAuB;CACvB,aAAa;CACb,aAAa;CACb,UAAU;CACV,WAAW;CACX,YAAY;CACZ,UAAU;CACV,gBAAgB;CAChB,YAAY;CACZ,aAAa;CACb,SAAS;CACT,UAAU;CACV,SAAS;CACT,aAAa;CACb,QAAQ;CACR,YAAY;CACZ,YAAY;CACZ,WAAW;CACX,WAAW;CACX,YAAY;CACZ,QAAQ;CACR,gBAAgB;CAChB,cAAc;CACd,SAAS;AAEX;;AAKA,IAAM,iBAAyD,OAAO,OACpE,2BACF;;;;;;;AAQA,SAAgB,0BACd,YAAoD,CAAC,GACnC;CAClB,MAAM,iBAAiB,IAAI,IACzB,UAAU,KAAI,cAAa,CAAC,UAAU,MAAM,SAAS,CAAC,CACxD;CACA,MAAM,aAA4C,CAChD,GAAG,eAAe,KAAI,cAAa,eAAe,IAAI,UAAU,IAAI,KAAK,SAAS,GAClF,GAAG,UAAU,QAAO,cAAa,CAAC,eAAe,MAAK,SAAQ,KAAK,SAAS,UAAU,IAAI,CAAC,CAC7F;CAEA,OAAO,uBAAuB;EAC5B,IAAI;EACJ,iBAAiB;EACjB;EACA;EACA;CACF,CAAC;AACH;;;ACpPA,IAAa,sBAAsB,0BAA0B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"keyboard-DE2yhz_b.js","names":[],"sources":["../../src/internal/keyboard.ts"],"sourcesContent":["/**\n * Общие примитивы разбора клавиатурных событий: IME-композиция и матчинг\n * клавиш, не зависящий от раскладки.\n *\n * Живут в `internal/`, а не рядом с потребителем: одно и то же нужно стеку\n * оверлеев (`composables/internal/overlayStack.ts`), директиве `v-hotkey` и\n * матчеру палитры (`components/shared/hotkey.ts`) — три слоя, у которых нет\n * общего предка ближе этого модуля.\n */\n\n/**\n * Событие пришло во время IME-композиции — обрабатывать его как команду нельзя:\n * Esc здесь отменяет композицию, Enter — коммитит её, стрелки ходят по\n * кандидатам. `keyCode === 229` — страховка для движков, которые не выставляют\n * `isComposing` (исторически WebKit/старый Chromium).\n */\nexport function isComposingEvent(event: KeyboardEvent): boolean {\n return event.isComposing || event.keyCode === 229\n}\n\n/**\n * Фокус на контроле, который сам распоряжается печатными клавишами.\n *\n * Нужен всем, кто вешает клавиатурные команды на контейнер: горячая клавиша и\n * typeahead меню обязаны молчать, пока пользователь печатает в поле внутри них.\n */\nexport function isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement))\n return false\n if (target.isContentEditable)\n return true\n\n const tag = target.tagName\n return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT'\n}\n\n/**\n * macOS определяем по платформе: от неё зависит, чем является токен `mod` —\n * Cmd или Ctrl. Живёт здесь, а не рядом с одним потребителем: то же нужно\n * `GrKbd` (что показать), палитре (что слушать) и директиве `v-hotkey`.\n */\nexport function isAppleDevice(): boolean {\n if (typeof navigator === 'undefined')\n return false\n return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent)\n}\n\n/** Физический код клавиши для латинской буквы или цифры; иначе `null`. */\nexport function codeForChar(ch: string): string | null {\n if (/^[a-z]$/i.test(ch))\n return `Key${ch.toUpperCase()}`\n if (/^\\d$/.test(ch))\n return `Digit${ch}`\n return null\n}\n\nexport interface EventMatchesKeyOptions {\n /**\n * Дополнительно матчить по физическому коду (`event.code`), когда `event.key`\n * не совпал. Нужен комбинациям с модификаторами: на нелатинской раскладке\n * Ctrl/Cmd+K приходит как `key: 'л'`, и без кода сочетание мертво. Для\n * одиночных клавиш без модификаторов фолбэк не включается — там семантика\n * печатная, а не позиционная.\n */\n codeFallback?: boolean\n}\n\n/** Совпадает ли нажатая клавиша с ожидаемой (`'k'`, `'Escape'`, `' '`). */\nexport function eventMatchesKey(\n event: KeyboardEvent,\n expected: string,\n options: EventMatchesKeyOptions = {},\n): boolean {\n if (expected === ' ')\n return event.key === ' ' || event.key === 'Spacebar'\n\n if (expected.length === 1) {\n if (event.key.toLowerCase() === expected.toLowerCase())\n return true\n return Boolean(options.codeFallback) && codeForChar(expected) === event.code\n }\n\n return event.key === expected\n}\n\n/**\n * Удовлетворяет ли состояние Shift ожиданиям комбинации.\n *\n * Объявленный `shift` требует нажатого Shift. Необъявленный — запрещает его\n * с одним исключением: символ, который без Shift не набрать (`?`, `+`, `:`),\n * легален вместе с ним, когда `event.key` уже равен ожидаемому символу.\n * Буквы под исключение не попадают: `'a'` и Shift+A — разные намерения.\n */\nexport function shiftSatisfied(event: KeyboardEvent, expectedKey: string, expectShift: boolean): boolean {\n if (expectShift)\n return event.shiftKey\n if (!event.shiftKey)\n return true\n\n return expectedKey.length === 1 && !/\\p{L}/u.test(expectedKey) && event.key === expectedKey\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,iBAAiB,OAA+B;CAC9D,OAAO,MAAM,eAAe,MAAM,YAAY;AAChD;;;;;;;AAQA,SAAgB,iBAAiB,QAAqC;CACpE,IAAI,EAAE,kBAAkB,cACtB,OAAO;CACT,IAAI,OAAO,mBACT,OAAO;CAET,MAAM,MAAM,OAAO;CACnB,OAAO,QAAQ,WAAW,QAAQ,cAAc,QAAQ;AAC1D;;;;;;AAOA,SAAgB,gBAAyB;CACvC,IAAI,OAAO,cAAc,aACvB,OAAO;CACT,OAAO,uBAAuB,KAAK,UAAU,YAAY,UAAU,SAAS;AAC9E;;AAGA,SAAgB,YAAY,IAA2B;CACrD,IAAI,WAAW,KAAK,EAAE,GACpB,OAAO,MAAM,GAAG,YAAY;CAC9B,IAAI,OAAO,KAAK,EAAE,GAChB,OAAO,QAAQ;CACjB,OAAO;AACT;;AAcA,SAAgB,gBACd,OACA,UACA,UAAkC,CAAC,GAC1B;CACT,IAAI,aAAa,KACf,OAAO,MAAM,QAAQ,OAAO,MAAM,QAAQ;CAE5C,IAAI,SAAS,WAAW,GAAG;EACzB,IAAI,MAAM,IAAI,YAAY,MAAM,SAAS,YAAY,GACnD,OAAO;EACT,OAAO,QAAQ,QAAQ,YAAY,KAAK,YAAY,QAAQ,MAAM,MAAM;CAC1E;CAEA,OAAO,MAAM,QAAQ;AACvB;;;;;;;;;AAUA,SAAgB,eAAe,OAAsB,aAAqB,aAA+B;CACvG,IAAI,aACF,OAAO,MAAM;CACf,IAAI,CAAC,MAAM,UACT,OAAO;CAET,OAAO,YAAY,WAAW,KAAK,CAAC,SAAS,KAAK,WAAW,KAAK,MAAM,QAAQ;AAClF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"overlayPanelSurface-BKeMhRx4.js","names":[],"sources":["../../src/components/shared/overlayTransition.ts","../../src/components/shared/overlayPanelSurface.ts"],"sourcesContent":["/**\n * Набор перехода всплывающей панели.\n *\n * Пять панелей — выпадающее меню, поповер, списки выбора — появляются\n * одинаково, и до выноса держали этот набор литералами в своих шаблонах:\n * шесть строк, повторённых дословно пять раз. Разъезжались они молча, потому\n * что визуально расхождение в одной фазе заметно только рядом с эталоном.\n *\n * Форма — объект по фазам, как `overlayTransition`/`panelTransition` у\n * `GrModal`: так набор биндится в `<transition>` по одному имени на фазу и\n * разворачивается в safelist одним вызовом, не превращаясь в «мешок токенов».\n *\n * Два правила, оба следуют из того, что модуль безадресный (в `dist` он лежит\n * в общем чанке, который пресет не сканирует):\n *\n * 1. **Каждый потребитель обязан объявить эти классы в своём `safelist.ts`** —\n * через `flattenTransitionTokens`. Гейт `src/__tests__/safelist.test.ts`\n * проверяет это обходом импортов; забывшего он назовёт поимённо.\n * 2. **Один пресет — один файл.** Второй набор, положенный сюда же, обложил бы\n * налогом потребителей первого: safelist считается по модулю целиком, и\n * `GrDropdown` понёс бы классы, которых не рендерит.\n *\n * Набор с единственным потребителем сюда не переезжает вовсе — литералы в его\n * `.vue` находит скан, и это дешевле. Поэтому здесь нет фейда `GrTooltip`.\n */\nexport const panelPopTransition = {\n enter: 'transition ease-[var(--gr-ease-out)] duration-[var(--gr-duration-fast)]',\n enterFrom: 'transform opacity-0 scale-95',\n enterTo: 'transform opacity-100 scale-100',\n leave: 'transition ease-[var(--gr-ease-in)] duration-[var(--gr-duration-fast)]',\n leaveFrom: 'transform opacity-100 scale-100',\n leaveTo: 'transform opacity-0 scale-95',\n} as const\n","/**\n * Общая поверхность всплывающей панели: радиус, рамка, фон, тень.\n *\n * До выноса шесть этих утилит были скопированы пять раз — у поповера,\n * выпадающего меню и трёх списков выбора. Расходились бы молча: разница в одном\n * токене видна только рядом с эталоном, а эталоны у компонентов свои.\n *\n * Фон — `--gr-popover`, и это не выбор из двух равных. Описание токена в\n * `tokens/themes/*.json` — «Фон popover-, dropdown- и overlay-поверхностей», то\n * есть он заведён ровно под этот случай; `--gr-card` — фон карточки. Четверо из\n * пяти брали карточный, и значения совпадали, поэтому расхождение не\n * проявлялось. Проявилось бы у первого, кто перекрасит `--gr-popover`, чтобы\n * отличать всплывающие поверхности от карточек.\n *\n * Всё, что специфично для компонента, — поле, потолок ширины, `overflow` — он\n * дописывает сам: это уже не поверхность, а его собственная раскладка.\n *\n * Модуль безадресный: в `dist` он уезжает в общий чанк, который пресет не\n * сканирует, поэтому каждый потребитель объявляет эти классы в своём `safelist.ts`.\n */\nexport const overlayPanelSurfaceClass = 'rounded-[var(--gr-radius-xl)] border border-[var(--gr-brd)] bg-[var(--gr-popover)] text-[var(--gr-popover-fg)] shadow-[var(--gr-shadow-2)]'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,qBAAqB;CAChC,OAAO;CACP,WAAW;CACX,SAAS;CACT,OAAO;CACP,WAAW;CACX,SAAS;AACX;;;;;;;;;;;;;;;;;;;;;;;ACZA,IAAa,2BAA2B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"ru-88i1WG0b.js","names":[],"sources":["../../src/i18n/locales/ru.json"],"sourcesContent":["{\n \"transfer\": {\n \"sourceTitle\": \"Доступны\",\n \"targetTitle\": \"Выбраны\",\n \"search\": \"Поиск\",\n \"toTarget\": \"Перенести к выбранным\",\n \"toSource\": \"Вернуть к доступным\",\n \"selectAll\": \"Выбрать всё показанное\",\n \"moveUp\": \"Раньше\",\n \"moveDown\": \"Позже\",\n \"selected\": \"{count} из {total}\",\n \"shown\": \"Показано {shown} из {total}\",\n \"empty\": \"Здесь пока пусто\",\n \"emptyFiltered\": \"Ничего не найдено\",\n \"moved\": \"{count} перенесено в «{list}»\",\n \"reordered\": \"Позиция {position} из {count}\",\n \"reorderFiltered\": \"Пока включён поиск, порядок не меняется\",\n \"cancelled\": \"Перенос отменён\"\n },\n \"carousel\": {\n \"roledescription\": \"карусель\",\n \"slideRoledescription\": \"слайд\",\n \"slidePosition\": \"{index} из {total}\",\n \"previous\": \"Предыдущий слайд\",\n \"next\": \"Следующий слайд\",\n \"play\": \"Запустить автопоказ\",\n \"pause\": \"Остановить автопоказ\",\n \"indicators\": \"Слайды\",\n \"autoplayStopped\": \"Автопоказ остановлен\"\n },\n \"chip\": {\n \"remove\": \"Убрать\",\n \"removeNamed\": \"Убрать {label}\"\n },\n \"common\": {\n \"confirm\": \"Подтвердить\",\n \"cancel\": \"Отмена\",\n \"add\": \"Добавить\",\n \"clear\": \"Очистить\",\n \"close\": \"Закрыть\",\n \"stateSuccess\": \"Корректно\",\n \"stateWarning\": \"Предупреждение\"\n },\n \"loading\": {\n \"defaultText\": \"Загрузка...\"\n },\n \"steps\": {\n \"label\": \"Ход выполнения\",\n \"status\": \"Шаг {step} из {count}\",\n \"completed\": \"выполнен\",\n \"error\": \"есть ошибки\"\n },\n \"treeSelect\": {\n \"filterPlaceholder\": \"Поиск…\",\n \"empty\": \"Нет данных\",\n \"loading\": \"Загрузка…\"\n },\n \"badgeWrap\": {\n \"count\": \"{count} новых\"\n },\n \"avatar\": {\n \"group\": \"Участники\",\n \"groupOverflow\": \"и ещё {count}\",\n \"status\": {\n \"online\": \"в сети\",\n \"offline\": \"не в сети\",\n \"busy\": \"занят\",\n \"away\": \"отошёл\"\n }\n },\n \"tree\": {\n \"drag\": \"Перетащить\",\n \"expand\": \"Развернуть\",\n \"collapse\": \"Свернуть\",\n \"moved\": \"{label} перемещён\"\n },\n \"select\": {\n \"customValuePlaceholder\": \"Добавить значение…\",\n \"addOption\": \"Добавить «{value}»\",\n \"clearOption\": \"Не выбрано\",\n \"searchPlaceholder\": \"Поиск…\",\n \"loading\": \"Загрузка…\",\n \"noResults\": \"Ничего не найдено\",\n \"removeTag\": \"Удалить {label}\"\n },\n \"dataTable\": {\n \"loading\": \"Загрузка…\",\n \"empty\": \"Нет данных\",\n \"selectAll\": \"Выбрать все строки\",\n \"selectRow\": \"Выбрать строку\",\n \"sortAsc\": \"Нажмите для сортировки по возрастанию\",\n \"sortDesc\": \"Нажмите для сортировки по убыванию\",\n \"sortNone\": \"Нажмите, чтобы снять сортировку\",\n \"moveColumn\": \"Переставить колонку {label}\",\n \"columnMoved\": \"Колонка {label} перемещена на позицию {position} из {count}\",\n \"resizeColumn\": \"Ширина колонки {label}\",\n \"columnResized\": \"Ширина колонки {label} — {width} пикселей\",\n \"expandRow\": \"Показать подробности\",\n \"collapseRow\": \"Скрыть подробности\",\n \"detailLoading\": \"Загружаем подробности…\",\n \"detailError\": \"Не удалось загрузить подробности\",\n \"detailRetry\": \"Повторить\",\n \"detailExpanded\": \"Подробности строки раскрыты\",\n \"detailCollapsed\": \"Подробности строки свёрнуты\",\n \"detailReady\": \"Подробности строки загружены\"\n },\n \"breadcrumbs\": {\n \"label\": \"Навигационная цепочка\",\n \"expand\": \"Показать скрытые уровни\"\n },\n \"autocomplete\": {\n \"loading\": \"Загрузка…\",\n \"noResults\": \"Ничего не найдено\",\n \"addOption\": \"Добавить «{value}»\",\n \"removeValue\": \"Убрать {label}\",\n \"typeMore\": {\n \"one\": \"Введите минимум {n} символ\",\n \"few\": \"Введите минимум {n} символа\",\n \"many\": \"Введите минимум {n} символов\",\n \"other\": \"Введите минимум {n} символа\"\n }\n },\n \"form\": {\n \"required\": \"Обязательное поле\",\n \"min\": \"Минимум {min}\",\n \"max\": \"Максимум {max}\",\n \"len\": \"Длина должна быть {len}\",\n \"pattern\": \"Неверный формат\",\n \"email\": \"Введите корректный e-mail\",\n \"url\": \"Введите корректный URL\",\n \"file\": \"Некорректный файл\",\n \"invalid\": \"Некорректное значение\",\n \"readonly\": \"Только для чтения\",\n \"validating\": \"Проверяем…\"\n },\n \"dialog\": {\n \"confirm\": {\n \"title\": \"Подтверждение\"\n },\n \"prompt\": {\n \"title\": \"Введите значение\",\n \"label\": \"Значение\",\n \"required\": \"Введите значение.\"\n },\n \"ok\": \"ОК\"\n },\n \"switch\": {\n \"loading\": \"Сохраняем…\",\n \"on\": \"ДА\",\n \"off\": \"НЕТ\"\n },\n \"slider\": {\n \"min\": \"минимум\",\n \"max\": \"максимум\"\n },\n \"sidebar\": {\n \"expand\": \"Развернуть панель\",\n \"collapse\": \"Свернуть панель\"\n },\n \"splitter\": {\n \"label\": \"Изменить размер панелей\"\n },\n \"statistic\": {\n \"trendUp\": \"Рост\",\n \"trendDown\": \"Падение\",\n \"trendFlat\": \"Без изменений\"\n },\n \"pagination\": {\n \"label\": \"Пагинация\",\n \"pageSize\": \"Размер страницы\",\n \"prev\": \"Назад\",\n \"next\": \"Вперёд\",\n \"page\": \"Страница {n}\",\n \"first\": \"Первая страница\",\n \"last\": \"Последняя страница\",\n \"jumpTo\": \"Перейти к\",\n \"total\": \"{from}–{to} из {total}\",\n \"status\": \"Страница {page} из {count}\"\n },\n \"navbar\": {\n \"openMenu\": \"Открыть меню\"\n },\n \"scrollSpy\": {\n \"label\": \"На этой странице\"\n },\n \"responseError\": {\n \"networkTitle\": \"Нет связи с сервером\",\n \"networkMessage\": \"Проверьте подключение к интернету и попробуйте ещё раз.\",\n \"abortedTitle\": \"Запрос отменён\",\n \"abortedMessage\": \"Запрос был отменён.\",\n \"validationTitle\": \"Проверьте данные\",\n \"validationMessage\": \"Сервер вернул ошибку валидации. Исправьте поля и попробуйте снова.\",\n \"clientTitle\": \"Ошибка запроса\",\n \"clientMessage\": \"Сервер отклонил запрос.\",\n \"serverTitle\": \"Ошибка сервера\",\n \"serverMessage\": \"Произошла ошибка на сервере. Попробуйте ещё раз.\",\n \"unknownTitle\": \"Что-то пошло не так\",\n \"unknownMessage\": \"Не удалось выполнить операцию. Попробуйте ещё раз.\",\n \"statusLabel\": \"HTTP {status}\",\n \"retryLabel\": \"Повторить\",\n \"dismissLabel\": \"Скрыть\"\n },\n \"colors\": {\n \"neutral\": \"Нейтральный\",\n \"success\": \"Успех\",\n \"warning\": \"Предупреждение\",\n \"danger\": \"Опасность\",\n \"info\": \"Инфо\",\n \"primary\": \"Primary\",\n \"slate\": \"Сланцевый\",\n \"azure\": \"Лазурный\"\n },\n \"drawer\": {\n \"title\": \"Панель\"\n },\n \"modal\": {\n \"title\": \"Диалог\"\n },\n \"numberInput\": {\n \"increase\": \"Увеличить\",\n \"decrease\": \"Уменьшить\"\n },\n \"toaster\": {\n \"dismiss\": \"Закрыть\",\n \"region\": \"Уведомления\"\n },\n \"inputTag\": {\n \"removeTag\": \"Удалить тег\",\n \"removeTagNamed\": \"Удалить тег {tag}\",\n \"clearAll\": \"Удалить все теги\",\n \"added\": \"Добавлен тег: {tag}\",\n \"addedMany\": \"Добавлено тегов: {count}\",\n \"removed\": \"Удалён тег: {tag}\",\n \"cleared\": \"Все теги удалены\",\n \"limitReached\": \"Достигнут предел тегов\"\n },\n \"fileUpload\": {\n \"placeholder\": \"Перетащите файлы сюда или нажмите для выбора\",\n \"progress\": \"Прогресс загрузки\",\n \"uploading\": \"Загрузка…\",\n \"success\": \"Загрузка завершена\",\n \"error\": \"Не удалось загрузить\",\n \"remove\": \"Убрать {fileName}\",\n \"retry\": \"Повторить загрузку\",\n \"retryFile\": \"Повторить {fileName}\",\n \"abortFile\": \"Отменить загрузку {fileName}\",\n \"statusPending\": \"В очереди\",\n \"statusUploading\": \"Загружается\",\n \"statusSuccess\": \"Загружен\",\n \"statusError\": \"Ошибка\"\n },\n \"formFile\": {\n \"upload\": \"Загрузить файл\",\n \"change\": \"Заменить файл\",\n \"remove\": \"Удалить\",\n \"clearAll\": \"Очистить всё\",\n \"placeholder\": \"Файлы не выбраны\",\n \"validateError\": \"Не удалось проверить перетащенные файлы\",\n \"removeFile\": \"Убрать {fileName}\"\n },\n \"imageViewer\": {\n \"close\": \"Закрыть просмотрщик\",\n \"prev\": \"Предыдущее изображение\",\n \"next\": \"Следующее изображение\",\n \"zoomIn\": \"Увеличить\",\n \"zoomOut\": \"Уменьшить\",\n \"resetZoom\": \"Сбросить масштаб\",\n \"zoomToNatural\": \"Натуральный размер (1:1)\",\n \"rotateLeft\": \"Повернуть влево\",\n \"rotateRight\": \"Повернуть вправо\",\n \"download\": \"Скачать изображение\",\n \"empty\": \"Нет изображения\",\n \"label\": \"Просмотр изображений\",\n \"position\": \"Изображение {index} из {total}\"\n },\n \"formErrorBanner\": {\n \"validationTitle\": \"Проверьте поля формы\",\n \"validationMessage\": \"Сервер отклонил данные. Исправьте выделенные поля и попробуйте снова.\",\n \"clientTitle\": \"Не удалось сохранить\",\n \"serverTitle\": \"Ошибка сохранения\",\n \"serverMessage\": \"Не удалось сохранить данные. Попробуйте позже.\"\n },\n \"uploadErrorBanner\": {\n \"networkTitle\": \"Не удалось загрузить файлы\",\n \"networkMessage\": \"Проверьте подключение и попробуйте снова.\",\n \"validationTitle\": \"Файлы не прошли проверку\",\n \"validationMessage\": \"Некоторые файлы не соответствуют требованиям.\",\n \"serverTitle\": \"Ошибка загрузки на сервере\",\n \"serverMessage\": \"Сервер не смог обработать загрузку. Попробуйте снова.\"\n },\n \"input\": {\n \"clear\": \"Очистить\",\n \"showPassword\": \"Показать пароль\",\n \"hidePassword\": \"Скрыть пароль\",\n \"limitReached\": \"Достигнут предел символов\"\n },\n \"textarea\": {\n \"lines\": {\n \"one\": \"{n} строка\",\n \"few\": \"{n} строки\",\n \"many\": \"{n} строк\",\n \"other\": \"{n} строки\"\n }\n },\n \"rating\": {\n \"label\": \"Оценка\",\n \"valueText\": \"{value} из {max}\",\n \"valueTextWithLabel\": \"{value} из {max}, {label}\"\n },\n \"commandPalette\": {\n \"label\": \"Палитра команд\",\n \"placeholder\": \"Введите команду или запрос…\",\n \"empty\": \"Ничего не найдено\",\n \"recent\": \"Недавние\",\n \"loading\": \"Загрузка…\"\n },\n \"delta\": {\n \"increase\": \"рост\"\n },\n \"filePreview\": {\n \"label\": \"Файл\"\n },\n \"fileValidation\": {\n \"accept\": \"Файл «{fileName}» не подходит под accept=\\\"{accept}\\\"\",\n \"extension\": \"У файла «{fileName}» недопустимое расширение «.{extension}»\",\n \"mimeType\": \"У файла «{fileName}» недопустимый тип «{mimeType}»\",\n \"mimeTypeFallback\": \"У файла «{fileName}» неопределённый тип «{mimeType}»\",\n \"maxFileSize\": \"Файл «{fileName}» слишком большой ({size} байт), максимум {maxBytes}\",\n \"maxCount\": \"Выбрано слишком много файлов ({count}), максимум — {maxCount}\",\n \"maxTotalSize\": \"Суммарный размер файлов слишком большой ({total} байт), максимум {maxBytes}\"\n },\n \"kbd\": {\n \"command\": \"Command\",\n \"option\": \"Option\",\n \"shift\": \"Shift\",\n \"control\": \"Control\",\n \"enter\": \"Enter\",\n \"escape\": \"Escape\",\n \"tab\": \"Tab\",\n \"backspace\": \"Backspace\",\n \"delete\": \"Delete\",\n \"pageUp\": \"Page Up\",\n \"pageDown\": \"Page Down\",\n \"arrowUp\": \"стрелка вверх\",\n \"arrowDown\": \"стрелка вниз\",\n \"arrowLeft\": \"стрелка влево\",\n \"arrowRight\": \"стрелка вправо\",\n \"then\": \"затем\"\n },\n \"link\": {\n \"opensInNewTab\": \"откроется в новой вкладке\"\n },\n \"colorPicker\": {\n \"panelLabel\": \"Выбор цвета\",\n \"hue\": \"Оттенок\",\n \"saturation\": \"Насыщенность\",\n \"lightness\": \"Светлота\",\n \"opacity\": \"Непрозрачность\",\n \"hexLabel\": \"Значение hex\",\n \"presetsLabel\": \"Палитра\",\n \"swatchLabel\": \"Цвет {color}\"\n },\n \"collapse\": {\n \"empty\": \"Пока пусто\"\n },\n \"list\": {\n \"empty\": \"Пока пусто\"\n },\n \"button\": {\n \"loading\": \"Загрузка…\"\n },\n \"table\": {\n \"empty\": \"Пока пусто\"\n },\n \"timeline\": {\n \"empty\": \"Пока пусто\"\n },\n \"tabs\": {\n \"empty\": \"Пока пусто\",\n \"close\": \"Закрыть вкладку\"\n },\n \"bottomNav\": {\n \"label\": \"Нижняя навигация\",\n \"badge\": \"{count} новых\"\n },\n \"emptyState\": {\n \"title\": \"Пока пусто\"\n },\n \"sortable\": {\n \"label\": \"Сортируемый список\",\n \"handle\": \"Переставить\",\n \"empty\": \"Пока нечего сортировать\",\n \"grabbed\": \"Взято. Позиция {position} из {count}\",\n \"moved\": \"Позиция {position} из {count}\",\n \"dropped\": \"Отпущено на позиции {position} из {count}\",\n \"cancelled\": \"Перенос отменён\"\n },\n \"jsonViewer\": {\n \"search\": \"Поиск по ключу или значению\",\n \"expandAll\": \"Раскрыть всё\",\n \"collapseAll\": \"Свернуть всё\",\n \"copy\": \"Скопировать значение\",\n \"copied\": \"Значение скопировано\",\n \"copyFailed\": \"Не удалось скопировать значение\",\n \"moreItems\": \"ещё\"\n },\n \"contextMenu\": {\n \"label\": \"Контекстное меню\"\n }\n}\n"],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrAutocomplete-Chhw65pI.js","names":[],"sources":["../../../../src/components/GrAutocomplete/composables/useRemoteOptions.ts","../../../../src/components/GrAutocomplete/composables/useAutocompleteValues.ts","../../../../src/components/GrAutocomplete/composables/useAutocompletePanel.ts","../../../../src/components/GrAutocomplete/composables/useAutocompleteVirtual.ts","../../../../src/components/GrAutocomplete/composables/useAutocompleteNavigation.ts","../../../../src/components/GrAutocomplete/GrAutocomplete.vue","../../../../src/components/GrAutocomplete/GrAutocomplete.vue"],"sourcesContent":["import type { Ref, ShallowRef } from 'vue'\nimport { onBeforeUnmount, ref, shallowRef, watch } from 'vue'\n\nimport type { GrAutocompleteOption, GrAutocompleteValue } from '../GrAutocomplete.vue'\n\n/**\n * Дебаунснутая удалённая загрузка опций.\n *\n * Три вещи, каждая из которых по отдельности выглядит необязательной, а вместе\n * составляют весь смысл модуля: запрос откладывается на `debounce`, летящий\n * отменяется новым, а ответ, стартовавший раньше и пришедший позже, обязан\n * проиграть последнему — иначе список показывает результат старого запроса.\n *\n * От DOM не зависит вовсе, поэтому проверяется без монтирования компонента.\n *\n * Единственный потребитель сегодня — `GrAutocomplete`. Появится второй\n * (открытая строка аудита: `GrTransfer` отдаёт `search` наружу, а подгрузку\n * делает потребитель) — модулю место в `composables/internal/`.\n */\nexport interface UseRemoteOptionsOptions<TValue extends GrAutocompleteValue> {\n fetchOptions: () => ((query: string, signal: AbortSignal) => Promise<GrAutocompleteOption<TValue>[]>) | undefined\n /** Стартовый список: его смена сбрасывает ответ сервера. */\n options: () => GrAutocompleteOption<TValue>[] | undefined\n debounce: () => number\n minQueryLength: () => number\n onSearch: (query: string) => void\n onSearchError: (error: unknown) => void\n}\n\nexport interface RemoteOptions<TValue extends GrAutocompleteValue> {\n remoteOptions: ShallowRef<GrAutocompleteOption<TValue>[]>\n remoteAnswered: Ref<boolean>\n remoteLoading: Ref<boolean>\n scheduleSearch: (value: string) => void\n cancelSearch: () => void\n}\n\nexport function useRemoteOptions<TValue extends GrAutocompleteValue>(\n options: UseRemoteOptionsOptions<TValue>,\n): RemoteOptions<TValue> {\n // Ответ последнего `fetchOptions`. До первого ответа показываем `options` —\n // с ними компонент рисует стартовый список, не дожидаясь сервера.\n const remoteOptions = shallowRef<GrAutocompleteOption<TValue>[]>([])\n const remoteAnswered = ref(false)\n const remoteLoading = ref(false)\n\n let searchTimer: ReturnType<typeof setTimeout> | null = null\n // Счётчик запросов: ответ, стартовавший раньше, но пришедший позже, обязан\n // проиграть последнему — иначе список показывает результат старого запроса.\n let searchSeq = 0\n let inflight: AbortController | null = null\n\n function isAbortError(error: unknown): boolean {\n return error instanceof Error && error.name === 'AbortError'\n }\n\n async function runFetch(query: string): Promise<void> {\n const fetchOptions = options.fetchOptions()\n if (!fetchOptions)\n return\n\n inflight?.abort()\n const controller = new AbortController()\n inflight = controller\n const seq = ++searchSeq\n remoteLoading.value = true\n\n try {\n const result = await fetchOptions(query, controller.signal)\n if (seq !== searchSeq)\n return\n remoteOptions.value = result\n remoteAnswered.value = true\n }\n catch (error) {\n if (seq !== searchSeq || isAbortError(error))\n return\n remoteOptions.value = []\n remoteAnswered.value = true\n options.onSearchError(error)\n }\n finally {\n if (seq === searchSeq)\n remoteLoading.value = false\n }\n }\n\n function scheduleSearch(value: string): void {\n if (searchTimer)\n clearTimeout(searchTimer)\n searchTimer = setTimeout(() => {\n if (options.minQueryLength() > 0 && value.trim().length < options.minQueryLength())\n return\n options.onSearch(value.trim())\n void runFetch(value.trim())\n }, options.debounce())\n }\n\n /**\n * Снять запланированный и летящий запрос. Инкремент `searchSeq` обязателен\n * вместе со снятием `remoteLoading`: после него `finally` в `runFetch` считает\n * себя устаревшим и флаг не тронет — спиннер остался бы навсегда.\n */\n function cancelSearch(): void {\n if (searchTimer)\n clearTimeout(searchTimer)\n searchTimer = null\n inflight?.abort()\n inflight = null\n searchSeq += 1\n remoteLoading.value = false\n }\n\n /**\n * Подпись состава стартового списка. Сравнивать идентичность массива нельзя:\n * инлайн-литерал `:options=\"[...]\"` пересоздаётся каждым ререндером родителя —\n * в том числе тем, который вызвал сам компонент своим `update:modelValue`, —\n * и remote-результаты исчезали бы прямо посреди выбора.\n */\n function optionsSignature(list: GrAutocompleteOption<TValue>[] | undefined): string {\n return (list ?? []).map(o => `${String(o.value)}\\u0000${o.label}`).join('\\u0001')\n }\n\n // Родитель сменил стартовый список — он снова источник до следующего ответа\n // сервера, а летящий запрос относится к прежнему набору данных и отменяется.\n watch(() => optionsSignature(options.options()), () => {\n if (!options.fetchOptions())\n return\n cancelSearch()\n remoteAnswered.value = false\n remoteOptions.value = []\n })\n\n onBeforeUnmount(cancelSearch)\n\n return { remoteOptions, remoteAnswered, remoteLoading, scheduleSearch, cancelSearch }\n}\n","import type { ComputedRef, Ref, ShallowRef } from 'vue'\nimport { computed } from 'vue'\n\nimport { resolveSelectedOptions } from '../../shared/optionFilter'\nimport type {\n GrAutocompleteModelValue,\n GrAutocompleteOption,\n GrAutocompleteValue,\n} from '../GrAutocomplete.vue'\n\n/**\n * Значение и опции `GrAutocomplete`: что выбрано и как это назвать.\n *\n * Ничего про панель, клавиатуру и вид. Состав списка зависит от того, отвечал\n * ли уже сервер: до первого ответа источник — проп `options`, иначе последний\n * ответ `fetchOptions`.\n */\nexport interface UseAutocompleteValuesOptions<TValue extends GrAutocompleteValue> {\n modelValue: () => GrAutocompleteModelValue<TValue>\n options: () => GrAutocompleteOption<TValue>[] | undefined\n multiple: () => boolean\n fetchOptions: () => unknown\n remoteOptions: ShallowRef<GrAutocompleteOption<TValue>[]>\n remoteAnswered: Ref<boolean>\n}\n\nexport interface AutocompleteValues<TValue extends GrAutocompleteValue> {\n optionsResolved: ComputedRef<GrAutocompleteOption<TValue>[]>\n isEmptyValue: (value: unknown) => boolean\n modelSingle: ComputedRef<TValue | ''>\n selectedValues: ComputedRef<TValue[]>\n hasSelection: ComputedRef<boolean>\n labelFor: (value: GrAutocompleteValue) => string\n selectedOptions: ComputedRef<GrAutocompleteOption<TValue>[]>\n singleSelectedLabel: ComputedRef<string>\n}\n\nexport function useAutocompleteValues<TValue extends GrAutocompleteValue>(\n options: UseAutocompleteValuesOptions<TValue>,\n): AutocompleteValues<TValue> {\n const optionsResolved = computed<GrAutocompleteOption<TValue>[]>(() =>\n options.fetchOptions() && options.remoteAnswered.value\n ? options.remoteOptions.value\n : (options.options() ?? []),\n )\n\n /** `0` — валидное значение, поэтому «пусто» проверяется явно, а не через falsy. */\n function isEmptyValue(value: unknown): boolean {\n return value === undefined || value === null || value === ''\n }\n\n function toArray(value: GrAutocompleteModelValue<TValue>): TValue[] {\n if (Array.isArray(value))\n return value\n if (isEmptyValue(value))\n return []\n return [value]\n }\n\n const modelSingle = computed<TValue | ''>(() => {\n const model = options.modelValue()\n const raw = Array.isArray(model) ? model[0] : model\n return isEmptyValue(raw) ? '' : (raw as TValue)\n })\n\n const selectedValues = computed(() => (\n options.multiple()\n ? toArray(options.modelValue())\n : (isEmptyValue(modelSingle.value) ? [] : [modelSingle.value as TValue])\n ))\n\n const hasSelection = computed(() => selectedValues.value.length > 0)\n\n function labelFor(value: GrAutocompleteValue): string {\n return optionsResolved.value.find(o => o.value === value)?.label ?? String(value)\n }\n\n /** Опции выбранных значений (для chips в multiple). Неизвестные значения показываем как есть. */\n const selectedOptions = computed<GrAutocompleteOption<TValue>[]>(() =>\n resolveSelectedOptions(selectedValues.value, optionsResolved.value),\n )\n\n const singleSelectedLabel = computed(() => (\n options.multiple() || isEmptyValue(modelSingle.value) ? '' : labelFor(modelSingle.value)\n ))\n\n return {\n optionsResolved,\n isEmptyValue,\n modelSingle,\n selectedValues,\n hasSelection,\n labelFor,\n selectedOptions,\n singleSelectedLabel,\n }\n}\n","import type { ComputedRef, Ref } from 'vue'\nimport { computed } from 'vue'\n\nimport { filterOptions } from '../../shared/optionFilter'\nimport type { GrAutocompleteOption, GrAutocompleteValue } from '../GrAutocomplete.vue'\n\n/**\n * Состав панели `GrAutocomplete`: что показывать под запросом.\n *\n * Три решения, которые легко перепутать между собой. При `fetchOptions`\n * локальный матчер выключается — он отсеял бы то, что сервер уже прислал в\n * ответ на этот же запрос. Ниже `minQueryLength` список пуст, а не «прошлый»:\n * показывать старый набор под подсказкой «введите ещё N» значит\n * дезинформировать. А «Add …» не предлагается, если такое значение или подпись\n * уже есть среди опций.\n */\nexport interface UseAutocompletePanelOptions<TValue extends GrAutocompleteValue> {\n optionsResolved: ComputedRef<GrAutocompleteOption<TValue>[]>\n /** Введённый текст без нормализации: тримит уже сам модуль. */\n query: Ref<string>\n /** Пользователь начал ввод — до этого single-режим показывает весь список. */\n dirty: Ref<boolean>\n filterable: () => boolean\n filter: () => ((option: GrAutocompleteOption<TValue>, query: string) => boolean) | undefined\n fetchOptions: () => unknown\n multiple: () => boolean\n minQueryLength: () => number\n allowCustomValue: () => boolean\n selectedValues: ComputedRef<TValue[]>\n modelSingle: ComputedRef<TValue | ''>\n isLoading: ComputedRef<boolean>\n}\n\nexport interface AutocompletePanel<TValue extends GrAutocompleteValue> {\n searchQuery: ComputedRef<string>\n belowMinQuery: ComputedRef<boolean>\n effectiveOptions: ComputedRef<GrAutocompleteOption<TValue>[]>\n canAddCustom: ComputedRef<boolean>\n showEmpty: ComputedRef<boolean>\n}\n\nexport function useAutocompletePanel<TValue extends GrAutocompleteValue>(\n options: UseAutocompletePanelOptions<TValue>,\n): AutocompletePanel<TValue> {\n const searchQuery = computed(() => {\n // При `fetchOptions` фильтрует сервер: локальный матчер отсеял бы то, что он\n // уже прислал в ответ на этот же запрос.\n if (!options.filterable() || options.fetchOptions())\n return ''\n // single: пока пользователь не начал вводить — показываем весь список.\n if (!options.multiple() && !options.dirty.value)\n return ''\n return options.query.value.trim()\n })\n\n const filteredOptions = computed<GrAutocompleteOption<TValue>[]>(() =>\n filterOptions(options.optionsResolved.value, searchQuery.value, options.filter()),\n )\n\n const belowMinQuery = computed(() =>\n options.minQueryLength() > 0 && options.query.value.trim().length < options.minQueryLength(),\n )\n\n /**\n * Опции к показу и навигации. Ниже `minQueryLength` — пусто: список ещё\n * относится к прошлому запросу, показывать его под подсказкой «введите ещё N»\n * значит дезинформировать.\n */\n const effectiveOptions = computed<GrAutocompleteOption<TValue>[]>(() =>\n belowMinQuery.value ? [] : filteredOptions.value,\n )\n\n const canAddCustom = computed(() => {\n if (!options.allowCustomValue())\n return false\n // Кастомное значение набирается текстом — оно строковое по природе;\n // при числовом `TValue` эта ветка неприменима (см. docs/components.md).\n const v = options.query.value.trim() as TValue\n if (!v)\n return false\n if (options.multiple() && options.selectedValues.value.includes(v))\n return false\n if (!options.multiple() && v === options.modelSingle.value)\n return false\n // Не предлагаем «Add», если такое значение/метка уже есть среди опций.\n return !options.optionsResolved.value.some(o => o.value === v || o.label === v)\n })\n\n const showEmpty = computed(() =>\n !options.isLoading.value && effectiveOptions.value.length === 0 && !canAddCustom.value,\n )\n\n return { searchQuery, belowMinQuery, effectiveOptions, canAddCustom, showEmpty }\n}\n","import type { ComputedRef, Ref } from 'vue'\nimport { computed } from 'vue'\n\nimport { useVirtualList } from '../../../composables/useVirtualList'\nimport type { GrAutocompleteOption, GrAutocompleteValue } from '../GrAutocomplete.vue'\n\n/** Оценка высоты опции: `py-2` вокруг строки кегля `sm`. Уточняется замером. */\nconst OPTION_SIZE_ESTIMATE = 36\n\n/**\n * Виртуализация панели `GrAutocomplete`.\n *\n * Набор — `[«Add …»?] + effectiveOptions`, тот же, по которому ходит клавиатура.\n * Иначе верхняя распорка вытолкнула бы строку «Add …» вниз: она отрисована\n * внутри listbox'а первой и является полноценной опцией. Отсюда `addOffset`,\n * который сдвигает окно виртуализатора относительно индексов в списке опций.\n */\nexport interface UseAutocompleteVirtualOptions<TValue extends GrAutocompleteValue> {\n /** Контейнер списка: по нему считается окно и замеряются строки. */\n listboxEl: Ref<HTMLElement | null>\n effectiveOptions: ComputedRef<GrAutocompleteOption<TValue>[]>\n canAddCustom: ComputedRef<boolean>\n virtual: () => boolean\n dropdownMaxHeight: () => number\n}\n\nexport interface AutocompleteVirtual<TValue extends GrAutocompleteValue> {\n /** Сдвиг окна из-за строки «Add …»: она идёт нулевым элементом набора. */\n addOffset: ComputedRef<number>\n virtualCount: ComputedRef<number>\n virtualizer: ReturnType<typeof useVirtualList>\n showAddOption: ComputedRef<boolean>\n renderedOptions: ComputedRef<Array<{ option: GrAutocompleteOption<TValue>, index: number }>>\n optionSetProps: (virtualIndex: number) => Record<string, number> | undefined\n listboxStyle: ComputedRef<Record<string, string>>\n}\n\nexport function useAutocompleteVirtual<TValue extends GrAutocompleteValue>(\n options: UseAutocompleteVirtualOptions<TValue>,\n): AutocompleteVirtual<TValue> {\n const addOffset = computed(() => (options.canAddCustom.value ? 1 : 0))\n const virtualCount = computed(() => options.effectiveOptions.value.length + addOffset.value)\n\n const virtualizer = useVirtualList({\n container: options.listboxEl,\n count: () => (options.virtual() ? virtualCount.value : 0),\n // Фильтрация/remote-ответ пересобирают набор — замеры прошлого невалидны.\n source: () => options.effectiveOptions.value,\n itemSize: OPTION_SIZE_ESTIMATE,\n // Панель скрыта `v-show`, пока закрыта, поэтому `clientHeight` контейнера —\n // ноль. Окно считается от объявленной высоты до первого настоящего замера.\n viewportSize: () => options.dropdownMaxHeight(),\n })\n\n /** Виден ли «Add …»: вне виртуального окна его рисовать нельзя — он элемент набора. */\n const showAddOption = computed(() => {\n if (!options.canAddCustom.value)\n return false\n return !options.virtual() || virtualizer.range.value.start === 0\n })\n\n /** Опции к отрисовке вместе с их абсолютным индексом в `effectiveOptions`. */\n const renderedOptions = computed(() => {\n const all = options.effectiveOptions.value\n if (!options.virtual())\n return all.map((option, index) => ({ option, index }))\n\n const { start, end } = virtualizer.range.value\n const from = Math.max(0, start - addOffset.value)\n const to = Math.max(0, end - addOffset.value)\n\n return all.slice(from, to).map((option, offset) => ({ option, index: from + offset }))\n })\n\n /**\n * Размер набора и позиция в нём объявляются только при виртуализации: в обычном\n * режиме диктор выводит их из DOM, а при неполном наборе получил бы «3 из 15»\n * на списке в десять тысяч.\n */\n function optionSetProps(virtualIndex: number): Record<string, number> | undefined {\n if (!options.virtual())\n return undefined\n return { 'aria-setsize': virtualCount.value, 'aria-posinset': virtualIndex + 1 }\n }\n\n const listboxStyle = computed(() => {\n const base: Record<string, string> = { maxHeight: `${options.dropdownMaxHeight()}px` }\n if (!options.virtual())\n return base\n\n return {\n ...base,\n ...virtualizer.spacerStyle.value,\n }\n })\n\n return { addOffset, virtualCount, virtualizer, showAddOption, renderedOptions, optionSetProps, listboxStyle }\n}\n","import type { ComputedRef, Ref } from 'vue'\nimport { computed, nextTick } from 'vue'\n\nimport { useComboboxNavigation } from '../../../composables/useComboboxNavigation'\nimport type { GrAutocompleteOption, GrAutocompleteValue } from '../GrAutocomplete.vue'\n\n/**\n * Клавиатурная навигация ходит и по опциям, и по варианту «добавить своё»:\n * иначе при непустом списке Enter всегда уходил бы в активную опцию, и\n * закоммитить произвольное значение с клавиатуры было бы нечем.\n */\nexport type GrAutocompleteNavigableItem<TValue extends GrAutocompleteValue>\n = | { kind: 'add' }\n | { kind: 'option', option: GrAutocompleteOption<TValue>, index: number }\n\nexport interface UseAutocompleteNavigationOptions<TValue extends GrAutocompleteValue> {\n effectiveOptions: ComputedRef<GrAutocompleteOption<TValue>[]>\n canAddCustom: ComputedRef<boolean>\n selectedValues: ComputedRef<TValue[]>\n open: Ref<boolean>\n virtual: () => boolean\n /** Сдвиг окна из-за строки «Add …» — из модуля виртуализации. */\n addOffset: ComputedRef<number>\n scrollToIndex: (index: number) => void\n optionDomId: (index: number) => string\n addOptionDomId: ComputedRef<string>\n}\n\nexport interface AutocompleteNavigation<TValue extends GrAutocompleteValue> {\n navigableItems: ComputedRef<Array<GrAutocompleteNavigableItem<TValue>>>\n isSelected: (value: TValue) => boolean\n navigableIndexOf: (value: TValue) => number\n activeIndex: Ref<number>\n activeItem: ComputedRef<GrAutocompleteNavigableItem<TValue> | undefined>\n activeDescendantId: ComputedRef<string | undefined>\n activeValue: ComputedRef<TValue | undefined>\n initActiveIndex: () => void\n resetActive: () => void\n handleNavigationKeys: (event: KeyboardEvent) => boolean\n}\n\nexport function useAutocompleteNavigation<TValue extends GrAutocompleteValue>(\n options: UseAutocompleteNavigationOptions<TValue>,\n): AutocompleteNavigation<TValue> {\n type Item = GrAutocompleteNavigableItem<TValue>\n\n const navigableItems = computed<Item[]>(() => {\n const items: Item[] = options.canAddCustom.value ? [{ kind: 'add' }] : []\n options.effectiveOptions.value.forEach((option, index) => {\n if (!option.disabled)\n items.push({ kind: 'option', option, index })\n })\n return items\n })\n\n function isSelected(value: TValue): boolean {\n return options.selectedValues.value.includes(value)\n }\n\n function navigableIndexOf(value: TValue): number {\n return navigableItems.value.findIndex(item => item.kind === 'option' && item.option.value === value)\n }\n\n /** Прокрутка к активному: сперва окно виртуального списка, затем доводка. */\n async function scrollActiveIntoView(item: Item): Promise<void> {\n // Вне окна активной опции в DOM нет: `getElementById` вернул бы `null`,\n // прокрутка не случилась бы, а `aria-activedescendant` указал бы в пустоту.\n if (options.virtual())\n options.scrollToIndex(item.kind === 'add' ? 0 : item.index + options.addOffset.value)\n\n await nextTick()\n const id = item.kind === 'add' ? options.addOptionDomId.value : options.optionDomId(item.index)\n document.getElementById(id)?.scrollIntoView?.({ block: 'nearest' })\n }\n\n const {\n activeIndex,\n activeItem,\n activeDescendantId,\n init: initActiveIndex,\n reset: resetActive,\n handleNavigationKeys,\n } = useComboboxNavigation<Item>({\n items: () => navigableItems.value,\n open: () => options.open.value,\n idOf: item => (item.kind === 'add' ? options.addOptionDomId.value : options.optionDomId(item.index)),\n initialIndex: () => navigableItems.value.findIndex(\n item => item.kind === 'option' && isSelected(item.option.value),\n ),\n scrollTo: item => scrollActiveIntoView(item),\n })\n\n const activeValue = computed(() => (\n activeItem.value?.kind === 'option' ? activeItem.value.option.value : undefined\n ))\n\n return {\n navigableItems,\n isSelected,\n navigableIndexOf,\n activeIndex,\n activeItem,\n activeDescendantId,\n activeValue,\n initActiveIndex,\n resetActive,\n handleNavigationKeys,\n }\n}\n","<script setup lang=\"ts\" generic=\"TValue extends GrAutocompleteValue = string\">\nimport { computed, nextTick, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { useGrComponentProp, useGrComponentSize, useGrThemeAttrs } from '../GrConfigProvider/context'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating } from '../../composables/useFloating'\nimport { useDismissible } from '../../composables/useDismissible'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useRemoteOptions } from './composables/useRemoteOptions'\nimport { useAutocompleteValues } from './composables/useAutocompleteValues'\nimport { useAutocompletePanel } from './composables/useAutocompletePanel'\nimport { useAutocompleteVirtual } from './composables/useAutocompleteVirtual'\nimport { useAutocompleteNavigation } from './composables/useAutocompleteNavigation'\nimport { isComposingEvent } from '../../internal/keyboard'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\n\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge/grBadgeStyles'\nimport GrChip from '../GrChip/GrChip.vue'\nimport { chipSizeForBadgeScale } from '../GrChip/grChipStyles'\nimport { panelPopTransition } from '../shared/overlayTransition'\n\nimport {\n autocompleteOptionClass,\n autocompletePanelClasses,\n autocompleteShellClass,\n autocompleteStateClass,\n type GrAutocompleteModelValue,\n type GrAutocompleteOption,\n type GrAutocompleteValue,\n type GrAutocompleteSize,\n} from './grAutocompleteStyles'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronDown from '~icons/lucide/chevron-down'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconX from '~icons/lucide/x'\n\nexport type {\n GrAutocompleteModelValue,\n GrAutocompleteOption,\n GrAutocompleteSize,\n GrAutocompleteValue,\n} from './grAutocompleteStyles'\n\n/**\n * Публичный GR-примитив «Autocomplete / Combobox» (WAI-ARIA editable combobox).\n *\n * В отличие от `GrSelect` (select-only combobox с кнопкой-триггером), здесь\n * combobox-ом является сам текстовый `<input>`: набранный текст — это поисковый\n * запрос, а выбор опции заполняет поле. Поддерживает локальную фильтрацию,\n * удалённую (async) загрузку через событие `search` + внешний проп `loading`,\n * произвольные значения (`allowCustomValue`) и multiple с удаляемыми chips.\n */\nexport interface GrAutocompleteProps<TValue extends GrAutocompleteValue = string> {\n /** Выбранное значение (single — строка, multiple — массив строк). */\n modelValue: GrAutocompleteModelValue<TValue>\n /**\n * Доступные опции. Для локального режима — полный список (фильтруется на клиенте).\n * Для remote-режима (`filterable=false`) — список, который родитель обновляет\n * в ответ на событие `search`.\n */\n options?: GrAutocompleteOption<TValue>[]\n multiple?: boolean\n /**\n * Вид чипов выбранных значений в режиме `multiple`. Рисует их `GrChip`, но\n * шкала пропа осталась бейджевой: `tagSize` публичен, и его значения обязаны\n * означать тот же кегль, что и раньше. Перевод ступеней — в\n * `chipSizeForBadgeScale`.\n */\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n disabled?: boolean\n /** Только для чтения: значение видно и уходит в форму, но не редактируется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n size?: GrAutocompleteSize\n placeholder?: string\n ariaLabel?: string\n /** Кнопка очистки выбранного значения/запроса. */\n clearable?: boolean\n /** Внешне управляемое состояние загрузки (для async-сценариев). */\n loading?: boolean\n /**\n * Локальная фильтрация опций по введённому запросу. Отключите (`false`) для\n * чисто удалённого поиска — тогда `options` показываются как есть, а фильтрацию\n * выполняет сервер по событию `search`.\n */\n filterable?: boolean\n /** Кастомный матчер локальной фильтрации. По умолчанию — подстрока в `label`/`value`. */\n filter?: (option: GrAutocompleteOption<TValue>, query: string) => boolean\n /**\n * Удалённая загрузка опций под управлением компонента: дебаунс, отмена\n * устаревшего запроса и `loading` берёт на себя он. Ответ на отменённый\n * запрос игнорируется — при быстром вводе в списке всегда результат\n * последнего запроса, а не того, который вернулся позже.\n *\n * `signal` пробрасывается в `fetch`. Локальная фильтрация в этом режиме\n * выключена: список фильтрует сервер. Альтернатива — событие `search`, если\n * запрос ведёт само приложение.\n */\n fetchOptions?: (query: string, signal: AbortSignal) => Promise<GrAutocompleteOption<TValue>[]>\n /** Минимальная длина запроса до эмита `search` (для дебаунса remote-загрузки). */\n minQueryLength?: number\n /** Задержка дебаунса события `search`, мс. */\n debounce?: number\n /** Разрешить ввод/коммит значения, которого нет в `options`. */\n allowCustomValue?: boolean\n /** Закрывать панель после выбора (single всегда закрывает). */\n closeOnSelect?: boolean\n /** Максимальная высота панели, px. */\n dropdownMaxHeight?: number\n /**\n * Виртуализация панели: в DOM живёт только окно вокруг вьюпорта.\n *\n * Высоту окна задаёт `dropdownMaxHeight`. Включается осознанно: на сотне\n * опций выигрыша нет, а в разметке остаётся только окно — вместе с ним\n * меняется и то, что находит `querySelector` потребителя. Профильный\n * сценарий — удалённый поиск по справочнику на тысячи позиций.\n */\n virtual?: boolean\n /** i18n-тексты состояний панели / aria. */\n loadingText?: string\n noResultsText?: string\n clearLabel?: string\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n /** Имя для нативной формы: hidden input по значению модели (не по тексту запроса). */\n name?: string\n /**\n * Ширины аддонов `prefix`/`suffix` — общий контракт контролов пакета\n * (`docs/form-controls.md`).\n */\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n prefixFixed?: boolean\n suffixFixed?: boolean\n}\n\nexport interface GrAutocompleteEmits<TValue extends GrAutocompleteValue = string> {\n (e: 'update:modelValue', value: GrAutocompleteModelValue<TValue>): void\n /** Дебаунснутый поисковый запрос — точка входа для удалённой загрузки опций. */\n (e: 'search', query: string): void\n /** Запрос `fetchOptions` завершился ошибкой (отмена устаревшего сюда не приходит). */\n (e: 'searchError', error: unknown): void\n /** Значение зафиксировано выбором или снятием опции. */\n (e: 'change', value: GrAutocompleteModelValue<TValue>): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n /** Значение снято кнопкой очистки; только при `clearable`. */\n (e: 'clear'): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrAutocompleteProps<TValue>>(),\n {\n options: undefined,\n multiple: false,\n tagTone: 'neutral',\n tagDark: false,\n // `sm`, а не `md` как у `GrInputTag`: чип живёт внутри контрола, а не в тексте.\n tagSize: 'sm',\n tagRadius: 'round',\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n size: undefined,\n placeholder: undefined,\n ariaLabel: undefined,\n clearable: undefined,\n loading: false,\n filterable: true,\n filter: undefined,\n fetchOptions: undefined,\n minQueryLength: 0,\n debounce: 250,\n allowCustomValue: false,\n closeOnSelect: true,\n dropdownMaxHeight: 280,\n virtual: false,\n loadingText: undefined,\n noResultsText: undefined,\n clearLabel: undefined,\n open: undefined,\n name: undefined,\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n prefixFixed: false,\n suffixFixed: false,\n },\n)\n\n/** Ширина аддона по умолчанию — та же лестница, что у `GrInput`. */\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrAutocompleteSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrAutocomplete' })\nconst resolvedClearable = useGrComponentProp('GrAutocomplete', 'clearable', () => props.clearable, false)\n\n/**\n * Аддоны живут флекс-соседями поля, а не поверх него: оболочка автокомплита —\n * флекс-строка с чипами, поэтому резервировать место паддингом не нужно.\n * Контракт ширин остаётся общим (`useControlAddons`).\n */\nconst { hasPrefix, hasSuffix, prefixEl, suffixEl, prefixStyle, suffixStyle } = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => '0px',\n})\n\nconst emit = defineEmits<GrAutocompleteEmits<TValue>>()\ndefineSlots<{\n /** Аддон слева от поля ввода. */\n prefix?: () => any\n /** Аддон справа, перед спиннером и крестиком. */\n suffix?: () => any\n /** Строка списка вместо подписи опции. */\n option?: (props: { option: GrAutocompleteOption<TValue>, selected: boolean }) => any\n /** Содержимое панели, пока едут опции. */\n loading?: () => any\n /** Содержимое панели, когда подходящих опций нет. */\n empty?: () => any\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedLoadingText = computed(() => props.loadingText ?? t('gr.autocomplete.loading', 'Loading…'))\nconst resolvedNoResultsText = computed(() => props.noResultsText ?? t('gr.autocomplete.noResults', 'No results'))\nconst resolvedClearLabel = computed(() => props.clearLabel ?? t('gr.common.clear', 'Clear'))\n// Число уходит под двумя общепринятыми именами: `n` читают `@feugene/fint-i18n`\n// и `vue-i18n`, `count` — `i18next`. Формы для каждого языка лежат в словаре,\n// выбирает их переводчик; встроенный fallback — одна английская строка.\nconst resolvedTypeMoreText = computed(() =>\n t('gr.autocomplete.typeMore', 'Type at least {n} characters', {\n n: props.minQueryLength,\n count: props.minQueryLength,\n }),\n)\n\n// Fallback из контекста `GrFormField` (id/aria-describedby/invalid/required).\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\nconst describedBy = computed(() => field?.describedById.value)\n\n// Read-only запирает контрол так же, как disabled: значение видно, но панель не\n// открывается, опции не выбираются и чипы не удаляются. Без этого `readonly`\n// оставался бы ARIA-атрибутом без поведения.\nconst locked = computed(() => isDisabled.value || isReadonly.value)\n\nconst { remoteOptions, remoteAnswered, remoteLoading, scheduleSearch } = useRemoteOptions<TValue>({\n fetchOptions: () => props.fetchOptions,\n options: () => props.options,\n debounce: () => props.debounce,\n minQueryLength: () => props.minQueryLength,\n onSearch: value => emit('search', value),\n onSearchError: error => emit('searchError', error),\n})\n\nconst {\n optionsResolved,\n modelSingle,\n selectedValues,\n hasSelection,\n selectedOptions,\n singleSelectedLabel,\n} = useAutocompleteValues<TValue>({\n modelValue: () => props.modelValue,\n options: () => props.options,\n multiple: () => props.multiple,\n fetchOptions: () => props.fetchOptions,\n remoteOptions,\n remoteAnswered,\n})\n\nconst isLoading = computed(() => props.loading || remoteLoading.value)\n\n// ————— Состояние.\nconst query = ref('')\n// `dirty` — пользователь начал вводить запрос. Нужно, чтобы в single-режиме при\n// открытии заполненного поля показать весь список (а не отфильтровать по метке\n// уже выбранной опции). Сбрасывается при программной установке `query`.\nconst dirty = ref(false)\n// Имя `open` сохранено: читатели работают с computed-Ref.\nconst { open, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst listboxEl = ref<HTMLElement | null>(null)\n\n// Панель телепортирована в `body`, то есть лежит вне корня, но для пользователя\n// она часть контрола: без неё уход фокуса в панель читался бы как `blur`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n containers: () => [panelEl.value],\n})\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\nfunction blur(): void {\n inputEl.value?.blur()\n}\n\ndefineExpose({\n focus,\n blur,\n open: () => openDropdown(),\n close: () => closeDropdown(),\n})\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst { floatingStyle } = useFloating(rootEl, panelEl, open, {\n placement: 'bottom-start',\n matchWidth: true,\n zIndexVar: '--gr-z-dropdown',\n})\n\nuseDismissible(open, closeDropdown)\n\nconst { belowMinQuery, effectiveOptions, canAddCustom, showEmpty } = useAutocompletePanel<TValue>({\n optionsResolved,\n query,\n dirty,\n filterable: () => props.filterable,\n filter: () => props.filter,\n fetchOptions: () => props.fetchOptions,\n multiple: () => props.multiple,\n minQueryLength: () => props.minQueryLength,\n allowCustomValue: () => props.allowCustomValue,\n selectedValues,\n modelSingle,\n isLoading,\n})\n\n// ————— Панель: id/aria-activedescendant.\nconst listboxId = useId()\n\n/**\n * Id опции строится от позиции, а не от значения: значение с пробелом дало бы\n * невалидный `id`, а `aria-activedescendant` — два токена вместо одной ссылки,\n * и активная опция перестала бы объявляться.\n */\nfunction optionDomId(index: number): string {\n return `${listboxId}-opt-${index}`\n}\nconst addOptionDomId = computed(() => `${listboxId}-add`)\n\nconst {\n addOffset,\n virtualizer,\n showAddOption,\n renderedOptions,\n optionSetProps,\n listboxStyle,\n} = useAutocompleteVirtual<TValue>({\n listboxEl,\n effectiveOptions,\n canAddCustom,\n virtual: () => props.virtual,\n dropdownMaxHeight: () => props.dropdownMaxHeight,\n})\n\nconst {\n isSelected,\n navigableIndexOf,\n activeIndex,\n activeItem,\n activeDescendantId,\n activeValue,\n initActiveIndex,\n resetActive,\n handleNavigationKeys,\n} = useAutocompleteNavigation<TValue>({\n effectiveOptions,\n canAddCustom,\n selectedValues,\n open,\n virtual: () => props.virtual,\n addOffset,\n scrollToIndex: index => virtualizer.scrollToIndex(index),\n optionDomId,\n addOptionDomId,\n})\n\n// ————— Открытие/закрытие.\nfunction openDropdown(): void {\n if (locked.value || open.value)\n return\n setOpen(true)\n}\n\nfunction closeDropdown(): void {\n setOpen(false)\n}\n\nfunction focusInput(): void {\n inputEl.value?.focus()\n}\n\n// ————— Ввод.\nfunction onInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value\n query.value = value\n dirty.value = true\n openDropdown()\n scheduleSearch(value)\n}\n\nfunction onFocus(): void {\n if (locked.value)\n return\n openDropdown()\n}\n\nfunction setQuery(value: string): void {\n query.value = value\n dirty.value = false\n}\n\n// ————— Выбор значений.\nfunction selectSingle(value: TValue, label: string): void {\n emit('update:modelValue', value)\n emit('change', value as GrAutocompleteModelValue<TValue>)\n setQuery(label)\n closeDropdown()\n}\n\nfunction toggleMultiple(value: TValue): void {\n const next = selectedValues.value.slice()\n const idx = next.indexOf(value)\n if (idx >= 0)\n next.splice(idx, 1)\n else next.push(value)\n emit('update:modelValue', next)\n emit('change', next as GrAutocompleteModelValue<TValue>)\n setQuery('')\n if (props.closeOnSelect)\n closeDropdown()\n else void nextTick(focusInput)\n}\n\nfunction chooseOption(option: GrAutocompleteOption<TValue>): void {\n if (locked.value || option.disabled)\n return\n if (props.multiple)\n toggleMultiple(option.value)\n else selectSingle(option.value, option.label)\n}\n\nfunction commitCustom(): void {\n if (locked.value)\n return\n // Кастомное значение строковое по природе — см. `canAddCustom`.\n const v = query.value.trim() as TValue\n if (!v)\n return\n if (props.multiple)\n toggleMultiple(v)\n else selectSingle(v, String(v))\n}\n\nfunction removeValue(value: TValue, focusAfter: () => void = focusInput): void {\n if (locked.value)\n return\n const next = selectedValues.value.filter(v => v !== value)\n emit('update:modelValue', next)\n emit('change', next as GrAutocompleteModelValue<TValue>)\n void nextTick(focusAfter)\n}\n\nfunction clearSelection(): void {\n if (locked.value)\n return\n const next = (props.multiple ? [] : '') as GrAutocompleteModelValue<TValue>\n emit('update:modelValue', next)\n emit('change', next)\n emit('clear')\n setQuery('')\n void nextTick(focusInput)\n}\n\nconst showClear = computed(() =>\n resolvedClearable.value && !locked.value && (hasSelection.value || query.value.length > 0),\n)\n\n// ————— Чипы (multiple): стрелки вместо таб-стопов.\n//\n// Крестики намеренно не табируемы: у combobox фокус живёт на `<input>`, и\n// двадцать выбранных значений не должны давать двадцать остановок Tab. Поэтому\n// вход в чипы — ArrowLeft из пустого запроса, а выход — ArrowRight/Esc/печать.\n//\n// Отсюда же единственное отличие от `GrInputTag`: `tabindexFor` здесь не\n// используется. Кольцо нужно как движок навигации, а таб-стоп у ряда чипов\n// отсутствует вовсе — он принадлежит полю ввода.\nconst chipRefs = ref<Array<{ removeEl: HTMLButtonElement | null } | null>>([])\n\nfunction setChipRef(index: number) {\n return (el: unknown): void => {\n chipRefs.value[index] = el as { removeEl: HTMLButtonElement | null } | null\n }\n}\n\n/**\n * Проп `tagSize` объявлен по шкале бейджа и остаётся публичным контрактом:\n * дефолт `sm` обязан означать для потребителя тот же кегль, что и раньше.\n */\nconst chipSize = computed(() => chipSizeForBadgeScale(props.tagSize))\n\n// Адресация индексом, а не значением: значения дженерик-типа, и `TValue`\n// сравнивался бы по ссылке там, где опции пересоздаются.\nconst chipIndexes = computed(() => selectedOptions.value.map((_, index) => index))\n\nconst chipRoving = useRovingFocus<number>({\n items: () => chipIndexes.value,\n elementFor: index => chipRefs.value[index]?.removeEl,\n orientation: () => 'horizontal',\n // Ряд чипов — не кольцо: за правым краем стоит поле ввода, за левым ничего.\n wrap: () => false,\n onOverflow: (edge) => {\n if (edge === 'end')\n focusInput()\n return true\n },\n // Удаление чипа перерисовывает ряд: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\n\nfunction focusChip(index: number): void {\n const last = selectedOptions.value.length - 1\n if (last < 0) {\n focusInput()\n return\n }\n\n void chipRoving.focusKey(Math.min(Math.max(index, 0), last))\n}\n\nfunction onChipKeydown(event: KeyboardEvent, index: number, value: TValue): void {\n if (chipRoving.handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'Delete':\n case 'Backspace':\n event.preventDefault()\n removeValue(value, () => focusChip(index))\n break\n case 'Escape':\n event.preventDefault()\n focusInput()\n break\n default:\n // Печатный символ возвращает в поле: фокус переезжает синхронно, до\n // вставки текста, поэтому символ попадает в запрос, а не пропадает.\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey)\n focusInput()\n }\n}\n\n// ————— Клавиатура.\nfunction onKeydown(event: KeyboardEvent): void {\n // Клавиша во время IME-композиции принадлежит композиции: Enter коммитит её,\n // Esc отменяет, стрелки ходят по кандидатам.\n if (isComposingEvent(event))\n return\n if (locked.value)\n return\n\n // Курсор в начале пустого запроса — стрелка влево уходит к чипам, а не\n // двигает каретку, которой всё равно некуда двигаться.\n if (event.key === 'ArrowLeft' && props.multiple && query.value === '' && selectedValues.value.length) {\n event.preventDefault()\n closeDropdown()\n focusChip(selectedValues.value.length - 1)\n return\n }\n\n if (!open.value && ['ArrowDown', 'ArrowUp'].includes(event.key)) {\n event.preventDefault()\n openDropdown()\n return\n }\n\n // Только при открытой панели: в закрытом инпуте Home/End двигают каретку.\n if (open.value && handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'Enter': {\n if (!open.value)\n break\n event.preventDefault()\n const item = activeItem.value\n if (item?.kind === 'option')\n chooseOption(item.option)\n else if (item?.kind === 'add' || canAddCustom.value)\n commitCustom()\n break\n }\n case 'Backspace':\n // multiple: пустой запрос + Backspace удаляет последний chip.\n if (props.multiple && query.value === '' && selectedValues.value.length) {\n event.preventDefault()\n removeValue(selectedValues.value[selectedValues.value.length - 1])\n }\n break\n case 'Tab':\n closeDropdown()\n break\n }\n}\n\n// ————— Синхронизация query с выбранным значением (single).\nwatch(\n [singleSelectedLabel, () => props.multiple],\n ([label, multiple]) => {\n if (multiple)\n return\n // Не перетираем то, что пользователь сейчас набирает.\n if (open.value || dirty.value)\n return\n setQuery(label)\n },\n { immediate: true },\n)\n\nwatch(open, (isOpen) => {\n if (isOpen) {\n initActiveIndex()\n return\n }\n // Закрытие: сбрасываем активную опцию и «черновик».\n resetActive()\n if (props.multiple) {\n setQuery('')\n }\n else {\n // single: возвращаем метку выбранной опции (revert ввода без выбора).\n setQuery(singleSelectedLabel.value)\n }\n})\n\nconst ariaAutocomplete = computed(() => (props.allowCustomValue ? 'both' : 'list'))\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget()\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: closeDropdown, enabled: open, exclude: clickOutsideExclude }\"\n data-gr-autocomplete\n class=\"relative w-full\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <div\n data-gr-autocomplete-shell\n :class=\"autocompleteShellClass({ size: resolvedSize, disabled: isDisabled, invalid: isInvalid })\"\n @mousedown.self.prevent=\"focusInput\"\n >\n <span\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-autocomplete-prefix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"prefixStyle\"\n >\n <slot name=\"prefix\" />\n </span>\n\n <!-- Chips выбранных значений (multiple). -->\n <template v-if=\"multiple\">\n <GrChip\n v-for=\"(option, chipIndex) in selectedOptions\"\n :key=\"option.value\"\n :ref=\"setChipRef(chipIndex)\"\n data-gr-autocomplete-chip\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"chipSize\"\n :radius=\"tagRadius\"\n :closable=\"!locked\"\n :remove-label=\"t('gr.autocomplete.removeValue', 'Remove {label}', { label: option.label })\"\n :remove-tabindex=\"-1\"\n @remove=\"removeValue(option.value)\"\n @keydown=\"onChipKeydown($event, chipIndex, option.value)\"\n >\n <span class=\"truncate\">{{ option.label }}</span>\n </GrChip>\n </template>\n\n <input\n :id=\"resolvedId\"\n ref=\"inputEl\"\n data-gr-autocomplete-input\n data-testid=\"gr-autocomplete-input\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n role=\"combobox\"\n :value=\"query\"\n :disabled=\"isDisabled\"\n :placeholder=\"hasSelection && multiple ? undefined : placeholder\"\n :aria-label=\"ariaLabel\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :readonly=\"isReadonly\"\n aria-haspopup=\"listbox\"\n :aria-autocomplete=\"ariaAutocomplete\"\n :aria-controls=\"open ? listboxId : undefined\"\n :aria-activedescendant=\"activeDescendantId\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n class=\"min-w-0 flex-1 bg-transparent text-inherit placeholder:text-[var(--gr-muted-fg)] focus:outline-none disabled:cursor-not-allowed\"\n @input=\"onInput\"\n @focus=\"onFocus\"\n @keydown=\"onKeydown\"\n >\n\n <span\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-autocomplete-suffix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"suffixStyle\"\n >\n <slot name=\"suffix\" />\n </span>\n\n <!-- Trailing: спиннер / очистка / шеврон. -->\n <span\n v-if=\"isLoading\"\n data-gr-autocomplete-spinner\n class=\"shrink-0 flex items-center text-[var(--gr-muted-fg)]\"\n >\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n </span>\n\n <button\n v-else-if=\"showClear\"\n type=\"button\"\n data-testid=\"gr-autocomplete-clear\"\n data-gr-autocomplete-clear\n class=\"shrink-0 inline-flex h-5 w-5 items-center justify-center rounded-[var(--gr-radius-control)] text-[var(--gr-muted-fg)] hover:text-[var(--gr-fg)]\"\n :aria-label=\"resolvedClearLabel\"\n @click=\"clearSelection\"\n >\n <IconX class=\"block h-4 w-4\" aria-hidden=\"true\" />\n </button>\n\n <span\n v-else\n data-testid=\"gr-autocomplete-chevron\"\n class=\"shrink-0 flex items-center text-[var(--gr-muted-fg)] pointer-events-none\"\n >\n <IconChevronDown class=\"block h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </div>\n\n <!-- Нативная форма: сериализуется модель, а не текст запроса. -->\n <template v-if=\"name\">\n <input\n v-for=\"value in selectedValues\"\n :key=\"`hidden-${String(value)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(value)\"\n >\n </template>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-testid=\"gr-autocomplete-panel\"\n v-bind=\"themeAttrs\"\n data-gr-autocomplete-panel\n data-gr-overlay-root\n :style=\"floatingStyle\"\n >\n <div :class=\"autocompletePanelClasses\">\n <!--\n Пустой listbox не рендерим: его `p-1` давал полосу пустоты над\n строкой состояния, и «ничего не найдено» выглядело прижатым к низу.\n -->\n <div\n v-if=\"showAddOption || renderedOptions.length\"\n :id=\"listboxId\"\n ref=\"listboxEl\"\n data-gr-autocomplete-listbox\n :data-gr-virtual=\"virtual ? '' : undefined\"\n class=\"p-1 overflow-auto\"\n :class=\"virtual ? 'flex flex-col' : ''\"\n :style=\"listboxStyle\"\n role=\"listbox\"\n :aria-multiselectable=\"multiple ? 'true' : undefined\"\n >\n <!--\n Прямые потомки listbox — только опции: роль объявляет остальных\n недопустимыми детьми (`aria-required-children`), поэтому строки\n состояний живут ниже, вне списка. `mousedown.prevent` держит\n фокус на `<input>` — контракт combobox с `aria-activedescendant`.\n -->\n <button\n v-if=\"showAddOption\"\n :id=\"addOptionDomId\"\n type=\"button\"\n role=\"option\"\n aria-selected=\"false\"\n tabindex=\"-1\"\n v-bind=\"optionSetProps(0)\"\n data-testid=\"gr-autocomplete-add-option\"\n data-gr-autocomplete-add-option\n :class=\"autocompleteOptionClass({ disabled: false, active: activeItem?.kind === 'add' })\"\n @mousedown.prevent\n @click=\"commitCustom\"\n @mousemove=\"activeIndex = 0\"\n >\n {{ t('gr.autocomplete.addOption', 'Add \"{value}\"', { value: query.trim() }) }}\n </button>\n\n <button\n v-for=\"{ option, index: optionIndex } in renderedOptions\"\n :id=\"optionDomId(optionIndex)\"\n :key=\"option.value\"\n :ref=\"(el) => virtual && virtualizer.measure(optionIndex + addOffset, el as Element | null)\"\n data-gr-autocomplete-option\n type=\"button\"\n role=\"option\"\n tabindex=\"-1\"\n v-bind=\"optionSetProps(optionIndex + addOffset)\"\n :disabled=\"option.disabled\"\n :aria-selected=\"isSelected(option.value) ? 'true' : 'false'\"\n :aria-disabled=\"option.disabled ? 'true' : undefined\"\n :class=\"autocompleteOptionClass({\n disabled: !!option.disabled,\n active: activeValue === option.value,\n })\"\n @mousedown.prevent\n @click=\"chooseOption(option)\"\n @mousemove=\"activeIndex = navigableIndexOf(option.value)\"\n >\n <slot name=\"option\" :option=\"option\" :selected=\"isSelected(option.value)\">\n <span class=\"flex items-center gap-2 min-w-0\">\n <span class=\"inline-block h-4 w-4 shrink-0\" aria-hidden=\"true\">\n <IconCheck v-if=\"isSelected(option.value)\" class=\"block h-4 w-4 text-[var(--gr-primary-text)]\" />\n </span>\n <span class=\"truncate\">{{ option.label }}</span>\n </span>\n </slot>\n </button>\n </div>\n\n <!--\n Загрузка, «введите ещё N» и «ничего не найдено» меняются молча:\n `aria-label` на generic-элементе AT игнорируют. Один живой регион\n на все три — и вне listbox, чтобы не ломать его состав.\n -->\n <div\n v-if=\"isLoading || belowMinQuery || showEmpty\"\n data-gr-autocomplete-status\n role=\"status\"\n aria-live=\"polite\"\n :class=\"autocompleteStateClass\"\n >\n <template v-if=\"isLoading\">\n <span data-gr-autocomplete-loading class=\"flex items-center gap-2\">\n <slot name=\"loading\">\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n <span>{{ resolvedLoadingText }}</span>\n </slot>\n </span>\n </template>\n <template v-else-if=\"belowMinQuery\">\n <span data-gr-autocomplete-hint>{{ resolvedTypeMoreText }}</span>\n </template>\n <template v-else>\n <span data-gr-autocomplete-empty>\n <slot name=\"empty\">\n {{ resolvedNoResultsText }}\n </slot>\n </span>\n </template>\n </div>\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n\n<style scoped>\n/*\n * Распорки виртуального списка.\n *\n * Не `padding` контейнера: `max-height` меряет ту же коробку, и распорка в\n * десятки тысяч пикселей раздула бы панель. Не обёртка внутри listbox'а:\n * прямыми потомками роли обязаны быть только опции (`aria-required-children`,\n * гейт — `GrAutocomplete.a11y.test.ts`). Не отступы крайних опций: при прыжке\n * прокрутки опции заменяются целиком, распорка исчезла бы вместе с ними, и\n * браузер обрезал бы `scrollTop`.\n *\n * Псевдоэлементы не узлы DOM: их не за что размонтировать, детьми listbox'а\n * они не считаются, а высота приезжает переменными в том же патче, что и опции.\n */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n</style>\n","<script setup lang=\"ts\" generic=\"TValue extends GrAutocompleteValue = string\">\nimport { computed, nextTick, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { useGrComponentProp, useGrComponentSize, useGrThemeAttrs } from '../GrConfigProvider/context'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating } from '../../composables/useFloating'\nimport { useDismissible } from '../../composables/useDismissible'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useRemoteOptions } from './composables/useRemoteOptions'\nimport { useAutocompleteValues } from './composables/useAutocompleteValues'\nimport { useAutocompletePanel } from './composables/useAutocompletePanel'\nimport { useAutocompleteVirtual } from './composables/useAutocompleteVirtual'\nimport { useAutocompleteNavigation } from './composables/useAutocompleteNavigation'\nimport { isComposingEvent } from '../../internal/keyboard'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\n\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge/grBadgeStyles'\nimport GrChip from '../GrChip/GrChip.vue'\nimport { chipSizeForBadgeScale } from '../GrChip/grChipStyles'\nimport { panelPopTransition } from '../shared/overlayTransition'\n\nimport {\n autocompleteOptionClass,\n autocompletePanelClasses,\n autocompleteShellClass,\n autocompleteStateClass,\n type GrAutocompleteModelValue,\n type GrAutocompleteOption,\n type GrAutocompleteValue,\n type GrAutocompleteSize,\n} from './grAutocompleteStyles'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronDown from '~icons/lucide/chevron-down'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconX from '~icons/lucide/x'\n\nexport type {\n GrAutocompleteModelValue,\n GrAutocompleteOption,\n GrAutocompleteSize,\n GrAutocompleteValue,\n} from './grAutocompleteStyles'\n\n/**\n * Публичный GR-примитив «Autocomplete / Combobox» (WAI-ARIA editable combobox).\n *\n * В отличие от `GrSelect` (select-only combobox с кнопкой-триггером), здесь\n * combobox-ом является сам текстовый `<input>`: набранный текст — это поисковый\n * запрос, а выбор опции заполняет поле. Поддерживает локальную фильтрацию,\n * удалённую (async) загрузку через событие `search` + внешний проп `loading`,\n * произвольные значения (`allowCustomValue`) и multiple с удаляемыми chips.\n */\nexport interface GrAutocompleteProps<TValue extends GrAutocompleteValue = string> {\n /** Выбранное значение (single — строка, multiple — массив строк). */\n modelValue: GrAutocompleteModelValue<TValue>\n /**\n * Доступные опции. Для локального режима — полный список (фильтруется на клиенте).\n * Для remote-режима (`filterable=false`) — список, который родитель обновляет\n * в ответ на событие `search`.\n */\n options?: GrAutocompleteOption<TValue>[]\n multiple?: boolean\n /**\n * Вид чипов выбранных значений в режиме `multiple`. Рисует их `GrChip`, но\n * шкала пропа осталась бейджевой: `tagSize` публичен, и его значения обязаны\n * означать тот же кегль, что и раньше. Перевод ступеней — в\n * `chipSizeForBadgeScale`.\n */\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n disabled?: boolean\n /** Только для чтения: значение видно и уходит в форму, но не редактируется. */\n readonly?: boolean\n /** Визуальное и ARIA-состояние ошибки. */\n invalid?: boolean\n /** Обязательное поле (`aria-required`). */\n required?: boolean\n size?: GrAutocompleteSize\n placeholder?: string\n ariaLabel?: string\n /** Кнопка очистки выбранного значения/запроса. */\n clearable?: boolean\n /** Внешне управляемое состояние загрузки (для async-сценариев). */\n loading?: boolean\n /**\n * Локальная фильтрация опций по введённому запросу. Отключите (`false`) для\n * чисто удалённого поиска — тогда `options` показываются как есть, а фильтрацию\n * выполняет сервер по событию `search`.\n */\n filterable?: boolean\n /** Кастомный матчер локальной фильтрации. По умолчанию — подстрока в `label`/`value`. */\n filter?: (option: GrAutocompleteOption<TValue>, query: string) => boolean\n /**\n * Удалённая загрузка опций под управлением компонента: дебаунс, отмена\n * устаревшего запроса и `loading` берёт на себя он. Ответ на отменённый\n * запрос игнорируется — при быстром вводе в списке всегда результат\n * последнего запроса, а не того, который вернулся позже.\n *\n * `signal` пробрасывается в `fetch`. Локальная фильтрация в этом режиме\n * выключена: список фильтрует сервер. Альтернатива — событие `search`, если\n * запрос ведёт само приложение.\n */\n fetchOptions?: (query: string, signal: AbortSignal) => Promise<GrAutocompleteOption<TValue>[]>\n /** Минимальная длина запроса до эмита `search` (для дебаунса remote-загрузки). */\n minQueryLength?: number\n /** Задержка дебаунса события `search`, мс. */\n debounce?: number\n /** Разрешить ввод/коммит значения, которого нет в `options`. */\n allowCustomValue?: boolean\n /** Закрывать панель после выбора (single всегда закрывает). */\n closeOnSelect?: boolean\n /** Максимальная высота панели, px. */\n dropdownMaxHeight?: number\n /**\n * Виртуализация панели: в DOM живёт только окно вокруг вьюпорта.\n *\n * Высоту окна задаёт `dropdownMaxHeight`. Включается осознанно: на сотне\n * опций выигрыша нет, а в разметке остаётся только окно — вместе с ним\n * меняется и то, что находит `querySelector` потребителя. Профильный\n * сценарий — удалённый поиск по справочнику на тысячи позиций.\n */\n virtual?: boolean\n /** i18n-тексты состояний панели / aria. */\n loadingText?: string\n noResultsText?: string\n clearLabel?: string\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n /** Имя для нативной формы: hidden input по значению модели (не по тексту запроса). */\n name?: string\n /**\n * Ширины аддонов `prefix`/`suffix` — общий контракт контролов пакета\n * (`docs/form-controls.md`).\n */\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n prefixFixed?: boolean\n suffixFixed?: boolean\n}\n\nexport interface GrAutocompleteEmits<TValue extends GrAutocompleteValue = string> {\n (e: 'update:modelValue', value: GrAutocompleteModelValue<TValue>): void\n /** Дебаунснутый поисковый запрос — точка входа для удалённой загрузки опций. */\n (e: 'search', query: string): void\n /** Запрос `fetchOptions` завершился ошибкой (отмена устаревшего сюда не приходит). */\n (e: 'searchError', error: unknown): void\n /** Значение зафиксировано выбором или снятием опции. */\n (e: 'change', value: GrAutocompleteModelValue<TValue>): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n /** Значение снято кнопкой очистки; только при `clearable`. */\n (e: 'clear'): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrAutocompleteProps<TValue>>(),\n {\n options: undefined,\n multiple: false,\n tagTone: 'neutral',\n tagDark: false,\n // `sm`, а не `md` как у `GrInputTag`: чип живёт внутри контрола, а не в тексте.\n tagSize: 'sm',\n tagRadius: 'round',\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n size: undefined,\n placeholder: undefined,\n ariaLabel: undefined,\n clearable: undefined,\n loading: false,\n filterable: true,\n filter: undefined,\n fetchOptions: undefined,\n minQueryLength: 0,\n debounce: 250,\n allowCustomValue: false,\n closeOnSelect: true,\n dropdownMaxHeight: 280,\n virtual: false,\n loadingText: undefined,\n noResultsText: undefined,\n clearLabel: undefined,\n open: undefined,\n name: undefined,\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n prefixFixed: false,\n suffixFixed: false,\n },\n)\n\n/** Ширина аддона по умолчанию — та же лестница, что у `GrInput`. */\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrAutocompleteSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrAutocomplete' })\nconst resolvedClearable = useGrComponentProp('GrAutocomplete', 'clearable', () => props.clearable, false)\n\n/**\n * Аддоны живут флекс-соседями поля, а не поверх него: оболочка автокомплита —\n * флекс-строка с чипами, поэтому резервировать место паддингом не нужно.\n * Контракт ширин остаётся общим (`useControlAddons`).\n */\nconst { hasPrefix, hasSuffix, prefixEl, suffixEl, prefixStyle, suffixStyle } = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => '0px',\n})\n\nconst emit = defineEmits<GrAutocompleteEmits<TValue>>()\ndefineSlots<{\n /** Аддон слева от поля ввода. */\n prefix?: () => any\n /** Аддон справа, перед спиннером и крестиком. */\n suffix?: () => any\n /** Строка списка вместо подписи опции. */\n option?: (props: { option: GrAutocompleteOption<TValue>, selected: boolean }) => any\n /** Содержимое панели, пока едут опции. */\n loading?: () => any\n /** Содержимое панели, когда подходящих опций нет. */\n empty?: () => any\n}>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedLoadingText = computed(() => props.loadingText ?? t('gr.autocomplete.loading', 'Loading…'))\nconst resolvedNoResultsText = computed(() => props.noResultsText ?? t('gr.autocomplete.noResults', 'No results'))\nconst resolvedClearLabel = computed(() => props.clearLabel ?? t('gr.common.clear', 'Clear'))\n// Число уходит под двумя общепринятыми именами: `n` читают `@feugene/fint-i18n`\n// и `vue-i18n`, `count` — `i18next`. Формы для каждого языка лежат в словаре,\n// выбирает их переводчик; встроенный fallback — одна английская строка.\nconst resolvedTypeMoreText = computed(() =>\n t('gr.autocomplete.typeMore', 'Type at least {n} characters', {\n n: props.minQueryLength,\n count: props.minQueryLength,\n }),\n)\n\n// Fallback из контекста `GrFormField` (id/aria-describedby/invalid/required).\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\nconst describedBy = computed(() => field?.describedById.value)\n\n// Read-only запирает контрол так же, как disabled: значение видно, но панель не\n// открывается, опции не выбираются и чипы не удаляются. Без этого `readonly`\n// оставался бы ARIA-атрибутом без поведения.\nconst locked = computed(() => isDisabled.value || isReadonly.value)\n\nconst { remoteOptions, remoteAnswered, remoteLoading, scheduleSearch } = useRemoteOptions<TValue>({\n fetchOptions: () => props.fetchOptions,\n options: () => props.options,\n debounce: () => props.debounce,\n minQueryLength: () => props.minQueryLength,\n onSearch: value => emit('search', value),\n onSearchError: error => emit('searchError', error),\n})\n\nconst {\n optionsResolved,\n modelSingle,\n selectedValues,\n hasSelection,\n selectedOptions,\n singleSelectedLabel,\n} = useAutocompleteValues<TValue>({\n modelValue: () => props.modelValue,\n options: () => props.options,\n multiple: () => props.multiple,\n fetchOptions: () => props.fetchOptions,\n remoteOptions,\n remoteAnswered,\n})\n\nconst isLoading = computed(() => props.loading || remoteLoading.value)\n\n// ————— Состояние.\nconst query = ref('')\n// `dirty` — пользователь начал вводить запрос. Нужно, чтобы в single-режиме при\n// открытии заполненного поля показать весь список (а не отфильтровать по метке\n// уже выбранной опции). Сбрасывается при программной установке `query`.\nconst dirty = ref(false)\n// Имя `open` сохранено: читатели работают с computed-Ref.\nconst { open, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst listboxEl = ref<HTMLElement | null>(null)\n\n// Панель телепортирована в `body`, то есть лежит вне корня, но для пользователя\n// она часть контрола: без неё уход фокуса в панель читался бы как `blur`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n containers: () => [panelEl.value],\n})\nconst inputEl = ref<HTMLInputElement | null>(null)\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\nfunction blur(): void {\n inputEl.value?.blur()\n}\n\ndefineExpose({\n focus,\n blur,\n open: () => openDropdown(),\n close: () => closeDropdown(),\n})\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst { floatingStyle } = useFloating(rootEl, panelEl, open, {\n placement: 'bottom-start',\n matchWidth: true,\n zIndexVar: '--gr-z-dropdown',\n})\n\nuseDismissible(open, closeDropdown)\n\nconst { belowMinQuery, effectiveOptions, canAddCustom, showEmpty } = useAutocompletePanel<TValue>({\n optionsResolved,\n query,\n dirty,\n filterable: () => props.filterable,\n filter: () => props.filter,\n fetchOptions: () => props.fetchOptions,\n multiple: () => props.multiple,\n minQueryLength: () => props.minQueryLength,\n allowCustomValue: () => props.allowCustomValue,\n selectedValues,\n modelSingle,\n isLoading,\n})\n\n// ————— Панель: id/aria-activedescendant.\nconst listboxId = useId()\n\n/**\n * Id опции строится от позиции, а не от значения: значение с пробелом дало бы\n * невалидный `id`, а `aria-activedescendant` — два токена вместо одной ссылки,\n * и активная опция перестала бы объявляться.\n */\nfunction optionDomId(index: number): string {\n return `${listboxId}-opt-${index}`\n}\nconst addOptionDomId = computed(() => `${listboxId}-add`)\n\nconst {\n addOffset,\n virtualizer,\n showAddOption,\n renderedOptions,\n optionSetProps,\n listboxStyle,\n} = useAutocompleteVirtual<TValue>({\n listboxEl,\n effectiveOptions,\n canAddCustom,\n virtual: () => props.virtual,\n dropdownMaxHeight: () => props.dropdownMaxHeight,\n})\n\nconst {\n isSelected,\n navigableIndexOf,\n activeIndex,\n activeItem,\n activeDescendantId,\n activeValue,\n initActiveIndex,\n resetActive,\n handleNavigationKeys,\n} = useAutocompleteNavigation<TValue>({\n effectiveOptions,\n canAddCustom,\n selectedValues,\n open,\n virtual: () => props.virtual,\n addOffset,\n scrollToIndex: index => virtualizer.scrollToIndex(index),\n optionDomId,\n addOptionDomId,\n})\n\n// ————— Открытие/закрытие.\nfunction openDropdown(): void {\n if (locked.value || open.value)\n return\n setOpen(true)\n}\n\nfunction closeDropdown(): void {\n setOpen(false)\n}\n\nfunction focusInput(): void {\n inputEl.value?.focus()\n}\n\n// ————— Ввод.\nfunction onInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value\n query.value = value\n dirty.value = true\n openDropdown()\n scheduleSearch(value)\n}\n\nfunction onFocus(): void {\n if (locked.value)\n return\n openDropdown()\n}\n\nfunction setQuery(value: string): void {\n query.value = value\n dirty.value = false\n}\n\n// ————— Выбор значений.\nfunction selectSingle(value: TValue, label: string): void {\n emit('update:modelValue', value)\n emit('change', value as GrAutocompleteModelValue<TValue>)\n setQuery(label)\n closeDropdown()\n}\n\nfunction toggleMultiple(value: TValue): void {\n const next = selectedValues.value.slice()\n const idx = next.indexOf(value)\n if (idx >= 0)\n next.splice(idx, 1)\n else next.push(value)\n emit('update:modelValue', next)\n emit('change', next as GrAutocompleteModelValue<TValue>)\n setQuery('')\n if (props.closeOnSelect)\n closeDropdown()\n else void nextTick(focusInput)\n}\n\nfunction chooseOption(option: GrAutocompleteOption<TValue>): void {\n if (locked.value || option.disabled)\n return\n if (props.multiple)\n toggleMultiple(option.value)\n else selectSingle(option.value, option.label)\n}\n\nfunction commitCustom(): void {\n if (locked.value)\n return\n // Кастомное значение строковое по природе — см. `canAddCustom`.\n const v = query.value.trim() as TValue\n if (!v)\n return\n if (props.multiple)\n toggleMultiple(v)\n else selectSingle(v, String(v))\n}\n\nfunction removeValue(value: TValue, focusAfter: () => void = focusInput): void {\n if (locked.value)\n return\n const next = selectedValues.value.filter(v => v !== value)\n emit('update:modelValue', next)\n emit('change', next as GrAutocompleteModelValue<TValue>)\n void nextTick(focusAfter)\n}\n\nfunction clearSelection(): void {\n if (locked.value)\n return\n const next = (props.multiple ? [] : '') as GrAutocompleteModelValue<TValue>\n emit('update:modelValue', next)\n emit('change', next)\n emit('clear')\n setQuery('')\n void nextTick(focusInput)\n}\n\nconst showClear = computed(() =>\n resolvedClearable.value && !locked.value && (hasSelection.value || query.value.length > 0),\n)\n\n// ————— Чипы (multiple): стрелки вместо таб-стопов.\n//\n// Крестики намеренно не табируемы: у combobox фокус живёт на `<input>`, и\n// двадцать выбранных значений не должны давать двадцать остановок Tab. Поэтому\n// вход в чипы — ArrowLeft из пустого запроса, а выход — ArrowRight/Esc/печать.\n//\n// Отсюда же единственное отличие от `GrInputTag`: `tabindexFor` здесь не\n// используется. Кольцо нужно как движок навигации, а таб-стоп у ряда чипов\n// отсутствует вовсе — он принадлежит полю ввода.\nconst chipRefs = ref<Array<{ removeEl: HTMLButtonElement | null } | null>>([])\n\nfunction setChipRef(index: number) {\n return (el: unknown): void => {\n chipRefs.value[index] = el as { removeEl: HTMLButtonElement | null } | null\n }\n}\n\n/**\n * Проп `tagSize` объявлен по шкале бейджа и остаётся публичным контрактом:\n * дефолт `sm` обязан означать для потребителя тот же кегль, что и раньше.\n */\nconst chipSize = computed(() => chipSizeForBadgeScale(props.tagSize))\n\n// Адресация индексом, а не значением: значения дженерик-типа, и `TValue`\n// сравнивался бы по ссылке там, где опции пересоздаются.\nconst chipIndexes = computed(() => selectedOptions.value.map((_, index) => index))\n\nconst chipRoving = useRovingFocus<number>({\n items: () => chipIndexes.value,\n elementFor: index => chipRefs.value[index]?.removeEl,\n orientation: () => 'horizontal',\n // Ряд чипов — не кольцо: за правым краем стоит поле ввода, за левым ничего.\n wrap: () => false,\n onOverflow: (edge) => {\n if (edge === 'end')\n focusInput()\n return true\n },\n // Удаление чипа перерисовывает ряд: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\n\nfunction focusChip(index: number): void {\n const last = selectedOptions.value.length - 1\n if (last < 0) {\n focusInput()\n return\n }\n\n void chipRoving.focusKey(Math.min(Math.max(index, 0), last))\n}\n\nfunction onChipKeydown(event: KeyboardEvent, index: number, value: TValue): void {\n if (chipRoving.handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'Delete':\n case 'Backspace':\n event.preventDefault()\n removeValue(value, () => focusChip(index))\n break\n case 'Escape':\n event.preventDefault()\n focusInput()\n break\n default:\n // Печатный символ возвращает в поле: фокус переезжает синхронно, до\n // вставки текста, поэтому символ попадает в запрос, а не пропадает.\n if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey)\n focusInput()\n }\n}\n\n// ————— Клавиатура.\nfunction onKeydown(event: KeyboardEvent): void {\n // Клавиша во время IME-композиции принадлежит композиции: Enter коммитит её,\n // Esc отменяет, стрелки ходят по кандидатам.\n if (isComposingEvent(event))\n return\n if (locked.value)\n return\n\n // Курсор в начале пустого запроса — стрелка влево уходит к чипам, а не\n // двигает каретку, которой всё равно некуда двигаться.\n if (event.key === 'ArrowLeft' && props.multiple && query.value === '' && selectedValues.value.length) {\n event.preventDefault()\n closeDropdown()\n focusChip(selectedValues.value.length - 1)\n return\n }\n\n if (!open.value && ['ArrowDown', 'ArrowUp'].includes(event.key)) {\n event.preventDefault()\n openDropdown()\n return\n }\n\n // Только при открытой панели: в закрытом инпуте Home/End двигают каретку.\n if (open.value && handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'Enter': {\n if (!open.value)\n break\n event.preventDefault()\n const item = activeItem.value\n if (item?.kind === 'option')\n chooseOption(item.option)\n else if (item?.kind === 'add' || canAddCustom.value)\n commitCustom()\n break\n }\n case 'Backspace':\n // multiple: пустой запрос + Backspace удаляет последний chip.\n if (props.multiple && query.value === '' && selectedValues.value.length) {\n event.preventDefault()\n removeValue(selectedValues.value[selectedValues.value.length - 1])\n }\n break\n case 'Tab':\n closeDropdown()\n break\n }\n}\n\n// ————— Синхронизация query с выбранным значением (single).\nwatch(\n [singleSelectedLabel, () => props.multiple],\n ([label, multiple]) => {\n if (multiple)\n return\n // Не перетираем то, что пользователь сейчас набирает.\n if (open.value || dirty.value)\n return\n setQuery(label)\n },\n { immediate: true },\n)\n\nwatch(open, (isOpen) => {\n if (isOpen) {\n initActiveIndex()\n return\n }\n // Закрытие: сбрасываем активную опцию и «черновик».\n resetActive()\n if (props.multiple) {\n setQuery('')\n }\n else {\n // single: возвращаем метку выбранной опции (revert ввода без выбора).\n setQuery(singleSelectedLabel.value)\n }\n})\n\nconst ariaAutocomplete = computed(() => (props.allowCustomValue ? 'both' : 'list'))\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget()\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: closeDropdown, enabled: open, exclude: clickOutsideExclude }\"\n data-gr-autocomplete\n class=\"relative w-full\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <div\n data-gr-autocomplete-shell\n :class=\"autocompleteShellClass({ size: resolvedSize, disabled: isDisabled, invalid: isInvalid })\"\n @mousedown.self.prevent=\"focusInput\"\n >\n <span\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-autocomplete-prefix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"prefixStyle\"\n >\n <slot name=\"prefix\" />\n </span>\n\n <!-- Chips выбранных значений (multiple). -->\n <template v-if=\"multiple\">\n <GrChip\n v-for=\"(option, chipIndex) in selectedOptions\"\n :key=\"option.value\"\n :ref=\"setChipRef(chipIndex)\"\n data-gr-autocomplete-chip\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"chipSize\"\n :radius=\"tagRadius\"\n :closable=\"!locked\"\n :remove-label=\"t('gr.autocomplete.removeValue', 'Remove {label}', { label: option.label })\"\n :remove-tabindex=\"-1\"\n @remove=\"removeValue(option.value)\"\n @keydown=\"onChipKeydown($event, chipIndex, option.value)\"\n >\n <span class=\"truncate\">{{ option.label }}</span>\n </GrChip>\n </template>\n\n <input\n :id=\"resolvedId\"\n ref=\"inputEl\"\n data-gr-autocomplete-input\n data-testid=\"gr-autocomplete-input\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n role=\"combobox\"\n :value=\"query\"\n :disabled=\"isDisabled\"\n :placeholder=\"hasSelection && multiple ? undefined : placeholder\"\n :aria-label=\"ariaLabel\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :readonly=\"isReadonly\"\n aria-haspopup=\"listbox\"\n :aria-autocomplete=\"ariaAutocomplete\"\n :aria-controls=\"open ? listboxId : undefined\"\n :aria-activedescendant=\"activeDescendantId\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n class=\"min-w-0 flex-1 bg-transparent text-inherit placeholder:text-[var(--gr-muted-fg)] focus:outline-none disabled:cursor-not-allowed\"\n @input=\"onInput\"\n @focus=\"onFocus\"\n @keydown=\"onKeydown\"\n >\n\n <span\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-autocomplete-suffix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"suffixStyle\"\n >\n <slot name=\"suffix\" />\n </span>\n\n <!-- Trailing: спиннер / очистка / шеврон. -->\n <span\n v-if=\"isLoading\"\n data-gr-autocomplete-spinner\n class=\"shrink-0 flex items-center text-[var(--gr-muted-fg)]\"\n >\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n </span>\n\n <button\n v-else-if=\"showClear\"\n type=\"button\"\n data-testid=\"gr-autocomplete-clear\"\n data-gr-autocomplete-clear\n class=\"shrink-0 inline-flex h-5 w-5 items-center justify-center rounded-[var(--gr-radius-control)] text-[var(--gr-muted-fg)] hover:text-[var(--gr-fg)]\"\n :aria-label=\"resolvedClearLabel\"\n @click=\"clearSelection\"\n >\n <IconX class=\"block h-4 w-4\" aria-hidden=\"true\" />\n </button>\n\n <span\n v-else\n data-testid=\"gr-autocomplete-chevron\"\n class=\"shrink-0 flex items-center text-[var(--gr-muted-fg)] pointer-events-none\"\n >\n <IconChevronDown class=\"block h-4 w-4\" aria-hidden=\"true\" />\n </span>\n </div>\n\n <!-- Нативная форма: сериализуется модель, а не текст запроса. -->\n <template v-if=\"name\">\n <input\n v-for=\"value in selectedValues\"\n :key=\"`hidden-${String(value)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(value)\"\n >\n </template>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-testid=\"gr-autocomplete-panel\"\n v-bind=\"themeAttrs\"\n data-gr-autocomplete-panel\n data-gr-overlay-root\n :style=\"floatingStyle\"\n >\n <div :class=\"autocompletePanelClasses\">\n <!--\n Пустой listbox не рендерим: его `p-1` давал полосу пустоты над\n строкой состояния, и «ничего не найдено» выглядело прижатым к низу.\n -->\n <div\n v-if=\"showAddOption || renderedOptions.length\"\n :id=\"listboxId\"\n ref=\"listboxEl\"\n data-gr-autocomplete-listbox\n :data-gr-virtual=\"virtual ? '' : undefined\"\n class=\"p-1 overflow-auto\"\n :class=\"virtual ? 'flex flex-col' : ''\"\n :style=\"listboxStyle\"\n role=\"listbox\"\n :aria-multiselectable=\"multiple ? 'true' : undefined\"\n >\n <!--\n Прямые потомки listbox — только опции: роль объявляет остальных\n недопустимыми детьми (`aria-required-children`), поэтому строки\n состояний живут ниже, вне списка. `mousedown.prevent` держит\n фокус на `<input>` — контракт combobox с `aria-activedescendant`.\n -->\n <button\n v-if=\"showAddOption\"\n :id=\"addOptionDomId\"\n type=\"button\"\n role=\"option\"\n aria-selected=\"false\"\n tabindex=\"-1\"\n v-bind=\"optionSetProps(0)\"\n data-testid=\"gr-autocomplete-add-option\"\n data-gr-autocomplete-add-option\n :class=\"autocompleteOptionClass({ disabled: false, active: activeItem?.kind === 'add' })\"\n @mousedown.prevent\n @click=\"commitCustom\"\n @mousemove=\"activeIndex = 0\"\n >\n {{ t('gr.autocomplete.addOption', 'Add \"{value}\"', { value: query.trim() }) }}\n </button>\n\n <button\n v-for=\"{ option, index: optionIndex } in renderedOptions\"\n :id=\"optionDomId(optionIndex)\"\n :key=\"option.value\"\n :ref=\"(el) => virtual && virtualizer.measure(optionIndex + addOffset, el as Element | null)\"\n data-gr-autocomplete-option\n type=\"button\"\n role=\"option\"\n tabindex=\"-1\"\n v-bind=\"optionSetProps(optionIndex + addOffset)\"\n :disabled=\"option.disabled\"\n :aria-selected=\"isSelected(option.value) ? 'true' : 'false'\"\n :aria-disabled=\"option.disabled ? 'true' : undefined\"\n :class=\"autocompleteOptionClass({\n disabled: !!option.disabled,\n active: activeValue === option.value,\n })\"\n @mousedown.prevent\n @click=\"chooseOption(option)\"\n @mousemove=\"activeIndex = navigableIndexOf(option.value)\"\n >\n <slot name=\"option\" :option=\"option\" :selected=\"isSelected(option.value)\">\n <span class=\"flex items-center gap-2 min-w-0\">\n <span class=\"inline-block h-4 w-4 shrink-0\" aria-hidden=\"true\">\n <IconCheck v-if=\"isSelected(option.value)\" class=\"block h-4 w-4 text-[var(--gr-primary-text)]\" />\n </span>\n <span class=\"truncate\">{{ option.label }}</span>\n </span>\n </slot>\n </button>\n </div>\n\n <!--\n Загрузка, «введите ещё N» и «ничего не найдено» меняются молча:\n `aria-label` на generic-элементе AT игнорируют. Один живой регион\n на все три — и вне listbox, чтобы не ломать его состав.\n -->\n <div\n v-if=\"isLoading || belowMinQuery || showEmpty\"\n data-gr-autocomplete-status\n role=\"status\"\n aria-live=\"polite\"\n :class=\"autocompleteStateClass\"\n >\n <template v-if=\"isLoading\">\n <span data-gr-autocomplete-loading class=\"flex items-center gap-2\">\n <slot name=\"loading\">\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n <span>{{ resolvedLoadingText }}</span>\n </slot>\n </span>\n </template>\n <template v-else-if=\"belowMinQuery\">\n <span data-gr-autocomplete-hint>{{ resolvedTypeMoreText }}</span>\n </template>\n <template v-else>\n <span data-gr-autocomplete-empty>\n <slot name=\"empty\">\n {{ resolvedNoResultsText }}\n </slot>\n </span>\n </template>\n </div>\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n\n<style scoped>\n/*\n * Распорки виртуального списка.\n *\n * Не `padding` контейнера: `max-height` меряет ту же коробку, и распорка в\n * десятки тысяч пикселей раздула бы панель. Не обёртка внутри listbox'а:\n * прямыми потомками роли обязаны быть только опции (`aria-required-children`,\n * гейт — `GrAutocomplete.a11y.test.ts`). Не отступы крайних опций: при прыжке\n * прокрутки опции заменяются целиком, распорка исчезла бы вместе с ними, и\n * браузер обрезал бы `scrollTop`.\n *\n * Псевдоэлементы не узлы DOM: их не за что размонтировать, детьми listbox'а\n * они не считаются, а высота приезжает переменными в том же патче, что и опции.\n */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n</style>\n"],"mappings":"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"}