@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrColorPicker-vGSgpUV9.js","names":[],"sources":["../../../../src/components/GrColorPicker/color.ts","../../../../src/components/GrColorPicker/colorArea.ts","../../../../src/components/GrColorPicker/eyeDropper.ts","../../../../src/components/GrColorPicker/GrColorPicker.vue","../../../../src/components/GrColorPicker/GrColorPicker.vue"],"sourcesContent":["/**\n * Арифметика цвета для `GrColorPicker` — чистый модуль без Vue.\n *\n * Модель компонента — hex-строка (в такой форме цвет лежит в токенах темы),\n * а панель работает в HSL: у оттенка, насыщенности и светлоты есть шкала, по\n * которой можно вести слайдер, а у каналов RGB её нет.\n *\n * Свой парсер, а не `__tests__/cssContrast.ts`: тот — инфраструктура гейтов, и\n * тянуть тестовый модуль в поставляемый код нельзя.\n */\n\nexport type GrHsla = {\n /** Оттенок, 0…359 (круговой: 360 — это 0). */\n h: number\n /** Насыщенность, 0…100. */\n s: number\n /** Светлота, 0…100. */\n l: number\n /** Непрозрачность, 0…1. */\n a: number\n}\n\ntype Rgb = { r: number, g: number, b: number }\n\nconst HEX_PATTERN = /^#?([0-9a-f]{3,8})$/i\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max)\n}\n\n/**\n * Оттенок цикличен: 360° — тот же цвет, что 0°.\n *\n * Округления здесь нет намеренно: `#3b82f6` даёт 217.22°, и округлив его до\n * целого, обратное преобразование вернуло бы `#3b83f6` — компонент молча\n * переписывал бы чужой цвет при первом же открытии панели. Целые градусы\n * появляются там, где они и нужны, — на шкале слайдера (`normalizeHsla`).\n */\nfunction normalizeHue(hue: number): number {\n if (!Number.isFinite(hue))\n return 0\n return ((hue % 360) + 360) % 360\n}\n\n/** Короткая форма `#abc` разворачивается в `#aabbcc` — так её читает и CSS. */\nfunction expandShorthand(hex: string): string | null {\n if (hex.length === 3 || hex.length === 4)\n return [...hex].map(char => char + char).join('')\n\n if (hex.length === 6 || hex.length === 8)\n return hex\n\n return null\n}\n\nfunction rgbToHsl({ r, g, b }: Rgb): { h: number, s: number, l: number } {\n const red = r / 255\n const green = g / 255\n const blue = b / 255\n\n const max = Math.max(red, green, blue)\n const min = Math.min(red, green, blue)\n const delta = max - min\n const lightness = (max + min) / 2\n\n if (delta === 0)\n return { h: 0, s: 0, l: lightness * 100 }\n\n const saturation = delta / (1 - Math.abs(2 * lightness - 1))\n\n let hue: number\n if (max === red)\n hue = ((green - blue) / delta) % 6\n else if (max === green)\n hue = (blue - red) / delta + 2\n else hue = (red - green) / delta + 4\n\n return { h: normalizeHue(hue * 60), s: saturation * 100, l: lightness * 100 }\n}\n\nfunction hslToRgb({ h, s, l }: Omit<GrHsla, 'a'>): Rgb {\n const saturation = clamp(s, 0, 100) / 100\n const lightness = clamp(l, 0, 100) / 100\n const hue = normalizeHue(h)\n\n const chroma = (1 - Math.abs(2 * lightness - 1)) * saturation\n const second = chroma * (1 - Math.abs(((hue / 60) % 2) - 1))\n const match = lightness - chroma / 2\n\n const [red, green, blue] = ((): [number, number, number] => {\n if (hue < 60)\n return [chroma, second, 0]\n if (hue < 120)\n return [second, chroma, 0]\n if (hue < 180)\n return [0, chroma, second]\n if (hue < 240)\n return [0, second, chroma]\n if (hue < 300)\n return [second, 0, chroma]\n return [chroma, 0, second]\n })()\n\n return {\n r: Math.round((red + match) * 255),\n g: Math.round((green + match) * 255),\n b: Math.round((blue + match) * 255),\n }\n}\n\nfunction toHexPair(value: number): string {\n return clamp(Math.round(value), 0, 255).toString(16).padStart(2, '0')\n}\n\n/**\n * Разбирает hex любой из четырёх форм (`#abc`, `#abcd`, `#aabbcc`, `#aabbccdd`),\n * регистр и решётка необязательны.\n *\n * Мусор возвращает `null`, а не бросает: значение приходит из модели снаружи и\n * из поля ввода, и упавший компонент — худший ответ на опечатку.\n */\nexport function parseHexColor(value: unknown): GrHsla | null {\n if (typeof value !== 'string')\n return null\n\n const match = HEX_PATTERN.exec(value.trim())\n if (!match)\n return null\n\n const hex = expandShorthand(match[1])\n if (!hex)\n return null\n\n const rgb: Rgb = {\n r: Number.parseInt(hex.slice(0, 2), 16),\n g: Number.parseInt(hex.slice(2, 4), 16),\n b: Number.parseInt(hex.slice(4, 6), 16),\n }\n\n const alpha = hex.length === 8 ? Number.parseInt(hex.slice(6, 8), 16) / 255 : 1\n\n return { ...rgbToHsl(rgb), a: alpha }\n}\n\n/**\n * Собирает hex обратно. `withAlpha: false` альфу отбрасывает, а не округляет до\n * непрозрачного: компонент без пропа `alpha` не вправе отдавать восьмизначную\n * форму, которую потребитель не ждёт.\n */\nexport function formatHexColor(color: GrHsla, withAlpha = false): string {\n const { r, g, b } = hslToRgb(color)\n const base = `#${toHexPair(r)}${toHexPair(g)}${toHexPair(b)}`\n\n if (!withAlpha)\n return base\n\n return `${base}${toHexPair(clamp(color.a, 0, 1) * 255)}`\n}\n\n/** Короткая запись числа: целое остаётся целым, дробь обрезается до сотых. */\nfunction trim(value: number): number {\n return Math.round(value * 100) / 100\n}\n\n/** CSS-запись цвета для превью и градиентов. */\nexport function hslaToCss(color: GrHsla): string {\n const h = trim(normalizeHue(color.h))\n const s = trim(clamp(color.s, 0, 100))\n const l = trim(clamp(color.l, 0, 100))\n\n return `hsl(${h} ${s}% ${l}% / ${trim(clamp(color.a, 0, 1))})`\n}\n\n/**\n * Приводит произвольный объект к валидному диапазону каналов.\n *\n * Округления нет ни у одного канала, и это то же правило, что у `normalizeHue`,\n * распространённое на насыщенность и светлоту: целочисленная сетка HSL мельче\n * сетки hex, и посадка на неё меняет цвет. Замер на типовых брендовых\n * значениях — 11 расхождений из 12: `#10b981` возвращался как `#10b77f`.\n * Пользователь при этом ничего не двигал, а компонент уже переписал его цвет —\n * достаточно было выбрать пресет или вставить hex в поле.\n *\n * Целые нужны шкалам, и они их и получают: бегунок читает `Math.round` своего\n * канала, а хранимое значение остаётся точным.\n */\nexport function normalizeHsla(color: GrHsla): GrHsla {\n return {\n h: normalizeHue(color.h),\n s: clamp(color.s, 0, 100),\n l: clamp(color.l, 0, 100),\n a: clamp(color.a, 0, 1),\n }\n}\n","/**\n * Арифметика двумерной области насыщенность × светлота.\n *\n * Модуль чистый: ни DOM, ни Vue. Всё, что здесь считается, проверяется без\n * монтирования — а в jsdom у области нет ни размеров, ни попадания указателя.\n *\n * Оси выбраны под модель компонента (HSL), а не под привычный HSV-квадрат.\n * Перевод в HSV дал бы более нарядную заливку, но принёс бы вторую проекцию с\n * потерями: при `v = 0` насыщенность HSV не определена, и чёрный терял бы её\n * ровно так же, как серый теряет оттенок. Компонент уже держит своё состояние\n * именно чтобы такого не было.\n */\n\nexport type GrColorAreaAxis = 'saturation' | 'lightness'\n\n/** Точка области в процентах: обе координаты — значения каналов, а не пиксели. */\nexport interface GrColorAreaPoint {\n s: number\n l: number\n}\n\n/** Шаг стрелки и крупный шаг `PageUp`/`PageDown` — те же, что у `GrSlider`. */\nconst STEP = 1\nconst PAGE_STEP = 10\n\nfunction clamp(value: number): number {\n return Math.min(100, Math.max(0, value))\n}\n\n/**\n * Положение ручки в процентах от левого верхнего угла.\n *\n * Светлота инвертирована: вверху области белое, внизу чёрное — так стоит\n * вертикальная шкала во всех привычных пикерах, и переворачивать её значило бы\n * ломать ожидание ради буквальности.\n */\nexport function colorAreaThumbPosition(point: GrColorAreaPoint): { x: number, y: number } {\n return { x: clamp(point.s), y: 100 - clamp(point.l) }\n}\n\n/**\n * Значение под указателем.\n *\n * Прямоугольник приходит снаружи: измерять его умеет только вызывающий, а\n * промах мимо области — норма, указатель уходит за её границы при каждом\n * протягивании.\n */\nexport function colorAreaPointAt(\n pointer: { clientX: number, clientY: number },\n rect: { left: number, top: number, width: number, height: number },\n): GrColorAreaPoint {\n const s = rect.width > 0 ? ((pointer.clientX - rect.left) / rect.width) * 100 : 0\n const y = rect.height > 0 ? ((pointer.clientY - rect.top) / rect.height) * 100 : 0\n\n return { s: clamp(s), l: clamp(100 - y) }\n}\n\n/**\n * Клавиша → новое значение и ось, которая изменилась.\n *\n * Ось возвращается не для отчёта: у области два настоящих `input[type=range]`,\n * по одному на канал, и стрелка поперёк оси сфокусированного поля обязана\n * увести фокус на соседнее — иначе диктор промолчит о том, что изменилось.\n *\n * `Home`/`End` и крупный шаг работают по оси **сфокусированного** поля: они\n * относятся к диапазону, а диапазонов здесь два.\n */\nexport function colorAreaKeyStep(\n key: string,\n point: GrColorAreaPoint,\n focused: GrColorAreaAxis,\n): { point: GrColorAreaPoint, axis: GrColorAreaAxis } | null {\n const move = (axis: GrColorAreaAxis, next: number) => ({\n point: axis === 'saturation'\n ? { s: clamp(next), l: point.l }\n : { s: point.s, l: clamp(next) },\n axis,\n })\n\n const current = focused === 'saturation' ? point.s : point.l\n\n switch (key) {\n case 'ArrowLeft':\n return move('saturation', point.s - STEP)\n case 'ArrowRight':\n return move('saturation', point.s + STEP)\n case 'ArrowDown':\n return move('lightness', point.l - STEP)\n case 'ArrowUp':\n return move('lightness', point.l + STEP)\n case 'PageDown':\n return move(focused, current - PAGE_STEP)\n case 'PageUp':\n return move(focused, current + PAGE_STEP)\n case 'Home':\n return move(focused, 0)\n case 'End':\n return move(focused, 100)\n default:\n return null\n }\n}\n","/**\n * Пипетка экрана поверх `EyeDropper`.\n *\n * API есть не везде (сегодня — браузеры на Chromium), поэтому вызывается через\n * проверку, а не через `try`: кнопка не должна появляться там, где нажатие\n * ничего не даст.\n *\n * Отказ пользователя ошибкой не считается. `open()` отклоняется `AbortError`\n * и на `Esc`, и на обрыв через `AbortSignal` — оба исхода означают «цвет не\n * выбран», и разговаривать о них с пользователем не о чем.\n */\n\n/**\n * `EyeDropper` нет в `lib.dom`, поэтому форма описана здесь — узко и ровно та,\n * что читается ниже (приём `GrOtpInput` для WebOTP).\n */\ninterface EyeDropperApi {\n new (): { open: (options?: { signal?: AbortSignal }) => Promise<{ sRGBHex: string }> }\n}\n\nfunction eyeDropperApi(): EyeDropperApi | null {\n if (typeof window === 'undefined' || !('EyeDropper' in window))\n return null\n\n return (window as unknown as { EyeDropper: EyeDropperApi }).EyeDropper\n}\n\n/** Поддерживается ли пипетка. Зовётся после монтирования: на сервере `window` нет. */\nexport function isEyeDropperSupported(): boolean {\n return eyeDropperApi() !== null\n}\n\n/**\n * Открыть пипетку и дождаться цвета. `null` — пользователь отказался или API\n * недоступно.\n *\n * Вызов обязан идти прямо из обработчика нажатия: без свежего жеста браузер\n * отклоняет `open()` как `NotAllowedError`.\n */\nexport async function pickScreenColor(signal?: AbortSignal): Promise<string | null> {\n const Api = eyeDropperApi()\n if (!Api)\n return null\n\n try {\n const { sRGBHex } = await new Api().open(signal ? { signal } : undefined)\n return sRGBHex\n }\n catch {\n return null\n }\n}\n","<script setup lang=\"ts\">\n/**\n * GrColorPicker — поле выбора цвета: образец с текущим значением, панель с\n * оттенком, насыщенностью, светлотой и прозрачностью, поле hex и палитра.\n *\n * Прямой сценарий — настройки темы и брендирования, поэтому модель хранит hex:\n * в такой форме цвет лежит в токенах и его понимает CSS.\n *\n * A11y: у каждого канала настоящий `role=\"slider\"` с полной клавиатурой и\n * `aria-valuetext`. У двумерной области он тоже настоящий, и даже дважды —\n * по одному `input[type=range]` на ось (см. `colorArea.ts`).\n */\nimport { computed, nextTick, onMounted, ref, useId, watch } from 'vue'\nimport IconPipette from '~icons/lucide/pipette'\n\nimport { useDragGesture } from '../../composables/useDragGesture'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrPopover from '../GrPopover/GrPopover.vue'\nimport GrSlider from '../GrSlider/GrSlider.vue'\n\nimport { formatHexColor, hslaToCss, normalizeHsla, parseHexColor, type GrHsla } from './color'\nimport { colorAreaKeyStep, colorAreaPointAt, colorAreaThumbPosition, type GrColorAreaAxis, type GrColorAreaPoint } from './colorArea'\nimport { isEyeDropperSupported, pickScreenColor } from './eyeDropper'\nimport {\n areaInputClass,\n areaThumbClass,\n checkerClass,\n eyedropperIconClass,\n grColorPickerAreaClass,\n grColorPickerEyedropperClass,\n grColorPickerPanelClass,\n grColorPickerPresetClass,\n grColorPickerTriggerClass,\n hexFieldClass,\n hexRowClass,\n presetsGridClass,\n previewClass,\n rowClass,\n rowLabelClass,\n rowValueClass,\n swatchBaseClass,\n swatchFillClass,\n triggerSwatchSizeBySize,\n triggerValueClass,\n type GrColorPickerSize,\n type GrColorPickerView,\n} from './grColorPickerStyles'\n\nexport type { GrColorPickerSize, GrColorPickerView } from './grColorPickerStyles'\n\nexport interface GrColorPickerProps {\n /** Цвет в hex: `#RRGGBB`, а при `alpha` — `#RRGGBBAA`. Мусор не роняет компонент. */\n modelValue: string\n /** Четвёртый слайдер и восьмизначная форма hex. */\n alpha?: boolean\n /**\n * Как задаются насыщенность и светлота: двумя бегунками или квадратом.\n * Оттенок и прозрачность остаются бегунками в обоих видах.\n */\n view?: GrColorPickerView\n /**\n * Кнопка пипетки. Рисуется только там, где браузер даёт `EyeDropper`, —\n * сегодня это Chromium.\n */\n eyedropper?: boolean\n /** Палитра быстрого выбора. Пусто — блок не рендерится. */\n presets?: string[]\n size?: GrColorPickerSize\n /** Контролируемое состояние панели (`v-model:open`). */\n open?: boolean\n /** Сторона, с которой раскрывается панель. */\n placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n /** Имя для нативной формы: значение уходит скрытым полем. */\n name?: string\n disabled?: boolean\n /** Только для чтения: цвет видно, панель открывается, но значение не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n ariaLabel?: string\n}\n\nexport interface GrColorPickerEmits {\n (e: 'update:modelValue', value: string): void\n (e: 'change', value: string): void\n (e: 'update:open', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrColorPickerProps>(), {\n alpha: false,\n // Дефолт живёт в резолвере — как у `size`.\n view: undefined,\n eyedropper: undefined,\n presets: () => [],\n // Дефолт живёт в резолвере: Vue подставил бы свой раньше, чем компонент\n // заглянет в `GrConfigProvider`.\n size: undefined,\n open: undefined,\n placement: 'bottom-start',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrColorPickerEmits>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrColorPicker' })\nconst resolvedView = useGrComponentProp('GrColorPicker', 'view', () => props.view, 'sliders')\nconst wantsEyedropper = useGrComponentProp('GrColorPicker', 'eyedropper', () => props.eyedropper, false)\n\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n // «Ввод не принимается» — `disabled` или `readonly`: значение видно, но не меняется.\n locked: isLocked,\n} = useGrFormControl(() => props)\n\n/**\n * `aria-required` и `aria-readonly` роль `button` не поддерживает — axe роняет\n * это как critical `aria-allowed-attr`. Состояния уходят в описание триггера:\n * иначе они пропали бы для диктора совсем (маркер `*` у `GrFormField`\n * декоративен и скрыт).\n */\nconst stateHintId = useId()\nconst stateHint = computed(() => [\n isRequired.value ? t('gr.form.required', 'This field is required') : undefined,\n isReadonly.value ? t('gr.form.readonly', 'Read only') : undefined,\n].filter(Boolean).join('. ') || undefined)\n\nconst describedBy = computed(() => [\n field?.describedById.value,\n stateHint.value ? stateHintId : undefined,\n].filter(Boolean).join(' ') || undefined)\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction focus(): void {\n triggerEl.value?.focus()\n}\n\nfunction blur(): void {\n triggerEl.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nconst FALLBACK: GrHsla = { h: 0, s: 0, l: 0, a: 1 }\n\n/**\n * Рабочее состояние панели.\n *\n * Держать его отдельно от модели обязательно: hex — проекция с потерями. У\n * серого нет оттенка, и без собственного состояния бегунок оттенка прыгал бы\n * обратно на 0° при каждом движении.\n */\nconst state = ref<GrHsla>(parseHexColor(props.modelValue) ?? FALLBACK)\n\n/** Последнее отданное значение: вернувшись в проп, оно не должно сбрасывать состояние. */\nlet lastEmitted = ''\n\nwatch(() => props.modelValue, (next) => {\n if (next === lastEmitted)\n return\n\n const parsed = parseHexColor(next)\n if (parsed)\n state.value = parsed\n})\n\nconst cssColor = computed(() => hslaToCss(state.value))\nconst hexValue = computed(() => formatHexColor(state.value, props.alpha))\n\nfunction commit(next: GrHsla): void {\n if (isLocked.value)\n return\n\n state.value = normalizeHsla(next)\n\n const hex = formatHexColor(state.value, props.alpha)\n lastEmitted = hex\n emit('update:modelValue', hex)\n emit('change', hex)\n}\n\n/** Канал панели: слайдер читает состояние и коммитит новое значение целиком. */\nfunction channel(key: 'h' | 's' | 'l' | 'a', scale = 1) {\n return computed<number>({\n get: () => Math.round(state.value[key] * scale),\n set: value => commit({ ...state.value, [key]: value / scale }),\n })\n}\n\nconst hue = channel('h')\nconst saturation = channel('s')\nconst lightness = channel('l')\n// Альфа хранится долей, а слайдер ходит по процентам — иначе шаг был бы 0.01.\nconst opacity = channel('a', 100)\n\nconst degrees = (value: number): string => `${value}°`\nconst percent = (value: number): string => `${value}%`\n\n/** Текст поля hex редактируется свободно и коммитится только валидным. */\nconst hexDraft = ref(hexValue.value)\n\nwatch(hexValue, (next) => {\n hexDraft.value = next\n})\n\nfunction commitHex(): void {\n const parsed = parseHexColor(hexDraft.value)\n\n // Мусор откатывается к текущему значению: держать в поле невалидный текст\n // после коммита — значит показывать цвет, которого нет.\n //\n // Откат идёт следующим тиком намеренно: вернув значение синхронно, мы отдали\n // бы Vue то же самое, что он уже отрисовал, — патча не случилось бы, и в поле\n // остался бы набранный мусор.\n if (!parsed) {\n void nextTick(() => {\n hexDraft.value = hexValue.value\n })\n return\n }\n\n commit(props.alpha ? parsed : { ...parsed, a: state.value.a })\n}\n\nconst isOpen = ref(false)\nconst panelOpen = computed({\n get: () => props.open ?? isOpen.value,\n set: (value) => {\n isOpen.value = value\n emit('update:open', value)\n },\n})\n\nconst presetList = computed(() => props.presets.filter(preset => parseHexColor(preset) !== null))\n\nfunction isPresetSelected(preset: string): boolean {\n const parsed = parseHexColor(preset)\n return parsed ? formatHexColor(parsed, props.alpha) === hexValue.value : false\n}\n\nfunction selectPreset(preset: string): void {\n const parsed = parseHexColor(preset)\n if (parsed)\n commit(parsed)\n}\n\nconst triggerClass = computed(() => grColorPickerTriggerClass({\n size: resolvedSize.value,\n disabled: isDisabled.value,\n invalid: isInvalid.value,\n}))\n\nconst panelClass = computed(() => grColorPickerPanelClass(resolvedSize.value))\nconst swatchSizeClass = computed(() => triggerSwatchSizeBySize[resolvedSize.value])\n\n/**\n * Градиенты дорожек. Через `--gr-slider-rail` их не подать: хук уходит в\n * `background-color`, а градиент там не работает — поэтому значения приезжают\n * переменными, а красит дорожки собственный `<style>` компонента.\n *\n * Переменные висят на самой панели, а не на корне: панель уезжает в портал, и\n * наследование от корня до неё не доходит.\n */\nconst trackVars = computed<Record<string, string>>(() => {\n const { h, s, l } = state.value\n const solid = hslaToCss({ h, s, l, a: 1 })\n\n return {\n // Заливка квадрата: серый → чистый тон при светлоте 50%. Белая и чёрная\n // вуали поверх неё статичны и живут в `<style>`; вместе они дают **точный**\n // HSL, а не приблизительный — осветление и затемнение в HSL линейны ровно\n // так же, как наложение белого и чёрного с альфой.\n '--gr-color-picker-area-saturation': `linear-gradient(to right, hsl(${Math.round(h)} 0% 50%), hsl(${Math.round(h)} 100% 50%))`,\n '--gr-color-picker-track-hue': 'linear-gradient(to right, hsl(0 100% 50%), hsl(60 100% 50%), hsl(120 100% 50%), hsl(180 100% 50%), hsl(240 100% 50%), hsl(300 100% 50%), hsl(360 100% 50%))',\n '--gr-color-picker-track-saturation': `linear-gradient(to right, hsl(${Math.round(h)} 0% ${Math.round(l)}%), hsl(${Math.round(h)} 100% ${Math.round(l)}%))`,\n '--gr-color-picker-track-lightness': `linear-gradient(to right, hsl(${Math.round(h)} ${Math.round(s)}% 0%), hsl(${Math.round(h)} ${Math.round(s)}% 50%), hsl(${Math.round(h)} ${Math.round(s)}% 100%))`,\n '--gr-color-picker-track-alpha': `linear-gradient(to right, transparent, ${solid})`,\n }\n})\n\nconst areaEl = ref<HTMLElement | null>(null)\nconst saturationInputEl = ref<HTMLInputElement | null>(null)\nconst lightnessInputEl = ref<HTMLInputElement | null>(null)\n\n/** Точка области целыми процентами: поля осей — обычные `input[type=range]`. */\nconst areaPoint = computed<GrColorAreaPoint>(() => ({\n s: Math.round(state.value.s),\n l: Math.round(state.value.l),\n}))\n\nconst areaThumbStyle = computed(() => {\n const { x, y } = colorAreaThumbPosition(areaPoint.value)\n\n return {\n left: `${x}%`,\n top: `${y}%`,\n background: hslaToCss({ ...state.value, a: 1 }),\n }\n})\n\nfunction applyAreaPoint(point: GrColorAreaPoint): void {\n commit({ ...state.value, s: point.s, l: point.l })\n}\n\nfunction areaPointerMove(event: PointerEvent): void {\n const rect = areaEl.value?.getBoundingClientRect()\n if (!rect)\n return\n\n applyAreaPoint(colorAreaPointAt(event, rect))\n}\n\n/** Цвет до начала жеста: оборванный жест обязан вернуть его на место. */\nlet colorBeforeDrag: GrHsla | null = null\n\nconst areaDrag = useDragGesture({\n disabled: () => isLocked.value,\n onStart: (event) => {\n colorBeforeDrag = state.value\n // Нажатие ставит значение сразу: попадание в область — это уже выбор, а не\n // только взятие ручки. Фокус уходит на ось насыщенности, чтобы жест можно\n // было продолжить стрелками.\n areaPointerMove(event)\n saturationInputEl.value?.focus()\n },\n onMove: areaPointerMove,\n onCancel: () => {\n if (colorBeforeDrag)\n commit(colorBeforeDrag)\n colorBeforeDrag = null\n },\n onEnd: () => {\n colorBeforeDrag = null\n },\n})\n\n/**\n * Клавиатура области.\n *\n * Стрелка поперёк оси сфокусированного поля уводит фокус на соседнее: значение\n * поменялось у него, и без переезда диктор промолчал бы о том, что изменилось.\n */\nfunction onAreaKeydown(event: KeyboardEvent, axis: GrColorAreaAxis): void {\n if (isLocked.value)\n return\n\n const next = colorAreaKeyStep(event.key, areaPoint.value, axis)\n if (!next)\n return\n\n // Гасим нативный шаг поля: у области своя арифметика по двум осям.\n event.preventDefault()\n applyAreaPoint(next.point)\n\n if (next.axis !== axis)\n (next.axis === 'saturation' ? saturationInputEl : lightnessInputEl).value?.focus()\n}\n\n/** Изменение поля мимо клавиатуры — например, жестом вспомогательной технологии. */\nfunction onAreaInput(event: Event, axis: GrColorAreaAxis): void {\n const value = Number((event.target as HTMLInputElement).value)\n if (!Number.isFinite(value))\n return\n\n applyAreaPoint(axis === 'saturation'\n ? { ...areaPoint.value, s: value }\n : { ...areaPoint.value, l: value })\n}\n\nconst areaClass = computed(() => grColorPickerAreaClass({\n size: resolvedSize.value,\n locked: isLocked.value,\n}))\n\n/**\n * Поддержка пипетки уточняется после монтирования: `window` в теле `setup`\n * либо роняет серверный рендер, либо расходится с ним. До этого кнопки нет —\n * ровно то же, что отдаёт сервер, поэтому гидрация совпадает.\n */\nconst eyedropperSupported = ref(false)\n\nonMounted(() => {\n eyedropperSupported.value = isEyeDropperSupported()\n})\n\nconst showEyedropper = computed(() => wantsEyedropper.value && eyedropperSupported.value)\nconst eyedropperClassName = computed(() => grColorPickerEyedropperClass(resolvedSize.value))\n\n/**\n * Пипетка зовётся прямо из обработчика нажатия: без свежего жеста браузер\n * отклоняет `open()`. Отказ пользователя — не ошибка и ничего не меняет.\n */\nasync function pickFromScreen(): Promise<void> {\n if (isLocked.value)\n return\n\n const picked = await pickScreenColor()\n if (!picked)\n return\n\n const parsed = parseHexColor(picked)\n if (!parsed)\n return\n\n // С экрана приходит уже смешанный цвет: прозрачности в нём нет, и текущая\n // остаётся как была.\n commit({ ...parsed, a: state.value.a })\n}\n</script>\n\n<template>\n <div data-gr-color-picker>\n <!-- Значение для нативной формы уходит скрытым полем: интерактивного\n контрола внутри виджета быть не должно. -->\n <input v-if=\"name\" type=\"hidden\" :name=\"name\" :value=\"hexValue\">\n\n <span v-if=\"stateHint\" :id=\"stateHintId\" class=\"sr-only\">{{ stateHint }}</span>\n\n <GrPopover\n v-model:open=\"panelOpen\"\n block\n :size=\"resolvedSize\"\n :placement=\"placement\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.panelLabel', 'Color picker')\"\n :close-on-content-click=\"false\"\n >\n <template #trigger=\"{ triggerProps }\">\n <button\n :id=\"fieldId\"\n ref=\"triggerEl\"\n v-bind=\"triggerProps\"\n data-gr-color-picker-trigger\n type=\"button\"\n :class=\"triggerClass\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <span\n data-gr-color-picker-swatch\n aria-hidden=\"true\"\n :class=\"[swatchBaseClass, swatchSizeClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </span>\n\n <span :class=\"triggerValueClass\">{{ hexValue }}</span>\n </button>\n </template>\n\n <template #content>\n <div data-gr-color-picker-panel :class=\"panelClass\" :style=\"trackVars\">\n <div\n data-gr-color-picker-preview\n aria-hidden=\"true\"\n :class=\"[previewClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </div>\n\n <!--\n Область насыщенность × светлота. Роль на обёртке — `group`, а не\n виджетная: внутри два настоящих `input[type=range]`, по одному на\n ось, и роль-виджет объявила бы их презентационными. Поля скрыты\n визуально, но остаются в таб-порядке — фокус показывает обёртка\n через `focus-within` (приём `GrFileUpload`).\n -->\n <div\n v-if=\"resolvedView === 'area'\"\n ref=\"areaEl\"\n data-gr-color-picker-area\n role=\"group\"\n :class=\"areaClass\"\n :aria-label=\"t('gr.colorPicker.area', 'Saturation and lightness')\"\n @pointerdown=\"areaDrag.start\"\n >\n <input\n ref=\"saturationInputEl\"\n data-gr-color-picker-area-axis=\"saturation\"\n type=\"range\"\n min=\"0\"\n max=\"100\"\n :value=\"areaPoint.s\"\n :class=\"areaInputClass\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.saturation', 'Saturation')\"\n :aria-valuetext=\"percent(areaPoint.s)\"\n @keydown=\"onAreaKeydown($event, 'saturation')\"\n @input=\"onAreaInput($event, 'saturation')\"\n >\n <input\n ref=\"lightnessInputEl\"\n data-gr-color-picker-area-axis=\"lightness\"\n type=\"range\"\n min=\"0\"\n max=\"100\"\n :value=\"areaPoint.l\"\n :class=\"areaInputClass\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.lightness', 'Lightness')\"\n :aria-valuetext=\"percent(areaPoint.l)\"\n @keydown=\"onAreaKeydown($event, 'lightness')\"\n @input=\"onAreaInput($event, 'lightness')\"\n >\n\n <span\n data-gr-color-picker-area-thumb\n aria-hidden=\"true\"\n :class=\"areaThumbClass\"\n :style=\"areaThumbStyle\"\n />\n </div>\n\n <div data-gr-color-picker-channel=\"hue\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">H</span>\n <GrSlider\n v-model=\"hue\"\n :min=\"0\"\n :max=\"359\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"degrees\"\n :aria-label=\"t('gr.colorPicker.hue', 'Hue')\"\n />\n <span :class=\"rowValueClass\">{{ degrees(hue) }}</span>\n </div>\n\n <template v-if=\"resolvedView === 'sliders'\">\n <div data-gr-color-picker-channel=\"saturation\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">S</span>\n <GrSlider\n v-model=\"saturation\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.saturation', 'Saturation')\"\n />\n <span :class=\"rowValueClass\">{{ percent(saturation) }}</span>\n </div>\n\n <div data-gr-color-picker-channel=\"lightness\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">L</span>\n <GrSlider\n v-model=\"lightness\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.lightness', 'Lightness')\"\n />\n <span :class=\"rowValueClass\">{{ percent(lightness) }}</span>\n </div>\n </template>\n\n <div v-if=\"alpha\" data-gr-color-picker-channel=\"alpha\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">A</span>\n <GrSlider\n v-model=\"opacity\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.opacity', 'Opacity')\"\n />\n <span :class=\"rowValueClass\">{{ percent(opacity) }}</span>\n </div>\n\n <div :class=\"hexRowClass\">\n <GrInput\n v-model=\"hexDraft\"\n data-gr-color-picker-hex\n :class=\"hexFieldClass\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :aria-label=\"t('gr.colorPicker.hexLabel', 'Hex value')\"\n @change=\"commitHex\"\n @keydown.enter=\"commitHex\"\n />\n\n <button\n v-if=\"showEyedropper\"\n data-gr-color-picker-eyedropper\n type=\"button\"\n :class=\"eyedropperClassName\"\n :disabled=\"isLocked\"\n :aria-label=\"t('gr.colorPicker.eyedropper', 'Pick a colour from the screen')\"\n @click=\"pickFromScreen\"\n >\n <IconPipette :class=\"eyedropperIconClass\" aria-hidden=\"true\" />\n </button>\n </div>\n\n <div\n v-if=\"presetList.length\"\n data-gr-color-picker-presets\n :class=\"presetsGridClass\"\n role=\"group\"\n :aria-label=\"t('gr.colorPicker.presetsLabel', 'Color presets')\"\n >\n <button\n v-for=\"preset in presetList\"\n :key=\"preset\"\n data-gr-color-picker-preset\n type=\"button\"\n :class=\"[grColorPickerPresetClass(isPresetSelected(preset)), checkerClass]\"\n :aria-label=\"t('gr.colorPicker.swatchLabel', 'Color {color}', { color: preset })\"\n :aria-pressed=\"isPresetSelected(preset) ? 'true' : 'false'\"\n :disabled=\"isLocked\"\n @click=\"selectPreset(preset)\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: preset }\" />\n </button>\n </div>\n </div>\n </template>\n </GrPopover>\n </div>\n</template>\n\n<style>\n/*\n * Шахматка под прозрачным цветом. Двумя `conic-gradient` — в утилите такое не\n * выражается, а без подложки прозрачный образец сливается с панелью.\n */\n.gr-color-picker-checker {\n background-image:\n conic-gradient(\n from 90deg,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 25%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0 50%,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 75%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0\n );\n background-size:\n calc(var(--gr-color-picker-checker-size, 6px) * 2)\n calc(var(--gr-color-picker-checker-size, 6px) * 2);\n /* Рамка образца полупрозрачна, и без обрезки шахматка просвечивает сквозь неё. */\n background-clip: padding-box;\n}\n\n/*\n * Дорожки каналов. Красим `[data-gr-slider-track]` потому, что хук\n * `--gr-slider-rail` уходит в `background-color`, а градиент там не работает.\n * Сами градиенты компонент подаёт переменными — CSS остаётся статичной.\n */\n[data-gr-color-picker-channel] [data-gr-slider-track] {\n border-radius: var(--gr-radius-full);\n}\n\n[data-gr-color-picker-channel='hue'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-hue);\n}\n\n[data-gr-color-picker-channel='saturation'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-saturation);\n}\n\n[data-gr-color-picker-channel='lightness'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-lightness);\n}\n\n[data-gr-color-picker-channel='alpha'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-alpha);\n}\n\n/* Заливка канала прозрачна: шкалу показывает сама дорожка. */\n[data-gr-color-picker-channel] [data-gr-slider-fill] {\n background-color: transparent;\n}\n\n/*\n * Заливка области. Три слоя, и порядок важен: белая вуаль сверху, чёрная снизу,\n * под ними — шкала насыщенности при светлоте 50%.\n *\n * Пара вуалей даёт **точный** HSL, а не похожий на него: осветление и\n * затемнение в HSL — линейная интерполяция к белому и к чёрному, ровно то же,\n * что делает наложение с альфой. Поэтому цвет под ручкой совпадает с образцом\n * и с hex до последнего разряда.\n */\n[data-gr-color-picker-area] {\n background-image:\n linear-gradient(\n to bottom,\n rgb(255 255 255) 0%,\n rgb(255 255 255 / 0) 50%,\n rgb(0 0 0 / 0) 50%,\n rgb(0 0 0) 100%\n ),\n var(--gr-color-picker-area-saturation);\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * GrColorPicker — поле выбора цвета: образец с текущим значением, панель с\n * оттенком, насыщенностью, светлотой и прозрачностью, поле hex и палитра.\n *\n * Прямой сценарий — настройки темы и брендирования, поэтому модель хранит hex:\n * в такой форме цвет лежит в токенах и его понимает CSS.\n *\n * A11y: у каждого канала настоящий `role=\"slider\"` с полной клавиатурой и\n * `aria-valuetext`. У двумерной области он тоже настоящий, и даже дважды —\n * по одному `input[type=range]` на ось (см. `colorArea.ts`).\n */\nimport { computed, nextTick, onMounted, ref, useId, watch } from 'vue'\nimport IconPipette from '~icons/lucide/pipette'\n\nimport { useDragGesture } from '../../composables/useDragGesture'\nimport { useGrFormControl } from '../../composables/useGrFormControl'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { useGrComponentProp, useGrComponentSize } from '../GrConfigProvider/context'\nimport { useGrFormFieldContext } from '../GrFormField/context'\nimport GrInput from '../GrInput/GrInput.vue'\nimport GrPopover from '../GrPopover/GrPopover.vue'\nimport GrSlider from '../GrSlider/GrSlider.vue'\n\nimport { formatHexColor, hslaToCss, normalizeHsla, parseHexColor, type GrHsla } from './color'\nimport { colorAreaKeyStep, colorAreaPointAt, colorAreaThumbPosition, type GrColorAreaAxis, type GrColorAreaPoint } from './colorArea'\nimport { isEyeDropperSupported, pickScreenColor } from './eyeDropper'\nimport {\n areaInputClass,\n areaThumbClass,\n checkerClass,\n eyedropperIconClass,\n grColorPickerAreaClass,\n grColorPickerEyedropperClass,\n grColorPickerPanelClass,\n grColorPickerPresetClass,\n grColorPickerTriggerClass,\n hexFieldClass,\n hexRowClass,\n presetsGridClass,\n previewClass,\n rowClass,\n rowLabelClass,\n rowValueClass,\n swatchBaseClass,\n swatchFillClass,\n triggerSwatchSizeBySize,\n triggerValueClass,\n type GrColorPickerSize,\n type GrColorPickerView,\n} from './grColorPickerStyles'\n\nexport type { GrColorPickerSize, GrColorPickerView } from './grColorPickerStyles'\n\nexport interface GrColorPickerProps {\n /** Цвет в hex: `#RRGGBB`, а при `alpha` — `#RRGGBBAA`. Мусор не роняет компонент. */\n modelValue: string\n /** Четвёртый слайдер и восьмизначная форма hex. */\n alpha?: boolean\n /**\n * Как задаются насыщенность и светлота: двумя бегунками или квадратом.\n * Оттенок и прозрачность остаются бегунками в обоих видах.\n */\n view?: GrColorPickerView\n /**\n * Кнопка пипетки. Рисуется только там, где браузер даёт `EyeDropper`, —\n * сегодня это Chromium.\n */\n eyedropper?: boolean\n /** Палитра быстрого выбора. Пусто — блок не рендерится. */\n presets?: string[]\n size?: GrColorPickerSize\n /** Контролируемое состояние панели (`v-model:open`). */\n open?: boolean\n /** Сторона, с которой раскрывается панель. */\n placement?: 'bottom-start' | 'bottom-end' | 'top-start' | 'top-end'\n /** Имя для нативной формы: значение уходит скрытым полем. */\n name?: string\n disabled?: boolean\n /** Только для чтения: цвет видно, панель открывается, но значение не меняется. */\n readonly?: boolean\n invalid?: boolean\n required?: boolean\n ariaLabel?: string\n}\n\nexport interface GrColorPickerEmits {\n (e: 'update:modelValue', value: string): void\n (e: 'change', value: string): void\n (e: 'update:open', value: boolean): void\n (e: 'focus', event: FocusEvent): void\n (e: 'blur', event: FocusEvent): void\n}\n\nconst props = withDefaults(defineProps<GrColorPickerProps>(), {\n alpha: false,\n // Дефолт живёт в резолвере — как у `size`.\n view: undefined,\n eyedropper: undefined,\n presets: () => [],\n // Дефолт живёт в резолвере: Vue подставил бы свой раньше, чем компонент\n // заглянет в `GrConfigProvider`.\n size: undefined,\n open: undefined,\n placement: 'bottom-start',\n name: undefined,\n disabled: false,\n readonly: false,\n invalid: false,\n required: false,\n ariaLabel: undefined,\n})\n\nconst emit = defineEmits<GrColorPickerEmits>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedSize = useGrComponentSize(() => props.size, { component: 'GrColorPicker' })\nconst resolvedView = useGrComponentProp('GrColorPicker', 'view', () => props.view, 'sliders')\nconst wantsEyedropper = useGrComponentProp('GrColorPicker', 'eyedropper', () => props.eyedropper, false)\n\nconst field = useGrFormFieldContext()\nconst fieldId = computed(() => field?.id.value)\nconst {\n disabled: isDisabled,\n invalid: isInvalid,\n required: isRequired,\n readonly: isReadonly,\n // «Ввод не принимается» — `disabled` или `readonly`: значение видно, но не меняется.\n locked: isLocked,\n} = useGrFormControl(() => props)\n\n/**\n * `aria-required` и `aria-readonly` роль `button` не поддерживает — axe роняет\n * это как critical `aria-allowed-attr`. Состояния уходят в описание триггера:\n * иначе они пропали бы для диктора совсем (маркер `*` у `GrFormField`\n * декоративен и скрыт).\n */\nconst stateHintId = useId()\nconst stateHint = computed(() => [\n isRequired.value ? t('gr.form.required', 'This field is required') : undefined,\n isReadonly.value ? t('gr.form.readonly', 'Read only') : undefined,\n].filter(Boolean).join('. ') || undefined)\n\nconst describedBy = computed(() => [\n field?.describedById.value,\n stateHint.value ? stateHintId : undefined,\n].filter(Boolean).join(' ') || undefined)\n\nconst triggerEl = ref<HTMLElement | null>(null)\n\nfunction focus(): void {\n triggerEl.value?.focus()\n}\n\nfunction blur(): void {\n triggerEl.value?.blur()\n}\n\ndefineExpose({ focus, blur })\n\nconst FALLBACK: GrHsla = { h: 0, s: 0, l: 0, a: 1 }\n\n/**\n * Рабочее состояние панели.\n *\n * Держать его отдельно от модели обязательно: hex — проекция с потерями. У\n * серого нет оттенка, и без собственного состояния бегунок оттенка прыгал бы\n * обратно на 0° при каждом движении.\n */\nconst state = ref<GrHsla>(parseHexColor(props.modelValue) ?? FALLBACK)\n\n/** Последнее отданное значение: вернувшись в проп, оно не должно сбрасывать состояние. */\nlet lastEmitted = ''\n\nwatch(() => props.modelValue, (next) => {\n if (next === lastEmitted)\n return\n\n const parsed = parseHexColor(next)\n if (parsed)\n state.value = parsed\n})\n\nconst cssColor = computed(() => hslaToCss(state.value))\nconst hexValue = computed(() => formatHexColor(state.value, props.alpha))\n\nfunction commit(next: GrHsla): void {\n if (isLocked.value)\n return\n\n state.value = normalizeHsla(next)\n\n const hex = formatHexColor(state.value, props.alpha)\n lastEmitted = hex\n emit('update:modelValue', hex)\n emit('change', hex)\n}\n\n/** Канал панели: слайдер читает состояние и коммитит новое значение целиком. */\nfunction channel(key: 'h' | 's' | 'l' | 'a', scale = 1) {\n return computed<number>({\n get: () => Math.round(state.value[key] * scale),\n set: value => commit({ ...state.value, [key]: value / scale }),\n })\n}\n\nconst hue = channel('h')\nconst saturation = channel('s')\nconst lightness = channel('l')\n// Альфа хранится долей, а слайдер ходит по процентам — иначе шаг был бы 0.01.\nconst opacity = channel('a', 100)\n\nconst degrees = (value: number): string => `${value}°`\nconst percent = (value: number): string => `${value}%`\n\n/** Текст поля hex редактируется свободно и коммитится только валидным. */\nconst hexDraft = ref(hexValue.value)\n\nwatch(hexValue, (next) => {\n hexDraft.value = next\n})\n\nfunction commitHex(): void {\n const parsed = parseHexColor(hexDraft.value)\n\n // Мусор откатывается к текущему значению: держать в поле невалидный текст\n // после коммита — значит показывать цвет, которого нет.\n //\n // Откат идёт следующим тиком намеренно: вернув значение синхронно, мы отдали\n // бы Vue то же самое, что он уже отрисовал, — патча не случилось бы, и в поле\n // остался бы набранный мусор.\n if (!parsed) {\n void nextTick(() => {\n hexDraft.value = hexValue.value\n })\n return\n }\n\n commit(props.alpha ? parsed : { ...parsed, a: state.value.a })\n}\n\nconst isOpen = ref(false)\nconst panelOpen = computed({\n get: () => props.open ?? isOpen.value,\n set: (value) => {\n isOpen.value = value\n emit('update:open', value)\n },\n})\n\nconst presetList = computed(() => props.presets.filter(preset => parseHexColor(preset) !== null))\n\nfunction isPresetSelected(preset: string): boolean {\n const parsed = parseHexColor(preset)\n return parsed ? formatHexColor(parsed, props.alpha) === hexValue.value : false\n}\n\nfunction selectPreset(preset: string): void {\n const parsed = parseHexColor(preset)\n if (parsed)\n commit(parsed)\n}\n\nconst triggerClass = computed(() => grColorPickerTriggerClass({\n size: resolvedSize.value,\n disabled: isDisabled.value,\n invalid: isInvalid.value,\n}))\n\nconst panelClass = computed(() => grColorPickerPanelClass(resolvedSize.value))\nconst swatchSizeClass = computed(() => triggerSwatchSizeBySize[resolvedSize.value])\n\n/**\n * Градиенты дорожек. Через `--gr-slider-rail` их не подать: хук уходит в\n * `background-color`, а градиент там не работает — поэтому значения приезжают\n * переменными, а красит дорожки собственный `<style>` компонента.\n *\n * Переменные висят на самой панели, а не на корне: панель уезжает в портал, и\n * наследование от корня до неё не доходит.\n */\nconst trackVars = computed<Record<string, string>>(() => {\n const { h, s, l } = state.value\n const solid = hslaToCss({ h, s, l, a: 1 })\n\n return {\n // Заливка квадрата: серый → чистый тон при светлоте 50%. Белая и чёрная\n // вуали поверх неё статичны и живут в `<style>`; вместе они дают **точный**\n // HSL, а не приблизительный — осветление и затемнение в HSL линейны ровно\n // так же, как наложение белого и чёрного с альфой.\n '--gr-color-picker-area-saturation': `linear-gradient(to right, hsl(${Math.round(h)} 0% 50%), hsl(${Math.round(h)} 100% 50%))`,\n '--gr-color-picker-track-hue': 'linear-gradient(to right, hsl(0 100% 50%), hsl(60 100% 50%), hsl(120 100% 50%), hsl(180 100% 50%), hsl(240 100% 50%), hsl(300 100% 50%), hsl(360 100% 50%))',\n '--gr-color-picker-track-saturation': `linear-gradient(to right, hsl(${Math.round(h)} 0% ${Math.round(l)}%), hsl(${Math.round(h)} 100% ${Math.round(l)}%))`,\n '--gr-color-picker-track-lightness': `linear-gradient(to right, hsl(${Math.round(h)} ${Math.round(s)}% 0%), hsl(${Math.round(h)} ${Math.round(s)}% 50%), hsl(${Math.round(h)} ${Math.round(s)}% 100%))`,\n '--gr-color-picker-track-alpha': `linear-gradient(to right, transparent, ${solid})`,\n }\n})\n\nconst areaEl = ref<HTMLElement | null>(null)\nconst saturationInputEl = ref<HTMLInputElement | null>(null)\nconst lightnessInputEl = ref<HTMLInputElement | null>(null)\n\n/** Точка области целыми процентами: поля осей — обычные `input[type=range]`. */\nconst areaPoint = computed<GrColorAreaPoint>(() => ({\n s: Math.round(state.value.s),\n l: Math.round(state.value.l),\n}))\n\nconst areaThumbStyle = computed(() => {\n const { x, y } = colorAreaThumbPosition(areaPoint.value)\n\n return {\n left: `${x}%`,\n top: `${y}%`,\n background: hslaToCss({ ...state.value, a: 1 }),\n }\n})\n\nfunction applyAreaPoint(point: GrColorAreaPoint): void {\n commit({ ...state.value, s: point.s, l: point.l })\n}\n\nfunction areaPointerMove(event: PointerEvent): void {\n const rect = areaEl.value?.getBoundingClientRect()\n if (!rect)\n return\n\n applyAreaPoint(colorAreaPointAt(event, rect))\n}\n\n/** Цвет до начала жеста: оборванный жест обязан вернуть его на место. */\nlet colorBeforeDrag: GrHsla | null = null\n\nconst areaDrag = useDragGesture({\n disabled: () => isLocked.value,\n onStart: (event) => {\n colorBeforeDrag = state.value\n // Нажатие ставит значение сразу: попадание в область — это уже выбор, а не\n // только взятие ручки. Фокус уходит на ось насыщенности, чтобы жест можно\n // было продолжить стрелками.\n areaPointerMove(event)\n saturationInputEl.value?.focus()\n },\n onMove: areaPointerMove,\n onCancel: () => {\n if (colorBeforeDrag)\n commit(colorBeforeDrag)\n colorBeforeDrag = null\n },\n onEnd: () => {\n colorBeforeDrag = null\n },\n})\n\n/**\n * Клавиатура области.\n *\n * Стрелка поперёк оси сфокусированного поля уводит фокус на соседнее: значение\n * поменялось у него, и без переезда диктор промолчал бы о том, что изменилось.\n */\nfunction onAreaKeydown(event: KeyboardEvent, axis: GrColorAreaAxis): void {\n if (isLocked.value)\n return\n\n const next = colorAreaKeyStep(event.key, areaPoint.value, axis)\n if (!next)\n return\n\n // Гасим нативный шаг поля: у области своя арифметика по двум осям.\n event.preventDefault()\n applyAreaPoint(next.point)\n\n if (next.axis !== axis)\n (next.axis === 'saturation' ? saturationInputEl : lightnessInputEl).value?.focus()\n}\n\n/** Изменение поля мимо клавиатуры — например, жестом вспомогательной технологии. */\nfunction onAreaInput(event: Event, axis: GrColorAreaAxis): void {\n const value = Number((event.target as HTMLInputElement).value)\n if (!Number.isFinite(value))\n return\n\n applyAreaPoint(axis === 'saturation'\n ? { ...areaPoint.value, s: value }\n : { ...areaPoint.value, l: value })\n}\n\nconst areaClass = computed(() => grColorPickerAreaClass({\n size: resolvedSize.value,\n locked: isLocked.value,\n}))\n\n/**\n * Поддержка пипетки уточняется после монтирования: `window` в теле `setup`\n * либо роняет серверный рендер, либо расходится с ним. До этого кнопки нет —\n * ровно то же, что отдаёт сервер, поэтому гидрация совпадает.\n */\nconst eyedropperSupported = ref(false)\n\nonMounted(() => {\n eyedropperSupported.value = isEyeDropperSupported()\n})\n\nconst showEyedropper = computed(() => wantsEyedropper.value && eyedropperSupported.value)\nconst eyedropperClassName = computed(() => grColorPickerEyedropperClass(resolvedSize.value))\n\n/**\n * Пипетка зовётся прямо из обработчика нажатия: без свежего жеста браузер\n * отклоняет `open()`. Отказ пользователя — не ошибка и ничего не меняет.\n */\nasync function pickFromScreen(): Promise<void> {\n if (isLocked.value)\n return\n\n const picked = await pickScreenColor()\n if (!picked)\n return\n\n const parsed = parseHexColor(picked)\n if (!parsed)\n return\n\n // С экрана приходит уже смешанный цвет: прозрачности в нём нет, и текущая\n // остаётся как была.\n commit({ ...parsed, a: state.value.a })\n}\n</script>\n\n<template>\n <div data-gr-color-picker>\n <!-- Значение для нативной формы уходит скрытым полем: интерактивного\n контрола внутри виджета быть не должно. -->\n <input v-if=\"name\" type=\"hidden\" :name=\"name\" :value=\"hexValue\">\n\n <span v-if=\"stateHint\" :id=\"stateHintId\" class=\"sr-only\">{{ stateHint }}</span>\n\n <GrPopover\n v-model:open=\"panelOpen\"\n block\n :size=\"resolvedSize\"\n :placement=\"placement\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.panelLabel', 'Color picker')\"\n :close-on-content-click=\"false\"\n >\n <template #trigger=\"{ triggerProps }\">\n <button\n :id=\"fieldId\"\n ref=\"triggerEl\"\n v-bind=\"triggerProps\"\n data-gr-color-picker-trigger\n type=\"button\"\n :class=\"triggerClass\"\n :aria-label=\"ariaLabel\"\n :aria-describedby=\"describedBy\"\n :aria-invalid=\"isInvalid ? 'true' : undefined\"\n @focus=\"emit('focus', $event)\"\n @blur=\"emit('blur', $event)\"\n >\n <span\n data-gr-color-picker-swatch\n aria-hidden=\"true\"\n :class=\"[swatchBaseClass, swatchSizeClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </span>\n\n <span :class=\"triggerValueClass\">{{ hexValue }}</span>\n </button>\n </template>\n\n <template #content>\n <div data-gr-color-picker-panel :class=\"panelClass\" :style=\"trackVars\">\n <div\n data-gr-color-picker-preview\n aria-hidden=\"true\"\n :class=\"[previewClass, checkerClass]\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: cssColor }\" />\n </div>\n\n <!--\n Область насыщенность × светлота. Роль на обёртке — `group`, а не\n виджетная: внутри два настоящих `input[type=range]`, по одному на\n ось, и роль-виджет объявила бы их презентационными. Поля скрыты\n визуально, но остаются в таб-порядке — фокус показывает обёртка\n через `focus-within` (приём `GrFileUpload`).\n -->\n <div\n v-if=\"resolvedView === 'area'\"\n ref=\"areaEl\"\n data-gr-color-picker-area\n role=\"group\"\n :class=\"areaClass\"\n :aria-label=\"t('gr.colorPicker.area', 'Saturation and lightness')\"\n @pointerdown=\"areaDrag.start\"\n >\n <input\n ref=\"saturationInputEl\"\n data-gr-color-picker-area-axis=\"saturation\"\n type=\"range\"\n min=\"0\"\n max=\"100\"\n :value=\"areaPoint.s\"\n :class=\"areaInputClass\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.saturation', 'Saturation')\"\n :aria-valuetext=\"percent(areaPoint.s)\"\n @keydown=\"onAreaKeydown($event, 'saturation')\"\n @input=\"onAreaInput($event, 'saturation')\"\n >\n <input\n ref=\"lightnessInputEl\"\n data-gr-color-picker-area-axis=\"lightness\"\n type=\"range\"\n min=\"0\"\n max=\"100\"\n :value=\"areaPoint.l\"\n :class=\"areaInputClass\"\n :disabled=\"isDisabled\"\n :aria-label=\"t('gr.colorPicker.lightness', 'Lightness')\"\n :aria-valuetext=\"percent(areaPoint.l)\"\n @keydown=\"onAreaKeydown($event, 'lightness')\"\n @input=\"onAreaInput($event, 'lightness')\"\n >\n\n <span\n data-gr-color-picker-area-thumb\n aria-hidden=\"true\"\n :class=\"areaThumbClass\"\n :style=\"areaThumbStyle\"\n />\n </div>\n\n <div data-gr-color-picker-channel=\"hue\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">H</span>\n <GrSlider\n v-model=\"hue\"\n :min=\"0\"\n :max=\"359\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"degrees\"\n :aria-label=\"t('gr.colorPicker.hue', 'Hue')\"\n />\n <span :class=\"rowValueClass\">{{ degrees(hue) }}</span>\n </div>\n\n <template v-if=\"resolvedView === 'sliders'\">\n <div data-gr-color-picker-channel=\"saturation\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">S</span>\n <GrSlider\n v-model=\"saturation\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.saturation', 'Saturation')\"\n />\n <span :class=\"rowValueClass\">{{ percent(saturation) }}</span>\n </div>\n\n <div data-gr-color-picker-channel=\"lightness\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">L</span>\n <GrSlider\n v-model=\"lightness\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.lightness', 'Lightness')\"\n />\n <span :class=\"rowValueClass\">{{ percent(lightness) }}</span>\n </div>\n </template>\n\n <div v-if=\"alpha\" data-gr-color-picker-channel=\"alpha\" :class=\"rowClass\">\n <span :class=\"rowLabelClass\" aria-hidden=\"true\">A</span>\n <GrSlider\n v-model=\"opacity\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :format-tooltip=\"percent\"\n :aria-label=\"t('gr.colorPicker.opacity', 'Opacity')\"\n />\n <span :class=\"rowValueClass\">{{ percent(opacity) }}</span>\n </div>\n\n <div :class=\"hexRowClass\">\n <GrInput\n v-model=\"hexDraft\"\n data-gr-color-picker-hex\n :class=\"hexFieldClass\"\n :size=\"resolvedSize\"\n :disabled=\"isDisabled\"\n :readonly=\"isReadonly\"\n :aria-label=\"t('gr.colorPicker.hexLabel', 'Hex value')\"\n @change=\"commitHex\"\n @keydown.enter=\"commitHex\"\n />\n\n <button\n v-if=\"showEyedropper\"\n data-gr-color-picker-eyedropper\n type=\"button\"\n :class=\"eyedropperClassName\"\n :disabled=\"isLocked\"\n :aria-label=\"t('gr.colorPicker.eyedropper', 'Pick a colour from the screen')\"\n @click=\"pickFromScreen\"\n >\n <IconPipette :class=\"eyedropperIconClass\" aria-hidden=\"true\" />\n </button>\n </div>\n\n <div\n v-if=\"presetList.length\"\n data-gr-color-picker-presets\n :class=\"presetsGridClass\"\n role=\"group\"\n :aria-label=\"t('gr.colorPicker.presetsLabel', 'Color presets')\"\n >\n <button\n v-for=\"preset in presetList\"\n :key=\"preset\"\n data-gr-color-picker-preset\n type=\"button\"\n :class=\"[grColorPickerPresetClass(isPresetSelected(preset)), checkerClass]\"\n :aria-label=\"t('gr.colorPicker.swatchLabel', 'Color {color}', { color: preset })\"\n :aria-pressed=\"isPresetSelected(preset) ? 'true' : 'false'\"\n :disabled=\"isLocked\"\n @click=\"selectPreset(preset)\"\n >\n <span :class=\"swatchFillClass\" :style=\"{ background: preset }\" />\n </button>\n </div>\n </div>\n </template>\n </GrPopover>\n </div>\n</template>\n\n<style>\n/*\n * Шахматка под прозрачным цветом. Двумя `conic-gradient` — в утилите такое не\n * выражается, а без подложки прозрачный образец сливается с панелью.\n */\n.gr-color-picker-checker {\n background-image:\n conic-gradient(\n from 90deg,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 25%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0 50%,\n var(--gr-color-picker-checker-light, var(--gr-bg)) 0 75%,\n var(--gr-color-picker-checker-dark, var(--gr-muted)) 0\n );\n background-size:\n calc(var(--gr-color-picker-checker-size, 6px) * 2)\n calc(var(--gr-color-picker-checker-size, 6px) * 2);\n /* Рамка образца полупрозрачна, и без обрезки шахматка просвечивает сквозь неё. */\n background-clip: padding-box;\n}\n\n/*\n * Дорожки каналов. Красим `[data-gr-slider-track]` потому, что хук\n * `--gr-slider-rail` уходит в `background-color`, а градиент там не работает.\n * Сами градиенты компонент подаёт переменными — CSS остаётся статичной.\n */\n[data-gr-color-picker-channel] [data-gr-slider-track] {\n border-radius: var(--gr-radius-full);\n}\n\n[data-gr-color-picker-channel='hue'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-hue);\n}\n\n[data-gr-color-picker-channel='saturation'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-saturation);\n}\n\n[data-gr-color-picker-channel='lightness'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-lightness);\n}\n\n[data-gr-color-picker-channel='alpha'] [data-gr-slider-track] {\n background-image: var(--gr-color-picker-track-alpha);\n}\n\n/* Заливка канала прозрачна: шкалу показывает сама дорожка. */\n[data-gr-color-picker-channel] [data-gr-slider-fill] {\n background-color: transparent;\n}\n\n/*\n * Заливка области. Три слоя, и порядок важен: белая вуаль сверху, чёрная снизу,\n * под ними — шкала насыщенности при светлоте 50%.\n *\n * Пара вуалей даёт **точный** HSL, а не похожий на него: осветление и\n * затемнение в HSL — линейная интерполяция к белому и к чёрному, ровно то же,\n * что делает наложение с альфой. Поэтому цвет под ручкой совпадает с образцом\n * и с hex до последнего разряда.\n */\n[data-gr-color-picker-area] {\n background-image:\n linear-gradient(\n to bottom,\n rgb(255 255 255) 0%,\n rgb(255 255 255 / 0) 50%,\n rgb(0 0 0 / 0) 50%,\n rgb(0 0 0) 100%\n ),\n var(--gr-color-picker-area-saturation);\n}\n</style>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrColorPicker_default } from "./chunks/GrColorPicker-BRM_4lyI.js";
2
- import { n as grColorPickerSafelist, t as grColorPickerConfig } from "../../chunks/config-DIDz_E5m.js";
1
+ import { t as GrColorPicker_default } from "./chunks/GrColorPicker-vGSgpUV9.js";
2
+ import { n as grColorPickerSafelist, t as grColorPickerConfig } from "../../chunks/config-B34mkd53.js";
3
3
  export { GrColorPicker_default as GrColorPicker, GrColorPicker_default as default, grColorPickerConfig, grColorPickerSafelist };
