@feugene/granularity 0.31.0 → 0.32.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 (287) hide show
  1. package/README.md +0 -1
  2. package/dist/chunks/adapter-CAOxmn2G.js.map +1 -1
  3. package/dist/chunks/{config-BHcS5Cwm.js → config-87fszqnD.js} +1 -1
  4. package/dist/chunks/{config-BHcS5Cwm.js.map → config-87fszqnD.js.map} +1 -1
  5. package/dist/chunks/config-A-bBiotF.js.map +1 -1
  6. package/dist/chunks/config-B3J0alyY.js.map +1 -1
  7. package/dist/chunks/config-BhfNgyWL.js.map +1 -1
  8. package/dist/chunks/config-Bjn30smH.js.map +1 -1
  9. package/dist/chunks/config-BqT6PMzO.js.map +1 -1
  10. package/dist/chunks/config-C0Ea9ePP.js.map +1 -1
  11. package/dist/chunks/config-C0Eu8jpG.js.map +1 -1
  12. package/dist/chunks/config-CDat1wXf.js.map +1 -1
  13. package/dist/chunks/config-CQLNjc9X2.js.map +1 -1
  14. package/dist/chunks/config-CbEbLyDE.js.map +1 -1
  15. package/dist/chunks/{config-jyr6AIZt2.js → config-CuQmUkMw2.js} +2 -2
  16. package/dist/chunks/{config-jyr6AIZt2.js.map → config-CuQmUkMw2.js.map} +1 -1
  17. package/dist/chunks/config-DeyT9dJl.js.map +1 -1
  18. package/dist/chunks/config-DnF472Ox.js.map +1 -1
  19. package/dist/chunks/config-DwABJHEo.js.map +1 -1
  20. package/dist/chunks/{config-tiUtEn4Q.js → config-E1cTyRVV.js} +1 -1
  21. package/dist/chunks/{config-tiUtEn4Q.js.map → config-E1cTyRVV.js.map} +1 -1
  22. package/dist/chunks/config-MmPym-Z72.js.map +1 -1
  23. package/dist/chunks/config-T3-DMXYm.js.map +1 -1
  24. package/dist/chunks/config-Yy67uWHY.js.map +1 -1
  25. package/dist/chunks/config-_jbgsFpw.js.map +1 -1
  26. package/dist/chunks/config-g8-JGZ_Y.js.map +1 -1
  27. package/dist/chunks/config-mlheIMtV.js.map +1 -1
  28. package/dist/chunks/config-rLkc9Zn2.js.map +1 -1
  29. package/dist/chunks/config-uzUuosv7.js.map +1 -1
  30. package/dist/chunks/context-CTbuwcYs.js.map +1 -1
  31. package/dist/chunks/deltaTone-B5OoS1vo.js.map +1 -1
  32. package/dist/chunks/es-Do2CNrC2.js.map +1 -1
  33. package/dist/chunks/fileValidation-D5TFBhbv.js.map +1 -1
  34. package/dist/chunks/focusables-BkzK42SQ.js.map +1 -1
  35. package/dist/chunks/{generated-DJ2dJ__C.js → generated-CSyPsWtM.js} +1 -1
  36. package/dist/chunks/{generated-DJ2dJ__C.js.map → generated-CSyPsWtM.js.map} +1 -1
  37. package/dist/chunks/grBadgeStyles-D8Mz73B5.js.map +1 -1
  38. package/dist/chunks/{grButtonStyles-B_-YRE__.js → grButtonStyles-B3wRWW_i.js} +4 -4
  39. package/dist/chunks/grButtonStyles-B3wRWW_i.js.map +1 -0
  40. package/dist/chunks/grLinkStyles-FME_qMpi.js.map +1 -1
  41. package/dist/chunks/grLoadingStyles-CnQaf5ry.js.map +1 -1
  42. package/dist/chunks/{grRadioStyles-D4gnU65n.js → grRadioStyles-DGL2QLy6.js} +1 -1
  43. package/dist/chunks/{grRadioStyles-D4gnU65n.js.map → grRadioStyles-DGL2QLy6.js.map} +1 -1
  44. package/dist/chunks/grSelectStyles-Cdtd10eY.js.map +1 -1
  45. package/dist/chunks/{grSliderStyles-B5uNxNJq.js → grSliderStyles-kaz6VXZ3.js} +9 -1
  46. package/dist/chunks/grSliderStyles-kaz6VXZ3.js.map +1 -0
  47. package/dist/chunks/{granular-provider-yJNX1g1G.js → granular-provider-Da2CJO6j.js} +3 -3
  48. package/dist/chunks/{granular-provider-yJNX1g1G.js.map → granular-provider-Da2CJO6j.js.map} +1 -1
  49. package/dist/chunks/granularityI18n-BC5zsj_d.js.map +1 -1
  50. package/dist/chunks/icon-Dag2tIMs.js.map +1 -1
  51. package/dist/chunks/inert-DIHCCn_1.js.map +1 -1
  52. package/dist/chunks/keyboard-DE2yhz_b.js.map +1 -1
  53. package/dist/chunks/numericStep-Bq2lj4ew.js.map +1 -1
  54. package/dist/chunks/optionFilter-DYw9XPPx.js.map +1 -1
  55. package/dist/chunks/{overlayStack-C8cfsqXa.js → overlayStack-0CZS99Da.js} +40 -6
  56. package/dist/chunks/overlayStack-0CZS99Da.js.map +1 -0
  57. package/dist/chunks/portalRoot-CVhCgdG6.js.map +1 -1
  58. package/dist/chunks/renamedProp-BwcN-SJg.js.map +1 -1
  59. package/dist/chunks/{safelist-BOq5Li7p.js → safelist-DxkMj5IW.js} +1 -1
  60. package/dist/chunks/{safelist-BOq5Li7p.js.map → safelist-DxkMj5IW.js.map} +1 -1
  61. package/dist/chunks/slotNodes-DxNXpC7v.js.map +1 -1
  62. package/dist/chunks/useControlAddons-asUr10Pf.js.map +1 -1
  63. package/dist/chunks/useControlledOpen-DV3SqLTP.js.map +1 -1
  64. package/dist/chunks/useDragSort-0l47h4yb.js.map +1 -1
  65. package/dist/chunks/useFilePreviews-DnwgdyBs.js.map +1 -1
  66. package/dist/chunks/useFocusWithin-BwHE0rzm.js.map +1 -1
  67. package/dist/chunks/{useModalOverlay-Cv5hF63W.js → useModalOverlay-D__CqLGn.js} +3 -0
  68. package/dist/chunks/useModalOverlay-D__CqLGn.js.map +1 -0
  69. package/dist/chunks/usePortalTarget-C0p-mhaM.js.map +1 -1
  70. package/dist/chunks/validation-5HhpanPP.js.map +1 -1
  71. package/dist/components/GrAlert/chunks/GrAlert-FAVf-ksH.js.map +1 -1
  72. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-X6RlmiJQ.js → GrAutocomplete-rYEY15UI.js} +1 -1
  73. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-rYEY15UI.js.map +1 -0
  74. package/dist/components/GrAutocomplete/index.js +1 -1
  75. package/dist/components/GrAutocomplete/styles.css +1 -1
  76. package/dist/components/GrAvatar/chunks/GrAvatar-CNmLmgcr.js.map +1 -1
  77. package/dist/components/GrBadge/chunks/{GrBadge-BsoocpF-.js → GrBadge-D2MfThPz.js} +1 -1
  78. package/dist/components/GrBadge/chunks/GrBadge-D2MfThPz.js.map +1 -0
  79. package/dist/components/GrBadge/index.js +1 -1
  80. package/dist/components/GrBadge/styles.css +1 -1
  81. package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-B-A3PRkE.js.map +1 -1
  82. package/dist/components/GrBottomNav/chunks/GrBottomNav-wtFatLjB.js.map +1 -1
  83. package/dist/components/GrBreadcrumbs/chunks/GrBreadcrumbs-DRDNan_n.js.map +1 -1
  84. package/dist/components/GrButton/chunks/{GrButton-Bw2AH4uX.js → GrButton-7GP0zObj.js} +1 -1
  85. package/dist/components/GrButton/chunks/GrButton-7GP0zObj.js.map +1 -0
  86. package/dist/components/GrButton/index.js +3 -3
  87. package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -1
  88. package/dist/components/GrCard/chunks/GrCard-BttXz1pQ.js.map +1 -1
  89. package/dist/components/GrCheckbox/chunks/GrCheckbox-CEcHIsXM.js.map +1 -1
  90. package/dist/components/GrCheckboxGroup/chunks/GrCheckboxGroup-BOwrVcFr.js.map +1 -1
  91. package/dist/components/GrChip/chunks/GrChip-C0vU69tf.js.map +1 -1
  92. package/dist/components/GrChipGroup/chunks/GrChipGroup-C78Vcwos.js.map +1 -1
  93. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-Dkvkr91t.js → GrCodeBlock-Dp0eEBTZ.js} +1 -1
  94. package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dp0eEBTZ.js.map +1 -0
  95. package/dist/components/GrCodeBlock/index.js +1 -1
  96. package/dist/components/GrCollapse/chunks/GrCollapse-BlW6ybdL.js.map +1 -1
  97. package/dist/components/GrColorPicker/chunks/{GrColorPicker-C7ifyQ0R.js → GrColorPicker-p2XH_8cE.js} +2 -2
  98. package/dist/components/GrColorPicker/chunks/GrColorPicker-p2XH_8cE.js.map +1 -0
  99. package/dist/components/GrColorPicker/index.js +1 -1
  100. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-C5abL2Y7.js → GrCommandPalette-BXbh3q7O.js} +2 -2
  101. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BXbh3q7O.js.map +1 -0
  102. package/dist/components/GrCommandPalette/index.js +1 -1
  103. package/dist/components/GrCommandPalette/styles.css +1 -1
  104. package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js.map +1 -1
  105. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-B9mIU78E.js → GrConfirmDialog-CUP43q__.js} +3 -3
  106. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-CUP43q__.js.map +1 -0
  107. package/dist/components/GrConfirmDialog/index.js +1 -1
  108. package/dist/components/GrContextMenu/chunks/{GrContextMenu-_FKwQvuQ.js → GrContextMenu-ClkVjdcP.js} +1 -1
  109. package/dist/components/GrContextMenu/chunks/GrContextMenu-ClkVjdcP.js.map +1 -0
  110. package/dist/components/GrContextMenu/index.js +1 -1
  111. package/dist/components/GrDataTable/chunks/{GrDataTable-C8a9_nCg.js → GrDataTable-CAGgRk27.js} +5 -3
  112. package/dist/components/GrDataTable/chunks/GrDataTable-CAGgRk27.js.map +1 -0
  113. package/dist/components/GrDataTable/index.js +1 -1
  114. package/dist/components/GrDelta/chunks/GrDelta-BZwkgQW-.js.map +1 -1
  115. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-BMeCgFV3.js.map +1 -1
  116. package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js → GrDialog-BiMJ9_T4.js} +2 -2
  117. package/dist/components/GrDialog/chunks/{GrDialog-bOUDYfmh.js.map → GrDialog-BiMJ9_T4.js.map} +1 -1
  118. package/dist/components/GrDialog/index.js +1 -1
  119. package/dist/components/GrDialogService/chunks/{GrDialogService-6s2cQ-_6.js → GrDialogService-BxNK6crD.js} +4 -4
  120. package/dist/components/GrDialogService/chunks/GrDialogService-BxNK6crD.js.map +1 -0
  121. package/dist/components/GrDialogService/index.js +1 -1
  122. package/dist/components/GrDivider/chunks/GrDivider-BXavGcMX.js.map +1 -1
  123. package/dist/components/GrDrawer/chunks/{GrDrawer-B7PiAcbU.js → GrDrawer-Ce2l3zaG.js} +6 -5
  124. package/dist/components/GrDrawer/chunks/GrDrawer-Ce2l3zaG.js.map +1 -0
  125. package/dist/components/GrDrawer/index.js +1 -1
  126. package/dist/components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js.map +1 -1
  127. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-GOzuAXsi.js.map +1 -1
  128. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js.map +1 -1
  129. package/dist/components/GrFilePreview/chunks/GrFilePreview-C9Z7hMK8.js.map +1 -1
  130. package/dist/components/GrFileUpload/chunks/GrFileUpload-NsHkRRIa.js.map +1 -1
  131. package/dist/components/GrForm/chunks/GrForm-CrnfCsgj.js.map +1 -1
  132. package/dist/components/GrFormField/chunks/GrFormField-DSylU7IU.js.map +1 -1
  133. package/dist/components/GrFormFile/chunks/{GrFormFile-CYtXU9HV.js → GrFormFile-B1jGZyIj.js} +2 -2
  134. package/dist/components/GrFormFile/chunks/GrFormFile-B1jGZyIj.js.map +1 -0
  135. package/dist/components/GrFormFile/index.js +1 -1
  136. package/dist/components/GrFormFile/styles.css +1 -1
  137. package/dist/components/GrIcon/chunks/GrIcon-Dmf0c9ba.js.map +1 -1
  138. package/dist/components/GrImageViewer/chunks/{GrImageViewer-CyVN6Zpc.js → GrImageViewer-CG4vUBg_.js} +4 -3
  139. package/dist/components/GrImageViewer/chunks/GrImageViewer-CG4vUBg_.js.map +1 -0
  140. package/dist/components/GrImageViewer/index.js +1 -1
  141. package/dist/components/GrInput/chunks/GrInput-BLywRZUN.js.map +1 -1
  142. package/dist/components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js.map +1 -1
  143. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-Cy2bknHO.js → GrJsonViewer-BCZ7lE2k.js} +2 -2
  144. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-BCZ7lE2k.js.map +1 -0
  145. package/dist/components/GrJsonViewer/index.js +1 -1
  146. package/dist/components/GrKbd/chunks/GrKbd-D2ga1H9i.js.map +1 -1
  147. package/dist/components/GrLink/chunks/GrLink-DYXw3W9w.js.map +1 -1
  148. package/dist/components/GrList/chunks/{GrList-DmT4qzLO.js → GrList-B_CRJB4c.js} +1 -1
  149. package/dist/components/GrList/chunks/GrList-B_CRJB4c.js.map +1 -0
  150. package/dist/components/GrList/index.js +1 -1
  151. package/dist/components/GrList/styles.css +1 -1
  152. package/dist/components/GrModal/chunks/{GrModal-CCoWZuIl.js → GrModal-D0mf1SAx.js} +3 -2
  153. package/dist/components/GrModal/chunks/GrModal-D0mf1SAx.js.map +1 -0
  154. package/dist/components/GrModal/index.js +1 -1
  155. package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js → GrNavbar-_rtHKwTf.js} +1 -1
  156. package/dist/components/GrNavbar/chunks/{GrNavbar-C5EjMKaC.js.map → GrNavbar-_rtHKwTf.js.map} +1 -1
  157. package/dist/components/GrNavbar/index.js +1 -1
  158. package/dist/components/GrNumberInput/chunks/GrNumberInput-DQ59YICu.js.map +1 -1
  159. package/dist/components/GrPagination/chunks/{GrPagination-Cw3R21dp.js → GrPagination-B_kAhoAV.js} +2 -2
  160. package/dist/components/GrPagination/chunks/{GrPagination-Cw3R21dp.js.map → GrPagination-B_kAhoAV.js.map} +1 -1
  161. package/dist/components/GrPagination/index.js +1 -1
  162. package/dist/components/GrPopover/chunks/{GrPopover-CofG-Tfe.js → GrPopover-faJanmGs.js} +1 -1
  163. package/dist/components/GrPopover/chunks/GrPopover-faJanmGs.js.map +1 -0
  164. package/dist/components/GrPopover/index.js +1 -1
  165. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-DLcl1xiq.js → GrPromptDialog-C6QGC7QJ.js} +4 -4
  166. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-C6QGC7QJ.js.map +1 -0
  167. package/dist/components/GrPromptDialog/index.js +1 -1
  168. package/dist/components/GrRadio/chunks/{GrRadio-C_rESc5g.js → GrRadio-Aq3v8XgG.js} +1 -1
  169. package/dist/components/GrRadio/chunks/GrRadio-Aq3v8XgG.js.map +1 -0
  170. package/dist/components/GrRadio/index.js +2 -2
  171. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-CdQO4G-U.js → GrRadioGroup-y9LVdTWh.js} +1 -1
  172. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-y9LVdTWh.js.map +1 -0
  173. package/dist/components/GrRadioGroup/index.js +1 -1
  174. package/dist/components/GrRating/chunks/GrRating-IEiTOdnF.js.map +1 -1
  175. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js → GrResponseErrorBanner-CBVRpgIG.js} +1 -1
  176. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-C_skObtv.js.map → GrResponseErrorBanner-CBVRpgIG.js.map} +1 -1
  177. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DudGc9LO.js → GrResponseErrorBanner-DMeOWlzj.js} +1 -1
  178. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js.map +1 -0
  179. package/dist/components/GrResponseErrorBanner/index.js +2 -2
  180. package/dist/components/GrSegmented/chunks/GrSegmented-CB-VR-yL.js.map +1 -1
  181. package/dist/components/GrSelect/chunks/{GrSelect-BiUrSSxc.js → GrSelect-gCeRFgQo.js} +1 -1
  182. package/dist/components/GrSelect/chunks/GrSelect-gCeRFgQo.js.map +1 -0
  183. package/dist/components/GrSelect/index.js +1 -1
  184. package/dist/components/GrSelect/styles.css +1 -1
  185. package/dist/components/GrSidebar/chunks/{GrSidebar-B8EQIlfW.js → GrSidebar-alkwBUzL.js} +1 -1
  186. package/dist/components/GrSidebar/chunks/GrSidebar-alkwBUzL.js.map +1 -0
  187. package/dist/components/GrSidebar/index.js +1 -1
  188. package/dist/components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js.map +1 -1
  189. package/dist/components/GrSlider/chunks/{GrSlider-DJfeEl4h.js → GrSlider-DTTrZTHK.js} +3 -3
  190. package/dist/components/GrSlider/chunks/GrSlider-DTTrZTHK.js.map +1 -0
  191. package/dist/components/GrSlider/index.js +2 -2
  192. package/dist/components/GrSortableList/chunks/GrSortableList-HyKX--rO.js.map +1 -1
  193. package/dist/components/GrSplitter/chunks/GrSplitter-MltjaADn.js.map +1 -1
  194. package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +1 -1
  195. package/dist/components/GrSteps/chunks/GrSteps-C2jxpZoN.js.map +1 -1
  196. package/dist/components/GrSwitch/chunks/{GrSwitch-g_OOSkh7.js → GrSwitch-7Oe5QfQZ.js} +1 -1
  197. package/dist/components/GrSwitch/chunks/GrSwitch-7Oe5QfQZ.js.map +1 -0
  198. package/dist/components/GrSwitch/index.js +1 -1
  199. package/dist/components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js.map +1 -1
  200. package/dist/components/GrTable/chunks/GrTable-Zcdz2St_.js.map +1 -1
  201. package/dist/components/GrTextarea/chunks/{GrTextarea-KREK75Bu.js → GrTextarea-DinXG12-.js} +10 -10
  202. package/dist/components/GrTextarea/chunks/GrTextarea-DinXG12-.js.map +1 -0
  203. package/dist/components/GrTextarea/index.js +1 -1
  204. package/dist/components/GrTimeline/chunks/GrTimeline-BiHpArsg.js.map +1 -1
  205. package/dist/components/GrToaster/chunks/{GrToaster-Dp7-4B8k.js → GrToaster-COXIBKzq.js} +2 -2
  206. package/dist/components/GrToaster/chunks/GrToaster-COXIBKzq.js.map +1 -0
  207. package/dist/components/GrToaster/index.js +1 -1
  208. package/dist/components/GrToaster/styles.css +1 -1
  209. package/dist/components/GrTooltip/chunks/GrTooltip-uYETdbCD.js.map +1 -1
  210. package/dist/components/GrTree/chunks/{GrTree-DC89I4AP.js → GrTree-Ci6CZfKR.js} +5 -5
  211. package/dist/components/GrTree/chunks/GrTree-Ci6CZfKR.js.map +1 -0
  212. package/dist/components/GrTree/index.js +1 -1
  213. package/dist/components/GrTree/styles.css +1 -1
  214. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-iJnMl2t9.js → GrTreeSelect-BHwgGJcT.js} +1 -1
  215. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-BHwgGJcT.js.map +1 -0
  216. package/dist/components/GrTreeSelect/index.js +1 -1
  217. package/dist/composables/useAnnouncer.js.map +1 -1
  218. package/dist/composables/useComboboxNavigation.js.map +1 -1
  219. package/dist/composables/useDragGesture.js.map +1 -1
  220. package/dist/composables/useFloating.js +2 -22
  221. package/dist/composables/useFloating.js.map +1 -1
  222. package/dist/composables/useFocusTrap.js.map +1 -1
  223. package/dist/composables/useOverlayLayer.js +10 -3
  224. package/dist/composables/useOverlayLayer.js.map +1 -1
  225. package/dist/composables/useRovingFocus.js.map +1 -1
  226. package/dist/composables/useTheme.js.map +1 -1
  227. package/dist/composables/useToast.js.map +1 -1
  228. package/dist/composables/useVirtualList.js.map +1 -1
  229. package/dist/directives/autofocus.js.map +1 -1
  230. package/dist/directives/autosize.js.map +1 -1
  231. package/dist/directives/clickOutside.js.map +1 -1
  232. package/dist/directives/dropzone.js.map +1 -1
  233. package/dist/directives/hotkey.js.map +1 -1
  234. package/dist/directives/loading.js.map +1 -1
  235. package/dist/granular-provider-node.js +1 -1
  236. package/dist/granular-provider.js +1 -1
  237. package/dist/index.js +37 -37
  238. package/dist/testing.js +2 -2
  239. package/dist/testing.js.map +1 -1
  240. package/dist/theme-apply.js.map +1 -1
  241. package/dist/theme.js +1 -1
  242. package/dist/theme.js.map +1 -1
  243. package/dist/tokens.js +1 -1
  244. package/dist/types/components/GrCodeBlock/tokenizeJson.d.ts +1 -3
  245. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +1 -1
  246. package/dist/types/components/GrInput/GrInput.vue.d.ts +24 -24
  247. package/dist/types/components/GrSlider/grSliderStyles.d.ts +9 -1
  248. package/dist/types/components/GrTabPanels/GrTabPanel.vue.d.ts +3 -3
  249. package/dist/types/composables/internal/overlayStack.d.ts +30 -0
  250. package/dist/types/composables/internal/useModalOverlay.d.ts +14 -0
  251. package/dist/types/composables/useOverlayLayer.d.ts +8 -0
  252. package/dist/vue/index.js.map +1 -1
  253. package/dist/web-types.json +1 -1
  254. package/package.json +3 -3
  255. package/dist/chunks/grButtonStyles-B_-YRE__.js.map +0 -1
  256. package/dist/chunks/grSliderStyles-B5uNxNJq.js.map +0 -1
  257. package/dist/chunks/overlayStack-C8cfsqXa.js.map +0 -1
  258. package/dist/chunks/useModalOverlay-Cv5hF63W.js.map +0 -1
  259. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-X6RlmiJQ.js.map +0 -1
  260. package/dist/components/GrBadge/chunks/GrBadge-BsoocpF-.js.map +0 -1
  261. package/dist/components/GrButton/chunks/GrButton-Bw2AH4uX.js.map +0 -1
  262. package/dist/components/GrCodeBlock/chunks/GrCodeBlock-Dkvkr91t.js.map +0 -1
  263. package/dist/components/GrColorPicker/chunks/GrColorPicker-C7ifyQ0R.js.map +0 -1
  264. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-C5abL2Y7.js.map +0 -1
  265. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-B9mIU78E.js.map +0 -1
  266. package/dist/components/GrContextMenu/chunks/GrContextMenu-_FKwQvuQ.js.map +0 -1
  267. package/dist/components/GrDataTable/chunks/GrDataTable-C8a9_nCg.js.map +0 -1
  268. package/dist/components/GrDialogService/chunks/GrDialogService-6s2cQ-_6.js.map +0 -1
  269. package/dist/components/GrDrawer/chunks/GrDrawer-B7PiAcbU.js.map +0 -1
  270. package/dist/components/GrFormFile/chunks/GrFormFile-CYtXU9HV.js.map +0 -1
  271. package/dist/components/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js.map +0 -1
  272. package/dist/components/GrJsonViewer/chunks/GrJsonViewer-Cy2bknHO.js.map +0 -1
  273. package/dist/components/GrList/chunks/GrList-DmT4qzLO.js.map +0 -1
  274. package/dist/components/GrModal/chunks/GrModal-CCoWZuIl.js.map +0 -1
  275. package/dist/components/GrPopover/chunks/GrPopover-CofG-Tfe.js.map +0 -1
  276. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-DLcl1xiq.js.map +0 -1
  277. package/dist/components/GrRadio/chunks/GrRadio-C_rESc5g.js.map +0 -1
  278. package/dist/components/GrRadioGroup/chunks/GrRadioGroup-CdQO4G-U.js.map +0 -1
  279. package/dist/components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DudGc9LO.js.map +0 -1
  280. package/dist/components/GrSelect/chunks/GrSelect-BiUrSSxc.js.map +0 -1
  281. package/dist/components/GrSidebar/chunks/GrSidebar-B8EQIlfW.js.map +0 -1
  282. package/dist/components/GrSlider/chunks/GrSlider-DJfeEl4h.js.map +0 -1
  283. package/dist/components/GrSwitch/chunks/GrSwitch-g_OOSkh7.js.map +0 -1
  284. package/dist/components/GrTextarea/chunks/GrTextarea-KREK75Bu.js.map +0 -1
  285. package/dist/components/GrToaster/chunks/GrToaster-Dp7-4B8k.js.map +0 -1
  286. package/dist/components/GrTree/chunks/GrTree-DC89I4AP.js.map +0 -1
  287. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-iJnMl2t9.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"hotkey.js","names":[],"sources":["../../src/directives/hotkey.ts"],"sourcesContent":["import type { Directive } from 'vue'\n\nimport { eventMatchesKey, isAppleDevice, isComposingEvent, isEditableTarget, shiftSatisfied } from '../internal/keyboard'\n\nexport type HotkeyHandler = (event: KeyboardEvent) => void\n\nexport type HotkeyEntry =\n | HotkeyHandler\n | {\n handler: HotkeyHandler\n /** По умолчанию: `true` для комбинаций с Ctrl/Meta/Alt, иначе `false`. */\n preventDefault?: boolean\n /** По умолчанию `false`. */\n stopPropagation?: boolean\n /** Разрешить срабатывать, когда фокус в `input/textarea/[contenteditable]`. */\n allowInEditable?: boolean\n }\n\nexport type HotkeyMap = Record<string, HotkeyEntry>\n\n/**\n * Где слушать клавиатуру:\n * - `'global'` (по умолчанию) — слушатель на `window`; хоткеи работают из любого места страницы.\n * - `'element'` — слушатель на самом элементе; хоткеи срабатывают только когда фокус внутри\n * элемента (событие всплывает до него). Элемент должен быть фокусируемым (`tabindex`).\n */\nexport type HotkeyScope = 'global' | 'element'\n\nexport type HotkeyBindingValue =\n | HotkeyMap\n | {\n handlers: HotkeyMap\n enabled?: boolean\n scope?: HotkeyScope\n }\n\ntype ParsedHotkey = {\n original: string\n key: string\n ctrl: boolean\n meta: boolean\n /** `mod` — Cmd на macOS, Ctrl на прочих: подсказка и привязка пишутся одинаково. */\n mod: boolean\n alt: boolean\n shift: boolean\n entry: HotkeyEntry\n}\n\ntype InternalState = {\n enabled: boolean\n hotkeys: ParsedHotkey[]\n listener: (event: KeyboardEvent) => void\n /** Цель, на которой висит слушатель (`window` для 'global', сам `el` для 'element'). */\n target: Window | HTMLElement\n}\n\nconst states = new WeakMap<HTMLElement, InternalState>()\n\nfunction normalizeBinding(value: HotkeyBindingValue | undefined) {\n if (!value) return { enabled: false, handlers: {} as HotkeyMap, scope: 'global' as HotkeyScope }\n if ('handlers' in (value as any)) {\n const v = value as { handlers: HotkeyMap; enabled?: boolean; scope?: HotkeyScope }\n return { enabled: v.enabled ?? true, handlers: v.handlers ?? {}, scope: v.scope ?? 'global' }\n }\n return { enabled: true, handlers: value as HotkeyMap, scope: 'global' as HotkeyScope }\n}\n\nfunction normalizeKeyToken(token: string): string {\n const t = token.trim().toLowerCase()\n if (t === 'esc') return 'Escape'\n if (t === 'escape') return 'Escape'\n if (t === 'space') return ' '\n if (t.length === 1) return t\n return token.trim()\n}\n\nfunction parseHotkeys(map: HotkeyMap): ParsedHotkey[] {\n const parsed: ParsedHotkey[] = []\n\n for (const [combo, entry] of Object.entries(map)) {\n const parts = combo\n .split('+')\n .map(p => p.trim())\n .filter(Boolean)\n\n if (!parts.length) continue\n\n let ctrl = false\n let meta = false\n let mod = false\n let alt = false\n let shift = false\n\n const keyToken = parts.at(-1)\n if (!keyToken) continue\n for (const p of parts.slice(0, -1)) {\n const t = p.toLowerCase()\n if (t === 'mod') mod = true\n else if (t === 'ctrl' || t === 'control') ctrl = true\n else if (t === 'meta' || t === 'cmd' || t === 'command' || t === '⌘') meta = true\n else if (t === 'alt' || t === 'option') alt = true\n else if (t === 'shift') shift = true\n }\n\n const key = normalizeKeyToken(keyToken)\n parsed.push({ original: combo, key, ctrl, meta, mod, alt, shift, entry })\n }\n\n return parsed\n}\n\nfunction matchesHotkey(event: KeyboardEvent, hk: ParsedHotkey): boolean {\n // Платформа читается в момент события: `navigator` в теле модуля на сервере\n // либо отсутствует, либо отвечает не за ту машину.\n const apple = hk.mod ? isAppleDevice() : false\n const expectMeta = hk.meta || (hk.mod && apple)\n const expectCtrl = hk.ctrl || (hk.mod && !apple)\n\n if (expectCtrl !== event.ctrlKey) return false\n if (expectMeta !== event.metaKey) return false\n if (hk.alt !== event.altKey) return false\n if (!shiftSatisfied(event, hk.key, hk.shift)) return false\n\n // По физическому коду матчатся только комбинации с модификаторами: там\n // клавиша — позиция на клавиатуре, и `Ctrl+K` обязан работать на любой\n // раскладке. Одиночная клавиша — печатная, её раскладка и определяет.\n return eventMatchesKey(event, hk.key, { codeFallback: expectCtrl || expectMeta || hk.alt })\n}\n\nfunction resolveEntry(entry: HotkeyEntry) {\n if (typeof entry === 'function') {\n return {\n handler: entry,\n preventDefault: undefined as boolean | undefined,\n stopPropagation: false,\n allowInEditable: false,\n }\n }\n\n return {\n handler: entry.handler,\n preventDefault: entry.preventDefault,\n stopPropagation: entry.stopPropagation ?? false,\n allowInEditable: entry.allowInEditable ?? false,\n }\n}\n\n/**\n * `v-hotkey` — горячие клавиши на компонент/страницу.\n *\n * Пример:\n * ```vue\n * <div v-hotkey=\"{ 'Escape': close, 'Ctrl+K': openSearch }\" />\n * ```\n *\n * По умолчанию слушатель глобальный (`window`). Чтобы хоткеи срабатывали только\n * когда фокус внутри элемента, используйте `scope: 'element'`:\n * ```vue\n * <div tabindex=\"0\" v-hotkey=\"{ handlers: { 'j': next }, scope: 'element' }\" />\n * ```\n */\nexport const vHotkey: Directive<HTMLElement, HotkeyBindingValue> = {\n mounted(el, binding) {\n if (typeof window === 'undefined') return\n\n const { enabled, handlers, scope } = normalizeBinding(binding.value)\n const target: Window | HTMLElement = scope === 'element' ? el : window\n\n const state: InternalState = {\n enabled,\n hotkeys: parseHotkeys(handlers),\n listener: (event: KeyboardEvent) => {\n const current = states.get(el)\n if (!current?.enabled) return\n if (!el.isConnected) return\n // Клавиша во время IME-композиции принадлежит композиции, а не хоткею.\n if (isComposingEvent(event)) return\n\n const editable = isEditableTarget(event.target)\n\n for (const hk of current.hotkeys) {\n if (!matchesHotkey(event, hk)) continue\n\n const entry = resolveEntry(hk.entry)\n\n // По умолчанию не перехватываем \"простые\" клавиши во время ввода.\n const hasModifier = hk.ctrl || hk.meta || hk.mod || hk.alt || hk.shift\n if (editable && !entry.allowInEditable && !hasModifier && hk.key !== 'Escape') {\n continue\n }\n\n const preventDefault = entry.preventDefault ?? (hk.ctrl || hk.meta || hk.mod || hk.alt)\n if (preventDefault) event.preventDefault()\n if (entry.stopPropagation) event.stopPropagation()\n\n entry.handler(event)\n return\n }\n },\n target,\n }\n\n states.set(el, state)\n target.addEventListener('keydown', state.listener as EventListener)\n },\n updated(el, binding) {\n const state = states.get(el)\n if (!state) return\n\n const next = normalizeBinding(binding.value)\n state.enabled = next.enabled\n state.hotkeys = parseHotkeys(next.handlers)\n\n // Смена scope на лету — переносим слушатель на новую цель.\n const nextTarget: Window | HTMLElement = next.scope === 'element' ? el : window\n if (nextTarget !== state.target) {\n state.target.removeEventListener('keydown', state.listener as EventListener)\n state.target = nextTarget\n nextTarget.addEventListener('keydown', state.listener as EventListener)\n }\n },\n unmounted(el) {\n const state = states.get(el)\n if (!state) return\n state.target.removeEventListener('keydown', state.listener as EventListener)\n states.delete(el)\n },\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"hotkey.js","names":[],"sources":["../../src/directives/hotkey.ts"],"sourcesContent":["import type { Directive } from 'vue'\n\nimport { eventMatchesKey, isAppleDevice, isComposingEvent, isEditableTarget, shiftSatisfied } from '../internal/keyboard'\n\nexport type HotkeyHandler = (event: KeyboardEvent) => void\n\nexport type HotkeyEntry\n = | HotkeyHandler\n | {\n handler: HotkeyHandler\n /** По умолчанию: `true` для комбинаций с Ctrl/Meta/Alt, иначе `false`. */\n preventDefault?: boolean\n /** По умолчанию `false`. */\n stopPropagation?: boolean\n /** Разрешить срабатывать, когда фокус в `input/textarea/[contenteditable]`. */\n allowInEditable?: boolean\n }\n\nexport type HotkeyMap = Record<string, HotkeyEntry>\n\n/**\n * Где слушать клавиатуру:\n * - `'global'` (по умолчанию) — слушатель на `window`; хоткеи работают из любого места страницы.\n * - `'element'` — слушатель на самом элементе; хоткеи срабатывают только когда фокус внутри\n * элемента (событие всплывает до него). Элемент должен быть фокусируемым (`tabindex`).\n */\nexport type HotkeyScope = 'global' | 'element'\n\nexport type HotkeyBindingValue\n = | HotkeyMap\n | {\n handlers: HotkeyMap\n enabled?: boolean\n scope?: HotkeyScope\n }\n\ntype ParsedHotkey = {\n original: string\n key: string\n ctrl: boolean\n meta: boolean\n /** `mod` — Cmd на macOS, Ctrl на прочих: подсказка и привязка пишутся одинаково. */\n mod: boolean\n alt: boolean\n shift: boolean\n entry: HotkeyEntry\n}\n\ntype InternalState = {\n enabled: boolean\n hotkeys: ParsedHotkey[]\n listener: (event: KeyboardEvent) => void\n /** Цель, на которой висит слушатель (`window` для 'global', сам `el` для 'element'). */\n target: Window | HTMLElement\n}\n\nconst states = new WeakMap<HTMLElement, InternalState>()\n\nfunction normalizeBinding(value: HotkeyBindingValue | undefined) {\n if (!value)\n return { enabled: false, handlers: {} as HotkeyMap, scope: 'global' as HotkeyScope }\n if ('handlers' in (value as any)) {\n const v = value as { handlers: HotkeyMap, enabled?: boolean, scope?: HotkeyScope }\n return { enabled: v.enabled ?? true, handlers: v.handlers ?? {}, scope: v.scope ?? 'global' }\n }\n return { enabled: true, handlers: value as HotkeyMap, scope: 'global' as HotkeyScope }\n}\n\nfunction normalizeKeyToken(token: string): string {\n const t = token.trim().toLowerCase()\n if (t === 'esc')\n return 'Escape'\n if (t === 'escape')\n return 'Escape'\n if (t === 'space')\n return ' '\n if (t.length === 1)\n return t\n return token.trim()\n}\n\nfunction parseHotkeys(map: HotkeyMap): ParsedHotkey[] {\n const parsed: ParsedHotkey[] = []\n\n for (const [combo, entry] of Object.entries(map)) {\n const parts = combo\n .split('+')\n .map(p => p.trim())\n .filter(Boolean)\n\n if (!parts.length)\n continue\n\n let ctrl = false\n let meta = false\n let mod = false\n let alt = false\n let shift = false\n\n const keyToken = parts.at(-1)\n if (!keyToken)\n continue\n for (const p of parts.slice(0, -1)) {\n const t = p.toLowerCase()\n if (t === 'mod')\n mod = true\n else if (t === 'ctrl' || t === 'control')\n ctrl = true\n else if (t === 'meta' || t === 'cmd' || t === 'command' || t === '⌘')\n meta = true\n else if (t === 'alt' || t === 'option')\n alt = true\n else if (t === 'shift')\n shift = true\n }\n\n const key = normalizeKeyToken(keyToken)\n parsed.push({ original: combo, key, ctrl, meta, mod, alt, shift, entry })\n }\n\n return parsed\n}\n\nfunction matchesHotkey(event: KeyboardEvent, hk: ParsedHotkey): boolean {\n // Платформа читается в момент события: `navigator` в теле модуля на сервере\n // либо отсутствует, либо отвечает не за ту машину.\n const apple = hk.mod ? isAppleDevice() : false\n const expectMeta = hk.meta || (hk.mod && apple)\n const expectCtrl = hk.ctrl || (hk.mod && !apple)\n\n if (expectCtrl !== event.ctrlKey)\n return false\n if (expectMeta !== event.metaKey)\n return false\n if (hk.alt !== event.altKey)\n return false\n if (!shiftSatisfied(event, hk.key, hk.shift))\n return false\n\n // По физическому коду матчатся только комбинации с модификаторами: там\n // клавиша — позиция на клавиатуре, и `Ctrl+K` обязан работать на любой\n // раскладке. Одиночная клавиша — печатная, её раскладка и определяет.\n return eventMatchesKey(event, hk.key, { codeFallback: expectCtrl || expectMeta || hk.alt })\n}\n\nfunction resolveEntry(entry: HotkeyEntry) {\n if (typeof entry === 'function') {\n return {\n handler: entry,\n preventDefault: undefined as boolean | undefined,\n stopPropagation: false,\n allowInEditable: false,\n }\n }\n\n return {\n handler: entry.handler,\n preventDefault: entry.preventDefault,\n stopPropagation: entry.stopPropagation ?? false,\n allowInEditable: entry.allowInEditable ?? false,\n }\n}\n\n/**\n * `v-hotkey` — горячие клавиши на компонент/страницу.\n *\n * Пример:\n * ```vue\n * <div v-hotkey=\"{ 'Escape': close, 'Ctrl+K': openSearch }\" />\n * ```\n *\n * По умолчанию слушатель глобальный (`window`). Чтобы хоткеи срабатывали только\n * когда фокус внутри элемента, используйте `scope: 'element'`:\n * ```vue\n * <div tabindex=\"0\" v-hotkey=\"{ handlers: { 'j': next }, scope: 'element' }\" />\n * ```\n */\nexport const vHotkey: Directive<HTMLElement, HotkeyBindingValue> = {\n mounted(el, binding) {\n if (typeof window === 'undefined')\n return\n\n const { enabled, handlers, scope } = normalizeBinding(binding.value)\n const target: Window | HTMLElement = scope === 'element' ? el : window\n\n const state: InternalState = {\n enabled,\n hotkeys: parseHotkeys(handlers),\n listener: (event: KeyboardEvent) => {\n const current = states.get(el)\n if (!current?.enabled)\n return\n if (!el.isConnected)\n return\n // Клавиша во время IME-композиции принадлежит композиции, а не хоткею.\n if (isComposingEvent(event))\n return\n\n const editable = isEditableTarget(event.target)\n\n for (const hk of current.hotkeys) {\n if (!matchesHotkey(event, hk))\n continue\n\n const entry = resolveEntry(hk.entry)\n\n // По умолчанию не перехватываем \"простые\" клавиши во время ввода.\n const hasModifier = hk.ctrl || hk.meta || hk.mod || hk.alt || hk.shift\n if (editable && !entry.allowInEditable && !hasModifier && hk.key !== 'Escape') {\n continue\n }\n\n const preventDefault = entry.preventDefault ?? (hk.ctrl || hk.meta || hk.mod || hk.alt)\n if (preventDefault)\n event.preventDefault()\n if (entry.stopPropagation)\n event.stopPropagation()\n\n entry.handler(event)\n return\n }\n },\n target,\n }\n\n states.set(el, state)\n target.addEventListener('keydown', state.listener as EventListener)\n },\n updated(el, binding) {\n const state = states.get(el)\n if (!state)\n return\n\n const next = normalizeBinding(binding.value)\n state.enabled = next.enabled\n state.hotkeys = parseHotkeys(next.handlers)\n\n // Смена scope на лету — переносим слушатель на новую цель.\n const nextTarget: Window | HTMLElement = next.scope === 'element' ? el : window\n if (nextTarget !== state.target) {\n state.target.removeEventListener('keydown', state.listener as EventListener)\n state.target = nextTarget\n nextTarget.addEventListener('keydown', state.listener as EventListener)\n }\n },\n unmounted(el) {\n const state = states.get(el)\n if (!state)\n return\n state.target.removeEventListener('keydown', state.listener as EventListener)\n states.delete(el)\n },\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"loading.js","names":[],"sources":["../../src/directives/loading.ts"],"sourcesContent":["import type { AppContext, Component, Directive } from 'vue'\nimport { createVNode, render } from 'vue'\n\nimport { inertableOutside, markInert } from '../composables/internal/inert'\nimport { ensurePortalRoot } from '../composables/internal/portalRoot'\nimport GrLoading from '../components/GrLoading/GrLoading.vue'\nimport type { GrIconSize, GrIconTone } from '../components/GrIcon/grIconStyles'\n\nexport type LoadingTarget = string | HTMLElement\n\nexport type LoadingOptions = {\n /**\n * Контейнер, куда будет вставлен оверлей.\n * - если не задано, то для директивы используется сам `el`\n * - для ручного вызова (`createLoading`) по умолчанию используется `document.body`\n */\n target?: LoadingTarget\n\n /**\n * Полноэкранный лоадер (рендерится в `document.body`).\n * По умолчанию включается, если `target` = `document.body`.\n */\n fullscreen?: boolean\n\n text?: string\n spinner?: Component\n spinnerClass?: string\n spinnerSize?: GrIconSize | number\n spinnerTone?: GrIconTone\n animated?: boolean\n background?: string\n /** Имя CSS-переменной слоя — escape-hatch мимо `--gr-z-loading`. */\n zIndexVar?: string\n /** Задержка показа в миллисекундах: короткая загрузка не мигает оверлеем. */\n delay?: number\n customClass?: string\n\n /**\n * Внутренний контекст Vue-приложения.\n * Нужен, чтобы кастомный `spinner` мог использовать `inject()` даже при ручном `render()`.\n */\n appContext?: AppContext\n}\n\nexport type LoadingController = {\n close: () => void\n setText: (text?: string) => void\n setOptions: (next: Partial<LoadingOptions>) => void\n readonly target: HTMLElement\n}\n\nexport type LoadingBindingValue =\n | boolean\n | (Omit<LoadingOptions, 'appContext'> & {\n loading?: boolean\n })\n\nfunction isHTMLElement(value: unknown): value is HTMLElement {\n return typeof value === 'object' && value !== null && (value as any).nodeType === 1\n}\n\nfunction resolveTarget(input: LoadingTarget | undefined, fallback: HTMLElement): HTMLElement {\n if (!input) return fallback\n\n if (typeof input === 'string') {\n // Prefer searching within the same root (document / document fragment / shadow root)\n // to support components that are not attached to `document` yet (e.g. in unit tests).\n const root = fallback.getRootNode?.() ?? document\n const foundInRoot =\n typeof (root as any).querySelector === 'function' ? ((root as any).querySelector(input) as Element | null) : null\n if (isHTMLElement(foundInRoot)) return foundInRoot\n\n const foundInDocument = document.querySelector(input)\n if (isHTMLElement(foundInDocument)) return foundInDocument\n\n return fallback\n }\n\n if (isHTMLElement(input)) {\n return input\n }\n\n return fallback\n}\n\nfunction resolveFullscreen(options: LoadingOptions, target: HTMLElement): boolean {\n if (options.fullscreen != null) return options.fullscreen\n return target === document.body\n}\n\nfunction ensurePositionedContainer(target: HTMLElement, fullscreen: boolean): () => void {\n if (fullscreen) return () => {}\n\n const prevInline = target.style.position\n const computed = window.getComputedStyle(target)\n const isStatic = computed.position === 'static' || !computed.position\n\n if (isStatic) {\n target.style.position = 'relative'\n return () => {\n target.style.position = prevInline\n }\n }\n\n return () => {}\n}\n\nfunction ensureClippedContainer(target: HTMLElement, fullscreen: boolean): () => void {\n if (fullscreen) return () => {}\n\n const computed = window.getComputedStyle(target)\n // If the target has rounded corners, we must clip its content so the overlay\n // (and its blurred backdrop) never bleeds outside the visible rounded shape.\n const hasRadius = !!computed.borderRadius && computed.borderRadius !== '0px'\n if (!hasRadius) return () => {}\n\n const overflow = computed.overflow\n if (overflow && overflow !== 'visible') return () => {}\n\n const prevInline = target.style.overflow\n target.style.overflow = 'hidden'\n return () => {\n target.style.overflow = prevInline\n }\n}\n\n/**\n * Блокирует контент под оверлеем.\n *\n * Оверлей перекрывает контейнер визуально, но не для клавиатуры и не для\n * скринридера: таб уходит в форму, которую пользователь уже не видит, а диктор\n * читает её как обычную. `inert` снимает поддерево целиком — и фокус, и\n * события указателя, и дерево доступности.\n *\n * Возвращает снятие блокировки. Чужой `inert` (элемент был инертен и до нас)\n * не трогается: снять его — значит вернуть в таб-порядок то, что скрыл кто-то\n * другой.\n */\nfunction blockContent(target: HTMLElement, overlayHost: HTMLElement, fullscreen: boolean): () => void {\n const previouslyFocused = document.activeElement\n\n // Занятость объявляет тот, чьё содержимое закрыто: у инлайнового лоадера это\n // его контейнер, у полноэкранного — вся страница. Сам оверлей при этом живёт\n // в портале, то есть в другой ветке.\n const busyElement = fullscreen ? document.body : target\n busyElement.setAttribute('aria-busy', 'true')\n\n const blocked = fullscreen\n ? inertableOutside(overlayHost)\n : Array.from(target.children).filter((child): child is HTMLElement =>\n child !== overlayHost && isHTMLElement(child),\n )\n\n const release = markInert(blocked)\n\n // Уже стоящий фокус браузер сам не забирает: Chrome оставляет его внутри\n // ставшего инертным поддерева, и пользователь продолжает печатать в поле под\n // оверлеем. Уводим фокус руками — вернём его при закрытии.\n if (isHTMLElement(previouslyFocused) && blocked.some(child => child.contains(previouslyFocused)))\n previouslyFocused.blur()\n\n return () => {\n busyElement.removeAttribute('aria-busy')\n release()\n\n // `inert` сбрасывает фокус на `body`. Возвращаем его туда, где он был, но\n // только если пользователь не увёл его сам, пока шла загрузка.\n const active = document.activeElement\n const focusLost = !active || active === document.body\n if (focusLost && isHTMLElement(previouslyFocused) && previouslyFocused.isConnected)\n previouslyFocused.focus()\n }\n}\n\nfunction parseBinding(value: LoadingBindingValue | undefined): { loading: boolean; options: LoadingOptions } {\n if (value === true || value === false) {\n return { loading: value, options: {} }\n }\n\n if (value && typeof value === 'object') {\n const { loading, ...rest } = value as any\n return { loading: loading ?? true, options: rest }\n }\n\n return { loading: false, options: {} }\n}\n\ntype InternalLoadingState = {\n controller?: LoadingController\n target?: HTMLElement\n fullscreen?: boolean\n}\n\nconst STATE_KEY: unique symbol = Symbol('grLoadingState')\n\nfunction getState(el: HTMLElement): InternalLoadingState {\n return ((el as any)[STATE_KEY] ??= {}) as InternalLoadingState\n}\n\nexport function createLoading(options: LoadingOptions = {}, fallbackTarget?: HTMLElement): LoadingController {\n const initialTarget = resolveTarget(options.target, fallbackTarget ?? document.body)\n const fullscreen = resolveFullscreen(options, initialTarget)\n // Полноэкранный лоадер — оверлей, значит живёт в общей ветке портала: только\n // так правило `inert` не пометит его вместе со страницей.\n const target = fullscreen ? (ensurePortalRoot() ?? document.body) : initialTarget\n\n const appContext = options.appContext\n\n const restorePosition = ensurePositionedContainer(target, fullscreen)\n const restoreOverflow = ensureClippedContainer(target, fullscreen)\n const mountEl = document.createElement('div')\n mountEl.setAttribute('data-gr-loading-host', '')\n // Маркер оверлея: чужой модальный слой не должен гасить лоадер `inert`.\n mountEl.setAttribute('data-gr-overlay-root', '')\n if (!fullscreen) {\n // Host wraps the overlay; make sure rounded corners of the target cascade\n // down to the overlay via `border-radius: inherit`.\n mountEl.style.borderRadius = 'inherit'\n }\n target.appendChild(mountEl)\n\n let current: LoadingOptions = { ...options }\n let disposed = false\n let unblockContent: (() => void) | undefined\n\n function doRender(): void {\n if (disposed) return\n\n const vnode = createVNode(GrLoading as any, {\n text: current.text,\n spinner: current.spinner,\n spinnerClass: current.spinnerClass,\n spinnerSize: current.spinnerSize,\n spinnerTone: current.spinnerTone,\n animated: current.animated,\n background: current.background,\n customClass: current.customClass,\n zIndexVar: current.zIndexVar,\n delay: current.delay,\n fullscreen,\n // Блокируем контент ровно тогда, когда оверлей стал видимым: с `delay`\n // это происходит позже монтирования, а до показа блокировать нечего.\n onShow: () => {\n unblockContent ??= blockContent(target, mountEl, fullscreen)\n },\n })\n\n if (appContext) {\n ;(vnode as any).appContext = appContext\n }\n\n render(vnode, mountEl)\n }\n\n function close(): void {\n if (disposed) return\n disposed = true\n\n render(null, mountEl)\n mountEl.remove()\n restoreOverflow()\n restorePosition()\n unblockContent?.()\n unblockContent = undefined\n }\n\n function setOptions(next: Partial<LoadingOptions>): void {\n current = {\n ...current,\n ...next,\n }\n doRender()\n }\n\n function setText(text?: string): void {\n setOptions({ text })\n }\n\n doRender()\n\n return {\n close,\n setOptions,\n setText,\n get target() {\n return target\n },\n }\n}\n\nfunction sync(el: HTMLElement, value: LoadingBindingValue | undefined, appContext?: AppContext): void {\n const { loading, options } = parseBinding(value)\n const state = getState(el)\n\n if (!loading) {\n state.controller?.close()\n state.controller = undefined\n state.target = undefined\n state.fullscreen = undefined\n return\n }\n\n const target = resolveTarget(options.target, el)\n const fullscreen = resolveFullscreen(options, target)\n const normalizedTarget = fullscreen ? (ensurePortalRoot() ?? document.body) : target\n\n const shouldRecreate =\n !state.controller\n || state.target !== normalizedTarget\n || state.fullscreen !== fullscreen\n\n if (shouldRecreate) {\n state.controller?.close()\n state.controller = createLoading({ ...options, fullscreen, target: normalizedTarget, appContext }, el)\n state.target = normalizedTarget\n state.fullscreen = fullscreen\n return\n }\n\n const controller = state.controller\n if (!controller) return\n controller.setOptions({ ...options, fullscreen, target: normalizedTarget })\n}\n\nexport const vLoading: Directive<HTMLElement, LoadingBindingValue> = {\n mounted(el, binding) {\n const appContext = (binding.instance as any)?.$?.appContext as AppContext | undefined\n sync(el, binding.value, appContext)\n },\n updated(el, binding) {\n const appContext = (binding.instance as any)?.$?.appContext as AppContext | undefined\n sync(el, binding.value, appContext)\n },\n unmounted(el) {\n const state = getState(el)\n state.controller?.close()\n state.controller = undefined\n state.target = undefined\n state.fullscreen = undefined\n },\n}\n"],"mappings":";;;;;AAyDA,SAAS,cAAc,OAAsC;CAC3D,OAAO,OAAO,UAAU,YAAY,UAAU,QAAS,MAAc,aAAa;AACpF;AAEA,SAAS,cAAc,OAAkC,UAAoC;CAC3F,IAAI,CAAC,OAAO,OAAO;CAEnB,IAAI,OAAO,UAAU,UAAU;EAG7B,MAAM,OAAO,SAAS,cAAc,KAAK;EACzC,MAAM,cACJ,OAAQ,KAAa,kBAAkB,aAAe,KAAa,cAAc,KAAK,IAAuB;EAC/G,IAAI,cAAc,WAAW,GAAG,OAAO;EAEvC,MAAM,kBAAkB,SAAS,cAAc,KAAK;EACpD,IAAI,cAAc,eAAe,GAAG,OAAO;EAE3C,OAAO;CACT;CAEA,IAAI,cAAc,KAAK,GACrB,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,kBAAkB,SAAyB,QAA8B;CAChF,IAAI,QAAQ,cAAc,MAAM,OAAO,QAAQ;CAC/C,OAAO,WAAW,SAAS;AAC7B;AAEA,SAAS,0BAA0B,QAAqB,YAAiC;CACvF,IAAI,YAAY,aAAa,CAAC;CAE9B,MAAM,aAAa,OAAO,MAAM;CAChC,MAAM,WAAW,OAAO,iBAAiB,MAAM;CAG/C,IAFiB,SAAS,aAAa,YAAY,CAAC,SAAS,UAE/C;EACZ,OAAO,MAAM,WAAW;EACxB,aAAa;GACX,OAAO,MAAM,WAAW;EAC1B;CACF;CAEA,aAAa,CAAC;AAChB;AAEA,SAAS,uBAAuB,QAAqB,YAAiC;CACpF,IAAI,YAAY,aAAa,CAAC;CAE9B,MAAM,WAAW,OAAO,iBAAiB,MAAM;CAI/C,IAAI,EADc,CAAC,CAAC,SAAS,gBAAgB,SAAS,iBAAiB,QACvD,aAAa,CAAC;CAE9B,MAAM,WAAW,SAAS;CAC1B,IAAI,YAAY,aAAa,WAAW,aAAa,CAAC;CAEtD,MAAM,aAAa,OAAO,MAAM;CAChC,OAAO,MAAM,WAAW;CACxB,aAAa;EACX,OAAO,MAAM,WAAW;CAC1B;AACF;;;;;;;;;;;;;AAcA,SAAS,aAAa,QAAqB,aAA0B,YAAiC;CACpG,MAAM,oBAAoB,SAAS;CAKnC,MAAM,cAAc,aAAa,SAAS,OAAO;CACjD,YAAY,aAAa,aAAa,MAAM;CAE5C,MAAM,UAAU,aACZ,iBAAiB,WAAW,IAC5B,MAAM,KAAK,OAAO,QAAQ,CAAC,CAAC,QAAQ,UAClC,UAAU,eAAe,cAAc,KAAK,CAC9C;CAEJ,MAAM,UAAU,UAAU,OAAO;CAKjC,IAAI,cAAc,iBAAiB,KAAK,QAAQ,MAAK,UAAS,MAAM,SAAS,iBAAiB,CAAC,GAC7F,kBAAkB,KAAK;CAEzB,aAAa;EACX,YAAY,gBAAgB,WAAW;EACvC,QAAQ;EAIR,MAAM,SAAS,SAAS;EAExB,KADkB,CAAC,UAAU,WAAW,SAAS,SAChC,cAAc,iBAAiB,KAAK,kBAAkB,aACrE,kBAAkB,MAAM;CAC5B;AACF;AAEA,SAAS,aAAa,OAAuF;CAC3G,IAAI,UAAU,QAAQ,UAAU,OAC9B,OAAO;EAAE,SAAS;EAAO,SAAS,CAAC;CAAE;CAGvC,IAAI,SAAS,OAAO,UAAU,UAAU;EACtC,MAAM,EAAE,SAAS,GAAG,SAAS;EAC7B,OAAO;GAAE,SAAS,WAAW;GAAM,SAAS;EAAK;CACnD;CAEA,OAAO;EAAE,SAAS;EAAO,SAAS,CAAC;CAAE;AACvC;AAQA,IAAM,YAA2B,OAAO,gBAAgB;AAExD,SAAS,SAAS,IAAuC;CACvD,OAAQ,GAAY,eAAe,CAAC;AACtC;AAEA,SAAgB,cAAc,UAA0B,CAAC,GAAG,gBAAiD;CAC3G,MAAM,gBAAgB,cAAc,QAAQ,QAAQ,kBAAkB,SAAS,IAAI;CACnF,MAAM,aAAa,kBAAkB,SAAS,aAAa;CAG3D,MAAM,SAAS,aAAc,iBAAiB,KAAK,SAAS,OAAQ;CAEpE,MAAM,aAAa,QAAQ;CAE3B,MAAM,kBAAkB,0BAA0B,QAAQ,UAAU;CACpE,MAAM,kBAAkB,uBAAuB,QAAQ,UAAU;CACjE,MAAM,UAAU,SAAS,cAAc,KAAK;CAC5C,QAAQ,aAAa,wBAAwB,EAAE;CAE/C,QAAQ,aAAa,wBAAwB,EAAE;CAC/C,IAAI,CAAC,YAGH,QAAQ,MAAM,eAAe;CAE/B,OAAO,YAAY,OAAO;CAE1B,IAAI,UAA0B,EAAE,GAAG,QAAQ;CAC3C,IAAI,WAAW;CACf,IAAI;CAEJ,SAAS,WAAiB;EACxB,IAAI,UAAU;EAEd,MAAM,QAAQ,YAAY,mBAAkB;GAC1C,MAAM,QAAQ;GACd,SAAS,QAAQ;GACjB,cAAc,QAAQ;GACtB,aAAa,QAAQ;GACrB,aAAa,QAAQ;GACrB,UAAU,QAAQ;GAClB,YAAY,QAAQ;GACpB,aAAa,QAAQ;GACrB,WAAW,QAAQ;GACnB,OAAO,QAAQ;GACf;GAGA,cAAc;IACZ,mBAAmB,aAAa,QAAQ,SAAS,UAAU;GAC7D;EACF,CAAC;EAED,IAAI,YACD,MAAe,aAAa;EAG/B,OAAO,OAAO,OAAO;CACvB;CAEA,SAAS,QAAc;EACrB,IAAI,UAAU;EACd,WAAW;EAEX,OAAO,MAAM,OAAO;EACpB,QAAQ,OAAO;EACf,gBAAgB;EAChB,gBAAgB;EAChB,iBAAiB;EACjB,iBAAiB,KAAA;CACnB;CAEA,SAAS,WAAW,MAAqC;EACvD,UAAU;GACR,GAAG;GACH,GAAG;EACL;EACA,SAAS;CACX;CAEA,SAAS,QAAQ,MAAqB;EACpC,WAAW,EAAE,KAAK,CAAC;CACrB;CAEA,SAAS;CAET,OAAO;EACL;EACA;EACA;EACA,IAAI,SAAS;GACX,OAAO;EACT;CACF;AACF;AAEA,SAAS,KAAK,IAAiB,OAAwC,YAA+B;CACpG,MAAM,EAAE,SAAS,YAAY,aAAa,KAAK;CAC/C,MAAM,QAAQ,SAAS,EAAE;CAEzB,IAAI,CAAC,SAAS;EACZ,MAAM,YAAY,MAAM;EACxB,MAAM,aAAa,KAAA;EACnB,MAAM,SAAS,KAAA;EACf,MAAM,aAAa,KAAA;EACnB;CACF;CAEA,MAAM,SAAS,cAAc,QAAQ,QAAQ,EAAE;CAC/C,MAAM,aAAa,kBAAkB,SAAS,MAAM;CACpD,MAAM,mBAAmB,aAAc,iBAAiB,KAAK,SAAS,OAAQ;CAO9E,IAJE,CAAC,MAAM,cACJ,MAAM,WAAW,oBACjB,MAAM,eAAe,YAEN;EAClB,MAAM,YAAY,MAAM;EACxB,MAAM,aAAa,cAAc;GAAE,GAAG;GAAS;GAAY,QAAQ;GAAkB;EAAW,GAAG,EAAE;EACrG,MAAM,SAAS;EACf,MAAM,aAAa;EACnB;CACF;CAEA,MAAM,aAAa,MAAM;CACzB,IAAI,CAAC,YAAY;CACjB,WAAW,WAAW;EAAE,GAAG;EAAS;EAAY,QAAQ;CAAiB,CAAC;AAC5E;AAEA,IAAa,WAAwD;CACnE,QAAQ,IAAI,SAAS;EACnB,MAAM,aAAc,QAAQ,UAAkB,GAAG;EACjD,KAAK,IAAI,QAAQ,OAAO,UAAU;CACpC;CACA,QAAQ,IAAI,SAAS;EACnB,MAAM,aAAc,QAAQ,UAAkB,GAAG;EACjD,KAAK,IAAI,QAAQ,OAAO,UAAU;CACpC;CACA,UAAU,IAAI;EACZ,MAAM,QAAQ,SAAS,EAAE;EACzB,MAAM,YAAY,MAAM;EACxB,MAAM,aAAa,KAAA;EACnB,MAAM,SAAS,KAAA;EACf,MAAM,aAAa,KAAA;CACrB;AACF"}
1
+ {"version":3,"file":"loading.js","names":[],"sources":["../../src/directives/loading.ts"],"sourcesContent":["import type { AppContext, Component, Directive } from 'vue'\nimport { createVNode, render } from 'vue'\n\nimport { inertableOutside, markInert } from '../composables/internal/inert'\nimport { ensurePortalRoot } from '../composables/internal/portalRoot'\nimport GrLoading from '../components/GrLoading/GrLoading.vue'\nimport type { GrIconSize, GrIconTone } from '../components/GrIcon/grIconStyles'\n\nexport type LoadingTarget = string | HTMLElement\n\nexport type LoadingOptions = {\n /**\n * Контейнер, куда будет вставлен оверлей.\n * - если не задано, то для директивы используется сам `el`\n * - для ручного вызова (`createLoading`) по умолчанию используется `document.body`\n */\n target?: LoadingTarget\n\n /**\n * Полноэкранный лоадер (рендерится в `document.body`).\n * По умолчанию включается, если `target` = `document.body`.\n */\n fullscreen?: boolean\n\n text?: string\n spinner?: Component\n spinnerClass?: string\n spinnerSize?: GrIconSize | number\n spinnerTone?: GrIconTone\n animated?: boolean\n background?: string\n /** Имя CSS-переменной слоя — escape-hatch мимо `--gr-z-loading`. */\n zIndexVar?: string\n /** Задержка показа в миллисекундах: короткая загрузка не мигает оверлеем. */\n delay?: number\n customClass?: string\n\n /**\n * Внутренний контекст Vue-приложения.\n * Нужен, чтобы кастомный `spinner` мог использовать `inject()` даже при ручном `render()`.\n */\n appContext?: AppContext\n}\n\nexport type LoadingController = {\n close: () => void\n setText: (text?: string) => void\n setOptions: (next: Partial<LoadingOptions>) => void\n readonly target: HTMLElement\n}\n\nexport type LoadingBindingValue\n = | boolean\n | (Omit<LoadingOptions, 'appContext'> & {\n loading?: boolean\n })\n\nfunction isHTMLElement(value: unknown): value is HTMLElement {\n return typeof value === 'object' && value !== null && (value as any).nodeType === 1\n}\n\nfunction resolveTarget(input: LoadingTarget | undefined, fallback: HTMLElement): HTMLElement {\n if (!input)\n return fallback\n\n if (typeof input === 'string') {\n // Prefer searching within the same root (document / document fragment / shadow root)\n // to support components that are not attached to `document` yet (e.g. in unit tests).\n const root = fallback.getRootNode?.() ?? document\n const foundInRoot\n = typeof (root as any).querySelector === 'function' ? ((root as any).querySelector(input) as Element | null) : null\n if (isHTMLElement(foundInRoot))\n return foundInRoot\n\n const foundInDocument = document.querySelector(input)\n if (isHTMLElement(foundInDocument))\n return foundInDocument\n\n return fallback\n }\n\n if (isHTMLElement(input)) {\n return input\n }\n\n return fallback\n}\n\nfunction resolveFullscreen(options: LoadingOptions, target: HTMLElement): boolean {\n if (options.fullscreen != null)\n return options.fullscreen\n return target === document.body\n}\n\nfunction ensurePositionedContainer(target: HTMLElement, fullscreen: boolean): () => void {\n if (fullscreen)\n return () => {}\n\n const prevInline = target.style.position\n const computed = window.getComputedStyle(target)\n const isStatic = computed.position === 'static' || !computed.position\n\n if (isStatic) {\n target.style.position = 'relative'\n return () => {\n target.style.position = prevInline\n }\n }\n\n return () => {}\n}\n\nfunction ensureClippedContainer(target: HTMLElement, fullscreen: boolean): () => void {\n if (fullscreen)\n return () => {}\n\n const computed = window.getComputedStyle(target)\n // If the target has rounded corners, we must clip its content so the overlay\n // (and its blurred backdrop) never bleeds outside the visible rounded shape.\n const hasRadius = !!computed.borderRadius && computed.borderRadius !== '0px'\n if (!hasRadius)\n return () => {}\n\n const overflow = computed.overflow\n if (overflow && overflow !== 'visible')\n return () => {}\n\n const prevInline = target.style.overflow\n target.style.overflow = 'hidden'\n return () => {\n target.style.overflow = prevInline\n }\n}\n\n/**\n * Блокирует контент под оверлеем.\n *\n * Оверлей перекрывает контейнер визуально, но не для клавиатуры и не для\n * скринридера: таб уходит в форму, которую пользователь уже не видит, а диктор\n * читает её как обычную. `inert` снимает поддерево целиком — и фокус, и\n * события указателя, и дерево доступности.\n *\n * Возвращает снятие блокировки. Чужой `inert` (элемент был инертен и до нас)\n * не трогается: снять его — значит вернуть в таб-порядок то, что скрыл кто-то\n * другой.\n */\nfunction blockContent(target: HTMLElement, overlayHost: HTMLElement, fullscreen: boolean): () => void {\n const previouslyFocused = document.activeElement\n\n // Занятость объявляет тот, чьё содержимое закрыто: у инлайнового лоадера это\n // его контейнер, у полноэкранного — вся страница. Сам оверлей при этом живёт\n // в портале, то есть в другой ветке.\n const busyElement = fullscreen ? document.body : target\n busyElement.setAttribute('aria-busy', 'true')\n\n const blocked = fullscreen\n ? inertableOutside(overlayHost)\n : Array.from(target.children).filter((child): child is HTMLElement =>\n child !== overlayHost && isHTMLElement(child),\n )\n\n const release = markInert(blocked)\n\n // Уже стоящий фокус браузер сам не забирает: Chrome оставляет его внутри\n // ставшего инертным поддерева, и пользователь продолжает печатать в поле под\n // оверлеем. Уводим фокус руками — вернём его при закрытии.\n if (isHTMLElement(previouslyFocused) && blocked.some(child => child.contains(previouslyFocused)))\n previouslyFocused.blur()\n\n return () => {\n busyElement.removeAttribute('aria-busy')\n release()\n\n // `inert` сбрасывает фокус на `body`. Возвращаем его туда, где он был, но\n // только если пользователь не увёл его сам, пока шла загрузка.\n const active = document.activeElement\n const focusLost = !active || active === document.body\n if (focusLost && isHTMLElement(previouslyFocused) && previouslyFocused.isConnected)\n previouslyFocused.focus()\n }\n}\n\nfunction parseBinding(value: LoadingBindingValue | undefined): { loading: boolean, options: LoadingOptions } {\n if (value === true || value === false) {\n return { loading: value, options: {} }\n }\n\n if (value && typeof value === 'object') {\n const { loading, ...rest } = value as any\n return { loading: loading ?? true, options: rest }\n }\n\n return { loading: false, options: {} }\n}\n\ntype InternalLoadingState = {\n controller?: LoadingController\n target?: HTMLElement\n fullscreen?: boolean\n}\n\nconst STATE_KEY: unique symbol = Symbol('grLoadingState')\n\nfunction getState(el: HTMLElement): InternalLoadingState {\n return ((el as any)[STATE_KEY] ??= {}) as InternalLoadingState\n}\n\nexport function createLoading(options: LoadingOptions = {}, fallbackTarget?: HTMLElement): LoadingController {\n const initialTarget = resolveTarget(options.target, fallbackTarget ?? document.body)\n const fullscreen = resolveFullscreen(options, initialTarget)\n // Полноэкранный лоадер — оверлей, значит живёт в общей ветке портала: только\n // так правило `inert` не пометит его вместе со страницей.\n const target = fullscreen ? (ensurePortalRoot() ?? document.body) : initialTarget\n\n const appContext = options.appContext\n\n const restorePosition = ensurePositionedContainer(target, fullscreen)\n const restoreOverflow = ensureClippedContainer(target, fullscreen)\n const mountEl = document.createElement('div')\n mountEl.setAttribute('data-gr-loading-host', '')\n // Маркер оверлея: чужой модальный слой не должен гасить лоадер `inert`.\n mountEl.setAttribute('data-gr-overlay-root', '')\n if (!fullscreen) {\n // Host wraps the overlay; make sure rounded corners of the target cascade\n // down to the overlay via `border-radius: inherit`.\n mountEl.style.borderRadius = 'inherit'\n }\n target.appendChild(mountEl)\n\n let current: LoadingOptions = { ...options }\n let disposed = false\n let unblockContent: (() => void) | undefined\n\n function doRender(): void {\n if (disposed)\n return\n\n const vnode = createVNode(GrLoading as any, {\n text: current.text,\n spinner: current.spinner,\n spinnerClass: current.spinnerClass,\n spinnerSize: current.spinnerSize,\n spinnerTone: current.spinnerTone,\n animated: current.animated,\n background: current.background,\n customClass: current.customClass,\n zIndexVar: current.zIndexVar,\n delay: current.delay,\n fullscreen,\n // Блокируем контент ровно тогда, когда оверлей стал видимым: с `delay`\n // это происходит позже монтирования, а до показа блокировать нечего.\n onShow: () => {\n unblockContent ??= blockContent(target, mountEl, fullscreen)\n },\n })\n\n if (appContext) {\n ;(vnode as any).appContext = appContext\n }\n\n render(vnode, mountEl)\n }\n\n function close(): void {\n if (disposed)\n return\n disposed = true\n\n render(null, mountEl)\n mountEl.remove()\n restoreOverflow()\n restorePosition()\n unblockContent?.()\n unblockContent = undefined\n }\n\n function setOptions(next: Partial<LoadingOptions>): void {\n current = {\n ...current,\n ...next,\n }\n doRender()\n }\n\n function setText(text?: string): void {\n setOptions({ text })\n }\n\n doRender()\n\n return {\n close,\n setOptions,\n setText,\n get target() {\n return target\n },\n }\n}\n\nfunction sync(el: HTMLElement, value: LoadingBindingValue | undefined, appContext?: AppContext): void {\n const { loading, options } = parseBinding(value)\n const state = getState(el)\n\n if (!loading) {\n state.controller?.close()\n state.controller = undefined\n state.target = undefined\n state.fullscreen = undefined\n return\n }\n\n const target = resolveTarget(options.target, el)\n const fullscreen = resolveFullscreen(options, target)\n const normalizedTarget = fullscreen ? (ensurePortalRoot() ?? document.body) : target\n\n const shouldRecreate\n = !state.controller\n || state.target !== normalizedTarget\n || state.fullscreen !== fullscreen\n\n if (shouldRecreate) {\n state.controller?.close()\n state.controller = createLoading({ ...options, fullscreen, target: normalizedTarget, appContext }, el)\n state.target = normalizedTarget\n state.fullscreen = fullscreen\n return\n }\n\n const controller = state.controller\n if (!controller)\n return\n controller.setOptions({ ...options, fullscreen, target: normalizedTarget })\n}\n\nexport const vLoading: Directive<HTMLElement, LoadingBindingValue> = {\n mounted(el, binding) {\n const appContext = (binding.instance as any)?.$?.appContext as AppContext | undefined\n sync(el, binding.value, appContext)\n },\n updated(el, binding) {\n const appContext = (binding.instance as any)?.$?.appContext as AppContext | undefined\n sync(el, binding.value, appContext)\n },\n unmounted(el) {\n const state = getState(el)\n state.controller?.close()\n state.controller = undefined\n state.target = undefined\n state.fullscreen = undefined\n },\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { a as granularityDefaultThemes, i as granularityComponentConfigs, n as GRANULARITY_PROVIDER_ID, o as granularityThemeNames, r as createGranularityProvider, t as granularityProvider } from "./chunks/granular-provider-yJNX1g1G.js";
1
+ import { a as granularityDefaultThemes, i as granularityComponentConfigs, n as GRANULARITY_PROVIDER_ID, o as granularityThemeNames, r as createGranularityProvider, t as granularityProvider } from "./chunks/granular-provider-Da2CJO6j.js";
2
2
  export { GRANULARITY_PROVIDER_ID, createGranularityProvider, granularityProvider as default, granularityProvider, granularityComponentConfigs, granularityDefaultThemes, granularityThemeNames };
@@ -1,2 +1,2 @@
1
- import { a as granularityDefaultThemes, i as granularityComponentConfigs, n as GRANULARITY_PROVIDER_ID, o as granularityThemeNames, r as createGranularityProvider, t as granularityProvider } from "./chunks/granular-provider-yJNX1g1G.js";
1
+ import { a as granularityDefaultThemes, i as granularityComponentConfigs, n as GRANULARITY_PROVIDER_ID, o as granularityThemeNames, r as createGranularityProvider, t as granularityProvider } from "./chunks/granular-provider-Da2CJO6j.js";
2
2
  export { GRANULARITY_PROVIDER_ID, createGranularityProvider, granularityProvider as default, granularityProvider, granularityComponentConfigs, granularityDefaultThemes, granularityThemeNames };
package/dist/index.js CHANGED
@@ -23,11 +23,11 @@ import { useComboboxNavigation } from "./composables/useComboboxNavigation.js";
23
23
  import { useRovingFocus } from "./composables/useRovingFocus.js";
24
24
  import { t as GrChip_default } from "./components/GrChip/chunks/GrChip-C0vU69tf.js";
25
25
  import { n as grAutocompleteSafelist, t as grAutocompleteConfig } from "./chunks/config-vYMJ3Cr1.js";
26
- import { t as GrAutocomplete_default } from "./components/GrAutocomplete/chunks/GrAutocomplete-X6RlmiJQ.js";
26
+ import { t as GrAutocomplete_default } from "./components/GrAutocomplete/chunks/GrAutocomplete-rYEY15UI.js";
27
27
  import { t as GrSkeleton_default } from "./components/GrSkeleton/chunks/GrSkeleton-CgfXxPQ2.js";
28
28
  import { n as GrAvatar_default, t as GrAvatarGroup_default } from "./components/GrAvatar/chunks/GrAvatar-CNmLmgcr.js";
29
29
  import { c as initialsFrom, n as grAvatarSafelist, t as grAvatarConfig } from "./chunks/config-B3J0alyY.js";
30
- import { t as GrBadge_default } from "./components/GrBadge/chunks/GrBadge-BsoocpF-.js";
30
+ import { t as GrBadge_default } from "./components/GrBadge/chunks/GrBadge-D2MfThPz.js";
31
31
  import { t as grBadgeSafelist } from "./chunks/safelist-CtiHPgrj.js";
32
32
  import { t as grBadgeConfig } from "./chunks/config-g8-JGZ_Y.js";
33
33
  import { n as grBadgeWrapSafelist, o as formatBadgeValue, t as grBadgeWrapConfig } from "./chunks/config-DwABJHEo.js";
@@ -38,9 +38,9 @@ import { t as GrLink_default } from "./components/GrLink/chunks/GrLink-DYXw3W9w.
38
38
  import { g as resolveBreadcrumbsLayout, h as resolveBreadcrumbsFit, n as grBreadcrumbsSafelist, t as grBreadcrumbsConfig } from "./chunks/config-C0Eu8jpG.js";
39
39
  import { t as GrBreadcrumbs_default } from "./components/GrBreadcrumbs/chunks/GrBreadcrumbs-DRDNan_n.js";
40
40
  import { n as useGrButtonGroup } from "./chunks/context-BfIQv7m1.js";
41
- import { t as GrButton_default } from "./components/GrButton/chunks/GrButton-Bw2AH4uX.js";
42
- import { t as grButtonSafelist } from "./chunks/safelist-BOq5Li7p.js";
43
- import { t as grButtonConfig } from "./chunks/config-BHcS5Cwm.js";
41
+ import { t as GrButton_default } from "./components/GrButton/chunks/GrButton-7GP0zObj.js";
42
+ import { t as grButtonSafelist } from "./chunks/safelist-DxkMj5IW.js";
43
+ import { t as grButtonConfig } from "./chunks/config-87fszqnD.js";
44
44
  import { t as GrButtonGroup_default } from "./components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js";
45
45
  import { t as grButtonGroupConfig } from "./chunks/config-DBmdgoVf2.js";
46
46
  import "./components/GrButtonGroup/index.js";
@@ -56,35 +56,35 @@ import "./components/GrChip/index.js";
56
56
  import { n as grChipGroupSafelist, t as grChipGroupConfig } from "./chunks/config-CZPDPJlg.js";
57
57
  import { t as GrChipGroup_default } from "./components/GrChipGroup/chunks/GrChipGroup-C78Vcwos.js";
58
58
  import { useAnnouncer } from "./composables/useAnnouncer.js";
59
- import { t as GrCodeBlock_default } from "./components/GrCodeBlock/chunks/GrCodeBlock-Dkvkr91t.js";
59
+ import { t as GrCodeBlock_default } from "./components/GrCodeBlock/chunks/GrCodeBlock-Dp0eEBTZ.js";
60
60
  import { n as grCodeBlockSafelist, t as grCodeBlockConfig } from "./chunks/config-DolULhjJ.js";
61
61
  import { n as grCollapseSafelist, t as grCollapseConfig } from "./chunks/config-BoUI0t-t.js";
62
62
  import { n as GrCollapse_default, t as GrCollapseItem_default } from "./components/GrCollapse/chunks/GrCollapse-BlW6ybdL.js";
63
63
  import { n as grIconSafelist, t as grIconConfig } from "./chunks/config-3bQeQvqd.js";
64
64
  import { t as GrInput_default } from "./components/GrInput/chunks/GrInput-BLywRZUN.js";
65
65
  import { useFocusTrap } from "./composables/useFocusTrap.js";
66
- import { t as GrPopover_default } from "./components/GrPopover/chunks/GrPopover-CofG-Tfe.js";
66
+ import { t as GrPopover_default } from "./components/GrPopover/chunks/GrPopover-faJanmGs.js";
67
67
  import { useDragGesture } from "./composables/useDragGesture.js";
68
- import { t as GrSlider_default } from "./components/GrSlider/chunks/GrSlider-DJfeEl4h.js";
69
- import { t as GrColorPicker_default } from "./components/GrColorPicker/chunks/GrColorPicker-C7ifyQ0R.js";
68
+ import { t as GrSlider_default } from "./components/GrSlider/chunks/GrSlider-DTTrZTHK.js";
69
+ import { t as GrColorPicker_default } from "./components/GrColorPicker/chunks/GrColorPicker-p2XH_8cE.js";
70
70
  import { n as grColorPickerSafelist, t as grColorPickerConfig } from "./chunks/config-DIDz_E5m.js";
71
71
  import { a as GR_KBD_TOKENS, o as findKbdToken, t as GrKbd_default } from "./components/GrKbd/chunks/GrKbd-D2ga1H9i.js";
72
- import { t as GrModal_default } from "./components/GrModal/chunks/GrModal-CCoWZuIl.js";
73
- import { t as GrCommandPalette_default } from "./components/GrCommandPalette/chunks/GrCommandPalette-C5abL2Y7.js";
72
+ import { t as GrModal_default } from "./components/GrModal/chunks/GrModal-D0mf1SAx.js";
73
+ import { t as GrCommandPalette_default } from "./components/GrCommandPalette/chunks/GrCommandPalette-BXbh3q7O.js";
74
74
  import { n as grCommandPaletteSafelist, t as grCommandPaletteConfig } from "./chunks/config-D0NzGYaE.js";
75
75
  import { t as GrConfigProvider_default } from "./components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js";
76
76
  import { t as grConfigProviderConfig } from "./chunks/config-B7W9VlZ7.js";
77
- import { i as GrDialogFooter_default, n as GrDialogHeader_default, r as GrDialogCloseButton_default, t as GrDialog_default } from "./components/GrDialog/chunks/GrDialog-bOUDYfmh.js";
78
- import { a as extendDefaultParsers, n as coreResponseErrorParsers, r as createResponseErrorClassifier, s as normalizeError, t as GrResponseErrorBanner_default } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DudGc9LO.js";
79
- import { t as GrConfirmDialog_default } from "./components/GrConfirmDialog/chunks/GrConfirmDialog-B9mIU78E.js";
77
+ import { i as GrDialogFooter_default, n as GrDialogHeader_default, r as GrDialogCloseButton_default, t as GrDialog_default } from "./components/GrDialog/chunks/GrDialog-BiMJ9_T4.js";
78
+ import { a as extendDefaultParsers, n as coreResponseErrorParsers, r as createResponseErrorClassifier, s as normalizeError, t as GrResponseErrorBanner_default } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-DMeOWlzj.js";
79
+ import { t as GrConfirmDialog_default } from "./components/GrConfirmDialog/chunks/GrConfirmDialog-CUP43q__.js";
80
80
  import { t as grConfirmDialogConfig } from "./chunks/config-A-bBiotF.js";
81
81
  import "./components/GrConfirmDialog/index.js";
82
82
  import { a as GrDropdownMenuItem_default, c as GrDropdownMenuDivider_default, o as GrDropdownMenuGroup_default, s as GrDropdownMenuHeader_default, t as GrDropdownMenuList_default } from "./components/GrDropdownMenu/chunks/GrDropdownMenuList-B33ZzwfB.js";
83
- import { t as GrContextMenu_default } from "./components/GrContextMenu/chunks/GrContextMenu-_FKwQvuQ.js";
83
+ import { t as GrContextMenu_default } from "./components/GrContextMenu/chunks/GrContextMenu-ClkVjdcP.js";
84
84
  import { t as grContextMenuConfig } from "./chunks/config-CPSxM7XE.js";
85
85
  import { t as GrTable_default } from "./components/GrTable/chunks/GrTable-Zcdz2St_.js";
86
86
  import { t as useDragSort } from "./chunks/useDragSort-0l47h4yb.js";
87
- import { t as GrDataTable_default } from "./components/GrDataTable/chunks/GrDataTable-C8a9_nCg.js";
87
+ import { t as GrDataTable_default } from "./components/GrDataTable/chunks/GrDataTable-CAGgRk27.js";
88
88
  import { n as grDataTableSafelist, t as grDataTableConfig } from "./chunks/config-DeyT9dJl.js";
89
89
  import { t as GrDelta_default } from "./components/GrDelta/chunks/GrDelta-BZwkgQW-.js";
90
90
  import { n as grValueSafelist, t as grValueConfig } from "./chunks/config-Z5LeUXys.js";
@@ -97,15 +97,15 @@ import { t as grDialogSafelist } from "./chunks/safelist-Y3zrlhOa.js";
97
97
  import "./components/GrDialog/index.js";
98
98
  import { n as useGrFormContext } from "./chunks/context-Bfrgsluh.js";
99
99
  import { t as GrFormField_default } from "./components/GrFormField/chunks/GrFormField-DSylU7IU.js";
100
- import { t as GrTextarea_default } from "./components/GrTextarea/chunks/GrTextarea-KREK75Bu.js";
100
+ import { t as GrTextarea_default } from "./components/GrTextarea/chunks/GrTextarea-DinXG12-.js";
101
101
  import { n as getByPath, o as runFieldRules, r as isEmpty, s as setByPath, t as createGrFormMessageResolver } from "./chunks/validation-5HhpanPP.js";
102
- import { t as GrPromptDialog_default } from "./components/GrPromptDialog/chunks/GrPromptDialog-DLcl1xiq.js";
103
- import { a as useDialogService, i as teardownDialogService, n as dialogService, r as granularityDialogServicePlugin, t as GrDialogServiceHost_default } from "./components/GrDialogService/chunks/GrDialogService-6s2cQ-_6.js";
102
+ import { t as GrPromptDialog_default } from "./components/GrPromptDialog/chunks/GrPromptDialog-C6QGC7QJ.js";
103
+ import { a as useDialogService, i as teardownDialogService, n as dialogService, r as granularityDialogServicePlugin, t as GrDialogServiceHost_default } from "./components/GrDialogService/chunks/GrDialogService-BxNK6crD.js";
104
104
  import { t as grDialogServiceConfig } from "./chunks/config-CjXjhphs.js";
105
105
  import { n as grDividerSafelist, t as grDividerConfig } from "./chunks/config-D82r782v.js";
106
106
  import { t as GrDivider_default } from "./components/GrDivider/chunks/GrDivider-BXavGcMX.js";
107
107
  import { n as grDrawerSafelist, t as grDrawerConfig } from "./chunks/config-ChPg-BQv.js";
108
- import { t as GrDrawer_default } from "./components/GrDrawer/chunks/GrDrawer-B7PiAcbU.js";
108
+ import { t as GrDrawer_default } from "./components/GrDrawer/chunks/GrDrawer-Ce2l3zaG.js";
109
109
  import { t as GrDropdown_default } from "./components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js";
110
110
  import { n as grDropdownSafelist, t as grDropdownConfig } from "./chunks/config-uzUuosv7.js";
111
111
  import "./components/GrDropdown/index.js";
@@ -122,36 +122,36 @@ import { t as GrForm_default } from "./components/GrForm/chunks/GrForm-CrnfCsgj.
122
122
  import { t as grFormConfig } from "./chunks/config-Droqn55j.js";
123
123
  import { n as grFormFieldSafelist, t as grFormFieldConfig } from "./chunks/config-B0uvcTPH.js";
124
124
  import "./components/GrFormField/index.js";
125
- import { t as GrFormFile_default } from "./components/GrFormFile/chunks/GrFormFile-CYtXU9HV.js";
125
+ import { t as GrFormFile_default } from "./components/GrFormFile/chunks/GrFormFile-B1jGZyIj.js";
126
126
  import { n as grFormFileSafelist, t as grFormFileConfig } from "./chunks/config-BcXX7S7B.js";
127
127
  import { n as grFormSectionSafelist, t as grFormSectionConfig } from "./chunks/config-BEO7brpO.js";
128
128
  import { t as GrFormSection_default } from "./components/GrFormSection/chunks/GrFormSection-ejieOg9H.js";
129
- import { t as GrImageViewer_default } from "./components/GrImageViewer/chunks/GrImageViewer-CyVN6Zpc.js";
129
+ import { t as GrImageViewer_default } from "./components/GrImageViewer/chunks/GrImageViewer-CG4vUBg_.js";
130
130
  import { n as grImageViewerSafelist, t as grImageViewerConfig } from "./chunks/config-BDSaD-5p.js";
131
131
  import { n as grInputSafelist, t as grInputConfig } from "./chunks/config-CIkdsWUk.js";
132
132
  import "./components/GrInput/index.js";
133
133
  import { n as grInputTagSafelist, t as grInputTagConfig } from "./chunks/config-BqT6PMzO.js";
134
134
  import { t as GrInputTag_default } from "./components/GrInputTag/chunks/GrInputTag-Cj4A9Xgs.js";
135
- import { t as GrTree_default } from "./components/GrTree/chunks/GrTree-DC89I4AP.js";
136
- import { t as GrJsonViewer_default } from "./components/GrJsonViewer/chunks/GrJsonViewer-Cy2bknHO.js";
135
+ import { t as GrTree_default } from "./components/GrTree/chunks/GrTree-Ci6CZfKR.js";
136
+ import { t as GrJsonViewer_default } from "./components/GrJsonViewer/chunks/GrJsonViewer-BCZ7lE2k.js";
137
137
  import { n as grJsonViewerSafelist, t as grJsonViewerConfig } from "./chunks/config-DpAYidyY2.js";
138
138
  import { n as grKbdSafelist, t as grKbdConfig } from "./chunks/config-BRESvs9g.js";
139
139
  import "./components/GrKbd/index.js";
140
140
  import { n as grLinkSafelist, t as grLinkConfig } from "./chunks/config-CQLNjc9X2.js";
141
141
  import "./components/GrLink/index.js";
142
142
  import { n as grListSafelist, t as grListConfig } from "./chunks/config-D0W8mGFD.js";
143
- import { n as GrList_default, t as GrListItem_default } from "./components/GrList/chunks/GrList-DmT4qzLO.js";
143
+ import { n as GrList_default, t as GrListItem_default } from "./components/GrList/chunks/GrList-B_CRJB4c.js";
144
144
  import { n as grLoadingSafelist, t as grLoadingConfig } from "./chunks/config-Bjn30smH.js";
145
145
  import "./components/GrLoading/index.js";
146
146
  import { n as grModalSafelist, t as grModalConfig } from "./chunks/config-mlheIMtV.js";
147
147
  import "./components/GrModal/index.js";
148
- import { t as GrNavbar_default } from "./components/GrNavbar/chunks/GrNavbar-C5EjMKaC.js";
148
+ import { t as GrNavbar_default } from "./components/GrNavbar/chunks/GrNavbar-_rtHKwTf.js";
149
149
  import { n as grNavbarSafelist, t as grNavbarConfig } from "./chunks/config-2ZHRsdOc.js";
150
150
  import { n as grNumberInputSafelist, t as grNumberInputConfig } from "./chunks/config-MmPym-Z72.js";
151
151
  import { t as GrNumberInput_default } from "./components/GrNumberInput/chunks/GrNumberInput-DQ59YICu.js";
152
- import { t as GrSelect_default } from "./components/GrSelect/chunks/GrSelect-BiUrSSxc.js";
152
+ import { t as GrSelect_default } from "./components/GrSelect/chunks/GrSelect-gCeRFgQo.js";
153
153
  import { n as grPaginationSafelist, t as grPaginationConfig } from "./chunks/config-CjKpUcmy.js";
154
- import { t as GrPagination_default } from "./components/GrPagination/chunks/GrPagination-Cw3R21dp.js";
154
+ import { t as GrPagination_default } from "./components/GrPagination/chunks/GrPagination-B_kAhoAV.js";
155
155
  import { n as grPopoverSafelist, t as grPopoverConfig } from "./chunks/config-BTwYMQaz2.js";
156
156
  import "./components/GrPopover/index.js";
157
157
  import { n as grProgressBarSafelist, r as GR_TONES, t as grProgressBarConfig } from "./chunks/config-DWL81-aM.js";
@@ -160,23 +160,23 @@ import { t as GrProgressCircle_default } from "./components/GrProgressCircle/chu
160
160
  import { n as grProgressCircleSafelist, t as grProgressCircleConfig } from "./chunks/config-CJzmDHfI.js";
161
161
  import { t as grPromptDialogConfig } from "./chunks/config-C0Ea9ePP.js";
162
162
  import "./components/GrPromptDialog/index.js";
163
- import { t as GrRadio_default } from "./components/GrRadio/chunks/GrRadio-C_rESc5g.js";
164
- import { n as grRadioSafelist, t as grRadioConfig } from "./chunks/config-jyr6AIZt2.js";
163
+ import { t as GrRadio_default } from "./components/GrRadio/chunks/GrRadio-Aq3v8XgG.js";
164
+ import { n as grRadioSafelist, t as grRadioConfig } from "./chunks/config-CuQmUkMw2.js";
165
165
  import "./components/GrRadio/index.js";
166
- import { t as GrRadioGroup_default } from "./components/GrRadioGroup/chunks/GrRadioGroup-CdQO4G-U.js";
166
+ import { t as GrRadioGroup_default } from "./components/GrRadioGroup/chunks/GrRadioGroup-y9LVdTWh.js";
167
167
  import { t as grRadioGroupConfig } from "./chunks/config-QaIc_gRa.js";
168
168
  import { n as grRatingSafelist, t as grRatingConfig } from "./chunks/config-DRbojEzO.js";
169
169
  import { t as GrRating_default } from "./components/GrRating/chunks/GrRating-IEiTOdnF.js";
170
- import { n as GrFormErrorBanner_default, r as GrUploadErrorBanner_default, t as useResponseError } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-C_skObtv.js";
170
+ import { n as GrFormErrorBanner_default, r as GrUploadErrorBanner_default, t as useResponseError } from "./components/GrResponseErrorBanner/chunks/GrResponseErrorBanner-CBVRpgIG.js";
171
171
  import { n as titleWhenTruncated, t as GrSegmented_default } from "./components/GrSegmented/chunks/GrSegmented-CB-VR-yL.js";
172
172
  import { n as grSegmentedSafelist, t as grSegmentedConfig } from "./chunks/config-rLkc9Zn2.js";
173
173
  import { n as grSelectSafelist, t as grSelectConfig } from "./chunks/config-DnF472Ox.js";
174
174
  import "./components/GrSelect/index.js";
175
175
  import { n as grSidebarSafelist, t as grSidebarConfig } from "./chunks/config-DNDgp9bB.js";
176
- import { n as GrSidebarItem_default, r as GrSidebar_default, t as GrSidebarGroup_default } from "./components/GrSidebar/chunks/GrSidebar-B8EQIlfW.js";
176
+ import { n as GrSidebarItem_default, r as GrSidebar_default, t as GrSidebarGroup_default } from "./components/GrSidebar/chunks/GrSidebar-alkwBUzL.js";
177
177
  import { t as grSkeletonConfig } from "./chunks/config-8Pcutu1j.js";
178
178
  import "./components/GrSkeleton/index.js";
179
- import { n as grSliderSafelist, t as grSliderConfig } from "./chunks/config-tiUtEn4Q.js";
179
+ import { n as grSliderSafelist, t as grSliderConfig } from "./chunks/config-E1cTyRVV.js";
180
180
  import "./components/GrSlider/index.js";
181
181
  import { n as grSortableListSafelist, t as grSortableListConfig } from "./chunks/config-CbEbLyDE.js";
182
182
  import { t as GrSortableList_default } from "./components/GrSortableList/chunks/GrSortableList-HyKX--rO.js";
@@ -187,7 +187,7 @@ import { n as grStatisticSafelist, t as grStatisticConfig } from "./chunks/confi
187
187
  import { n as grStepsSafelist, t as grStepsConfig } from "./chunks/config-CLjjjPZj.js";
188
188
  import { t as GrSteps_default } from "./components/GrSteps/chunks/GrSteps-C2jxpZoN.js";
189
189
  import { n as grSwitchSafelist, t as grSwitchConfig } from "./chunks/config-Yy67uWHY.js";
190
- import { t as GrSwitch_default } from "./components/GrSwitch/chunks/GrSwitch-g_OOSkh7.js";
190
+ import { t as GrSwitch_default } from "./components/GrSwitch/chunks/GrSwitch-7Oe5QfQZ.js";
191
191
  import { n as grTableSafelist, t as grTableConfig } from "./chunks/config-DCq4JySZ.js";
192
192
  import "./components/GrTable/index.js";
193
193
  import { n as GrTabPanels_default, t as GrTabPanel_default } from "./components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js";
@@ -200,12 +200,12 @@ import { n as GrTimeline_default, t as GrTimelineItem_default } from "./componen
200
200
  import { n as grTimelineSafelist, t as grTimelineConfig } from "./chunks/config-Bd7QfiGj.js";
201
201
  import { GRANULARITY_TOAST_STATE, granularityToastPlugin, useToast } from "./composables/useToast.js";
202
202
  import { n as grToasterSafelist, t as grToasterConfig } from "./chunks/config-B5SBUa6u.js";
203
- import { t as GrToaster_default } from "./components/GrToaster/chunks/GrToaster-Dp7-4B8k.js";
203
+ import { t as GrToaster_default } from "./components/GrToaster/chunks/GrToaster-COXIBKzq.js";
204
204
  import { n as grTooltipSafelist, t as grTooltipConfig } from "./chunks/config-BTmfQFwi.js";
205
205
  import { t as GrTooltip_default } from "./components/GrTooltip/chunks/GrTooltip-uYETdbCD.js";
206
206
  import { n as grTreeSafelist, t as grTreeConfig } from "./chunks/config-CDat1wXf.js";
207
207
  import { n as grTreeSelectSafelist, t as grTreeSelectConfig } from "./chunks/config-T3-DMXYm.js";
208
- import { t as GrTreeSelect_default } from "./components/GrTreeSelect/chunks/GrTreeSelect-iJnMl2t9.js";
208
+ import { t as GrTreeSelect_default } from "./components/GrTreeSelect/chunks/GrTreeSelect-BHwgGJcT.js";
209
209
  import "./composables/useGrComponentConfig.js";
210
210
  import "./composables/useGranularityTranslations.js";
211
211
  import { GRANULARITY_THEME_STATE, granularityThemePlugin, initThemeEarly, useTheme } from "./composables/useTheme.js";
package/dist/testing.js CHANGED
@@ -155,7 +155,7 @@ function resetGranularityDom() {
155
155
  function stubMatchMedia(options = {}) {
156
156
  const { reducedMotion = false, matches = false } = options;
157
157
  const original = window.matchMedia;
158
- window.matchMedia = ((query) => ({
158
+ window.matchMedia = (query) => ({
159
159
  media: query,
160
160
  matches: query.includes("prefers-reduced-motion") ? reducedMotion : matches,
161
161
  onchange: null,
@@ -164,7 +164,7 @@ function stubMatchMedia(options = {}) {
164
164
  addListener: () => {},
165
165
  removeListener: () => {},
166
166
  dispatchEvent: () => false
167
- }));
167
+ });
168
168
  return () => {
169
169
  window.matchMedia = original;
170
170
  };
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","names":[],"sources":["../src/testing/pointer.ts","../src/testing/keyboard.ts","../src/testing/geometry.ts","../src/testing/env.ts","../src/testing/context.ts","../src/testing/announcer.ts"],"sourcesContent":["/**\n * Указательные жесты в тестах.\n *\n * Две вещи, которые ломают наивную запись жеста, и обе неочевидны:\n *\n * 1. **`pointerdown` идёт в элемент, а `pointermove`/`pointerup`/`pointercancel` — в `window`.**\n * Так слушает `useDragGesture` (и всё, что на нём стоит: слайдер, сплиттер,\n * перестановка, смахивание тоста): нажатие приходит от разметки, а движение\n * ловится глобально, иначе жест обрывался бы на выходе курсора за элемент.\n * Тест, отправивший движение в тот же элемент, ничего не проверяет — и молча.\n * 2. **`PointerEvent` в jsdom нет**, а `wrapper.trigger('pointerdown', { clientY })`\n * падает на попытке записать `clientY`. Поэтому события собираются\n * `MouseEvent`-ом и отправляются через `dispatchEvent`.\n *\n * Плюс `button: 0` по умолчанию: жест игнорирует неосновную кнопку, и без этого\n * «перетаскивание» в тесте не начинается вовсе.\n */\n\n/** Событие указателя: `MouseEvent`, потому что `PointerEvent` в jsdom не реализован. */\nexport function pointer(type: string, init: MouseEventInit = {}): MouseEvent {\n return new MouseEvent(type, { bubbles: true, ...init })\n}\n\n/** Нажатие: единственное событие жеста, которое адресуется элементу. */\nexport function press(target: Element, init: MouseEventInit = {}): void {\n target.dispatchEvent(pointer('pointerdown', { button: 0, ...init }))\n}\n\nexport function move(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointermove', init))\n}\n\nexport function release(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointerup', init))\n}\n\n/**\n * Обрыв жеста: система забрала указатель (системный жест, звонок, потеря окна).\n * Отдельная ветка поведения у всех потребителей — смахивание возвращает тост,\n * перестановка откатывает порядок, — поэтому проверяется отдельно от `release`.\n */\nexport function cancelPointer(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointercancel', init))\n}\n\n/** Жест целиком: нажали на элементе, провели, отпустили. */\nexport function drag(target: Element, from: MouseEventInit, to: MouseEventInit): void {\n press(target, from)\n move(to)\n release(to)\n}\n","/**\n * Клавиатурные события в тестах.\n *\n * Существует ради одного флага: **`isComposing` не переживает\n * `wrapper.trigger('keydown', …)`**. `@vue/test-utils` собирает событие из\n * переданного объекта, но `isComposing` — свойство только для чтения на\n * `KeyboardEvent`, и присвоение молча теряется. Тест «Enter во время\n * IME-композиции ничего не коммитит» при такой записи проверяет обычный Enter,\n * то есть зеленеет на сломанном коде.\n *\n * Пакет читает флаг через `isComposingEvent` (`src/internal/keyboard.ts`) —\n * `event.isComposing || event.keyCode === 229`, потому что Safari до 16.4 не\n * ставил первое. Генератор ставит оба, иначе тест проверял бы половину предиката.\n *\n * Композиция — это не экзотика: пока пользователь набирает 日本語, 한국어 или\n * что угодно через IME, `Enter` подтверждает **выбор иероглифа**, а не действие\n * виджета. Компонент, который на нём выберет опцию или отправит форму, у такого\n * пользователя неработоспособен.\n */\n\nexport type KeyboardEventOptions = KeyboardEventInit & { key: string }\n\n/** Клавиатурное событие с разумными умолчаниями (всплывает, отменяемо). */\nexport function keyboardEvent(type: string, init: KeyboardEventOptions): KeyboardEvent {\n return new KeyboardEvent(type, { bubbles: true, cancelable: true, ...init })\n}\n\n/** Нажатие клавиши в элемент. */\nexport function keydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n const event = keyboardEvent('keydown', { key, ...init })\n target.dispatchEvent(event)\n return event\n}\n\n/**\n * Нажатие во время IME-композиции. Отдельная функция, а не флаг у `keydown`:\n * из имени в тесте видно, что проверяется, а `keyCode: 229` не приходится\n * помнить на каждом вызове.\n */\nexport function composingKeydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n return keydown(target, key, { isComposing: true, keyCode: 229, ...init })\n}\n","/**\n * Геометрия в jsdom.\n *\n * Раскладки в jsdom нет: `getBoundingClientRect` у любого элемента возвращает\n * нули. Всё, что считает попадание указателя — слайдер, сплиттер, перестановка,\n * ширины колонок таблицы, — на нулевом прямоугольнике проверять не на чем,\n * поэтому геометрия задаётся руками.\n */\n\nexport type MockRect = Partial<Omit<DOMRect, 'toJSON'>>\n\n/** Прямоугольник элемента. Незаданные стороны выводятся из заданных. */\nexport function mockRect(target: Element, rect: MockRect): void {\n const left = rect.left ?? rect.x ?? 0\n const top = rect.top ?? rect.y ?? 0\n const width = rect.width ?? (rect.right ?? 0) - left\n const height = rect.height ?? (rect.bottom ?? 0) - top\n\n const value: DOMRect = {\n x: left,\n y: top,\n left,\n top,\n width,\n height,\n right: rect.right ?? left + width,\n bottom: rect.bottom ?? top + height,\n toJSON: () => ({}),\n }\n\n target.getBoundingClientRect = () => value\n}\n\nexport interface StackRectsOptions {\n /** Размер элемента вдоль оси. */\n size: number\n /** Ось раскладки. По умолчанию вертикальная — так лежат списки и строки. */\n axis?: 'vertical' | 'horizontal'\n /** Смещение первого элемента. */\n start?: number\n /** Размер поперёк оси. */\n cross?: number\n}\n\n/** Элементы подряд, встык, без зазоров: строки списка, ячейки шапки, деления шкалы. */\nexport function stackRects(targets: Iterable<Element>, options: StackRectsOptions): void {\n const { size, axis = 'vertical', start = 0, cross = 100 } = options\n\n let offset = start\n\n for (const target of targets) {\n mockRect(target, axis === 'vertical'\n ? { top: offset, height: size, left: 0, width: cross }\n : { left: offset, width: size, top: 0, height: cross })\n\n offset += size\n }\n}\n","import { resetAnnouncer } from '../composables/useAnnouncer'\nimport { resetPortalRoot } from '../composables/internal/portalRoot'\nimport { useToast } from '../composables/useToast'\n\n/**\n * Уборка между тестами.\n *\n * `document.body.innerHTML = ''` сам по себе оставляет пакет в разобранном\n * состоянии: корень портала и хост живого региона закэшированы модулями, и\n * после очистки `body` они указывают на узлы **вне документа**. Следующий\n * монтаж телепортирует туда оверлеи, тест ищет их в документе и не находит —\n * без единой ошибки в консоли. Очередь тостов переживает размонтирование по\n * замыслу, поэтому её тоже гасим.\n */\nexport function resetGranularityDom(): void {\n useToast().clear()\n resetAnnouncer()\n resetPortalRoot()\n\n if (typeof document !== 'undefined')\n document.body.innerHTML = ''\n}\n\nexport interface StubMatchMediaOptions {\n /** Ответ на `(prefers-reduced-motion: reduce)`. */\n reducedMotion?: boolean\n /** Ответ на остальные запросы. */\n matches?: boolean\n}\n\n/**\n * Ответ `matchMedia` — например «пользователь просил меньше движения».\n *\n * Не для того, чтобы «не падало»: сам пакет зовёт `matchMedia` опционально и без\n * него живёт. Нужно, когда проверяется поведение **под** медиазапросом.\n * Возвращает функцию отката: глобальное состояние обязано уйти вместе с тестом.\n */\nexport function stubMatchMedia(options: StubMatchMediaOptions = {}): () => void {\n const { reducedMotion = false, matches = false } = options\n const original = window.matchMedia\n\n window.matchMedia = ((query: string) => ({\n media: query,\n matches: query.includes('prefers-reduced-motion') ? reducedMotion : matches,\n onchange: null,\n addEventListener: () => {},\n removeEventListener: () => {},\n addListener: () => {},\n removeListener: () => {},\n dispatchEvent: () => false,\n }))\n\n return () => {\n window.matchMedia = original\n }\n}\n","import { computed, ref, type Ref } from 'vue'\n\nimport { GR_CONFIG_KEY, type GrComponentDefaults, type GrComponentSize, type GrConfigContext } from '../components/GrConfigProvider/context'\nimport { GRANULARITY_I18N_KEY, type GranularityI18nAdapter, type GranularityI18nParams } from '../i18n/adapter'\n\nexport interface I18nAdapterOptions {\n /** Перевод по ключу. По умолчанию — сам ключ: видно, что спросили. */\n t?: (key: string, params?: GranularityI18nParams) => string\n te?: (key: string) => boolean\n locale?: string | Ref<string>\n}\n\n/** Адаптер перевода для теста: словарь или своя функция. */\nexport function i18nAdapter(options: I18nAdapterOptions | Record<string, string> = {}): GranularityI18nAdapter {\n const isDictionary = typeof (options as I18nAdapterOptions).t !== 'function'\n && !('locale' in options)\n && !('te' in options)\n\n if (isDictionary) {\n const dictionary = options as Record<string, string>\n\n return {\n t: key => dictionary[key] ?? key,\n te: key => key in dictionary,\n }\n }\n\n const { t, te, locale } = options as I18nAdapterOptions\n\n return {\n t: t ?? (key => key),\n te,\n locale: typeof locale === 'string' ? ref(locale) : locale,\n }\n}\n\nexport interface GranularityGlobalOptions {\n size?: GrComponentSize\n componentDefaults?: GrComponentDefaults\n theme?: string\n portalTarget?: string | HTMLElement\n /** Адаптер перевода: готовый, словарь `{ ключ: перевод }` или опции `i18nAdapter`. */\n i18n?: GranularityI18nAdapter | I18nAdapterOptions | Record<string, string>\n}\n\n/**\n * Окружение пакета для монтирования — то, что `<GrConfigProvider>` раздаёт\n * через `provide`.\n *\n * Отдаётся объектом, а не компонентом-обёрткой, намеренно: провайдер тянет за\n * собой лишний корневой элемент, а искать компонент внутри чужой разметки в\n * каждом тесте дороже, чем передать `global`. Проверять **сам** провайдер\n * (`data-gr-config-provider`, тема на корне) этим нельзя и не нужно — для этого\n * его и монтируют.\n *\n * ```ts\n * mount(GrSelect, { props, global: granularityGlobal({ size: 'sm' }) })\n * ```\n */\nexport function granularityGlobal(options: GranularityGlobalOptions = {}): { provide: Record<symbol, unknown> } {\n const config: GrConfigContext = {\n size: computed(() => options.size),\n componentDefaults: computed(() => options.componentDefaults ?? {}),\n theme: computed(() => options.theme),\n portalTarget: computed(() => options.portalTarget),\n }\n\n const provide: Record<symbol, unknown> = { [GR_CONFIG_KEY]: config }\n\n if (options.i18n)\n provide[GRANULARITY_I18N_KEY] = 't' in options.i18n && typeof options.i18n.t === 'function'\n ? options.i18n\n : i18nAdapter(options.i18n)\n\n return { provide }\n}\n","import type { GrAnnouncerPoliteness } from '../composables/useAnnouncer'\n\n/**\n * Текст живого региона.\n *\n * Ждать здесь обязательно: `announce` пишет в регион **отложенным** макротаском,\n * и это не деталь реализации, а условие работы. Регион, в котором текст\n * появился в том же кадре, что и сам регион, часть AT не объявляет вовсе;\n * поэтому синхронное чтение сразу после действия покажет пустую строку.\n */\nexport async function announced(politeness: GrAnnouncerPoliteness = 'polite'): Promise<string> {\n await new Promise(resolve => setTimeout(resolve, 2))\n\n return document.querySelector(`[data-gr-announcer-region=\"${politeness}\"]`)?.textContent ?? ''\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,QAAQ,MAAc,OAAuB,CAAC,GAAe;CAC3E,OAAO,IAAI,WAAW,MAAM;EAAE,SAAS;EAAM,GAAG;CAAK,CAAC;AACxD;;AAGA,SAAgB,MAAM,QAAiB,OAAuB,CAAC,GAAS;CACtE,OAAO,cAAc,QAAQ,eAAe;EAAE,QAAQ;EAAG,GAAG;CAAK,CAAC,CAAC;AACrE;AAEA,SAAgB,KAAK,OAAuB,CAAC,GAAS;CACpD,OAAO,cAAc,QAAQ,eAAe,IAAI,CAAC;AACnD;AAEA,SAAgB,QAAQ,OAAuB,CAAC,GAAS;CACvD,OAAO,cAAc,QAAQ,aAAa,IAAI,CAAC;AACjD;;;;;;AAOA,SAAgB,cAAc,OAAuB,CAAC,GAAS;CAC7D,OAAO,cAAc,QAAQ,iBAAiB,IAAI,CAAC;AACrD;;AAGA,SAAgB,KAAK,QAAiB,MAAsB,IAA0B;CACpF,MAAM,QAAQ,IAAI;CAClB,KAAK,EAAE;CACP,QAAQ,EAAE;AACZ;;;;AC3BA,SAAgB,cAAc,MAAc,MAA2C;CACrF,OAAO,IAAI,cAAc,MAAM;EAAE,SAAS;EAAM,YAAY;EAAM,GAAG;CAAK,CAAC;AAC7E;;AAGA,SAAgB,QAAQ,QAAiB,KAAa,OAA0B,CAAC,GAAkB;CACjG,MAAM,QAAQ,cAAc,WAAW;EAAE;EAAK,GAAG;CAAK,CAAC;CACvD,OAAO,cAAc,KAAK;CAC1B,OAAO;AACT;;;;;;AAOA,SAAgB,iBAAiB,QAAiB,KAAa,OAA0B,CAAC,GAAkB;CAC1G,OAAO,QAAQ,QAAQ,KAAK;EAAE,aAAa;EAAM,SAAS;EAAK,GAAG;CAAK,CAAC;AAC1E;;;;AC7BA,SAAgB,SAAS,QAAiB,MAAsB;CAC9D,MAAM,OAAO,KAAK,QAAQ,KAAK,KAAK;CACpC,MAAM,MAAM,KAAK,OAAO,KAAK,KAAK;CAClC,MAAM,QAAQ,KAAK,UAAU,KAAK,SAAS,KAAK;CAChD,MAAM,SAAS,KAAK,WAAW,KAAK,UAAU,KAAK;CAEnD,MAAM,QAAiB;EACrB,GAAG;EACH,GAAG;EACH;EACA;EACA;EACA;EACA,OAAO,KAAK,SAAS,OAAO;EAC5B,QAAQ,KAAK,UAAU,MAAM;EAC7B,eAAe,CAAC;CAClB;CAEA,OAAO,8BAA8B;AACvC;;AAcA,SAAgB,WAAW,SAA4B,SAAkC;CACvF,MAAM,EAAE,MAAM,OAAO,YAAY,QAAQ,GAAG,QAAQ,QAAQ;CAE5D,IAAI,SAAS;CAEb,KAAK,MAAM,UAAU,SAAS;EAC5B,SAAS,QAAQ,SAAS,aACtB;GAAE,KAAK;GAAQ,QAAQ;GAAM,MAAM;GAAG,OAAO;EAAM,IACnD;GAAE,MAAM;GAAQ,OAAO;GAAM,KAAK;GAAG,QAAQ;EAAM,CAAC;EAExD,UAAU;CACZ;AACF;;;;;;;;;;;;;AC3CA,SAAgB,sBAA4B;CAC1C,SAAS,CAAC,CAAC,MAAM;CACjB,eAAe;CACf,gBAAgB;CAEhB,IAAI,OAAO,aAAa,aACtB,SAAS,KAAK,YAAY;AAC9B;;;;;;;;AAgBA,SAAgB,eAAe,UAAiC,CAAC,GAAe;CAC9E,MAAM,EAAE,gBAAgB,OAAO,UAAU,UAAU;CACnD,MAAM,WAAW,OAAO;CAExB,OAAO,eAAe,WAAmB;EACvC,OAAO;EACP,SAAS,MAAM,SAAS,wBAAwB,IAAI,gBAAgB;EACpE,UAAU;EACV,wBAAwB,CAAC;EACzB,2BAA2B,CAAC;EAC5B,mBAAmB,CAAC;EACpB,sBAAsB,CAAC;EACvB,qBAAqB;CACvB;CAEA,aAAa;EACX,OAAO,aAAa;CACtB;AACF;;;;AC1CA,SAAgB,YAAY,UAAuD,CAAC,GAA2B;CAK7G,IAJqB,OAAQ,QAA+B,MAAM,cAC7D,EAAE,YAAY,YACd,EAAE,QAAQ,UAEG;EAChB,MAAM,aAAa;EAEnB,OAAO;GACL,IAAG,QAAO,WAAW,QAAQ;GAC7B,KAAI,QAAO,OAAO;EACpB;CACF;CAEA,MAAM,EAAE,GAAG,IAAI,WAAW;CAE1B,OAAO;EACL,GAAG,OAAM,QAAO;EAChB;EACA,QAAQ,OAAO,WAAW,WAAW,IAAI,MAAM,IAAI;CACrD;AACF;;;;;;;;;;;;;;;AAyBA,SAAgB,kBAAkB,UAAoC,CAAC,GAAyC;CAC9G,MAAM,SAA0B;EAC9B,MAAM,eAAe,QAAQ,IAAI;EACjC,mBAAmB,eAAe,QAAQ,qBAAqB,CAAC,CAAC;EACjE,OAAO,eAAe,QAAQ,KAAK;EACnC,cAAc,eAAe,QAAQ,YAAY;CACnD;CAEA,MAAM,UAAmC,GAAG,gBAAgB,OAAO;CAEnE,IAAI,QAAQ,MACV,QAAQ,wBAAwB,OAAO,QAAQ,QAAQ,OAAO,QAAQ,KAAK,MAAM,aAC7E,QAAQ,OACR,YAAY,QAAQ,IAAI;CAE9B,OAAO,EAAE,QAAQ;AACnB;;;;;;;;;;;ACjEA,eAAsB,UAAU,aAAoC,UAA2B;CAC7F,MAAM,IAAI,SAAQ,YAAW,WAAW,SAAS,CAAC,CAAC;CAEnD,OAAO,SAAS,cAAc,8BAA8B,WAAW,GAAG,CAAC,EAAE,eAAe;AAC9F"}
1
+ {"version":3,"file":"testing.js","names":[],"sources":["../src/testing/pointer.ts","../src/testing/keyboard.ts","../src/testing/geometry.ts","../src/testing/env.ts","../src/testing/context.ts","../src/testing/announcer.ts"],"sourcesContent":["/**\n * Указательные жесты в тестах.\n *\n * Две вещи, которые ломают наивную запись жеста, и обе неочевидны:\n *\n * 1. **`pointerdown` идёт в элемент, а `pointermove`/`pointerup`/`pointercancel` — в `window`.**\n * Так слушает `useDragGesture` (и всё, что на нём стоит: слайдер, сплиттер,\n * перестановка, смахивание тоста): нажатие приходит от разметки, а движение\n * ловится глобально, иначе жест обрывался бы на выходе курсора за элемент.\n * Тест, отправивший движение в тот же элемент, ничего не проверяет — и молча.\n * 2. **`PointerEvent` в jsdom нет**, а `wrapper.trigger('pointerdown', { clientY })`\n * падает на попытке записать `clientY`. Поэтому события собираются\n * `MouseEvent`-ом и отправляются через `dispatchEvent`.\n *\n * Плюс `button: 0` по умолчанию: жест игнорирует неосновную кнопку, и без этого\n * «перетаскивание» в тесте не начинается вовсе.\n */\n\n/** Событие указателя: `MouseEvent`, потому что `PointerEvent` в jsdom не реализован. */\nexport function pointer(type: string, init: MouseEventInit = {}): MouseEvent {\n return new MouseEvent(type, { bubbles: true, ...init })\n}\n\n/** Нажатие: единственное событие жеста, которое адресуется элементу. */\nexport function press(target: Element, init: MouseEventInit = {}): void {\n target.dispatchEvent(pointer('pointerdown', { button: 0, ...init }))\n}\n\nexport function move(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointermove', init))\n}\n\nexport function release(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointerup', init))\n}\n\n/**\n * Обрыв жеста: система забрала указатель (системный жест, звонок, потеря окна).\n * Отдельная ветка поведения у всех потребителей — смахивание возвращает тост,\n * перестановка откатывает порядок, — поэтому проверяется отдельно от `release`.\n */\nexport function cancelPointer(init: MouseEventInit = {}): void {\n window.dispatchEvent(pointer('pointercancel', init))\n}\n\n/** Жест целиком: нажали на элементе, провели, отпустили. */\nexport function drag(target: Element, from: MouseEventInit, to: MouseEventInit): void {\n press(target, from)\n move(to)\n release(to)\n}\n","/**\n * Клавиатурные события в тестах.\n *\n * Существует ради одного флага: **`isComposing` не переживает\n * `wrapper.trigger('keydown', …)`**. `@vue/test-utils` собирает событие из\n * переданного объекта, но `isComposing` — свойство только для чтения на\n * `KeyboardEvent`, и присвоение молча теряется. Тест «Enter во время\n * IME-композиции ничего не коммитит» при такой записи проверяет обычный Enter,\n * то есть зеленеет на сломанном коде.\n *\n * Пакет читает флаг через `isComposingEvent` (`src/internal/keyboard.ts`) —\n * `event.isComposing || event.keyCode === 229`, потому что Safari до 16.4 не\n * ставил первое. Генератор ставит оба, иначе тест проверял бы половину предиката.\n *\n * Композиция — это не экзотика: пока пользователь набирает 日本語, 한국어 или\n * что угодно через IME, `Enter` подтверждает **выбор иероглифа**, а не действие\n * виджета. Компонент, который на нём выберет опцию или отправит форму, у такого\n * пользователя неработоспособен.\n */\n\nexport type KeyboardEventOptions = KeyboardEventInit & { key: string }\n\n/** Клавиатурное событие с разумными умолчаниями (всплывает, отменяемо). */\nexport function keyboardEvent(type: string, init: KeyboardEventOptions): KeyboardEvent {\n return new KeyboardEvent(type, { bubbles: true, cancelable: true, ...init })\n}\n\n/** Нажатие клавиши в элемент. */\nexport function keydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n const event = keyboardEvent('keydown', { key, ...init })\n target.dispatchEvent(event)\n return event\n}\n\n/**\n * Нажатие во время IME-композиции. Отдельная функция, а не флаг у `keydown`:\n * из имени в тесте видно, что проверяется, а `keyCode: 229` не приходится\n * помнить на каждом вызове.\n */\nexport function composingKeydown(target: Element, key: string, init: KeyboardEventInit = {}): KeyboardEvent {\n return keydown(target, key, { isComposing: true, keyCode: 229, ...init })\n}\n","/**\n * Геометрия в jsdom.\n *\n * Раскладки в jsdom нет: `getBoundingClientRect` у любого элемента возвращает\n * нули. Всё, что считает попадание указателя — слайдер, сплиттер, перестановка,\n * ширины колонок таблицы, — на нулевом прямоугольнике проверять не на чем,\n * поэтому геометрия задаётся руками.\n */\n\nexport type MockRect = Partial<Omit<DOMRect, 'toJSON'>>\n\n/** Прямоугольник элемента. Незаданные стороны выводятся из заданных. */\nexport function mockRect(target: Element, rect: MockRect): void {\n const left = rect.left ?? rect.x ?? 0\n const top = rect.top ?? rect.y ?? 0\n const width = rect.width ?? (rect.right ?? 0) - left\n const height = rect.height ?? (rect.bottom ?? 0) - top\n\n const value: DOMRect = {\n x: left,\n y: top,\n left,\n top,\n width,\n height,\n right: rect.right ?? left + width,\n bottom: rect.bottom ?? top + height,\n toJSON: () => ({}),\n }\n\n target.getBoundingClientRect = () => value\n}\n\nexport interface StackRectsOptions {\n /** Размер элемента вдоль оси. */\n size: number\n /** Ось раскладки. По умолчанию вертикальная — так лежат списки и строки. */\n axis?: 'vertical' | 'horizontal'\n /** Смещение первого элемента. */\n start?: number\n /** Размер поперёк оси. */\n cross?: number\n}\n\n/** Элементы подряд, встык, без зазоров: строки списка, ячейки шапки, деления шкалы. */\nexport function stackRects(targets: Iterable<Element>, options: StackRectsOptions): void {\n const { size, axis = 'vertical', start = 0, cross = 100 } = options\n\n let offset = start\n\n for (const target of targets) {\n mockRect(target, axis === 'vertical'\n ? { top: offset, height: size, left: 0, width: cross }\n : { left: offset, width: size, top: 0, height: cross })\n\n offset += size\n }\n}\n","import { resetAnnouncer } from '../composables/useAnnouncer'\nimport { resetPortalRoot } from '../composables/internal/portalRoot'\nimport { useToast } from '../composables/useToast'\n\n/**\n * Уборка между тестами.\n *\n * `document.body.innerHTML = ''` сам по себе оставляет пакет в разобранном\n * состоянии: корень портала и хост живого региона закэшированы модулями, и\n * после очистки `body` они указывают на узлы **вне документа**. Следующий\n * монтаж телепортирует туда оверлеи, тест ищет их в документе и не находит —\n * без единой ошибки в консоли. Очередь тостов переживает размонтирование по\n * замыслу, поэтому её тоже гасим.\n */\nexport function resetGranularityDom(): void {\n useToast().clear()\n resetAnnouncer()\n resetPortalRoot()\n\n if (typeof document !== 'undefined')\n document.body.innerHTML = ''\n}\n\nexport interface StubMatchMediaOptions {\n /** Ответ на `(prefers-reduced-motion: reduce)`. */\n reducedMotion?: boolean\n /** Ответ на остальные запросы. */\n matches?: boolean\n}\n\n/**\n * Ответ `matchMedia` — например «пользователь просил меньше движения».\n *\n * Не для того, чтобы «не падало»: сам пакет зовёт `matchMedia` опционально и без\n * него живёт. Нужно, когда проверяется поведение **под** медиазапросом.\n * Возвращает функцию отката: глобальное состояние обязано уйти вместе с тестом.\n */\nexport function stubMatchMedia(options: StubMatchMediaOptions = {}): () => void {\n const { reducedMotion = false, matches = false } = options\n const original = window.matchMedia\n\n window.matchMedia = (query: string) => ({\n media: query,\n matches: query.includes('prefers-reduced-motion') ? reducedMotion : matches,\n onchange: null,\n addEventListener: () => {},\n removeEventListener: () => {},\n addListener: () => {},\n removeListener: () => {},\n dispatchEvent: () => false,\n })\n\n return () => {\n window.matchMedia = original\n }\n}\n","import { computed, ref, type Ref } from 'vue'\n\nimport { GR_CONFIG_KEY, type GrComponentDefaults, type GrComponentSize, type GrConfigContext } from '../components/GrConfigProvider/context'\nimport { GRANULARITY_I18N_KEY, type GranularityI18nAdapter, type GranularityI18nParams } from '../i18n/adapter'\n\nexport interface I18nAdapterOptions {\n /** Перевод по ключу. По умолчанию — сам ключ: видно, что спросили. */\n t?: (key: string, params?: GranularityI18nParams) => string\n te?: (key: string) => boolean\n locale?: string | Ref<string>\n}\n\n/** Адаптер перевода для теста: словарь или своя функция. */\nexport function i18nAdapter(options: I18nAdapterOptions | Record<string, string> = {}): GranularityI18nAdapter {\n const isDictionary = typeof (options as I18nAdapterOptions).t !== 'function'\n && !('locale' in options)\n && !('te' in options)\n\n if (isDictionary) {\n const dictionary = options as Record<string, string>\n\n return {\n t: key => dictionary[key] ?? key,\n te: key => key in dictionary,\n }\n }\n\n const { t, te, locale } = options as I18nAdapterOptions\n\n return {\n t: t ?? (key => key),\n te,\n locale: typeof locale === 'string' ? ref(locale) : locale,\n }\n}\n\nexport interface GranularityGlobalOptions {\n size?: GrComponentSize\n componentDefaults?: GrComponentDefaults\n theme?: string\n portalTarget?: string | HTMLElement\n /** Адаптер перевода: готовый, словарь `{ ключ: перевод }` или опции `i18nAdapter`. */\n i18n?: GranularityI18nAdapter | I18nAdapterOptions | Record<string, string>\n}\n\n/**\n * Окружение пакета для монтирования — то, что `<GrConfigProvider>` раздаёт\n * через `provide`.\n *\n * Отдаётся объектом, а не компонентом-обёрткой, намеренно: провайдер тянет за\n * собой лишний корневой элемент, а искать компонент внутри чужой разметки в\n * каждом тесте дороже, чем передать `global`. Проверять **сам** провайдер\n * (`data-gr-config-provider`, тема на корне) этим нельзя и не нужно — для этого\n * его и монтируют.\n *\n * ```ts\n * mount(GrSelect, { props, global: granularityGlobal({ size: 'sm' }) })\n * ```\n */\nexport function granularityGlobal(options: GranularityGlobalOptions = {}): { provide: Record<symbol, unknown> } {\n const config: GrConfigContext = {\n size: computed(() => options.size),\n componentDefaults: computed(() => options.componentDefaults ?? {}),\n theme: computed(() => options.theme),\n portalTarget: computed(() => options.portalTarget),\n }\n\n const provide: Record<symbol, unknown> = { [GR_CONFIG_KEY]: config }\n\n if (options.i18n) {\n provide[GRANULARITY_I18N_KEY] = 't' in options.i18n && typeof options.i18n.t === 'function'\n ? options.i18n\n : i18nAdapter(options.i18n)\n }\n\n return { provide }\n}\n","import type { GrAnnouncerPoliteness } from '../composables/useAnnouncer'\n\n/**\n * Текст живого региона.\n *\n * Ждать здесь обязательно: `announce` пишет в регион **отложенным** макротаском,\n * и это не деталь реализации, а условие работы. Регион, в котором текст\n * появился в том же кадре, что и сам регион, часть AT не объявляет вовсе;\n * поэтому синхронное чтение сразу после действия покажет пустую строку.\n */\nexport async function announced(politeness: GrAnnouncerPoliteness = 'polite'): Promise<string> {\n await new Promise(resolve => setTimeout(resolve, 2))\n\n return document.querySelector(`[data-gr-announcer-region=\"${politeness}\"]`)?.textContent ?? ''\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"theme-apply.js","names":[],"sources":["../src/theme/apply.ts"],"sourcesContent":["/**\n * Подключение темы в рантайме — `@feugene/granularity/theme/apply`.\n *\n * Отдельный подпуть от `@feugene/granularity/theme` не по вкусу, а по весу:\n * там справочник токенов (сотня килобайт данных), нужный, чтобы тему\n * **собрать**. Чтобы её **подключить**, не нужно ничего, кроме готовой строки,\n * — и приложению незачем платить за первое, если оно делает второе.\n *\n * Штатный путь всё же другой: собрать тему на сборке и отдать браузеру обычный\n * CSS-файл. Этот модуль — для случаев, когда тема появляется только в браузере:\n * редактор тем, превью, тема из пользовательских настроек.\n */\n\nconst ATTRIBUTE = 'data-gr-theme'\n\nexport interface ApplyThemeOptions {\n /**\n * Имя, под которым тема живёт в документе. Повторный вызов с тем же именем\n * заменяет её содержимое, а не добавляет второй `<style>`: иначе редактор\n * темы за минуту работы оставил бы в `<head>` сотню слоёв, и побеждал бы\n * последний — то есть результат зависел бы от истории правок.\n */\n name?: string\n /** Куда вставлять. По умолчанию `document.head`. */\n target?: HTMLElement | null\n}\n\n/** Подключает CSS темы и возвращает функцию, которая его снимает. */\nexport function applyTheme(css: string, options: ApplyThemeOptions = {}): () => void {\n const { name = 'custom', target } = options\n\n if (typeof document === 'undefined')\n return () => {}\n\n const host = target ?? document.head\n const existing = host.querySelector<HTMLStyleElement>(`style[${ATTRIBUTE}=\"${name}\"]`)\n const style = existing ?? document.createElement('style')\n\n style.setAttribute(ATTRIBUTE, name)\n style.textContent = css\n\n if (!existing) host.append(style)\n\n return () => style.remove()\n}\n\n/** Снимает тему, подключённую `applyTheme`. */\nexport function removeTheme(name = 'custom', target?: HTMLElement | null): void {\n if (typeof document === 'undefined') return\n\n const host = target ?? document.head\n host.querySelector(`style[${ATTRIBUTE}=\"${name}\"]`)?.remove()\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAM,YAAY;;AAelB,SAAgB,WAAW,KAAa,UAA6B,CAAC,GAAe;CACnF,MAAM,EAAE,OAAO,UAAU,WAAW;CAEpC,IAAI,OAAO,aAAa,aACtB,aAAa,CAAC;CAEhB,MAAM,OAAO,UAAU,SAAS;CAChC,MAAM,WAAW,KAAK,cAAgC,SAAS,UAAU,IAAI,KAAK,GAAG;CACrF,MAAM,QAAQ,YAAY,SAAS,cAAc,OAAO;CAExD,MAAM,aAAa,WAAW,IAAI;CAClC,MAAM,cAAc;CAEpB,IAAI,CAAC,UAAU,KAAK,OAAO,KAAK;CAEhC,aAAa,MAAM,OAAO;AAC5B;;AAGA,SAAgB,YAAY,OAAO,UAAU,QAAmC;CAC9E,IAAI,OAAO,aAAa,aAAa;CAGrC,CADa,UAAU,SAAS,KAAA,CAC3B,cAAc,SAAS,UAAU,IAAI,KAAK,GAAG,CAAC,EAAE,OAAO;AAC9D"}
1
+ {"version":3,"file":"theme-apply.js","names":[],"sources":["../src/theme/apply.ts"],"sourcesContent":["/**\n * Подключение темы в рантайме — `@feugene/granularity/theme/apply`.\n *\n * Отдельный подпуть от `@feugene/granularity/theme` не по вкусу, а по весу:\n * там справочник токенов (сотня килобайт данных), нужный, чтобы тему\n * **собрать**. Чтобы её **подключить**, не нужно ничего, кроме готовой строки,\n * — и приложению незачем платить за первое, если оно делает второе.\n *\n * Штатный путь всё же другой: собрать тему на сборке и отдать браузеру обычный\n * CSS-файл. Этот модуль — для случаев, когда тема появляется только в браузере:\n * редактор тем, превью, тема из пользовательских настроек.\n */\n\nconst ATTRIBUTE = 'data-gr-theme'\n\nexport interface ApplyThemeOptions {\n /**\n * Имя, под которым тема живёт в документе. Повторный вызов с тем же именем\n * заменяет её содержимое, а не добавляет второй `<style>`: иначе редактор\n * темы за минуту работы оставил бы в `<head>` сотню слоёв, и побеждал бы\n * последний — то есть результат зависел бы от истории правок.\n */\n name?: string\n /** Куда вставлять. По умолчанию `document.head`. */\n target?: HTMLElement | null\n}\n\n/** Подключает CSS темы и возвращает функцию, которая его снимает. */\nexport function applyTheme(css: string, options: ApplyThemeOptions = {}): () => void {\n const { name = 'custom', target } = options\n\n if (typeof document === 'undefined')\n return () => {}\n\n const host = target ?? document.head\n const existing = host.querySelector<HTMLStyleElement>(`style[${ATTRIBUTE}=\"${name}\"]`)\n const style = existing ?? document.createElement('style')\n\n style.setAttribute(ATTRIBUTE, name)\n style.textContent = css\n\n if (!existing)\n host.append(style)\n\n return () => style.remove()\n}\n\n/** Снимает тему, подключённую `applyTheme`. */\nexport function removeTheme(name = 'custom', target?: HTMLElement | null): void {\n if (typeof document === 'undefined')\n return\n\n const host = target ?? document.head\n host.querySelector(`style[${ATTRIBUTE}=\"${name}\"]`)?.remove()\n}\n"],"mappings":";;;;;;;;;;;;;AAaA,IAAM,YAAY;;AAelB,SAAgB,WAAW,KAAa,UAA6B,CAAC,GAAe;CACnF,MAAM,EAAE,OAAO,UAAU,WAAW;CAEpC,IAAI,OAAO,aAAa,aACtB,aAAa,CAAC;CAEhB,MAAM,OAAO,UAAU,SAAS;CAChC,MAAM,WAAW,KAAK,cAAgC,SAAS,UAAU,IAAI,KAAK,GAAG;CACrF,MAAM,QAAQ,YAAY,SAAS,cAAc,OAAO;CAExD,MAAM,aAAa,WAAW,IAAI;CAClC,MAAM,cAAc;CAEpB,IAAI,CAAC,UACH,KAAK,OAAO,KAAK;CAEnB,aAAa,MAAM,OAAO;AAC5B;;AAGA,SAAgB,YAAY,OAAO,UAAU,QAAmC;CAC9E,IAAI,OAAO,aAAa,aACtB;CAGF,CADa,UAAU,SAAS,KAAA,CAC3B,cAAc,SAAS,UAAU,IAAI,KAAK,GAAG,CAAC,EAAE,OAAO;AAC9D"}
package/dist/theme.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as grThemeTokens, n as grDerivedTokens, t as grComponentTokens } from "./chunks/generated-DJ2dJ__C.js";
1
+ import { a as grThemeTokens, n as grDerivedTokens, t as grComponentTokens } from "./chunks/generated-CSyPsWtM.js";
2
2
  //#region src/theme/color.ts
3
3
  function parseHex(value) {
4
4
  const match = value.trim().match(/^#([\da-f]{3}|[\da-f]{6})$/i);