@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
@@ -11,8 +11,8 @@ import { t as _plugin_vue_export_helper_default } from "../../../chunks/_plugin-
11
11
  import { t as GrButton_default } from "../../GrButton/chunks/GrButton-CS4TqMtG.js";
12
12
  import { useDragGesture } from "../../../composables/useDragGesture.js";
13
13
  import { useToast } from "../../../composables/useToast.js";
14
- import { a as SWIPE_THRESHOLD_RATIO, i as SWIPE_DIRECTION, o as swipeOpacity, r as PLACEMENT_CLASS } from "../../../chunks/config-B5SBUa6u.js";
15
- import { Fragment, Teleport, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeStyle, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useSlots, watchEffect, withCtx, withDirectives } from "vue";
14
+ import { a as SWIPE_THRESHOLD_RATIO, c as swipeOpacity, i as SWIPE_DIRECTION, o as collapsedTransform, r as PLACEMENT_CLASS, s as stackDepth } from "../../../chunks/config-B7qZqiUB.js";
15
+ import { Fragment, Teleport, TransitionGroup, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onUpdated, openBlock, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, unref, useSlots, watchEffect, withCtx, withDirectives } from "vue";
16
16
  import '../styles.css';//#region src/components/GrToaster/GrToaster.vue?vue&type=script&setup=true&lang.ts
17
17
  var _hoisted_1 = ["aria-label"];
18
18
  var _hoisted_2 = [
@@ -21,14 +21,13 @@ var _hoisted_2 = [
21
21
  "role",
22
22
  "onKeydown"
23
23
  ];
24
- var _hoisted_3 = { class: "flex items-start gap-3" };
25
- var _hoisted_4 = { class: "min-w-0 flex-1" };
26
- var _hoisted_5 = { class: "text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] font-700" };
27
- var _hoisted_6 = {
24
+ var _hoisted_3 = { class: "min-w-0 flex-1" };
25
+ var _hoisted_4 = { class: "text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] font-700" };
26
+ var _hoisted_5 = {
28
27
  key: 0,
29
28
  class: "mt-0.5 text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] text-[var(--gr-muted-fg)]"
30
29
  };
31
- var _hoisted_7 = {
30
+ var _hoisted_6 = {
32
31
  key: 1,
33
32
  class: "mt-2 flex flex-wrap gap-2"
34
33
  };
@@ -49,6 +48,10 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
49
48
  swipeDismiss: {
50
49
  type: Boolean,
51
50
  default: true
51
+ },
52
+ collapse: {
53
+ type: [Number, Boolean],
54
+ default: 3
52
55
  }
53
56
  },
54
57
  setup(__props, { expose: __expose }) {
@@ -144,6 +147,79 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
144
147
  const hovered = ref(false);
145
148
  const focusWithin = ref(false);
146
149
  const containerEl = ref(null);
150
+ /**
151
+ * Развёрнуто — по тем же двум флагам, что держат `paused`: рука на стеке или
152
+ * фокус внутри. Отдельного сигнала не заводим — читать стопку и не остановить
153
+ * при этом таймеры было бы ловушкой.
154
+ */
155
+ const expanded = computed(() => hovered.value || focusWithin.value);
156
+ const stacked = computed(() => props.collapse !== false && visibleToasts.value.length > Math.max(1, props.collapse));
157
+ const collapsed = computed(() => stacked.value && !expanded.value);
158
+ /**
159
+ * Высоты тостов: они разные (заголовок, заголовок с текстом, плюс кнопки), а
160
+ * развёрнутая раскладка складывает их накопительно.
161
+ *
162
+ * `offsetHeight`, а не `getBoundingClientRect().height`: свёрнутая карточка
163
+ * уменьшена `scale()`, и рект вернул бы её экранный размер — стопка мерила бы
164
+ * саму себя и с каждым замером сжималась.
165
+ */
166
+ const toastHeights = ref({});
167
+ let heightObserver = null;
168
+ function measureToasts() {
169
+ const root = containerEl.value;
170
+ if (!root) return;
171
+ const next = {};
172
+ for (const node of root.querySelectorAll("[data-gr-toast]")) {
173
+ const id = node.dataset.toastId;
174
+ if (id && node.offsetHeight > 0) next[id] = node.offsetHeight;
175
+ heightObserver?.observe(node);
176
+ }
177
+ toastHeights.value = next;
178
+ }
179
+ onMounted(() => {
180
+ if (typeof ResizeObserver !== "undefined") heightObserver = new ResizeObserver(() => measureToasts());
181
+ measureToasts();
182
+ });
183
+ onUpdated(measureToasts);
184
+ onBeforeUnmount(() => {
185
+ heightObserver?.disconnect();
186
+ heightObserver = null;
187
+ });
188
+ /** Все ли видимые тосты измерены. Пока нет — раскладка остаётся потоком. */
189
+ const measured = computed(() => visibleToasts.value.every((toast) => toastHeights.value[toast.id] > 0));
190
+ /** Абсолютная раскладка включается только когда есть чем считать смещения. */
191
+ const positioned = computed(() => stacked.value && measured.value);
192
+ function expandedOffset(index) {
193
+ let offset = 0;
194
+ for (let i = 0; i < index; i++) offset += (toastHeights.value[visibleToasts.value[i].id] ?? 0) + 12;
195
+ return offset;
196
+ }
197
+ function depthOf(index) {
198
+ return stackDepth(index, visibleToasts.value.length, props.placement);
199
+ }
200
+ /** Высота передней карточки — по ней живёт вся свёрнутая стопка. */
201
+ const frontHeight = computed(() => {
202
+ const heights = visibleToasts.value.map((toast) => toastHeights.value[toast.id] ?? 0);
203
+ return props.placement.startsWith("top") ? heights[0] : heights[heights.length - 1];
204
+ });
205
+ const stackHeight = computed(() => {
206
+ if (!positioned.value) return void 0;
207
+ if (collapsed.value) return `${frontHeight.value}px`;
208
+ const heights = visibleToasts.value.map((toast) => toastHeights.value[toast.id] ?? 0);
209
+ return `${heights.reduce((sum, h) => sum + h, 0) + 12 * (heights.length - 1)}px`;
210
+ });
211
+ /** Карточка лежит за передней: в свёрнутой стопке от неё виден только край. */
212
+ function isBehind(index) {
213
+ return collapsed.value && positioned.value && depthOf(index) > 0;
214
+ }
215
+ /**
216
+ * Содержимое карточек за передней гасится: из-под неё видно 12 пикселей, и в
217
+ * эту полоску попадали обрывок строки и хвост полосы прогресса. Колода должна
218
+ * читаться краями карточек, а не мусором в щели.
219
+ */
220
+ function toastContentStyle(index) {
221
+ return isBehind(index) ? { opacity: "0" } : void 0;
222
+ }
147
223
  const swipingId = ref(null);
148
224
  const swipeOffset = ref(0);
149
225
  let swipeStartX = 0;
@@ -212,13 +288,31 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
212
288
  },
213
289
  onCancel: resetSwipe
214
290
  });
