@feugene/granularity 0.16.0 → 0.18.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 (343) hide show
  1. package/dist/chunks/{config-Zc_bUvZY2.js → config-BDfTXHo12.js} +1 -1
  2. package/dist/chunks/{config-Zc_bUvZY2.js.map → config-BDfTXHo12.js.map} +1 -1
  3. package/dist/chunks/config-BE6n20np2.js.map +1 -0
  4. package/dist/chunks/{config-CpwwkFBO.js → config-Baj7Wvx-.js} +1 -1
  5. package/dist/chunks/{config-CpwwkFBO.js.map → config-Baj7Wvx-.js.map} +1 -1
  6. package/dist/chunks/config-BoNR7_PD2.js.map +1 -0
  7. package/dist/chunks/{config-DxCTVBfx.js → config-BsPDQ0dS.js} +2 -2
  8. package/dist/chunks/config-BsPDQ0dS.js.map +1 -0
  9. package/dist/chunks/config-CN2ULSQL.js.map +1 -0
  10. package/dist/chunks/{config-Cw6TDzWv2.js → config-COpuWGr_.js} +1 -1
  11. package/dist/chunks/config-COpuWGr_.js.map +1 -0
  12. package/dist/chunks/config-D2aNP7Es.js +70 -0
  13. package/dist/chunks/config-D2aNP7Es.js.map +1 -0
  14. package/dist/chunks/config-D94Z9po5.js.map +1 -0
  15. package/dist/chunks/{config-B-g6lT19.js → config-DA6SnEoy.js} +5 -2
  16. package/dist/chunks/config-DA6SnEoy.js.map +1 -0
  17. package/dist/chunks/config-DCFvmHEv2.js.map +1 -0
  18. package/dist/chunks/config-DEvsMTQE.js +150 -0
  19. package/dist/chunks/config-DEvsMTQE.js.map +1 -0
  20. package/dist/chunks/{config-CvC0sX8p.js → config-MRvhUl-O.js} +1 -1
  21. package/dist/chunks/{config-CvC0sX8p.js.map → config-MRvhUl-O.js.map} +1 -1
  22. package/dist/chunks/config-ScuvHw6k2.js +42 -0
  23. package/dist/chunks/config-ScuvHw6k2.js.map +1 -0
  24. package/dist/chunks/config-T3qdQBgU2.js.map +1 -0
  25. package/dist/chunks/config-eXB87DOi.js.map +1 -0
  26. package/dist/chunks/{config-D8tSR2uS.js → config-gvq_hWNM.js} +1 -1
  27. package/dist/chunks/{config-D8tSR2uS.js.map → config-gvq_hWNM.js.map} +1 -1
  28. package/dist/chunks/context-BSYR7RZs.js.map +1 -1
  29. package/dist/chunks/{en-B3xMeswz.js → en-COdzxgAX.js} +30 -5
  30. package/dist/chunks/en-COdzxgAX.js.map +1 -0
  31. package/dist/chunks/{es-CA-mkU--.js → es-ClqJ-4hr.js} +30 -5
  32. package/dist/chunks/es-ClqJ-4hr.js.map +1 -0
  33. package/dist/chunks/{es-Bv8vvqdT.js → es-DGMHwknJ.js} +3 -3
  34. package/dist/chunks/{es-Bv8vvqdT.js.map → es-DGMHwknJ.js.map} +1 -1
  35. package/dist/chunks/grKbdStyles-CeZhGQHr.js +43 -0
  36. package/dist/chunks/grKbdStyles-CeZhGQHr.js.map +1 -0
  37. package/dist/chunks/{grTextareaStyles-CWI2SqC8.js → grTextareaStyles-iOcHuVMM.js} +2 -2
  38. package/dist/chunks/{grTextareaStyles-CWI2SqC8.js.map → grTextareaStyles-iOcHuVMM.js.map} +1 -1
  39. package/dist/chunks/{granular-provider-CtrXGa7c.js → granular-provider-B9nXQCMu.js} +18 -16
  40. package/dist/chunks/granular-provider-B9nXQCMu.js.map +1 -0
  41. package/dist/chunks/{keyboard-zYvvyHd4.js → keyboard-DE2yhz_b.js} +10 -1
  42. package/dist/chunks/keyboard-DE2yhz_b.js.map +1 -0
  43. package/dist/chunks/{optionFilter-BVY988pC.js → optionFilter-DYw9XPPx.js} +1 -71
  44. package/dist/chunks/optionFilter-DYw9XPPx.js.map +1 -0
  45. package/dist/chunks/{useOverlayLayer-BupuP_hs.js → overlayStack-C8cfsqXa.js} +11 -61
  46. package/dist/chunks/overlayStack-C8cfsqXa.js.map +1 -0
  47. package/dist/chunks/{ru-COWxgh2A.js → ru-9z8ix45c.js} +30 -5
  48. package/dist/chunks/ru-9z8ix45c.js.map +1 -0
  49. package/dist/chunks/useDragSort-0l47h4yb.js +265 -0
  50. package/dist/chunks/useDragSort-0l47h4yb.js.map +1 -0
  51. package/dist/chunks/{useModalOverlay-DCM4d3yA.js → useModalOverlay-BTq-0ImG.js} +1 -1
  52. package/dist/chunks/{useModalOverlay-DCM4d3yA.js.map → useModalOverlay-BTq-0ImG.js.map} +1 -1
  53. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-CQ9T7Lly.js → GrAutocomplete-CPEQxmLZ.js} +4 -3
  54. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-CPEQxmLZ.js.map +1 -0
  55. package/dist/components/GrAutocomplete/index.js +1 -1
  56. package/dist/components/GrAutocomplete/styles.css +1 -1
  57. package/dist/components/GrColorPicker/chunks/{GrColorPicker-bnYBRGk8.js → GrColorPicker-DAdQ-Gc3.js} +4 -4
  58. package/dist/components/GrColorPicker/chunks/{GrColorPicker-bnYBRGk8.js.map → GrColorPicker-DAdQ-Gc3.js.map} +1 -1
  59. package/dist/components/GrColorPicker/index.js +2 -2
  60. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-MWDYDPNC.js → GrCommandPalette-DMeSqkEv.js} +6 -7
  61. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-DMeSqkEv.js.map +1 -0
  62. package/dist/components/GrCommandPalette/index.js +1 -1
  63. package/dist/components/GrCommandPalette/styles.css +1 -1
  64. package/dist/components/GrConfigProvider/index.js +2 -2
  65. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-DaQmlp1_.js → GrConfirmDialog-hUTi-GdJ.js} +1 -1
  66. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-DaQmlp1_.js.map → GrConfirmDialog-hUTi-GdJ.js.map} +1 -1
  67. package/dist/components/GrConfirmDialog/index.js +1 -1
  68. package/dist/components/GrDataTable/chunks/{GrDataTable-DVFho9Cj.js → GrDataTable-DzaGLG3A.js} +495 -47
  69. package/dist/components/GrDataTable/chunks/GrDataTable-DzaGLG3A.js.map +1 -0
  70. package/dist/components/GrDataTable/index.js +2 -2
  71. package/dist/components/GrDialog/chunks/{GrDialog-AE1gIZuz.js → GrDialog-MD9Fzy9C.js} +1 -1
  72. package/dist/components/GrDialog/chunks/{GrDialog-AE1gIZuz.js.map → GrDialog-MD9Fzy9C.js.map} +1 -1
  73. package/dist/components/GrDialog/index.js +1 -1
  74. package/dist/components/GrDialogService/chunks/{GrDialogService-B4DYWDkA.js → GrDialogService-DtgUijMj.js} +2 -2
  75. package/dist/components/GrDialogService/chunks/{GrDialogService-B4DYWDkA.js.map → GrDialogService-DtgUijMj.js.map} +1 -1
  76. package/dist/components/GrDialogService/index.js +1 -1
  77. package/dist/components/GrDrawer/chunks/{GrDrawer-DQwi6aRw.js → GrDrawer-DWHdZZzW.js} +2 -2
  78. package/dist/components/GrDrawer/chunks/{GrDrawer-DQwi6aRw.js.map → GrDrawer-DWHdZZzW.js.map} +1 -1
  79. package/dist/components/GrDrawer/index.js +2 -2
  80. package/dist/components/GrDropdown/chunks/{GrDropdown-BLng6V1m.js → GrDropdown-0tJK01Kq.js} +2 -2
  81. package/dist/components/GrDropdown/chunks/{GrDropdown-BLng6V1m.js.map → GrDropdown-0tJK01Kq.js.map} +1 -1
  82. package/dist/components/GrDropdown/index.js +1 -1
  83. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BImk2Vs7.js → GrDropdownMenu-VPPrpCoA.js} +1 -1
  84. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-BImk2Vs7.js.map → GrDropdownMenu-VPPrpCoA.js.map} +1 -1
  85. package/dist/components/GrDropdownMenu/index.js +1 -1
  86. package/dist/components/GrFileUpload/chunks/{GrFileUpload-D0B-BEsd.js → GrFileUpload-DuDzC43S.js} +2 -2
  87. package/dist/components/GrFileUpload/chunks/{GrFileUpload-D0B-BEsd.js.map → GrFileUpload-DuDzC43S.js.map} +1 -1
  88. package/dist/components/GrFileUpload/index.js +1 -1
  89. package/dist/components/GrImageViewer/chunks/{GrImageViewer-BeCnE8XQ.js → GrImageViewer-DE7MBbF8.js} +46 -22
  90. package/dist/components/GrImageViewer/chunks/GrImageViewer-DE7MBbF8.js.map +1 -0
  91. package/dist/components/GrImageViewer/index.js +1 -1
  92. package/dist/components/GrInput/chunks/{GrInput-DD2gYdqS.js → GrInput-2wd7Crs0.js} +1 -1
  93. package/dist/components/GrInput/chunks/GrInput-2wd7Crs0.js.map +1 -0
  94. package/dist/components/GrInput/index.js +1 -1
  95. package/dist/components/GrInputTag/chunks/{GrInputTag-DmNunixz.js → GrInputTag-CyV2eY7Z.js} +20 -33
  96. package/dist/components/GrInputTag/chunks/GrInputTag-CyV2eY7Z.js.map +1 -0
  97. package/dist/components/GrInputTag/index.js +1 -1
  98. package/dist/components/GrKbd/chunks/{GrKbd-DRFPvW3G.js → GrKbd-DU2lBkRV.js} +218 -52
  99. package/dist/components/GrKbd/chunks/GrKbd-DU2lBkRV.js.map +1 -0
  100. package/dist/components/GrKbd/index.js +3 -3
  101. package/dist/components/GrModal/chunks/{GrModal-B8I78T0N.js → GrModal-BbhcsDQ8.js} +1 -1
  102. package/dist/components/GrModal/chunks/{GrModal-B8I78T0N.js.map → GrModal-BbhcsDQ8.js.map} +1 -1
  103. package/dist/components/GrModal/index.js +1 -1
  104. package/dist/components/GrPagination/chunks/{GrPagination-B6N0QZBf.js → GrPagination-waKhxBP7.js} +4 -4
  105. package/dist/components/GrPagination/chunks/GrPagination-waKhxBP7.js.map +1 -0
  106. package/dist/components/GrPagination/index.js +1 -1
  107. package/dist/components/GrPopover/chunks/{GrPopover-B1eRCOoO.js → GrPopover-DuqeoFaI.js} +1 -1
  108. package/dist/components/GrPopover/chunks/{GrPopover-B1eRCOoO.js.map → GrPopover-DuqeoFaI.js.map} +1 -1
  109. package/dist/components/GrPopover/index.js +1 -1
  110. package/dist/components/GrProgressBar/chunks/{GrProgressBar-BiHnaitu.js → GrProgressBar-xwbNM9QB.js} +1 -1
  111. package/dist/components/GrProgressBar/chunks/GrProgressBar-xwbNM9QB.js.map +1 -0
  112. package/dist/components/GrProgressBar/index.js +1 -1
  113. package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-CTogjcHz.js → GrProgressCircle-B8olXRo5.js} +1 -1
  114. package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-CTogjcHz.js.map → GrProgressCircle-B8olXRo5.js.map} +1 -1
  115. package/dist/components/GrProgressCircle/index.js +2 -2
  116. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-Ct174NVD.js → GrPromptDialog-JVVqBsPY.js} +3 -3
  117. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-Ct174NVD.js.map → GrPromptDialog-JVVqBsPY.js.map} +1 -1
  118. package/dist/components/GrPromptDialog/index.js +1 -1
  119. package/dist/components/GrRadio/chunks/{GrRadio-DksDro_U.js → GrRadio-DWiRaMzt.js} +8 -32
  120. package/dist/components/GrRadio/chunks/GrRadio-DWiRaMzt.js.map +1 -0
  121. package/dist/components/GrRadio/index.js +1 -1
  122. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-BOIhejE6.js → GrRadioGroup-DIuBw0wk.js} +34 -27
  123. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-DIuBw0wk.js.map +1 -0
  124. package/dist/components/GrRadioGroup/index.js +1 -1
  125. package/dist/components/GrRating/chunks/{GrRating-JrHXz0Rv.js → GrRating-LarIiwJL.js} +2 -2
  126. package/dist/components/GrRating/chunks/GrRating-LarIiwJL.js.map +1 -0
  127. package/dist/components/GrRating/index.js +2 -2
  128. package/dist/components/GrSegmented/chunks/{GrSegmented-BQIlH5KI.js → GrSegmented-CQw3ijqa.js} +47 -65
  129. package/dist/components/GrSegmented/chunks/GrSegmented-CQw3ijqa.js.map +1 -0
  130. package/dist/components/GrSegmented/index.js +1 -1
  131. package/dist/components/GrSelect/chunks/{GrSelect-aqkPCqjd.js → GrSelect-DAdu044K.js} +4 -3
  132. package/dist/components/GrSelect/chunks/GrSelect-DAdu044K.js.map +1 -0
  133. package/dist/components/GrSelect/index.js +1 -1
  134. package/dist/components/GrSlider/chunks/{GrSlider-DkU9IQSX.js → GrSlider-CyhVsNKn.js} +21 -34
  135. package/dist/components/GrSlider/chunks/GrSlider-CyhVsNKn.js.map +1 -0
  136. package/dist/components/GrSlider/index.js +2 -2
  137. package/dist/components/GrSortableList/chunks/GrSortableList-BefVfWKh.js +276 -0
  138. package/dist/components/GrSortableList/chunks/GrSortableList-BefVfWKh.js.map +1 -0
  139. package/dist/components/GrSortableList/index.js +3 -0
  140. package/dist/components/GrSplitter/chunks/{GrSplitter-7To8jbJ8.js → GrSplitter-BzxVQwbY.js} +17 -37
  141. package/dist/components/GrSplitter/chunks/GrSplitter-BzxVQwbY.js.map +1 -0
  142. package/dist/components/GrSplitter/index.js +2 -2
  143. package/dist/components/GrStatistic/chunks/{GrStatistic-CttyoYPT.js → GrStatistic-J4qLs3TH.js} +1 -1
  144. package/dist/components/GrStatistic/chunks/{GrStatistic-CttyoYPT.js.map → GrStatistic-J4qLs3TH.js.map} +1 -1
  145. package/dist/components/GrStatistic/index.js +2 -2
  146. package/dist/components/GrSwitch/chunks/{GrSwitch-B9TYbiih.js → GrSwitch-DpyvVrZG.js} +1 -1
  147. package/dist/components/GrSwitch/chunks/{GrSwitch-B9TYbiih.js.map → GrSwitch-DpyvVrZG.js.map} +1 -1
  148. package/dist/components/GrSwitch/index.js +2 -2
  149. package/dist/components/GrTabPanels/index.js +1 -1
  150. package/dist/components/GrTable/chunks/{GrTable-BB-mI_NM.js → GrTable-BfqgwETQ.js} +7 -1
  151. package/dist/components/GrTable/chunks/GrTable-BfqgwETQ.js.map +1 -0
  152. package/dist/components/GrTable/index.js +1 -1
  153. package/dist/components/GrTabs/chunks/{GrTabs-B8CDq2D9.js → GrTabs-TeXaU5Uh.js} +50 -61
  154. package/dist/components/GrTabs/chunks/GrTabs-TeXaU5Uh.js.map +1 -0
  155. package/dist/components/GrTabs/index.js +1 -1
  156. package/dist/components/GrTextarea/chunks/{GrTextarea-DUh5Tlo4.js → GrTextarea-DSvd1nSy.js} +1 -1
  157. package/dist/components/GrTextarea/chunks/{GrTextarea-DUh5Tlo4.js.map → GrTextarea-DSvd1nSy.js.map} +1 -1
  158. package/dist/components/GrTextarea/index.js +2 -2
  159. package/dist/components/GrTimeline/chunks/{GrTimeline-CE9b3s18.js → GrTimeline-B-h2Yanw.js} +1 -1
  160. package/dist/components/GrTimeline/chunks/{GrTimeline-CE9b3s18.js.map → GrTimeline-B-h2Yanw.js.map} +1 -1
  161. package/dist/components/GrTimeline/index.js +2 -2
  162. package/dist/components/GrToaster/chunks/{GrToaster-BKQy3Srm.js → GrToaster-Ct-39hga.js} +113 -12
  163. package/dist/components/GrToaster/chunks/GrToaster-Ct-39hga.js.map +1 -0
  164. package/dist/components/GrToaster/index.js +2 -2
  165. package/dist/components/GrToaster/styles.css +1 -1
  166. package/dist/components/GrTooltip/chunks/{GrTooltip-DEbejfhA.js → GrTooltip-xAcqs0bP.js} +1 -1
  167. package/dist/components/GrTooltip/chunks/{GrTooltip-DEbejfhA.js.map → GrTooltip-xAcqs0bP.js.map} +1 -1
  168. package/dist/components/GrTooltip/index.js +2 -2
  169. package/dist/components/GrTree/chunks/{GrTree-wfdbvygw.js → GrTree-CaYK8dGZ.js} +124 -92
  170. package/dist/components/GrTree/chunks/GrTree-CaYK8dGZ.js.map +1 -0
  171. package/dist/components/GrTree/index.js +1 -1
  172. package/dist/components/GrTree/styles.css +1 -1
  173. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-lLWmAMtI.js → GrTreeSelect-DZp7CqqW.js} +4 -4
  174. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-lLWmAMtI.js.map → GrTreeSelect-DZp7CqqW.js.map} +1 -1
  175. package/dist/components/GrTreeSelect/index.js +2 -2
  176. package/dist/composables/useComboboxNavigation.js +71 -0
  177. package/dist/composables/useComboboxNavigation.js.map +1 -0
  178. package/dist/composables/useDismissible.js +1 -1
  179. package/dist/composables/useDragGesture.js +55 -0
  180. package/dist/composables/useDragGesture.js.map +1 -0
  181. package/dist/composables/useDragSort.js +2 -0
  182. package/dist/composables/useFloating.js +22 -1
  183. package/dist/composables/useFloating.js.map +1 -1
  184. package/dist/composables/useGrComponentConfig.js +2 -0
  185. package/dist/composables/useGranularityTranslations.js +2 -0
  186. package/dist/composables/useOverlayLayer.js +64 -1
  187. package/dist/composables/useOverlayLayer.js.map +1 -0
  188. package/dist/composables/useRovingFocus.js +150 -0
  189. package/dist/composables/useRovingFocus.js.map +1 -0
  190. package/dist/directives/hotkey.js +13 -7
  191. package/dist/directives/hotkey.js.map +1 -1
  192. package/dist/granular-provider-node.js +1 -1
  193. package/dist/granular-provider.js +1 -1
  194. package/dist/i18n/all.js +1 -1
  195. package/dist/i18n/index.js +1 -1
  196. package/dist/index.js +67 -58
  197. package/dist/tokens.js +84 -0
  198. package/dist/tokens.js.map +1 -1
  199. package/dist/types/src/components/GrAlert/defaults.d.ts +1 -1
  200. package/dist/types/src/components/GrAutocomplete/defaults.d.ts +1 -1
  201. package/dist/types/src/components/GrAvatar/defaults.d.ts +1 -1
  202. package/dist/types/src/components/GrBadge/defaults.d.ts +1 -1
  203. package/dist/types/src/components/GrBottomNav/defaults.d.ts +1 -1
  204. package/dist/types/src/components/GrBreadcrumbs/defaults.d.ts +1 -1
  205. package/dist/types/src/components/GrButton/defaults.d.ts +1 -1
  206. package/dist/types/src/components/GrCard/defaults.d.ts +1 -1
  207. package/dist/types/src/components/GrCheckbox/defaults.d.ts +1 -1
  208. package/dist/types/src/components/GrCheckboxGroup/defaults.d.ts +1 -1
  209. package/dist/types/src/components/GrCollapse/defaults.d.ts +1 -1
  210. package/dist/types/src/components/GrColorPicker/defaults.d.ts +1 -1
  211. package/dist/types/src/components/GrColorPicker/grColorPickerStyles.d.ts +2 -2
  212. package/dist/types/src/components/GrCommandPalette/defaults.d.ts +1 -1
  213. package/dist/types/src/components/GrConfigProvider/context.d.ts +6 -22
  214. package/dist/types/src/components/GrConfigProvider/index.d.ts +1 -1
  215. package/dist/types/src/components/GrConfirmDialog/defaults.d.ts +1 -1
  216. package/dist/types/src/components/GrDataTable/GrDataTable.vue.d.ts +53 -0
  217. package/dist/types/src/components/GrDataTable/defaults.d.ts +1 -1
  218. package/dist/types/src/components/GrDataTable/grDataTableStyles.d.ts +39 -0
  219. package/dist/types/src/components/GrDialog/defaults.d.ts +1 -1
  220. package/dist/types/src/components/GrDivider/defaults.d.ts +1 -1
  221. package/dist/types/src/components/GrDrawer/defaults.d.ts +1 -1
  222. package/dist/types/src/components/GrEmptyState/defaults.d.ts +1 -1
  223. package/dist/types/src/components/GrFileUpload/defaults.d.ts +1 -1
  224. package/dist/types/src/components/GrFormField/defaults.d.ts +1 -1
  225. package/dist/types/src/components/GrFormFile/defaults.d.ts +1 -1
  226. package/dist/types/src/components/GrFormSection/defaults.d.ts +1 -1
  227. package/dist/types/src/components/GrIcon/defaults.d.ts +1 -1
  228. package/dist/types/src/components/GrImageViewer/composables/usePointerGestures.d.ts +1 -0
  229. package/dist/types/src/components/GrImageViewer/composables/useZoomPan.d.ts +1 -2
  230. package/dist/types/src/components/GrInput/defaults.d.ts +1 -1
  231. package/dist/types/src/components/GrInputTag/defaults.d.ts +1 -1
  232. package/dist/types/src/components/GrKbd/GrKbd.vue.d.ts +18 -3
  233. package/dist/types/src/components/GrKbd/defaults.d.ts +1 -1
  234. package/dist/types/src/components/GrKbd/grKbdStyles.d.ts +20 -3
  235. package/dist/types/src/components/GrKbd/index.d.ts +6 -0
  236. package/dist/types/src/components/GrLink/defaults.d.ts +1 -1
  237. package/dist/types/src/components/GrModal/defaults.d.ts +1 -1
  238. package/dist/types/src/components/GrNumberInput/defaults.d.ts +1 -1
  239. package/dist/types/src/components/GrPagination/defaults.d.ts +1 -1
  240. package/dist/types/src/components/GrPopover/GrPopover.vue.d.ts +1 -1
  241. package/dist/types/src/components/GrPopover/defaults.d.ts +1 -1
  242. package/dist/types/src/components/GrProgressBar/defaults.d.ts +1 -1
  243. package/dist/types/src/components/GrProgressCircle/defaults.d.ts +1 -1
  244. package/dist/types/src/components/GrProgressCircle/grProgressCircleStyles.d.ts +1 -1
  245. package/dist/types/src/components/GrPromptDialog/defaults.d.ts +1 -1
  246. package/dist/types/src/components/GrRadio/defaults.d.ts +1 -1
  247. package/dist/types/src/components/GrRadio/grRadioGroupContext.d.ts +12 -4
  248. package/dist/types/src/components/GrRadioGroup/defaults.d.ts +1 -1
  249. package/dist/types/src/components/GrRating/defaults.d.ts +1 -1
  250. package/dist/types/src/components/GrSegmented/defaults.d.ts +1 -1
  251. package/dist/types/src/components/GrSelect/defaults.d.ts +1 -1
  252. package/dist/types/src/components/GrSlider/defaults.d.ts +1 -1
  253. package/dist/types/src/components/GrSortableList/GrSortableList.vue.d.ts +68 -0
  254. package/dist/types/src/components/GrSortableList/config.d.ts +1 -0
  255. package/dist/types/src/components/GrSortableList/grSortableListStyles.d.ts +38 -0
  256. package/dist/types/src/components/GrSortableList/index.d.ts +9 -0
  257. package/dist/types/src/components/GrSortableList/safelist.d.ts +1 -0
  258. package/dist/types/src/components/GrSplitter/defaults.d.ts +1 -1
  259. package/dist/types/src/components/GrStatistic/defaults.d.ts +1 -1
  260. package/dist/types/src/components/GrStatistic/grStatisticStyles.d.ts +1 -1
  261. package/dist/types/src/components/GrSwitch/defaults.d.ts +1 -1
  262. package/dist/types/src/components/GrTable/GrTable.vue.d.ts +13 -0
  263. package/dist/types/src/components/GrTable/defaults.d.ts +1 -1
  264. package/dist/types/src/components/GrTabs/defaults.d.ts +1 -1
  265. package/dist/types/src/components/GrTextarea/defaults.d.ts +1 -1
  266. package/dist/types/src/components/GrTextarea/grTextareaStyles.d.ts +2 -2
  267. package/dist/types/src/components/GrTimeline/defaults.d.ts +1 -1
  268. package/dist/types/src/components/GrTimeline/grTimelineStyles.d.ts +1 -1
  269. package/dist/types/src/components/GrToaster/GrToaster.vue.d.ts +8 -0
  270. package/dist/types/src/components/GrToaster/grToasterStyles.d.ts +27 -0
  271. package/dist/types/src/components/GrTooltip/defaults.d.ts +1 -1
  272. package/dist/types/src/components/GrTree/defaults.d.ts +1 -1
  273. package/dist/types/src/components/GrTree/grTreeInteractionContext.d.ts +0 -1
  274. package/dist/types/src/components/GrTreeSelect/defaults.d.ts +1 -1
  275. package/dist/types/src/components/shared/hotkey.d.ts +7 -15
  276. package/dist/types/src/components/shared/hotkeyTokens.d.ts +37 -0
  277. package/dist/types/src/composables/internal/dragSortGeometry.d.ts +59 -0
  278. package/dist/types/src/composables/internal/overlayStack.d.ts +11 -0
  279. package/dist/types/src/composables/useDragGesture.d.ts +63 -0
  280. package/dist/types/src/composables/useDragSort.d.ts +80 -0
  281. package/dist/types/src/composables/useFloating.d.ts +5 -1
  282. package/dist/types/src/composables/useGrComponentConfig.d.ts +41 -0
  283. package/dist/types/src/composables/useGranularityTranslations.d.ts +13 -0
  284. package/dist/types/src/composables/useRovingFocus.d.ts +108 -0
  285. package/dist/types/src/granular-provider/shared.d.ts +1 -0
  286. package/dist/types/src/i18n/messages/en.d.ts +48 -0
  287. package/dist/types/src/i18n/messages/es.d.ts +48 -0
  288. package/dist/types/src/i18n/messages/ru.d.ts +48 -0
  289. package/dist/types/src/index.d.ts +12 -0
  290. package/dist/types/src/internal/keyboard.d.ts +6 -0
  291. package/dist/web-types.json +201 -3
  292. package/package.json +31 -3
  293. package/dist/chunks/config-B-g6lT19.js.map +0 -1
  294. package/dist/chunks/config-BE6n20np.js.map +0 -1
  295. package/dist/chunks/config-BNfQwyL4.js +0 -97
  296. package/dist/chunks/config-BNfQwyL4.js.map +0 -1
  297. package/dist/chunks/config-BoNR7_PD.js.map +0 -1
  298. package/dist/chunks/config-CN2ULSQL2.js.map +0 -1
  299. package/dist/chunks/config-Cw6TDzWv2.js.map +0 -1
  300. package/dist/chunks/config-D94Z9po52.js.map +0 -1
  301. package/dist/chunks/config-DCFvmHEv.js.map +0 -1
  302. package/dist/chunks/config-DxCTVBfx.js.map +0 -1
  303. package/dist/chunks/config-LGrZIdaZ.js +0 -21
  304. package/dist/chunks/config-LGrZIdaZ.js.map +0 -1
  305. package/dist/chunks/config-T3qdQBgU.js.map +0 -1
  306. package/dist/chunks/config-eXB87DOi2.js.map +0 -1
  307. package/dist/chunks/en-B3xMeswz.js.map +0 -1
  308. package/dist/chunks/es-CA-mkU--.js.map +0 -1
  309. package/dist/chunks/grKbdStyles-DAoxiytu.js +0 -31
  310. package/dist/chunks/grKbdStyles-DAoxiytu.js.map +0 -1
  311. package/dist/chunks/granular-provider-CtrXGa7c.js.map +0 -1
  312. package/dist/chunks/keyboard-zYvvyHd4.js.map +0 -1
  313. package/dist/chunks/optionFilter-BVY988pC.js.map +0 -1
  314. package/dist/chunks/ru-COWxgh2A.js.map +0 -1
  315. package/dist/chunks/useOverlayLayer-BupuP_hs.js.map +0 -1
  316. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-CQ9T7Lly.js.map +0 -1
  317. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-MWDYDPNC.js.map +0 -1
  318. package/dist/components/GrDataTable/chunks/GrDataTable-DVFho9Cj.js.map +0 -1
  319. package/dist/components/GrImageViewer/chunks/GrImageViewer-BeCnE8XQ.js.map +0 -1
  320. package/dist/components/GrInput/chunks/GrInput-DD2gYdqS.js.map +0 -1
  321. package/dist/components/GrInputTag/chunks/GrInputTag-DmNunixz.js.map +0 -1
  322. package/dist/components/GrKbd/chunks/GrKbd-DRFPvW3G.js.map +0 -1
  323. package/dist/components/GrPagination/chunks/GrPagination-B6N0QZBf.js.map +0 -1
  324. package/dist/components/GrProgressBar/chunks/GrProgressBar-BiHnaitu.js.map +0 -1
  325. package/dist/components/GrRadio/chunks/GrRadio-DksDro_U.js.map +0 -1
  326. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-BOIhejE6.js.map +0 -1
  327. package/dist/components/GrRating/chunks/GrRating-JrHXz0Rv.js.map +0 -1
  328. package/dist/components/GrSegmented/chunks/GrSegmented-BQIlH5KI.js.map +0 -1
  329. package/dist/components/GrSelect/chunks/GrSelect-aqkPCqjd.js.map +0 -1
  330. package/dist/components/GrSlider/chunks/GrSlider-DkU9IQSX.js.map +0 -1
  331. package/dist/components/GrSplitter/chunks/GrSplitter-7To8jbJ8.js.map +0 -1
  332. package/dist/components/GrTable/chunks/GrTable-BB-mI_NM.js.map +0 -1
  333. package/dist/components/GrTabs/chunks/GrTabs-B8CDq2D9.js.map +0 -1
  334. package/dist/components/GrToaster/chunks/GrToaster-BKQy3Srm.js.map +0 -1
  335. package/dist/components/GrTree/chunks/GrTree-wfdbvygw.js.map +0 -1
  336. /package/dist/chunks/{config-BE6n20np.js → config-BE6n20np2.js} +0 -0
  337. /package/dist/chunks/{config-BoNR7_PD.js → config-BoNR7_PD2.js} +0 -0
  338. /package/dist/chunks/{config-CN2ULSQL2.js → config-CN2ULSQL.js} +0 -0
  339. /package/dist/chunks/{config-D94Z9po52.js → config-D94Z9po5.js} +0 -0
  340. /package/dist/chunks/{config-DCFvmHEv.js → config-DCFvmHEv2.js} +0 -0
  341. /package/dist/chunks/{config-T3qdQBgU.js → config-T3qdQBgU2.js} +0 -0
  342. /package/dist/chunks/{config-eXB87DOi2.js → config-eXB87DOi.js} +0 -0
  343. /package/dist/types/src/composables/{internal/useComboboxNavigation.d.ts → useComboboxNavigation.d.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { t as x_default } from "../../../chunks/x-2KXnqxiD.js";
2
2
  import { a as useGrComponentProp, o as useGrComponentSize } from "../../../chunks/context-BSYR7RZs.js";
3
3
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
4
- import { n as isComposingEvent } from "../../../chunks/keyboard-zYvvyHd4.js";
4
+ import { r as isComposingEvent } from "../../../chunks/keyboard-DE2yhz_b.js";
5
5
  import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-BvA2ZGXP.js";
6
6
  import { n as useGrFormFieldContext } from "../../../chunks/context-DdNIxa1w.js";
7
7
  import { useGrFormControl } from "../../../composables/useGrFormControl.js";
@@ -10,6 +10,7 @@ import { t as useControlAddons } from "../../../chunks/useControlAddons-asUr10Pf
10
10
  import { t as GrBadge_default } from "../../GrBadge/chunks/GrBadge-B1tgqfGQ.js";
11
11
  import { t as loader_2_default } from "../../../chunks/loader-2-B1fdsdWW.js";
12
12
  import { useAnnouncer } from "../../../composables/useAnnouncer.js";
13
+ import { useRovingFocus } from "../../../composables/useRovingFocus.js";
13
14
  import { a as grInputTagWrapperClass, i as grInputTagInputClass, o as removeButtonClass, r as clearButtonClass, s as spinnerClass } from "../../../chunks/config-BN4sXYXn.js";
14
15
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, toDisplayString, unref, withCtx, withModifiers } from "vue";
15
16
  //#region src/components/GrInputTag/GrInputTag.vue?vue&type=script&setup=true&lang.ts