@@ -1 +1 @@
1
- .gr-color-picker-checker{background-image:conic-gradient(from 90deg, var(--gr-color-picker-checker-light,var(--gr-bg)) 0 25%, var(--gr-color-picker-checker-dark,var(--gr-muted)) 0 50%, var(--gr-color-picker-checker-light,var(--gr-bg)) 0 75%, var(--gr-color-picker-checker-dark,var(--gr-muted)) 0);background-size:calc(var(--gr-color-picker-checker-size,6px) * 2) calc(var(--gr-color-picker-checker-size,6px) * 2);background-clip:padding-box}[data-gr-color-picker-channel] [data-gr-slider-track]{border-radius:var(--gr-radius-full)}[data-gr-color-picker-channel=hue] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-hue)}[data-gr-color-picker-channel=saturation] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-saturation)}[data-gr-color-picker-channel=lightness] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-lightness)}[data-gr-color-picker-channel=alpha] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-alpha)}[data-gr-color-picker-channel] [data-gr-slider-fill]{background-color:#0000}
1
+ .gr-color-picker-checker{background-image:conic-gradient(from 90deg, var(--gr-color-picker-checker-light,var(--gr-bg)) 0 25%, var(--gr-color-picker-checker-dark,var(--gr-muted)) 0 50%, var(--gr-color-picker-checker-light,var(--gr-bg)) 0 75%, var(--gr-color-picker-checker-dark,var(--gr-muted)) 0);background-size:calc(var(--gr-color-picker-checker-size,6px) * 2) calc(var(--gr-color-picker-checker-size,6px) * 2);background-clip:padding-box}[data-gr-color-picker-channel] [data-gr-slider-track]{border-radius:var(--gr-radius-full)}[data-gr-color-picker-channel=hue] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-hue)}[data-gr-color-picker-channel=saturation] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-saturation)}[data-gr-color-picker-channel=lightness] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-lightness)}[data-gr-color-picker-channel=alpha] [data-gr-slider-track]{background-image:var(--gr-color-picker-track-alpha)}[data-gr-color-picker-channel] [data-gr-slider-fill]{background-color:#0000}[data-gr-color-picker-area]{background-image:linear-gradient(to bottom, #fff 0%, #fff0 50%, #0000 50%, #000 100%), var(--gr-color-picker-area-saturation)}
@@ -1,14 +1,16 @@
1
1
  import { i as useGrComponentProp } from "../../../chunks/context-CPMRfwVr.js";
2
2
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
- import { n as isAppleDevice, r as isComposingEvent } from "../../../chunks/keyboard-DE2yhz_b.js";
3
+ import { a as parseHotkeySequence, n as isComposingEvent, t as isAppleDevice } from "../../../chunks/keyboard-BiFSgWLt.js";
4
+ import { t as createHotkeySequenceTracker } from "../../../chunks/hotkeySequence-BTHIM_5A.js";
4
5
  import { t as loader_circle_default } from "../../../chunks/loader-circle-CfVLz7lb.js";
5
6
  import { i as normalizeOptionQuery, r as matchesQueryParts } from "../../../chunks/optionFilter-DYw9XPPx.js";
6
7
  import { useVirtualList } from "../../../composables/useVirtualList.js";
7
8
  import { useComboboxNavigation } from "../../../composables/useComboboxNavigation.js";
8
9
  import { t as _plugin_vue_export_helper_default } from "../../../chunks/_plugin-vue_export-helper-BOaGB7Aw.js";
9
10
  import { n as iconTag, t as iconClass } from "../../../chunks/icon-Dag2tIMs.js";
10
- import { i as parseCommandHotkey, n as formatCommandHotkey, r as matchesCommandHotkey, t as GrKbd_default } from "../../GrKbd/chunks/GrKbd-BNMeoaLV.js";
11
- import { t as GrModal_default } from "../../GrModal/chunks/GrModal-Cm0mtSXk.js";
11
+ import { useHotkeys } from "../../../composables/useHotkeys.js";
12
+ import { n as formatCommandHotkey, t as GrKbd_default } from "../../GrKbd/chunks/GrKbd-D2rHDkQv.js";
13
+ import { t as GrModal_default } from "../../GrModal/chunks/GrModal-SHb1U2qx.js";
12
14
  import { a as commandGroupLabelClass, c as commandItemMutedClass, d as commandSearchInputClass, f as commandSearchRowClass, i as commandFooterClass, l as commandMatchClass, o as commandItemClass, r as commandEmptyClass, s as commandItemDescriptionClass, u as commandPaletteModalSizeBySize } from "../../../chunks/config-D0NzGYaE.js";
13
15
  import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, markRaw, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useId, watch, withCtx } from "vue";