215
- function swipeStyle(toast) {
216
- if (swipingId.value !== toast.id) return void 0;
217
- return {
218
- transform: `translateX(${swipeOffset.value}px)`,
219
- opacity: String(swipeOpacity(swipeOffset.value, swipeThreshold)),
220
- ...swipeReleased.value ? {} : { transition: "none" }
221
- };
291
+ /**
292
+ * Стиль тоста: смахивание и стопка пишут в один `transform`. Двух инлайновых
293
+ * трансформов не бывает — второй затирает первый, и жест отменял бы раскладку.
294
+ */
295
+ function toastStyle(toast, index) {
296
+ const style = {};
297
+ const transforms = [];
298
+ if (swipingId.value === toast.id) {
299
+ transforms.push(`translateX(${swipeOffset.value}px)`);
300
+ style.opacity = String(swipeOpacity(swipeOffset.value, swipeThreshold));
301
+ if (!swipeReleased.value) style.transition = "none";
302
+ }
303
+ if (positioned.value) {
304
+ const depth = depthOf(index);
305
+ transforms.push(collapsed.value ? collapsedTransform(depth, props.placement) : `translateY(${expandedOffset(index)}px)`);
306
+ style.zIndex = String(visibleToasts.value.length - depth);
307
+ style.transformOrigin = props.placement.startsWith("top") ? "top center" : "bottom center";
308
+ if (collapsed.value && depth > 0 && frontHeight.value > 0) style.height = `${frontHeight.value}px`;
309
+ if (collapsed.value && depth > 2) {
310
+ style.opacity = "0";
311
+ style.pointerEvents = "none";
312
+ }
313
+ }
314
+ if (transforms.length > 0) style.transform = transforms.join(" ");
315
+ return Object.keys(style).length > 0 ? style : void 0;
222
316
  }
223
317
  /**
224
318
  * Клавиатурный эквивалент смахивания. `Escape` намеренно не берём: тостер не
@@ -240,6 +334,30 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
240
334
  return TONE_META[tone] ?? TONE_META.info;
241
335
  }
242
336
  const containerClass = computed(() => PLACEMENT_CLASS[props.placement]);
337
+ const listClass = computed(() => positioned.value ? "relative transition-[height] duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]" : "grid gap-3");
338
+ const listStyle = computed(() => stackHeight.value ? { height: stackHeight.value } : void 0);
339
+ /**
340
+ * В стопке карточка вынута из потока, а её место задаёт трансформ — он и
341
+ * обязан ехать плавно. В обычной колонке переход не нужен: там позицию держит
342
+ * сама раскладка, а сдвиги отрабатывает `move-class` группы.
343
+ */
344
+ const toastLayoutClass = computed(() => positioned.value ? "absolute inset-x-0 top-0 transition-[transform,opacity] duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]" : "relative");
345
+ /**
346
+ * В стопке перемещение группы выключается. `TransitionGroup` двигает детей
347
+ * приёмом FLIP: сам пишет в инлайновый `transform` и по концу перехода
348
+ * **очищает** его — то есть стирает раскладку стопки. Класс без перехода
349
+ * трансформа отключает проверку `hasCSSTransform`, и до записи дело не доходит.
350
+ */
351
+ const moveClass = computed(() => positioned.value ? "transition-none" : "transition-transform duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]");
352
+ /**
353
+ * В стопке появление и уход красятся только прозрачностью: `translate-y-*` из
354
+ * классов группы спорил бы с инлайновым трансформом раскладки, а инлайновый
355
+ * сильнее — сдвиг всё равно не сыграл бы.
356
+ */
357
+ const enterFromClass = computed(() => positioned.value ? "opacity-0" : "opacity-0 translate-y-2");
358
+ const enterToClass = computed(() => positioned.value ? "opacity-100" : "opacity-100 translate-y-0");
359
+ const leaveFromClass = computed(() => positioned.value ? "opacity-100" : "opacity-100 translate-y-0");
360
+ const leaveToClass = computed(() => positioned.value ? "opacity-0" : "opacity-0 translate-y-2");
243
361
  const containerStyle = computed(() => {
244
362
  if (props.width === void 0) return void 0;
245
363
  return { "--gr-toaster-width": typeof props.width === "number" ? `${props.width}px` : props.width };
@@ -286,16 +404,17 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
286
404
  onFocusout: _cache[4] || (_cache[4] = ($event) => focusWithin.value = false)
287
405
  }), [createVNode(TransitionGroup, {
288
406
  tag: "div",
289
- class: "grid gap-3",
407
+ class: normalizeClass(listClass.value),
408
+ style: normalizeStyle(listStyle.value),
290
409
  "enter-active-class": "transition duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]",
291
- "enter-from-class": "opacity-0 translate-y-2",
292
- "enter-to-class": "opacity-100 translate-y-0",
410
+ "enter-from-class": enterFromClass.value,
411
+ "enter-to-class": enterToClass.value,
293
412
  "leave-active-class": "transition duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)] absolute",
294
- "leave-from-class": "opacity-100 translate-y-0",
295
- "leave-to-class": "opacity-0 translate-y-2",
296
- "move-class": "transition-transform duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]"
413
+ "leave-from-class": leaveFromClass.value,
414
+ "leave-to-class": leaveToClass.value,
415
+ "move-class": moveClass.value
297
416
  }, {
298
- default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(visibleToasts.value, (toast) => {
417
+ default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(visibleToasts.value, (toast, index) => {
299
418
  return openBlock(), createElementBlock("div", {
300
419
  key: toast.id,
301
420
  "data-gr-toast": "",
@@ -304,11 +423,14 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
304
423
  role: metaFor(toast.tone).role,
305
424
  "aria-atomic": "true",
306
425
  tabindex: "-1",
307
- class: normalizeClass(["relative overflow-hidden rounded-[var(--gr-radius-lg)] border border-[var(--gr-brd)] bg-[var(--gr-card)] px-4 py-3 shadow-[var(--gr-shadow-2)] focus-visible:outline-none focus-visible:shadow-[var(--gr-shadow-2),0_0_0_2px_var(--gr-ring)]", __props.swipeDismiss ? "[touch-action:pan-y]" : ""]),
308
- style: normalizeStyle(swipeStyle(toast)),
426
+ class: normalizeClass(["overflow-hidden rounded-[var(--gr-radius-lg)] border border-[var(--gr-brd)] bg-[var(--gr-card)] px-4 py-3 shadow-[var(--gr-shadow-2)] focus-visible:outline-none focus-visible:shadow-[var(--gr-shadow-2),0_0_0_2px_var(--gr-ring)]", [__props.swipeDismiss ? "[touch-action:pan-y]" : "", toastLayoutClass.value]]),
427
+ style: normalizeStyle(toastStyle(toast, index)),
309
428
  onPointerdown: _cache[0] || (_cache[0] = (...args) => unref(swipe).start && unref(swipe).start(...args)),
310
429
  onKeydown: ($event) => onToastKeydown($event, toast)
311
- }, [createElementVNode("div", _hoisted_3, [
430
+ }, [createElementVNode("div", {
431
+ class: "flex items-start gap-3 transition-opacity duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]",
432
+ style: normalizeStyle(toastContentStyle(index))
433
+ }, [
312
434
  createVNode(unref(GrIcon_default), {
313
435
  size: "md",
314
436
  class: "mt-0.5",
@@ -317,10 +439,10 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
317
439
  default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(metaFor(toast.tone).icon)))]),
318
440
  _: 2
319
441
  }, 1032, ["style"]),
320
- createElementVNode("div", _hoisted_4, [
321
- createElementVNode("div", _hoisted_5, toDisplayString(toast.title), 1),
322
- toast.message ? (openBlock(), createElementBlock("div", _hoisted_6, toDisplayString(toast.message), 1)) : createCommentVNode("", true),
323
- hasActions(toast) ? (openBlock(), createElementBlock("div", _hoisted_7, [renderSlot(_ctx.$slots, "actions", {
442
+ createElementVNode("div", _hoisted_3, [
443
+ createElementVNode("div", _hoisted_4, toDisplayString(toast.title), 1),
444
+ toast.message ? (openBlock(), createElementBlock("div", _hoisted_5, toDisplayString(toast.message), 1)) : createCommentVNode("", true),
445
+ hasActions(toast) ? (openBlock(), createElementBlock("div", _hoisted_6, [renderSlot(_ctx.$slots, "actions", {
324
446
  toast,
325
447
  dismiss: () => unref(dismiss)(toast.id)
326
448
  }, () => [(openBlock(true), createElementBlock(Fragment, null, renderList(toastActions(toast), (action, index) => {
@@ -353,7 +475,7 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
353
475
  })]),
354
476
  _: 1
355
477
  }, 8, ["aria-label", "onClick"])
356
- ]), toast.timeoutMs > 0 ? (openBlock(), createElementBlock("div", {
478
+ ], 4), toast.timeoutMs > 0 ? (openBlock(), createElementBlock("div", {
357
479
  key: 0,
358
480
  "data-gr-toast-progress": "",
359
481
  "aria-hidden": "true",
@@ -361,14 +483,23 @@ var GrToaster_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PU
361
483
  style: normalizeStyle({
362
484
  backgroundColor: metaFor(toast.tone).color,
363
485
  animationDuration: `${toast.timeoutMs}ms`,
364
- animationPlayState: paused.value ? "paused" : "running"
486
+ animationPlayState: paused.value ? "paused" : "running",
487
+ ...toastContentStyle(index)
365
488
  })
366
489
  }, null, 4)) : createCommentVNode("", true)], 46, _hoisted_2);
367
490
  }), 128))]),
368
491
  _: 3
369
- })], 16, _hoisted_1)), [[unref(vHotkey), hotkeyBinding.value]])], 8, ["to", "disabled"]);
492
+ }, 8, [
493
+ "class",
494
+ "style",
495
+ "enter-from-class",
496
+ "enter-to-class",
497
+ "leave-from-class",
498
+ "leave-to-class",
499
+ "move-class"
500
+ ])], 16, _hoisted_1)), [[unref(vHotkey), hotkeyBinding.value]])], 8, ["to", "disabled"]);
370
501
  };
371
502
  }
372
- }), [["__scopeId", "data-v-a9c5da3d"]]);
503
+ }), [["__scopeId", "data-v-185f56c0"]]);
373
504
  //#endregion
