@feugene/granularity 0.48.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 (418) 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-2vrOFn2f.js → config-AKpLyIGD.js} +2 -2
  7. package/dist/chunks/{config-2vrOFn2f.js.map → config-AKpLyIGD.js.map} +1 -1
  8. package/dist/chunks/{config-DIDz_E5m.js → config-B34mkd53.js} +66 -1
  9. package/dist/chunks/config-B34mkd53.js.map +1 -0
  10. package/dist/chunks/{config-B5SBUa6u.js → config-B7qZqiUB.js} +28 -1
  11. package/dist/chunks/config-B7qZqiUB.js.map +1 -0
  12. package/dist/chunks/config-BBrPUEye.js +8 -0
  13. package/dist/chunks/config-BBrPUEye.js.map +1 -0
  14. package/dist/chunks/config-BBtBQE3s.js +108 -0
  15. package/dist/chunks/config-BBtBQE3s.js.map +1 -0
  16. package/dist/chunks/{config-CT4lP6S4.js → config-BOCzHqWh.js} +2 -2
  17. package/dist/chunks/{config-CT4lP6S4.js.map → config-BOCzHqWh.js.map} +1 -1
  18. package/dist/chunks/{config-iemgzS4x.js → config-BP1ktzwh.js} +2 -24
  19. package/dist/chunks/config-BP1ktzwh.js.map +1 -0
  20. package/dist/chunks/config-BTxmdRzT.js +28 -0
  21. package/dist/chunks/config-BTxmdRzT.js.map +1 -0
  22. package/dist/chunks/{config-CjWOTgLL.js → config-Bk52xd5l.js} +12 -5
  23. package/dist/chunks/config-Bk52xd5l.js.map +1 -0
  24. package/dist/chunks/{config-D3HOuHDe.js → config-C3SqBqSQ.js} +3 -1
  25. package/dist/chunks/config-C3SqBqSQ.js.map +1 -0
  26. package/dist/chunks/{config-2ZHRsdOc.js → config-C3uqd-sW.js} +1 -1
  27. package/dist/chunks/config-C3uqd-sW.js.map +1 -0
  28. package/dist/chunks/{config-BXRmsn3t.js → config-CPhcZzHi.js} +72 -10
  29. package/dist/chunks/config-CPhcZzHi.js.map +1 -0
  30. package/dist/chunks/config-CWtfxkM9.js.map +1 -1
  31. package/dist/chunks/{config--t2dxj0t.js → config-CmLTCmY9.js} +2 -2
  32. package/dist/chunks/{config--t2dxj0t.js.map → config-CmLTCmY9.js.map} +1 -1
  33. package/dist/chunks/{config-BAse0laT.js → config-CvtqB4ki.js} +8 -3
  34. package/dist/chunks/config-CvtqB4ki.js.map +1 -0
  35. package/dist/chunks/{config-BcXX7S7B.js → config-D-JgqV0J.js} +5 -1
  36. package/dist/chunks/{config-BcXX7S7B.js.map → config-D-JgqV0J.js.map} +1 -1
  37. package/dist/chunks/{config-BHLMTJaR.js → config-D1oVht-E.js} +8 -3
  38. package/dist/chunks/config-D1oVht-E.js.map +1 -0
  39. package/dist/chunks/{config-BscVxZR3.js → config-DF1ezU6y.js} +1 -1
  40. package/dist/chunks/{config-BscVxZR3.js.map → config-DF1ezU6y.js.map} +1 -1
  41. package/dist/chunks/{config-B42iJ48O.js → config-DG41PD9i.js} +13 -1
  42. package/dist/chunks/config-DG41PD9i.js.map +1 -0
  43. package/dist/chunks/{config-Bs1HwUcx.js → config-DPJ3jtiB.js} +12 -2
  44. package/dist/chunks/config-DPJ3jtiB.js.map +1 -0
  45. package/dist/chunks/{config-tNqtapcT.js → config-DpqjlCfB.js} +2 -2
  46. package/dist/chunks/{config-tNqtapcT.js.map → config-DpqjlCfB.js.map} +1 -1
  47. package/dist/chunks/{config-DNDgp9bB.js → config-DpzFoSIh.js} +64 -2
  48. package/dist/chunks/config-DpzFoSIh.js.map +1 -0
  49. package/dist/chunks/config-MUkhktTP.js +267 -0
  50. package/dist/chunks/config-MUkhktTP.js.map +1 -0
  51. package/dist/chunks/config-SPugeaHT.js +37 -0
  52. package/dist/chunks/config-SPugeaHT.js.map +1 -0
  53. package/dist/chunks/{en-Bxyn5lW7.js → en-mIFywnV2.js} +27 -7
  54. package/dist/chunks/en-mIFywnV2.js.map +1 -0
  55. package/dist/chunks/{es-Dtl-a7ui.js → es-CvthYwtB.js} +27 -7
  56. package/dist/chunks/es-CvthYwtB.js.map +1 -0
  57. package/dist/chunks/{es-Bj_vc18Z.js → es-DlGd6Mrj.js} +3 -3
  58. package/dist/chunks/{es-Bj_vc18Z.js.map → es-DlGd6Mrj.js.map} +1 -1
  59. package/dist/chunks/{generated-hELWB0gZ.js → generated-Cx4C7GRN.js} +126 -0
  60. package/dist/chunks/{generated-hELWB0gZ.js.map → generated-Cx4C7GRN.js.map} +1 -1
  61. package/dist/chunks/{grBadgeStyles-DV0DrAew.js → grBadgeStyles-D51AXbj5.js} +57 -1
  62. package/dist/chunks/grBadgeStyles-D51AXbj5.js.map +1 -0
  63. package/dist/chunks/{grChipStyles-DcDyxAL0.js → grChipStyles-CA9Wj1_E.js} +1 -1
  64. package/dist/chunks/{grChipStyles-DcDyxAL0.js.map → grChipStyles-CA9Wj1_E.js.map} +1 -1
  65. package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js → grPopoverStyles-CncEkiPu.js} +1 -1
  66. package/dist/chunks/{grPopoverStyles-CYAeO3Ov.js.map → grPopoverStyles-CncEkiPu.js.map} +1 -1
  67. package/dist/chunks/{grSelectStyles-D9EQ-pgK.js → grSelectStyles-Cam-IG9s.js} +3 -2
  68. package/dist/chunks/grSelectStyles-Cam-IG9s.js.map +1 -0
  69. package/dist/chunks/{grSliderStyles-kaz6VXZ3.js → grSliderStyles-CqzV0hll.js} +1 -1
  70. package/dist/chunks/grSliderStyles-CqzV0hll.js.map +1 -0
  71. package/dist/chunks/{config-CbEbLyDE.js → grSortableListStyles-CxieDmpe.js} +1 -27
  72. package/dist/chunks/grSortableListStyles-CxieDmpe.js.map +1 -0
  73. package/dist/chunks/grTableStyles-CPSxDTOW.js +66 -0
  74. package/dist/chunks/grTableStyles-CPSxDTOW.js.map +1 -0
  75. package/dist/chunks/{config-CMNfZO7S.js → grTabsStyles-DIz2VdIm.js} +1 -36
  76. package/dist/chunks/grTabsStyles-DIz2VdIm.js.map +1 -0
  77. package/dist/chunks/grTooltipStyles-CtbGEEGV.js +24 -0
  78. package/dist/chunks/grTooltipStyles-CtbGEEGV.js.map +1 -0
  79. package/dist/chunks/{granular-provider-BOQp7N5o.js → granular-provider-cv5vaM1a.js} +26 -22
  80. package/dist/chunks/granular-provider-cv5vaM1a.js.map +1 -0
  81. package/dist/chunks/hotkeySequence-BTHIM_5A.js +46 -0
  82. package/dist/chunks/hotkeySequence-BTHIM_5A.js.map +1 -0
  83. package/dist/chunks/{keyboard-DE2yhz_b.js → keyboard-BiFSgWLt.js} +70 -1
  84. package/dist/chunks/keyboard-BiFSgWLt.js.map +1 -0
  85. package/dist/chunks/optionPanel-DvY7Tv_4.js +182 -0
  86. package/dist/chunks/optionPanel-DvY7Tv_4.js.map +1 -0
  87. package/dist/chunks/overlayListPanel-D91jBCHU.js +21 -0
  88. package/dist/chunks/overlayListPanel-D91jBCHU.js.map +1 -0
  89. package/dist/chunks/{overlayStack-DH4Z7am1.js → overlayStack-DCkCgXZP.js} +1 -1
  90. package/dist/chunks/{overlayStack-DH4Z7am1.js.map → overlayStack-DCkCgXZP.js.map} +1 -1
  91. package/dist/chunks/{overlayPanelSurface-BKeMhRx4.js → overlayTransition-C0FDMx7Q.js} +24 -24
  92. package/dist/chunks/overlayTransition-C0FDMx7Q.js.map +1 -0
  93. package/dist/chunks/{ru-hrB4I1u_.js → ru-CQKDR-kD.js} +27 -7
  94. package/dist/chunks/ru-CQKDR-kD.js.map +1 -0
  95. package/dist/chunks/{safelist-x8USecK8.js → safelist-CSfynUC1.js} +5 -1
  96. package/dist/chunks/safelist-CSfynUC1.js.map +1 -0
  97. package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js → useMenuItemsFocus-C031blYS.js} +1 -1
  98. package/dist/chunks/{useMenuItemsFocus-B7Bl_aFA.js.map → useMenuItemsFocus-C031blYS.js.map} +1 -1
  99. package/dist/chunks/{useModalOverlay-ACRkflzx.js → useModalOverlay-CKCQkGdB.js} +1 -1
  100. package/dist/chunks/{useModalOverlay-ACRkflzx.js.map → useModalOverlay-CKCQkGdB.js.map} +1 -1
  101. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-C-uovdv8.js → GrAutocomplete-Cyr1-ENw.js} +183 -125
  102. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-Cyr1-ENw.js.map +1 -0
  103. package/dist/components/GrAutocomplete/index.js +2 -2
  104. package/dist/components/GrAutocomplete/styles.css +1 -1
  105. package/dist/components/GrBadge/chunks/GrBadge-C42KLyUD.js +71 -0
  106. package/dist/components/GrBadge/chunks/GrBadge-C42KLyUD.js.map +1 -0
  107. package/dist/components/GrBadge/index.js +3 -3
  108. package/dist/components/GrBadge/styles.css +1 -1
  109. package/dist/components/GrCarousel/chunks/{GrCarousel-ByuughtI.js → GrCarousel-CBj-PEPB.js} +186 -37
  110. package/dist/components/GrCarousel/chunks/GrCarousel-CBj-PEPB.js.map +1 -0
  111. package/dist/components/GrCarousel/index.js +2 -2
  112. package/dist/components/GrCarousel/styles.css +1 -1
  113. package/dist/components/GrCheckbox/chunks/{GrCheckbox-Dp201frb.js → GrCheckbox-B4NJc7Ur.js} +2 -1
  114. package/dist/components/GrCheckbox/chunks/GrCheckbox-B4NJc7Ur.js.map +1 -0
  115. package/dist/components/GrCheckbox/index.js +1 -1
  116. package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js → GrCheckboxGroup-qZHpNFCX.js} +1 -1
  117. package/dist/components/GrCheckboxGroup/chunks/{GrCheckboxGroup-IpqG5qwm.js.map → GrCheckboxGroup-qZHpNFCX.js.map} +1 -1
  118. package/dist/components/GrCheckboxGroup/index.js +1 -1
  119. package/dist/components/GrChip/chunks/{GrChip-CKqyzYcv.js → GrChip-DoyS1Dr4.js} +1 -1
  120. package/dist/components/GrChip/chunks/{GrChip-CKqyzYcv.js.map → GrChip-DoyS1Dr4.js.map} +1 -1
  121. package/dist/components/GrChip/index.js +2 -2
  122. package/dist/components/GrColorPicker/chunks/{GrColorPicker-BRM_4lyI.js → GrColorPicker-vGSgpUV9.js} +353 -38
  123. package/dist/components/GrColorPicker/chunks/GrColorPicker-vGSgpUV9.js.map +1 -0
  124. package/dist/components/GrColorPicker/index.js +2 -2
  125. package/dist/components/GrColorPicker/styles.css +1 -1
  126. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BJHmkDQv.js → GrCommandPalette-CAHgj0Aa.js} +23 -7
  127. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-CAHgj0Aa.js.map +1 -0
  128. package/dist/components/GrCommandPalette/index.js +1 -1
  129. package/dist/components/GrCommandPalette/styles.css +1 -1
  130. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js → GrConfirmDialog-dg021BMd.js} +1 -1
  131. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-BzUQwbec.js.map → GrConfirmDialog-dg021BMd.js.map} +1 -1
  132. package/dist/components/GrConfirmDialog/index.js +1 -1
  133. package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js → GrContextMenu-bQ1Vvy2c.js} +3 -3
  134. package/dist/components/GrContextMenu/chunks/{GrContextMenu-RpxMHQXH.js.map → GrContextMenu-bQ1Vvy2c.js.map} +1 -1
  135. package/dist/components/GrContextMenu/index.js +1 -1
  136. package/dist/components/GrDataTable/chunks/{GrDataTable-DQxYYgQk.js → GrDataTable-Bb2jWnRG.js} +576 -136
  137. package/dist/components/GrDataTable/chunks/GrDataTable-Bb2jWnRG.js.map +1 -0
  138. package/dist/components/GrDataTable/index.js +2 -2
  139. package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js → GrDelta-BSv1KdMy.js} +0 -0
  140. package/dist/components/GrDelta/chunks/{GrDelta-CgTvfoIN.js.map → GrDelta-BSv1KdMy.js.map} +1 -1
  141. package/dist/components/GrDelta/index.js +2 -2
  142. package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js → GrDialog-C9Zu72jB.js} +1 -1
  143. package/dist/components/GrDialog/chunks/{GrDialog-DDz_OEhk.js.map → GrDialog-C9Zu72jB.js.map} +1 -1
  144. package/dist/components/GrDialog/index.js +1 -1
  145. package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js → GrDialogService-DLBifO61.js} +2 -2
  146. package/dist/components/GrDialogService/chunks/{GrDialogService-Dtq0ZCN5.js.map → GrDialogService-DLBifO61.js.map} +1 -1
  147. package/dist/components/GrDialogService/index.js +1 -1
  148. package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js → GrDrawer-DOcRTE8G.js} +1 -1
  149. package/dist/components/GrDrawer/chunks/{GrDrawer-CNpSMuN-.js.map → GrDrawer-DOcRTE8G.js.map} +1 -1
  150. package/dist/components/GrDrawer/index.js +1 -1
  151. package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js → GrDropdown-kxwmgfSe.js} +2 -2
  152. package/dist/components/GrDropdown/chunks/{GrDropdown-cLZuZMEY.js.map → GrDropdown-kxwmgfSe.js.map} +1 -1
  153. package/dist/components/GrDropdown/index.js +2 -2
  154. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-Dxkz_ry4.js → GrDropdownMenu--VoK3VY0.js} +3 -34
  155. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu--VoK3VY0.js.map +1 -0
  156. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js +34 -0
  157. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-CkM3BFPL.js.map +1 -0
  158. package/dist/components/GrDropdownMenu/index.js +2 -1
  159. package/dist/components/GrEmptyState/chunks/{GrEmptyState-BbvwE-E0.js → GrEmptyState-Bz6-_ED4.js} +42 -6
  160. package/dist/components/GrEmptyState/chunks/GrEmptyState-Bz6-_ED4.js.map +1 -0
  161. package/dist/components/GrEmptyState/index.js +1 -1
  162. package/dist/components/GrFileUpload/chunks/{GrFileUpload-BwMR71zN.js → GrFileUpload-Bgdfnkd8.js} +5 -2
  163. package/dist/components/GrFileUpload/chunks/GrFileUpload-Bgdfnkd8.js.map +1 -0
  164. package/dist/components/GrFileUpload/index.js +1 -1
  165. package/dist/components/GrFormFile/chunks/{GrFormFile-Dlxx-9zi.js → GrFormFile-Ctq1isz-.js} +78 -11
  166. package/dist/components/GrFormFile/chunks/GrFormFile-Ctq1isz-.js.map +1 -0
  167. package/dist/components/GrFormFile/index.js +2 -2
  168. package/dist/components/GrFormFile/styles.css +1 -1
  169. package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js → GrImageViewer-Bnql_dNP.js} +1 -1
  170. package/dist/components/GrImageViewer/chunks/{GrImageViewer-DK-iVHHC.js.map → GrImageViewer-Bnql_dNP.js.map} +1 -1
  171. package/dist/components/GrImageViewer/index.js +1 -1
  172. package/dist/components/GrInput/chunks/{GrInput-DV4gMWPR.js → GrInput-CoaFLpaU.js} +43 -22
  173. package/dist/components/GrInput/chunks/GrInput-CoaFLpaU.js.map +1 -0
  174. package/dist/components/GrInput/index.js +1 -1
  175. package/dist/components/GrInputTag/chunks/{GrInputTag-CO0YU-ok.js → GrInputTag-BzzNRBe3.js} +247 -20
  176. package/dist/components/GrInputTag/chunks/GrInputTag-BzzNRBe3.js.map +1 -0
  177. package/dist/components/GrInputTag/index.js +2 -2
  178. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js → GrJsonViewer-B6ZJ3GFH.js} +2 -2
  179. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-D7CyWzhT.js.map → GrJsonViewer-B6ZJ3GFH.js.map} +1 -1
  180. package/dist/components/GrJsonViewer/index.js +1 -1
  181. package/dist/components/GrKbd/chunks/{GrKbd-BNMeoaLV.js → GrKbd-D2rHDkQv.js} +42 -37
  182. package/dist/components/GrKbd/chunks/GrKbd-D2rHDkQv.js.map +1 -0
  183. package/dist/components/GrKbd/index.js +1 -1
  184. package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js → GrModal-SHb1U2qx.js} +1 -1
  185. package/dist/components/GrModal/chunks/{GrModal-Cm0mtSXk.js.map → GrModal-SHb1U2qx.js.map} +1 -1
  186. package/dist/components/GrModal/index.js +1 -1
  187. package/dist/components/GrNavbar/chunks/{GrNavbar-BRGuksiy.js → GrNavbar-IEIHC5Vt.js} +10 -4
  188. package/dist/components/GrNavbar/chunks/GrNavbar-IEIHC5Vt.js.map +1 -0
  189. package/dist/components/GrNavbar/index.js +2 -2
  190. package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js → GrNumberInput-CmnUDaKi.js} +2 -22
  191. package/dist/components/GrNumberInput/chunks/{GrNumberInput-BI6-vkcs.js.map → GrNumberInput-CmnUDaKi.js.map} +1 -1
  192. package/dist/components/GrNumberInput/index.js +1 -1
  193. package/dist/components/GrOtpInput/chunks/GrOtpInput-B_Q-RDLw.js +419 -0
  194. package/dist/components/GrOtpInput/chunks/GrOtpInput-B_Q-RDLw.js.map +1 -0
  195. package/dist/components/GrOtpInput/index.js +3 -0
  196. package/dist/components/GrOtpInput/styles.css +1 -0
  197. package/dist/components/GrPagination/chunks/{GrPagination-BbaF5eXk.js → GrPagination-AMbn5D8I.js} +1 -1
  198. package/dist/components/GrPagination/chunks/{GrPagination-BbaF5eXk.js.map → GrPagination-AMbn5D8I.js.map} +1 -1
  199. package/dist/components/GrPagination/index.js +1 -1
  200. package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js → GrPopover-DjVxt8bf.js} +3 -3
  201. package/dist/components/GrPopover/chunks/{GrPopover-CcWvr1ZA.js.map → GrPopover-DjVxt8bf.js.map} +1 -1
  202. package/dist/components/GrPopover/index.js +2 -2
  203. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js → GrPromptDialog-BhbIZP1f.js} +3 -3
  204. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BEL-QgwE.js.map → GrPromptDialog-BhbIZP1f.js.map} +1 -1
  205. package/dist/components/GrPromptDialog/index.js +1 -1
  206. package/dist/components/GrSelect/chunks/{GrSelect-0iI4wdR_.js → GrSelect-B-ykrHpL.js} +26 -182
  207. package/dist/components/GrSelect/chunks/GrSelect-B-ykrHpL.js.map +1 -0
  208. package/dist/components/GrSelect/index.js +2 -2
  209. package/dist/components/GrSelect/styles.css +1 -1
  210. package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js +543 -0
  211. package/dist/components/GrSidebar/chunks/GrSidebar-jVvoLGDO.js.map +1 -0
  212. package/dist/components/GrSidebar/index.js +2 -2
  213. package/dist/components/GrSlider/chunks/{GrSlider-CO8N9SF6.js → GrSlider-DF2Cq0rV.js} +29 -4
  214. package/dist/components/GrSlider/chunks/GrSlider-DF2Cq0rV.js.map +1 -0
  215. package/dist/components/GrSlider/index.js +2 -2
  216. package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js → GrSortableList-ChH9nQBv.js} +1 -1
  217. package/dist/components/GrSortableList/chunks/{GrSortableList-NKriuGm_.js.map → GrSortableList-ChH9nQBv.js.map} +1 -1
  218. package/dist/components/GrSortableList/index.js +2 -2
  219. package/dist/components/GrSwitch/chunks/{GrSwitch-CriHWT2A.js → GrSwitch-D7X42uIA.js} +61 -7
  220. package/dist/components/GrSwitch/chunks/GrSwitch-D7X42uIA.js.map +1 -0
  221. package/dist/components/GrSwitch/index.js +2 -2
  222. package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js +30 -0
  223. package/dist/components/GrTabPanels/chunks/GrTabPanels-BDt5oVdd.js.map +1 -0
  224. package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js +83 -0
  225. package/dist/components/GrTabPanels/chunks/GrTabPanels-BJvAflnA.js.map +1 -0
  226. package/dist/components/GrTabPanels/index.js +2 -1
  227. package/dist/components/GrTable/chunks/{GrTable-CKJ-HrsN.js → GrTable-BQitSDep.js} +52 -16
  228. package/dist/components/GrTable/chunks/GrTable-BQitSDep.js.map +1 -0
  229. package/dist/components/GrTable/index.js +2 -2
  230. package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js → GrTabs-DVC6nfWB.js} +1 -1
  231. package/dist/components/GrTabs/chunks/{GrTabs-s9RzC1WX.js.map → GrTabs-DVC6nfWB.js.map} +1 -1
  232. package/dist/components/GrTabs/index.js +2 -2
  233. package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js +98 -0
  234. package/dist/components/GrTabsWithPanels/chunks/GrTabsWithPanels-BYtuzouj.js.map +1 -0
  235. package/dist/components/GrTabsWithPanels/index.js +3 -0
  236. package/dist/components/GrTextarea/chunks/{GrTextarea-Bfgc0DD2.js → GrTextarea-BFwyqcHB.js} +22 -5
  237. package/dist/components/GrTextarea/chunks/GrTextarea-BFwyqcHB.js.map +1 -0
  238. package/dist/components/GrTextarea/index.js +1 -1
  239. package/dist/components/GrToaster/chunks/{GrToaster-CZixNk0l.js → GrToaster-OzT1VKcp.js} +163 -32
  240. package/dist/components/GrToaster/chunks/GrToaster-OzT1VKcp.js.map +1 -0
  241. package/dist/components/GrToaster/index.js +2 -2
  242. package/dist/components/GrToaster/styles.css +1 -1
  243. package/dist/components/GrTooltip/chunks/{GrTooltip-DkMMM0uq.js → GrTooltip-BDcFycvW.js} +26 -13
  244. package/dist/components/GrTooltip/chunks/GrTooltip-BDcFycvW.js.map +1 -0
  245. package/dist/components/GrTooltip/index.js +2 -2
  246. package/dist/components/GrTransfer/chunks/{GrTransfer-DdfBUf35.js → GrTransfer-CV7BL5UK.js} +114 -12
  247. package/dist/components/GrTransfer/chunks/GrTransfer-CV7BL5UK.js.map +1 -0
  248. package/dist/components/GrTransfer/index.js +1 -1
  249. package/dist/components/GrTransfer/styles.css +1 -1
  250. package/dist/components/GrTree/chunks/{GrTree-6yZrncJE.js → GrTree-DpgaP8hk.js} +39 -1
  251. package/dist/components/GrTree/chunks/GrTree-DpgaP8hk.js.map +1 -0
  252. package/dist/components/GrTree/index.js +1 -1
  253. package/dist/components/GrTree/styles.css +1 -1
  254. package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js → GrTreeSections-BeOj__44.js} +1 -1
  255. package/dist/components/GrTreeSections/chunks/{GrTreeSections-DcmDcLwj.js.map → GrTreeSections-BeOj__44.js.map} +1 -1
  256. package/dist/components/GrTreeSections/index.js +1 -1
  257. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-B6KoDYiZ.js → GrTreeSelect-BHq-T8wH.js} +113 -14
  258. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHq-T8wH.js.map +1 -0
  259. package/dist/components/GrTreeSelect/index.js +2 -2
  260. package/dist/composables/useFloating.js +1 -1
  261. package/dist/composables/useHotkeys.js +89 -0
  262. package/dist/composables/useHotkeys.js.map +1 -0
  263. package/dist/composables/useOverlayLayer.js +1 -1
  264. package/dist/directives/hotkey.js +19 -46
  265. package/dist/directives/hotkey.js.map +1 -1
  266. package/dist/granular-provider-node.js +1 -1
  267. package/dist/granular-provider.js +1 -1
  268. package/dist/i18n/all.js +1 -1
  269. package/dist/i18n/index.js +1 -1
  270. package/dist/index.js +80 -71
  271. package/dist/theme.js +1 -1
  272. package/dist/tokens.js +1 -1
  273. package/dist/types/components/GrAutocomplete/GrAutocomplete.vue.d.ts +4 -4
  274. package/dist/types/components/GrAutocomplete/composables/useAutocompleteNavigation.d.ts +12 -3
  275. package/dist/types/components/GrAutocomplete/composables/useAutocompletePanel.d.ts +12 -2
  276. package/dist/types/components/GrAutocomplete/composables/useAutocompleteValues.d.ts +7 -4
  277. package/dist/types/components/GrAutocomplete/composables/useRemoteOptions.d.ts +4 -4
  278. package/dist/types/components/GrAutocomplete/grAutocompleteStyles.d.ts +15 -1
  279. package/dist/types/components/GrAutocomplete/index.d.ts +1 -1
  280. package/dist/types/components/GrBadge/GrBadge.vue.d.ts +15 -1
  281. package/dist/types/components/GrBadge/grBadgeStyles.d.ts +57 -0
  282. package/dist/types/components/GrBadge/index.d.ts +1 -1
  283. package/dist/types/components/GrCarousel/GrCarousel.vue.d.ts +29 -1
  284. package/dist/types/components/GrCarousel/composables/useCarouselSwipe.d.ts +5 -0
  285. package/dist/types/components/GrCarousel/grCarouselContext.d.ts +21 -0
  286. package/dist/types/components/GrCarousel/grCarouselStyles.d.ts +39 -9
  287. package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +13 -0
  288. package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +18 -2
  289. package/dist/types/components/GrColorPicker/color.d.ts +13 -1
  290. package/dist/types/components/GrColorPicker/colorArea.d.ts +59 -0
  291. package/dist/types/components/GrColorPicker/defaults.d.ts +3 -1
  292. package/dist/types/components/GrColorPicker/eyeDropper.d.ts +21 -0
  293. package/dist/types/components/GrColorPicker/grColorPickerStyles.d.ts +42 -0
  294. package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +10 -1
  295. package/dist/types/components/GrDataTable/GrDataTable.vue.d.ts +41 -1
  296. package/dist/types/components/GrDataTable/composables/useDataTableGridNavigation.d.ts +53 -0
  297. package/dist/types/components/GrDataTable/grDataTableStyles.d.ts +8 -0
  298. package/dist/types/components/GrDataTable/index.d.ts +1 -1
  299. package/dist/types/components/GrDelta/grDeltaStyles.d.ts +10 -3
  300. package/dist/types/components/GrEmptyState/GrEmptyState.vue.d.ts +11 -2
  301. package/dist/types/components/GrEmptyState/grEmptyStateStyles.d.ts +10 -0
  302. package/dist/types/components/GrEmptyState/index.d.ts +1 -1
  303. package/dist/types/components/GrFileUpload/GrFileUpload.vue.d.ts +2 -1
  304. package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +10 -0
  305. package/dist/types/components/GrInput/GrInput.vue.d.ts +15 -0
  306. package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +16 -0
  307. package/dist/types/components/GrInputTag/grInputTagStyles.d.ts +11 -0
  308. package/dist/types/components/GrKbd/GrKbd.vue.d.ts +14 -0
  309. package/dist/types/components/GrNavbar/GrNavbar.vue.d.ts +18 -0
  310. package/dist/types/components/GrNavbar/grNavbarStyles.d.ts +10 -1
  311. package/dist/types/components/GrNavbar/index.d.ts +1 -0
  312. package/dist/types/components/GrOtpInput/GrOtpInput.vue.d.ts +164 -0
  313. package/dist/types/components/GrOtpInput/config.d.ts +1 -0
  314. package/dist/types/components/GrOtpInput/defaults.d.ts +15 -0
  315. package/dist/types/components/GrOtpInput/grOtpInputStyles.d.ts +62 -0
  316. package/dist/types/components/GrOtpInput/index.d.ts +9 -0
  317. package/dist/types/components/GrOtpInput/otpValue.d.ts +71 -0
  318. package/dist/types/components/GrOtpInput/safelist.d.ts +7 -0
  319. package/dist/types/components/GrSelect/composables/useSelectPanelItems.d.ts +8 -34
  320. package/dist/types/components/GrSelect/composables/useSelectVirtualization.d.ts +7 -0
  321. package/dist/types/components/GrSelect/grSelectStyles.d.ts +1 -1
  322. package/dist/types/components/GrSidebar/GrSidebar.vue.d.ts +20 -0
  323. package/dist/types/components/GrSidebar/GrSidebarItem.vue.d.ts +39 -5
  324. package/dist/types/components/GrSidebar/grSidebarStyles.d.ts +32 -0
  325. package/dist/types/components/GrSidebar/index.d.ts +1 -1
  326. package/dist/types/components/GrSidebar/sidebarContext.d.ts +23 -1
  327. package/dist/types/components/GrSlider/GrSlider.vue.d.ts +39 -1
  328. package/dist/types/components/GrSlider/grSliderStyles.d.ts +1 -1
  329. package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +42 -4
  330. package/dist/types/components/GrSwitch/defaults.d.ts +2 -0
  331. package/dist/types/components/GrSwitch/grSwitchStyles.d.ts +129 -25
  332. package/dist/types/components/GrSwitch/index.d.ts +1 -1
  333. package/dist/types/components/GrSwitch/safelist.d.ts +4 -3
  334. package/dist/types/components/GrTabPanels/context.d.ts +6 -0
  335. package/dist/types/components/GrTable/GrTable.vue.d.ts +37 -0
  336. package/dist/types/components/GrTable/grTableStyles.d.ts +16 -7
  337. package/dist/types/components/GrTabsWithPanels/GrTabsWithPanels.vue.d.ts +77 -0
  338. package/dist/types/components/GrTabsWithPanels/config.d.ts +1 -0
  339. package/dist/types/components/GrTabsWithPanels/index.d.ts +4 -0
  340. package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +19 -1
  341. package/dist/types/components/GrToaster/GrToaster.vue.d.ts +12 -0
  342. package/dist/types/components/GrToaster/grToasterStyles.d.ts +26 -0
  343. package/dist/types/components/GrTooltip/GrTooltip.vue.d.ts +22 -0
  344. package/dist/types/components/GrTransfer/GrTransfer.vue.d.ts +23 -0
  345. package/dist/types/components/GrTreeSelect/grTreeSelectStyles.d.ts +1 -1
  346. package/dist/types/components/GrTreeSelect/grTreeSelectTypes.d.ts +20 -0
  347. package/dist/types/components/shared/hotkey.d.ts +8 -9
  348. package/dist/types/components/shared/optionPanel.d.ts +100 -0
  349. package/dist/types/components/shared/overlayListPanel.d.ts +18 -0
  350. package/dist/types/composables/useHotkeys.d.ts +43 -0
  351. package/dist/types/granular-provider/shared.d.ts +2 -0
  352. package/dist/types/i18n/messages/en.d.ts +32 -0
  353. package/dist/types/i18n/messages/es.d.ts +32 -0
  354. package/dist/types/i18n/messages/ru.d.ts +32 -0
  355. package/dist/types/index.d.ts +4 -0
  356. package/dist/types/internal/hotkeySequence.d.ts +22 -0
  357. package/dist/types/internal/keyboard.d.ts +45 -0
  358. package/dist/web-types.json +784 -101
  359. package/package.json +13 -1
  360. package/dist/chunks/config-2ZHRsdOc.js.map +0 -1
  361. package/dist/chunks/config-B42iJ48O.js.map +0 -1
  362. package/dist/chunks/config-B5SBUa6u.js.map +0 -1
  363. package/dist/chunks/config-BAse0laT.js.map +0 -1
  364. package/dist/chunks/config-BHLMTJaR.js.map +0 -1
  365. package/dist/chunks/config-BXRmsn3t.js.map +0 -1
  366. package/dist/chunks/config-Bs1HwUcx.js.map +0 -1
  367. package/dist/chunks/config-CMNfZO7S.js.map +0 -1
  368. package/dist/chunks/config-CbEbLyDE.js.map +0 -1
  369. package/dist/chunks/config-CjWOTgLL.js.map +0 -1
  370. package/dist/chunks/config-D3HOuHDe.js.map +0 -1
  371. package/dist/chunks/config-DIDz_E5m.js.map +0 -1
  372. package/dist/chunks/config-DNDgp9bB.js.map +0 -1
  373. package/dist/chunks/config-Yy67uWHY.js +0 -140
  374. package/dist/chunks/config-Yy67uWHY.js.map +0 -1
  375. package/dist/chunks/config-iemgzS4x.js.map +0 -1
  376. package/dist/chunks/en-Bxyn5lW7.js.map +0 -1
  377. package/dist/chunks/es-Dtl-a7ui.js.map +0 -1
  378. package/dist/chunks/grBadgeStyles-DV0DrAew.js.map +0 -1
  379. package/dist/chunks/grSelectStyles-D9EQ-pgK.js.map +0 -1
  380. package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +0 -1
  381. package/dist/chunks/grTableStyles-DkQPMfx9.js +0 -39
  382. package/dist/chunks/grTableStyles-DkQPMfx9.js.map +0 -1
  383. package/dist/chunks/granular-provider-BOQp7N5o.js.map +0 -1
  384. package/dist/chunks/keyboard-DE2yhz_b.js.map +0 -1
  385. package/dist/chunks/overlayPanelSurface-BKeMhRx4.js.map +0 -1
  386. package/dist/chunks/ru-hrB4I1u_.js.map +0 -1
  387. package/dist/chunks/safelist-x8USecK8.js.map +0 -1
  388. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-C-uovdv8.js.map +0 -1
  389. package/dist/components/GrBadge/chunks/GrBadge-DBeQXEir.js +0 -47
  390. package/dist/components/GrBadge/chunks/GrBadge-DBeQXEir.js.map +0 -1
  391. package/dist/components/GrCarousel/chunks/GrCarousel-ByuughtI.js.map +0 -1
  392. package/dist/components/GrCheckbox/chunks/GrCheckbox-Dp201frb.js.map +0 -1
  393. package/dist/components/GrColorPicker/chunks/GrColorPicker-BRM_4lyI.js.map +0 -1
  394. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BJHmkDQv.js.map +0 -1
  395. package/dist/components/GrDataTable/chunks/GrDataTable-DQxYYgQk.js.map +0 -1
  396. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-Dxkz_ry4.js.map +0 -1
  397. package/dist/components/GrEmptyState/chunks/GrEmptyState-BbvwE-E0.js.map +0 -1
  398. package/dist/components/GrFileUpload/chunks/GrFileUpload-BwMR71zN.js.map +0 -1
  399. package/dist/components/GrFormFile/chunks/GrFormFile-Dlxx-9zi.js.map +0 -1
  400. package/dist/components/GrInput/chunks/GrInput-DV4gMWPR.js.map +0 -1
  401. package/dist/components/GrInputTag/chunks/GrInputTag-CO0YU-ok.js.map +0 -1
  402. package/dist/components/GrKbd/chunks/GrKbd-BNMeoaLV.js.map +0 -1
  403. package/dist/components/GrNavbar/chunks/GrNavbar-BRGuksiy.js.map +0 -1
  404. package/dist/components/GrSelect/chunks/GrSelect-0iI4wdR_.js.map +0 -1
  405. package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js +0 -264
  406. package/dist/components/GrSidebar/chunks/GrSidebar-DoKLlHSw.js.map +0 -1
  407. package/dist/components/GrSlider/chunks/GrSlider-CO8N9SF6.js.map +0 -1
  408. package/dist/components/GrSwitch/chunks/GrSwitch-CriHWT2A.js.map +0 -1
  409. package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js +0 -92
  410. package/dist/components/GrTabPanels/chunks/GrTabPanels-5zsbqS1v.js.map +0 -1
  411. package/dist/components/GrTable/chunks/GrTable-CKJ-HrsN.js.map +0 -1
  412. package/dist/components/GrTextarea/chunks/GrTextarea-Bfgc0DD2.js.map +0 -1
  413. package/dist/components/GrToaster/chunks/GrToaster-CZixNk0l.js.map +0 -1
  414. package/dist/components/GrTooltip/chunks/GrTooltip-DkMMM0uq.js.map +0 -1
  415. package/dist/components/GrTransfer/chunks/GrTransfer-DdfBUf35.js.map +0 -1
  416. package/dist/components/GrTree/chunks/GrTree-6yZrncJE.js.map +0 -1
  417. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-B6KoDYiZ.js.map +0 -1
  418. package/dist/types/components/GrAutocomplete/composables/useAutocompleteVirtual.d.ts +0 -33
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrTree-6yZrncJE.js","names":[],"sources":["../../../../src/components/GrTree/grTreeInteractionContext.ts","../../../../src/components/GrTree/grTreeStyles.ts","../../../../src/components/GrTree/GrTree.vue","../../../../src/components/GrTree/GrTree.vue"],"sourcesContent":["import type { Ref, ShallowRef } from 'vue'\nimport { ref, shallowRef } from 'vue'\nimport type {\n GrTreeAllowDropType,\n GrTreeKey,\n GrTreeNode,\n GrTreeNodeDropType,\n} from './grTreeTypes'\n\nexport type GrTreeDropTarget = {\n key: GrTreeKey\n type: GrTreeNodeDropType\n allowed: boolean\n}\n\nexport type GrTreeInteractionOptions<T> = {\n draggable?: boolean\n allowDrop?: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, type: GrTreeAllowDropType) => boolean\n allowDrag?: (draggingNode: GrTreeNode<T>) => boolean\n}\n\nexport type GrTreeInteractionEmitters<T> = {\n emitNodeClick: (data: T, node: GrTreeNode<T>) => void\n emitNodeExpand: (data: T, node: GrTreeNode<T>) => void\n emitNodeCollapse: (data: T, node: GrTreeNode<T>) => void\n emitNodeDrop: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType) => void\n emitNodeContextMenu: (evt: MouseEvent, data: T, node: GrTreeNode<T>) => void\n}\n\nexport type GrTreeInteractionContext<T> = {\n hoveredKey: Ref<GrTreeKey | undefined>\n /** Клавиша узла, держащего roving-фокус (единственный tabindex=0 во всём дереве). */\n /**\n * Реестр DOM-узлов строк, общий на все уровни дерева. Нужен клавиатуре: без\n * него каждое нажатие стрелки обходило бы весь DOM поддерева в поисках\n * строки по `data`-атрибуту.\n */\n nodeEls: Map<GrTreeKey, HTMLElement>\n registerNodeEl: (key: GrTreeKey, el: HTMLElement | null) => void\n draggingNode: ShallowRef<GrTreeNode<T> | null>\n dropTarget: ShallowRef<GrTreeDropTarget | null>\n canDrag: (node: GrTreeNode<T>) => boolean\n canDrop: (drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType) => boolean\n resetDragState: () => void\n emitNodeClick: (data: T, node: GrTreeNode<T>) => void\n emitNodeExpand: (data: T, node: GrTreeNode<T>) => void\n emitNodeCollapse: (data: T, node: GrTreeNode<T>) => void\n emitNodeDrop: (draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType) => void\n emitNodeContextMenu: (evt: MouseEvent, data: T, node: GrTreeNode<T>) => void\n}\n\nexport function createGrTreeInteractionContext<T>(\n options: GrTreeInteractionOptions<T>,\n emitters: GrTreeInteractionEmitters<T>,\n): GrTreeInteractionContext<T> {\n const hoveredKey = ref<GrTreeKey | undefined>(undefined)\n const draggingNode = shallowRef<GrTreeNode<T> | null>(null)\n const dropTarget = shallowRef<GrTreeDropTarget | null>(null)\n const nodeEls = new Map<GrTreeKey, HTMLElement>()\n\n function registerNodeEl(key: GrTreeKey, el: HTMLElement | null) {\n if (el) {\n nodeEls.set(key, el)\n return\n }\n\n // Перенос узла в другую ветку размонтирует старый элемент уже после того,\n // как зарегистрировался новый: снимаем запись, только если она протухла.\n const previous = nodeEls.get(key)\n if (previous && !previous.isConnected)\n nodeEls.delete(key)\n }\n\n function canDrag(node: GrTreeNode<T>): boolean {\n if (!options.draggable)\n return false\n\n if (options.allowDrag)\n return options.allowDrag(node)\n\n return true\n }\n\n function canDrop(drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType): boolean {\n if (!options.allowDrop)\n return true\n\n return options.allowDrop(drag, target, type)\n }\n\n function resetDragState() {\n draggingNode.value = null\n dropTarget.value = null\n }\n\n return {\n hoveredKey,\n nodeEls,\n registerNodeEl,\n draggingNode,\n dropTarget,\n canDrag,\n canDrop,\n resetDragState,\n ...emitters,\n }\n}\n","import type { GrComponentSize } from '../shared/sizes'\n\nexport type GrTreeSize = GrComponentSize\n\n/**\n * Размер дерева выражен переменными, а не утилитарными классами: те же\n * `--gr-tree-*` уже объявлены точками кастомизации в `GrTree.vue`, и size\n * обязан задавать им дефолты, а не спорить с ними отдельным каналом.\n *\n * `font-size` на `md` намеренно `inherit`: дерево по умолчанию набирается\n * кеглем родителя, и подстановка конкретных пикселей сменила бы вид всем,\n * кто ничего не просил.\n */\nexport type GrTreeSizeVars = {\n '--gr-tree-row-min-height': string\n '--gr-tree-row-px': string\n '--gr-tree-row-py': string\n '--gr-tree-toggle-size': string\n '--gr-tree-drag-handle-size': string\n '--gr-tree-icon-size': string\n '--gr-tree-content-gap': string\n '--gr-tree-font-size': string\n}\n\nexport const treeSizeVars: Record<GrTreeSize, GrTreeSizeVars> = {\n xs: {\n '--gr-tree-row-min-height': '22px',\n '--gr-tree-row-px': '4px',\n '--gr-tree-row-py': '2px',\n '--gr-tree-toggle-size': '18px',\n '--gr-tree-drag-handle-size': '18px',\n '--gr-tree-icon-size': '12px',\n '--gr-tree-content-gap': '4px',\n '--gr-tree-font-size': '12px',\n },\n sm: {\n '--gr-tree-row-min-height': '24px',\n '--gr-tree-row-px': '6px',\n '--gr-tree-row-py': '3px',\n '--gr-tree-toggle-size': '20px',\n '--gr-tree-drag-handle-size': '20px',\n '--gr-tree-icon-size': '14px',\n '--gr-tree-content-gap': '6px',\n '--gr-tree-font-size': '13px',\n },\n md: {\n '--gr-tree-row-min-height': '28px',\n '--gr-tree-row-px': '8px',\n '--gr-tree-row-py': '4px',\n '--gr-tree-toggle-size': '24px',\n '--gr-tree-drag-handle-size': '24px',\n '--gr-tree-icon-size': '16px',\n '--gr-tree-content-gap': '8px',\n '--gr-tree-font-size': 'inherit',\n },\n lg: {\n '--gr-tree-row-min-height': '32px',\n '--gr-tree-row-px': '10px',\n '--gr-tree-row-py': '6px',\n '--gr-tree-toggle-size': '28px',\n '--gr-tree-drag-handle-size': '28px',\n '--gr-tree-icon-size': '20px',\n '--gr-tree-content-gap': '10px',\n '--gr-tree-font-size': '15px',\n },\n}\n\n/**\n * Готовые виды дерева — наборы значений тех же `--gr-tree-*`, что задаёт\n * `size`. Не проп: второй канал спорил бы с размером за одни переменные, а\n * набор с ним композируется — потребитель раскладывает его в `style` и при\n * необходимости переопределяет по одной строке.\n *\n * Шрифт и значки в набор не входят: семейства у дерева своего токена нет, а\n * значки — это `expandIcon`/`collapseIcon` и слот строки, то есть решение\n * потребителя, а не вида.\n */\nexport type GrTreeView = 'explorer' | 'rail' | 'outline' | 'picker'\n\nexport const grTreeViewVars: Record<GrTreeView, Record<string, string>> = {\n /**\n * Плотный проводник: максимум узлов на экран, колена связей вместо простых\n * вертикалей. Под мышь — 24px меньше минимальной цели касания.\n */\n explorer: {\n '--gr-tree-row-min-height': '24px',\n '--gr-tree-row-py': '2px',\n '--gr-tree-row-radius': '4px',\n '--gr-tree-children-pl': '6px',\n '--gr-tree-branch-line-offset': '8px',\n '--gr-tree-branch-elbow-width': '10px',\n '--gr-tree-content-gap': '6px',\n /* Волосяная нейтральная линия вместо акцентной по умолчанию: на шести\n уровнях акцент превращается в частокол и спорит со значками папок,\n которые в этом виде и несут акцент. */\n '--gr-tree-branch-line-width': '1px',\n '--gr-tree-branch-line-default-color': 'var(--gr-brd)',\n /* Кегль входит в набор, хотя семейство — нет: 24px строки при базовом\n кегле недостижимы, высоту держит текст, а не `min-height`. */\n '--gr-tree-font-size': '12.5px',\n '--gr-tree-toggle-size': '16px',\n '--gr-tree-icon-size': '14px',\n /* Ветвистость здесь читается значком папки и шевроном, поэтому вес подписи\n свободен: жирные ветки в плотном моноширинном списке дают полосатость. */\n '--gr-tree-branch-font-weight': '400',\n '--gr-tree-row-current-color': 'var(--gr-primary-text)',\n },\n /**\n * Навигация: выбранная строка — сплошная плашка, скруглённая только справа.\n * Плоский левый край — не украшение: плашка начинается от отступа уровня, и\n * скругление с той стороны читалось бы как отдельная кнопка, оторванная от\n * рельса. Текст перекрашивается своим токеном, иначе на насыщенной подложке\n * он остался бы нечитаемым.\n */\n rail: {\n '--gr-tree-row-min-height': '30px',\n /* Высоту держит `min-height`, а поля лишь не дают строке распереть её:\n при базовом кегле строчный бокс уже 24px, и пять пикселей сверху и снизу\n увели бы строку на 34 — рельс перестал бы быть рельсом. */\n '--gr-tree-row-py': '3px',\n '--gr-tree-row-radius': '0 999px 999px 0',\n '--gr-tree-row-current-bg': 'var(--gr-primary)',\n '--gr-tree-row-current-hover-bg': 'var(--gr-primary-hover, var(--gr-primary))',\n '--gr-tree-row-current-color': 'var(--gr-primary-fg)',\n /* Рельс — нейтральная шина уровня, а не подсветка: цвет по умолчанию\n выведен из подложки выбора и на ней же дублировался бы акцентом. */\n '--gr-tree-branch-line-default-color': 'var(--gr-brd)',\n },\n\n /**\n * Отбор: дерево, по которому не ходят, а которое размечают. Строка просторнее\n * остальных видов, потому что цель нажатия здесь — квадрат отметки, а не\n * подпись: 38px и увеличенный квадрат делают её достижимой и пальцем.\n *\n * Сам по себе вид отметок не включает — это ортогональная ось (`showCheckbox`),\n * и она же работает в любом другом виде. Набор задаёт только плотность под неё.\n */\n picker: {\n '--gr-tree-row-min-height': '38px',\n '--gr-tree-row-py': '7px',\n '--gr-tree-row-px': '6px',\n '--gr-tree-row-pr': '10px',\n '--gr-tree-row-radius': '9px',\n '--gr-tree-content-gap': '9px',\n '--gr-tree-indent-step': '22px',\n '--gr-tree-checkbox-size': '17px',\n '--gr-tree-checkbox-radius': '5px',\n '--gr-tree-checkbox-mr': '9px',\n /* Квадрат крупнее обычного, и волосяная граница на нём теряется: при 17px\n она перестаёт читаться как рамка и выглядит серым контуром заливки. */\n '--gr-tree-checkbox-brd-width': '1.5px',\n },\n\n /**\n * Оглавление: иерархию несёт набор, а не хром. Направляющие и подложки\n * гасятся, выбор отмечается полосой у края списка, цветом и весом — вид\n * рассчитан на то, чтобы стоять рядом с читаемым текстом и не спорить с ним.\n *\n * Ступени кегля по уровням задаются `rowClass`: это единственное, чего набор\n * значений сделать не может — уровень строки знает только разметка.\n */\n outline: {\n '--gr-tree-row-min-height': '26px',\n '--gr-tree-row-py': '3px',\n '--gr-tree-row-px': '6px',\n '--gr-tree-row-radius': '6px',\n '--gr-tree-row-hover-bg': 'transparent',\n '--gr-tree-row-current-bg': 'transparent',\n '--gr-tree-row-current-hover-bg': 'transparent',\n '--gr-tree-row-current-color': 'var(--gr-primary-text)',\n '--gr-tree-row-current-bar-width': '2px',\n '--gr-tree-children-pl': '4px',\n '--gr-tree-branch-line-offset': '6px',\n /* Вес здесь означает уровень, а не ветвистость: без этого лист первого\n уровня выглядел бы младше ветки третьего. */\n '--gr-tree-branch-font-weight': 'inherit',\n },\n}\n","<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'\nimport type {\n GrTreeAllowDropType,\n GrTreeInstance,\n GrTreeKey,\n GrTreeNode,\n GrTreeNodeDropType,\n} from './grTreeTypes'\nimport { createGrTreeDataAdapter } from '../../composables/internal/treeAdapter'\nimport type { GrTreeDropTarget } from './grTreeInteractionContext'\nimport { createGrTreeInteractionContext } from './grTreeInteractionContext'\nimport type { GrTreeCheckState } from '../../composables/internal/treeChecking'\nimport { useTree } from '../../composables/useTree'\nimport { treeSizeVars } from './grTreeStyles'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useDragSort } from '../../composables/useDragSort'\nimport { useTypeahead } from '../../composables/internal/useTypeahead'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { iconClass, iconTag } from '../shared/icon'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronRight from '~icons/lucide/chevron-right'\nimport IconGripVertical from '~icons/lucide/grip-vertical'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconMinus from '~icons/lucide/minus'\nimport type {\n GrTreeBranchLineColor,\n GrTreeNodeClass,\n GrTreeProps,\n GrTreeVisibleRow,\n} from './grTreeProps'\n\nexport interface GrTreeEmits<T extends Record<string, any> = any> {\n (e: 'nodeClick', data: T, node: GrTreeNode<T>): void\n (e: 'nodeExpand', data: T, node: GrTreeNode<T>): void\n (e: 'nodeCollapse', data: T, node: GrTreeNode<T>): void\n (e: 'nodeDrop', draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType): void\n (e: 'nodeContextMenu', evt: MouseEvent, data: T, node: GrTreeNode<T>): void\n (e: 'update:currentKey', key: GrTreeKey | undefined): void\n /**\n * Результат фильтрации. Без него потребитель не отличит «данных нет» от\n * «поиск ничего не нашёл» — а это разные пустые экраны: второй пользователь\n * может исправить сам.\n */\n (e: 'filter', info: { value: string, visibleCount: number, matchedCount: number }): void\n (e: 'update:checkedKeys', keys: GrTreeKey[]): void\n (e: 'check', data: T, node: GrTreeNode<T>, info: { checkedKeys: GrTreeKey[], halfCheckedKeys: GrTreeKey[] }): void\n}\n\nconst DEFAULT_BRANCH_LINE_COLOR = 'var(--gr-tree-branch-line-default-color, var(--gr-brd))'\n\n/** Стрелки, которые вместе с `Shift` двигают узел, а не фокус. */\nconst MOVE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'])\n\nconst props = withDefaults(defineProps<GrTreeProps<T>>(), {\n props: () => ({\n children: 'children',\n label: 'label',\n }),\n nodeKey: 'id' as any,\n defaultExpandedKeys: () => [],\n defaultExpandAll: false,\n expandOnClickNode: false,\n accordion: false,\n size: undefined,\n highlightCurrent: true,\n indent: 0,\n virtual: false,\n maxHeight: undefined,\n showCheckbox: false,\n currentKey: undefined,\n filterValue: undefined,\n dragHandleVisibility: 'auto',\n checkedKeys: undefined,\n defaultCheckedKeys: () => [],\n checkStrictly: false,\n lazy: false,\n load: undefined,\n expandIcon: undefined,\n collapseIcon: undefined,\n toggleIconRotate: true,\n branchLine: 'line',\n branchLineColor: undefined,\n branchLineActiveColor: undefined,\n draggable: false,\n dragHandleIcon: undefined,\n dragLabel: undefined,\n expandLabel: undefined,\n collapseLabel: undefined,\n rowClass: undefined,\n dragHandleClass: undefined,\n toggleClass: undefined,\n toggleIconClass: undefined,\n toggleSpacerClass: undefined,\n contentClass: undefined,\n})\n\nconst emit = defineEmits<GrTreeEmits<T>>()\n\ndefineSlots<{\n default?: (props: { node: GrTreeNode<T>, data: T }) => any\n}>()\n\nconst dataAdapter = createGrTreeDataAdapter<T>(props)\nconst treeStore = useTree({\n adapter: dataAdapter,\n // Цвет направляющей — решение компонента, а не модели: она лишь копит цепочку\n // предков. Выключенный `branchLine` не даёт цвета вовсе, и цепочка пуста.\n branchColorFor: branchColorForNode,\n data: () => props.data,\n defaultExpandedKeys: () => props.defaultExpandedKeys,\n defaultExpandAll: () => props.defaultExpandAll,\n filterNodeMethod: filterNodeForModel,\n defaultCheckedKeys: () => props.defaultCheckedKeys,\n checkedKeys: () => props.checkedKeys,\n checkStrictly: () => props.checkStrictly,\n lazy: () => props.lazy,\n load: loadForModel,\n})\nconst interactionContext = createGrTreeInteractionContext(props, {\n emitNodeClick: (data, node) => emit('nodeClick', data, node),\n emitNodeExpand: (data, node) => emit('nodeExpand', data, node),\n emitNodeCollapse: (data, node) => emit('nodeCollapse', data, node),\n emitNodeDrop: (draggingNode, dropNode, dropType) => emit('nodeDrop', draggingNode, dropNode, dropType),\n emitNodeContextMenu: (evt, data, node) => emit('nodeContextMenu', evt, data, node),\n})\n\nconst treeProps = props as Readonly<GrTreeProps<T>>\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\nconst dragLabel = computed(() => treeProps.dragLabel ?? t('gr.tree.drag', 'Drag'))\nconst expandLabel = computed(() => treeProps.expandLabel ?? t('gr.tree.expand', 'Expand'))\nconst collapseLabel = computed(() => treeProps.collapseLabel ?? t('gr.tree.collapse', 'Collapse'))\nconst currentKey = treeStore.currentKey\nconst hoveredKey = interactionContext.hoveredKey\nconst dropTarget = interactionContext.dropTarget\n\n/**\n * Текущий узел: управляемый режим включает сам факт того, что проп задан.\n *\n * Иначе у одного понятия два владельца — подсветку рисует дерево по своему\n * ключу, а обёртка считает остальное по своему пропу; разойдись они на такт, и\n * строка подсвечена, а подпись не выделена. С `v-model:current-key` источник\n * правды один, и `nextTick` вокруг `setCurrentKey()` больше не нужен.\n */\nconst currentKeyControlled = computed(() => treeProps.currentKey !== undefined)\n\nwatch(() => treeProps.currentKey, (key) => {\n if (!currentKeyControlled.value)\n return\n if (treeStore.currentKey.value === (key ?? undefined))\n return\n\n treeStore.setCurrentKey(key ?? undefined)\n}, { immediate: true })\n\n/** Значение фильтра приходит пропом; метод `filter()` остаётся для императивных сценариев. */\nwatch(() => treeProps.filterValue, (value) => {\n if (value === undefined)\n return\n\n applyFilter(value)\n}, { immediate: true })\n\n// Корневой элемент дерева — область для делегированной клавиатуры (WAI-ARIA tree).\nconst treeRootEl = ref<HTMLElement | null>(null)\n\n/**\n * Видимые строки считает модель (`useTree`): в плоском DOM группы нет, и\n * структуру дерева диктору сообщают `aria-level`, `aria-posinset` и\n * `aria-setsize` — всё это приходит из неё готовым.\n */\nconst visibleRows = treeStore.visibleRows\n\n/**\n * Кольцо roving-фокуса: ровно один `treeitem` на всё дерево держит `tabindex=0`.\n *\n * Ориентация вертикальная намеренно: влево-вправо в дереве заняты раскрытием\n * ветки и переходом к родителю, и примитив их не трогает — это доменная логика,\n * она осталась в `onTreeKeydown`.\n */\nconst roving = useRovingFocus<GrTreeNode<T>['key']>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key),\n orientation: () => 'vertical',\n // У дерева есть верх и низ: с последней строки вниз идти некуда.\n wrap: () => false,\n // Но клавишу на краю всё равно гасим: иначе `ArrowDown` на последнем узле\n // прокрутит страницу под деревом.\n onOverflow: () => true,\n // Пока фокус не трогали, остановку держит текущий (выбранный) узел, а если\n // его не видно — первая видимая строка.\n initialKey: () => currentKey.value ?? undefined,\n beforeFocus: key => scrollRowIntoView(key),\n})\n\nfunction onRowClick(node: GrTreeNode<T>) {\n // В управляемом режиме дерево ведёт подсветку до ответа снаружи: строка\n // отзывается на клик сразу, а расхождение снимет наблюдатель за пропом.\n treeStore.setCurrentKey(node.key)\n emit('update:currentKey', node.key)\n roving.setActive(node.key)\n interactionContext.emitNodeClick(node.data, node)\n}\n\n// Клик мышью, в отличие от Enter, умеет ещё и раскрывать узел: `Enter` в\n// паттерне tree закреплён за выбором, и подмешивать в него раскрытие нельзя.\nfunction onRowActivate(row: GrTreeVisibleRow<T>) {\n onRowClick(row.node)\n\n if (treeProps.expandOnClickNode && !row.isLeaf)\n toggleExpand(row.node)\n}\n\nfunction onRowContextMenu(evt: MouseEvent, node: GrTreeNode<T>) {\n interactionContext.emitNodeContextMenu(evt, node.data, node)\n}\n\n// ————— Клавиатурная навигация по WAI-ARIA tree pattern (только корневой инстанс).\n\nfunction isRovingItem(key: GrTreeNode<T>['key']): boolean {\n return roving.rovingKey.value === key\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTree' })\n\n// Переменные ставим и вложенным уровням тоже: `v-bind=\"props\"` доносит до них\n// `size`, а значения одинаковые — наследование от корня не нарушается.\nconst sizeStyle = computed(() => treeSizeVars[resolvedSize.value])\n\n/**\n * Виртуализация: в DOM живёт только окно вокруг вьюпорта.\n *\n * Корень дерева и есть скроллер — обёрток-распорок между `role=\"tree\"` и\n * `role=\"treeitem\"` быть не должно, поэтому срезанное сверху и снизу держат\n * отступы самого корня.\n */\nconst TREE_ROW_GAP = 2\n\nconst rowEstimate = computed(() => Number.parseFloat(sizeStyle.value['--gr-tree-row-min-height']))\n\nconst virtualMaxHeight = computed(() => {\n const value = treeProps.maxHeight\n if (value == null)\n return undefined\n return typeof value === 'number' ? `${value}px` : value\n})\n\nconst virtualizer = useVirtualList({\n container: treeRootEl,\n count: () => (treeProps.virtual ? visibleRows.value.length : 0),\n // Раскрытие/фильтр сдвигают индексы строк — замеры прошлого набора невалидны.\n source: () => visibleRows.value,\n itemSize: () => rowEstimate.value,\n gap: TREE_ROW_GAP,\n // Первый рендер обязан совпасть с серверным: контейнера ещё нет, и окно\n // считается от объявленной высоты, а не от измеренной.\n viewportSize: () => (typeof treeProps.maxHeight === 'number' ? treeProps.maxHeight : undefined),\n})\n\n/** Строки к отрисовке: при выключенной виртуализации — все. */\nconst renderedRows = computed(() => {\n if (!treeProps.virtual)\n return visibleRows.value\n\n const { start, end } = virtualizer.range.value\n return visibleRows.value.slice(start, end)\n})\n\n/**\n * Срезанное сверху и снизу держат псевдоэлементы контейнера.\n *\n * Ни один из трёх напрашивающихся вариантов не годится:\n *\n * - `padding` контейнера — `max-height` меряет ту же коробку, и распорка в сто\n * тысяч пикселей либо раздувает скроллер до той же сотни тысяч, либо съедает\n * всю его высоту;\n * - обёртка-распорка внутри — между `role=\"tree\"` и `role=\"treeitem\"` не должно\n * быть посторонних узлов, роль потеряла бы обязательных потомков;\n * - отступы крайних отрисованных строк — распорка исчезает ровно в тот момент,\n * когда строки заменяются целиком (прыжок прокрутки), содержимое схлопывается\n * до высоты окна, и браузер обрезает `scrollTop` до почти нуля.\n *\n * `::before`/`::after` не узлы DOM: их не за что размонтировать, в дереве\n * доступности их нет, а высота приезжает переменными в том же патче, что и сами\n * строки, — схлопнуться между кадрами нечему.\n */\nconst rootStyle = computed(() => {\n if (!treeProps.virtual)\n return sizeStyle.value\n\n return {\n ...sizeStyle.value,\n overflow: 'auto',\n maxHeight: virtualMaxHeight.value,\n ...virtualizer.spacerStyle.value,\n }\n})\n\n/** Абсолютный индекс отрисованной строки: поиск по массиву стоил бы O(n) на строку. */\nfunction absoluteIndex(offsetInWindow: number): number {\n return treeProps.virtual ? virtualizer.range.value.start + offsetInWindow : offsetInWindow\n}\n\n/**\n * Строка размонтируется: снимаем регистрацию и, если фокус был на ней, уводим\n * его на корень — делегированный keydown живёт там, первая же стрелка вернёт\n * видимую строку через `focusRow`. Иначе фокус упал бы на `body` и клавиатура\n * дерева умерла бы до клика мышью.\n *\n * Спрашиваем сам элемент, а не `document.activeElement === body`: Vue обнуляет\n * function ref ДО удаления узла, поэтому в момент вызова фокус ещё на строке —\n * а «фокус на body» означает лишь то, что страницу никто не трогал.\n */\nlet isUnmounting = false\n\nfunction releaseNodeEl(key: GrTreeKey): void {\n const el = interactionContext.nodeEls.get(key)\n const active = typeof document === 'undefined' ? null : document.activeElement\n const heldFocus = Boolean(el && active && (el === active || el.contains(active)))\n\n interactionContext.registerNodeEl(key, null)\n\n if (heldFocus && !isUnmounting)\n treeRootEl.value?.focus({ preventScroll: true })\n}\n\n/**\n * При виртуализации узла вне окна в DOM нет: `nodeEls.get` вернул бы\n * `undefined`, а фокус уехал бы на `body` вместе с размонтированной строкой.\n * Поэтому сперва прокрутка, и только следующим тиком — фокус.\n */\nfunction scrollRowIntoView(key: GrTreeNode<T>['key']): Promise<void> {\n if (treeProps.virtual) {\n const index = visibleRows.value.findIndex(row => row.node.key === key)\n if (index >= 0)\n virtualizer.scrollToIndex(index)\n }\n\n return nextTick()\n}\n\nfunction focusRow(key: GrTreeNode<T>['key']): void {\n void roving.focusKey(key)\n}\n\n/**\n * Typeahead паттерна tree: печатные символы копятся в буфер и переводят фокус\n * на первый подходящий видимый узел, начиная со следующего за текущим.\n *\n * Поиск идёт по данным (`visibleRows`), а не по DOM: при виртуализации узла вне\n * окна в разметке нет, и поиск по тексту элементов находил бы только видимое.\n */\nconst typeahead = useTypeahead<GrTreeVisibleRow<T>>({\n items: () => visibleRows.value,\n textOf: row => row.node.label,\n // Без наведённого фокуса ищем с начала списка, а не от конца: `findIndex`\n // вернул бы `-1`, и первая строка выпала бы из обхода.\n currentIndex: rows => Math.max(0, rows.findIndex(row => row.node.key === roving.rovingKey.value)),\n onMatch: row => focusRow(row.node.key),\n})\n\n/** `*` — раскрыть всех соседей узла, на котором фокус (уровень целиком). */\nfunction expandSiblings(node: GrTreeNode<T>): void {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.childNodes.length === 0 || treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, true)\n interactionContext.emitNodeExpand(sibling.data, sibling)\n }\n}\n\nfunction onTreeKeydown(event: KeyboardEvent): void {\n // Делегированная клавиатура уважает интерактивные цели: печать в инпуте слота\n // узла — ввод текста, а не typeahead. Без гарда preventDefault отменял бы это.\n const target = event.target as HTMLElement | null\n const interactive = target?.closest<HTMLElement>('button, a[href], input, select, textarea, [contenteditable]')\n if (interactive && interactive !== event.currentTarget) {\n // Табируемая цель — самостоятельный таб-стоп: клавиатура целиком её.\n if (interactive.tabIndex >= 0)\n return\n\n // Кнопки строки (toggle, drag-handle) не табируемы: фокус попадает на них\n // только мышью. За ними остаётся активация — Enter на toggle это его клик, —\n // а навигация принадлежит дереву, иначе клик мышью убивал бы стрелки.\n if (event.key === 'Enter' || event.key === ' ')\n return\n }\n\n const rows = visibleRows.value\n if (rows.length === 0)\n return\n\n const idx = Math.max(0, rows.findIndex(r => r.node.key === roving.rovingKey.value))\n const cur = rows[idx]\n\n if (event.key === '*') {\n event.preventDefault()\n expandSiblings(cur.node)\n return\n }\n\n // Печатный символ без модификаторов — typeahead, а не команда.\n if (event.key.length === 1 && event.key !== ' ' && !event.ctrlKey && !event.metaKey && !event.altKey) {\n event.preventDefault()\n typeahead.type(event.key)\n return\n }\n\n // `Shift` со стрелкой двигает сам узел — раскладка аутлайнера. Проверяется\n // раньше навигации: иначе примитив увёл бы фокус вместо переноса.\n if (event.shiftKey && MOVE_KEYS.has(event.key)) {\n if (!treeProps.draggable)\n return\n\n event.preventDefault()\n void onNodeMoveKey(cur.node, event.key)\n return\n }\n\n // Вертикаль, `Home` и `End` ведёт примитив. Влево-вправо он не трогает: в\n // дереве это раскрытие ветки и переход к родителю, а не движение по списку.\n if (roving.handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'ArrowRight':\n event.preventDefault()\n if (!cur.isLeaf) {\n if (!cur.isExpanded)\n toggleExpand(cur.node)\n else if (idx < rows.length - 1)\n focusRow(rows[idx + 1].node.key)\n }\n break\n case 'ArrowLeft':\n event.preventDefault()\n if (!cur.isLeaf && cur.isExpanded)\n toggleExpand(cur.node)\n else if (cur.node.parent && rows.some(r => r.node.key === cur.node.parent!.key))\n focusRow(cur.node.parent.key)\n break\n case 'Enter':\n event.preventDefault()\n onRowClick(cur.node)\n break\n // Space при чекбоксах переключает отметку — это и есть выбор в\n // multi-select дереве; без них он остаётся вторым способом выбрать узел.\n case ' ':\n event.preventDefault()\n if (treeProps.showCheckbox)\n toggleChecked(cur.node)\n else\n onRowClick(cur.node)\n break\n }\n}\n\nfunction onRowMouseEnter(node: GrTreeNode<T>) {\n hoveredKey.value = node.key\n}\n\nfunction onRowMouseLeave(node: GrTreeNode<T>) {\n if (hoveredKey.value === node.key)\n hoveredKey.value = undefined\n}\n\nfunction collapseSiblings(node: GrTreeNode<T>) {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.key === node.key || !treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, false)\n interactionContext.emitNodeCollapse(sibling.data, sibling)\n }\n}\n\nfunction toggleExpand(node: GrTreeNode<T>) {\n const expanded = !treeStore.isExpandedKey(node.key)\n\n if (expanded && treeProps.accordion)\n collapseSiblings(node)\n\n // Ленивая ветка грузится по первому раскрытию; повторное ничего не запрашивает.\n if (expanded)\n treeStore.ensureLoaded(node)\n\n treeStore.toggleExpand(node)\n\n if (expanded)\n interactionContext.emitNodeExpand(node.data, node)\n else\n interactionContext.emitNodeCollapse(node.data, node)\n}\n\n// ————— Отметки (чекбоксы).\n\nfunction checkStateOf(key: GrTreeKey): GrTreeCheckState {\n return treeStore.getCheckState(key)\n}\n\nfunction ariaCheckedOf(row: GrTreeVisibleRow<T>): 'true' | 'false' | 'mixed' | undefined {\n if (!treeProps.showCheckbox)\n return undefined\n\n const state = checkStateOf(row.node.key)\n return state === 'checked' ? 'true' : state === 'half' ? 'mixed' : 'false'\n}\n\nfunction emitCheck(node: GrTreeNode<T>): void {\n const checkedKeys = treeStore.getCheckedKeys()\n emit('update:checkedKeys', checkedKeys)\n emit('check', node.data, node, { checkedKeys, halfCheckedKeys: treeStore.getHalfCheckedKeys() })\n}\n\nfunction toggleChecked(node: GrTreeNode<T>): void {\n if (!treeProps.showCheckbox)\n return\n\n const changed = treeStore.toggleChecked(node)\n if (changed)\n emitCheck(changed)\n}\n\n// ————— Геометрия строки: отступ уровня и направляющие ветвей.\n\nfunction rowStyle(row: GrTreeVisibleRow<T>) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return { '--gr-tree-row-indent': `calc(${step} * ${row.node.level - 1})` }\n}\n\n/**\n * Направляющая уровня-предка. Считается от того же шага отступа, что и сам\n * отступ строки, — иначе линия и содержимое разъедутся на вложенных уровнях.\n */\n/**\n * Колено рисуется только у направляющей собственного уровня строки: остальные\n * — это транзит предков, и горизонтальная черта у них указывала бы на строку,\n * к которой они не относятся.\n *\n * У последнего ребёнка вертикаль обрывается на середине: продолжать её значит\n * обещать сиблинга, которого нет.\n */\n/**\n * Цвет направляющей уровня для модели. Объявление функцией, а не стрелкой на\n * месте вызова: `treeProps` определяются ниже, и ссылка на них в выражении\n * читалась бы до объявления.\n */\n/**\n * Обёртки над пропами для модели: объявлением, а не стрелкой на месте вызова —\n * `treeProps` определяются ниже. `undefined` от фильтра означает «решай сам»:\n * так обёртка возвращает модель к её подстрочному матчу, когда своего правила\n * потребитель не задал.\n */\nfunction filterNodeForModel(value: string, data: T, node: GrTreeNode<T>) {\n return treeProps.filterNodeMethod?.(value, data, node)\n}\n\nfunction loadForModel(node: GrTreeNode<T>, resolve: (children: T[]) => void) {\n treeProps.load?.(node, resolve)\n}\n\nfunction branchColorForNode(node: GrTreeNode<T>) {\n return treeProps.branchLine ? resolveBranchLineColor(node) : undefined\n}\n\nfunction branchGuideModifiers(row: GrTreeVisibleRow<T>, index: number) {\n if (treeProps.branchLine !== 'elbow' || index !== row.branchColors.length - 1)\n return undefined\n\n return row.posInSet === row.setSize\n ? 'gr-tree__branch-guide--elbow gr-tree__branch-guide--last'\n : 'gr-tree__branch-guide--elbow'\n}\n\nfunction branchGuideStyle(row: GrTreeVisibleRow<T>, index: number) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return {\n 'left': `calc(${step} * ${index} + var(--gr-tree-branch-line-offset))`,\n '--gr-tree-branch-line-color': row.branchColors[index],\n }\n}\n\n// Drag & drop\nfunction canDrag(node: GrTreeNode<T>): boolean {\n return interactionContext.canDrag(node)\n}\n\n/**\n * Ручка «по наведению» на тач-устройстве недостижима: событий наведения там нет,\n * ключ не выставляется, класс видимости не появляется — то есть перетаскивания\n * нет вовсе, хотя `touch-action: none` у ручки стоит ровно ради него.\n *\n * Режим `auto` решает это без JS: класс-модификатор на корне, а показ включает\n * `@media (hover: none)` — так поведение остаётся верным и на сервере, где\n * никакого `matchMedia` спрашивать нельзя.\n */\nfunction shouldShowDragHandle(node: GrTreeNode<T>): boolean {\n if (!canDrag(node))\n return false\n\n return treeProps.dragHandleVisibility === 'always' || hoveredKey.value === node.key\n}\n\n/**\n * Треть строки сверху — «до», треть снизу — «после», середина — «внутрь».\n * Зоны нарезает компонент: примитив отдаёт только долю вдоль строки.\n */\nfunction dropTypeFromFraction(fraction: number): GrTreeNodeDropType {\n if (fraction < 1 / 3)\n return 'prev'\n if (fraction > 2 / 3)\n return 'next'\n\n return 'inner'\n}\n\nfunction canDrop(drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType): boolean {\n return interactionContext.canDrop(drag, target, type)\n}\n\n/** Перенос состоялся: одна дорога и для указателя, и для клавиатуры. */\nfunction applyMove(source: GrTreeNode<T>, targetKey: GrTreeKey, type: GrTreeNodeDropType): boolean {\n const reference = treeStore.getNode(targetKey)\n if (!reference)\n return false\n\n const movedNode = treeStore.moveNode(source, reference, type)\n if (!movedNode)\n return false\n\n const dropNode = treeStore.getNode(reference.key) ?? reference\n interactionContext.emitNodeDrop(movedNode, dropNode, type)\n\n return true\n}\n\nconst dragSort = useDragSort<GrTreeKey, GrTreeDropTarget>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key) ?? null,\n scroller: () => treeRootEl.value,\n disabled: () => !treeProps.draggable,\n canDrag: (key) => {\n const node = treeStore.getNode(key)\n\n return node ? canDrag(node) : false\n },\n resolveTarget: (hit, sourceKey, previous) => {\n const source = treeStore.getNode(sourceKey)\n const node = treeStore.getNode(hit.key)\n if (!source || !node)\n return null\n\n const type = dropTypeFromFraction(hit.fraction)\n const allowed = treeStore.canMoveNode(source, node, type) && canDrop(source, node, type)\n\n // Та же ссылка, пока смысл не изменился: иначе подсветка перерисовывалась бы\n // на каждом движении указателя.\n if (previous && previous.key === node.key && previous.type === type && previous.allowed === allowed)\n return previous\n\n return { key: node.key, type, allowed }\n },\n onDrop: (sourceKey, target) => {\n const source = treeStore.getNode(sourceKey)\n if (!source || !target.allowed)\n return\n\n applyMove(source, target.key, target.type)\n },\n onUpdate: (sourceKey, target) => {\n interactionContext.draggingNode.value = sourceKey === null ? null : treeStore.getNode(sourceKey) ?? null\n interactionContext.dropTarget.value = target\n },\n})\n\nfunction onHandlePointerDown(event: PointerEvent, node: GrTreeNode<T>): void {\n if (!treeProps.draggable)\n return\n\n dragSort.startFrom(node.key)(event)\n}\n\n/**\n * Клавиатурный перенос — раскладка аутлайнера: `Shift` со стрелкой сразу\n * двигает узел, без режима «взято». Режим здесь был бы лишним: `Space` в дереве\n * уже отмечает чекбокс, а стрелки водят фокус по веткам.\n */\nfunction moveByKeyboard(node: GrTreeNode<T>, key: string): boolean {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n const index = siblings.findIndex(sibling => sibling.key === node.key)\n\n if (key === 'ArrowUp' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'prev')\n\n if (key === 'ArrowDown' && index >= 0 && index < siblings.length - 1)\n return applyMove(node, siblings[index + 1].key, 'next')\n\n // Вправо — в предыдущего соседа: у первого в уровне такого соседа нет.\n if (key === 'ArrowRight' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'inner')\n\n if (key === 'ArrowLeft' && node.parent)\n return applyMove(node, node.parent.key, 'next')\n\n return false\n}\n\nasync function onNodeMoveKey(node: GrTreeNode<T>, key: string): Promise<void> {\n if (!treeProps.draggable || !canDrag(node))\n return\n if (!moveByKeyboard(node, key))\n return\n\n announce(t('gr.tree.moved', 'Moved {label}', { label: node.label }))\n\n // Перестановка перерисовывает уровень: без возврата фокуса следующий Shift\n // уже некуда было бы адресовать.\n await nextTick()\n focusRow(node.key)\n}\n\n/**\n * Фильтрация и отчёт о её результате.\n *\n * Счёт снимается после пересчёта видимых строк: `visibleCount` — то, что\n * пользователь реально видит, а `matchedCount` — сколько узлов совпало само,\n * без учёта родителей, раскрытых ради показа совпадения.\n */\nasync function applyFilter(value: string) {\n treeStore.filter(value)\n await nextTick()\n\n emit('filter', {\n value,\n visibleCount: visibleRows.value.length,\n matchedCount: treeStore.filterInfo.value.matchedKeys.size,\n })\n}\n\nfunction filter(value: string) {\n void applyFilter(value)\n}\n\nfunction resolveNodeClass(classValue: GrTreeNodeClass<T> | undefined, row: GrTreeVisibleRow<T>) {\n if (!classValue)\n return undefined\n\n return typeof classValue === 'function'\n ? classValue(row)\n : classValue\n}\n\nfunction resolveBranchLineColorValue(color: GrTreeBranchLineColor<T> | undefined, node: GrTreeNode<T>) {\n if (!color)\n return undefined\n\n return typeof color === 'function'\n ? color(node) ?? undefined\n : color\n}\n\nfunction isBranchLineActive(node: GrTreeNode<T>) {\n const selectedKey = currentKey.value\n\n if (selectedKey == null)\n return false\n\n if (node.key === selectedKey)\n return true\n\n return node.childNodes.some(child => child.key === selectedKey && !treeStore.isExpandedKey(child.key))\n}\n\nfunction resolveBranchLineColor(node: GrTreeNode<T>) {\n const defaultColor = resolveBranchLineColorValue(treeProps.branchLineColor, node) ?? DEFAULT_BRANCH_LINE_COLOR\n\n if (!isBranchLineActive(node))\n return defaultColor\n\n return resolveBranchLineColorValue(treeProps.branchLineActiveColor, node) ?? defaultColor\n}\n\n/**\n * Переводит фокус на узел (по умолчанию — на тот, что держит roving tabindex).\n * Нужен снаружи: `GrTreeSelect` открывает панель и обязан отдать клавиатуру\n * дереву, иначе стрелки из триггера никуда не ведут.\n */\nfunction focus(key?: GrTreeKey): boolean {\n const rows = visibleRows.value\n if (rows.length === 0)\n return false\n\n const target = key != null && rows.some(row => row.node.key === key)\n ? key\n : roving.rovingKey.value ?? rows[0].node.key\n\n focusRow(target)\n return true\n}\n\n// Дерево уничтожают целиком — строки размонтируются вместе с ним, и возвращать\n// фокус на умирающий корень нельзя: он уедет из документа вместе с деревом.\nonBeforeUnmount(() => {\n isUnmounting = true\n})\n\ndefineExpose<GrTreeInstance<T>>({\n appendNode: treeStore.appendNode,\n getCheckedKeys: options => treeStore.getCheckedKeys(options),\n setCheckedKeys: (keys) => {\n treeStore.setCheckedKeys(keys)\n emit('update:checkedKeys', treeStore.getCheckedKeys())\n },\n getHalfCheckedKeys: treeStore.getHalfCheckedKeys,\n setChecked: (node, checked) => {\n const changed = treeStore.setChecked(node, checked)\n if (changed)\n emitCheck(changed)\n return Boolean(changed)\n },\n filter,\n focus,\n getCurrentNode: treeStore.getCurrentNode,\n setCurrentKey: treeStore.setCurrentKey,\n getCurrentKey: treeStore.getCurrentKey,\n getNode: treeStore.getNode,\n insertNodeAfter: treeStore.insertNodeAfter,\n insertNodeBefore: treeStore.insertNodeBefore,\n removeNode: treeStore.removeNode,\n setCurrentNode: treeStore.setCurrentNode,\n})\n</script>\n\n<template>\n <div\n ref=\"treeRootEl\"\n data-gr-tree\n class=\"gr-tree\"\n :class=\"treeProps.dragHandleVisibility === 'auto' ? 'gr-tree--drag-handle-auto' : ''\"\n tabindex=\"-1\"\n :data-gr-virtual=\"treeProps.virtual ? '' : undefined\"\n role=\"tree\"\n :aria-multiselectable=\"treeProps.showCheckbox ? 'true' : undefined\"\n :style=\"rootStyle\"\n @keydown=\"onTreeKeydown\"\n >\n <div\n v-for=\"(row, windowIndex) in renderedRows\"\n :key=\"row.node.key\"\n :ref=\"(el) => {\n if (el) interactionContext.registerNodeEl(row.node.key, el as HTMLElement)\n else releaseNodeEl(row.node.key)\n if (treeProps.virtual) virtualizer.measure(absoluteIndex(windowIndex), el as Element | null)\n }\"\n data-gr-tree-node\n :data-gr-tree-node-key=\"row.node.key\"\n role=\"treeitem\"\n :aria-level=\"row.node.level\"\n :aria-posinset=\"row.posInSet\"\n :aria-setsize=\"row.setSize\"\n :aria-expanded=\"row.isLeaf ? undefined : row.isExpanded\"\n :aria-selected=\"currentKey === row.node.key ? 'true' : undefined\"\n :aria-checked=\"ariaCheckedOf(row)\"\n :aria-busy=\"row.isLoading ? 'true' : undefined\"\n :tabindex=\"isRovingItem(row.node.key) ? 0 : -1\"\n >\n <div\n data-gr-tree-row\n class=\"gr-tree__row\"\n :class=\"[\n treeProps.highlightCurrent && currentKey === row.node.key ? 'gr-tree__row--current' : '',\n row.isLeaf ? 'gr-tree__row--leaf' : '',\n row.isMatched ? 'gr-tree__row--matched' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'inner' ? 'gr-tree__row--drop-inner' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'prev' ? 'gr-tree__row--drop-prev' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'next' ? 'gr-tree__row--drop-next' : '',\n resolveNodeClass(treeProps.rowClass, row),\n ]\"\n :style=\"rowStyle(row)\"\n @click=\"onRowActivate(row)\"\n @contextmenu=\"onRowContextMenu($event, row.node)\"\n @drop.prevent\n @mouseenter=\"onRowMouseEnter(row.node)\"\n @mouseleave=\"onRowMouseLeave(row.node)\"\n >\n <!--\n Направляющие ветвей: по одной на каждый уровень предка. Вложенной\n обёртки с `border-left` больше нет, поэтому линию рисует сама строка —\n и заходит в зазор между строками, иначе она распалась бы на штрихи.\n -->\n <span\n v-for=\"(color, guideIndex) in row.branchColors\"\n :key=\"guideIndex\"\n data-gr-tree-branch-guide\n class=\"gr-tree__branch-guide\"\n :class=\"branchGuideModifiers(row, guideIndex)\"\n :style=\"branchGuideStyle(row, guideIndex)\"\n aria-hidden=\"true\"\n />\n\n <button\n v-if=\"treeProps.draggable\"\n type=\"button\"\n tabindex=\"-1\"\n data-gr-tree-drag-handle\n class=\"gr-tree__drag-handle\"\n :class=\"[\n shouldShowDragHandle(row.node) ? 'gr-tree__drag-handle--visible' : '',\n canDrag(row.node) ? '' : 'gr-tree__drag-handle--disabled',\n resolveNodeClass(treeProps.dragHandleClass, row),\n ]\"\n :aria-label=\"dragLabel\"\n :aria-disabled=\"canDrag(row.node) ? undefined : 'true'\"\n @click.stop\n @pointerdown=\"onHandlePointerDown($event, row.node)\"\n >\n <component\n :is=\"iconTag(treeProps.dragHandleIcon, IconGripVertical)\"\n class=\"gr-tree__drag-icon\"\n :class=\"iconClass(treeProps.dragHandleIcon)\"\n />\n </button>\n\n <!-- tabindex=\"-1\": внутри roving-композита интерактив не табируется,\n клавиатурный эквивалент — ArrowRight/ArrowLeft на строке. -->\n <button\n v-if=\"!row.isLeaf\"\n data-gr-tree-toggle\n type=\"button\"\n tabindex=\"-1\"\n class=\"gr-tree__toggle\"\n :class=\"resolveNodeClass(treeProps.toggleClass, row)\"\n :aria-label=\"row.isExpanded ? collapseLabel : expandLabel\"\n @click.stop=\"toggleExpand(row.node)\"\n >\n <IconLoaderCircle\n v-if=\"row.isLoading\"\n data-gr-tree-loading\n class=\"gr-tree__toggle-icon animate-spin\"\n />\n <component\n :is=\"iconTag(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon, IconChevronRight)\"\n v-else\n class=\"gr-tree__toggle-icon\"\n :class=\"[\n iconClass(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon),\n row.isExpanded && treeProps.toggleIconRotate ? 'gr-tree__toggle-icon--expanded' : '',\n resolveNodeClass(treeProps.toggleIconClass, row),\n ]\"\n />\n </button>\n <span\n v-else\n class=\"gr-tree__toggle-spacer\"\n :class=\"resolveNodeClass(treeProps.toggleSpacerClass, row)\"\n />\n\n <!--\n Квадратик отметки декоративен: состояние живёт на самом `treeitem`\n (`aria-checked`), а вложить интерактивный чекбокс внутрь роли-виджета\n нельзя — роль объявляет потомков презентационными.\n -->\n <span\n v-if=\"treeProps.showCheckbox\"\n data-gr-tree-checkbox\n class=\"gr-tree__checkbox\"\n :class=\"[\n checkStateOf(row.node.key) === 'checked' ? 'gr-tree__checkbox--checked' : '',\n checkStateOf(row.node.key) === 'half' ? 'gr-tree__checkbox--half' : '',\n ]\"\n aria-hidden=\"true\"\n @click.stop=\"toggleChecked(row.node)\"\n >\n <component\n :is=\"checkStateOf(row.node.key) === 'half' ? IconMinus : IconCheck\"\n v-if=\"checkStateOf(row.node.key) !== 'unchecked'\"\n class=\"gr-tree__checkbox-mark\"\n />\n </span>\n\n <div class=\"gr-tree__content\" :class=\"resolveNodeClass(treeProps.contentClass, row)\">\n <slot\n :node=\"row.node\"\n :data=\"row.node.data\"\n >\n <span class=\"gr-tree__label\">{{ row.node.label }}</span>\n </slot>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.gr-tree {\n --gr-tree-gap: 2px;\n --gr-tree-children-pl: 10px;\n --gr-tree-row-min-height: 28px;\n --gr-tree-row-radius: 8px;\n --gr-tree-row-px: 8px;\n --gr-tree-row-py: 8px;\n --gr-tree-row-pr: var(--gr-tree-row-px);\n --gr-tree-font-size: inherit;\n --gr-tree-row-color: var(--gr-fg);\n --gr-tree-row-hover-bg: color-mix(in srgb, var(--gr-primary) 10%, transparent);\n --gr-tree-row-current-bg: color-mix(in srgb, var(--gr-primary) 14%, transparent);\n --gr-tree-row-current-hover-bg: color-mix(in srgb, var(--gr-primary) 16%, transparent);\n --gr-tree-drag-handle-size: 24px;\n --gr-tree-drag-handle-mr: 0;\n --gr-tree-drag-handle-radius: 6px;\n --gr-tree-drag-handle-color: inherit;\n --gr-tree-drag-handle-opacity: 0.55;\n --gr-tree-drag-handle-hover-bg: color-mix(in srgb, var(--gr-muted) 22%, transparent);\n --gr-tree-drag-handle-hover-color: var(--gr-tree-drag-handle-color);\n --gr-tree-drag-handle-hover-opacity: 0.9;\n --gr-tree-drag-handle-disabled-opacity: 0.25;\n --gr-tree-toggle-size: 24px;\n --gr-tree-toggle-mr: 0;\n --gr-tree-toggle-radius: 6px;\n --gr-tree-toggle-color: inherit;\n --gr-tree-toggle-hover-bg: color-mix(in srgb, var(--gr-muted) 25%, transparent);\n --gr-tree-toggle-hover-color: var(--gr-tree-toggle-color);\n --gr-tree-icon-size: 16px;\n --gr-tree-content-gap: 8px;\n --gr-tree-branch-line-default-color: var(--gr-tree-row-current-bg);\n --gr-tree-branch-line-width: 2px;\n /* Шаг отступа уровня: переключатель, отступ вложенного списка и толщина\n направляющей — линия обязана попадать между ними. */\n --gr-tree-indent-step: calc(12px + var(--gr-tree-children-pl) + var(--gr-tree-branch-line-width));\n --gr-tree-row-current-color: var(--gr-tree-row-color);\n --gr-tree-row-current-bar-width: 0px;\n --gr-tree-row-current-bar-color: var(--gr-primary);\n --gr-tree-branch-font-weight: 600;\n --gr-tree-branch-elbow-width: 8px;\n --gr-tree-branch-line-offset: 12px;\n --gr-tree-checkbox-size: 16px;\n --gr-tree-checkbox-radius: 4px;\n --gr-tree-checkbox-brd-width: 1px;\n --gr-tree-checkbox-brd: var(--gr-brd);\n --gr-tree-checkbox-bg: transparent;\n --gr-tree-checkbox-checked-bg: var(--gr-primary);\n --gr-tree-checkbox-checked-fg: var(--gr-primary-fg);\n --gr-tree-checkbox-mr: 4px;\n display: flex;\n flex-direction: column;\n gap: var(--gr-tree-gap);\n /* Кегль и цвет объявлены на дереве, а строка их наследует. На строке они\n были бы объявлением, и класс из `rowClass` — при равном весе и более\n раннем подключении — молча проигрывал бы: ступени кегля по уровням у\n оглавления не применялись вовсе. Наследование уступает любому классу\n потребителя, а модификаторы строки (`--current`) остаются выше. */\n font-size: var(--gr-tree-font-size);\n color: var(--gr-tree-row-color);\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\n.gr-tree__row {\n position: relative;\n display: flex;\n align-items: center;\n min-height: var(--gr-tree-row-min-height);\n padding: var(--gr-tree-row-py) var(--gr-tree-row-pr) var(--gr-tree-row-py)\n calc(var(--gr-tree-row-px) + var(--gr-tree-row-indent, 0px));\n cursor: default;\n user-select: none;\n outline: none;\n isolation: isolate;\n}\n\n/* Поверхность строки — отдельный слой, вставленный слева на отступ уровня.\n Фон на самой коробке шёл от левого края дерева и накрывал направляющие\n предков: линия ветки исчезала под подсветкой ровно там, где она и нужна.\n Слой лежит ниже направляющих (они — следующие элементы строки), поэтому\n линия остаётся видна при любом наложении.\n\n `z-index: -1` уводит слой под содержимое строки. Без него позиционированный\n `::before` красится ПОВЕРХ потоковых подписи, шеврона и отметки — при\n полупрозрачном фоне это лишь лёгкое затенение, а при непрозрачном значении\n публичного токена содержимое исчезает целиком. Поднимать вместо этого\n содержимое пришлось бы у каждого элемента строки и у каждого нового.\n\n `isolation` на самой строке обязателен в паре: без своего контекста\n наложения отрицательный слой уезжает за фон ближайшего предка с заливкой, и\n подсветка пропадает на карточке. */\n.gr-tree__row::before {\n content: '';\n position: absolute;\n inset: 0 0 0 var(--gr-tree-row-indent, 0px);\n border-radius: var(--gr-tree-row-radius);\n pointer-events: none;\n z-index: -1;\n}\n\n.gr-tree__row:hover::before {\n background: var(--gr-tree-row-hover-bg);\n}\n\n/* Направляющая тянется в зазор между строками: иначе линия ветки распалась бы\n на штрихи по числу строк. */\n/* Колено: горизонтальная черта от направляющей к строке. Цвет берётся\n `inherit`, потому что сама направляющая красится инлайновой переменной —\n повторять её резолв в псевдоэлементе значило бы завести второй источник. */\n.gr-tree__branch-guide--elbow::after {\n content: '';\n position: absolute;\n left: 0;\n top: 50%;\n width: var(--gr-tree-branch-elbow-width);\n height: var(--gr-tree-branch-line-width);\n background-color: inherit;\n transform: translateY(-50%);\n}\n\n.gr-tree__branch-guide--last {\n bottom: 50%;\n}\n\n.gr-tree__branch-guide {\n position: absolute;\n top: calc(var(--gr-tree-gap) / -2);\n bottom: calc(var(--gr-tree-gap) / -2);\n width: var(--gr-tree-branch-line-width);\n background: var(--gr-tree-branch-line-color, var(--gr-tree-branch-line-default-color));\n pointer-events: none;\n}\n\n.gr-tree__checkbox {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--gr-tree-checkbox-size);\n height: var(--gr-tree-checkbox-size);\n margin-right: var(--gr-tree-checkbox-mr);\n border: var(--gr-tree-checkbox-brd-width) solid var(--gr-tree-checkbox-brd);\n border-radius: var(--gr-tree-checkbox-radius);\n background: var(--gr-tree-checkbox-bg);\n color: var(--gr-tree-checkbox-checked-fg);\n cursor: pointer;\n}\n\n.gr-tree__checkbox--checked,\n.gr-tree__checkbox--half {\n border-color: var(--gr-tree-checkbox-checked-bg);\n background: var(--gr-tree-checkbox-checked-bg);\n}\n\n.gr-tree__checkbox-mark {\n width: calc(var(--gr-tree-checkbox-size) - 4px);\n height: calc(var(--gr-tree-checkbox-size) - 4px);\n}\n\n[data-gr-tree-node] {\n outline: none;\n}\n\n/* Кольцо фокуса — на той же поверхности, что подсветка: иначе строка читалась бы\n двумя разными прямоугольниками. `outline` для этого не годится — он рисуется по\n границе коробки, а не по инсету. */\n[data-gr-tree-node]:focus-visible > .gr-tree__row::before {\n box-shadow: inset 0 0 0 2px var(--gr-primary);\n}\n\n.gr-tree__row--current {\n color: var(--gr-tree-row-current-color);\n}\n\n.gr-tree__row--current::before {\n background: var(--gr-tree-row-current-bg);\n}\n\n.gr-tree__row--current:hover::before {\n background: var(--gr-tree-row-current-hover-bg);\n}\n\n.gr-tree__row--matched .gr-tree__label {\n font-weight: 600;\n}\n\n/* Ветка набирается плотнее листа: без этого «Операции» и «Эскалации» выглядят\n одним и тем же, и различает их только шеврон, которого у листа нет. Вид, где\n вес несёт уровень, а не ветвистость (оглавление), гасит это токеном. */\n.gr-tree__row:not(.gr-tree__row--leaf) .gr-tree__label {\n font-weight: var(--gr-tree-branch-font-weight);\n}\n\n/* Полоса у текущей строки рисуется на самой строке, а не на подсветке:\n подсветка отступает на отступ уровня, а полоса обязана стоять у края\n списка — иначе она уезжает вправо вместе с вложенностью и перестаёт\n собирать выбранные строки разных уровней в один вертикальный ряд. */\n.gr-tree__row--current {\n box-shadow: inset var(--gr-tree-row-current-bar-width) 0 0 0 var(--gr-tree-row-current-bar-color);\n}\n\n.gr-tree__drag-handle {\n width: var(--gr-tree-drag-handle-size);\n height: var(--gr-tree-drag-handle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-drag-handle-mr);\n border-radius: var(--gr-tree-drag-handle-radius);\n color: var(--gr-tree-drag-handle-color);\n cursor: grab;\n /* Без этого вертикальный свайп по ручке уходит в прокрутку страницы,\n браузер отзывает указатель, и пальцем узел неперетаскиваем. */\n touch-action: none;\n visibility: hidden;\n pointer-events: none;\n opacity: 0;\n}\n\n/* Где наведения не бывает, ручка «по наведению» недостижима — то есть\n перетаскивания нет вовсе. Медиазапрос, а не `matchMedia`: ответ нужен и на\n сервере, а спрашивать среду в первом рендере нельзя. */\n@media (hover: none) {\n .gr-tree--drag-handle-auto .gr-tree__drag-handle {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n }\n}\n\n.gr-tree__drag-handle--visible {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n}\n\n.gr-tree__drag-handle:hover {\n background: var(--gr-tree-drag-handle-hover-bg);\n color: var(--gr-tree-drag-handle-hover-color);\n opacity: var(--gr-tree-drag-handle-hover-opacity);\n}\n\n.gr-tree__drag-handle:active {\n cursor: grabbing;\n}\n\n.gr-tree__drag-handle--disabled {\n cursor: default;\n opacity: var(--gr-tree-drag-handle-disabled-opacity);\n}\n\n.gr-tree__drag-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n}\n\n.gr-tree__toggle {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-toggle-mr);\n border-radius: var(--gr-tree-toggle-radius);\n color: var(--gr-tree-toggle-color);\n}\n\n.gr-tree__toggle:hover {\n background: var(--gr-tree-toggle-hover-bg);\n color: var(--gr-tree-toggle-hover-color);\n}\n\n.gr-tree__toggle-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n transition: transform var(--gr-duration-fast) var(--gr-ease-out);\n}\n\n.gr-tree__toggle-icon--expanded {\n transform: rotate(90deg);\n}\n\n.gr-tree__toggle-spacer {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n margin-right: var(--gr-tree-toggle-mr);\n display: inline-block;\n}\n\n/* Растёт на всю свободную ширину строки: без этого слот сжат по содержимому, и\n хвост строки — счётчик, метка, значок статуса — невозможно прижать вправо\n ничем, кроме внешней ширины, которой у слота нет. Фон и подсветка лежат на\n строке, поэтому у разметки без хвоста рост ничего не меняет. */\n.gr-tree__content {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: var(--gr-tree-content-gap);\n}\n\n.gr-tree__label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.gr-tree__row--drop-inner {\n outline: 2px solid color-mix(in srgb, var(--gr-primary) 40%, transparent);\n}\n\n.gr-tree__row--drop-prev::before,\n.gr-tree__row--drop-next::after {\n content: '';\n position: absolute;\n left: 8px;\n right: 8px;\n height: 2px;\n background: color-mix(in srgb, var(--gr-primary) 55%, transparent);\n}\n\n.gr-tree__row--drop-prev::before {\n top: 2px;\n}\n\n.gr-tree__row--drop-next::after {\n bottom: 2px;\n}\n</style>\n","<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'\nimport type {\n GrTreeAllowDropType,\n GrTreeInstance,\n GrTreeKey,\n GrTreeNode,\n GrTreeNodeDropType,\n} from './grTreeTypes'\nimport { createGrTreeDataAdapter } from '../../composables/internal/treeAdapter'\nimport type { GrTreeDropTarget } from './grTreeInteractionContext'\nimport { createGrTreeInteractionContext } from './grTreeInteractionContext'\nimport type { GrTreeCheckState } from '../../composables/internal/treeChecking'\nimport { useTree } from '../../composables/useTree'\nimport { treeSizeVars } from './grTreeStyles'\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useDragSort } from '../../composables/useDragSort'\nimport { useTypeahead } from '../../composables/internal/useTypeahead'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { iconClass, iconTag } from '../shared/icon'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronRight from '~icons/lucide/chevron-right'\nimport IconGripVertical from '~icons/lucide/grip-vertical'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconMinus from '~icons/lucide/minus'\nimport type {\n GrTreeBranchLineColor,\n GrTreeNodeClass,\n GrTreeProps,\n GrTreeVisibleRow,\n} from './grTreeProps'\n\nexport interface GrTreeEmits<T extends Record<string, any> = any> {\n (e: 'nodeClick', data: T, node: GrTreeNode<T>): void\n (e: 'nodeExpand', data: T, node: GrTreeNode<T>): void\n (e: 'nodeCollapse', data: T, node: GrTreeNode<T>): void\n (e: 'nodeDrop', draggingNode: GrTreeNode<T>, dropNode: GrTreeNode<T>, dropType: GrTreeNodeDropType): void\n (e: 'nodeContextMenu', evt: MouseEvent, data: T, node: GrTreeNode<T>): void\n (e: 'update:currentKey', key: GrTreeKey | undefined): void\n /**\n * Результат фильтрации. Без него потребитель не отличит «данных нет» от\n * «поиск ничего не нашёл» — а это разные пустые экраны: второй пользователь\n * может исправить сам.\n */\n (e: 'filter', info: { value: string, visibleCount: number, matchedCount: number }): void\n (e: 'update:checkedKeys', keys: GrTreeKey[]): void\n (e: 'check', data: T, node: GrTreeNode<T>, info: { checkedKeys: GrTreeKey[], halfCheckedKeys: GrTreeKey[] }): void\n}\n\nconst DEFAULT_BRANCH_LINE_COLOR = 'var(--gr-tree-branch-line-default-color, var(--gr-brd))'\n\n/** Стрелки, которые вместе с `Shift` двигают узел, а не фокус. */\nconst MOVE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'])\n\nconst props = withDefaults(defineProps<GrTreeProps<T>>(), {\n props: () => ({\n children: 'children',\n label: 'label',\n }),\n nodeKey: 'id' as any,\n defaultExpandedKeys: () => [],\n defaultExpandAll: false,\n expandOnClickNode: false,\n accordion: false,\n size: undefined,\n highlightCurrent: true,\n indent: 0,\n virtual: false,\n maxHeight: undefined,\n showCheckbox: false,\n currentKey: undefined,\n filterValue: undefined,\n dragHandleVisibility: 'auto',\n checkedKeys: undefined,\n defaultCheckedKeys: () => [],\n checkStrictly: false,\n lazy: false,\n load: undefined,\n expandIcon: undefined,\n collapseIcon: undefined,\n toggleIconRotate: true,\n branchLine: 'line',\n branchLineColor: undefined,\n branchLineActiveColor: undefined,\n draggable: false,\n dragHandleIcon: undefined,\n dragLabel: undefined,\n expandLabel: undefined,\n collapseLabel: undefined,\n rowClass: undefined,\n dragHandleClass: undefined,\n toggleClass: undefined,\n toggleIconClass: undefined,\n toggleSpacerClass: undefined,\n contentClass: undefined,\n})\n\nconst emit = defineEmits<GrTreeEmits<T>>()\n\ndefineSlots<{\n default?: (props: { node: GrTreeNode<T>, data: T }) => any\n}>()\n\nconst dataAdapter = createGrTreeDataAdapter<T>(props)\nconst treeStore = useTree({\n adapter: dataAdapter,\n // Цвет направляющей — решение компонента, а не модели: она лишь копит цепочку\n // предков. Выключенный `branchLine` не даёт цвета вовсе, и цепочка пуста.\n branchColorFor: branchColorForNode,\n data: () => props.data,\n defaultExpandedKeys: () => props.defaultExpandedKeys,\n defaultExpandAll: () => props.defaultExpandAll,\n filterNodeMethod: filterNodeForModel,\n defaultCheckedKeys: () => props.defaultCheckedKeys,\n checkedKeys: () => props.checkedKeys,\n checkStrictly: () => props.checkStrictly,\n lazy: () => props.lazy,\n load: loadForModel,\n})\nconst interactionContext = createGrTreeInteractionContext(props, {\n emitNodeClick: (data, node) => emit('nodeClick', data, node),\n emitNodeExpand: (data, node) => emit('nodeExpand', data, node),\n emitNodeCollapse: (data, node) => emit('nodeCollapse', data, node),\n emitNodeDrop: (draggingNode, dropNode, dropType) => emit('nodeDrop', draggingNode, dropNode, dropType),\n emitNodeContextMenu: (evt, data, node) => emit('nodeContextMenu', evt, data, node),\n})\n\nconst treeProps = props as Readonly<GrTreeProps<T>>\n\nconst { t } = useGranularityTranslations()\nconst { announce } = useAnnouncer()\nconst dragLabel = computed(() => treeProps.dragLabel ?? t('gr.tree.drag', 'Drag'))\nconst expandLabel = computed(() => treeProps.expandLabel ?? t('gr.tree.expand', 'Expand'))\nconst collapseLabel = computed(() => treeProps.collapseLabel ?? t('gr.tree.collapse', 'Collapse'))\nconst currentKey = treeStore.currentKey\nconst hoveredKey = interactionContext.hoveredKey\nconst dropTarget = interactionContext.dropTarget\n\n/**\n * Текущий узел: управляемый режим включает сам факт того, что проп задан.\n *\n * Иначе у одного понятия два владельца — подсветку рисует дерево по своему\n * ключу, а обёртка считает остальное по своему пропу; разойдись они на такт, и\n * строка подсвечена, а подпись не выделена. С `v-model:current-key` источник\n * правды один, и `nextTick` вокруг `setCurrentKey()` больше не нужен.\n */\nconst currentKeyControlled = computed(() => treeProps.currentKey !== undefined)\n\nwatch(() => treeProps.currentKey, (key) => {\n if (!currentKeyControlled.value)\n return\n if (treeStore.currentKey.value === (key ?? undefined))\n return\n\n treeStore.setCurrentKey(key ?? undefined)\n}, { immediate: true })\n\n/** Значение фильтра приходит пропом; метод `filter()` остаётся для императивных сценариев. */\nwatch(() => treeProps.filterValue, (value) => {\n if (value === undefined)\n return\n\n applyFilter(value)\n}, { immediate: true })\n\n// Корневой элемент дерева — область для делегированной клавиатуры (WAI-ARIA tree).\nconst treeRootEl = ref<HTMLElement | null>(null)\n\n/**\n * Видимые строки считает модель (`useTree`): в плоском DOM группы нет, и\n * структуру дерева диктору сообщают `aria-level`, `aria-posinset` и\n * `aria-setsize` — всё это приходит из неё готовым.\n */\nconst visibleRows = treeStore.visibleRows\n\n/**\n * Кольцо roving-фокуса: ровно один `treeitem` на всё дерево держит `tabindex=0`.\n *\n * Ориентация вертикальная намеренно: влево-вправо в дереве заняты раскрытием\n * ветки и переходом к родителю, и примитив их не трогает — это доменная логика,\n * она осталась в `onTreeKeydown`.\n */\nconst roving = useRovingFocus<GrTreeNode<T>['key']>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key),\n orientation: () => 'vertical',\n // У дерева есть верх и низ: с последней строки вниз идти некуда.\n wrap: () => false,\n // Но клавишу на краю всё равно гасим: иначе `ArrowDown` на последнем узле\n // прокрутит страницу под деревом.\n onOverflow: () => true,\n // Пока фокус не трогали, остановку держит текущий (выбранный) узел, а если\n // его не видно — первая видимая строка.\n initialKey: () => currentKey.value ?? undefined,\n beforeFocus: key => scrollRowIntoView(key),\n})\n\nfunction onRowClick(node: GrTreeNode<T>) {\n // В управляемом режиме дерево ведёт подсветку до ответа снаружи: строка\n // отзывается на клик сразу, а расхождение снимет наблюдатель за пропом.\n treeStore.setCurrentKey(node.key)\n emit('update:currentKey', node.key)\n roving.setActive(node.key)\n interactionContext.emitNodeClick(node.data, node)\n}\n\n// Клик мышью, в отличие от Enter, умеет ещё и раскрывать узел: `Enter` в\n// паттерне tree закреплён за выбором, и подмешивать в него раскрытие нельзя.\nfunction onRowActivate(row: GrTreeVisibleRow<T>) {\n onRowClick(row.node)\n\n if (treeProps.expandOnClickNode && !row.isLeaf)\n toggleExpand(row.node)\n}\n\nfunction onRowContextMenu(evt: MouseEvent, node: GrTreeNode<T>) {\n interactionContext.emitNodeContextMenu(evt, node.data, node)\n}\n\n// ————— Клавиатурная навигация по WAI-ARIA tree pattern (только корневой инстанс).\n\nfunction isRovingItem(key: GrTreeNode<T>['key']): boolean {\n return roving.rovingKey.value === key\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTree' })\n\n// Переменные ставим и вложенным уровням тоже: `v-bind=\"props\"` доносит до них\n// `size`, а значения одинаковые — наследование от корня не нарушается.\nconst sizeStyle = computed(() => treeSizeVars[resolvedSize.value])\n\n/**\n * Виртуализация: в DOM живёт только окно вокруг вьюпорта.\n *\n * Корень дерева и есть скроллер — обёрток-распорок между `role=\"tree\"` и\n * `role=\"treeitem\"` быть не должно, поэтому срезанное сверху и снизу держат\n * отступы самого корня.\n */\nconst TREE_ROW_GAP = 2\n\nconst rowEstimate = computed(() => Number.parseFloat(sizeStyle.value['--gr-tree-row-min-height']))\n\nconst virtualMaxHeight = computed(() => {\n const value = treeProps.maxHeight\n if (value == null)\n return undefined\n return typeof value === 'number' ? `${value}px` : value\n})\n\nconst virtualizer = useVirtualList({\n container: treeRootEl,\n count: () => (treeProps.virtual ? visibleRows.value.length : 0),\n // Раскрытие/фильтр сдвигают индексы строк — замеры прошлого набора невалидны.\n source: () => visibleRows.value,\n itemSize: () => rowEstimate.value,\n gap: TREE_ROW_GAP,\n // Первый рендер обязан совпасть с серверным: контейнера ещё нет, и окно\n // считается от объявленной высоты, а не от измеренной.\n viewportSize: () => (typeof treeProps.maxHeight === 'number' ? treeProps.maxHeight : undefined),\n})\n\n/** Строки к отрисовке: при выключенной виртуализации — все. */\nconst renderedRows = computed(() => {\n if (!treeProps.virtual)\n return visibleRows.value\n\n const { start, end } = virtualizer.range.value\n return visibleRows.value.slice(start, end)\n})\n\n/**\n * Срезанное сверху и снизу держат псевдоэлементы контейнера.\n *\n * Ни один из трёх напрашивающихся вариантов не годится:\n *\n * - `padding` контейнера — `max-height` меряет ту же коробку, и распорка в сто\n * тысяч пикселей либо раздувает скроллер до той же сотни тысяч, либо съедает\n * всю его высоту;\n * - обёртка-распорка внутри — между `role=\"tree\"` и `role=\"treeitem\"` не должно\n * быть посторонних узлов, роль потеряла бы обязательных потомков;\n * - отступы крайних отрисованных строк — распорка исчезает ровно в тот момент,\n * когда строки заменяются целиком (прыжок прокрутки), содержимое схлопывается\n * до высоты окна, и браузер обрезает `scrollTop` до почти нуля.\n *\n * `::before`/`::after` не узлы DOM: их не за что размонтировать, в дереве\n * доступности их нет, а высота приезжает переменными в том же патче, что и сами\n * строки, — схлопнуться между кадрами нечему.\n */\nconst rootStyle = computed(() => {\n if (!treeProps.virtual)\n return sizeStyle.value\n\n return {\n ...sizeStyle.value,\n overflow: 'auto',\n maxHeight: virtualMaxHeight.value,\n ...virtualizer.spacerStyle.value,\n }\n})\n\n/** Абсолютный индекс отрисованной строки: поиск по массиву стоил бы O(n) на строку. */\nfunction absoluteIndex(offsetInWindow: number): number {\n return treeProps.virtual ? virtualizer.range.value.start + offsetInWindow : offsetInWindow\n}\n\n/**\n * Строка размонтируется: снимаем регистрацию и, если фокус был на ней, уводим\n * его на корень — делегированный keydown живёт там, первая же стрелка вернёт\n * видимую строку через `focusRow`. Иначе фокус упал бы на `body` и клавиатура\n * дерева умерла бы до клика мышью.\n *\n * Спрашиваем сам элемент, а не `document.activeElement === body`: Vue обнуляет\n * function ref ДО удаления узла, поэтому в момент вызова фокус ещё на строке —\n * а «фокус на body» означает лишь то, что страницу никто не трогал.\n */\nlet isUnmounting = false\n\nfunction releaseNodeEl(key: GrTreeKey): void {\n const el = interactionContext.nodeEls.get(key)\n const active = typeof document === 'undefined' ? null : document.activeElement\n const heldFocus = Boolean(el && active && (el === active || el.contains(active)))\n\n interactionContext.registerNodeEl(key, null)\n\n if (heldFocus && !isUnmounting)\n treeRootEl.value?.focus({ preventScroll: true })\n}\n\n/**\n * При виртуализации узла вне окна в DOM нет: `nodeEls.get` вернул бы\n * `undefined`, а фокус уехал бы на `body` вместе с размонтированной строкой.\n * Поэтому сперва прокрутка, и только следующим тиком — фокус.\n */\nfunction scrollRowIntoView(key: GrTreeNode<T>['key']): Promise<void> {\n if (treeProps.virtual) {\n const index = visibleRows.value.findIndex(row => row.node.key === key)\n if (index >= 0)\n virtualizer.scrollToIndex(index)\n }\n\n return nextTick()\n}\n\nfunction focusRow(key: GrTreeNode<T>['key']): void {\n void roving.focusKey(key)\n}\n\n/**\n * Typeahead паттерна tree: печатные символы копятся в буфер и переводят фокус\n * на первый подходящий видимый узел, начиная со следующего за текущим.\n *\n * Поиск идёт по данным (`visibleRows`), а не по DOM: при виртуализации узла вне\n * окна в разметке нет, и поиск по тексту элементов находил бы только видимое.\n */\nconst typeahead = useTypeahead<GrTreeVisibleRow<T>>({\n items: () => visibleRows.value,\n textOf: row => row.node.label,\n // Без наведённого фокуса ищем с начала списка, а не от конца: `findIndex`\n // вернул бы `-1`, и первая строка выпала бы из обхода.\n currentIndex: rows => Math.max(0, rows.findIndex(row => row.node.key === roving.rovingKey.value)),\n onMatch: row => focusRow(row.node.key),\n})\n\n/** `*` — раскрыть всех соседей узла, на котором фокус (уровень целиком). */\nfunction expandSiblings(node: GrTreeNode<T>): void {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.childNodes.length === 0 || treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, true)\n interactionContext.emitNodeExpand(sibling.data, sibling)\n }\n}\n\nfunction onTreeKeydown(event: KeyboardEvent): void {\n // Делегированная клавиатура уважает интерактивные цели: печать в инпуте слота\n // узла — ввод текста, а не typeahead. Без гарда preventDefault отменял бы это.\n const target = event.target as HTMLElement | null\n const interactive = target?.closest<HTMLElement>('button, a[href], input, select, textarea, [contenteditable]')\n if (interactive && interactive !== event.currentTarget) {\n // Табируемая цель — самостоятельный таб-стоп: клавиатура целиком её.\n if (interactive.tabIndex >= 0)\n return\n\n // Кнопки строки (toggle, drag-handle) не табируемы: фокус попадает на них\n // только мышью. За ними остаётся активация — Enter на toggle это его клик, —\n // а навигация принадлежит дереву, иначе клик мышью убивал бы стрелки.\n if (event.key === 'Enter' || event.key === ' ')\n return\n }\n\n const rows = visibleRows.value\n if (rows.length === 0)\n return\n\n const idx = Math.max(0, rows.findIndex(r => r.node.key === roving.rovingKey.value))\n const cur = rows[idx]\n\n if (event.key === '*') {\n event.preventDefault()\n expandSiblings(cur.node)\n return\n }\n\n // Печатный символ без модификаторов — typeahead, а не команда.\n if (event.key.length === 1 && event.key !== ' ' && !event.ctrlKey && !event.metaKey && !event.altKey) {\n event.preventDefault()\n typeahead.type(event.key)\n return\n }\n\n // `Shift` со стрелкой двигает сам узел — раскладка аутлайнера. Проверяется\n // раньше навигации: иначе примитив увёл бы фокус вместо переноса.\n if (event.shiftKey && MOVE_KEYS.has(event.key)) {\n if (!treeProps.draggable)\n return\n\n event.preventDefault()\n void onNodeMoveKey(cur.node, event.key)\n return\n }\n\n // Вертикаль, `Home` и `End` ведёт примитив. Влево-вправо он не трогает: в\n // дереве это раскрытие ветки и переход к родителю, а не движение по списку.\n if (roving.handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'ArrowRight':\n event.preventDefault()\n if (!cur.isLeaf) {\n if (!cur.isExpanded)\n toggleExpand(cur.node)\n else if (idx < rows.length - 1)\n focusRow(rows[idx + 1].node.key)\n }\n break\n case 'ArrowLeft':\n event.preventDefault()\n if (!cur.isLeaf && cur.isExpanded)\n toggleExpand(cur.node)\n else if (cur.node.parent && rows.some(r => r.node.key === cur.node.parent!.key))\n focusRow(cur.node.parent.key)\n break\n case 'Enter':\n event.preventDefault()\n onRowClick(cur.node)\n break\n // Space при чекбоксах переключает отметку — это и есть выбор в\n // multi-select дереве; без них он остаётся вторым способом выбрать узел.\n case ' ':\n event.preventDefault()\n if (treeProps.showCheckbox)\n toggleChecked(cur.node)\n else\n onRowClick(cur.node)\n break\n }\n}\n\nfunction onRowMouseEnter(node: GrTreeNode<T>) {\n hoveredKey.value = node.key\n}\n\nfunction onRowMouseLeave(node: GrTreeNode<T>) {\n if (hoveredKey.value === node.key)\n hoveredKey.value = undefined\n}\n\nfunction collapseSiblings(node: GrTreeNode<T>) {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n\n for (const sibling of siblings) {\n if (sibling.key === node.key || !treeStore.isExpandedKey(sibling.key))\n continue\n\n treeStore.setExpandedKey(sibling.key, false)\n interactionContext.emitNodeCollapse(sibling.data, sibling)\n }\n}\n\nfunction toggleExpand(node: GrTreeNode<T>) {\n const expanded = !treeStore.isExpandedKey(node.key)\n\n if (expanded && treeProps.accordion)\n collapseSiblings(node)\n\n // Ленивая ветка грузится по первому раскрытию; повторное ничего не запрашивает.\n if (expanded)\n treeStore.ensureLoaded(node)\n\n treeStore.toggleExpand(node)\n\n if (expanded)\n interactionContext.emitNodeExpand(node.data, node)\n else\n interactionContext.emitNodeCollapse(node.data, node)\n}\n\n// ————— Отметки (чекбоксы).\n\nfunction checkStateOf(key: GrTreeKey): GrTreeCheckState {\n return treeStore.getCheckState(key)\n}\n\nfunction ariaCheckedOf(row: GrTreeVisibleRow<T>): 'true' | 'false' | 'mixed' | undefined {\n if (!treeProps.showCheckbox)\n return undefined\n\n const state = checkStateOf(row.node.key)\n return state === 'checked' ? 'true' : state === 'half' ? 'mixed' : 'false'\n}\n\nfunction emitCheck(node: GrTreeNode<T>): void {\n const checkedKeys = treeStore.getCheckedKeys()\n emit('update:checkedKeys', checkedKeys)\n emit('check', node.data, node, { checkedKeys, halfCheckedKeys: treeStore.getHalfCheckedKeys() })\n}\n\nfunction toggleChecked(node: GrTreeNode<T>): void {\n if (!treeProps.showCheckbox)\n return\n\n const changed = treeStore.toggleChecked(node)\n if (changed)\n emitCheck(changed)\n}\n\n// ————— Геометрия строки: отступ уровня и направляющие ветвей.\n\nfunction rowStyle(row: GrTreeVisibleRow<T>) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return { '--gr-tree-row-indent': `calc(${step} * ${row.node.level - 1})` }\n}\n\n/**\n * Направляющая уровня-предка. Считается от того же шага отступа, что и сам\n * отступ строки, — иначе линия и содержимое разъедутся на вложенных уровнях.\n */\n/**\n * Колено рисуется только у направляющей собственного уровня строки: остальные\n * — это транзит предков, и горизонтальная черта у них указывала бы на строку,\n * к которой они не относятся.\n *\n * У последнего ребёнка вертикаль обрывается на середине: продолжать её значит\n * обещать сиблинга, которого нет.\n */\n/**\n * Цвет направляющей уровня для модели. Объявление функцией, а не стрелкой на\n * месте вызова: `treeProps` определяются ниже, и ссылка на них в выражении\n * читалась бы до объявления.\n */\n/**\n * Обёртки над пропами для модели: объявлением, а не стрелкой на месте вызова —\n * `treeProps` определяются ниже. `undefined` от фильтра означает «решай сам»:\n * так обёртка возвращает модель к её подстрочному матчу, когда своего правила\n * потребитель не задал.\n */\nfunction filterNodeForModel(value: string, data: T, node: GrTreeNode<T>) {\n return treeProps.filterNodeMethod?.(value, data, node)\n}\n\nfunction loadForModel(node: GrTreeNode<T>, resolve: (children: T[]) => void) {\n treeProps.load?.(node, resolve)\n}\n\nfunction branchColorForNode(node: GrTreeNode<T>) {\n return treeProps.branchLine ? resolveBranchLineColor(node) : undefined\n}\n\nfunction branchGuideModifiers(row: GrTreeVisibleRow<T>, index: number) {\n if (treeProps.branchLine !== 'elbow' || index !== row.branchColors.length - 1)\n return undefined\n\n return row.posInSet === row.setSize\n ? 'gr-tree__branch-guide--elbow gr-tree__branch-guide--last'\n : 'gr-tree__branch-guide--elbow'\n}\n\nfunction branchGuideStyle(row: GrTreeVisibleRow<T>, index: number) {\n const step = treeProps.indent && treeProps.indent > 0\n ? `${treeProps.indent}px`\n : 'var(--gr-tree-indent-step)'\n\n return {\n 'left': `calc(${step} * ${index} + var(--gr-tree-branch-line-offset))`,\n '--gr-tree-branch-line-color': row.branchColors[index],\n }\n}\n\n// Drag & drop\nfunction canDrag(node: GrTreeNode<T>): boolean {\n return interactionContext.canDrag(node)\n}\n\n/**\n * Ручка «по наведению» на тач-устройстве недостижима: событий наведения там нет,\n * ключ не выставляется, класс видимости не появляется — то есть перетаскивания\n * нет вовсе, хотя `touch-action: none` у ручки стоит ровно ради него.\n *\n * Режим `auto` решает это без JS: класс-модификатор на корне, а показ включает\n * `@media (hover: none)` — так поведение остаётся верным и на сервере, где\n * никакого `matchMedia` спрашивать нельзя.\n */\nfunction shouldShowDragHandle(node: GrTreeNode<T>): boolean {\n if (!canDrag(node))\n return false\n\n return treeProps.dragHandleVisibility === 'always' || hoveredKey.value === node.key\n}\n\n/**\n * Треть строки сверху — «до», треть снизу — «после», середина — «внутрь».\n * Зоны нарезает компонент: примитив отдаёт только долю вдоль строки.\n */\nfunction dropTypeFromFraction(fraction: number): GrTreeNodeDropType {\n if (fraction < 1 / 3)\n return 'prev'\n if (fraction > 2 / 3)\n return 'next'\n\n return 'inner'\n}\n\nfunction canDrop(drag: GrTreeNode<T>, target: GrTreeNode<T>, type: GrTreeAllowDropType): boolean {\n return interactionContext.canDrop(drag, target, type)\n}\n\n/** Перенос состоялся: одна дорога и для указателя, и для клавиатуры. */\nfunction applyMove(source: GrTreeNode<T>, targetKey: GrTreeKey, type: GrTreeNodeDropType): boolean {\n const reference = treeStore.getNode(targetKey)\n if (!reference)\n return false\n\n const movedNode = treeStore.moveNode(source, reference, type)\n if (!movedNode)\n return false\n\n const dropNode = treeStore.getNode(reference.key) ?? reference\n interactionContext.emitNodeDrop(movedNode, dropNode, type)\n\n return true\n}\n\nconst dragSort = useDragSort<GrTreeKey, GrTreeDropTarget>({\n items: () => visibleRows.value.map(row => row.node.key),\n elementFor: key => interactionContext.nodeEls.get(key) ?? null,\n scroller: () => treeRootEl.value,\n disabled: () => !treeProps.draggable,\n canDrag: (key) => {\n const node = treeStore.getNode(key)\n\n return node ? canDrag(node) : false\n },\n resolveTarget: (hit, sourceKey, previous) => {\n const source = treeStore.getNode(sourceKey)\n const node = treeStore.getNode(hit.key)\n if (!source || !node)\n return null\n\n const type = dropTypeFromFraction(hit.fraction)\n const allowed = treeStore.canMoveNode(source, node, type) && canDrop(source, node, type)\n\n // Та же ссылка, пока смысл не изменился: иначе подсветка перерисовывалась бы\n // на каждом движении указателя.\n if (previous && previous.key === node.key && previous.type === type && previous.allowed === allowed)\n return previous\n\n return { key: node.key, type, allowed }\n },\n onDrop: (sourceKey, target) => {\n const source = treeStore.getNode(sourceKey)\n if (!source || !target.allowed)\n return\n\n applyMove(source, target.key, target.type)\n },\n onUpdate: (sourceKey, target) => {\n interactionContext.draggingNode.value = sourceKey === null ? null : treeStore.getNode(sourceKey) ?? null\n interactionContext.dropTarget.value = target\n },\n})\n\nfunction onHandlePointerDown(event: PointerEvent, node: GrTreeNode<T>): void {\n if (!treeProps.draggable)\n return\n\n dragSort.startFrom(node.key)(event)\n}\n\n/**\n * Клавиатурный перенос — раскладка аутлайнера: `Shift` со стрелкой сразу\n * двигает узел, без режима «взято». Режим здесь был бы лишним: `Space` в дереве\n * уже отмечает чекбокс, а стрелки водят фокус по веткам.\n */\nfunction moveByKeyboard(node: GrTreeNode<T>, key: string): boolean {\n const siblings = node.parent ? node.parent.childNodes : treeStore.treeModel.value.roots\n const index = siblings.findIndex(sibling => sibling.key === node.key)\n\n if (key === 'ArrowUp' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'prev')\n\n if (key === 'ArrowDown' && index >= 0 && index < siblings.length - 1)\n return applyMove(node, siblings[index + 1].key, 'next')\n\n // Вправо — в предыдущего соседа: у первого в уровне такого соседа нет.\n if (key === 'ArrowRight' && index > 0)\n return applyMove(node, siblings[index - 1].key, 'inner')\n\n if (key === 'ArrowLeft' && node.parent)\n return applyMove(node, node.parent.key, 'next')\n\n return false\n}\n\nasync function onNodeMoveKey(node: GrTreeNode<T>, key: string): Promise<void> {\n if (!treeProps.draggable || !canDrag(node))\n return\n if (!moveByKeyboard(node, key))\n return\n\n announce(t('gr.tree.moved', 'Moved {label}', { label: node.label }))\n\n // Перестановка перерисовывает уровень: без возврата фокуса следующий Shift\n // уже некуда было бы адресовать.\n await nextTick()\n focusRow(node.key)\n}\n\n/**\n * Фильтрация и отчёт о её результате.\n *\n * Счёт снимается после пересчёта видимых строк: `visibleCount` — то, что\n * пользователь реально видит, а `matchedCount` — сколько узлов совпало само,\n * без учёта родителей, раскрытых ради показа совпадения.\n */\nasync function applyFilter(value: string) {\n treeStore.filter(value)\n await nextTick()\n\n emit('filter', {\n value,\n visibleCount: visibleRows.value.length,\n matchedCount: treeStore.filterInfo.value.matchedKeys.size,\n })\n}\n\nfunction filter(value: string) {\n void applyFilter(value)\n}\n\nfunction resolveNodeClass(classValue: GrTreeNodeClass<T> | undefined, row: GrTreeVisibleRow<T>) {\n if (!classValue)\n return undefined\n\n return typeof classValue === 'function'\n ? classValue(row)\n : classValue\n}\n\nfunction resolveBranchLineColorValue(color: GrTreeBranchLineColor<T> | undefined, node: GrTreeNode<T>) {\n if (!color)\n return undefined\n\n return typeof color === 'function'\n ? color(node) ?? undefined\n : color\n}\n\nfunction isBranchLineActive(node: GrTreeNode<T>) {\n const selectedKey = currentKey.value\n\n if (selectedKey == null)\n return false\n\n if (node.key === selectedKey)\n return true\n\n return node.childNodes.some(child => child.key === selectedKey && !treeStore.isExpandedKey(child.key))\n}\n\nfunction resolveBranchLineColor(node: GrTreeNode<T>) {\n const defaultColor = resolveBranchLineColorValue(treeProps.branchLineColor, node) ?? DEFAULT_BRANCH_LINE_COLOR\n\n if (!isBranchLineActive(node))\n return defaultColor\n\n return resolveBranchLineColorValue(treeProps.branchLineActiveColor, node) ?? defaultColor\n}\n\n/**\n * Переводит фокус на узел (по умолчанию — на тот, что держит roving tabindex).\n * Нужен снаружи: `GrTreeSelect` открывает панель и обязан отдать клавиатуру\n * дереву, иначе стрелки из триггера никуда не ведут.\n */\nfunction focus(key?: GrTreeKey): boolean {\n const rows = visibleRows.value\n if (rows.length === 0)\n return false\n\n const target = key != null && rows.some(row => row.node.key === key)\n ? key\n : roving.rovingKey.value ?? rows[0].node.key\n\n focusRow(target)\n return true\n}\n\n// Дерево уничтожают целиком — строки размонтируются вместе с ним, и возвращать\n// фокус на умирающий корень нельзя: он уедет из документа вместе с деревом.\nonBeforeUnmount(() => {\n isUnmounting = true\n})\n\ndefineExpose<GrTreeInstance<T>>({\n appendNode: treeStore.appendNode,\n getCheckedKeys: options => treeStore.getCheckedKeys(options),\n setCheckedKeys: (keys) => {\n treeStore.setCheckedKeys(keys)\n emit('update:checkedKeys', treeStore.getCheckedKeys())\n },\n getHalfCheckedKeys: treeStore.getHalfCheckedKeys,\n setChecked: (node, checked) => {\n const changed = treeStore.setChecked(node, checked)\n if (changed)\n emitCheck(changed)\n return Boolean(changed)\n },\n filter,\n focus,\n getCurrentNode: treeStore.getCurrentNode,\n setCurrentKey: treeStore.setCurrentKey,\n getCurrentKey: treeStore.getCurrentKey,\n getNode: treeStore.getNode,\n insertNodeAfter: treeStore.insertNodeAfter,\n insertNodeBefore: treeStore.insertNodeBefore,\n removeNode: treeStore.removeNode,\n setCurrentNode: treeStore.setCurrentNode,\n})\n</script>\n\n<template>\n <div\n ref=\"treeRootEl\"\n data-gr-tree\n class=\"gr-tree\"\n :class=\"treeProps.dragHandleVisibility === 'auto' ? 'gr-tree--drag-handle-auto' : ''\"\n tabindex=\"-1\"\n :data-gr-virtual=\"treeProps.virtual ? '' : undefined\"\n role=\"tree\"\n :aria-multiselectable=\"treeProps.showCheckbox ? 'true' : undefined\"\n :style=\"rootStyle\"\n @keydown=\"onTreeKeydown\"\n >\n <div\n v-for=\"(row, windowIndex) in renderedRows\"\n :key=\"row.node.key\"\n :ref=\"(el) => {\n if (el) interactionContext.registerNodeEl(row.node.key, el as HTMLElement)\n else releaseNodeEl(row.node.key)\n if (treeProps.virtual) virtualizer.measure(absoluteIndex(windowIndex), el as Element | null)\n }\"\n data-gr-tree-node\n :data-gr-tree-node-key=\"row.node.key\"\n role=\"treeitem\"\n :aria-level=\"row.node.level\"\n :aria-posinset=\"row.posInSet\"\n :aria-setsize=\"row.setSize\"\n :aria-expanded=\"row.isLeaf ? undefined : row.isExpanded\"\n :aria-selected=\"currentKey === row.node.key ? 'true' : undefined\"\n :aria-checked=\"ariaCheckedOf(row)\"\n :aria-busy=\"row.isLoading ? 'true' : undefined\"\n :tabindex=\"isRovingItem(row.node.key) ? 0 : -1\"\n >\n <div\n data-gr-tree-row\n class=\"gr-tree__row\"\n :class=\"[\n treeProps.highlightCurrent && currentKey === row.node.key ? 'gr-tree__row--current' : '',\n row.isLeaf ? 'gr-tree__row--leaf' : '',\n row.isMatched ? 'gr-tree__row--matched' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'inner' ? 'gr-tree__row--drop-inner' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'prev' ? 'gr-tree__row--drop-prev' : '',\n dropTarget?.key === row.node.key && dropTarget.allowed && dropTarget.type === 'next' ? 'gr-tree__row--drop-next' : '',\n resolveNodeClass(treeProps.rowClass, row),\n ]\"\n :style=\"rowStyle(row)\"\n @click=\"onRowActivate(row)\"\n @contextmenu=\"onRowContextMenu($event, row.node)\"\n @drop.prevent\n @mouseenter=\"onRowMouseEnter(row.node)\"\n @mouseleave=\"onRowMouseLeave(row.node)\"\n >\n <!--\n Направляющие ветвей: по одной на каждый уровень предка. Вложенной\n обёртки с `border-left` больше нет, поэтому линию рисует сама строка —\n и заходит в зазор между строками, иначе она распалась бы на штрихи.\n -->\n <span\n v-for=\"(color, guideIndex) in row.branchColors\"\n :key=\"guideIndex\"\n data-gr-tree-branch-guide\n class=\"gr-tree__branch-guide\"\n :class=\"branchGuideModifiers(row, guideIndex)\"\n :style=\"branchGuideStyle(row, guideIndex)\"\n aria-hidden=\"true\"\n />\n\n <button\n v-if=\"treeProps.draggable\"\n type=\"button\"\n tabindex=\"-1\"\n data-gr-tree-drag-handle\n class=\"gr-tree__drag-handle\"\n :class=\"[\n shouldShowDragHandle(row.node) ? 'gr-tree__drag-handle--visible' : '',\n canDrag(row.node) ? '' : 'gr-tree__drag-handle--disabled',\n resolveNodeClass(treeProps.dragHandleClass, row),\n ]\"\n :aria-label=\"dragLabel\"\n :aria-disabled=\"canDrag(row.node) ? undefined : 'true'\"\n @click.stop\n @pointerdown=\"onHandlePointerDown($event, row.node)\"\n >\n <component\n :is=\"iconTag(treeProps.dragHandleIcon, IconGripVertical)\"\n class=\"gr-tree__drag-icon\"\n :class=\"iconClass(treeProps.dragHandleIcon)\"\n />\n </button>\n\n <!-- tabindex=\"-1\": внутри roving-композита интерактив не табируется,\n клавиатурный эквивалент — ArrowRight/ArrowLeft на строке. -->\n <button\n v-if=\"!row.isLeaf\"\n data-gr-tree-toggle\n type=\"button\"\n tabindex=\"-1\"\n class=\"gr-tree__toggle\"\n :class=\"resolveNodeClass(treeProps.toggleClass, row)\"\n :aria-label=\"row.isExpanded ? collapseLabel : expandLabel\"\n @click.stop=\"toggleExpand(row.node)\"\n >\n <IconLoaderCircle\n v-if=\"row.isLoading\"\n data-gr-tree-loading\n class=\"gr-tree__toggle-icon animate-spin\"\n />\n <component\n :is=\"iconTag(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon, IconChevronRight)\"\n v-else\n class=\"gr-tree__toggle-icon\"\n :class=\"[\n iconClass(row.isExpanded ? treeProps.collapseIcon : treeProps.expandIcon),\n row.isExpanded && treeProps.toggleIconRotate ? 'gr-tree__toggle-icon--expanded' : '',\n resolveNodeClass(treeProps.toggleIconClass, row),\n ]\"\n />\n </button>\n <span\n v-else\n class=\"gr-tree__toggle-spacer\"\n :class=\"resolveNodeClass(treeProps.toggleSpacerClass, row)\"\n />\n\n <!--\n Квадратик отметки декоративен: состояние живёт на самом `treeitem`\n (`aria-checked`), а вложить интерактивный чекбокс внутрь роли-виджета\n нельзя — роль объявляет потомков презентационными.\n -->\n <span\n v-if=\"treeProps.showCheckbox\"\n data-gr-tree-checkbox\n class=\"gr-tree__checkbox\"\n :class=\"[\n checkStateOf(row.node.key) === 'checked' ? 'gr-tree__checkbox--checked' : '',\n checkStateOf(row.node.key) === 'half' ? 'gr-tree__checkbox--half' : '',\n ]\"\n aria-hidden=\"true\"\n @click.stop=\"toggleChecked(row.node)\"\n >\n <component\n :is=\"checkStateOf(row.node.key) === 'half' ? IconMinus : IconCheck\"\n v-if=\"checkStateOf(row.node.key) !== 'unchecked'\"\n class=\"gr-tree__checkbox-mark\"\n />\n </span>\n\n <div class=\"gr-tree__content\" :class=\"resolveNodeClass(treeProps.contentClass, row)\">\n <slot\n :node=\"row.node\"\n :data=\"row.node.data\"\n >\n <span class=\"gr-tree__label\">{{ row.node.label }}</span>\n </slot>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style scoped>\n.gr-tree {\n --gr-tree-gap: 2px;\n --gr-tree-children-pl: 10px;\n --gr-tree-row-min-height: 28px;\n --gr-tree-row-radius: 8px;\n --gr-tree-row-px: 8px;\n --gr-tree-row-py: 8px;\n --gr-tree-row-pr: var(--gr-tree-row-px);\n --gr-tree-font-size: inherit;\n --gr-tree-row-color: var(--gr-fg);\n --gr-tree-row-hover-bg: color-mix(in srgb, var(--gr-primary) 10%, transparent);\n --gr-tree-row-current-bg: color-mix(in srgb, var(--gr-primary) 14%, transparent);\n --gr-tree-row-current-hover-bg: color-mix(in srgb, var(--gr-primary) 16%, transparent);\n --gr-tree-drag-handle-size: 24px;\n --gr-tree-drag-handle-mr: 0;\n --gr-tree-drag-handle-radius: 6px;\n --gr-tree-drag-handle-color: inherit;\n --gr-tree-drag-handle-opacity: 0.55;\n --gr-tree-drag-handle-hover-bg: color-mix(in srgb, var(--gr-muted) 22%, transparent);\n --gr-tree-drag-handle-hover-color: var(--gr-tree-drag-handle-color);\n --gr-tree-drag-handle-hover-opacity: 0.9;\n --gr-tree-drag-handle-disabled-opacity: 0.25;\n --gr-tree-toggle-size: 24px;\n --gr-tree-toggle-mr: 0;\n --gr-tree-toggle-radius: 6px;\n --gr-tree-toggle-color: inherit;\n --gr-tree-toggle-hover-bg: color-mix(in srgb, var(--gr-muted) 25%, transparent);\n --gr-tree-toggle-hover-color: var(--gr-tree-toggle-color);\n --gr-tree-icon-size: 16px;\n --gr-tree-content-gap: 8px;\n --gr-tree-branch-line-default-color: var(--gr-tree-row-current-bg);\n --gr-tree-branch-line-width: 2px;\n /* Шаг отступа уровня: переключатель, отступ вложенного списка и толщина\n направляющей — линия обязана попадать между ними. */\n --gr-tree-indent-step: calc(12px + var(--gr-tree-children-pl) + var(--gr-tree-branch-line-width));\n --gr-tree-row-current-color: var(--gr-tree-row-color);\n --gr-tree-row-current-bar-width: 0px;\n --gr-tree-row-current-bar-color: var(--gr-primary);\n --gr-tree-branch-font-weight: 600;\n --gr-tree-branch-elbow-width: 8px;\n --gr-tree-branch-line-offset: 12px;\n --gr-tree-checkbox-size: 16px;\n --gr-tree-checkbox-radius: 4px;\n --gr-tree-checkbox-brd-width: 1px;\n --gr-tree-checkbox-brd: var(--gr-brd);\n --gr-tree-checkbox-bg: transparent;\n --gr-tree-checkbox-checked-bg: var(--gr-primary);\n --gr-tree-checkbox-checked-fg: var(--gr-primary-fg);\n --gr-tree-checkbox-mr: 4px;\n display: flex;\n flex-direction: column;\n gap: var(--gr-tree-gap);\n /* Кегль и цвет объявлены на дереве, а строка их наследует. На строке они\n были бы объявлением, и класс из `rowClass` — при равном весе и более\n раннем подключении — молча проигрывал бы: ступени кегля по уровням у\n оглавления не применялись вовсе. Наследование уступает любому классу\n потребителя, а модификаторы строки (`--current`) остаются выше. */\n font-size: var(--gr-tree-font-size);\n color: var(--gr-tree-row-color);\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\n.gr-tree__row {\n position: relative;\n display: flex;\n align-items: center;\n min-height: var(--gr-tree-row-min-height);\n padding: var(--gr-tree-row-py) var(--gr-tree-row-pr) var(--gr-tree-row-py)\n calc(var(--gr-tree-row-px) + var(--gr-tree-row-indent, 0px));\n cursor: default;\n user-select: none;\n outline: none;\n isolation: isolate;\n}\n\n/* Поверхность строки — отдельный слой, вставленный слева на отступ уровня.\n Фон на самой коробке шёл от левого края дерева и накрывал направляющие\n предков: линия ветки исчезала под подсветкой ровно там, где она и нужна.\n Слой лежит ниже направляющих (они — следующие элементы строки), поэтому\n линия остаётся видна при любом наложении.\n\n `z-index: -1` уводит слой под содержимое строки. Без него позиционированный\n `::before` красится ПОВЕРХ потоковых подписи, шеврона и отметки — при\n полупрозрачном фоне это лишь лёгкое затенение, а при непрозрачном значении\n публичного токена содержимое исчезает целиком. Поднимать вместо этого\n содержимое пришлось бы у каждого элемента строки и у каждого нового.\n\n `isolation` на самой строке обязателен в паре: без своего контекста\n наложения отрицательный слой уезжает за фон ближайшего предка с заливкой, и\n подсветка пропадает на карточке. */\n.gr-tree__row::before {\n content: '';\n position: absolute;\n inset: 0 0 0 var(--gr-tree-row-indent, 0px);\n border-radius: var(--gr-tree-row-radius);\n pointer-events: none;\n z-index: -1;\n}\n\n.gr-tree__row:hover::before {\n background: var(--gr-tree-row-hover-bg);\n}\n\n/* Направляющая тянется в зазор между строками: иначе линия ветки распалась бы\n на штрихи по числу строк. */\n/* Колено: горизонтальная черта от направляющей к строке. Цвет берётся\n `inherit`, потому что сама направляющая красится инлайновой переменной —\n повторять её резолв в псевдоэлементе значило бы завести второй источник. */\n.gr-tree__branch-guide--elbow::after {\n content: '';\n position: absolute;\n left: 0;\n top: 50%;\n width: var(--gr-tree-branch-elbow-width);\n height: var(--gr-tree-branch-line-width);\n background-color: inherit;\n transform: translateY(-50%);\n}\n\n.gr-tree__branch-guide--last {\n bottom: 50%;\n}\n\n.gr-tree__branch-guide {\n position: absolute;\n top: calc(var(--gr-tree-gap) / -2);\n bottom: calc(var(--gr-tree-gap) / -2);\n width: var(--gr-tree-branch-line-width);\n background: var(--gr-tree-branch-line-color, var(--gr-tree-branch-line-default-color));\n pointer-events: none;\n}\n\n.gr-tree__checkbox {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--gr-tree-checkbox-size);\n height: var(--gr-tree-checkbox-size);\n margin-right: var(--gr-tree-checkbox-mr);\n border: var(--gr-tree-checkbox-brd-width) solid var(--gr-tree-checkbox-brd);\n border-radius: var(--gr-tree-checkbox-radius);\n background: var(--gr-tree-checkbox-bg);\n color: var(--gr-tree-checkbox-checked-fg);\n cursor: pointer;\n}\n\n.gr-tree__checkbox--checked,\n.gr-tree__checkbox--half {\n border-color: var(--gr-tree-checkbox-checked-bg);\n background: var(--gr-tree-checkbox-checked-bg);\n}\n\n.gr-tree__checkbox-mark {\n width: calc(var(--gr-tree-checkbox-size) - 4px);\n height: calc(var(--gr-tree-checkbox-size) - 4px);\n}\n\n[data-gr-tree-node] {\n outline: none;\n}\n\n/* Кольцо фокуса — на той же поверхности, что подсветка: иначе строка читалась бы\n двумя разными прямоугольниками. `outline` для этого не годится — он рисуется по\n границе коробки, а не по инсету. */\n[data-gr-tree-node]:focus-visible > .gr-tree__row::before {\n box-shadow: inset 0 0 0 2px var(--gr-primary);\n}\n\n.gr-tree__row--current {\n color: var(--gr-tree-row-current-color);\n}\n\n.gr-tree__row--current::before {\n background: var(--gr-tree-row-current-bg);\n}\n\n.gr-tree__row--current:hover::before {\n background: var(--gr-tree-row-current-hover-bg);\n}\n\n.gr-tree__row--matched .gr-tree__label {\n font-weight: 600;\n}\n\n/* Ветка набирается плотнее листа: без этого «Операции» и «Эскалации» выглядят\n одним и тем же, и различает их только шеврон, которого у листа нет. Вид, где\n вес несёт уровень, а не ветвистость (оглавление), гасит это токеном. */\n.gr-tree__row:not(.gr-tree__row--leaf) .gr-tree__label {\n font-weight: var(--gr-tree-branch-font-weight);\n}\n\n/* Полоса у текущей строки рисуется на самой строке, а не на подсветке:\n подсветка отступает на отступ уровня, а полоса обязана стоять у края\n списка — иначе она уезжает вправо вместе с вложенностью и перестаёт\n собирать выбранные строки разных уровней в один вертикальный ряд. */\n.gr-tree__row--current {\n box-shadow: inset var(--gr-tree-row-current-bar-width) 0 0 0 var(--gr-tree-row-current-bar-color);\n}\n\n.gr-tree__drag-handle {\n width: var(--gr-tree-drag-handle-size);\n height: var(--gr-tree-drag-handle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-drag-handle-mr);\n border-radius: var(--gr-tree-drag-handle-radius);\n color: var(--gr-tree-drag-handle-color);\n cursor: grab;\n /* Без этого вертикальный свайп по ручке уходит в прокрутку страницы,\n браузер отзывает указатель, и пальцем узел неперетаскиваем. */\n touch-action: none;\n visibility: hidden;\n pointer-events: none;\n opacity: 0;\n}\n\n/* Где наведения не бывает, ручка «по наведению» недостижима — то есть\n перетаскивания нет вовсе. Медиазапрос, а не `matchMedia`: ответ нужен и на\n сервере, а спрашивать среду в первом рендере нельзя. */\n@media (hover: none) {\n .gr-tree--drag-handle-auto .gr-tree__drag-handle {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n }\n}\n\n.gr-tree__drag-handle--visible {\n visibility: visible;\n pointer-events: auto;\n opacity: var(--gr-tree-drag-handle-opacity);\n}\n\n.gr-tree__drag-handle:hover {\n background: var(--gr-tree-drag-handle-hover-bg);\n color: var(--gr-tree-drag-handle-hover-color);\n opacity: var(--gr-tree-drag-handle-hover-opacity);\n}\n\n.gr-tree__drag-handle:active {\n cursor: grabbing;\n}\n\n.gr-tree__drag-handle--disabled {\n cursor: default;\n opacity: var(--gr-tree-drag-handle-disabled-opacity);\n}\n\n.gr-tree__drag-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n}\n\n.gr-tree__toggle {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: var(--gr-tree-toggle-mr);\n border-radius: var(--gr-tree-toggle-radius);\n color: var(--gr-tree-toggle-color);\n}\n\n.gr-tree__toggle:hover {\n background: var(--gr-tree-toggle-hover-bg);\n color: var(--gr-tree-toggle-hover-color);\n}\n\n.gr-tree__toggle-icon {\n width: var(--gr-tree-icon-size);\n height: var(--gr-tree-icon-size);\n transition: transform var(--gr-duration-fast) var(--gr-ease-out);\n}\n\n.gr-tree__toggle-icon--expanded {\n transform: rotate(90deg);\n}\n\n.gr-tree__toggle-spacer {\n width: var(--gr-tree-toggle-size);\n height: var(--gr-tree-toggle-size);\n margin-right: var(--gr-tree-toggle-mr);\n display: inline-block;\n}\n\n/* Растёт на всю свободную ширину строки: без этого слот сжат по содержимому, и\n хвост строки — счётчик, метка, значок статуса — невозможно прижать вправо\n ничем, кроме внешней ширины, которой у слота нет. Фон и подсветка лежат на\n строке, поэтому у разметки без хвоста рост ничего не меняет. */\n.gr-tree__content {\n flex: 1;\n min-width: 0;\n display: flex;\n align-items: center;\n gap: var(--gr-tree-content-gap);\n}\n\n.gr-tree__label {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.gr-tree__row--drop-inner {\n outline: 2px solid color-mix(in srgb, var(--gr-primary) 40%, transparent);\n}\n\n.gr-tree__row--drop-prev::before,\n.gr-tree__row--drop-next::after {\n content: '';\n position: absolute;\n left: 8px;\n right: 8px;\n height: 2px;\n background: color-mix(in srgb, var(--gr-primary) 55%, transparent);\n}\n\n.gr-tree__row--drop-prev::before {\n top: 2px;\n}\n\n.gr-tree__row--drop-next::after {\n bottom: 2px;\n}\n</style>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrTreeSelect-B6KoDYiZ.js","names":["$slots"],"sources":["../../../../src/components/GrTreeSelect/GrTreeSelect.vue","../../../../src/components/GrTreeSelect/GrTreeSelect.vue"],"sourcesContent":["<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, nextTick, ref, useId, useSlots, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useGrComponentSize, useGrThemeAttrs } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport {\n controlSignalState,\n controlStateFallbackText,\n controlStateIconClass,\n controlStateIconColors,\n controlStateTextKey,\n} from '../shared/controlState'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrTree, {\n type GrTreeInstance,\n type GrTreeKey,\n type GrTreeNode,\n} from '../GrTree'\nimport type { GrInputSize } from '../GrInput/GrInput.vue'\nimport { panelPopTransition } from '../shared/overlayTransition'\nimport type { GrTreeSelectModelValue, GrTreeSelectProps } from './grTreeSelectTypes'\nimport { grTreeSelectClass, grTreeSelectPanelClass, grTreeSelectStateClass, paddingX, trailingZoneWidth } from './grTreeSelectStyles'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronDown from '~icons/lucide/chevron-down'\nimport IconCheckCircle from '~icons/lucide/check-circle'\nimport IconAlertTriangle from '~icons/lucide/alert-triangle'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconX from '~icons/lucide/x'\n\nexport interface GrTreeSelectEmits<T extends Record<string, any> = any> {\n (e: 'update:modelValue', value: GrTreeSelectModelValue): void\n (e: 'change', value: GrTreeSelectModelValue): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n (e: 'clear'): void\n (e: 'nodeClick', data: T, node: GrTreeNode<T>): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrTreeSelectProps<T>>(),\n {\n props: () => ({\n children: 'children',\n label: 'label',\n }),\n nodeKey: 'id' as any,\n defaultExpandedKeys: () => [],\n disabled: false,\n placeholder: undefined,\n size: undefined,\n loading: false,\n invalid: false,\n readonly: false,\n required: false,\n ariaLabel: undefined,\n state: 'default',\n multiple: false,\n showCheckbox: false,\n checkStrictly: false,\n clearable: false,\n open: undefined,\n name: undefined,\n valueDisplay: 'label',\n filterable: false,\n filterPlaceholder: undefined,\n filterInputmode: undefined,\n filterNodeMethod: undefined,\n closeOnSelect: undefined,\n dropdownMaxHeight: 320,\n virtual: false,\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n prefixFixed: false,\n suffixFixed: false,\n },\n)\n\nconst { t } = useGranularityTranslations()\n\nconst emit = defineEmits<GrTreeSelectEmits<T>>()\n\ndefineSlots<{\n /** Рендер значения внутри триггера (вместо дефолтного текста). */\n value?: (props: { value: GrTreeSelectModelValue, labels: string[], displayValue: string, pathLabels?: string[] }) => any\n /** Рендер строки дерева. */\n node?: (props: { node: GrTreeNode<T>, data: T, selected: boolean }) => any\n /** Содержимое пустого состояния (когда нет данных). */\n empty?: () => any\n /** Содержимое панели, пока данные едут. */\n loading?: () => any\n /** Аддон слева от значения: иконка, код валюты, метка. */\n prefix?: () => any\n /** Аддон справа от значения, перед крестиком и шевроном. */\n suffix?: () => any\n}>()\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst triggerEl = ref<HTMLInputElement | null>(null)\nconst treeId = `gr-tree-select-tree-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst stateTextId = useId()\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\n/**\n * Небуквенный признак состояния: иконка для глаз, скрытая подпись для\n * скринридера. Разбор — `shared/controlState`. Встаёт левее крестика и\n * шеврона: правый край триггера занят одним из них всегда.\n */\nconst signalState = computed(() => controlSignalState(props.state, isInvalid.value))\nconst stateIcon = computed(() => (signalState.value === 'success' ? IconCheckCircle : IconAlertTriangle))\nconst stateIconClass = computed(() => (signalState.value\n ? `${controlStateIconClass} ${controlStateIconColors[signalState.value]}`\n : ''))\nconst stateText = computed(() => (signalState.value\n ? t(controlStateTextKey[signalState.value], controlStateFallbackText[signalState.value])\n : ''))\n\nconst describedBy = computed(() =>\n [field?.describedById.value, signalState.value ? stateTextId : undefined]\n .filter(Boolean)\n .join(' ') || undefined,\n)\n\nfunction focus(): void {\n triggerEl.value?.focus()\n}\n\nfunction blur(): void {\n triggerEl.value?.blur()\n}\n\ndefineExpose({ focus, blur })\nconst filterInputRef = ref<InstanceType<typeof GrInput> | null>(null)\nconst treeRef = ref<GrTreeInstance | null>(null)\nconst panelEl = 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})\n\nconst clickOutsideExclude = [() => panelEl.value]\n\nlet hadPointerDownOnTrigger = false\n\n// Имя `open` сохранено: читатели работают с computed-Ref.\nconst { open, setOpen: setOpenState } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\nconst filterValue = ref('')\n\nconst { floatingStyle } = useFloating(rootEl, panelEl, open, {\n placement: 'bottom-start',\n matchWidth: true,\n zIndexVar: '--gr-z-dropdown',\n})\n\nconst closeOnSelectResolved = computed(() => {\n return props.closeOnSelect ?? !props.multiple\n})\n\nfunction getChildrenKey() {\n return props.props.children ?? 'children'\n}\n\nfunction getLabelKey() {\n return props.props.label ?? 'label'\n}\n\nfunction nodeLabel(data: T): string {\n const key = getLabelKey() as keyof T\n const v = data[key]\n return v == null ? '' : String(v)\n}\n\nfunction nodeChildren(data: T): T[] {\n const key = getChildrenKey() as keyof T\n const v = data[key]\n return Array.isArray(v) ? (v as any) : []\n}\n\nfunction nodeKeyOf(data: T, index: number, parentKey: GrTreeKey | undefined): GrTreeKey {\n const keyName = props.nodeKey as keyof T\n const v = data[keyName]\n if (v != null)\n return v as GrTreeKey\n\n return parentKey == null ? index : `${String(parentKey)}:${index}`\n}\n\nconst labelByKey = computed(() => {\n const map = new Map<GrTreeKey, string>()\n\n const walk = (items: T[], parentKey: GrTreeKey | undefined) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const key = nodeKeyOf(item, i, parentKey)\n map.set(key, nodeLabel(item))\n walk(nodeChildren(item), key)\n }\n }\n\n walk(props.data ?? [], undefined)\n return map\n})\n\nconst pathLabelsByKey = computed(() => {\n const map = new Map<GrTreeKey, string[]>()\n\n const walk = (items: T[], parentKey: GrTreeKey | undefined, parentPath: string[]) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const key = nodeKeyOf(item, i, parentKey)\n const label = nodeLabel(item)\n const path = [...parentPath, label]\n map.set(key, path)\n walk(nodeChildren(item), key, path)\n }\n }\n\n walk(props.data ?? [], undefined, [])\n return map\n})\n\nconst selectedKeys = computed<GrTreeKey[]>(() => {\n if (props.multiple) {\n return Array.isArray(props.modelValue) ? props.modelValue : []\n }\n\n const v = props.modelValue\n if (v == null || Array.isArray(v))\n return []\n return [v]\n})\n\nconst selectedKeySet = computed(() => new Set(selectedKeys.value))\n\nconst selectedLabels = computed(() => {\n const map = labelByKey.value\n return selectedKeys.value.map(k => map.get(k) ?? String(k))\n})\n\nconst selectedPathLabels = computed<string[] | undefined>(() => {\n if (props.multiple)\n return undefined\n\n const key = selectedKeys.value[0]\n if (key == null)\n return undefined\n\n const path = pathLabelsByKey.value.get(key)\n if (path?.length)\n return path\n\n const labels = selectedLabels.value\n return labels.length ? [labels[0]] : undefined\n})\n\nconst displayValue = computed(() => {\n const labels = selectedLabels.value\n if (labels.length === 0)\n return ''\n\n if (!props.multiple) {\n if (props.valueDisplay === 'path') {\n const path = selectedPathLabels.value\n if (path?.length)\n return path.join(' / ')\n }\n return labels[0]\n }\n\n if (labels.length === 1)\n return labels[0]\n return `${labels[0]} +${labels.length - 1}`\n})\n\nconst hasSelection = computed(() => selectedKeys.value.length > 0)\n\n/** Дерево рендерится только когда есть что показать — ссылаться иначе не на что. */\nconst hasTree = computed(() => !props.loading && (props.data?.length ?? 0) > 0)\n\nconst resolvedFilterPlaceholder = computed(() => {\n return props.filterPlaceholder ?? t('gr.treeSelect.filterPlaceholder', 'Search…')\n})\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTreeSelect' })\n\nconst className = computed(() => {\n return grTreeSelectClass({\n size: resolvedSize.value,\n state: props.state,\n invalid: isInvalid.value,\n disabled: isDisabled.value,\n })\n})\n\nconst panelClasses = computed(() => {\n return grTreeSelectPanelClass\n})\n\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrInputSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\nconst slots = useSlots()\n\nconst {\n hasPrefix,\n hasSuffix,\n prefixEl,\n suffixEl,\n prefixStyle,\n suffixStyle,\n fieldPadding: triggerStyle,\n} = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => paddingX[resolvedSize.value],\n // Место под крестик и шеврон уже отдано классом `pr-9`, но инлайн-паддинг\n // перекрывает класс целиком — с суффиксом эту зону приходится вернуть числом.\n trailingReserve: () => (slots.suffix ? trailingZoneWidth : '0px'),\n})\n\n// Слот `value` рисуется поверх поля и обязан жить в тех же границах, что и\n// текст под ним. Без аддонов границы задаёт класс — стиль остаётся пустым.\nconst valueOverlayStyle = computed(() => ({\n left: hasPrefix.value ? triggerStyle.value.paddingLeft : undefined,\n right: hasSuffix.value ? triggerStyle.value.paddingRight : undefined,\n}))\n\nfunction setOpen(next: boolean) {\n if (isDisabled.value || isReadonly.value)\n return\n\n setOpenState(next)\n}\n\nfunction onClickOutside(): void {\n setOpen(false)\n}\n\nfunction openDropdown(): void {\n setOpen(true)\n}\n\n/**\n * Стек слоёв возвращает фокус на триггер сразу после закрытия, а у триггера\n * открытие висит на `focus`. Без флага `Escape` из дерева закрывал бы панель и\n * тем же движением открывал её заново.\n */\nlet suppressFocusOpen = false\n\nfunction closeDropdown(): void {\n suppressFocusOpen = true\n setOpen(false)\n setTimeout(() => {\n suppressFocusOpen = false\n }, 0)\n}\n\nfunction toggleDropdown(): void {\n setOpen(!open.value)\n}\n\n// Клик по триггеру сам переключает панель через `@click`; флаг гасит открытие\n// по приходящему следом `focus`, иначе один клик открыл бы и тут же закрыл.\nfunction onTriggerPointerDown(): void {\n hadPointerDownOnTrigger = true\n setTimeout(() => {\n hadPointerDownOnTrigger = false\n }, 0)\n}\n\nfunction onTriggerFocus(): void {\n if (hadPointerDownOnTrigger || suppressFocusOpen)\n return\n openDropdown()\n}\n\n// Возврат фокуса на триггер — из контракта слоя, а не руками через `nextTick`.\nuseOverlayLayer(open, closeDropdown, { root: panelEl })\n\nwatch(\n open,\n async (isOpen) => {\n if (!isOpen) {\n if (filterValue.value.trim().length > 0)\n filterValue.value = ''\n return\n }\n\n // Подсветка дерева идёт за значением: панель могли открыть после того, как\n // значение сменили снаружи.\n if (!props.multiple) {\n const v = props.modelValue\n if (v != null && !Array.isArray(v))\n treeRef.value?.setCurrentKey(v)\n }\n\n if (props.filterable) {\n await nextTick()\n filterInputRef.value?.focus()\n }\n },\n { immediate: true },\n)\n\nwatch(\n () => props.modelValue,\n (v) => {\n if (props.multiple)\n return\n if (v == null || Array.isArray(v)) {\n treeRef.value?.setCurrentKey(undefined)\n return\n }\n treeRef.value?.setCurrentKey(v)\n },\n)\n\nwatch(\n filterValue,\n (v) => {\n treeRef.value?.filter(v)\n },\n)\n\nfunction emitModel(next: GrTreeSelectModelValue) {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction clear(): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n const next: GrTreeSelectModelValue = props.multiple ? [] : null\n emitModel(next)\n emit('clear')\n if (!props.multiple)\n treeRef.value?.setCurrentKey(undefined)\n}\n\n/**\n * Отдаёт клавиатуру дереву. Панель под `v-show`, поэтому дерево уже в DOM, но\n * скрытый элемент сфокусировать нельзя — сначала открытие, потом кадр, потом\n * фокус. Дальше работают клавиши `GrTree`, а `Escape` возвращает фокус на\n * триггер силами общего стека слоёв.\n */\nasync function focusTree(): Promise<boolean> {\n if (!open.value)\n return false\n\n await nextTick()\n return treeRef.value?.focus() ?? false\n}\n\nfunction onTriggerKeydown(e: KeyboardEvent): void {\n if (isDisabled.value)\n return\n\n if (e.key === 'Escape') {\n e.preventDefault()\n closeDropdown()\n return\n }\n\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n openDropdown()\n\n // При `filterable` фокус уходит в поле поиска (см. watch на `open`), и\n // дальше в дерево ведёт стрелка уже оттуда.\n if (!props.filterable)\n void focusTree()\n }\n}\n\n/** Стрелка из поля поиска — единственный путь из фильтра в дерево. */\nfunction onFilterKeydown(e: KeyboardEvent): void {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')\n return\n\n e.preventDefault()\n void focusTree()\n}\n\n/** `Tab` уводит из панели — оставлять её открытой за спиной незачем. */\nfunction onPanelKeydown(e: KeyboardEvent): void {\n if (e.key === 'Tab')\n closeDropdown()\n}\n\n// Чекбоксы осмысленны только в множественном выборе: одиночный уже подсвечен\n// текущим узлом.\nconst checkboxMode = computed(() => props.multiple && props.showCheckbox)\n\n// В режиме чекбоксов каскад по родителям и детям считает `GrTree`, а не копия\n// его логики здесь: значение приходит обратно одним `update:checkedKeys`.\nfunction onCheckedKeys(keys: GrTreeKey[]): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n emitModel([...keys])\n}\n\nfunction onNodeClick(data: T, node: GrTreeNode<T>): void {\n emit('nodeClick', data, node)\n\n if (isDisabled.value)\n return\n\n if (checkboxMode.value) {\n // Клик по строке — тот же переключатель отметки, что и сам чекбокс;\n // значение придёт через `update:checkedKeys`, поэтому здесь не эмитим.\n treeRef.value?.setChecked(node.key, !selectedKeySet.value.has(node.key))\n return\n }\n\n if (props.multiple) {\n const next = new Set(selectedKeySet.value)\n if (next.has(node.key))\n next.delete(node.key)\n else\n next.add(node.key)\n emitModel([...next])\n\n if (closeOnSelectResolved.value) {\n closeDropdown()\n }\n return\n }\n\n emitModel(node.key)\n if (closeOnSelectResolved.value) {\n closeDropdown()\n }\n}\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: onClickOutside, enabled: open, exclude: clickOutsideExclude }\"\n data-gr-tree-select\n class=\"relative\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Нативная форма: hidden на каждый выбранный ключ. -->\n <template v-if=\"name\">\n <input\n v-for=\"key in selectedKeys\"\n :key=\"`hidden-${String(key)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(key)\"\n >\n </template>\n <div class=\"relative\">\n <div\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-tree-select-prefix\n class=\"absolute inset-y-px left-px flex items-center justify-center rounded-l-[var(--gr-radius-control)] border-r border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate\"\n :style=\"prefixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"prefix\" />\n </div>\n\n <input\n :id=\"fieldId\"\n ref=\"triggerEl\"\n data-testid=\"gr-tree-select-trigger\"\n data-gr-tree-select-trigger\n type=\"text\"\n :value=\"displayValue\"\n :placeholder=\"placeholder\"\n :disabled=\"isDisabled\"\n readonly\n role=\"combobox\"\n aria-readonly=\"true\"\n aria-haspopup=\"tree\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :aria-controls=\"open && hasTree ? treeId : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n class=\"w-full rounded-[var(--gr-radius-control)] border placeholder:text-[var(--gr-muted-fg)] transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]\"\n :class=\"[className, $slots.value ? 'text-transparent placeholder:text-transparent' : '']\"\n :style=\"triggerStyle\"\n @pointerdown=\"onTriggerPointerDown\"\n @click=\"toggleDropdown\"\n @focus=\"onTriggerFocus\"\n @keydown=\"onTriggerKeydown\"\n >\n\n <span\n v-if=\"signalState\"\n data-gr-tree-select-state\n class=\"absolute top-1/2 -translate-y-1/2 right-9\"\n :class=\"stateIconClass\"\n aria-hidden=\"true\"\n >\n <component :is=\"stateIcon\" class=\"h-4 w-4\" />\n </span>\n\n <span v-if=\"signalState\" :id=\"stateTextId\" data-gr-tree-select-state-text class=\"sr-only\">{{ stateText }}</span>\n\n <button\n v-if=\"clearable && hasSelection && !disabled && !isReadonly\"\n data-testid=\"gr-tree-select-clear\"\n data-gr-tree-select-clear\n type=\"button\"\n class=\"absolute top-1/2 -translate-y-1/2 right-3 h-6 w-6 inline-flex items-center justify-center rounded-[var(--gr-radius-control)] text-[var(--gr-muted-fg)] hover:text-[var(--gr-fg)] hover:bg-[color-mix(in_srgb,var(--gr-muted)_25%,transparent)]\"\n :aria-label=\"t('gr.common.clear', 'Clear')\"\n @click.stop=\"clear\"\n >\n <IconX class=\"inline-block h-4 w-4\" aria-hidden=\"true\" />\n </button>\n\n <span\n v-else\n data-testid=\"gr-tree-select-chevron\"\n data-gr-tree-select-chevron\n class=\"absolute top-1/2 -translate-y-1/2 right-3 text-[var(--gr-muted-fg)] pointer-events-none\"\n >\n <IconChevronDown\n class=\"inline-block h-4 w-4 transition-transform duration-[var(--gr-duration-fast)]\"\n :class=\"open ? 'rotate-180' : ''\"\n aria-hidden=\"true\"\n />\n </span>\n\n <div\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-tree-select-suffix\n class=\"absolute inset-y-px right-9 flex items-center justify-center border-l border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate\"\n :class=\"suffixFixed ? '[direction:rtl]' : ''\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n\n <div\n v-if=\"$slots.value\"\n class=\"absolute inset-y-0 left-3 right-9 flex items-center pointer-events-none\"\n :style=\"valueOverlayStyle\"\n >\n <slot\n name=\"value\"\n :value=\"modelValue\"\n :labels=\"selectedLabels\"\n :display-value=\"displayValue\"\n :path-labels=\"selectedPathLabels\"\n />\n </div>\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-testid=\"gr-tree-select-panel\"\n v-bind=\"themeAttrs\"\n data-gr-tree-select-panel\n data-gr-overlay-root\n :style=\"floatingStyle\"\n @keydown=\"onPanelKeydown\"\n >\n <div :class=\"panelClasses\">\n <div v-if=\"filterable\" class=\"p-2 border-b border-[var(--gr-brd)]\">\n <GrInput\n ref=\"filterInputRef\"\n v-model=\"filterValue\"\n data-testid=\"gr-tree-select-filter\"\n data-gr-tree-select-filter\n type=\"search\"\n :inputmode=\"filterInputmode\"\n :placeholder=\"resolvedFilterPlaceholder\"\n size=\"sm\"\n @keydown=\"onFilterKeydown\"\n />\n </div>\n\n <!--\n Скроллер один. При виртуализации его берёт на себя дерево: своя\n высота нужна ему, чтобы посчитать окно, а вложенный скроллер поверх\n дал бы вторую полосу прокрутки на том же списке.\n -->\n <div\n class=\"p-1\"\n :class=\"virtual ? '' : 'overflow-auto'\"\n :style=\"virtual ? undefined : { maxHeight: `${dropdownMaxHeight}px` }\"\n >\n <div\n v-if=\"loading\"\n data-gr-tree-select-loading\n role=\"status\"\n :class=\"grTreeSelectStateClass\"\n >\n <slot name=\"loading\">\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n <span>{{ t('gr.treeSelect.loading', 'Loading…') }}</span>\n </slot>\n </div>\n\n <div v-else-if=\"(data?.length ?? 0) === 0\" :class=\"grTreeSelectStateClass\">\n <slot name=\"empty\">\n {{ t('gr.treeSelect.empty', 'No data') }}\n </slot>\n </div>\n\n <GrTree\n v-else\n :id=\"treeId\"\n ref=\"treeRef\"\n :size=\"resolvedSize\"\n :data=\"data\"\n :props=\"props.props\"\n :node-key=\"nodeKey as any\"\n :default-expanded-keys=\"defaultExpandedKeys\"\n :filter-node-method=\"filterNodeMethod\"\n :highlight-current=\"!multiple\"\n :virtual=\"virtual\"\n :max-height=\"dropdownMaxHeight\"\n :show-checkbox=\"checkboxMode\"\n :check-strictly=\"checkStrictly\"\n :checked-keys=\"selectedKeys\"\n @node-click=\"onNodeClick\"\n @update:checked-keys=\"onCheckedKeys\"\n >\n <template #default=\"{ node, data }\">\n <slot\n name=\"node\"\n :node=\"node\"\n :data=\"data\"\n :selected=\"selectedKeySet.has(node.key)\"\n >\n <div class=\"flex items-center gap-2 min-w-0\">\n <!-- Чекбокс дерева уже показывает отметку: вторая галочка\n рядом читалась бы как ошибка. -->\n <span\n v-if=\"!checkboxMode\"\n data-gr-tree-select-check\n class=\"inline-block h-4 w-4 shrink-0\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"selectedKeySet.has(node.key)\" class=\"block h-4 w-4 text-[var(--gr-primary-text)]\" />\n </span>\n <span class=\"truncate\">{{ node.label }}</span>\n </div>\n </slot>\n </template>\n </GrTree>\n </div>\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\" generic=\"T extends Record<string, any> = any\">\nimport { computed, nextTick, ref, useId, useSlots, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useGrComponentSize, useGrThemeAttrs } from '../GrConfigProvider/context'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport {\n controlSignalState,\n controlStateFallbackText,\n controlStateIconClass,\n controlStateIconColors,\n controlStateTextKey,\n} from '../shared/controlState'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrTree, {\n type GrTreeInstance,\n type GrTreeKey,\n type GrTreeNode,\n} from '../GrTree'\nimport type { GrInputSize } from '../GrInput/GrInput.vue'\nimport { panelPopTransition } from '../shared/overlayTransition'\nimport type { GrTreeSelectModelValue, GrTreeSelectProps } from './grTreeSelectTypes'\nimport { grTreeSelectClass, grTreeSelectPanelClass, grTreeSelectStateClass, paddingX, trailingZoneWidth } from './grTreeSelectStyles'\n\nimport IconCheck from '~icons/lucide/check'\nimport IconChevronDown from '~icons/lucide/chevron-down'\nimport IconCheckCircle from '~icons/lucide/check-circle'\nimport IconAlertTriangle from '~icons/lucide/alert-triangle'\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconX from '~icons/lucide/x'\n\nexport interface GrTreeSelectEmits<T extends Record<string, any> = any> {\n (e: 'update:modelValue', value: GrTreeSelectModelValue): void\n (e: 'change', value: GrTreeSelectModelValue): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n (e: 'clear'): void\n (e: 'nodeClick', data: T, node: GrTreeNode<T>): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrTreeSelectProps<T>>(),\n {\n props: () => ({\n children: 'children',\n label: 'label',\n }),\n nodeKey: 'id' as any,\n defaultExpandedKeys: () => [],\n disabled: false,\n placeholder: undefined,\n size: undefined,\n loading: false,\n invalid: false,\n readonly: false,\n required: false,\n ariaLabel: undefined,\n state: 'default',\n multiple: false,\n showCheckbox: false,\n checkStrictly: false,\n clearable: false,\n open: undefined,\n name: undefined,\n valueDisplay: 'label',\n filterable: false,\n filterPlaceholder: undefined,\n filterInputmode: undefined,\n filterNodeMethod: undefined,\n closeOnSelect: undefined,\n dropdownMaxHeight: 320,\n virtual: false,\n prefixMinWidth: undefined,\n prefixMaxWidth: undefined,\n suffixMinWidth: undefined,\n suffixMaxWidth: undefined,\n prefixFixed: false,\n suffixFixed: false,\n },\n)\n\nconst { t } = useGranularityTranslations()\n\nconst emit = defineEmits<GrTreeSelectEmits<T>>()\n\ndefineSlots<{\n /** Рендер значения внутри триггера (вместо дефолтного текста). */\n value?: (props: { value: GrTreeSelectModelValue, labels: string[], displayValue: string, pathLabels?: string[] }) => any\n /** Рендер строки дерева. */\n node?: (props: { node: GrTreeNode<T>, data: T, selected: boolean }) => any\n /** Содержимое пустого состояния (когда нет данных). */\n empty?: () => any\n /** Содержимое панели, пока данные едут. */\n loading?: () => any\n /** Аддон слева от значения: иконка, код валюты, метка. */\n prefix?: () => any\n /** Аддон справа от значения, перед крестиком и шевроном. */\n suffix?: () => any\n}>()\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst triggerEl = ref<HTMLInputElement | null>(null)\nconst treeId = `gr-tree-select-tree-${useId()}`\n\n// Контекст `GrFormField` + общий контракт форм-контрола.\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst stateTextId = useId()\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\n/**\n * Небуквенный признак состояния: иконка для глаз, скрытая подпись для\n * скринридера. Разбор — `shared/controlState`. Встаёт левее крестика и\n * шеврона: правый край триггера занят одним из них всегда.\n */\nconst signalState = computed(() => controlSignalState(props.state, isInvalid.value))\nconst stateIcon = computed(() => (signalState.value === 'success' ? IconCheckCircle : IconAlertTriangle))\nconst stateIconClass = computed(() => (signalState.value\n ? `${controlStateIconClass} ${controlStateIconColors[signalState.value]}`\n : ''))\nconst stateText = computed(() => (signalState.value\n ? t(controlStateTextKey[signalState.value], controlStateFallbackText[signalState.value])\n : ''))\n\nconst describedBy = computed(() =>\n [field?.describedById.value, signalState.value ? stateTextId : undefined]\n .filter(Boolean)\n .join(' ') || undefined,\n)\n\nfunction focus(): void {\n triggerEl.value?.focus()\n}\n\nfunction blur(): void {\n triggerEl.value?.blur()\n}\n\ndefineExpose({ focus, blur })\nconst filterInputRef = ref<InstanceType<typeof GrInput> | null>(null)\nconst treeRef = ref<GrTreeInstance | null>(null)\nconst panelEl = 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})\n\nconst clickOutsideExclude = [() => panelEl.value]\n\nlet hadPointerDownOnTrigger = false\n\n// Имя `open` сохранено: читатели работают с computed-Ref.\nconst { open, setOpen: setOpenState } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\nconst filterValue = ref('')\n\nconst { floatingStyle } = useFloating(rootEl, panelEl, open, {\n placement: 'bottom-start',\n matchWidth: true,\n zIndexVar: '--gr-z-dropdown',\n})\n\nconst closeOnSelectResolved = computed(() => {\n return props.closeOnSelect ?? !props.multiple\n})\n\nfunction getChildrenKey() {\n return props.props.children ?? 'children'\n}\n\nfunction getLabelKey() {\n return props.props.label ?? 'label'\n}\n\nfunction nodeLabel(data: T): string {\n const key = getLabelKey() as keyof T\n const v = data[key]\n return v == null ? '' : String(v)\n}\n\nfunction nodeChildren(data: T): T[] {\n const key = getChildrenKey() as keyof T\n const v = data[key]\n return Array.isArray(v) ? (v as any) : []\n}\n\nfunction nodeKeyOf(data: T, index: number, parentKey: GrTreeKey | undefined): GrTreeKey {\n const keyName = props.nodeKey as keyof T\n const v = data[keyName]\n if (v != null)\n return v as GrTreeKey\n\n return parentKey == null ? index : `${String(parentKey)}:${index}`\n}\n\nconst labelByKey = computed(() => {\n const map = new Map<GrTreeKey, string>()\n\n const walk = (items: T[], parentKey: GrTreeKey | undefined) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const key = nodeKeyOf(item, i, parentKey)\n map.set(key, nodeLabel(item))\n walk(nodeChildren(item), key)\n }\n }\n\n walk(props.data ?? [], undefined)\n return map\n})\n\nconst pathLabelsByKey = computed(() => {\n const map = new Map<GrTreeKey, string[]>()\n\n const walk = (items: T[], parentKey: GrTreeKey | undefined, parentPath: string[]) => {\n for (let i = 0; i < items.length; i++) {\n const item = items[i]\n const key = nodeKeyOf(item, i, parentKey)\n const label = nodeLabel(item)\n const path = [...parentPath, label]\n map.set(key, path)\n walk(nodeChildren(item), key, path)\n }\n }\n\n walk(props.data ?? [], undefined, [])\n return map\n})\n\nconst selectedKeys = computed<GrTreeKey[]>(() => {\n if (props.multiple) {\n return Array.isArray(props.modelValue) ? props.modelValue : []\n }\n\n const v = props.modelValue\n if (v == null || Array.isArray(v))\n return []\n return [v]\n})\n\nconst selectedKeySet = computed(() => new Set(selectedKeys.value))\n\nconst selectedLabels = computed(() => {\n const map = labelByKey.value\n return selectedKeys.value.map(k => map.get(k) ?? String(k))\n})\n\nconst selectedPathLabels = computed<string[] | undefined>(() => {\n if (props.multiple)\n return undefined\n\n const key = selectedKeys.value[0]\n if (key == null)\n return undefined\n\n const path = pathLabelsByKey.value.get(key)\n if (path?.length)\n return path\n\n const labels = selectedLabels.value\n return labels.length ? [labels[0]] : undefined\n})\n\nconst displayValue = computed(() => {\n const labels = selectedLabels.value\n if (labels.length === 0)\n return ''\n\n if (!props.multiple) {\n if (props.valueDisplay === 'path') {\n const path = selectedPathLabels.value\n if (path?.length)\n return path.join(' / ')\n }\n return labels[0]\n }\n\n if (labels.length === 1)\n return labels[0]\n return `${labels[0]} +${labels.length - 1}`\n})\n\nconst hasSelection = computed(() => selectedKeys.value.length > 0)\n\n/** Дерево рендерится только когда есть что показать — ссылаться иначе не на что. */\nconst hasTree = computed(() => !props.loading && (props.data?.length ?? 0) > 0)\n\nconst resolvedFilterPlaceholder = computed(() => {\n return props.filterPlaceholder ?? t('gr.treeSelect.filterPlaceholder', 'Search…')\n})\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrTreeSelect' })\n\nconst className = computed(() => {\n return grTreeSelectClass({\n size: resolvedSize.value,\n state: props.state,\n invalid: isInvalid.value,\n disabled: isDisabled.value,\n })\n})\n\nconst panelClasses = computed(() => {\n return grTreeSelectPanelClass\n})\n\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrInputSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\nconst slots = useSlots()\n\nconst {\n hasPrefix,\n hasSuffix,\n prefixEl,\n suffixEl,\n prefixStyle,\n suffixStyle,\n fieldPadding: triggerStyle,\n} = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => paddingX[resolvedSize.value],\n // Место под крестик и шеврон уже отдано классом `pr-9`, но инлайн-паддинг\n // перекрывает класс целиком — с суффиксом эту зону приходится вернуть числом.\n trailingReserve: () => (slots.suffix ? trailingZoneWidth : '0px'),\n})\n\n// Слот `value` рисуется поверх поля и обязан жить в тех же границах, что и\n// текст под ним. Без аддонов границы задаёт класс — стиль остаётся пустым.\nconst valueOverlayStyle = computed(() => ({\n left: hasPrefix.value ? triggerStyle.value.paddingLeft : undefined,\n right: hasSuffix.value ? triggerStyle.value.paddingRight : undefined,\n}))\n\nfunction setOpen(next: boolean) {\n if (isDisabled.value || isReadonly.value)\n return\n\n setOpenState(next)\n}\n\nfunction onClickOutside(): void {\n setOpen(false)\n}\n\nfunction openDropdown(): void {\n setOpen(true)\n}\n\n/**\n * Стек слоёв возвращает фокус на триггер сразу после закрытия, а у триггера\n * открытие висит на `focus`. Без флага `Escape` из дерева закрывал бы панель и\n * тем же движением открывал её заново.\n */\nlet suppressFocusOpen = false\n\nfunction closeDropdown(): void {\n suppressFocusOpen = true\n setOpen(false)\n setTimeout(() => {\n suppressFocusOpen = false\n }, 0)\n}\n\nfunction toggleDropdown(): void {\n setOpen(!open.value)\n}\n\n// Клик по триггеру сам переключает панель через `@click`; флаг гасит открытие\n// по приходящему следом `focus`, иначе один клик открыл бы и тут же закрыл.\nfunction onTriggerPointerDown(): void {\n hadPointerDownOnTrigger = true\n setTimeout(() => {\n hadPointerDownOnTrigger = false\n }, 0)\n}\n\nfunction onTriggerFocus(): void {\n if (hadPointerDownOnTrigger || suppressFocusOpen)\n return\n openDropdown()\n}\n\n// Возврат фокуса на триггер — из контракта слоя, а не руками через `nextTick`.\nuseOverlayLayer(open, closeDropdown, { root: panelEl })\n\nwatch(\n open,\n async (isOpen) => {\n if (!isOpen) {\n if (filterValue.value.trim().length > 0)\n filterValue.value = ''\n return\n }\n\n // Подсветка дерева идёт за значением: панель могли открыть после того, как\n // значение сменили снаружи.\n if (!props.multiple) {\n const v = props.modelValue\n if (v != null && !Array.isArray(v))\n treeRef.value?.setCurrentKey(v)\n }\n\n if (props.filterable) {\n await nextTick()\n filterInputRef.value?.focus()\n }\n },\n { immediate: true },\n)\n\nwatch(\n () => props.modelValue,\n (v) => {\n if (props.multiple)\n return\n if (v == null || Array.isArray(v)) {\n treeRef.value?.setCurrentKey(undefined)\n return\n }\n treeRef.value?.setCurrentKey(v)\n },\n)\n\nwatch(\n filterValue,\n (v) => {\n treeRef.value?.filter(v)\n },\n)\n\nfunction emitModel(next: GrTreeSelectModelValue) {\n emit('update:modelValue', next)\n emit('change', next)\n}\n\nfunction clear(): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n const next: GrTreeSelectModelValue = props.multiple ? [] : null\n emitModel(next)\n emit('clear')\n if (!props.multiple)\n treeRef.value?.setCurrentKey(undefined)\n}\n\n/**\n * Отдаёт клавиатуру дереву. Панель под `v-show`, поэтому дерево уже в DOM, но\n * скрытый элемент сфокусировать нельзя — сначала открытие, потом кадр, потом\n * фокус. Дальше работают клавиши `GrTree`, а `Escape` возвращает фокус на\n * триггер силами общего стека слоёв.\n */\nasync function focusTree(): Promise<boolean> {\n if (!open.value)\n return false\n\n await nextTick()\n return treeRef.value?.focus() ?? false\n}\n\nfunction onTriggerKeydown(e: KeyboardEvent): void {\n if (isDisabled.value)\n return\n\n if (e.key === 'Escape') {\n e.preventDefault()\n closeDropdown()\n return\n }\n\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n openDropdown()\n\n // При `filterable` фокус уходит в поле поиска (см. watch на `open`), и\n // дальше в дерево ведёт стрелка уже оттуда.\n if (!props.filterable)\n void focusTree()\n }\n}\n\n/** Стрелка из поля поиска — единственный путь из фильтра в дерево. */\nfunction onFilterKeydown(e: KeyboardEvent): void {\n if (e.key !== 'ArrowDown' && e.key !== 'ArrowUp')\n return\n\n e.preventDefault()\n void focusTree()\n}\n\n/** `Tab` уводит из панели — оставлять её открытой за спиной незачем. */\nfunction onPanelKeydown(e: KeyboardEvent): void {\n if (e.key === 'Tab')\n closeDropdown()\n}\n\n// Чекбоксы осмысленны только в множественном выборе: одиночный уже подсвечен\n// текущим узлом.\nconst checkboxMode = computed(() => props.multiple && props.showCheckbox)\n\n// В режиме чекбоксов каскад по родителям и детям считает `GrTree`, а не копия\n// его логики здесь: значение приходит обратно одним `update:checkedKeys`.\nfunction onCheckedKeys(keys: GrTreeKey[]): void {\n if (isDisabled.value || isReadonly.value)\n return\n\n emitModel([...keys])\n}\n\nfunction onNodeClick(data: T, node: GrTreeNode<T>): void {\n emit('nodeClick', data, node)\n\n if (isDisabled.value)\n return\n\n if (checkboxMode.value) {\n // Клик по строке — тот же переключатель отметки, что и сам чекбокс;\n // значение придёт через `update:checkedKeys`, поэтому здесь не эмитим.\n treeRef.value?.setChecked(node.key, !selectedKeySet.value.has(node.key))\n return\n }\n\n if (props.multiple) {\n const next = new Set(selectedKeySet.value)\n if (next.has(node.key))\n next.delete(node.key)\n else\n next.add(node.key)\n emitModel([...next])\n\n if (closeOnSelectResolved.value) {\n closeDropdown()\n }\n return\n }\n\n emitModel(node.key)\n if (closeOnSelectResolved.value) {\n closeDropdown()\n }\n}\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: onClickOutside, enabled: open, exclude: clickOutsideExclude }\"\n data-gr-tree-select\n class=\"relative\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <!-- Нативная форма: hidden на каждый выбранный ключ. -->\n <template v-if=\"name\">\n <input\n v-for=\"key in selectedKeys\"\n :key=\"`hidden-${String(key)}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"String(key)\"\n >\n </template>\n <div class=\"relative\">\n <div\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-tree-select-prefix\n class=\"absolute inset-y-px left-px flex items-center justify-center rounded-l-[var(--gr-radius-control)] border-r border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate\"\n :style=\"prefixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"prefix\" />\n </div>\n\n <input\n :id=\"fieldId\"\n ref=\"triggerEl\"\n data-testid=\"gr-tree-select-trigger\"\n data-gr-tree-select-trigger\n type=\"text\"\n :value=\"displayValue\"\n :placeholder=\"placeholder\"\n :disabled=\"isDisabled\"\n readonly\n role=\"combobox\"\n aria-readonly=\"true\"\n aria-haspopup=\"tree\"\n :aria-expanded=\"open ? 'true' : 'false'\"\n :aria-controls=\"open && hasTree ? treeId : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-describedby=\"describedBy\"\n :aria-label=\"ariaLabel\"\n class=\"w-full rounded-[var(--gr-radius-control)] border placeholder:text-[var(--gr-muted-fg)] transition-colors duration-[var(--gr-duration-fast)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]\"\n :class=\"[className, $slots.value ? 'text-transparent placeholder:text-transparent' : '']\"\n :style=\"triggerStyle\"\n @pointerdown=\"onTriggerPointerDown\"\n @click=\"toggleDropdown\"\n @focus=\"onTriggerFocus\"\n @keydown=\"onTriggerKeydown\"\n >\n\n <span\n v-if=\"signalState\"\n data-gr-tree-select-state\n class=\"absolute top-1/2 -translate-y-1/2 right-9\"\n :class=\"stateIconClass\"\n aria-hidden=\"true\"\n >\n <component :is=\"stateIcon\" class=\"h-4 w-4\" />\n </span>\n\n <span v-if=\"signalState\" :id=\"stateTextId\" data-gr-tree-select-state-text class=\"sr-only\">{{ stateText }}</span>\n\n <button\n v-if=\"clearable && hasSelection && !disabled && !isReadonly\"\n data-testid=\"gr-tree-select-clear\"\n data-gr-tree-select-clear\n type=\"button\"\n class=\"absolute top-1/2 -translate-y-1/2 right-3 h-6 w-6 inline-flex items-center justify-center rounded-[var(--gr-radius-control)] text-[var(--gr-muted-fg)] hover:text-[var(--gr-fg)] hover:bg-[color-mix(in_srgb,var(--gr-muted)_25%,transparent)]\"\n :aria-label=\"t('gr.common.clear', 'Clear')\"\n @click.stop=\"clear\"\n >\n <IconX class=\"inline-block h-4 w-4\" aria-hidden=\"true\" />\n </button>\n\n <span\n v-else\n data-testid=\"gr-tree-select-chevron\"\n data-gr-tree-select-chevron\n class=\"absolute top-1/2 -translate-y-1/2 right-3 text-[var(--gr-muted-fg)] pointer-events-none\"\n >\n <IconChevronDown\n class=\"inline-block h-4 w-4 transition-transform duration-[var(--gr-duration-fast)]\"\n :class=\"open ? 'rotate-180' : ''\"\n aria-hidden=\"true\"\n />\n </span>\n\n <div\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-tree-select-suffix\n class=\"absolute inset-y-px right-9 flex items-center justify-center border-l border-[var(--gr-brd)] px-2 text-[var(--gr-muted-fg)] pointer-events-none select-none truncate\"\n :class=\"suffixFixed ? '[direction:rtl]' : ''\"\n :style=\"suffixStyle\"\n aria-hidden=\"true\"\n >\n <slot name=\"suffix\" />\n </div>\n\n <div\n v-if=\"$slots.value\"\n class=\"absolute inset-y-0 left-3 right-9 flex items-center pointer-events-none\"\n :style=\"valueOverlayStyle\"\n >\n <slot\n name=\"value\"\n :value=\"modelValue\"\n :labels=\"selectedLabels\"\n :display-value=\"displayValue\"\n :path-labels=\"selectedPathLabels\"\n />\n </div>\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n :enter-active-class=\"panelPopTransition.enter\"\n :enter-from-class=\"panelPopTransition.enterFrom\"\n :enter-to-class=\"panelPopTransition.enterTo\"\n :leave-active-class=\"panelPopTransition.leave\"\n :leave-from-class=\"panelPopTransition.leaveFrom\"\n :leave-to-class=\"panelPopTransition.leaveTo\"\n >\n <div\n v-show=\"open\"\n ref=\"panelEl\"\n data-testid=\"gr-tree-select-panel\"\n v-bind=\"themeAttrs\"\n data-gr-tree-select-panel\n data-gr-overlay-root\n :style=\"floatingStyle\"\n @keydown=\"onPanelKeydown\"\n >\n <div :class=\"panelClasses\">\n <div v-if=\"filterable\" class=\"p-2 border-b border-[var(--gr-brd)]\">\n <GrInput\n ref=\"filterInputRef\"\n v-model=\"filterValue\"\n data-testid=\"gr-tree-select-filter\"\n data-gr-tree-select-filter\n type=\"search\"\n :inputmode=\"filterInputmode\"\n :placeholder=\"resolvedFilterPlaceholder\"\n size=\"sm\"\n @keydown=\"onFilterKeydown\"\n />\n </div>\n\n <!--\n Скроллер один. При виртуализации его берёт на себя дерево: своя\n высота нужна ему, чтобы посчитать окно, а вложенный скроллер поверх\n дал бы вторую полосу прокрутки на том же списке.\n -->\n <div\n class=\"p-1\"\n :class=\"virtual ? '' : 'overflow-auto'\"\n :style=\"virtual ? undefined : { maxHeight: `${dropdownMaxHeight}px` }\"\n >\n <div\n v-if=\"loading\"\n data-gr-tree-select-loading\n role=\"status\"\n :class=\"grTreeSelectStateClass\"\n >\n <slot name=\"loading\">\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" aria-hidden=\"true\" />\n <span>{{ t('gr.treeSelect.loading', 'Loading…') }}</span>\n </slot>\n </div>\n\n <div v-else-if=\"(data?.length ?? 0) === 0\" :class=\"grTreeSelectStateClass\">\n <slot name=\"empty\">\n {{ t('gr.treeSelect.empty', 'No data') }}\n </slot>\n </div>\n\n <GrTree\n v-else\n :id=\"treeId\"\n ref=\"treeRef\"\n :size=\"resolvedSize\"\n :data=\"data\"\n :props=\"props.props\"\n :node-key=\"nodeKey as any\"\n :default-expanded-keys=\"defaultExpandedKeys\"\n :filter-node-method=\"filterNodeMethod\"\n :highlight-current=\"!multiple\"\n :virtual=\"virtual\"\n :max-height=\"dropdownMaxHeight\"\n :show-checkbox=\"checkboxMode\"\n :check-strictly=\"checkStrictly\"\n :checked-keys=\"selectedKeys\"\n @node-click=\"onNodeClick\"\n @update:checked-keys=\"onCheckedKeys\"\n >\n <template #default=\"{ node, data }\">\n <slot\n name=\"node\"\n :node=\"node\"\n :data=\"data\"\n :selected=\"selectedKeySet.has(node.key)\"\n >\n <div class=\"flex items-center gap-2 min-w-0\">\n <!-- Чекбокс дерева уже показывает отметку: вторая галочка\n рядом читалась бы как ошибка. -->\n <span\n v-if=\"!checkboxMode\"\n data-gr-tree-select-check\n class=\"inline-block h-4 w-4 shrink-0\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"selectedKeySet.has(node.key)\" class=\"block h-4 w-4 text-[var(--gr-primary-text)]\" />\n </span>\n <span class=\"truncate\">{{ node.label }}</span>\n </div>\n </slot>\n </template>\n </GrTree>\n </div>\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmDA,MAAM,QAAQ;EAyCd,MAAM,EAAE,MAAM,2BAA2B;EAEzC,MAAM,OAAO;EAiBb,MAAM,SAAS,IAAwB,IAAI;EAC3C,MAAM,YAAY,IAA6B,IAAI;EACnD,MAAM,SAAS,uBAAuB,MAAM;EAG5C,MAAM,QAAQ,sBAAsB;EACpC,MAAM,UAAU,eAAe,OAAO,GAAG,KAAK;EAC9C,MAAM,cAAc,MAAM;EAC1B,MAAM,EACJ,UAAU,YACV,SAAS,WACT,UAAU,YACV,UAAU,eACR,uBAAuB,KAAK;;;;;;EAOhC,MAAM,cAAc,eAAe,mBAAmB,MAAM,OAAO,UAAU,KAAK,CAAC;EACnF,MAAM,YAAY,eAAgB,YAAY,UAAU,YAAY,uBAAkB,sBAAkB;EACxG,MAAM,iBAAiB,eAAgB,YAAY,QAC/C,GAAG,sBAAsB,GAAG,uBAAuB,YAAY,WAC/D,EAAG;EACP,MAAM,YAAY,eAAgB,YAAY,QAC1C,EAAE,oBAAoB,YAAY,QAAQ,yBAAyB,YAAY,MAAM,IACrF,EAAG;EAEP,MAAM,cAAc,eAClB,CAAC,OAAO,cAAc,OAAO,YAAY,QAAQ,cAAc,KAAA,CAAS,CAAA,CACrE,OAAO,OAAO,CAAA,CACd,KAAK,GAAG,KAAK,KAAA,CAClB;EAEA,SAAS,QAAc;GACrB,UAAU,OAAO,MAAM;EACzB;EAEA,SAAS,OAAa;GACpB,UAAU,OAAO,KAAK;EACxB;EAEA,SAAa;GAAE;GAAO;EAAK,CAAC;EAC5B,MAAM,iBAAiB,IAAyC,IAAI;EACpE,MAAM,UAAU,IAA2B,IAAI;EAC/C,MAAM,UAAU,IAAwB,IAAI;EAI5C,MAAM,EAAE,WAAW,eAAe,eAAe,QAAQ;GACvD,QAAO,UAAS,KAAK,SAAS,KAAK;GACnC,QAAO,UAAS,KAAK,QAAQ,KAAK;GAClC,kBAAkB,CAAC,QAAQ,KAAK;EAClC,CAAC;EAED,MAAM,sBAAsB,OAAO,QAAQ,KAAK;EAEhD,IAAI,0BAA0B;EAG9B,MAAM,EAAE,MAAM,SAAS,iBAAiB,wBAChC,MAAM,OACZ,SAAQ,KAAK,eAAe,IAAI,CAClC;EACA,MAAM,cAAc,IAAI,EAAE;EAE1B,MAAM,EAAE,kBAAkB,YAAY,QAAQ,SAAS,MAAM;GAC3D,WAAW;GACX,YAAY;GACZ,WAAW;EACb,CAAC;EAED,MAAM,wBAAwB,eAAe;GAC3C,OAAO,MAAM,iBAAiB,CAAC,MAAM;EACvC,CAAC;EAED,SAAS,iBAAiB;GACxB,OAAO,MAAM,MAAM,YAAY;EACjC;EAEA,SAAS,cAAc;GACrB,OAAO,MAAM,MAAM,SAAS;EAC9B;EAEA,SAAS,UAAU,MAAiB;GAElC,MAAM,IAAI,KADE,YACG;GACf,OAAO,KAAK,OAAO,KAAK,OAAO,CAAC;EAClC;EAEA,SAAS,aAAa,MAAc;GAElC,MAAM,IAAI,KADE,eACG;GACf,OAAO,MAAM,QAAQ,CAAC,IAAK,IAAY,CAAC;EAC1C;EAEA,SAAS,UAAU,MAAS,OAAe,WAA6C;GAEtF,MAAM,IAAI,KADM,MAAM;GAEtB,IAAI,KAAK,MACP,OAAO;GAET,OAAO,aAAa,OAAO,QAAQ,GAAG,OAAO,SAAS,EAAE,GAAG;EAC7D;EAEA,MAAM,aAAa,eAAe;GAChC,MAAM,sBAAM,IAAI,IAAuB;GAEvC,MAAM,QAAQ,OAAY,cAAqC;IAC7D,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;KACrC,MAAM,OAAO,MAAM;KACnB,MAAM,MAAM,UAAU,MAAM,GAAG,SAAS;KACxC,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC;KAC5B,KAAK,aAAa,IAAI,GAAG,GAAG;IAC9B;GACF;GAEA,KAAK,MAAM,QAAQ,CAAC,GAAG,KAAA,CAAS;GAChC,OAAO;EACT,CAAC;EAED,MAAM,kBAAkB,eAAe;GACrC,MAAM,sBAAM,IAAI,IAAyB;GAEzC,MAAM,QAAQ,OAAY,WAAkC,eAAyB;IACnF,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;KACrC,MAAM,OAAO,MAAM;KACnB,MAAM,MAAM,UAAU,MAAM,GAAG,SAAS;KACxC,MAAM,QAAQ,UAAU,IAAI;KAC5B,MAAM,OAAO,CAAC,GAAG,YAAY,KAAK;KAClC,IAAI,IAAI,KAAK,IAAI;KACjB,KAAK,aAAa,IAAI,GAAG,KAAK,IAAI;IACpC;GACF;GAEA,KAAK,MAAM,QAAQ,CAAC,GAAG,KAAA,GAAW,CAAC,CAAC;GACpC,OAAO;EACT,CAAC;EAED,MAAM,eAAe,eAA4B;GAC/C,IAAI,MAAM,UACR,OAAO,MAAM,QAAQ,MAAM,UAAU,IAAI,MAAM,aAAa,CAAC;GAG/D,MAAM,IAAI,MAAM;GAChB,IAAI,KAAK,QAAQ,MAAM,QAAQ,CAAC,GAC9B,OAAO,CAAC;GACV,OAAO,CAAC,CAAC;EACX,CAAC;EAED,MAAM,iBAAiB,eAAe,IAAI,IAAI,aAAa,KAAK,CAAC;EAEjE,MAAM,iBAAiB,eAAe;GACpC,MAAM,MAAM,WAAW;GACvB,OAAO,aAAa,MAAM,KAAI,MAAK,IAAI,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC;EAC5D,CAAC;EAED,MAAM,qBAAqB,eAAqC;GAC9D,IAAI,MAAM,UACR,OAAO,KAAA;GAET,MAAM,MAAM,aAAa,MAAM;GAC/B,IAAI,OAAO,MACT,OAAO,KAAA;GAET,MAAM,OAAO,gBAAgB,MAAM,IAAI,GAAG;GAC1C,IAAI,MAAM,QACR,OAAO;GAET,MAAM,SAAS,eAAe;GAC9B,OAAO,OAAO,SAAS,CAAC,OAAO,EAAE,IAAI,KAAA;EACvC,CAAC;EAED,MAAM,eAAe,eAAe;GAClC,MAAM,SAAS,eAAe;GAC9B,IAAI,OAAO,WAAW,GACpB,OAAO;GAET,IAAI,CAAC,MAAM,UAAU;IACnB,IAAI,MAAM,iBAAiB,QAAQ;KACjC,MAAM,OAAO,mBAAmB;KAChC,IAAI,MAAM,QACR,OAAO,KAAK,KAAK,KAAK;IAC1B;IACA,OAAO,OAAO;GAChB;GAEA,IAAI,OAAO,WAAW,GACpB,OAAO,OAAO;GAChB,OAAO,GAAG,OAAO,GAAG,IAAI,OAAO,SAAS;EAC1C,CAAC;EAED,MAAM,eAAe,eAAe,aAAa,MAAM,SAAS,CAAC;;EAGjE,MAAM,UAAU,eAAe,CAAC,MAAM,YAAY,MAAM,MAAM,UAAU,KAAK,CAAC;EAE9E,MAAM,4BAA4B,eAAe;GAC/C,OAAO,MAAM,qBAAqB,EAAE,mCAAmC,SAAS;EAClF,CAAC;EAED,MAAM,eAAe,yBAAyB,MAAM,MAAM,EAAE,WAAW,eAAe,CAAC;EAEvF,MAAM,YAAY,eAAe;GAC/B,OAAO,kBAAkB;IACvB,MAAM,aAAa;IACnB,OAAO,MAAM;IACb,SAAS,UAAU;IACnB,UAAU,WAAW;GACvB,CAAC;EACH,CAAC;EAED,MAAM,eAAe,eAAe;GAClC,OAAO;EACT,CAAC;EAED,MAAM,0BAAuD;GAC3D,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;EACN;EAEA,MAAM,QAAQ,SAAS;EAEvB,MAAM,EACJ,WACA,WACA,UACA,UACA,aACA,aACA,cAAc,iBACZ,uBAAuB,OAAO;GAChC,uBAAuB,wBAAwB,aAAa;GAC5D,gBAAgB,SAAS,aAAa;GAGtC,uBAAwB,MAAM,SAAS,oBAAoB;EAC7D,CAAC;EAID,MAAM,oBAAoB,gBAAgB;GACxC,MAAM,UAAU,QAAQ,aAAa,MAAM,cAAc,KAAA;GACzD,OAAO,UAAU,QAAQ,aAAa,MAAM,eAAe,KAAA;EAC7D,EAAE;EAEF,SAAS,QAAQ,MAAe;GAC9B,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,aAAa,IAAI;EACnB;EAEA,SAAS,iBAAuB;GAC9B,QAAQ,KAAK;EACf;EAEA,SAAS,eAAqB;GAC5B,QAAQ,IAAI;EACd;;;;;;EAOA,IAAI,oBAAoB;EAExB,SAAS,gBAAsB;GAC7B,oBAAoB;GACpB,QAAQ,KAAK;GACb,iBAAiB;IACf,oBAAoB;GACtB,GAAG,CAAC;EACN;EAEA,SAAS,iBAAuB;GAC9B,QAAQ,CAAC,KAAK,KAAK;EACrB;EAIA,SAAS,uBAA6B;GACpC,0BAA0B;GAC1B,iBAAiB;IACf,0BAA0B;GAC5B,GAAG,CAAC;EACN;EAEA,SAAS,iBAAuB;GAC9B,IAAI,2BAA2B,mBAC7B;GACF,aAAa;EACf;EAGA,gBAAgB,MAAM,eAAe,EAAE,MAAM,QAAQ,CAAC;EAEtD,MACE,MACA,OAAO,WAAW;GAChB,IAAI,CAAC,QAAQ;IACX,IAAI,YAAY,MAAM,KAAK,CAAC,CAAC,SAAS,GACpC,YAAY,QAAQ;IACtB;GACF;GAIA,IAAI,CAAC,MAAM,UAAU;IACnB,MAAM,IAAI,MAAM;IAChB,IAAI,KAAK,QAAQ,CAAC,MAAM,QAAQ,CAAC,GAC/B,QAAQ,OAAO,cAAc,CAAC;GAClC;GAEA,IAAI,MAAM,YAAY;IACpB,MAAM,SAAS;IACf,eAAe,OAAO,MAAM;GAC9B;EACF,GACA,EAAE,WAAW,KAAK,CACpB;EAEA,YACQ,MAAM,aACX,MAAM;GACL,IAAI,MAAM,UACR;GACF,IAAI,KAAK,QAAQ,MAAM,QAAQ,CAAC,GAAG;IACjC,QAAQ,OAAO,cAAc,KAAA,CAAS;IACtC;GACF;GACA,QAAQ,OAAO,cAAc,CAAC;EAChC,CACF;EAEA,MACE,cACC,MAAM;GACL,QAAQ,OAAO,OAAO,CAAC;EACzB,CACF;EAEA,SAAS,UAAU,MAA8B;GAC/C,KAAK,qBAAqB,IAAI;GAC9B,KAAK,UAAU,IAAI;EACrB;EAEA,SAAS,QAAc;GACrB,IAAI,WAAW,SAAS,WAAW,OACjC;GAGF,UADqC,MAAM,WAAW,CAAC,IAAI,IAC7C;GACd,KAAK,OAAO;GACZ,IAAI,CAAC,MAAM,UACT,QAAQ,OAAO,cAAc,KAAA,CAAS;EAC1C;;;;;;;EAQA,eAAe,YAA8B;GAC3C,IAAI,CAAC,KAAK,OACR,OAAO;GAET,MAAM,SAAS;GACf,OAAO,QAAQ,OAAO,MAAM,KAAK;EACnC;EAEA,SAAS,iBAAiB,GAAwB;GAChD,IAAI,WAAW,OACb;GAEF,IAAI,EAAE,QAAQ,UAAU;IACtB,EAAE,eAAe;IACjB,cAAc;IACd;GACF;GAEA,IAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,aAAa,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;IACtF,EAAE,eAAe;IACjB,aAAa;IAIb,IAAI,CAAC,MAAM,YACT,UAAe;GACnB;EACF;;EAGA,SAAS,gBAAgB,GAAwB;GAC/C,IAAI,EAAE,QAAQ,eAAe,EAAE,QAAQ,WACrC;GAEF,EAAE,eAAe;GACjB,UAAe;EACjB;;EAGA,SAAS,eAAe,GAAwB;GAC9C,IAAI,EAAE,QAAQ,OACZ,cAAc;EAClB;EAIA,MAAM,eAAe,eAAe,MAAM,YAAY,MAAM,YAAY;EAIxE,SAAS,cAAc,MAAyB;GAC9C,IAAI,WAAW,SAAS,WAAW,OACjC;GAEF,UAAU,CAAC,GAAG,IAAI,CAAC;EACrB;EAEA,SAAS,YAAY,MAAS,MAA2B;GACvD,KAAK,aAAa,MAAM,IAAI;GAE5B,IAAI,WAAW,OACb;GAEF,IAAI,aAAa,OAAO;IAGtB,QAAQ,OAAO,WAAW,KAAK,KAAK,CAAC,eAAe,MAAM,IAAI,KAAK,GAAG,CAAC;IACvE;GACF;GAEA,IAAI,MAAM,UAAU;IAClB,MAAM,OAAO,IAAI,IAAI,eAAe,KAAK;IACzC,IAAI,KAAK,IAAI,KAAK,GAAG,GACnB,KAAK,OAAO,KAAK,GAAG;SAEpB,KAAK,IAAI,KAAK,GAAG;IACnB,UAAU,CAAC,GAAG,IAAI,CAAC;IAEnB,IAAI,sBAAsB,OACxB,cAAc;IAEhB;GACF;GAEA,UAAU,KAAK,GAAG;GAClB,IAAI,sBAAsB,OACxB,cAAc;EAElB;EAIA,MAAM,EAAE,QAAQ,cAAc,SAAS,oBAAoB,gBAAgB;EAM3E,MAAM,aAAa,gBAAgB;;GAIjC,OAAA,gBAAA,UAAA,GAAA,mBAuOM,OAAA;IAtOA,SAAA;IAAJ,KAAI;IAEJ,uBAAA;IACA,OAAM;IACJ,WAAO,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,SAAA,KAAA,MAAA,SAAA,CAAA,CAAA,GAAA,IAAA;IACV,YAAQ,OAAA,OAAA,OAAA,MAAE,GAAA,SAAA,MAAA,UAAA,KAAA,MAAA,UAAA,CAAA,CAAA,GAAA,IAAA;;IAGK,QAAA,QACd,UAAA,IAAA,GAAA,mBAMC,UAAA,EAAA,KAAA,EAAA,GAAA,WALe,aAAA,QAAP,QAAG;KADZ,OAAA,UAAA,GAAA,mBAMC,SAAA;MAJE,KAAG,UAAY,OAAO,GAAG;MAC1B,MAAK;MACJ,MAAM,QAAA;MACN,OAAO,OAAO,GAAG;;;IAGtB,mBAsGM,OAtGN,YAsGM;KApGI,MAAA,SAAA,KADR,UAAA,GAAA,mBASM,OAAA;;MAPA,SAAA;MAAJ,KAAI;MACJ,8BAAA;MACA,OAAM;MACL,OAAK,eAAE,MAAA,WAAA,CAAW;MACnB,eAAY;KAEZ,GAAA,CAAA,WAAsB,KAAA,QAAA,QAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KAGxB,mBA0BC,SAAA;MAzBE,IAAI,QAAA;MACD,SAAA;MAAJ,KAAI;MACJ,eAAY;MACZ,+BAAA;MACA,MAAK;MACJ,OAAO,aAAA;MACP,aAAa,QAAA;MACb,UAAU,MAAA,UAAA;MACX,UAAA;MACA,MAAK;MACL,iBAAc;MACd,iBAAc;MACb,iBAAe,MAAA,IAAA,IAAI,SAAA;MACnB,iBAAe,MAAA,IAAA,KAAQ,QAAA,QAAU,SAAS,KAAA;MAC1C,gBAAc,MAAA,SAAA,IAAS,SAAY,KAAA;MACnC,iBAAe,MAAA,UAAA,IAAU,SAAY,KAAA;MACrC,oBAAkB,YAAA;MAClB,cAAY,QAAA;MACb,OAAK,eAAA,CAAC,2NAAyN,CACtN,UAAA,OAAWA,KAAAA,OAAO,QAAK,kDAAA,EAAA,CAAA,CAAA;MAC/B,OAAK,eAAE,MAAA,YAAA,CAAY;MACnB,eAAa;MACb,SAAO;MACP,SAAO;MACP,WAAS;;KAIJ,YAAA,SADR,UAAA,GAAA,mBAQO,QAAA;;MANL,6BAAA;MACA,OAAK,eAAA,CAAC,6CACE,eAAA,KAAc,CAAA;MACtB,eAAY;KAEZ,GAAA,EAAA,UAAA,GAAA,YAA6C,wBAA7B,UAAA,KAAS,GAAA,EAAE,OAAM,UAAS,CAAA,EAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KAGhC,YAAA,SAAZ,UAAA,GAAA,mBAAgH,QAAA;;MAAtF,IAAI,MAAA,WAAA;MAAa,kCAAA;MAA+B,OAAM;KAAa,GAAA,gBAAA,UAAA,KAAS,GAAA,GAAA,UAAA,KAAA,mBAAA,IAAA,IAAA;KAG9F,QAAA,aAAa,aAAA,SAAY,CAAK,QAAA,YAAQ,CAAK,MAAA,UAAA,KADnD,UAAA,GAAA,mBAUS,UAAA;;MARP,eAAY;MACZ,6BAAA;MACA,MAAK;MACL,OAAM;MACL,cAAY,MAAA,CAAA,CAAC,CAAA,mBAAA,OAAA;MACb,SAAK,cAAO,OAAK,CAAA,MAAA,CAAA;KAElB,GAAA,CAAA,YAAyD,MAAA,SAAA,GAAA;MAAlD,OAAM;MAAuB,eAAY;KAGlD,CAAA,CAAA,GAAA,GAAA,UAAA,MAAA,UAAA,GAAA,mBAWO,QAXP,YAWO,CALL,YAIE,MAAA,oBAAA,GAAA;MAHA,OAAK,eAAA,CAAC,gFACE,MAAA,IAAA,IAAI,eAAA,EAAA,CAAA;MACZ,eAAY;;KAKR,MAAA,SAAA,KADR,UAAA,GAAA,mBAUM,OAAA;;MARA,SAAA;MAAJ,KAAI;MACJ,8BAAA;MACA,OAAK,eAAA,CAAC,wKACE,QAAA,cAAW,oBAAA,EAAA,CAAA;MAClB,OAAK,eAAE,MAAA,WAAA,CAAW;MACnB,eAAY;KAEZ,GAAA,CAAA,WAAsB,KAAA,QAAA,QAAA,CAAA,GAAA,CAAA,KAAA,mBAAA,IAAA,IAAA;KAIhBA,KAAAA,OAAO,SADf,UAAA,GAAA,mBAYM,OAAA;;MAVJ,OAAM;MACL,OAAK,eAAE,kBAAA,KAAiB;KAEzB,GAAA,CAAA,WAME,KAAA,QAAA,SAAA;MAJC,OAAO,QAAA;MACP,QAAQ,eAAA;MACR,cAAe,aAAA;MACf,YAAa,mBAAA;;;KAKpB,UAAA,GAAA,YA4GW,UAAA;KA5GA,IAAI,MAAA,YAAA;KAAe,UAAQ,CAAG,MAAA,eAAA;IACvC,GAAA,CAAA,YA0Ga,YAAA;KAzGV,sBAAoB,MAAA,kBAAA,CAAkB,CAAC;KACvC,oBAAkB,MAAA,kBAAA,CAAkB,CAAC;KACrC,kBAAgB,MAAA,kBAAA,CAAkB,CAAC;KACnC,sBAAoB,MAAA,kBAAA,CAAkB,CAAC;KACvC,oBAAkB,MAAA,kBAAA,CAAkB,CAAC;KACrC,kBAAgB,MAAA,kBAAA,CAAkB,CAAC;;KAEpC,SAAA,cAiGM,CAjGN,eAAA,mBAiGM,OAjGN,WAiGM;MA/FA,SAAA;MAAJ,KAAI;MACJ,eAAY;KACJ,GAAA,MAAA,UAAA,GAAU;MAClB,6BAAA;MACA,wBAAA;MACC,OAAO,MAAA,aAAA;MACP,WAAS;KAEV,CAAA,GAAA,CAAA,mBAsFI,OAAA,EAtFE,OAAK,eAAE,aAAA,KAAY,EAAA,GAAA,CACd,QAAA,cAAX,UAAA,GAAA,mBAYM,OAZN,YAYM,CAXJ,YAUE,iBAAA;MATI,SAAA;MAAJ,KAAI;MACK,YAAA,YAAA;MAAA,uBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,YAAW,QAAA;MACpB,eAAY;MACZ,8BAAA;MACA,MAAK;MACJ,WAAW,QAAA;MACX,aAAa,0BAAA;MACd,MAAK;MACJ,WAAS;;;;;KASd,CAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAAA,mBAiEM,OAAA;MAhEJ,OAAK,eAAA,CAAC,OACE,QAAA,UAAO,KAAA,eAAA,CAAA;MACd,OAAK,eAAE,QAAA,UAAU,KAAA,IAAS,EAAA,WAAA,GAAmB,QAAA,kBAAiB,IAAA,CAAA;KAGvD,GAAA,CAAA,QAAA,WADR,UAAA,GAAA,mBAUM,OAAA;;MARJ,+BAAA;MACA,MAAK;MACJ,OAAK,eAAE,MAAA,sBAAA,CAAsB;KAE9B,GAAA,CAAA,WAGO,KAAA,QAAA,WAAA,CAAA,SAAA,CAFL,YAA0E,MAAA,qBAAA,GAAA;MAAxD,OAAM;MAA6B,eAAY;KACjE,CAAA,GAAA,mBAAyD,QAAA,MAAA,gBAAhD,MAAA,CAAA,CAAC,CAAA,yBAAA,UAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAIG,QAAA,MAAM,UAAM,OAAA,KAA7B,UAAA,GAAA,mBAIM,OAAA;;MAJsC,OAAK,eAAE,MAAA,sBAAA,CAAsB;KACvE,GAAA,CAAA,WAEO,KAAA,QAAA,SAAA,CAAA,SAAA,CADF,gBAAA,gBAAA,MAAA,CAAA,CAAC,CAAA,uBAAA,SAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,MAIR,UAAA,GAAA,YAyCS,MAAA,cAAA,GAAA;;MAvCN,IAAI;MACD,SAAA;MAAJ,KAAI;MACH,MAAM,MAAA,YAAA;MACN,MAAM,QAAA;MACN,OAAO,MAAM;MACb,YAAU,QAAA;MACV,yBAAuB,QAAA;MACvB,sBAAoB,QAAA;MACpB,qBAAiB,CAAG,QAAA;MACpB,SAAS,QAAA;MACT,cAAY,QAAA;MACZ,iBAAe,aAAA;MACf,kBAAgB,QAAA;MAChB,gBAAc,aAAA;MACF;MACZ,wBAAqB;;MAEX,SAAO,SAoBT,EApBa,MAAM,WAAI,CAC9B,WAmBO,KAAA,QAAA,QAAA;OAjBE;OACA;OACN,UAAU,eAAA,MAAe,IAAI,KAAK,GAAG;MAJxC,SAmBO,CAbL,mBAYM,OAZN,YAYM,CARK,CAAA,aAAA,SADT,UAAA,GAAA,mBAOO,QAPP,YAOO,CADY,eAAA,MAAe,IAAI,KAAK,GAAG,KAA5C,UAAA,GAAA,YAAqG,MAAA,aAAA,GAAA;;OAAtD,OAAM;MAEvD,CAAA,KAAA,mBAAA,IAAA,IAAA,CAAA,CAAA,KAAA,mBAAA,IAAA,IAAA,GAAA,mBAA8C,QAA9C,aAA8C,gBAApB,KAAK,KAAK,GAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;;;;;;KAzFtC,CAAA,EAAA,GAAA,CAAA,CAAA,GAAA,CAAA,CAAA,GAAA,EAAA,GAAA,CAAA,CAAA,OAAA,MAAA,IAAA,CAAI,CAAA,CAAA,CAAA,CAAA;;;;;;;;;;GAlIU,GAAA,EAAA,IAAA,CAAA,CAAA,MAAA,aAAA,GAAA;IAAA,SAAA;IAAc,SAAW,MAAA,IAAA;IAAI,SAAW;GAAmB,CAAA,CAAA,CAAA"}
@@ -1,33 +0,0 @@
1
- import type { ComputedRef, Ref } from 'vue';
2
- import { useVirtualList } from '../../../composables/useVirtualList';
3
- import type { GrAutocompleteOption, GrAutocompleteValue } from '../GrAutocomplete.vue';
4
- /**
5
- * Виртуализация панели `GrAutocomplete`.
6
- *
7
- * Набор — `[«Add …»?] + effectiveOptions`, тот же, по которому ходит клавиатура.
8
- * Иначе верхняя распорка вытолкнула бы строку «Add …» вниз: она отрисована
9
- * внутри listbox'а первой и является полноценной опцией. Отсюда `addOffset`,
10
- * который сдвигает окно виртуализатора относительно индексов в списке опций.
11
- */
12
- export interface UseAutocompleteVirtualOptions<TValue extends GrAutocompleteValue> {
13
- /** Контейнер списка: по нему считается окно и замеряются строки. */
14
- listboxEl: Ref<HTMLElement | null>;
15
- effectiveOptions: ComputedRef<GrAutocompleteOption<TValue>[]>;
16
- canAddCustom: ComputedRef<boolean>;
17
- virtual: () => boolean;
18
- dropdownMaxHeight: () => number;
19
- }
20
- export interface AutocompleteVirtual<TValue extends GrAutocompleteValue> {
21
- /** Сдвиг окна из-за строки «Add …»: она идёт нулевым элементом набора. */
22
- addOffset: ComputedRef<number>;
23
- virtualCount: ComputedRef<number>;
24
- virtualizer: ReturnType<typeof useVirtualList>;
25
- showAddOption: ComputedRef<boolean>;
26
- renderedOptions: ComputedRef<Array<{
27
- option: GrAutocompleteOption<TValue>;
28
- index: number;
29
- }>>;
30
- optionSetProps: (virtualIndex: number) => Record<string, number> | undefined;
31
- listboxStyle: ComputedRef<Record<string, string>>;
32
- }
33
- export declare function useAutocompleteVirtual<TValue extends GrAutocompleteValue>(options: UseAutocompleteVirtualOptions<TValue>): AutocompleteVirtual<TValue>;