14
16
  import '../styles.css';//#region src/components/GrCommandPalette/filtering.ts
@@ -206,6 +208,7 @@ var GrCommandPalette_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/
206
208
  placeholder: { default: void 0 },
207
209
  size: { default: void 0 },
208
210
  hotkey: { default: "mod+k" },
211
+ hotkeyId: { default: void 0 },
209
212
  filterable: {
210
213
  type: Boolean,
211
214
  default: true
@@ -418,12 +421,25 @@ var GrCommandPalette_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/
418
421
  watch([() => props.modelValue, inputEl], ([open]) => {
419
422
  if (open) inputEl.value?.focus();
420
423
  }, { flush: "post" });
421
- const parsedHotkey = computed(() => props.hotkey ? parseCommandHotkey(props.hotkey) : null);
424
+ const registry = useHotkeys();
425
+ /** Реестр сильнее пропа: два источника сочетания молча спорить не должны. */
426
+ const hotkeyValue = computed(() => props.hotkeyId !== void 0 ? registry.keysOf(props.hotkeyId) : props.hotkey);
427
+ /**
428
+ * Шаги открытия. Аккорд — один шаг, `'g p'` — два: палитра берёт тот же разбор,
429
+ * что и директива, поэтому цепочка открывает её так же, как и любое другое место.
430
+ */
431
+ const hotkeySteps = computed(() => hotkeyValue.value ? parseHotkeySequence(hotkeyValue.value) : []);
432
+ const parsedHotkey = computed(() => hotkeySteps.value[0] ?? null);
433
+ const sequence = createHotkeySequenceTracker();
422
434
  const isApple = ref(false);
423
435
  const hotkeyHint = computed(() => props.showHotkeyHint && parsedHotkey.value ? formatCommandHotkey(parsedHotkey.value, isApple.value) : []);
424
436
  function onWindowKeydown(event) {
425
- const hotkey = parsedHotkey.value;
426
- if (!hotkey || !matchesCommandHotkey(event, hotkey, isApple.value)) return;
437
+ const steps = hotkeySteps.value;
438
+ if (steps.length === 0) return;
439
+ if (isComposingEvent(event)) return;
440
+ sequence.push(event, Date.now());
441
+ if (!sequence.matches(steps, isApple.value)) return;
442
+ sequence.reset();
427
443
  event.preventDefault();
428
444
  toggle();
429
445
  }
@@ -586,6 +602,6 @@ var GrCommandPalette_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/
586
602
  }, 8, ["model-value", "size"]);