374
505
  export { GrToaster_default as t };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GrToaster-OzT1VKcp.js","names":[],"sources":["../../../../src/components/GrToaster/GrToaster.vue","../../../../src/components/GrToaster/GrToaster.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * GrToaster — GR-примитив области уведомлений (toast).\n *\n * Модель состояния берётся из `useToast`, поэтому в приложении предполагается\n * **один активный `GrToaster`** на корень (или app-scoped через плагин).\n *\n * A11y:\n * - контейнер — `role=\"region\"` с `aria-label` (i18n-проп `regionLabel`);\n * - объявляет каждый тост сам собой: `role=\"status\"`, а критичные\n * (`warning`/`danger`) — ассертивный `role=\"alert\"`. Обёртки-live-region над\n * ними нет намеренно: вложение регионов с разной ассертивностью\n * спецификацией не определено, браузеры и SR расходятся вплоть до потери\n * объявления;\n * - стек достижим с клавиатуры по `focusHotkey` (по умолчанию `F6`) — тосты\n * телепортированы в конец `body`, и без хоткея кнопка «Отменить» лежала бы\n * за пределами разумного числа нажатий `Tab`.\n *\n * UX:\n * - `maxVisible` ограничивает стек; лишние ждут в очереди (их таймеры на паузе);\n * - автозакрытие **останавливается под курсором/фокусом** (WCAG 2.2.1) и\n * визуализируется прогресс-баром до закрытия;\n * - `placement` настраивает угол экрана; слой — `--gr-z-toast`.\n */\nimport { computed, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, useSlots, watchEffect } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\nimport type { Component } from 'vue'\n\nimport { useDragGesture } from '../../composables/useDragGesture'\nimport { useToast } from '../../composables/useToast'\nimport { vHotkey } from '../../directives'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type { GrToastTone, Toast, ToastAction } from '../../composables/useToast'\nimport GrButton from '../GrButton'\nimport GrIcon from '../GrIcon'\nimport {\n collapsedTransform,\n PLACEMENT_CLASS,\n STACK_GAP_PX,\n STACK_PEEK_DEPTH,\n stackDepth,\n SWIPE_DIRECTION,\n SWIPE_FLY_OUT_PX,\n SWIPE_RESISTANCE,\n SWIPE_THRESHOLD_MIN_PX,\n SWIPE_THRESHOLD_RATIO,\n swipeOpacity,\n type GrToasterPlacement,\n} from './grToasterStyles'\n\nimport IconCheck from '~icons/lucide/check-circle'\nimport IconWarning from '~icons/lucide/alert-triangle'\nimport IconError from '~icons/lucide/x-circle'\nimport IconInfo from '~icons/lucide/info'\nimport IconClose from '~icons/lucide/x'\n\nexport type { GrToasterPlacement }\n\ninterface ToneMeta {\n icon: Component\n color: string\n role: 'status' | 'alert'\n}\n\n// Единый маппинг по tone'у: иконка, цвет, a11y-роль. На уровне модуля —\n// чтобы не пересоздавать объект на каждый рендер.\nconst TONE_META: Record<GrToastTone, ToneMeta> = {\n primary: { icon: IconInfo, color: 'var(--gr-primary)', role: 'status' },\n neutral: { icon: IconInfo, color: 'var(--gr-muted-fg)', role: 'status' },\n info: { icon: IconInfo, color: 'var(--gr-info)', role: 'status' },\n success: { icon: IconCheck, color: 'var(--gr-success)', role: 'status' },\n warning: { icon: IconWarning, color: 'var(--gr-warning)', role: 'alert' },\n danger: { icon: IconError, color: 'var(--gr-danger)', role: 'alert' },\n slate: { icon: IconInfo, color: 'var(--gr-slate)', role: 'status' },\n azure: { icon: IconInfo, color: 'var(--gr-azure)', role: 'status' },\n}\n\nexport interface GrToasterProps {\n /** Угол экрана для стека уведомлений. */\n placement?: GrToasterPlacement\n /** Максимум одновременно видимых тостов; остальные ждут в очереди. По умолчанию `4`. */\n maxVisible?: number\n /** A11y-лейбл кнопки закрытия (i18n). */\n dismissLabel?: string\n /** A11y-лейбл контейнера-региона (i18n). */\n regionLabel?: string\n /**\n * Ширина стека. Число — пиксели, строка — любая CSS-длина. Уезжает в\n * `--gr-toaster-width`, поэтому то же самое можно задать и темой.\n */\n width?: string | number\n /**\n * Клавиша перевода фокуса в стек уведомлений; `false` отключает хоткей.\n * `F6` — рекомендация APG для перехода между «регионами» страницы.\n */\n focusHotkey?: string | false\n /**\n * Смахивание тоста к своему краю экрана. Клавиатурный эквивалент — `Delete`\n * и `Backspace` на сфокусированном тосте — остаётся и при выключенном жесте.\n */\n swipeDismiss?: boolean\n /**\n * Со скольких видимых тостов стек схлопывается в стопку: колонка занимает\n * место одного тоста, а остальные выглядывают из-под передней. Разворачивается\n * по наведению и по фокусу. `false` — не схлопывать никогда.\n *\n * Порог, а не переключатель: пока тостов мало, колонка читается лучше стопки,\n * и менять её незачем.\n */\n collapse?: number | false\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\n\nconst props = withDefaults(defineProps<GrToasterProps>(), {\n placement: 'top-right',\n maxVisible: 4,\n dismissLabel: undefined,\n regionLabel: undefined,\n width: undefined,\n focusHotkey: 'F6',\n swipeDismiss: true,\n collapse: 3,\n})\n\n/**\n * Слот `actions` полностью заменяет дефолтные action-кнопки тоста. Получает сам\n * `toast` и `dismiss` — функцию, закрывающую именно этот тост.\n */\ndefineSlots<{\n actions?: (props: { toast: Toast, dismiss: () => void }) => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\nconst slots = useSlots()\nconst resolvedDismissLabel = computed(() => props.dismissLabel ?? t('gr.toaster.dismiss', 'Dismiss'))\nconst resolvedRegionLabel = computed(() => props.regionLabel ?? t('gr.toaster.region', 'Notifications'))\n\nconst { list, dismiss, pause, resume } = useToast()\n\n// Единый список кнопок тоста: `action` (шорткат) + массив `actions`.\nfunction toastActions(toast: Toast): ToastAction[] {\n return [...(toast.action ? [toast.action] : []), ...(toast.actions ?? [])]\n}\n\n// Показываем блок действий, если есть кнопки или задан слот `actions`.\nfunction hasActions(toast: Toast): boolean {\n return Boolean(slots.actions) || toastActions(toast).length > 0\n}\n\n// Клик по action-кнопке тоста: вызываем обработчик и (по умолчанию) закрываем тост.\nfunction onAction(toast: Toast, action: ToastAction): void {\n action.onClick()\n if (action.dismissOnClick !== false)\n dismiss(toast.id)\n}\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем `teleport`.\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget()\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\n// Видимые тосты (не больше `maxVisible`); остальные ждут в очереди. Список\n// хранится новейшими вперёд, поэтому «видимые дожинают, новые ждут» — это\n// хвост: старейшие N. Взяв голову, стек показывал бы новейшие, и каждый пуш\n// вытеснял бы с экрана тост, который пользователь ещё читает.\nconst visibleToasts = computed(() => list.value.slice(-Math.max(1, props.maxVisible)))\nconst visibleIds = computed(() => new Set(visibleToasts.value.map(toast => toast.id)))\n\n// Пауза под курсором/фокусом (WCAG 2.2.1). Флага два и они независимы: один\n// `paused` терялся на «фокус внутри + мышь прошла насквозь» — `mouseleave`\n// возобновлял отсчёт под клавиатурным фокусом.\nconst hovered = ref(false)\nconst focusWithin = ref(false)\n\n// Контейнер стека: по нему ищутся тосты — и для фокуса, и для жеста.\nconst containerEl = ref<HTMLElement | null>(null)\n\n// ————— Стопка.\n\n/**\n * Развёрнуто — по тем же двум флагам, что держат `paused`: рука на стеке или\n * фокус внутри. Отдельного сигнала не заводим — читать стопку и не остановить\n * при этом таймеры было бы ловушкой.\n */\nconst expanded = computed(() => hovered.value || focusWithin.value)\nconst stacked = computed(() => props.collapse !== false && visibleToasts.value.length > Math.max(1, props.collapse))\nconst collapsed = computed(() => stacked.value && !expanded.value)\n\n/**\n * Высоты тостов: они разные (заголовок, заголовок с текстом, плюс кнопки), а\n * развёрнутая раскладка складывает их накопительно.\n *\n * `offsetHeight`, а не `getBoundingClientRect().height`: свёрнутая карточка\n * уменьшена `scale()`, и рект вернул бы её экранный размер — стопка мерила бы\n * саму себя и с каждым замером сжималась.\n */\nconst toastHeights = ref<Record<string, number>>({})\n\nlet heightObserver: ResizeObserver | null = null\n\nfunction measureToasts(): void {\n const root = containerEl.value\n if (!root)\n return\n\n const next: Record<string, number> = {}\n for (const node of root.querySelectorAll<HTMLElement>('[data-gr-toast]')) {\n const id = node.dataset.toastId\n // В jsdom высота нулевая: раскладка обязана это пережить, поэтому нули не\n // запоминаются, а потребитель значения падает на запасной путь.\n if (id && node.offsetHeight > 0)\n next[id] = node.offsetHeight\n\n heightObserver?.observe(node)\n }\n\n toastHeights.value = next\n}\n\nonMounted(() => {\n if (typeof ResizeObserver !== 'undefined')\n heightObserver = new ResizeObserver(() => measureToasts())\n\n measureToasts()\n})\n\n// Замер до отрисовки кадра: содержимое тоста меняется на месте (`update`,\n// `toast.promise`), и без этого стопка кадр стояла бы по старым высотам.\nonUpdated(measureToasts)\n\nonBeforeUnmount(() => {\n heightObserver?.disconnect()\n heightObserver = null\n})\n\n/** Все ли видимые тосты измерены. Пока нет — раскладка остаётся потоком. */\nconst measured = computed(() => visibleToasts.value.every(toast => toastHeights.value[toast.id] > 0))\n\n/** Абсолютная раскладка включается только когда есть чем считать смещения. */\nconst positioned = computed(() => stacked.value && measured.value)\n\nfunction expandedOffset(index: number): number {\n let offset = 0\n for (let i = 0; i < index; i++)\n offset += (toastHeights.value[visibleToasts.value[i].id] ?? 0) + STACK_GAP_PX\n\n return offset\n}\n\nfunction depthOf(index: number): number {\n return stackDepth(index, visibleToasts.value.length, props.placement)\n}\n\n/** Высота передней карточки — по ней живёт вся свёрнутая стопка. */\nconst frontHeight = computed(() => {\n const heights = visibleToasts.value.map(toast => toastHeights.value[toast.id] ?? 0)\n return props.placement.startsWith('top') ? heights[0] : heights[heights.length - 1]\n})\n\nconst stackHeight = computed(() => {\n if (!positioned.value)\n return undefined\n\n if (collapsed.value)\n return `${frontHeight.value}px`\n\n const heights = visibleToasts.value.map(toast => toastHeights.value[toast.id] ?? 0)\n return `${heights.reduce((sum, h) => sum + h, 0) + STACK_GAP_PX * (heights.length - 1)}px`\n})\n\n/** Карточка лежит за передней: в свёрнутой стопке от неё виден только край. */\nfunction isBehind(index: number): boolean {\n return collapsed.value && positioned.value && depthOf(index) > 0\n}\n\n/**\n * Содержимое карточек за передней гасится: из-под неё видно 12 пикселей, и в\n * эту полоску попадали обрывок строки и хвост полосы прогресса. Колода должна\n * читаться краями карточек, а не мусором в щели.\n */\nfunction toastContentStyle(index: number): Record<string, string> | undefined {\n return isBehind(index) ? { opacity: '0' } : undefined\n}\n\n// ————— Смахивание.\n\nconst swipingId = ref<string | null>(null)\nconst swipeOffset = ref(0)\nlet swipeStartX = 0\nlet swipeThreshold = SWIPE_THRESHOLD_MIN_PX\n\n// Тост, который тянут, тоже держит таймеры: иначе уведомление сгорало бы прямо\n// под пальцем, посреди жеста.\nconst paused = computed(() => hovered.value || focusWithin.value || swipingId.value !== null)\n\nfunction toastElement(id: string): HTMLElement | null {\n return containerEl.value?.querySelector<HTMLElement>(`[data-gr-toast][data-toast-id=\"${id}\"]`) ?? null\n}\n\n/** Жест отпущен и тост закрывается: переход снова разрешён (см. `releaseSwiped`). */\nconst swipeReleased = ref(false)\n\nfunction resetSwipe(): void {\n swipingId.value = null\n swipeOffset.value = 0\n swipeReleased.value = false\n}\n\n/**\n * Отпущенный тост уезжает за свой край и только потом закрывается.\n *\n * Два кадра здесь обязательны, и оба по одной причине: уходящий элемент Vue\n * больше не перерисовывает — он уезжает с тем стилем, что был на последнем\n * рендере. Значит и разрешение перехода, и конечную точку нужно успеть отдать\n * до закрытия: первый кадр снимает инлайновый `transition: none` (во время\n * жеста он нужен, иначе переходы группы борются с пальцем), второй задаёт точку\n * отлёта — с этого момента анимация уже идёт, и `leave` подхватывает её на ходу.\n *\n * Закрыв тост сразу, получили бы не отлёт, а мгновенное исчезновение: элемент\n * ушёл бы в `leave` с запрещённым переходом.\n */\nasync function releaseSwiped(id: string): Promise<void> {\n swipeReleased.value = true\n await nextTick()\n\n swipeOffset.value = SWIPE_DIRECTION[props.placement] * SWIPE_FLY_OUT_PX\n await nextTick()\n\n dismiss(id)\n resetSwipe()\n}\n\n/**\n * Движение к своему краю идёт один к одному, в обратную сторону — с\n * сопротивлением: тост едет за пальцем, но закрыть его «наоборот» нельзя.\n */\nfunction resistOffset(delta: number): number {\n const toEdge = SWIPE_DIRECTION[props.placement]\n\n return Math.sign(delta) === toEdge ? delta : delta / SWIPE_RESISTANCE\n}\n\nconst swipe = useDragGesture({\n disabled: () => !props.swipeDismiss,\n onStart: (event) => {\n const target = event.target as HTMLElement | null\n // Нажатие на кнопке — это нажатие на кнопке: закрытие и действия тоста не\n // должны превращаться в протяжку.\n if (target?.closest('button, a[href]'))\n return false\n\n const host = target?.closest<HTMLElement>('[data-gr-toast]')\n const id = host?.dataset.toastId\n if (!host || !id)\n return false\n\n swipingId.value = id\n swipeOffset.value = 0\n swipeStartX = event.clientX\n swipeThreshold = Math.max(SWIPE_THRESHOLD_MIN_PX, host.getBoundingClientRect().width * SWIPE_THRESHOLD_RATIO)\n },\n onMove: (event) => {\n // Против выделения текста тоста во время протяжки.\n event.preventDefault()\n swipeOffset.value = resistOffset(event.clientX - swipeStartX)\n },\n onEnd: () => {\n const id = swipingId.value\n const passed = id !== null\n && Math.sign(swipeOffset.value) === SWIPE_DIRECTION[props.placement]\n && Math.abs(swipeOffset.value) >= swipeThreshold\n\n if (passed)\n void releaseSwiped(id)\n else resetSwipe()\n },\n // Обрыв возвращает тост на место, а не дожимает смахивание: указатель забрал\n // браузер, а не пользователь довёл жест.\n onCancel: resetSwipe,\n})\n\n/**\n * Стиль тоста: смахивание и стопка пишут в один `transform`. Двух инлайновых\n * трансформов не бывает — второй затирает первый, и жест отменял бы раскладку.\n */\nfunction toastStyle(toast: Toast, index: number): Record<string, string> | undefined {\n const style: Record<string, string> = {}\n const transforms: string[] = []\n\n if (swipingId.value === toast.id) {\n // Смахивание идёт первым: трансформы применяются справа налево, и после\n // `scale()` жест ехал бы в масштабе карточки, а не в пикселях экрана.\n transforms.push(`translateX(${swipeOffset.value}px)`)\n style.opacity = String(swipeOpacity(swipeOffset.value, swipeThreshold))\n\n // Переходы группы во время жеста борются с пальцем: тост едет с задержкой\n // и «догоняет» курсор после отпускания. После отпускания запрет снимается —\n // уходящему тосту переход нужен, иначе он не уедет вовсе.\n if (!swipeReleased.value)\n style.transition = 'none'\n }\n\n if (positioned.value) {\n const depth = depthOf(index)\n\n transforms.push(collapsed.value\n ? collapsedTransform(depth, props.placement)\n : `translateY(${expandedOffset(index)}px)`)\n\n style.zIndex = String(visibleToasts.value.length - depth)\n\n /*\n * Уменьшение идёт от того края, которым стопка прижата к углу. По центру\n * (умолчание) карточка теряет высоту с обеих сторон, и соседи разной высоты\n * выглядывают на разное расстояние — колода получается рваной.\n */\n style.transformOrigin = props.placement.startsWith('top') ? 'top center' : 'bottom center'\n\n /*\n * Высота карточек за передней приравнивается к её собственной: иначе более\n * высокий тост выглядывал бы дальше соседа, и шаг колоды плясал бы вместе с\n * длиной сообщения.\n */\n if (collapsed.value && depth > 0 && frontHeight.value > 0)\n style.height = `${frontHeight.value}px`\n\n if (collapsed.value && depth > STACK_PEEK_DEPTH) {\n style.opacity = '0'\n // Почти невидимый край иначе ловил бы клики мимо передней карточки.\n style.pointerEvents = 'none'\n }\n }\n\n if (transforms.length > 0)\n style.transform = transforms.join(' ')\n\n return Object.keys(style).length > 0 ? style : undefined\n}\n\n/**\n * Клавиатурный эквивалент смахивания. `Escape` намеренно не берём: тостер не\n * модальный слой, и перехват закрывал бы уведомление вместо диалога под ним.\n */\nfunction onToastKeydown(event: KeyboardEvent, toast: Toast): void {\n if (event.key !== 'Delete' && event.key !== 'Backspace')\n return\n\n event.preventDefault()\n\n const index = visibleToasts.value.findIndex(item => item.id === toast.id)\n const next = visibleToasts.value[index + 1] ?? visibleToasts.value[index - 1]\n\n dismiss(toast.id)\n\n // Фокус не должен упасть на `body`: дальше по стеку есть что читать.\n if (next)\n void nextTick(() => toastElement(next.id)?.focus())\n}\n\n// Единый источник правды по таймерам: тост тикает, только если он видим И стек не на\n// паузе. Очередь и hover — на паузе. Реагирует на изменения списка/hover.\n//\n// `timeoutMs` читается ради зависимости, а не ради значения: `toast.promise` и\n// `update` перезапускают таймер уже существующего тоста, не трогая ни список, ни\n// паузу. Без этой зависимости эффект не просыпался бы, и заново заведённый\n// таймер тикал бы под курсором или у тоста, который ещё ждёт в очереди, — тот\n// сгорал бы, ни разу не показавшись.\nwatchEffect(() => {\n for (const toast of list.value) {\n const shouldTick = toast.timeoutMs > 0 && visibleIds.value.has(toast.id) && !paused.value\n\n if (shouldTick)\n resume(toast.id)\n else\n pause(toast.id)\n }\n})\n\nfunction metaFor(tone: GrToastTone): ToneMeta {\n return TONE_META[tone] ?? TONE_META.info\n}\n\nconst containerClass = computed(() => PLACEMENT_CLASS[props.placement])\n\nconst listClass = computed(() => (positioned.value\n ? 'relative transition-[height] duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]'\n : 'grid gap-3'))\n\nconst listStyle = computed(() => (stackHeight.value ? { height: stackHeight.value } : undefined))\n\n/**\n * В стопке карточка вынута из потока, а её место задаёт трансформ — он и\n * обязан ехать плавно. В обычной колонке переход не нужен: там позицию держит\n * сама раскладка, а сдвиги отрабатывает `move-class` группы.\n */\nconst toastLayoutClass = computed(() => (positioned.value\n ? 'absolute inset-x-0 top-0 transition-[transform,opacity] duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]'\n : 'relative'))\n\n/**\n * В стопке перемещение группы выключается. `TransitionGroup` двигает детей\n * приёмом FLIP: сам пишет в инлайновый `transform` и по концу перехода\n * **очищает** его — то есть стирает раскладку стопки. Класс без перехода\n * трансформа отключает проверку `hasCSSTransform`, и до записи дело не доходит.\n */\nconst moveClass = computed(() => (positioned.value\n ? 'transition-none'\n : 'transition-transform duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]'))\n\n/**\n * В стопке появление и уход красятся только прозрачностью: `translate-y-*` из\n * классов группы спорил бы с инлайновым трансформом раскладки, а инлайновый\n * сильнее — сдвиг всё равно не сыграл бы.\n */\nconst enterFromClass = computed(() => (positioned.value ? 'opacity-0' : 'opacity-0 translate-y-2'))\nconst enterToClass = computed(() => (positioned.value ? 'opacity-100' : 'opacity-100 translate-y-0'))\nconst leaveFromClass = computed(() => (positioned.value ? 'opacity-100' : 'opacity-100 translate-y-0'))\nconst leaveToClass = computed(() => (positioned.value ? 'opacity-0' : 'opacity-0 translate-y-2'))\n\nconst containerStyle = computed(() => {\n if (props.width === undefined)\n return undefined\n\n return { '--gr-toaster-width': typeof props.width === 'number' ? `${props.width}px` : props.width }\n})\n\n/**\n * Переводит фокус на верхний тост. Тост фокусируем только программно\n * (`tabindex=\"-1\"`): собственной остановкой `Tab` стек быть не должен, иначе\n * всплывающее уведомление перехватывало бы обход страницы.\n */\nfunction focus(): boolean {\n const target = containerEl.value?.querySelector<HTMLElement>('[data-gr-toast]')\n if (!target)\n return false\n\n target.focus()\n return true\n}\n\nconst hotkeyBinding = computed(() => ({\n enabled: props.focusHotkey !== false && visibleToasts.value.length > 0,\n handlers: { [props.focusHotkey || 'F6']: { handler: onFocusHotkey, allowInEditable: true } },\n}))\n\nfunction onFocusHotkey(event: KeyboardEvent): void {\n if (focus())\n event.preventDefault()\n}\n\ndefineExpose({ focus })\n</script>\n\n<template>\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <div\n ref=\"containerEl\"\n v-hotkey=\"hotkeyBinding\"\n v-bind=\"themeAttrs\"\n data-gr-toaster\n data-gr-overlay-root\n role=\"region\"\n :aria-label=\"resolvedRegionLabel\"\n class=\"fixed z-[var(--gr-z-toast)] w-[var(--gr-toaster-width,360px)] max-w-[calc(100vw-2rem)]\"\n :class=\"containerClass\"\n :style=\"containerStyle\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @focusin=\"focusWithin = true\"\n @focusout=\"focusWithin = false\"\n >\n <TransitionGroup\n tag=\"div\"\n :class=\"listClass\"\n :style=\"listStyle\"\n enter-active-class=\"transition duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n :enter-from-class=\"enterFromClass\"\n :enter-to-class=\"enterToClass\"\n leave-active-class=\"transition duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)] absolute\"\n :leave-from-class=\"leaveFromClass\"\n :leave-to-class=\"leaveToClass\"\n :move-class=\"moveClass\"\n >\n <div\n v-for=\"(toast, index) in visibleToasts\"\n :key=\"toast.id\"\n data-gr-toast\n :data-tone=\"toast.tone\"\n :data-toast-id=\"toast.id\"\n :role=\"metaFor(toast.tone).role\"\n aria-atomic=\"true\"\n tabindex=\"-1\"\n class=\"overflow-hidden rounded-[var(--gr-radius-lg)] border border-[var(--gr-brd)] bg-[var(--gr-card)] px-4 py-3 shadow-[var(--gr-shadow-2)] focus-visible:outline-none focus-visible:shadow-[var(--gr-shadow-2),0_0_0_2px_var(--gr-ring)]\"\n :class=\"[swipeDismiss ? '[touch-action:pan-y]' : '', toastLayoutClass]\"\n :style=\"toastStyle(toast, index)\"\n @pointerdown=\"swipe.start\"\n @keydown=\"onToastKeydown($event, toast)\"\n >\n <div\n class=\"flex items-start gap-3 transition-opacity duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n :style=\"toastContentStyle(index)\"\n >\n <GrIcon size=\"md\" class=\"mt-0.5\" :style=\"{ color: metaFor(toast.tone).color }\">\n <component :is=\"metaFor(toast.tone).icon\" />\n </GrIcon>\n <div class=\"min-w-0 flex-1\">\n <div class=\"text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] font-700\">\n {{ toast.title }}\n </div>\n <div v-if=\"toast.message\" class=\"mt-0.5 text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] text-[var(--gr-muted-fg)]\">\n {{ toast.message }}\n </div>\n\n <!-- Action-кнопки тоста: например «Отменить»/«Повторить». Можно\n задать массивом (`actions`) или переопределить слотом. -->\n <div v-if=\"hasActions(toast)\" class=\"mt-2 flex flex-wrap gap-2\">\n <slot name=\"actions\" :toast=\"toast\" :dismiss=\"() => dismiss(toast.id)\">\n <GrButton\n v-for=\"(action, index) in toastActions(toast)\"\n :key=\"index\"\n :variant=\"action.variant ?? 'outline'\"\n :size=\"action.size ?? 'sm'\"\n data-gr-toast-action\n @click=\"onAction(toast, action)\"\n >\n {{ action.label }}\n </GrButton>\n </slot>\n </div>\n </div>\n <GrButton\n variant=\"ghost\"\n size=\"sm\"\n square\n :aria-label=\"resolvedDismissLabel\"\n @click=\"dismiss(toast.id)\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </GrButton>\n </div>\n\n <!-- Прогресс до автозакрытия; замирает вместе с таймером на паузе. -->\n <div\n v-if=\"toast.timeoutMs > 0\"\n data-gr-toast-progress\n aria-hidden=\"true\"\n class=\"gr-toast-progress absolute bottom-0 left-0 h-[2px] w-full origin-left\"\n :style=\"{\n backgroundColor: metaFor(toast.tone).color,\n animationDuration: `${toast.timeoutMs}ms`,\n animationPlayState: paused ? 'paused' : 'running',\n ...toastContentStyle(index),\n }\"\n />\n </div>\n </TransitionGroup>\n </div>\n </teleport>\n</template>\n\n<style scoped>\n.gr-toast-progress {\n animation-name: gr-toast-progress;\n animation-timing-function: linear;\n animation-fill-mode: forwards;\n}\n\n@keyframes gr-toast-progress {\n from {\n transform: scaleX(1);\n }\n to {\n transform: scaleX(0);\n }\n}\n\n/*\n * Единственная анимация пакета, которую глобальный кламп чинит неверно.\n *\n * У полосы `animation-fill-mode: forwards`, поэтому сжатая до `0.01ms` она не\n * возвращается в исходное состояние, а фиксируется на `scaleX(0)`: таймер\n * выглядит истёкшим, пока тост ещё висит на экране. Полоса — единственный\n * носитель этого смысла, и статичной её оставить нельзя, поэтому под reduce она\n * убирается совсем. Автозакрытие ведёт JS-таймер, оно не страдает, а сам элемент\n * и так `aria-hidden`.\n */\n@media (prefers-reduced-motion: reduce) {\n .gr-toast-progress {\n display: none;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * GrToaster — GR-примитив области уведомлений (toast).\n *\n * Модель состояния берётся из `useToast`, поэтому в приложении предполагается\n * **один активный `GrToaster`** на корень (или app-scoped через плагин).\n *\n * A11y:\n * - контейнер — `role=\"region\"` с `aria-label` (i18n-проп `regionLabel`);\n * - объявляет каждый тост сам собой: `role=\"status\"`, а критичные\n * (`warning`/`danger`) — ассертивный `role=\"alert\"`. Обёртки-live-region над\n * ними нет намеренно: вложение регионов с разной ассертивностью\n * спецификацией не определено, браузеры и SR расходятся вплоть до потери\n * объявления;\n * - стек достижим с клавиатуры по `focusHotkey` (по умолчанию `F6`) — тосты\n * телепортированы в конец `body`, и без хоткея кнопка «Отменить» лежала бы\n * за пределами разумного числа нажатий `Tab`.\n *\n * UX:\n * - `maxVisible` ограничивает стек; лишние ждут в очереди (их таймеры на паузе);\n * - автозакрытие **останавливается под курсором/фокусом** (WCAG 2.2.1) и\n * визуализируется прогресс-баром до закрытия;\n * - `placement` настраивает угол экрана; слой — `--gr-z-toast`.\n */\nimport { computed, nextTick, onBeforeUnmount, onMounted, onUpdated, ref, useSlots, watchEffect } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\nimport type { Component } from 'vue'\n\nimport { useDragGesture } from '../../composables/useDragGesture'\nimport { useToast } from '../../composables/useToast'\nimport { vHotkey } from '../../directives'\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport type { GrToastTone, Toast, ToastAction } from '../../composables/useToast'\nimport GrButton from '../GrButton'\nimport GrIcon from '../GrIcon'\nimport {\n collapsedTransform,\n PLACEMENT_CLASS,\n STACK_GAP_PX,\n STACK_PEEK_DEPTH,\n stackDepth,\n SWIPE_DIRECTION,\n SWIPE_FLY_OUT_PX,\n SWIPE_RESISTANCE,\n SWIPE_THRESHOLD_MIN_PX,\n SWIPE_THRESHOLD_RATIO,\n swipeOpacity,\n type GrToasterPlacement,\n} from './grToasterStyles'\n\nimport IconCheck from '~icons/lucide/check-circle'\nimport IconWarning from '~icons/lucide/alert-triangle'\nimport IconError from '~icons/lucide/x-circle'\nimport IconInfo from '~icons/lucide/info'\nimport IconClose from '~icons/lucide/x'\n\nexport type { GrToasterPlacement }\n\ninterface ToneMeta {\n icon: Component\n color: string\n role: 'status' | 'alert'\n}\n\n// Единый маппинг по tone'у: иконка, цвет, a11y-роль. На уровне модуля —\n// чтобы не пересоздавать объект на каждый рендер.\nconst TONE_META: Record<GrToastTone, ToneMeta> = {\n primary: { icon: IconInfo, color: 'var(--gr-primary)', role: 'status' },\n neutral: { icon: IconInfo, color: 'var(--gr-muted-fg)', role: 'status' },\n info: { icon: IconInfo, color: 'var(--gr-info)', role: 'status' },\n success: { icon: IconCheck, color: 'var(--gr-success)', role: 'status' },\n warning: { icon: IconWarning, color: 'var(--gr-warning)', role: 'alert' },\n danger: { icon: IconError, color: 'var(--gr-danger)', role: 'alert' },\n slate: { icon: IconInfo, color: 'var(--gr-slate)', role: 'status' },\n azure: { icon: IconInfo, color: 'var(--gr-azure)', role: 'status' },\n}\n\nexport interface GrToasterProps {\n /** Угол экрана для стека уведомлений. */\n placement?: GrToasterPlacement\n /** Максимум одновременно видимых тостов; остальные ждут в очереди. По умолчанию `4`. */\n maxVisible?: number\n /** A11y-лейбл кнопки закрытия (i18n). */\n dismissLabel?: string\n /** A11y-лейбл контейнера-региона (i18n). */\n regionLabel?: string\n /**\n * Ширина стека. Число — пиксели, строка — любая CSS-длина. Уезжает в\n * `--gr-toaster-width`, поэтому то же самое можно задать и темой.\n */\n width?: string | number\n /**\n * Клавиша перевода фокуса в стек уведомлений; `false` отключает хоткей.\n * `F6` — рекомендация APG для перехода между «регионами» страницы.\n */\n focusHotkey?: string | false\n /**\n * Смахивание тоста к своему краю экрана. Клавиатурный эквивалент — `Delete`\n * и `Backspace` на сфокусированном тосте — остаётся и при выключенном жесте.\n */\n swipeDismiss?: boolean\n /**\n * Со скольких видимых тостов стек схлопывается в стопку: колонка занимает\n * место одного тоста, а остальные выглядывают из-под передней. Разворачивается\n * по наведению и по фокусу. `false` — не схлопывать никогда.\n *\n * Порог, а не переключатель: пока тостов мало, колонка читается лучше стопки,\n * и менять её незачем.\n */\n collapse?: number | false\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\n\nconst props = withDefaults(defineProps<GrToasterProps>(), {\n placement: 'top-right',\n maxVisible: 4,\n dismissLabel: undefined,\n regionLabel: undefined,\n width: undefined,\n focusHotkey: 'F6',\n swipeDismiss: true,\n collapse: 3,\n})\n\n/**\n * Слот `actions` полностью заменяет дефолтные action-кнопки тоста. Получает сам\n * `toast` и `dismiss` — функцию, закрывающую именно этот тост.\n */\ndefineSlots<{\n actions?: (props: { toast: Toast, dismiss: () => void }) => unknown\n}>()\n\nconst { t } = useGranularityTranslations()\nconst slots = useSlots()\nconst resolvedDismissLabel = computed(() => props.dismissLabel ?? t('gr.toaster.dismiss', 'Dismiss'))\nconst resolvedRegionLabel = computed(() => props.regionLabel ?? t('gr.toaster.region', 'Notifications'))\n\nconst { list, dismiss, pause, resume } = useToast()\n\n// Единый список кнопок тоста: `action` (шорткат) + массив `actions`.\nfunction toastActions(toast: Toast): ToastAction[] {\n return [...(toast.action ? [toast.action] : []), ...(toast.actions ?? [])]\n}\n\n// Показываем блок действий, если есть кнопки или задан слот `actions`.\nfunction hasActions(toast: Toast): boolean {\n return Boolean(slots.actions) || toastActions(toast).length > 0\n}\n\n// Клик по action-кнопке тоста: вызываем обработчик и (по умолчанию) закрываем тост.\nfunction onAction(toast: Toast, action: ToastAction): void {\n action.onClick()\n if (action.dismissOnClick !== false)\n dismiss(toast.id)\n}\n\n// SSR-guard: на сервере `document.body` недоступен — отключаем `teleport`.\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget()\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\n// Видимые тосты (не больше `maxVisible`); остальные ждут в очереди. Список\n// хранится новейшими вперёд, поэтому «видимые дожинают, новые ждут» — это\n// хвост: старейшие N. Взяв голову, стек показывал бы новейшие, и каждый пуш\n// вытеснял бы с экрана тост, который пользователь ещё читает.\nconst visibleToasts = computed(() => list.value.slice(-Math.max(1, props.maxVisible)))\nconst visibleIds = computed(() => new Set(visibleToasts.value.map(toast => toast.id)))\n\n// Пауза под курсором/фокусом (WCAG 2.2.1). Флага два и они независимы: один\n// `paused` терялся на «фокус внутри + мышь прошла насквозь» — `mouseleave`\n// возобновлял отсчёт под клавиатурным фокусом.\nconst hovered = ref(false)\nconst focusWithin = ref(false)\n\n// Контейнер стека: по нему ищутся тосты — и для фокуса, и для жеста.\nconst containerEl = ref<HTMLElement | null>(null)\n\n// ————— Стопка.\n\n/**\n * Развёрнуто — по тем же двум флагам, что держат `paused`: рука на стеке или\n * фокус внутри. Отдельного сигнала не заводим — читать стопку и не остановить\n * при этом таймеры было бы ловушкой.\n */\nconst expanded = computed(() => hovered.value || focusWithin.value)\nconst stacked = computed(() => props.collapse !== false && visibleToasts.value.length > Math.max(1, props.collapse))\nconst collapsed = computed(() => stacked.value && !expanded.value)\n\n/**\n * Высоты тостов: они разные (заголовок, заголовок с текстом, плюс кнопки), а\n * развёрнутая раскладка складывает их накопительно.\n *\n * `offsetHeight`, а не `getBoundingClientRect().height`: свёрнутая карточка\n * уменьшена `scale()`, и рект вернул бы её экранный размер — стопка мерила бы\n * саму себя и с каждым замером сжималась.\n */\nconst toastHeights = ref<Record<string, number>>({})\n\nlet heightObserver: ResizeObserver | null = null\n\nfunction measureToasts(): void {\n const root = containerEl.value\n if (!root)\n return\n\n const next: Record<string, number> = {}\n for (const node of root.querySelectorAll<HTMLElement>('[data-gr-toast]')) {\n const id = node.dataset.toastId\n // В jsdom высота нулевая: раскладка обязана это пережить, поэтому нули не\n // запоминаются, а потребитель значения падает на запасной путь.\n if (id && node.offsetHeight > 0)\n next[id] = node.offsetHeight\n\n heightObserver?.observe(node)\n }\n\n toastHeights.value = next\n}\n\nonMounted(() => {\n if (typeof ResizeObserver !== 'undefined')\n heightObserver = new ResizeObserver(() => measureToasts())\n\n measureToasts()\n})\n\n// Замер до отрисовки кадра: содержимое тоста меняется на месте (`update`,\n// `toast.promise`), и без этого стопка кадр стояла бы по старым высотам.\nonUpdated(measureToasts)\n\nonBeforeUnmount(() => {\n heightObserver?.disconnect()\n heightObserver = null\n})\n\n/** Все ли видимые тосты измерены. Пока нет — раскладка остаётся потоком. */\nconst measured = computed(() => visibleToasts.value.every(toast => toastHeights.value[toast.id] > 0))\n\n/** Абсолютная раскладка включается только когда есть чем считать смещения. */\nconst positioned = computed(() => stacked.value && measured.value)\n\nfunction expandedOffset(index: number): number {\n let offset = 0\n for (let i = 0; i < index; i++)\n offset += (toastHeights.value[visibleToasts.value[i].id] ?? 0) + STACK_GAP_PX\n\n return offset\n}\n\nfunction depthOf(index: number): number {\n return stackDepth(index, visibleToasts.value.length, props.placement)\n}\n\n/** Высота передней карточки — по ней живёт вся свёрнутая стопка. */\nconst frontHeight = computed(() => {\n const heights = visibleToasts.value.map(toast => toastHeights.value[toast.id] ?? 0)\n return props.placement.startsWith('top') ? heights[0] : heights[heights.length - 1]\n})\n\nconst stackHeight = computed(() => {\n if (!positioned.value)\n return undefined\n\n if (collapsed.value)\n return `${frontHeight.value}px`\n\n const heights = visibleToasts.value.map(toast => toastHeights.value[toast.id] ?? 0)\n return `${heights.reduce((sum, h) => sum + h, 0) + STACK_GAP_PX * (heights.length - 1)}px`\n})\n\n/** Карточка лежит за передней: в свёрнутой стопке от неё виден только край. */\nfunction isBehind(index: number): boolean {\n return collapsed.value && positioned.value && depthOf(index) > 0\n}\n\n/**\n * Содержимое карточек за передней гасится: из-под неё видно 12 пикселей, и в\n * эту полоску попадали обрывок строки и хвост полосы прогресса. Колода должна\n * читаться краями карточек, а не мусором в щели.\n */\nfunction toastContentStyle(index: number): Record<string, string> | undefined {\n return isBehind(index) ? { opacity: '0' } : undefined\n}\n\n// ————— Смахивание.\n\nconst swipingId = ref<string | null>(null)\nconst swipeOffset = ref(0)\nlet swipeStartX = 0\nlet swipeThreshold = SWIPE_THRESHOLD_MIN_PX\n\n// Тост, который тянут, тоже держит таймеры: иначе уведомление сгорало бы прямо\n// под пальцем, посреди жеста.\nconst paused = computed(() => hovered.value || focusWithin.value || swipingId.value !== null)\n\nfunction toastElement(id: string): HTMLElement | null {\n return containerEl.value?.querySelector<HTMLElement>(`[data-gr-toast][data-toast-id=\"${id}\"]`) ?? null\n}\n\n/** Жест отпущен и тост закрывается: переход снова разрешён (см. `releaseSwiped`). */\nconst swipeReleased = ref(false)\n\nfunction resetSwipe(): void {\n swipingId.value = null\n swipeOffset.value = 0\n swipeReleased.value = false\n}\n\n/**\n * Отпущенный тост уезжает за свой край и только потом закрывается.\n *\n * Два кадра здесь обязательны, и оба по одной причине: уходящий элемент Vue\n * больше не перерисовывает — он уезжает с тем стилем, что был на последнем\n * рендере. Значит и разрешение перехода, и конечную точку нужно успеть отдать\n * до закрытия: первый кадр снимает инлайновый `transition: none` (во время\n * жеста он нужен, иначе переходы группы борются с пальцем), второй задаёт точку\n * отлёта — с этого момента анимация уже идёт, и `leave` подхватывает её на ходу.\n *\n * Закрыв тост сразу, получили бы не отлёт, а мгновенное исчезновение: элемент\n * ушёл бы в `leave` с запрещённым переходом.\n */\nasync function releaseSwiped(id: string): Promise<void> {\n swipeReleased.value = true\n await nextTick()\n\n swipeOffset.value = SWIPE_DIRECTION[props.placement] * SWIPE_FLY_OUT_PX\n await nextTick()\n\n dismiss(id)\n resetSwipe()\n}\n\n/**\n * Движение к своему краю идёт один к одному, в обратную сторону — с\n * сопротивлением: тост едет за пальцем, но закрыть его «наоборот» нельзя.\n */\nfunction resistOffset(delta: number): number {\n const toEdge = SWIPE_DIRECTION[props.placement]\n\n return Math.sign(delta) === toEdge ? delta : delta / SWIPE_RESISTANCE\n}\n\nconst swipe = useDragGesture({\n disabled: () => !props.swipeDismiss,\n onStart: (event) => {\n const target = event.target as HTMLElement | null\n // Нажатие на кнопке — это нажатие на кнопке: закрытие и действия тоста не\n // должны превращаться в протяжку.\n if (target?.closest('button, a[href]'))\n return false\n\n const host = target?.closest<HTMLElement>('[data-gr-toast]')\n const id = host?.dataset.toastId\n if (!host || !id)\n return false\n\n swipingId.value = id\n swipeOffset.value = 0\n swipeStartX = event.clientX\n swipeThreshold = Math.max(SWIPE_THRESHOLD_MIN_PX, host.getBoundingClientRect().width * SWIPE_THRESHOLD_RATIO)\n },\n onMove: (event) => {\n // Против выделения текста тоста во время протяжки.\n event.preventDefault()\n swipeOffset.value = resistOffset(event.clientX - swipeStartX)\n },\n onEnd: () => {\n const id = swipingId.value\n const passed = id !== null\n && Math.sign(swipeOffset.value) === SWIPE_DIRECTION[props.placement]\n && Math.abs(swipeOffset.value) >= swipeThreshold\n\n if (passed)\n void releaseSwiped(id)\n else resetSwipe()\n },\n // Обрыв возвращает тост на место, а не дожимает смахивание: указатель забрал\n // браузер, а не пользователь довёл жест.\n onCancel: resetSwipe,\n})\n\n/**\n * Стиль тоста: смахивание и стопка пишут в один `transform`. Двух инлайновых\n * трансформов не бывает — второй затирает первый, и жест отменял бы раскладку.\n */\nfunction toastStyle(toast: Toast, index: number): Record<string, string> | undefined {\n const style: Record<string, string> = {}\n const transforms: string[] = []\n\n if (swipingId.value === toast.id) {\n // Смахивание идёт первым: трансформы применяются справа налево, и после\n // `scale()` жест ехал бы в масштабе карточки, а не в пикселях экрана.\n transforms.push(`translateX(${swipeOffset.value}px)`)\n style.opacity = String(swipeOpacity(swipeOffset.value, swipeThreshold))\n\n // Переходы группы во время жеста борются с пальцем: тост едет с задержкой\n // и «догоняет» курсор после отпускания. После отпускания запрет снимается —\n // уходящему тосту переход нужен, иначе он не уедет вовсе.\n if (!swipeReleased.value)\n style.transition = 'none'\n }\n\n if (positioned.value) {\n const depth = depthOf(index)\n\n transforms.push(collapsed.value\n ? collapsedTransform(depth, props.placement)\n : `translateY(${expandedOffset(index)}px)`)\n\n style.zIndex = String(visibleToasts.value.length - depth)\n\n /*\n * Уменьшение идёт от того края, которым стопка прижата к углу. По центру\n * (умолчание) карточка теряет высоту с обеих сторон, и соседи разной высоты\n * выглядывают на разное расстояние — колода получается рваной.\n */\n style.transformOrigin = props.placement.startsWith('top') ? 'top center' : 'bottom center'\n\n /*\n * Высота карточек за передней приравнивается к её собственной: иначе более\n * высокий тост выглядывал бы дальше соседа, и шаг колоды плясал бы вместе с\n * длиной сообщения.\n */\n if (collapsed.value && depth > 0 && frontHeight.value > 0)\n style.height = `${frontHeight.value}px`\n\n if (collapsed.value && depth > STACK_PEEK_DEPTH) {\n style.opacity = '0'\n // Почти невидимый край иначе ловил бы клики мимо передней карточки.\n style.pointerEvents = 'none'\n }\n }\n\n if (transforms.length > 0)\n style.transform = transforms.join(' ')\n\n return Object.keys(style).length > 0 ? style : undefined\n}\n\n/**\n * Клавиатурный эквивалент смахивания. `Escape` намеренно не берём: тостер не\n * модальный слой, и перехват закрывал бы уведомление вместо диалога под ним.\n */\nfunction onToastKeydown(event: KeyboardEvent, toast: Toast): void {\n if (event.key !== 'Delete' && event.key !== 'Backspace')\n return\n\n event.preventDefault()\n\n const index = visibleToasts.value.findIndex(item => item.id === toast.id)\n const next = visibleToasts.value[index + 1] ?? visibleToasts.value[index - 1]\n\n dismiss(toast.id)\n\n // Фокус не должен упасть на `body`: дальше по стеку есть что читать.\n if (next)\n void nextTick(() => toastElement(next.id)?.focus())\n}\n\n// Единый источник правды по таймерам: тост тикает, только если он видим И стек не на\n// паузе. Очередь и hover — на паузе. Реагирует на изменения списка/hover.\n//\n// `timeoutMs` читается ради зависимости, а не ради значения: `toast.promise` и\n// `update` перезапускают таймер уже существующего тоста, не трогая ни список, ни\n// паузу. Без этой зависимости эффект не просыпался бы, и заново заведённый\n// таймер тикал бы под курсором или у тоста, который ещё ждёт в очереди, — тот\n// сгорал бы, ни разу не показавшись.\nwatchEffect(() => {\n for (const toast of list.value) {\n const shouldTick = toast.timeoutMs > 0 && visibleIds.value.has(toast.id) && !paused.value\n\n if (shouldTick)\n resume(toast.id)\n else\n pause(toast.id)\n }\n})\n\nfunction metaFor(tone: GrToastTone): ToneMeta {\n return TONE_META[tone] ?? TONE_META.info\n}\n\nconst containerClass = computed(() => PLACEMENT_CLASS[props.placement])\n\nconst listClass = computed(() => (positioned.value\n ? 'relative transition-[height] duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]'\n : 'grid gap-3'))\n\nconst listStyle = computed(() => (stackHeight.value ? { height: stackHeight.value } : undefined))\n\n/**\n * В стопке карточка вынута из потока, а её место задаёт трансформ — он и\n * обязан ехать плавно. В обычной колонке переход не нужен: там позицию держит\n * сама раскладка, а сдвиги отрабатывает `move-class` группы.\n */\nconst toastLayoutClass = computed(() => (positioned.value\n ? 'absolute inset-x-0 top-0 transition-[transform,opacity] duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]'\n : 'relative'))\n\n/**\n * В стопке перемещение группы выключается. `TransitionGroup` двигает детей\n * приёмом FLIP: сам пишет в инлайновый `transform` и по концу перехода\n * **очищает** его — то есть стирает раскладку стопки. Класс без перехода\n * трансформа отключает проверку `hasCSSTransform`, и до записи дело не доходит.\n */\nconst moveClass = computed(() => (positioned.value\n ? 'transition-none'\n : 'transition-transform duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]'))\n\n/**\n * В стопке появление и уход красятся только прозрачностью: `translate-y-*` из\n * классов группы спорил бы с инлайновым трансформом раскладки, а инлайновый\n * сильнее — сдвиг всё равно не сыграл бы.\n */\nconst enterFromClass = computed(() => (positioned.value ? 'opacity-0' : 'opacity-0 translate-y-2'))\nconst enterToClass = computed(() => (positioned.value ? 'opacity-100' : 'opacity-100 translate-y-0'))\nconst leaveFromClass = computed(() => (positioned.value ? 'opacity-100' : 'opacity-100 translate-y-0'))\nconst leaveToClass = computed(() => (positioned.value ? 'opacity-0' : 'opacity-0 translate-y-2'))\n\nconst containerStyle = computed(() => {\n if (props.width === undefined)\n return undefined\n\n return { '--gr-toaster-width': typeof props.width === 'number' ? `${props.width}px` : props.width }\n})\n\n/**\n * Переводит фокус на верхний тост. Тост фокусируем только программно\n * (`tabindex=\"-1\"`): собственной остановкой `Tab` стек быть не должен, иначе\n * всплывающее уведомление перехватывало бы обход страницы.\n */\nfunction focus(): boolean {\n const target = containerEl.value?.querySelector<HTMLElement>('[data-gr-toast]')\n if (!target)\n return false\n\n target.focus()\n return true\n}\n\nconst hotkeyBinding = computed(() => ({\n enabled: props.focusHotkey !== false && visibleToasts.value.length > 0,\n handlers: { [props.focusHotkey || 'F6']: { handler: onFocusHotkey, allowInEditable: true } },\n}))\n\nfunction onFocusHotkey(event: KeyboardEvent): void {\n if (focus())\n event.preventDefault()\n}\n\ndefineExpose({ focus })\n</script>\n\n<template>\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <div\n ref=\"containerEl\"\n v-hotkey=\"hotkeyBinding\"\n v-bind=\"themeAttrs\"\n data-gr-toaster\n data-gr-overlay-root\n role=\"region\"\n :aria-label=\"resolvedRegionLabel\"\n class=\"fixed z-[var(--gr-z-toast)] w-[var(--gr-toaster-width,360px)] max-w-[calc(100vw-2rem)]\"\n :class=\"containerClass\"\n :style=\"containerStyle\"\n @mouseenter=\"hovered = true\"\n @mouseleave=\"hovered = false\"\n @focusin=\"focusWithin = true\"\n @focusout=\"focusWithin = false\"\n >\n <TransitionGroup\n tag=\"div\"\n :class=\"listClass\"\n :style=\"listStyle\"\n enter-active-class=\"transition duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n :enter-from-class=\"enterFromClass\"\n :enter-to-class=\"enterToClass\"\n leave-active-class=\"transition duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-in)] absolute\"\n :leave-from-class=\"leaveFromClass\"\n :leave-to-class=\"leaveToClass\"\n :move-class=\"moveClass\"\n >\n <div\n v-for=\"(toast, index) in visibleToasts\"\n :key=\"toast.id\"\n data-gr-toast\n :data-tone=\"toast.tone\"\n :data-toast-id=\"toast.id\"\n :role=\"metaFor(toast.tone).role\"\n aria-atomic=\"true\"\n tabindex=\"-1\"\n class=\"overflow-hidden rounded-[var(--gr-radius-lg)] border border-[var(--gr-brd)] bg-[var(--gr-card)] px-4 py-3 shadow-[var(--gr-shadow-2)] focus-visible:outline-none focus-visible:shadow-[var(--gr-shadow-2),0_0_0_2px_var(--gr-ring)]\"\n :class=\"[swipeDismiss ? '[touch-action:pan-y]' : '', toastLayoutClass]\"\n :style=\"toastStyle(toast, index)\"\n @pointerdown=\"swipe.start\"\n @keydown=\"onToastKeydown($event, toast)\"\n >\n <div\n class=\"flex items-start gap-3 transition-opacity duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]\"\n :style=\"toastContentStyle(index)\"\n >\n <GrIcon size=\"md\" class=\"mt-0.5\" :style=\"{ color: metaFor(toast.tone).color }\">\n <component :is=\"metaFor(toast.tone).icon\" />\n </GrIcon>\n <div class=\"min-w-0 flex-1\">\n <div class=\"text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] font-700\">\n {{ toast.title }}\n </div>\n <div v-if=\"toast.message\" class=\"mt-0.5 text-[length:var(--gr-text-sm)] leading-[var(--gr-leading-sm)] text-[var(--gr-muted-fg)]\">\n {{ toast.message }}\n </div>\n\n <!-- Action-кнопки тоста: например «Отменить»/«Повторить». Можно\n задать массивом (`actions`) или переопределить слотом. -->\n <div v-if=\"hasActions(toast)\" class=\"mt-2 flex flex-wrap gap-2\">\n <slot name=\"actions\" :toast=\"toast\" :dismiss=\"() => dismiss(toast.id)\">\n <GrButton\n v-for=\"(action, index) in toastActions(toast)\"\n :key=\"index\"\n :variant=\"action.variant ?? 'outline'\"\n :size=\"action.size ?? 'sm'\"\n data-gr-toast-action\n @click=\"onAction(toast, action)\"\n >\n {{ action.label }}\n </GrButton>\n </slot>\n </div>\n </div>\n <GrButton\n variant=\"ghost\"\n size=\"sm\"\n square\n :aria-label=\"resolvedDismissLabel\"\n @click=\"dismiss(toast.id)\"\n >\n <GrIcon size=\"sm\">\n <IconClose />\n </GrIcon>\n </GrButton>\n </div>\n\n <!-- Прогресс до автозакрытия; замирает вместе с таймером на паузе. -->\n <div\n v-if=\"toast.timeoutMs > 0\"\n data-gr-toast-progress\n aria-hidden=\"true\"\n class=\"gr-toast-progress absolute bottom-0 left-0 h-[2px] w-full origin-left\"\n :style=\"{\n backgroundColor: metaFor(toast.tone).color,\n animationDuration: `${toast.timeoutMs}ms`,\n animationPlayState: paused ? 'paused' : 'running',\n ...toastContentStyle(index),\n }\"\n />\n </div>\n </TransitionGroup>\n </div>\n </teleport>\n</template>\n\n<style scoped>\n.gr-toast-progress {\n animation-name: gr-toast-progress;\n animation-timing-function: linear;\n animation-fill-mode: forwards;\n}\n\n@keyframes gr-toast-progress {\n from {\n transform: scaleX(1);\n }\n to {\n transform: scaleX(0);\n }\n}\n\n/*\n * Единственная анимация пакета, которую глобальный кламп чинит неверно.\n *\n * У полосы `animation-fill-mode: forwards`, поэтому сжатая до `0.01ms` она не\n * возвращается в исходное состояние, а фиксируется на `scaleX(0)`: таймер\n * выглядит истёкшим, пока тост ещё висит на экране. Полоса — единственный\n * носитель этого смысла, и статичной её оставить нельзя, поэтому под reduce она\n * убирается совсем. Автозакрытие ведёт JS-таймер, оно не страдает, а сам элемент\n * и так `aria-hidden`.\n */\n@media (prefers-reduced-motion: reduce) {\n .gr-toast-progress {\n display: none;\n }\n}\n</style>\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { n as grToasterSafelist, t as grToasterConfig } from "../../chunks/config-B5SBUa6u.js";