@@ -191,12 +192,21 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
191
192
  /**
192
193
  * Roving tabindex по крестикам: двадцать тегов давали двадцать одну остановку
193
194
  * `Tab`. В таб-порядке ровно один крестик, между ними ходят стрелками.
195
+ *
196
+ * Адресация индексом, а не значением тега: теги допускают повторы, и по
197
+ * значению два одинаковых чипа было бы не различить.
194
198
  */
195
- const focusedTagIndex = ref(0);
196
- const rovingIndex = computed(() => {
197
- const last = props.modelValue.length - 1;
198
- if (last < 0) return -1;
199
- return Math.min(Math.max(focusedTagIndex.value, 0), last);
199
+ const tagIndexes = computed(() => props.modelValue.map((_, index) => index));
200
+ const roving = useRovingFocus({
201
+ items: () => tagIndexes.value,
202
+ elementFor: (index) => removeEls.value[index],
203
+ orientation: () => "horizontal",
204
+ wrap: () => false,
205
+ onOverflow: (edge) => {
206
+ if (edge === "end") focus();
207
+ return true;
208
+ },
209
+ beforeFocus: () => nextTick()
200
210
  });
201
211
  async function focusTag(index) {
202
212
  const last = props.modelValue.length - 1;
@@ -204,10 +214,7 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
204
214
  focus();
205
215
  return;
206
216
  }
207
- const target = Math.min(Math.max(index, 0), last);
208
- focusedTagIndex.value = target;
209
- await nextTick();
210
- removeEls.value[target]?.focus();
217
+ await roving.focusKey(Math.min(Math.max(index, 0), last));
211
218
  }
212
219
  function escapeRegexChar(ch) {
213
220
  return ch.replace(REGEX_SPECIAL_CHAR_RE, "\\$&");
@@ -336,27 +343,7 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
336
343
  }
337
344
  }