587
603
  };
588
604
  }
589
- }), [["__scopeId", "data-v-041dfab7"]]);
605
+ }), [["__scopeId", "data-v-eb4919ed"]]);
590
606
  //#endregion
591
607
  export { GrCommandPalette_default as t };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrCommandPalette-CAHgj0Aa.js","names":["$emit","$slots"],"sources":["../../../../src/components/GrCommandPalette/filtering.ts","../../../../src/components/GrCommandPalette/GrCommandPalette.vue","../../../../src/components/GrCommandPalette/GrCommandPalette.vue"],"sourcesContent":["import type { Component } from 'vue'\n\nimport { matchesQueryParts, normalizeOptionQuery } from '../shared/optionFilter'\n\n/** Команда палитры. `id` обязателен — он же ключ рендера и цель `aria-activedescendant`. */\nexport type GrCommandItem = {\n id: string\n label: string\n /** Пояснение под меткой. */\n description?: string\n /**\n * Иконка команды: Vue-компонент либо класс иконки вашей UnoCSS-сборки\n * (`'i-lucide-file-plus'` — тогда нужен ваш `presetIcons`).\n */\n icon?: string | Component\n /** Подсказка сочетания клавиш — массив клавиш, каждая рисуется отдельным `GrKbd`. */\n shortcut?: string[]\n /** Заголовок группы, под которой команда показывается в списке. */\n group?: string\n /** Дополнительные слова для поиска (синонимы, транслитерация). */\n keywords?: string[]\n disabled?: boolean\n}\n\n/** Команды, сгруппированные для рендера: порядок групп — порядок первого вхождения. */\nexport type GrCommandGroup = {\n /** `undefined` — команды без группы (рендерятся без заголовка). */\n name: string | undefined\n items: GrCommandItem[]\n}\n\nexport type GrCommandFilter = (item: GrCommandItem, query: string) => boolean\n\n/**\n * Матчер по умолчанию: подстрока (без учёта регистра) в метке, описании,\n * названии группы или ключевых словах.\n *\n * Набор полей у команды шире, чем у опции списка, а сам подстрочный матч — тот\n * же самый на весь пакет (`shared/optionFilter.ts`).\n */\nexport function matchCommandItem(item: GrCommandItem, query: string): boolean {\n const parts = [item.label, item.description, item.group, ...(item.keywords ?? [])]\n\n return matchesQueryParts(parts, normalizeOptionQuery(query))\n}\n\nexport function filterCommandItems(\n items: GrCommandItem[],\n query: string,\n filter: GrCommandFilter = matchCommandItem,\n): GrCommandItem[] {\n if (!query.trim())\n return items\n return items.filter(item => filter(item, query))\n}\n\n/**\n * Раскладывает плоский список по группам, сохраняя порядок первого появления\n * группы. Команды без `group` собираются в единственную безымянную группу,\n * которая остаётся на своём месте в общем порядке.\n */\nexport function groupCommandItems(items: GrCommandItem[]): GrCommandGroup[] {\n const groups: GrCommandGroup[] = []\n const byName = new Map<string | undefined, GrCommandGroup>()\n\n for (const item of items) {\n const name = item.group || undefined\n let group = byName.get(name)\n if (!group) {\n group = { name, items: [] }\n byName.set(name, group)\n groups.push(group)\n }\n group.items.push(item)\n }\n\n return groups\n}\n\n/** Кусок текста для подсветки: `match` — попал в запрос. */\nexport type GrCommandMatchSegment = {\n text: string\n match: boolean\n}\n\n/**\n * Режет текст на сегменты по вхождению запроса (без учёта регистра).\n *\n * Совпадения нет — один сегмент целиком: свой `filter` вправе матчить по\n * `keywords`, и тогда в метке подсвечивать нечего. Регистр исходного текста\n * сохраняется — подсветка не должна менять то, что читает пользователь.\n */\nexport function splitCommandMatch(text: string, query: string): GrCommandMatchSegment[] {\n const needle = query.trim().toLowerCase()\n if (!needle || !text)\n return [{ text, match: false }]\n\n const segments: GrCommandMatchSegment[] = []\n const haystack = text.toLowerCase()\n let from = 0\n\n while (from < text.length) {\n const at = haystack.indexOf(needle, from)\n if (at < 0)\n break\n\n if (at > from)\n segments.push({ text: text.slice(from, at), match: false })\n segments.push({ text: text.slice(at, at + needle.length), match: true })\n from = at + needle.length\n }\n\n if (!segments.length)\n return [{ text, match: false }]\n if (from < text.length)\n segments.push({ text: text.slice(from), match: false })\n\n return segments\n}\n\n/**\n * Поднимает «недавние» команды в отдельную группу наверх, сохраняя порядок\n * `recentIds`, и убирает их из остального списка — иначе одна и та же команда\n * оказалась бы в списке дважды, а `id` у неё один.\n */\nexport function withRecentCommands(\n groups: GrCommandGroup[],\n items: GrCommandItem[],\n recentIds: string[],\n title: string,\n): GrCommandGroup[] {\n if (!recentIds.length)\n return groups\n\n const byId = new Map(items.map(item => [item.id, item]))\n const recent: GrCommandItem[] = []\n const taken = new Set<string>()\n\n for (const id of recentIds) {\n const item = byId.get(id)\n if (!item || taken.has(id))\n continue\n recent.push(item)\n taken.add(id)\n }\n\n if (!recent.length)\n return groups\n\n const rest = groups\n .map(group => ({ ...group, items: group.items.filter(item => !taken.has(item.id)) }))\n .filter(group => group.items.length > 0)\n\n return [{ name: title, items: recent }, ...rest]\n}\n\n/** Идентификаторы, встретившиеся больше одного раза. */\nexport function findDuplicateCommandIds(items: GrCommandItem[]): string[] {\n const seen = new Set<string>()\n const duplicates = new Set<string>()\n\n for (const item of items) {\n if (seen.has(item.id))\n duplicates.add(item.id)\n else seen.add(item.id)\n }\n\n return [...duplicates]\n}\n","<script setup lang=\"ts\">\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { isComposingEvent, parseHotkeySequence } from '../../internal/keyboard'\nimport { useComboboxNavigation } from '../../composables/useComboboxNavigation'\nimport { iconClass, iconTag } from '../shared/icon'\nimport GrKbd from '../GrKbd/GrKbd.vue'\nimport GrModal from '../GrModal/GrModal.vue'\n\nimport {\n filterCommandItems,\n findDuplicateCommandIds,\n groupCommandItems,\n matchCommandItem,\n splitCommandMatch,\n withRecentCommands,\n type GrCommandFilter,\n type GrCommandItem,\n} from './filtering'\nimport { useHotkeys } from '../../composables/useHotkeys'\nimport { createHotkeySequenceTracker } from '../../internal/hotkeySequence'\nimport {\n formatCommandHotkey,\n isAppleDevice,\n} from '../shared/hotkey'\nimport {\n commandEmptyClass,\n commandFooterClass,\n commandGroupLabelClass,\n commandItemClass,\n commandItemDescriptionClass,\n commandItemMutedClass,\n commandMatchClass,\n commandPaletteModalSizeBySize,\n commandSearchInputClass,\n commandSearchRowClass,\n type GrCommandPaletteSize,\n} from './grCommandPaletteStyles'\n\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconSearch from '~icons/lucide/search'\n\nexport type { GrCommandFilter, GrCommandGroup, GrCommandItem } from './filtering'\nexport type { GrCommandPaletteSize } from './grCommandPaletteStyles'\n\n/**\n * Публичный GR-примитив «Command palette» (⌘K) — модальный поиск по командам\n * приложения с группировкой, подсказками сочетаний и клавиатурной навигацией.\n *\n * A11y: WAI-ARIA combobox поверх модалки — `role=\"combobox\"` на поле ввода,\n * `role=\"listbox\"` на списке, `aria-activedescendant` на активной команде\n * (фокус остаётся в поле). Esc, фокус-ловушка и блокировка скролла приходят\n * из `GrModal`.\n *\n * Открытие по глобальному сочетанию (`hotkey`, по умолчанию `mod+k` — Cmd на\n * macOS, Ctrl на прочих) компонент берёт на себя; передайте `hotkey: null`,\n * чтобы управлять открытием только через `v-model`.\n */\nexport interface GrCommandPaletteProps {\n /** Открыта ли палитра. */\n modelValue: boolean\n /** Плоский список команд; группировка — по полю `group` самой команды. */\n items?: GrCommandItem[]\n /**\n * Недавние команды: пока запрос пуст, они поднимаются отдельной группой\n * наверх в этом порядке и не дублируются ниже.\n */\n recentIds?: string[]\n placeholder?: string\n size?: GrCommandPaletteSize\n /** Глобальное сочетание открытия. `null` — не вешать слушатель. */\n hotkey?: string | null\n /**\n * Идентификатор записи в реестре (`granularityHotkeysPlugin`) вместо\n * сочетания строкой: подсказка и привязка берутся из одного источника и не\n * могут разойтись. Сильнее `hotkey`.\n */\n hotkeyId?: string\n /** Локальная фильтрация по запросу. `false` — фильтрует владелец по событию `search`. */\n filterable?: boolean\n /** Кастомный матчер локальной фильтрации. */\n filter?: GrCommandFilter\n /** Внешне управляемое состояние загрузки (для remote-поиска). */\n loading?: boolean\n /** Закрывать палитру после выбора команды. */\n closeOnSelect?: boolean\n /** Максимальная высота списка, px. */\n maxHeight?: number\n /**\n * Виртуализация списка: в DOM живёт только окно вокруг вьюпорта. Высоту окна\n * задаёт `maxHeight`.\n *\n * Включается осознанно: на сотне команд выигрыша нет, а в разметке остаётся\n * только окно — вместе с ним меняется и то, что находит `querySelector`\n * потребителя. Профильный сценарий — палитра приложения на тысячи команд.\n */\n virtual?: boolean\n /** Показывать подсказку сочетания в поле ввода. */\n showHotkeyHint?: boolean\n emptyText?: string\n ariaLabel?: string\n}\n\nexport interface GrCommandPaletteEmits {\n (e: 'update:modelValue', value: boolean): void\n /** Команда выбрана (клик или Enter). */\n (e: 'select', item: GrCommandItem): void\n /** Поисковый запрос изменился — точка входа для remote-поиска. */\n (e: 'search', query: string): void\n}\n\nimport './defaults'\n\nconst props = withDefaults(\n defineProps<GrCommandPaletteProps>(),\n {\n items: undefined,\n recentIds: undefined,\n placeholder: undefined,\n // Дефолт `size` живёт в резолвере ниже, а не здесь: Vue подставил бы его\n // до того, как компонент заглянет в `GrConfigProvider`.\n size: undefined,\n hotkey: 'mod+k',\n hotkeyId: undefined,\n filterable: true,\n filter: undefined,\n loading: false,\n closeOnSelect: true,\n maxHeight: 360,\n virtual: false,\n showHotkeyHint: true,\n emptyText: undefined,\n ariaLabel: undefined,\n },\n)\n\nconst emit = defineEmits<GrCommandPaletteEmits>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedPlaceholder = computed(() => props.placeholder ?? t('gr.commandPalette.placeholder', 'Type a command or search…'))\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.commandPalette.empty', 'Nothing found'))\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.commandPalette.label', 'Command palette'))\nconst loadingText = computed(() => t('gr.commandPalette.loading', 'Loading…'))\nconst recentTitle = computed(() => t('gr.commandPalette.recent', 'Recent'))\n\nconst query = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\nconst listboxId = useId()\n\nconst itemsResolved = computed<GrCommandItem[]>(() => props.items ?? [])\n\nconst filteredItems = computed<GrCommandItem[]>(() =>\n props.filterable\n ? filterCommandItems(itemsResolved.value, query.value, props.filter ?? matchCommandItem)\n : itemsResolved.value,\n)\n\nconst groups = computed(() => {\n const grouped = groupCommandItems(filteredItems.value)\n\n // С непустым запросом секции «недавние» нет: там правит релевантность, а не\n // история — иначе первая же буква уводила бы взгляд не туда.\n if (query.value.trim())\n return grouped\n\n return withRecentCommands(grouped, filteredItems.value, props.recentIds ?? [], recentTitle.value)\n})\n\n/**\n * Порядок обхода стрелками совпадает с порядком на экране: «недавние» стоят\n * первыми, значит и первая стрелка ведёт туда же.\n */\nconst orderedItems = computed(() => groups.value.flatMap(group => group.items))\n\n/** Плоский список того, что реально выбирается — по нему ходят стрелки. */\nconst navigableItems = computed(() => orderedItems.value.filter(item => !item.disabled))\n\nfunction itemDomId(id: string): string {\n return `${listboxId}-item-${id}`\n}\n\n/**\n * Виртуализация списка.\n *\n * Набор — плоский поток строк экрана: заголовок группы занимает такую же\n * строку, как команда, поэтому входит в него наравне. Вложенную структуру\n * рендер пересобирает уже из окна.\n */\n\n/** Оценки высоты строк. Команда крупнее заголовка; дальше уточняются замером. */\nconst ITEM_SIZE_ESTIMATE = 44\nconst GROUP_LABEL_SIZE_ESTIMATE = 28\n\ntype PaletteRow\n = | { kind: 'label', groupIndex: number }\n | { kind: 'item', groupIndex: number, item: GrCommandItem, posInSet: number, setSize: number }\n\nconst listEl = ref<HTMLElement | null>(null)\n\nconst paletteRows = computed<PaletteRow[]>(() => {\n const rows: PaletteRow[] = []\n\n groups.value.forEach((group, groupIndex) => {\n if (group.name)\n rows.push({ kind: 'label', groupIndex })\n\n group.items.forEach((item, index) => {\n rows.push({\n kind: 'item',\n groupIndex,\n item,\n // Набор — группа, а не весь список: по ARIA позиция отсчитывается от неё.\n posInSet: index + 1,\n setSize: group.items.length,\n })\n })\n })\n\n return rows\n})\n\nconst virtualizer = useVirtualList({\n container: listEl,\n count: () => (props.virtual ? paletteRows.value.length : 0),\n // Запрос пересобирает набор строк — замеры прошлого набора невалидны.\n source: () => paletteRows.value,\n itemSize: index => (paletteRows.value[index]?.kind === 'label' ? GROUP_LABEL_SIZE_ESTIMATE : ITEM_SIZE_ESTIMATE),\n // Список закрытой палитры не смонтирован вовсе: `clientHeight` взять неоткуда.\n // `maxHeight` можно перебить `--gr-command-list-max-height` — тогда точная\n // высота приедет с первым замером, а это останется оценкой первого рендера.\n viewportSize: () => props.maxHeight,\n})\n\n/**\n * Группы к отрисовке. При виртуализации пересобираются из среза `paletteRows`:\n * группа, начатая выше окна, всё равно открывается — иначе её команды остались\n * бы прямыми потомками listbox'а, что роль запрещает.\n */\ntype RenderedGroup = {\n key: string\n groupIndex: number\n name: string | undefined\n labelVisible: boolean\n /** Позиция строки заголовка в `paletteRows` — по ней его замеряет виртуализатор. */\n labelRowIndex?: number\n items: { item: GrCommandItem, rowIndex: number, posInSet: number, setSize: number }[]\n}\n\nconst renderedGroups = computed<RenderedGroup[]>(() => {\n const rows = paletteRows.value\n\n const from = props.virtual ? virtualizer.range.value.start : 0\n const to = props.virtual ? Math.min(rows.length, virtualizer.range.value.end) : rows.length\n\n const result: RenderedGroup[] = []\n let current: RenderedGroup | undefined\n\n for (let rowIndex = from; rowIndex < to; rowIndex++) {\n const row = rows[rowIndex]!\n const group = groups.value[row.groupIndex]\n\n if (!current || current.groupIndex !== row.groupIndex) {\n current = {\n key: group?.name ?? `__ungrouped-${row.groupIndex}`,\n groupIndex: row.groupIndex,\n name: group?.name,\n labelVisible: false,\n items: [],\n }\n result.push(current)\n }\n\n if (row.kind === 'label') {\n current.labelVisible = true\n current.labelRowIndex = rowIndex\n continue\n }\n\n current.items.push({ item: row.item, rowIndex, posInSet: row.posInSet, setSize: row.setSize })\n }\n\n return result\n})\n\n/** ARIA набора: объявляем только при виртуализации — иначе набор виден по DOM. */\nfunction itemSetProps(entry: { posInSet: number, setSize: number }): Record<string, number> | undefined {\n if (!props.virtual)\n return undefined\n return { 'aria-setsize': entry.setSize, 'aria-posinset': entry.posInSet }\n}\n\n/** Сегменты подсветки: совпавшее с запросом рисуется `<mark>`. */\nfunction matchSegments(text: string): ReturnType<typeof splitCommandMatch> {\n return splitCommandMatch(text, props.filterable ? query.value : '')\n}\n\nasync function scrollActiveIntoView(item: GrCommandItem): Promise<void> {\n // Вне окна активной команды в DOM нет: `getElementById` вернул бы `null`,\n // прокрутка не случилась бы, а `aria-activedescendant` указал бы в пустоту.\n if (props.virtual) {\n const rowIndex = paletteRows.value.findIndex(row => row.kind === 'item' && row.item.id === item.id)\n if (rowIndex >= 0)\n virtualizer.scrollToIndex(rowIndex)\n }\n\n await nextTick()\n document.getElementById(itemDomId(item.id))?.scrollIntoView?.({ block: 'nearest' })\n}\n\nconst {\n activeItem,\n activeDescendantId,\n setActive,\n reset: resetActive,\n handleNavigationKeys,\n} = useComboboxNavigation<GrCommandItem>({\n items: () => navigableItems.value,\n open: () => props.modelValue,\n idOf: item => itemDomId(item.id),\n scrollTo: item => scrollActiveIntoView(item),\n})\n\n// Палитра всегда стартует с первой команды — и при монтировании открытой тоже.\nresetActive(0)\n\nfunction isActive(item: GrCommandItem): boolean {\n return activeItem.value?.id === item.id\n}\n\n// Активной становится первая команда, когда список изменился **по содержимому**.\n// Следить за идентичностью массива нельзя: родитель, отдающий `:items` инлайн-\n// выражением, пересоздаёт его на каждый посторонний ререндер — и выбранная\n// стрелками команда прыгала бы в начало.\n// Разделитель — пробел, а не запятая: `id` вправе её содержать, и «a,b» + «c»\n// дало бы тот же ключ, что «a» + «b,c».\nwatch(\n () => orderedItems.value.map(item => item.id).join(' '),\n () => resetActive(0),\n)\n\n// `id` — ключ рендера и цель `aria-activedescendant`: дубли дают одинаковые\n// DOM-id, и фокус уезжает не на ту команду.\nwatch(\n itemsResolved,\n (items) => {\n if (!__GR_DEV__)\n return\n const duplicates = findDuplicateCommandIds(items)\n if (!duplicates.length)\n return\n\n console.warn(\n `[GrCommandPalette] повторяющиеся id команд: ${duplicates.join(', ')}. `\n + 'Из-за одинаковых DOM-id `aria-activedescendant` укажет не на ту команду.',\n )\n },\n { immediate: true },\n)\n\nfunction open(): void {\n emit('update:modelValue', true)\n}\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction toggle(): void {\n emit('update:modelValue', !props.modelValue)\n}\n\nfunction selectItem(item: GrCommandItem): void {\n if (item.disabled)\n return\n emit('select', item)\n if (props.closeOnSelect)\n close()\n}\n\nfunction onItemHover(item: GrCommandItem): void {\n const index = navigableItems.value.indexOf(item)\n if (index >= 0)\n setActive(index)\n}\n\nfunction onInput(event: Event): void {\n query.value = (event.target as HTMLInputElement).value\n emit('search', query.value.trim())\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n // Клавиша во время IME-композиции принадлежит композиции: Enter коммитит её,\n // стрелки ходят по кандидатам.\n if (isComposingEvent(event))\n return\n\n if (handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'Enter':\n if (!activeItem.value)\n break\n event.preventDefault()\n selectItem(activeItem.value)\n break\n }\n}\n\n// ————— Открытие: сброс запроса и выбора.\nwatch(\n () => props.modelValue,\n (open) => {\n if (!open)\n return\n\n query.value = ''\n resetActive(0)\n },\n)\n\n// Фокус в поле — отдельным наблюдателем, и по появлению самого поля: содержимое\n// панели рождается вместе с ней, и по одному лишь пропу фокусировать нечего.\n// Ловушка фокуса `GrModal` этот выбор не перебивает — фокус, уже стоящий внутри\n// слоя, она считает осознанным.\nwatch(\n [() => props.modelValue, inputEl],\n ([open]) => {\n if (open)\n inputEl.value?.focus()\n },\n { flush: 'post' },\n)\n\n// ————— Глобальное сочетание открытия.\n\nconst registry = useHotkeys()\n\n/** Реестр сильнее пропа: два источника сочетания молча спорить не должны. */\nconst hotkeyValue = computed(() => (props.hotkeyId !== undefined\n ? registry.keysOf(props.hotkeyId)\n : props.hotkey))\n\n/**\n * Шаги открытия. Аккорд — один шаг, `'g p'` — два: палитра берёт тот же разбор,\n * что и директива, поэтому цепочка открывает её так же, как и любое другое место.\n */\nconst hotkeySteps = computed(() => (hotkeyValue.value ? parseHotkeySequence(hotkeyValue.value) : []))\n\nconst parsedHotkey = computed(() => hotkeySteps.value[0] ?? null)\n\nconst sequence = createHotkeySequenceTracker()\n\n// Платформа определяется только после монтирования: на сервере `navigator` нет,\n// и первый рендер обязан совпасть с серверным. Иначе сервер отдаёт `Ctrl`,\n// клиент на macOS рисует `⌘`, и гидрация расходится по тексту подсказки.\nconst isApple = ref(false)\n\nconst hotkeyHint = computed(() =>\n props.showHotkeyHint && parsedHotkey.value ? formatCommandHotkey(parsedHotkey.value, isApple.value) : [],\n)\n\nfunction onWindowKeydown(event: KeyboardEvent): void {\n const steps = hotkeySteps.value\n if (steps.length === 0)\n return\n\n // Клавиша во время IME-композиции принадлежит композиции, а не сочетанию.\n if (isComposingEvent(event))\n return\n\n sequence.push(event, Date.now())\n\n if (!sequence.matches(steps, isApple.value))\n return\n\n // Сложившаяся цепочка снимается с буфера: иначе следующее нажатие достроило\n // бы её заново и переключило палитру второй раз.\n sequence.reset()\n\n event.preventDefault()\n toggle()\n}\n\nonMounted(() => {\n if (typeof window === 'undefined')\n return\n isApple.value = isAppleDevice()\n window.addEventListener('keydown', onWindowKeydown)\n})\n\nonBeforeUnmount(() => {\n if (typeof window !== 'undefined')\n window.removeEventListener('keydown', onWindowKeydown)\n})\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentProp('GrCommandPalette', 'size', () => props.size, 'lg')\n\nconst modalSize = computed(() => commandPaletteModalSizeBySize[resolvedSize.value])\nconst listStyle = computed(() => ({ maxHeight: `var(--gr-command-list-max-height, ${props.maxHeight}px)` }))\n\nconst listStyleWithSpacers = computed(() => {\n const base = listStyle.value\n if (!props.virtual)\n return base\n\n return {\n ...base,\n ...virtualizer.spacerStyle.value,\n }\n})\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /** Строка списка вместо стандартной. */\n item?: (props: { item: GrCommandItem, active: boolean }) => any\n /** Пустое состояние: получает запрос, чтобы предложить действие по нему. */\n empty?: (props: { query: string }) => any\n /** Подвал палитры: подсказки по клавишам, счётчик. */\n footer?: () => any\n}>()\n</script>\n\n<template>\n <GrModal\n :model-value=\"modelValue\"\n :size=\"modalSize\"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n >\n <div data-gr-command-palette :aria-label=\"resolvedAriaLabel\">\n <div data-gr-command-palette-search :class=\"commandSearchRowClass\">\n <IconSearch class=\"block h-4 w-4 shrink-0 text-[var(--gr-muted-fg)]\" aria-hidden=\"true\" />\n\n <input\n ref=\"inputEl\"\n data-gr-command-palette-input\n data-testid=\"gr-command-palette-input\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n :aria-label=\"resolvedAriaLabel\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendantId\"\n :value=\"query\"\n :placeholder=\"resolvedPlaceholder\"\n :class=\"commandSearchInputClass\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n >\n\n <span v-if=\"loading\" class=\"shrink-0 text-[var(--gr-muted-fg)]\" aria-hidden=\"true\">\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" />\n </span>\n <span v-else-if=\"hotkeyHint.length\" class=\"shrink-0\" aria-hidden=\"true\">\n <GrKbd :keys=\"hotkeyHint\" size=\"sm\" />\n </span>\n </div>\n\n <div\n :id=\"listboxId\"\n ref=\"listEl\"\n data-gr-command-palette-list\n data-testid=\"gr-command-palette-list\"\n :data-gr-virtual=\"virtual ? '' : undefined\"\n class=\"overflow-y-auto p-2\"\n :style=\"listStyleWithSpacers\"\n role=\"listbox\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <!-- Прямыми потомками listbox могут быть только `role=\"group\"`: заголовок\n группы лежит внутри неё и объявлен презентационным (имя группе он\n даёт через `aria-labelledby`), иначе ломается `aria-required-children`.\n\n При виртуализации окно может начаться ниже заголовка — тогда его в\n DOM нет, и имя группы идёт напрямую в `aria-label`. -->\n <div\n v-for=\"group in renderedGroups\"\n :key=\"group.key\"\n role=\"group\"\n :aria-labelledby=\"group.name && group.labelVisible ? `${listboxId}-group-${group.groupIndex}` : undefined\"\n :aria-label=\"group.name && !group.labelVisible ? group.name : undefined\"\n >\n <div\n v-if=\"group.name && group.labelVisible\"\n :id=\"`${listboxId}-group-${group.groupIndex}`\"\n :ref=\"(el) => virtual && group.labelRowIndex !== undefined && virtualizer.measure(group.labelRowIndex, el as Element | null)\"\n data-gr-command-palette-group\n role=\"presentation\"\n :class=\"commandGroupLabelClass\"\n >\n {{ group.name }}\n </div>\n\n <div>\n <div\n v-for=\"entry in group.items\"\n :id=\"itemDomId(entry.item.id)\"\n :key=\"entry.item.id\"\n :ref=\"(el) => virtual && virtualizer.measure(entry.rowIndex, el as Element | null)\"\n data-gr-command-palette-item\n :data-testid=\"`gr-command-palette-item-${entry.item.id}`\"\n role=\"option\"\n v-bind=\"itemSetProps(entry)\"\n :aria-selected=\"isActive(entry.item) ? 'true' : 'false'\"\n :aria-disabled=\"entry.item.disabled ? 'true' : undefined\"\n :class=\"commandItemClass({ active: isActive(entry.item), disabled: Boolean(entry.item.disabled) })\"\n @click=\"selectItem(entry.item)\"\n @mousemove=\"onItemHover(entry.item)\"\n >\n <slot name=\"item\" :item=\"entry.item\" :active=\"isActive(entry.item)\">\n <component\n :is=\"iconTag(entry.item.icon)\"\n v-if=\"entry.item.icon\"\n class=\"block h-4 w-4 shrink-0\"\n :class=\"[iconClass(entry.item.icon), commandItemMutedClass(Boolean(entry.item.disabled))]\"\n aria-hidden=\"true\"\n />\n <span class=\"min-w-0 flex-1\">\n <span class=\"block truncate\">\n <template v-for=\"(segment, index) in matchSegments(entry.item.label)\" :key=\"index\">\n <mark v-if=\"segment.match\" :class=\"commandMatchClass\">{{ segment.text }}</mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </span>\n <span\n v-if=\"entry.item.description\"\n :class=\"[commandItemDescriptionClass, commandItemMutedClass(Boolean(entry.item.disabled))]\"\n >\n <template v-for=\"(segment, index) in matchSegments(entry.item.description)\" :key=\"index\">\n <mark v-if=\"segment.match\" :class=\"commandMatchClass\">{{ segment.text }}</mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </span>\n </span>\n <span v-if=\"entry.item.shortcut?.length\" class=\"shrink-0\">\n <GrKbd :keys=\"entry.item.shortcut\" size=\"sm\" />\n </span>\n </slot>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Состояния объявляются живым регионом: `aria-label` на generic-элементе\n большинство AT игнорируют, и загрузка осталась бы неозвученной. Регион\n один на оба состояния и лежит вне listbox — внутри он стал бы его\n недопустимым потомком. -->\n <div\n v-if=\"loading || !filteredItems.length\"\n data-gr-command-palette-empty\n data-testid=\"gr-command-palette-empty\"\n role=\"status\"\n aria-live=\"polite\"\n :class=\"commandEmptyClass\"\n >\n <template v-if=\"loading\">\n {{ loadingText }}\n </template>\n <slot v-else name=\"empty\" :query=\"query\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <div v-if=\"$slots.footer\" data-gr-command-palette-footer :class=\"commandFooterClass\">\n <slot name=\"footer\" />\n </div>\n </div>\n </GrModal>\n</template>\n\n<style scoped>\n/*\n * Распорки виртуального списка.\n *\n * Не `padding` контейнера: `max-height` меряет ту же коробку. Не обёртка внутри\n * listbox'а: прямыми потомками роли обязаны быть только группы. Не отступы\n * крайних строк: при прыжке прокрутки строки заменяются целиком, и распорка\n * исчезла бы вместе с ними.\n *\n * `display: block` обязателен: список палитры — блочный поток, а псевдоэлемент\n * по умолчанию строчный, и строчная коробка игнорирует `height` — распорка\n * молча не создалась бы вовсе.\n */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { useGrComponentProp } from '../GrConfigProvider/context'\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { useVirtualList } from '../../composables/useVirtualList'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { isComposingEvent, parseHotkeySequence } from '../../internal/keyboard'\nimport { useComboboxNavigation } from '../../composables/useComboboxNavigation'\nimport { iconClass, iconTag } from '../shared/icon'\nimport GrKbd from '../GrKbd/GrKbd.vue'\nimport GrModal from '../GrModal/GrModal.vue'\n\nimport {\n filterCommandItems,\n findDuplicateCommandIds,\n groupCommandItems,\n matchCommandItem,\n splitCommandMatch,\n withRecentCommands,\n type GrCommandFilter,\n type GrCommandItem,\n} from './filtering'\nimport { useHotkeys } from '../../composables/useHotkeys'\nimport { createHotkeySequenceTracker } from '../../internal/hotkeySequence'\nimport {\n formatCommandHotkey,\n isAppleDevice,\n} from '../shared/hotkey'\nimport {\n commandEmptyClass,\n commandFooterClass,\n commandGroupLabelClass,\n commandItemClass,\n commandItemDescriptionClass,\n commandItemMutedClass,\n commandMatchClass,\n commandPaletteModalSizeBySize,\n commandSearchInputClass,\n commandSearchRowClass,\n type GrCommandPaletteSize,\n} from './grCommandPaletteStyles'\n\nimport IconLoaderCircle from '~icons/lucide/loader-circle'\nimport IconSearch from '~icons/lucide/search'\n\nexport type { GrCommandFilter, GrCommandGroup, GrCommandItem } from './filtering'\nexport type { GrCommandPaletteSize } from './grCommandPaletteStyles'\n\n/**\n * Публичный GR-примитив «Command palette» (⌘K) — модальный поиск по командам\n * приложения с группировкой, подсказками сочетаний и клавиатурной навигацией.\n *\n * A11y: WAI-ARIA combobox поверх модалки — `role=\"combobox\"` на поле ввода,\n * `role=\"listbox\"` на списке, `aria-activedescendant` на активной команде\n * (фокус остаётся в поле). Esc, фокус-ловушка и блокировка скролла приходят\n * из `GrModal`.\n *\n * Открытие по глобальному сочетанию (`hotkey`, по умолчанию `mod+k` — Cmd на\n * macOS, Ctrl на прочих) компонент берёт на себя; передайте `hotkey: null`,\n * чтобы управлять открытием только через `v-model`.\n */\nexport interface GrCommandPaletteProps {\n /** Открыта ли палитра. */\n modelValue: boolean\n /** Плоский список команд; группировка — по полю `group` самой команды. */\n items?: GrCommandItem[]\n /**\n * Недавние команды: пока запрос пуст, они поднимаются отдельной группой\n * наверх в этом порядке и не дублируются ниже.\n */\n recentIds?: string[]\n placeholder?: string\n size?: GrCommandPaletteSize\n /** Глобальное сочетание открытия. `null` — не вешать слушатель. */\n hotkey?: string | null\n /**\n * Идентификатор записи в реестре (`granularityHotkeysPlugin`) вместо\n * сочетания строкой: подсказка и привязка берутся из одного источника и не\n * могут разойтись. Сильнее `hotkey`.\n */\n hotkeyId?: string\n /** Локальная фильтрация по запросу. `false` — фильтрует владелец по событию `search`. */\n filterable?: boolean\n /** Кастомный матчер локальной фильтрации. */\n filter?: GrCommandFilter\n /** Внешне управляемое состояние загрузки (для remote-поиска). */\n loading?: boolean\n /** Закрывать палитру после выбора команды. */\n closeOnSelect?: boolean\n /** Максимальная высота списка, px. */\n maxHeight?: number\n /**\n * Виртуализация списка: в DOM живёт только окно вокруг вьюпорта. Высоту окна\n * задаёт `maxHeight`.\n *\n * Включается осознанно: на сотне команд выигрыша нет, а в разметке остаётся\n * только окно — вместе с ним меняется и то, что находит `querySelector`\n * потребителя. Профильный сценарий — палитра приложения на тысячи команд.\n */\n virtual?: boolean\n /** Показывать подсказку сочетания в поле ввода. */\n showHotkeyHint?: boolean\n emptyText?: string\n ariaLabel?: string\n}\n\nexport interface GrCommandPaletteEmits {\n (e: 'update:modelValue', value: boolean): void\n /** Команда выбрана (клик или Enter). */\n (e: 'select', item: GrCommandItem): void\n /** Поисковый запрос изменился — точка входа для remote-поиска. */\n (e: 'search', query: string): void\n}\n\nimport './defaults'\n\nconst props = withDefaults(\n defineProps<GrCommandPaletteProps>(),\n {\n items: undefined,\n recentIds: undefined,\n placeholder: undefined,\n // Дефолт `size` живёт в резолвере ниже, а не здесь: Vue подставил бы его\n // до того, как компонент заглянет в `GrConfigProvider`.\n size: undefined,\n hotkey: 'mod+k',\n hotkeyId: undefined,\n filterable: true,\n filter: undefined,\n loading: false,\n closeOnSelect: true,\n maxHeight: 360,\n virtual: false,\n showHotkeyHint: true,\n emptyText: undefined,\n ariaLabel: undefined,\n },\n)\n\nconst emit = defineEmits<GrCommandPaletteEmits>()\n\nconst { t } = useGranularityTranslations()\n\nconst resolvedPlaceholder = computed(() => props.placeholder ?? t('gr.commandPalette.placeholder', 'Type a command or search…'))\nconst resolvedEmptyText = computed(() => props.emptyText ?? t('gr.commandPalette.empty', 'Nothing found'))\nconst resolvedAriaLabel = computed(() => props.ariaLabel ?? t('gr.commandPalette.label', 'Command palette'))\nconst loadingText = computed(() => t('gr.commandPalette.loading', 'Loading…'))\nconst recentTitle = computed(() => t('gr.commandPalette.recent', 'Recent'))\n\nconst query = ref('')\nconst inputEl = ref<HTMLInputElement | null>(null)\nconst listboxId = useId()\n\nconst itemsResolved = computed<GrCommandItem[]>(() => props.items ?? [])\n\nconst filteredItems = computed<GrCommandItem[]>(() =>\n props.filterable\n ? filterCommandItems(itemsResolved.value, query.value, props.filter ?? matchCommandItem)\n : itemsResolved.value,\n)\n\nconst groups = computed(() => {\n const grouped = groupCommandItems(filteredItems.value)\n\n // С непустым запросом секции «недавние» нет: там правит релевантность, а не\n // история — иначе первая же буква уводила бы взгляд не туда.\n if (query.value.trim())\n return grouped\n\n return withRecentCommands(grouped, filteredItems.value, props.recentIds ?? [], recentTitle.value)\n})\n\n/**\n * Порядок обхода стрелками совпадает с порядком на экране: «недавние» стоят\n * первыми, значит и первая стрелка ведёт туда же.\n */\nconst orderedItems = computed(() => groups.value.flatMap(group => group.items))\n\n/** Плоский список того, что реально выбирается — по нему ходят стрелки. */\nconst navigableItems = computed(() => orderedItems.value.filter(item => !item.disabled))\n\nfunction itemDomId(id: string): string {\n return `${listboxId}-item-${id}`\n}\n\n/**\n * Виртуализация списка.\n *\n * Набор — плоский поток строк экрана: заголовок группы занимает такую же\n * строку, как команда, поэтому входит в него наравне. Вложенную структуру\n * рендер пересобирает уже из окна.\n */\n\n/** Оценки высоты строк. Команда крупнее заголовка; дальше уточняются замером. */\nconst ITEM_SIZE_ESTIMATE = 44\nconst GROUP_LABEL_SIZE_ESTIMATE = 28\n\ntype PaletteRow\n = | { kind: 'label', groupIndex: number }\n | { kind: 'item', groupIndex: number, item: GrCommandItem, posInSet: number, setSize: number }\n\nconst listEl = ref<HTMLElement | null>(null)\n\nconst paletteRows = computed<PaletteRow[]>(() => {\n const rows: PaletteRow[] = []\n\n groups.value.forEach((group, groupIndex) => {\n if (group.name)\n rows.push({ kind: 'label', groupIndex })\n\n group.items.forEach((item, index) => {\n rows.push({\n kind: 'item',\n groupIndex,\n item,\n // Набор — группа, а не весь список: по ARIA позиция отсчитывается от неё.\n posInSet: index + 1,\n setSize: group.items.length,\n })\n })\n })\n\n return rows\n})\n\nconst virtualizer = useVirtualList({\n container: listEl,\n count: () => (props.virtual ? paletteRows.value.length : 0),\n // Запрос пересобирает набор строк — замеры прошлого набора невалидны.\n source: () => paletteRows.value,\n itemSize: index => (paletteRows.value[index]?.kind === 'label' ? GROUP_LABEL_SIZE_ESTIMATE : ITEM_SIZE_ESTIMATE),\n // Список закрытой палитры не смонтирован вовсе: `clientHeight` взять неоткуда.\n // `maxHeight` можно перебить `--gr-command-list-max-height` — тогда точная\n // высота приедет с первым замером, а это останется оценкой первого рендера.\n viewportSize: () => props.maxHeight,\n})\n\n/**\n * Группы к отрисовке. При виртуализации пересобираются из среза `paletteRows`:\n * группа, начатая выше окна, всё равно открывается — иначе её команды остались\n * бы прямыми потомками listbox'а, что роль запрещает.\n */\ntype RenderedGroup = {\n key: string\n groupIndex: number\n name: string | undefined\n labelVisible: boolean\n /** Позиция строки заголовка в `paletteRows` — по ней его замеряет виртуализатор. */\n labelRowIndex?: number\n items: { item: GrCommandItem, rowIndex: number, posInSet: number, setSize: number }[]\n}\n\nconst renderedGroups = computed<RenderedGroup[]>(() => {\n const rows = paletteRows.value\n\n const from = props.virtual ? virtualizer.range.value.start : 0\n const to = props.virtual ? Math.min(rows.length, virtualizer.range.value.end) : rows.length\n\n const result: RenderedGroup[] = []\n let current: RenderedGroup | undefined\n\n for (let rowIndex = from; rowIndex < to; rowIndex++) {\n const row = rows[rowIndex]!\n const group = groups.value[row.groupIndex]\n\n if (!current || current.groupIndex !== row.groupIndex) {\n current = {\n key: group?.name ?? `__ungrouped-${row.groupIndex}`,\n groupIndex: row.groupIndex,\n name: group?.name,\n labelVisible: false,\n items: [],\n }\n result.push(current)\n }\n\n if (row.kind === 'label') {\n current.labelVisible = true\n current.labelRowIndex = rowIndex\n continue\n }\n\n current.items.push({ item: row.item, rowIndex, posInSet: row.posInSet, setSize: row.setSize })\n }\n\n return result\n})\n\n/** ARIA набора: объявляем только при виртуализации — иначе набор виден по DOM. */\nfunction itemSetProps(entry: { posInSet: number, setSize: number }): Record<string, number> | undefined {\n if (!props.virtual)\n return undefined\n return { 'aria-setsize': entry.setSize, 'aria-posinset': entry.posInSet }\n}\n\n/** Сегменты подсветки: совпавшее с запросом рисуется `<mark>`. */\nfunction matchSegments(text: string): ReturnType<typeof splitCommandMatch> {\n return splitCommandMatch(text, props.filterable ? query.value : '')\n}\n\nasync function scrollActiveIntoView(item: GrCommandItem): Promise<void> {\n // Вне окна активной команды в DOM нет: `getElementById` вернул бы `null`,\n // прокрутка не случилась бы, а `aria-activedescendant` указал бы в пустоту.\n if (props.virtual) {\n const rowIndex = paletteRows.value.findIndex(row => row.kind === 'item' && row.item.id === item.id)\n if (rowIndex >= 0)\n virtualizer.scrollToIndex(rowIndex)\n }\n\n await nextTick()\n document.getElementById(itemDomId(item.id))?.scrollIntoView?.({ block: 'nearest' })\n}\n\nconst {\n activeItem,\n activeDescendantId,\n setActive,\n reset: resetActive,\n handleNavigationKeys,\n} = useComboboxNavigation<GrCommandItem>({\n items: () => navigableItems.value,\n open: () => props.modelValue,\n idOf: item => itemDomId(item.id),\n scrollTo: item => scrollActiveIntoView(item),\n})\n\n// Палитра всегда стартует с первой команды — и при монтировании открытой тоже.\nresetActive(0)\n\nfunction isActive(item: GrCommandItem): boolean {\n return activeItem.value?.id === item.id\n}\n\n// Активной становится первая команда, когда список изменился **по содержимому**.\n// Следить за идентичностью массива нельзя: родитель, отдающий `:items` инлайн-\n// выражением, пересоздаёт его на каждый посторонний ререндер — и выбранная\n// стрелками команда прыгала бы в начало.\n// Разделитель — пробел, а не запятая: `id` вправе её содержать, и «a,b» + «c»\n// дало бы тот же ключ, что «a» + «b,c».\nwatch(\n () => orderedItems.value.map(item => item.id).join(' '),\n () => resetActive(0),\n)\n\n// `id` — ключ рендера и цель `aria-activedescendant`: дубли дают одинаковые\n// DOM-id, и фокус уезжает не на ту команду.\nwatch(\n itemsResolved,\n (items) => {\n if (!__GR_DEV__)\n return\n const duplicates = findDuplicateCommandIds(items)\n if (!duplicates.length)\n return\n\n console.warn(\n `[GrCommandPalette] повторяющиеся id команд: ${duplicates.join(', ')}. `\n + 'Из-за одинаковых DOM-id `aria-activedescendant` укажет не на ту команду.',\n )\n },\n { immediate: true },\n)\n\nfunction open(): void {\n emit('update:modelValue', true)\n}\n\nfunction close(): void {\n emit('update:modelValue', false)\n}\n\nfunction toggle(): void {\n emit('update:modelValue', !props.modelValue)\n}\n\nfunction selectItem(item: GrCommandItem): void {\n if (item.disabled)\n return\n emit('select', item)\n if (props.closeOnSelect)\n close()\n}\n\nfunction onItemHover(item: GrCommandItem): void {\n const index = navigableItems.value.indexOf(item)\n if (index >= 0)\n setActive(index)\n}\n\nfunction onInput(event: Event): void {\n query.value = (event.target as HTMLInputElement).value\n emit('search', query.value.trim())\n}\n\nfunction onKeydown(event: KeyboardEvent): void {\n // Клавиша во время IME-композиции принадлежит композиции: Enter коммитит её,\n // стрелки ходят по кандидатам.\n if (isComposingEvent(event))\n return\n\n if (handleNavigationKeys(event))\n return\n\n switch (event.key) {\n case 'Enter':\n if (!activeItem.value)\n break\n event.preventDefault()\n selectItem(activeItem.value)\n break\n }\n}\n\n// ————— Открытие: сброс запроса и выбора.\nwatch(\n () => props.modelValue,\n (open) => {\n if (!open)\n return\n\n query.value = ''\n resetActive(0)\n },\n)\n\n// Фокус в поле — отдельным наблюдателем, и по появлению самого поля: содержимое\n// панели рождается вместе с ней, и по одному лишь пропу фокусировать нечего.\n// Ловушка фокуса `GrModal` этот выбор не перебивает — фокус, уже стоящий внутри\n// слоя, она считает осознанным.\nwatch(\n [() => props.modelValue, inputEl],\n ([open]) => {\n if (open)\n inputEl.value?.focus()\n },\n { flush: 'post' },\n)\n\n// ————— Глобальное сочетание открытия.\n\nconst registry = useHotkeys()\n\n/** Реестр сильнее пропа: два источника сочетания молча спорить не должны. */\nconst hotkeyValue = computed(() => (props.hotkeyId !== undefined\n ? registry.keysOf(props.hotkeyId)\n : props.hotkey))\n\n/**\n * Шаги открытия. Аккорд — один шаг, `'g p'` — два: палитра берёт тот же разбор,\n * что и директива, поэтому цепочка открывает её так же, как и любое другое место.\n */\nconst hotkeySteps = computed(() => (hotkeyValue.value ? parseHotkeySequence(hotkeyValue.value) : []))\n\nconst parsedHotkey = computed(() => hotkeySteps.value[0] ?? null)\n\nconst sequence = createHotkeySequenceTracker()\n\n// Платформа определяется только после монтирования: на сервере `navigator` нет,\n// и первый рендер обязан совпасть с серверным. Иначе сервер отдаёт `Ctrl`,\n// клиент на macOS рисует `⌘`, и гидрация расходится по тексту подсказки.\nconst isApple = ref(false)\n\nconst hotkeyHint = computed(() =>\n props.showHotkeyHint && parsedHotkey.value ? formatCommandHotkey(parsedHotkey.value, isApple.value) : [],\n)\n\nfunction onWindowKeydown(event: KeyboardEvent): void {\n const steps = hotkeySteps.value\n if (steps.length === 0)\n return\n\n // Клавиша во время IME-композиции принадлежит композиции, а не сочетанию.\n if (isComposingEvent(event))\n return\n\n sequence.push(event, Date.now())\n\n if (!sequence.matches(steps, isApple.value))\n return\n\n // Сложившаяся цепочка снимается с буфера: иначе следующее нажатие достроило\n // бы её заново и переключило палитру второй раз.\n sequence.reset()\n\n event.preventDefault()\n toggle()\n}\n\nonMounted(() => {\n if (typeof window === 'undefined')\n return\n isApple.value = isAppleDevice()\n window.addEventListener('keydown', onWindowKeydown)\n})\n\nonBeforeUnmount(() => {\n if (typeof window !== 'undefined')\n window.removeEventListener('keydown', onWindowKeydown)\n})\n\n// Эффективный размер: локальный проп → `GrConfigProvider` → дефолт компонента.\nconst resolvedSize = useGrComponentProp('GrCommandPalette', 'size', () => props.size, 'lg')\n\nconst modalSize = computed(() => commandPaletteModalSizeBySize[resolvedSize.value])\nconst listStyle = computed(() => ({ maxHeight: `var(--gr-command-list-max-height, ${props.maxHeight}px)` }))\n\nconst listStyleWithSpacers = computed(() => {\n const base = listStyle.value\n if (!props.virtual)\n return base\n\n return {\n ...base,\n ...virtualizer.spacerStyle.value,\n }\n})\n\ndefineExpose({ open, close, toggle })\n\ndefineSlots<{\n /** Строка списка вместо стандартной. */\n item?: (props: { item: GrCommandItem, active: boolean }) => any\n /** Пустое состояние: получает запрос, чтобы предложить действие по нему. */\n empty?: (props: { query: string }) => any\n /** Подвал палитры: подсказки по клавишам, счётчик. */\n footer?: () => any\n}>()\n</script>\n\n<template>\n <GrModal\n :model-value=\"modelValue\"\n :size=\"modalSize\"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n >\n <div data-gr-command-palette :aria-label=\"resolvedAriaLabel\">\n <div data-gr-command-palette-search :class=\"commandSearchRowClass\">\n <IconSearch class=\"block h-4 w-4 shrink-0 text-[var(--gr-muted-fg)]\" aria-hidden=\"true\" />\n\n <input\n ref=\"inputEl\"\n data-gr-command-palette-input\n data-testid=\"gr-command-palette-input\"\n type=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-autocomplete=\"list\"\n aria-expanded=\"true\"\n :aria-label=\"resolvedAriaLabel\"\n :aria-controls=\"listboxId\"\n :aria-activedescendant=\"activeDescendantId\"\n :value=\"query\"\n :placeholder=\"resolvedPlaceholder\"\n :class=\"commandSearchInputClass\"\n @input=\"onInput\"\n @keydown=\"onKeydown\"\n >\n\n <span v-if=\"loading\" class=\"shrink-0 text-[var(--gr-muted-fg)]\" aria-hidden=\"true\">\n <IconLoaderCircle class=\"block h-4 w-4 animate-spin\" />\n </span>\n <span v-else-if=\"hotkeyHint.length\" class=\"shrink-0\" aria-hidden=\"true\">\n <GrKbd :keys=\"hotkeyHint\" size=\"sm\" />\n </span>\n </div>\n\n <div\n :id=\"listboxId\"\n ref=\"listEl\"\n data-gr-command-palette-list\n data-testid=\"gr-command-palette-list\"\n :data-gr-virtual=\"virtual ? '' : undefined\"\n class=\"overflow-y-auto p-2\"\n :style=\"listStyleWithSpacers\"\n role=\"listbox\"\n :aria-label=\"resolvedAriaLabel\"\n >\n <!-- Прямыми потомками listbox могут быть только `role=\"group\"`: заголовок\n группы лежит внутри неё и объявлен презентационным (имя группе он\n даёт через `aria-labelledby`), иначе ломается `aria-required-children`.\n\n При виртуализации окно может начаться ниже заголовка — тогда его в\n DOM нет, и имя группы идёт напрямую в `aria-label`. -->\n <div\n v-for=\"group in renderedGroups\"\n :key=\"group.key\"\n role=\"group\"\n :aria-labelledby=\"group.name && group.labelVisible ? `${listboxId}-group-${group.groupIndex}` : undefined\"\n :aria-label=\"group.name && !group.labelVisible ? group.name : undefined\"\n >\n <div\n v-if=\"group.name && group.labelVisible\"\n :id=\"`${listboxId}-group-${group.groupIndex}`\"\n :ref=\"(el) => virtual && group.labelRowIndex !== undefined && virtualizer.measure(group.labelRowIndex, el as Element | null)\"\n data-gr-command-palette-group\n role=\"presentation\"\n :class=\"commandGroupLabelClass\"\n >\n {{ group.name }}\n </div>\n\n <div>\n <div\n v-for=\"entry in group.items\"\n :id=\"itemDomId(entry.item.id)\"\n :key=\"entry.item.id\"\n :ref=\"(el) => virtual && virtualizer.measure(entry.rowIndex, el as Element | null)\"\n data-gr-command-palette-item\n :data-testid=\"`gr-command-palette-item-${entry.item.id}`\"\n role=\"option\"\n v-bind=\"itemSetProps(entry)\"\n :aria-selected=\"isActive(entry.item) ? 'true' : 'false'\"\n :aria-disabled=\"entry.item.disabled ? 'true' : undefined\"\n :class=\"commandItemClass({ active: isActive(entry.item), disabled: Boolean(entry.item.disabled) })\"\n @click=\"selectItem(entry.item)\"\n @mousemove=\"onItemHover(entry.item)\"\n >\n <slot name=\"item\" :item=\"entry.item\" :active=\"isActive(entry.item)\">\n <component\n :is=\"iconTag(entry.item.icon)\"\n v-if=\"entry.item.icon\"\n class=\"block h-4 w-4 shrink-0\"\n :class=\"[iconClass(entry.item.icon), commandItemMutedClass(Boolean(entry.item.disabled))]\"\n aria-hidden=\"true\"\n />\n <span class=\"min-w-0 flex-1\">\n <span class=\"block truncate\">\n <template v-for=\"(segment, index) in matchSegments(entry.item.label)\" :key=\"index\">\n <mark v-if=\"segment.match\" :class=\"commandMatchClass\">{{ segment.text }}</mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </span>\n <span\n v-if=\"entry.item.description\"\n :class=\"[commandItemDescriptionClass, commandItemMutedClass(Boolean(entry.item.disabled))]\"\n >\n <template v-for=\"(segment, index) in matchSegments(entry.item.description)\" :key=\"index\">\n <mark v-if=\"segment.match\" :class=\"commandMatchClass\">{{ segment.text }}</mark>\n <template v-else>{{ segment.text }}</template>\n </template>\n </span>\n </span>\n <span v-if=\"entry.item.shortcut?.length\" class=\"shrink-0\">\n <GrKbd :keys=\"entry.item.shortcut\" size=\"sm\" />\n </span>\n </slot>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Состояния объявляются живым регионом: `aria-label` на generic-элементе\n большинство AT игнорируют, и загрузка осталась бы неозвученной. Регион\n один на оба состояния и лежит вне listbox — внутри он стал бы его\n недопустимым потомком. -->\n <div\n v-if=\"loading || !filteredItems.length\"\n data-gr-command-palette-empty\n data-testid=\"gr-command-palette-empty\"\n role=\"status\"\n aria-live=\"polite\"\n :class=\"commandEmptyClass\"\n >\n <template v-if=\"loading\">\n {{ loadingText }}\n </template>\n <slot v-else name=\"empty\" :query=\"query\">\n {{ resolvedEmptyText }}\n </slot>\n </div>\n\n <div v-if=\"$slots.footer\" data-gr-command-palette-footer :class=\"commandFooterClass\">\n <slot name=\"footer\" />\n </div>\n </div>\n </GrModal>\n</template>\n\n<style scoped>\n/*\n * Распорки виртуального списка.\n *\n * Не `padding` контейнера: `max-height` меряет ту же коробку. Не обёртка внутри\n * listbox'а: прямыми потомками роли обязаны быть только группы. Не отступы\n * крайних строк: при прыжке прокрутки строки заменяются целиком, и распорка\n * исчезла бы вместе с ними.\n *\n * `display: block` обязателен: список палитры — блочный поток, а псевдоэлемент\n * по умолчанию строчный, и строчная коробка игнорирует `height` — распорка\n * молча не создалась бы вовсе.\n */\n[data-gr-virtual]::before,\n[data-gr-virtual]::after {\n content: '';\n display: block;\n flex: none;\n}\n\n[data-gr-virtual]::before {\n height: var(--gr-virtual-before, 0px);\n}\n\n[data-gr-virtual]::after {\n height: var(--gr-virtual-after, 0px);\n}\n</style>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { t as GrCommandPalette_default } from "./chunks/GrCommandPalette-BJHmkDQv.js";