2
- import { t as GrToaster_default } from "./chunks/GrToaster-CZixNk0l.js";
1
+ import { n as grToasterSafelist, t as grToasterConfig } from "../../chunks/config-B7qZqiUB.js";
2
+ import { t as GrToaster_default } from "./chunks/GrToaster-OzT1VKcp.js";
3
3
  export { GrToaster_default as GrToaster, GrToaster_default as default, grToasterConfig, grToasterSafelist };
@@ -1 +1 @@
1
- .gr-toast-progress[data-v-a9c5da3d]{animation-name:gr-toast-progress-a9c5da3d;animation-timing-function:linear;animation-fill-mode:forwards}@keyframes gr-toast-progress-a9c5da3d{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@media (prefers-reduced-motion:reduce){.gr-toast-progress[data-v-a9c5da3d]{display:none}}
1
+ .gr-toast-progress[data-v-185f56c0]{animation-name:gr-toast-progress-185f56c0;animation-timing-function:linear;animation-fill-mode:forwards}@keyframes gr-toast-progress-185f56c0{0%{transform:scaleX(1)}to{transform:scaleX(0)}}@media (prefers-reduced-motion:reduce){.gr-toast-progress[data-v-185f56c0]{display:none}}
@@ -5,14 +5,10 @@ import { vClickOutside } from "../../../directives/clickOutside.js";
5
5
  import { t as GrIcon_default } from "../../GrIcon/chunks/GrIcon-DTZIgmje.js";
6
6
  import { useFloating } from "../../../composables/useFloating.js";
7
7
  import { useDismissible } from "../../../composables/useDismissible.js";
8
- import { a as triggerIconSizes, i as panelWidths, r as panelSizes } from "../../../chunks/config-iemgzS4x.js";
9
- import { Teleport, Transition, computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, normalizeStyle, onMounted, onUnmounted, onUpdated, openBlock, ref, renderSlot, toDisplayString, unref, useId, useSlots, vShow, watchEffect, withCtx, withDirectives } from "vue";
8
+ import { n as panelWidths, r as triggerIconSizes, t as panelSizes } from "../../../chunks/grTooltipStyles-CtbGEEGV.js";
9
+ import { Teleport, Transition, computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, mergeProps, normalizeClass, normalizeStyle, onMounted, onUnmounted, onUpdated, openBlock, ref, renderSlot, toDisplayString, unref, useId, useSlots, vShow, watchEffect, withCtx, withDirectives } from "vue";
10
10
  //#region src/components/GrTooltip/GrTooltip.vue?vue&type=script&setup=true&lang.ts
11
- var _hoisted_1 = {
12
- "data-gr-tooltip": "",
13
- class: "relative inline-flex"
14
- };
15
- var _hoisted_2 = ["tabindex", "aria-describedby"];
11
+ var _hoisted_1 = ["tabindex", "aria-describedby"];
16
12
  var FOCUSABLE_SELECTOR = "a[href],button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"])";