338
345
  function onTagKeydown(e, index) {
339
- if (e.key === "ArrowLeft") {
340
- e.preventDefault();
341
- focusTag(index - 1);
342
- return;
343
- }
344
- if (e.key === "ArrowRight") {
345
- e.preventDefault();
346
- if (index === props.modelValue.length - 1) focus();
347
- else focusTag(index + 1);
348
- return;
349
- }
350
- if (e.key === "Home") {
351
- e.preventDefault();
352
- focusTag(0);
353
- return;
354
- }
355
- if (e.key === "End") {
356
- e.preventDefault();
357
- focusTag(props.modelValue.length - 1);
358
- return;
359
- }
346
+ if (roving.handleNavigationKeys(e)) return;
360
347
  if (e.key === "Delete" || e.key === "Backspace") {
361
348
  e.preventDefault();
362
349
  removeAtFromKeyboard(index);
@@ -445,12 +432,12 @@ var GrInputTag_default = /* @__PURE__ */ defineComponent({
445
432
  type: "button",
446
433
  class: normalizeClass(unref(removeButtonClass)),
447
434
  "aria-label": removeTagLabelFor(tag),
448
- tabindex: rovingIndex.value === i ? 0 : -1,
435
+ tabindex: unref(roving).tabindexFor(i),
449
436
  "data-gr-input-tag-remove": "",
450
437
  "data-testid": "gr-input-tag-remove",
451
438
  "data-index": i,
452
439
  onMousedown: _cache[0] || (_cache[0] = withModifiers(() => {}, ["prevent", "stop"])),
453
- onFocus: ($event) => focusedTagIndex.value = i,
440
+ onFocus: ($event) => unref(roving).setActive(i),
454
441
  onKeydown: ($event) => onTagKeydown($event, i),
455
442
  onClick: withModifiers(($event) => removeAt(i), ["stop"])
456
443
  }, [createVNode(GrIcon_default, { size: "sm" }, {
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrInputTag-CyV2eY7Z.js","names":[],"sources":["../../../../src/components/GrInputTag/GrInputTag.vue","../../../../src/components/GrInputTag/GrInputTag.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, ref } from 'vue'\n\nimport GrBadge from '../GrBadge/GrBadge.vue'\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\nimport IconLoader from '~icons/lucide/loader-2'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nimport {\n clearButtonClass,\n grInputTagInputClass,\n grInputTagWrapperClass,\n removeButtonClass,\n spinnerClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n /** Обязательное поле (`aria-required`). Складывается с `required` у `GrFormField`. */\n required?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n /**\n * Проверка тега перед добавлением. Может быть асинхронной (проверка на\n * сервере). Отклонённый тег не добавляется и уходит в событие `reject`.\n */\n beforeAdd?: (tag: string) => boolean | Promise<boolean>\n /** Кнопка «снести все теги». Настраивается через `GrConfigProvider`. */\n clearable?: boolean\n /** Фоновая работа: спиннер + `aria-busy`. Асинхронный `beforeAdd` поднимает его сам. */\n loading?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n /** i18n aria-label кнопки «снести все». */\n clearAllLabel?: string\n /**\n * Имя контрола, когда он используется вне `GrFormField`. Внутри поля имя даёт\n * связка с его `<label for>` — там проп не нужен. Без того и другого у инпута\n * нет доступного имени вовсе: placeholder именем не считается.\n */\n ariaLabel?: string\n /** Имя для нативной формы: hidden input на каждый тег. */\n name?: string\n /**\n * Ширины аддонов `prefix`/`suffix` — общий контракт контролов пакета\n * (`docs/form-controls.md`).\n */\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n prefixFixed?: boolean\n suffixFixed?: boolean\n}\n\nexport interface GrInputTagEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n /** Тег не прошёл `beforeAdd`. */\n (e: 'reject', value: string): void\n /** Набор снесён кнопкой «очистить». */\n (e: 'clear'): void\n /** Набор тегов изменился. */\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n state: 'default',\n // Настраивается через `GrConfigProvider`; дефолт — в резолвере ниже.\n size: undefined,\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n beforeAdd: undefined,\n clearable: undefined,\n loading: false,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: undefined,\n clearAllLabel: undefined,\n ariaLabel: undefined,\n name: undefined,\n },\n)\n\nconst emit = defineEmits<GrInputTagEmits>()\ndefineSlots<{\n /** Аддон слева от чипов: иконка, метка. */\n prefix?: () => any\n /** Аддон справа, перед кнопкой очистки. */\n suffix?: () => any\n /** Свой чип: `remove` снимает значение. */\n tag?: (props: { tag: string, index: number, remove: () => void }) => any\n}>()\n\n\n// Fallback из контекста `GrFormField` (id/aria-describedby/invalid/required) —\n// как у GrInput и GrSelect: контрол не знает про форму, знает только про поле.\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\n// Эффективные значения: локальный проп → `GrConfigProvider` → дефолт компонента.\n/** Ширина аддона по умолчанию — та же лестница, что у `GrInput`. */\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrInputTagSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrInputTag' })\n\n/**\n * Аддоны — флекс-соседи поля: оболочка тегового поля и так флекс-строка с\n * бейджами, поэтому места паддингом резервировать не нужно.\n */\nconst { hasPrefix, hasSuffix, prefixEl, suffixEl, prefixStyle, suffixStyle } = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => '0px',\n})\nconst resolvedClearable = useGrComponentProp('GrInputTag', 'clearable', () => props.clearable, false)\n\nconst { t } = useGranularityTranslations()\nconst resolvedClearAllLabel = computed(() => props.clearAllLabel ?? t('gr.inputTag.clearAll', 'Clear all tags'))\n\nfunction removeTagLabelFor(tag: string): string {\n // Безликое «Remove tag» на двадцати кнопках подряд не даёт выбрать нужную:\n // имя обязано называть сам тег.\n return props.removeTagLabel ?? t('gr.inputTag.removeTagNamed', 'Remove tag {tag}', { tag })\n}\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Внутри корня фокус ходит между полем и кнопками удаления чипов: без границы\n// каждое такое перемещение давало бы потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\nconst removeEls = ref<HTMLButtonElement[]>([])\n\nfunction setRemoveEl(index: number) {\n return (el: unknown): void => {\n removeEls.value[index] = el as HTMLButtonElement\n }\n}\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\nfunction blur(): void {\n inputEl.value?.blur()\n}\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !isDisabled.value && !isReadonly.value)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\n// Добавление, удаление и достигнутый предел — события, а не состояние виджета:\n// показывать их негде, объявить нужно. Это работа общего живого региона.\nconst { announce } = useAnnouncer()\n\n/**\n * Roving tabindex по крестикам: двадцать тегов давали двадцать одну остановку\n * `Tab`. В таб-порядке ровно один крестик, между ними ходят стрелками.\n *\n * Адресация индексом, а не значением тега: теги допускают повторы, и по\n * значению два одинаковых чипа было бы не различить.\n */\nconst tagIndexes = computed(() => props.modelValue.map((_, index) => index))\n\nconst roving = useRovingFocus<number>({\n items: () => tagIndexes.value,\n elementFor: index => removeEls.value[index],\n orientation: () => 'horizontal',\n // Ряд чипов — не кольцо: у него есть край, и за краем стоит поле ввода.\n wrap: () => false,\n onOverflow: (edge) => {\n // За последним чипом — поле ввода: продолжение того же ряда. Слева от\n // первого — начало строки, фокус остаётся на месте.\n if (edge === 'end') focus()\n return true\n },\n // Удаление чипа перерисовывает ряд: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\n\nasync function focusTag(index: number): Promise<void> {\n const last = props.modelValue.length - 1\n if (last < 0) {\n focus()\n return\n }\n\n await roving.focusKey(Math.min(Math.max(index, 0), last))\n}\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n const added: string[] = []\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n added.push(tag)\n emit('add', tag)\n }\n\n if (!added.length)\n return false\n\n emit('update:modelValue', next)\n emit('change', next)\n announce(added.length === 1\n ? t('gr.inputTag.added', 'Tag added: {tag}', { tag: added[0]! })\n : t('gr.inputTag.addedMany', '{count} tags added', { count: added.length }))\n\n return true\n}\n\n// Счётчик запуска: пока идёт асинхронная проверка, пользователь успевает нажать\n// Enter второй раз — результат устаревшей проверки дописывать нельзя.\nlet validationRun = 0\nconst validating = ref(false)\nconst isBusy = computed(() => props.loading || validating.value)\n\nasync function filterAllowed(tags: string[], run: number): Promise<string[] | null> {\n const check = props.beforeAdd\n if (!check)\n return tags\n\n const allowed: string[] = []\n\n for (const tag of tags) {\n const ok = await check(tag)\n if (run !== validationRun)\n return null\n\n if (ok)\n allowed.push(tag)\n else\n emit('reject', tag)\n }\n\n return allowed\n}\n\nasync function commitInput(): Promise<void> {\n if (!canEdit.value || !inputValue.value)\n return\n\n if (isMaxed.value) {\n announce(t('gr.inputTag.limitReached', 'Tag limit reached'))\n return\n }\n\n const raw = inputValue.value\n const tags = splitToTags(raw)\n if (!tags.length)\n return\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n const allowed = await filterAllowed(tags, run)\n\n if (run === validationRun)\n validating.value = false\n\n if (allowed === null || !allowed.length)\n return\n\n const changed = addMany(allowed)\n // Значение могло измениться, пока шла проверка: стирать чужой ввод нельзя.\n if (changed && props.clearInputOnAdd && inputValue.value === raw)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('change', next)\n emit('remove', removed, index)\n announce(t('gr.inputTag.removed', 'Tag removed: {tag}', { tag: removed }))\n}\n\n/** Удаление с клавиатуры: фокус переезжает на соседний чип, а не пропадает. */\nasync function removeAtFromKeyboard(index: number): Promise<void> {\n removeAt(index)\n await nextTick()\n\n if (props.modelValue.length === 0) {\n focus()\n return\n }\n\n await focusTag(Math.min(index, props.modelValue.length - 1))\n}\n\nfunction clearAll(): void {\n if (!canEdit.value || props.modelValue.length === 0)\n return\n\n emit('update:modelValue', [])\n emit('change', [])\n emit('clear')\n announce(t('gr.inputTag.cleared', 'All tags removed'))\n focus()\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n // Enter/сепаратор во время IME-композиции коммитят её, а не тег.\n if (isComposingEvent(e))\n return\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if (inputValue.value.length === 0 && props.modelValue.length > 0) {\n if (e.key === 'Backspace') {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n return\n }\n\n // Из пустого поля стрелка влево уводит на последний чип — дальше по чипам\n // работают те же стрелки, `Tab` для этого не нужен.\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n void focusTag(props.modelValue.length - 1)\n }\n }\n}\n\nfunction onTagKeydown(e: KeyboardEvent, index: number): void {\n if (roving.handleNavigationKeys(e)) {\n return\n }\n\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault()\n void removeAtFromKeyboard(index)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n void commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n void filterAllowed(tags, run).then((allowed) => {\n if (run === validationRun)\n validating.value = false\n\n if (allowed?.length)\n addMany(allowed)\n })\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: resolvedSize.value,\n state: props.state,\n invalid: isInvalid.value,\n disabled: isDisabled.value,\n })\n})\n\nconst inputClassName = computed(() => grInputTagInputClass(resolvedSize.value))\n\nconst showClearAll = computed(() => resolvedClearable.value && canEdit.value && props.modelValue.length > 0)\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n\ndefineExpose({ focus, blur, clear: clearAll })\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-input-tag\n data-testid=\"gr-input-tag\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <span\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-input-tag-prefix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"prefixStyle\"\n >\n <slot name=\"prefix\" />\n </span>\n\n <!-- Нативная форма: hidden на каждый тег — стандартная сериализация набора. -->\n <template v-if=\"name\">\n <input\n v-for=\"(tag, tagIndex) in modelValue\"\n :key=\"`hidden-${tagIndex}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"tag\"\n >\n </template>\n <!--\n `display: contents` — список нужен ради роли, а не ради раскладки: чипы\n обязаны переноситься в одном потоке с полем ввода.\n -->\n <span v-if=\"modelValue.length\" role=\"list\" class=\"contents\">\n <GrBadge\n v-for=\"(tag, i) in modelValue\"\n :key=\"`${tag}-${i}`\"\n role=\"listitem\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"tagSize\"\n :radius=\"tagRadius\"\n data-gr-input-tag-item\n data-testid=\"gr-input-tag-item\"\n :data-index=\"i\"\n >\n <span class=\"inline-flex items-center gap-1 align-middle\">\n <slot name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n\n <button\n v-if=\"showRemove\"\n :ref=\"setRemoveEl(i)\"\n type=\"button\"\n :class=\"removeButtonClass\"\n :aria-label=\"removeTagLabelFor(tag)\"\n :tabindex=\"roving.tabindexFor(i)\"\n data-gr-input-tag-remove\n data-testid=\"gr-input-tag-remove\"\n :data-index=\"i\"\n @mousedown.prevent.stop\n @focus=\"roving.setActive(i)\"\n @keydown=\"onTagKeydown($event, i)\"\n @click.stop=\"removeAt(i)\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </button>\n </span>\n </GrBadge>\n </span>\n\n <input\n :id=\"resolvedId\"\n ref=\"inputEl\"\n data-gr-input-tag-input\n data-testid=\"gr-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :placeholder=\"placeholderText\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-busy=\"isBusy ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--gr-muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n\n <span\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-input-tag-suffix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"suffixStyle\"\n >\n <slot name=\"suffix\" />\n </span>\n\n <span\n v-if=\"isBusy\"\n data-gr-input-tag-spinner\n :class=\"spinnerClass\"\n aria-hidden=\"true\"\n >\n <GrIcon size=\"sm\">\n <IconLoader class=\"animate-spin\" />\n </GrIcon>\n </span>\n\n <button\n v-if=\"showClearAll\"\n type=\"button\"\n data-gr-input-tag-clear\n :class=\"clearButtonClass\"\n :aria-label=\"resolvedClearAllLabel\"\n @mousedown.prevent.stop\n @click.stop=\"clearAll\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </button>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, ref } from 'vue'\n\nimport GrBadge from '../GrBadge/GrBadge.vue'\nimport type { GrBadgeRadius, GrBadgeSize, GrBadgeTone } from '../GrBadge'\nimport GrIcon from '../GrIcon/GrIcon.vue'\nimport IconClose from '~icons/lucide/x'\nimport IconLoader from '~icons/lucide/loader-2'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useControlAddons } from '../../composables/internal/useControlAddons'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport { useAnnouncer } from '../../composables/useAnnouncer'\nimport { useRovingFocus } from '../../composables/useRovingFocus'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useFocusWithin } from '../../composables/internal/useFocusWithin'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { isComposingEvent } from '../../internal/keyboard'\n\nimport {\n clearButtonClass,\n grInputTagInputClass,\n grInputTagWrapperClass,\n removeButtonClass,\n spinnerClass,\n type GrInputTagSize,\n type GrInputTagState,\n} from './grInputTagStyles'\n\nexport type { GrInputTagSize, GrInputTagState } from './grInputTagStyles'\n\nconst REGEX_SPECIAL_CHAR_RE = /[.*+?^${}()|[\\]\\\\]/g\n\n/**\n * Props for {@link GrInputTag}.\n * Tag-input primitive: renders a set of badges with an inline `<input>` for entering new tags.\n * Splits input by configurable `separators`, supports paste, Enter and Backspace editing.\n */\nexport interface GrInputTagProps {\n modelValue: string[]\n placeholder?: string\n disabled?: boolean\n readonly?: boolean\n invalid?: boolean\n /** Обязательное поле (`aria-required`). Складывается с `required` у `GrFormField`. */\n required?: boolean\n state?: GrInputTagState\n size?: GrInputTagSize\n separators?: string[]\n allowDuplicates?: boolean\n trim?: boolean\n max?: number\n addOnBlur?: boolean\n clearInputOnAdd?: boolean\n /**\n * Проверка тега перед добавлением. Может быть асинхронной (проверка на\n * сервере). Отклонённый тег не добавляется и уходит в событие `reject`.\n */\n beforeAdd?: (tag: string) => boolean | Promise<boolean>\n /** Кнопка «снести все теги». Настраивается через `GrConfigProvider`. */\n clearable?: boolean\n /** Фоновая работа: спиннер + `aria-busy`. Асинхронный `beforeAdd` поднимает его сам. */\n loading?: boolean\n tagTone?: GrBadgeTone\n tagDark?: boolean\n tagSize?: GrBadgeSize\n tagRadius?: GrBadgeRadius\n tagClosable?: boolean\n /** i18n-friendly aria-label for the per-tag remove button. */\n removeTagLabel?: string\n /** i18n aria-label кнопки «снести все». */\n clearAllLabel?: string\n /**\n * Имя контрола, когда он используется вне `GrFormField`. Внутри поля имя даёт\n * связка с его `<label for>` — там проп не нужен. Без того и другого у инпута\n * нет доступного имени вовсе: placeholder именем не считается.\n */\n ariaLabel?: string\n /** Имя для нативной формы: hidden input на каждый тег. */\n name?: string\n /**\n * Ширины аддонов `prefix`/`suffix` — общий контракт контролов пакета\n * (`docs/form-controls.md`).\n */\n prefixMinWidth?: string\n prefixMaxWidth?: string\n suffixMinWidth?: string\n suffixMaxWidth?: string\n prefixFixed?: boolean\n suffixFixed?: boolean\n}\n\nexport interface GrInputTagEmits {\n (e: 'update:modelValue', value: string[]): void\n (e: 'add', value: string): void\n (e: 'remove', value: string, index: number): void\n /** Тег не прошёл `beforeAdd`. */\n (e: 'reject', value: string): void\n /** Набор снесён кнопкой «очистить». */\n (e: 'clear'): void\n /** Набор тегов изменился. */\n (e: 'change', value: string[]): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(\n defineProps<GrInputTagProps>(),\n {\n placeholder: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n state: 'default',\n // Настраивается через `GrConfigProvider`; дефолт — в резолвере ниже.\n size: undefined,\n separators: () => [','],\n allowDuplicates: false,\n trim: true,\n max: undefined,\n addOnBlur: false,\n clearInputOnAdd: true,\n beforeAdd: undefined,\n clearable: undefined,\n loading: false,\n tagTone: 'neutral',\n tagDark: false,\n tagSize: 'md',\n tagRadius: 'round',\n tagClosable: true,\n removeTagLabel: undefined,\n clearAllLabel: undefined,\n ariaLabel: undefined,\n name: undefined,\n },\n)\n\nconst emit = defineEmits<GrInputTagEmits>()\ndefineSlots<{\n /** Аддон слева от чипов: иконка, метка. */\n prefix?: () => any\n /** Аддон справа, перед кнопкой очистки. */\n suffix?: () => any\n /** Свой чип: `remove` снимает значение. */\n tag?: (props: { tag: string, index: number, remove: () => void }) => any\n}>()\n\n\n// Fallback из контекста `GrFormField` (id/aria-describedby/invalid/required) —\n// как у GrInput и GrSelect: контрол не знает про форму, знает только про поле.\nconst field = useGrFormFieldContext()\nconst resolvedId = computed(() => field?.id.value)\nconst describedBy = computed(() => field?.describedById.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n} = useGrFormControl(() => props)\n\n// Эффективные значения: локальный проп → `GrConfigProvider` → дефолт компонента.\n/** Ширина аддона по умолчанию — та же лестница, что у `GrInput`. */\nconst ADDON_MIN_WIDTH_BY_SIZE: Record<GrInputTagSize, string> = {\n xs: '2rem',\n sm: '2.25rem',\n md: '2.5rem',\n lg: '3rem',\n}\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrInputTag' })\n\n/**\n * Аддоны — флекс-соседи поля: оболочка тегового поля и так флекс-строка с\n * бейджами, поэтому места паддингом резервировать не нужно.\n */\nconst { hasPrefix, hasSuffix, prefixEl, suffixEl, prefixStyle, suffixStyle } = useControlAddons(() => props, {\n defaultMinWidth: () => ADDON_MIN_WIDTH_BY_SIZE[resolvedSize.value],\n paddingX: () => '0px',\n})\nconst resolvedClearable = useGrComponentProp('GrInputTag', 'clearable', () => props.clearable, false)\n\nconst { t } = useGranularityTranslations()\nconst resolvedClearAllLabel = computed(() => props.clearAllLabel ?? t('gr.inputTag.clearAll', 'Clear all tags'))\n\nfunction removeTagLabelFor(tag: string): string {\n // Безликое «Remove tag» на двадцати кнопках подряд не даёт выбрать нужную:\n // имя обязано называть сам тег.\n return props.removeTagLabel ?? t('gr.inputTag.removeTagNamed', 'Remove tag {tag}', { tag })\n}\n\nconst inputValue = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\nconst rootEl = ref<HTMLElement | null>(null)\n\n// Внутри корня фокус ходит между полем и кнопками удаления чипов: без границы\n// каждое такое перемещение давало бы потребителю пару `blur` + `focus`.\nconst { onFocusIn, onFocusOut } = useFocusWithin(rootEl, {\n enter: event => emit('focus', event),\n leave: event => emit('blur', event),\n})\nconst removeEls = ref<HTMLButtonElement[]>([])\n\nfunction setRemoveEl(index: number) {\n return (el: unknown): void => {\n removeEls.value[index] = el as HTMLButtonElement\n }\n}\n\nfunction focus(): void {\n inputEl.value?.focus()\n}\n\nfunction blur(): void {\n inputEl.value?.blur()\n}\n\nconst isMaxed = computed(() => props.max !== undefined && props.modelValue.length >= props.max)\nconst canEdit = computed(() => !isDisabled.value && !isReadonly.value)\nconst showRemove = computed(() => props.tagClosable && canEdit.value)\n\n// Добавление, удаление и достигнутый предел — события, а не состояние виджета:\n// показывать их негде, объявить нужно. Это работа общего живого региона.\nconst { announce } = useAnnouncer()\n\n/**\n * Roving tabindex по крестикам: двадцать тегов давали двадцать одну остановку\n * `Tab`. В таб-порядке ровно один крестик, между ними ходят стрелками.\n *\n * Адресация индексом, а не значением тега: теги допускают повторы, и по\n * значению два одинаковых чипа было бы не различить.\n */\nconst tagIndexes = computed(() => props.modelValue.map((_, index) => index))\n\nconst roving = useRovingFocus<number>({\n items: () => tagIndexes.value,\n elementFor: index => removeEls.value[index],\n orientation: () => 'horizontal',\n // Ряд чипов — не кольцо: у него есть край, и за краем стоит поле ввода.\n wrap: () => false,\n onOverflow: (edge) => {\n // За последним чипом — поле ввода: продолжение того же ряда. Слева от\n // первого — начало строки, фокус остаётся на месте.\n if (edge === 'end') focus()\n return true\n },\n // Удаление чипа перерисовывает ряд: без ожидания фокус уехал бы на узел,\n // которого уже нет.\n beforeFocus: () => nextTick(),\n})\n\nasync function focusTag(index: number): Promise<void> {\n const last = props.modelValue.length - 1\n if (last < 0) {\n focus()\n return\n }\n\n await roving.focusKey(Math.min(Math.max(index, 0), last))\n}\n\nfunction escapeRegexChar(ch: string): string {\n return ch.replace(REGEX_SPECIAL_CHAR_RE, '\\\\$&')\n}\n\nconst splitRegex = computed(() => {\n const seps = (props.separators ?? []).filter(Boolean).map(s => s[0]!)\n const uniq = [...new Set([...seps, '\\n', '\\r', '\\t'])]\n const body = uniq.map(escapeRegexChar).join('')\n return new RegExp(`[${body}]+`, 'g')\n})\n\nfunction normalizeTag(raw: string): string {\n return props.trim ? raw.trim() : raw\n}\n\nfunction splitToTags(raw: string): string[] {\n return raw\n .split(splitRegex.value)\n .map(v => normalizeTag(v))\n .filter(Boolean)\n}\n\nfunction addMany(rawTags: string[]): boolean {\n if (!canEdit.value || isMaxed.value)\n return false\n\n const next = props.modelValue.slice()\n const added: string[] = []\n\n for (const raw of rawTags) {\n const tag = normalizeTag(raw)\n if (!tag)\n continue\n\n if (!props.allowDuplicates && next.includes(tag))\n continue\n\n if (props.max !== undefined && next.length >= props.max)\n break\n\n next.push(tag)\n added.push(tag)\n emit('add', tag)\n }\n\n if (!added.length)\n return false\n\n emit('update:modelValue', next)\n emit('change', next)\n announce(added.length === 1\n ? t('gr.inputTag.added', 'Tag added: {tag}', { tag: added[0]! })\n : t('gr.inputTag.addedMany', '{count} tags added', { count: added.length }))\n\n return true\n}\n\n// Счётчик запуска: пока идёт асинхронная проверка, пользователь успевает нажать\n// Enter второй раз — результат устаревшей проверки дописывать нельзя.\nlet validationRun = 0\nconst validating = ref(false)\nconst isBusy = computed(() => props.loading || validating.value)\n\nasync function filterAllowed(tags: string[], run: number): Promise<string[] | null> {\n const check = props.beforeAdd\n if (!check)\n return tags\n\n const allowed: string[] = []\n\n for (const tag of tags) {\n const ok = await check(tag)\n if (run !== validationRun)\n return null\n\n if (ok)\n allowed.push(tag)\n else\n emit('reject', tag)\n }\n\n return allowed\n}\n\nasync function commitInput(): Promise<void> {\n if (!canEdit.value || !inputValue.value)\n return\n\n if (isMaxed.value) {\n announce(t('gr.inputTag.limitReached', 'Tag limit reached'))\n return\n }\n\n const raw = inputValue.value\n const tags = splitToTags(raw)\n if (!tags.length)\n return\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n const allowed = await filterAllowed(tags, run)\n\n if (run === validationRun)\n validating.value = false\n\n if (allowed === null || !allowed.length)\n return\n\n const changed = addMany(allowed)\n // Значение могло измениться, пока шла проверка: стирать чужой ввод нельзя.\n if (changed && props.clearInputOnAdd && inputValue.value === raw)\n inputValue.value = ''\n}\n\nfunction removeAt(index: number): void {\n if (!canEdit.value)\n return\n\n const next = props.modelValue.slice()\n const removed = next[index]\n if (removed === undefined)\n return\n\n next.splice(index, 1)\n emit('update:modelValue', next)\n emit('change', next)\n emit('remove', removed, index)\n announce(t('gr.inputTag.removed', 'Tag removed: {tag}', { tag: removed }))\n}\n\n/** Удаление с клавиатуры: фокус переезжает на соседний чип, а не пропадает. */\nasync function removeAtFromKeyboard(index: number): Promise<void> {\n removeAt(index)\n await nextTick()\n\n if (props.modelValue.length === 0) {\n focus()\n return\n }\n\n await focusTag(Math.min(index, props.modelValue.length - 1))\n}\n\nfunction clearAll(): void {\n if (!canEdit.value || props.modelValue.length === 0)\n return\n\n emit('update:modelValue', [])\n emit('change', [])\n emit('clear')\n announce(t('gr.inputTag.cleared', 'All tags removed'))\n focus()\n}\n\nfunction onInput(e: Event): void {\n inputValue.value = (e.target as HTMLInputElement).value\n}\n\nfunction onKeydown(e: KeyboardEvent): void {\n // Enter/сепаратор во время IME-композиции коммитят её, а не тег.\n if (isComposingEvent(e))\n return\n if (!canEdit.value)\n return\n\n if (e.key === 'Enter') {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if ((props.separators ?? []).includes(e.key)) {\n e.preventDefault()\n void commitInput()\n return\n }\n\n if (inputValue.value.length === 0 && props.modelValue.length > 0) {\n if (e.key === 'Backspace') {\n e.preventDefault()\n removeAt(props.modelValue.length - 1)\n return\n }\n\n // Из пустого поля стрелка влево уводит на последний чип — дальше по чипам\n // работают те же стрелки, `Tab` для этого не нужен.\n if (e.key === 'ArrowLeft') {\n e.preventDefault()\n void focusTag(props.modelValue.length - 1)\n }\n }\n}\n\nfunction onTagKeydown(e: KeyboardEvent, index: number): void {\n if (roving.handleNavigationKeys(e)) {\n return\n }\n\n if (e.key === 'Delete' || e.key === 'Backspace') {\n e.preventDefault()\n void removeAtFromKeyboard(index)\n }\n}\n\nfunction onBlur(): void {\n if (props.addOnBlur)\n void commitInput()\n}\n\nfunction onPaste(e: ClipboardEvent): void {\n if (!canEdit.value || isMaxed.value)\n return\n\n const pasted = e.clipboardData?.getData('text')\n if (!pasted)\n return\n\n const tags = splitToTags(pasted)\n if (tags.length <= 1)\n return\n\n e.preventDefault()\n\n const run = ++validationRun\n validating.value = Boolean(props.beforeAdd)\n\n void filterAllowed(tags, run).then((allowed) => {\n if (run === validationRun)\n validating.value = false\n\n if (allowed?.length)\n addMany(allowed)\n })\n}\n\nconst wrapperClassName = computed(() => {\n return grInputTagWrapperClass({\n size: resolvedSize.value,\n state: props.state,\n invalid: isInvalid.value,\n disabled: isDisabled.value,\n })\n})\n\nconst inputClassName = computed(() => grInputTagInputClass(resolvedSize.value))\n\nconst showClearAll = computed(() => resolvedClearable.value && canEdit.value && props.modelValue.length > 0)\n\nconst placeholderText = computed(() => props.modelValue.length > 0 ? undefined : props.placeholder)\n\ndefineExpose({ focus, blur, clear: clearAll })\n</script>\n\n<template>\n <div\n ref=\"rootEl\"\n data-gr-input-tag\n data-testid=\"gr-input-tag\"\n :class=\"wrapperClassName\"\n @click=\"focus\"\n @focusin=\"onFocusIn\"\n @focusout=\"onFocusOut\"\n >\n <span\n v-if=\"hasPrefix\"\n ref=\"prefixEl\"\n data-gr-input-tag-prefix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"prefixStyle\"\n >\n <slot name=\"prefix\" />\n </span>\n\n <!-- Нативная форма: hidden на каждый тег — стандартная сериализация набора. -->\n <template v-if=\"name\">\n <input\n v-for=\"(tag, tagIndex) in modelValue\"\n :key=\"`hidden-${tagIndex}`\"\n type=\"hidden\"\n :name=\"name\"\n :value=\"tag\"\n >\n </template>\n <!--\n `display: contents` — список нужен ради роли, а не ради раскладки: чипы\n обязаны переноситься в одном потоке с полем ввода.\n -->\n <span v-if=\"modelValue.length\" role=\"list\" class=\"contents\">\n <GrBadge\n v-for=\"(tag, i) in modelValue\"\n :key=\"`${tag}-${i}`\"\n role=\"listitem\"\n :tone=\"tagTone\"\n :dark=\"tagDark\"\n :size=\"tagSize\"\n :radius=\"tagRadius\"\n data-gr-input-tag-item\n data-testid=\"gr-input-tag-item\"\n :data-index=\"i\"\n >\n <span class=\"inline-flex items-center gap-1 align-middle\">\n <slot name=\"tag\" :tag=\"tag\" :index=\"i\" :remove=\"() => removeAt(i)\">\n <span class=\"truncate max-w-[18rem]\">{{ tag }}</span>\n </slot>\n\n <button\n v-if=\"showRemove\"\n :ref=\"setRemoveEl(i)\"\n type=\"button\"\n :class=\"removeButtonClass\"\n :aria-label=\"removeTagLabelFor(tag)\"\n :tabindex=\"roving.tabindexFor(i)\"\n data-gr-input-tag-remove\n data-testid=\"gr-input-tag-remove\"\n :data-index=\"i\"\n @mousedown.prevent.stop\n @focus=\"roving.setActive(i)\"\n @keydown=\"onTagKeydown($event, i)\"\n @click.stop=\"removeAt(i)\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </button>\n </span>\n </GrBadge>\n </span>\n\n <input\n :id=\"resolvedId\"\n ref=\"inputEl\"\n data-gr-input-tag-input\n data-testid=\"gr-input-tag-input\"\n :value=\"inputValue\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :placeholder=\"placeholderText\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-required=\"isRequired ? 'true' : undefined\"\n :aria-readonly=\"isReadonly ? 'true' : undefined\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n :aria-busy=\"isBusy ? 'true' : undefined\"\n class=\"flex-1 min-w-[120px] bg-transparent border-none outline-none placeholder:text-[var(--gr-muted-fg)]\"\n :class=\"inputClassName\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n @blur=\"onBlur\"\n @paste=\"onPaste\"\n >\n\n <span\n v-if=\"hasSuffix\"\n ref=\"suffixEl\"\n data-gr-input-tag-suffix\n class=\"inline-flex shrink-0 items-center justify-center text-[var(--gr-muted-fg)]\"\n :style=\"suffixStyle\"\n >\n <slot name=\"suffix\" />\n </span>\n\n <span\n v-if=\"isBusy\"\n data-gr-input-tag-spinner\n :class=\"spinnerClass\"\n aria-hidden=\"true\"\n >\n <GrIcon size=\"sm\">\n <IconLoader class=\"animate-spin\" />\n </GrIcon>\n </span>\n\n <button\n v-if=\"showClearAll\"\n type=\"button\"\n data-gr-input-tag-clear\n :class=\"clearButtonClass\"\n :aria-label=\"resolvedClearAllLabel\"\n @mousedown.prevent.stop\n @click.stop=\"clearAll\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </button>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
1
  import { n as grInputTagSafelist, t as grInputTagConfig } from "../../chunks/config-BN4sXYXn.js";
2
- import { t as GrInputTag_default } from "./chunks/GrInputTag-DmNunixz.js";
2
+ import { t as GrInputTag_default } from "./chunks/GrInputTag-CyV2eY7Z.js";
3
3
  export { GrInputTag_default as GrInputTag, GrInputTag_default as default, grInputTagConfig, grInputTagSafelist };
@@ -1,8 +1,180 @@
1
1
  import { o as useGrComponentSize } from "../../../chunks/context-BSYR7RZs.js";
2
2
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
- import { i as shiftSatisfied, n as isComposingEvent, t as eventMatchesKey } from "../../../chunks/keyboard-zYvvyHd4.js";
4
- import { i as grKbdKeyClass, r as grKbdComboClass, s as separatorClass } from "../../../chunks/grKbdStyles-DAoxiytu.js";
3
+ import { a as shiftSatisfied, n as isAppleDevice, r as isComposingEvent, t as eventMatchesKey } from "../../../chunks/keyboard-DE2yhz_b.js";
4
+ import { a as grKbdKeyClass, d as sequenceSeparatorClass, i as grKbdInnerKeyClass, r as grKbdComboClass, u as separatorClass } from "../../../chunks/grKbdStyles-CeZhGQHr.js";
5
5
  import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, onMounted, openBlock, ref, renderList, renderSlot, toDisplayString, unref } from "vue";
6
+ //#region src/components/shared/hotkeyTokens.ts
7
+ function symbol(label, name) {
8
+ return {
9
+ label,
10
+ name,
11
+ symbol: true
12
+ };
13
+ }
14
+ function word(label, name) {
15
+ return name ? {
16
+ label,
17
+ name
18
+ } : { label };
19
+ }
20
+ var GR_KBD_TOKENS = [
21
+ {
22
+ token: "mod",
23
+ aliases: [],
24
+ group: "modifier",
25
+ apple: symbol("⌘", "command"),
26
+ other: word("Ctrl")
27
+ },
28
+ {
29
+ token: "meta",
30
+ aliases: [
31
+ "cmd",
32
+ "command",
33
+ "⌘"
34
+ ],
35
+ group: "modifier",
36
+ apple: symbol("⌘", "command"),
37
+ other: word("Meta")
38
+ },
39
+ {
40
+ token: "ctrl",
41
+ aliases: ["control", "⌃"],
42
+ group: "modifier",
43
+ apple: symbol("⌃", "control"),
44
+ other: word("Ctrl")
45
+ },
46
+ {
47
+ token: "alt",
48
+ aliases: ["option", "⌥"],
49
+ group: "modifier",
50
+ apple: symbol("⌥", "option"),
51
+ other: word("Alt")
52
+ },
53
+ {
54
+ token: "shift",
55
+ aliases: ["⇧"],
56
+ group: "modifier",
57
+ apple: symbol("⇧", "shift"),
58
+ other: word("Shift")
59
+ },
60
+ {
61
+ token: "enter",
62
+ aliases: [
63
+ "return",
64
+ "↵",
65
+ "↩"
66
+ ],
67
+ group: "editing",
68
+ apple: symbol("↩", "enter"),
69
+ other: word("Enter")
70
+ },
71
+ {
72
+ token: "esc",
73
+ aliases: ["escape"],
74
+ group: "editing",
75
+ apple: word("Esc", "escape"),
76
+ other: word("Esc", "escape")
77
+ },
78
+ {
79
+ token: "tab",
80
+ aliases: ["⇥"],
81
+ group: "editing",
82
+ apple: symbol("⇥", "tab"),
83
+ other: word("Tab")
84
+ },
85
+ {
86
+ token: "space",
87
+ aliases: [],
88
+ group: "editing",
89
+ apple: word("Space"),
90
+ other: word("Space")
91
+ },
92
+ {
93
+ token: "backspace",
94
+ aliases: ["⌫"],
95
+ group: "editing",
96
+ apple: symbol("⌫", "backspace"),
97
+ other: word("Backspace")
98
+ },
99
+ {
100
+ token: "delete",
101
+ aliases: ["del", "⌦"],
102
+ group: "editing",
103
+ apple: symbol("⌦", "delete"),
104
+ other: word("Del")
105
+ },
106
+ {
107
+ token: "up",
108
+ aliases: ["arrowup", "↑"],
109
+ group: "navigation",
110
+ apple: symbol("↑", "arrowUp"),
111
+ other: symbol("↑", "arrowUp")
112
+ },
113
+ {
114
+ token: "down",
115
+ aliases: ["arrowdown", "↓"],
116
+ group: "navigation",
117
+ apple: symbol("↓", "arrowDown"),
118
+ other: symbol("↓", "arrowDown")
119
+ },
120
+ {
121
+ token: "left",
122
+ aliases: ["arrowleft", "←"],
123
+ group: "navigation",
124
+ apple: symbol("←", "arrowLeft"),
125
+ other: symbol("←", "arrowLeft")
126
+ },
127
+ {
128
+ token: "right",
129
+ aliases: ["arrowright", "→"],
130
+ group: "navigation",
131
+ apple: symbol("→", "arrowRight"),
132
+ other: symbol("→", "arrowRight")
133
+ },
134
+ {
135
+ token: "home",
136
+ aliases: [],
137
+ group: "navigation",
138
+ apple: word("Home"),
139
+ other: word("Home")
140
+ },
141
+ {
142
+ token: "end",
143
+ aliases: [],
144
+ group: "navigation",
145
+ apple: word("End"),
146
+ other: word("End")
147
+ },
148
+ {
149
+ token: "pageup",
150
+ aliases: ["pgup", "⇞"],
151
+ group: "navigation",
152
+ apple: symbol("⇞", "pageUp"),
153
+ other: word("PgUp")
154
+ },
155
+ {
156
+ token: "pagedown",
157
+ aliases: [
158
+ "pgdn",
159
+ "pgdown",
160
+ "⇟"
161
+ ],
162
+ group: "navigation",
163
+ apple: symbol("⇟", "pageDown"),
164
+ other: word("PgDn")
165
+ }
166
+ ];
167
+ var BY_ALIAS = /* @__PURE__ */ new Map();
168
+ for (const spec of GR_KBD_TOKENS) {
169
+ BY_ALIAS.set(spec.token, spec);
170
+ for (const alias of spec.aliases) BY_ALIAS.set(alias, spec);
171
+ }
172
+ /** Токен или его синоним — в описание клавиши. Регистр не важен, глиф тоже принимается. */
173
+ function findKbdToken(token) {
174
+ const trimmed = token.trim();
175
+ return BY_ALIAS.get(trimmed.toLowerCase()) ?? BY_ALIAS.get(trimmed);
176
+ }
177
+ //#endregion
6
178
  //#region src/components/shared/hotkey.ts
7
179
  /**
8
180
  * Разбор, матчинг и человекочитаемое представление сочетаний клавиш.
@@ -38,11 +210,6 @@ function parseCommandHotkey(combo) {
38
210
  }
39
211
  return parsed;
40
212
  }
41
- /** macOS определяем по платформе — от неё зависит, чем является `mod`. */
42
- function isAppleDevice() {
43
- if (typeof navigator === "undefined") return false;
44
- return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent);
45
- }
46
213
  function matchesCommandHotkey(event, hotkey, apple = isAppleDevice()) {
47
214
  if (isComposingEvent(event)) return false;
48
215
  const expectMeta = hotkey.meta || hotkey.mod && apple;
@@ -64,42 +231,14 @@ function formatCommandHotkey(hotkey, apple = isAppleDevice()) {
64
231
  return keys;
65
232
  }
66
233
  /**
67
- * Токен → то, что видит пользователь. `mod` зависит от платформы: на macOS это
68
- * Cmd, на остальных Ctrl. Символы отдаются вместе с ключом читаемого имени:
69
- * `⌘` без имени диктор произносит как «знак места интереса».
234
+ * Токен → то, что видит пользователь. Каталог общий с витриной и докой
235
+ * (`hotkeyTokens.ts`): цепочка `if` расходилась бы со списком, который читает
236
+ * потребитель.
70
237
  */
71
238
  function formatHotkeyToken(token, apple) {
239
+ const spec = findKbdToken(token);
240
+ if (spec) return apple ? spec.apple : spec.other;
72
241
  const t = token.trim();
73
- const lower = t.toLowerCase();
74
- if (lower === "mod") return apple ? {
75
- label: "⌘",
76
- name: "command"
77
- } : { label: "Ctrl" };
78
- if (lower === "meta" || lower === "cmd" || lower === "command" || t === "⌘") return apple ? {
79
- label: "⌘",
80
- name: "command"
81
- } : { label: "Meta" };
82
- if (lower === "ctrl" || lower === "control" || t === "⌃") return apple ? {
83
- label: "⌃",
84
- name: "control"
85
- } : { label: "Ctrl" };
86
- if (lower === "alt" || lower === "option" || t === "⌥") return apple ? {
87
- label: "⌥",
88
- name: "option"
89
- } : { label: "Alt" };
90
- if (lower === "shift" || t === "⇧") return apple ? {
91
- label: "⇧",
92
- name: "shift"
93
- } : { label: "Shift" };
94
- if (lower === "enter" || lower === "return" || t === "↵" || t === "↩") return apple ? {
95
- label: "↩",
96
- name: "enter"
97
- } : { label: "Enter" };
98
- if (lower === "esc" || lower === "escape") return {
99
- label: "Esc",
100
- name: "escape"
101
- };
102
- if (lower === "space") return { label: "Space" };
103
242
  return { label: t.length === 1 ? t.toUpperCase() : t };
104
243
  }
105
244
  function formatHotkeyTokens(tokens, apple) {
@@ -111,8 +250,9 @@ function splitHotkeyCombo(combo) {
111
250
  }
112
251
  //#endregion
113
252
  //#region src/components/GrKbd/GrKbd.vue?vue&type=script&setup=true&lang.ts
114
- var _hoisted_1 = ["aria-hidden"];
115
- var _hoisted_2 = {
253
+ var _hoisted_1 = ["data-variant"];
254
+ var _hoisted_2 = ["aria-hidden"];
255
+ var _hoisted_3 = {
116
256
  key: 0,
117
257
  class: "sr-only"
118
258
  };
@@ -122,8 +262,9 @@ var GrKbd_default = /* @__PURE__ */ defineComponent({
122
262
  __name: "GrKbd",
123
263
  props: {
124
264
  size: { default: void 0 },
265
+ variant: { default: "merged" },
125
266
  keys: { default: void 0 },
126
- separator: { default: "+" },
267
+ separator: { default: void 0 },
127
268
  platform: { default: "auto" }
128
269
  },
129
270
  setup(__props) {
@@ -151,14 +292,38 @@ var GrKbd_default = /* @__PURE__ */ defineComponent({
151
292
  const keyViews = computed(() => formatHotkeyTokens(tokens.value, isApple.value));
152
293
  const hasCombo = computed(() => keyViews.value.length > 0);
153
294
  const keyClass = computed(() => grKbdKeyClass(resolvedSize.value));
154
- const comboClass = computed(() => grKbdComboClass(resolvedSize.value));
295
+ const innerKeyClass = computed(() => grKbdInnerKeyClass(resolvedSize.value, props.variant));
296
+ const comboClass = computed(() => grKbdComboClass(resolvedSize.value, props.variant));
297
+ /**
298
+ * Разделитель перед клавишей `index`.
299
+ *
300
+ * Авто-правило одно: в общей плашке символы склеиваются, слова — нет. Внутри
301
+ * одной платформы набор однороден (macOS даёт `⌘⌥⇧`, прочие — `Ctrl`, `Alt`),
302
+ * поэтому «слева символ» и означает «пишем как система».
303
+ */
304
+ function separatorAt(index) {
305
+ if (index === 0) return "";
306
+ if (props.separator !== void 0) return props.separator;
307
+ if (props.variant === "sequence") return t("gr.kbd.then", "then");
308
+ if (props.variant === "split") return "+";
309
+ return keyViews.value[index - 1]?.symbol ? "" : "+";
310
+ }
155
311
  const NAME_FALLBACKS = {
156
312
  command: "Command",
157
313
  option: "Option",
158
314
  shift: "Shift",
159
315
  control: "Control",
160
316
  enter: "Enter",
161
- escape: "Escape"
317
+ escape: "Escape",
318
+ tab: "Tab",
319
+ backspace: "Backspace",
320
+ delete: "Delete",
321
+ pageUp: "Page Up",
322
+ pageDown: "Page Down",
323
+ arrowUp: "Arrow Up",
324
+ arrowDown: "Arrow Down",
325
+ arrowLeft: "Arrow Left",
326
+ arrowRight: "Arrow Right"
162
327
  };
163
328
  /** Читаемое имя символьной клавиши: `⌘` без него диктор произносит как знак. */
164
329
  function readableName(name) {
@@ -169,17 +334,18 @@ var GrKbd_default = /* @__PURE__ */ defineComponent({
169
334
  key: 0,
170
335
  "data-gr-kbd": "",
171
336
  "data-gr-kbd-combo": "",
337
+ "data-variant": __props.variant,
172
338
  class: normalizeClass(comboClass.value)
173
339
  }, [(openBlock(true), createElementBlock(Fragment, null, renderList(keyViews.value, (key, index) => {
174
- return openBlock(), createElementBlock(Fragment, { key: `${key.label}-${index}` }, [index > 0 && __props.separator ? (openBlock(), createElementBlock("span", {
340
+ return openBlock(), createElementBlock(Fragment, { key: `${key.label}-${index}` }, [separatorAt(index) ? (openBlock(), createElementBlock("span", {
175
341
  key: 0,
176
- class: normalizeClass(unref(separatorClass)),
342
+ class: normalizeClass(__props.variant === "sequence" ? unref(sequenceSeparatorClass) : unref(separatorClass)),
177
343
  "aria-hidden": "true"
178
- }, toDisplayString(__props.separator), 3)) : createCommentVNode("", true), createElementVNode("kbd", {
344
+ }, toDisplayString(separatorAt(index)), 3)) : createCommentVNode("", true), createElementVNode("kbd", {
179
345
  "data-gr-kbd-key": "",
180
- class: normalizeClass(keyClass.value)
181
- }, [createElementVNode("span", { "aria-hidden": key.name ? "true" : void 0 }, toDisplayString(key.label), 9, _hoisted_1), key.name ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(readableName(key.name)), 1)) : createCommentVNode("", true)], 2)], 64);
182
- }), 128))], 2)) : (openBlock(), createElementBlock("kbd", {
346
+ class: normalizeClass(innerKeyClass.value)
347
+ }, [createElementVNode("span", { "aria-hidden": key.name ? "true" : void 0 }, toDisplayString(key.label), 9, _hoisted_2), key.name ? (openBlock(), createElementBlock("span", _hoisted_3, toDisplayString(readableName(key.name)), 1)) : createCommentVNode("", true)], 2)], 64);
348
+ }), 128))], 10, _hoisted_1)) : (openBlock(), createElementBlock("kbd", {
183
349
  key: 1,
184
350
  "data-gr-kbd": "",
185
351
  "data-gr-kbd-key": "",
@@ -189,4 +355,4 @@ var GrKbd_default = /* @__PURE__ */ defineComponent({
189
355
  }
190
356
  });
191
357
  //#endregion
192
- export { parseCommandHotkey as a, matchesCommandHotkey as i, formatCommandHotkey as n, isAppleDevice as r, GrKbd_default as t };
358
+ export { GR_KBD_TOKENS as a, parseCommandHotkey as i, formatCommandHotkey as n, findKbdToken as o, matchesCommandHotkey as r, GrKbd_default as t };