1
+ import { t as GrCommandPalette_default } from "./chunks/GrCommandPalette-CAHgj0Aa.js";
2
2
  import { n as grCommandPaletteSafelist, t as grCommandPaletteConfig } from "../../chunks/config-D0NzGYaE.js";
3
3
  export { GrCommandPalette_default as GrCommandPalette, GrCommandPalette_default as default, grCommandPaletteConfig, grCommandPaletteSafelist };
@@ -1 +1 @@
1
- [data-gr-virtual][data-v-041dfab7]:before,[data-gr-virtual][data-v-041dfab7]:after{content:"";flex:none;display:block}[data-gr-virtual][data-v-041dfab7]:before{height:var(--gr-virtual-before,0px)}[data-gr-virtual][data-v-041dfab7]:after{height:var(--gr-virtual-after,0px)}
1
+ [data-gr-virtual][data-v-eb4919ed]:before,[data-gr-virtual][data-v-eb4919ed]:after{content:"";flex:none;display:block}[data-gr-virtual][data-v-eb4919ed]:before{height:var(--gr-virtual-before,0px)}[data-gr-virtual][data-v-eb4919ed]:after{height:var(--gr-virtual-after,0px)}
@@ -1,7 +1,7 @@
1
1
  import { i as useGrComponentProp } from "../../../chunks/context-CPMRfwVr.js";
2
2
  import { n as useGranularityTranslations } from "../../../chunks/granularityI18n-BC5zsj_d.js";
3
3
  import { t as GrButton_default } from "../../GrButton/chunks/GrButton-CS4TqMtG.js";
4
- import { t as GrDialog_default } from "../../GrDialog/chunks/GrDialog-DDz_OEhk.js";
4
+ import { t as GrDialog_default } from "../../GrDialog/chunks/GrDialog-C9Zu72jB.js";
5
5
  import { t as GrResponseErrorBanner_default } from "../../GrResponseErrorBanner/chunks/GrResponseErrorBanner-Bdd5c07x.js";
6
6
  import { computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, openBlock, ref, renderSlot, toDisplayString, unref, watch, withCtx } from "vue";
7
7
  //#region src/components/GrConfirmDialog/GrConfirmDialog.vue?vue&type=script&setup=true&lang.ts