17
13
  //#endregion
18
14
  //#region src/components/GrTooltip/GrTooltip.vue
@@ -33,6 +29,14 @@ var GrTooltip_default = /* @__PURE__ */ defineComponent({
33
29
  open: {
34
30
  type: Boolean,
35
31
  default: void 0
32
+ },
33
+ block: {
34
+ type: Boolean,
35
+ default: false
36
+ },
37
+ describeTrigger: {
38
+ type: Boolean,
39
+ default: true
36
40
  }
37
41
  },
38
42
  emits: ["update:open"],
@@ -130,21 +134,30 @@ var GrTooltip_default = /* @__PURE__ */ defineComponent({
130
134
  onUpdated(syncSlotFocusable);
131
135
  watchEffect((onCleanup) => {
132
136
  const el = slotFocusableEl.value;
133
- if (!el) return;
137
+ if (!el || !props.describeTrigger) return;
134
138
  el.setAttribute("aria-describedby", tooltipId);
135
139
  onCleanup(() => el.removeAttribute("aria-describedby"));
136
140
  });
137
141
  const wrapperTabindex = computed(() => slotFocusableEl.value ? void 0 : 0);
138
- const wrapperDescribedBy = computed(() => slotFocusableEl.value ? void 0 : tooltipId);
142
+ const wrapperDescribedBy = computed(() => slotFocusableEl.value || !props.describeTrigger ? void 0 : tooltipId);
143
+ /**
144
+ * Обе обёртки, а не только внешняя: внутренний триггер тоже `inline-flex`, и
145
+ * снаружи до него не дотянуться — оставь его как есть, и содержимое всё равно
146
+ * схлопнется по себе.
147
+ */
148
+ const layoutClass = computed(() => props.block ? "flex w-full" : "inline-flex");
139
149
  return (_ctx, _cache) => {
140
- return withDirectives((openBlock(), createElementBlock("span", _hoisted_1, [createElementVNode("span", {
150
+ return withDirectives((openBlock(), createElementBlock("span", {
151
+ "data-gr-tooltip": "",
152
+ class: normalizeClass(["relative", layoutClass.value])
153
+ }, [createElementVNode("span", {
141
154
  ref_key: "triggerEl",
142
155
  ref: triggerEl,
143
156
  "data-gr-tooltip-trigger": "",
144
157
  "data-testid": "gr-tooltip-trigger",
145
158
  tabindex: wrapperTabindex.value,
146
159
  "aria-describedby": wrapperDescribedBy.value,
147
- class: "inline-flex items-center justify-center focus:outline-none",
160
+ class: normalizeClass(["items-center justify-center focus:outline-none", layoutClass.value]),
148
161
  style: normalizeStyle(triggerStyle.value),
149
162
  onMouseenter: show,
150
163
  onMouseleave: hide,
@@ -154,7 +167,7 @@ var GrTooltip_default = /* @__PURE__ */ defineComponent({
154
167
  }, [renderSlot(_ctx.$slots, "default", {}, () => [createVNode(unref(GrIcon_default), { size: triggerIconSize.value }, {
155
168
  default: withCtx(() => [createVNode(unref(info_default))]),
156
169
  _: 1
157
- }, 8, ["size"])])], 44, _hoisted_2), (openBlock(), createBlock(Teleport, {
170
+ }, 8, ["size"])])], 46, _hoisted_1), (openBlock(), createBlock(Teleport, {
158
171
  to: unref(portalTarget),
159
172
  disabled: !unref(teleportEnabled)
160
173
  }, [createVNode(Transition, {
@@ -177,7 +190,7 @@ var GrTooltip_default = /* @__PURE__ */ defineComponent({
177
190
  style: unref(floatingStyle)
178
191
  }), [renderSlot(_ctx.$slots, "content", {}, () => [createTextVNode(toDisplayString(__props.text), 1)])], 16), [[vShow, open.value]])]),
179
192
  _: 3
180
- })], 8, ["to", "disabled"]))])), [[unref(vClickOutside), dismissOnOutside.value]]);
193
+ })], 8, ["to", "disabled"]))], 2)), [[unref(vClickOutside), dismissOnOutside.value]]);
181
194
  };
182
195
  }
183
196
  });