@feugene/granularity 0.26.0 → 0.27.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 (578) hide show
  1. package/dist/chunks/classTokens-8v2XC74x.js +16 -0
  2. package/dist/chunks/classTokens-8v2XC74x.js.map +1 -0
  3. package/dist/chunks/{config-Bpt9Xbxm.js → config-2ZHRsdOc.js} +2 -2
  4. package/dist/chunks/config-2ZHRsdOc.js.map +1 -0
  5. package/dist/chunks/{config-D6W1rnlp.js → config-B0uvcTPH.js} +1 -1
  6. package/dist/chunks/{config-D6W1rnlp.js.map → config-B0uvcTPH.js.map} +1 -1
  7. package/dist/chunks/{config-Bsh948nP.js → config-B3J0alyY.js} +1 -1
  8. package/dist/chunks/{config-Bsh948nP.js.map → config-B3J0alyY.js.map} +1 -1
  9. package/dist/chunks/{config-ScuvHw6k.js → config-B5SBUa6u.js} +1 -1
  10. package/dist/chunks/{config-ScuvHw6k.js.map → config-B5SBUa6u.js.map} +1 -1
  11. package/dist/chunks/{config-BeZRuonp.js → config-BDSaD-5p.js} +1 -1
  12. package/dist/chunks/{config-BeZRuonp.js.map → config-BDSaD-5p.js.map} +1 -1
  13. package/dist/chunks/{config-Dgj1Q6JY.js → config-BEO7brpO.js} +3 -3
  14. package/dist/chunks/config-BEO7brpO.js.map +1 -0
  15. package/dist/chunks/{config-B84z1aos.js → config-BHcS5Cwm.js} +1 -1
  16. package/dist/chunks/{config-B84z1aos.js.map → config-BHcS5Cwm.js.map} +1 -1
  17. package/dist/chunks/{config-DA6SnEoy.js → config-BRESvs9g.js} +2 -2
  18. package/dist/chunks/{config-DA6SnEoy.js.map → config-BRESvs9g.js.map} +1 -1
  19. package/dist/chunks/{config-CN2ULSQL.js → config-BTmfQFwi.js} +5 -5
  20. package/dist/chunks/config-BTmfQFwi.js.map +1 -0
  21. package/dist/chunks/{config-DtgYuGUn2.js → config-BTwYMQaz2.js} +5 -3
  22. package/dist/chunks/config-BTwYMQaz2.js.map +1 -0
  23. package/dist/chunks/{config-QJ54_fcM.js → config-BaWANzzB.js} +1 -1
  24. package/dist/chunks/{config-QJ54_fcM.js.map → config-BaWANzzB.js.map} +1 -1
  25. package/dist/chunks/{config-COvrUfhR.js → config-BcXX7S7B.js} +5 -5
  26. package/dist/chunks/config-BcXX7S7B.js.map +1 -0
  27. package/dist/chunks/{config-COpuWGr_.js → config-Bd7QfiGj.js} +1 -1
  28. package/dist/chunks/{config-COpuWGr_.js.map → config-Bd7QfiGj.js.map} +1 -1
  29. package/dist/chunks/{config-BDfTXHo1.js → config-BhfNgyWL.js} +2 -2
  30. package/dist/chunks/{config-BDfTXHo1.js.map → config-BhfNgyWL.js.map} +1 -1
  31. package/dist/chunks/{config-CjnbevbD.js → config-Bjn30smH.js} +1 -1
  32. package/dist/chunks/{config-CjnbevbD.js.map → config-Bjn30smH.js.map} +1 -1
  33. package/dist/chunks/{config-CN970ZcJ.js → config-BlJa1Mj9.js} +13 -13
  34. package/dist/chunks/config-BlJa1Mj9.js.map +1 -0
  35. package/dist/chunks/{config-DU2DNSRx.js → config-BoUI0t-t.js} +1 -1
  36. package/dist/chunks/{config-DU2DNSRx.js.map → config-BoUI0t-t.js.map} +1 -1
  37. package/dist/chunks/{config-BN4sXYXn.js → config-BqT6PMzO.js} +7 -14
  38. package/dist/chunks/config-BqT6PMzO.js.map +1 -0
  39. package/dist/chunks/config-BuGlNPE9.js.map +1 -0
  40. package/dist/chunks/{config-MRvhUl-O.js → config-CJzmDHfI.js} +1 -1
  41. package/dist/chunks/{config-MRvhUl-O.js.map → config-CJzmDHfI.js.map} +1 -1
  42. package/dist/chunks/{config-DGWFal5h.js → config-CLjjjPZj.js} +7 -7
  43. package/dist/chunks/config-CLjjjPZj.js.map +1 -0
  44. package/dist/chunks/{config-Cl4ST6Qd.js → config-CQLNjc9X2.js} +2 -2
  45. package/dist/chunks/config-CQLNjc9X2.js.map +1 -0
  46. package/dist/chunks/{config-vSji8w90.js → config-CWtfxkM9.js} +9 -9
  47. package/dist/chunks/config-CWtfxkM9.js.map +1 -0
  48. package/dist/chunks/{config-DKISz9gR.js → config-CWthWcWY.js} +2 -2
  49. package/dist/chunks/{config-DKISz9gR.js.map → config-CWthWcWY.js.map} +1 -1
  50. package/dist/chunks/{config-Iu684VNI.js → config-CZPDPJlg.js} +1 -1
  51. package/dist/chunks/{config-Iu684VNI.js.map → config-CZPDPJlg.js.map} +1 -1
  52. package/dist/chunks/{config-DAX8Deh1.js → config-CbEbLyDE.js} +3 -3
  53. package/dist/chunks/config-CbEbLyDE.js.map +1 -0
  54. package/dist/chunks/{config-D94Z9po5.js → config-ChPg-BQv.js} +2 -2
  55. package/dist/chunks/config-ChPg-BQv.js.map +1 -0
  56. package/dist/chunks/{config-DSJY6aEl.js → config-CjKpUcmy.js} +17 -17
  57. package/dist/chunks/config-CjKpUcmy.js.map +1 -0
  58. package/dist/chunks/{config-BIa3ilQm.js → config-CjWOTgLL.js} +4 -4
  59. package/dist/chunks/{config-BIa3ilQm.js.map → config-CjWOTgLL.js.map} +1 -1
  60. package/dist/chunks/{config-rkcKArZQ.js → config-CnYdE3HZ2.js} +5 -5
  61. package/dist/chunks/config-CnYdE3HZ2.js.map +1 -0
  62. package/dist/chunks/{config-BE6n20np.js → config-CvbVM4ep.js} +1 -1
  63. package/dist/chunks/{config-BE6n20np.js.map → config-CvbVM4ep.js.map} +1 -1
  64. package/dist/chunks/{config-9PYRZlKE.js → config-D0NzGYaE.js} +6 -6
  65. package/dist/chunks/config-D0NzGYaE.js.map +1 -0
  66. package/dist/chunks/{config-CKULiuvc.js → config-D0W8mGFD.js} +4 -4
  67. package/dist/chunks/{config-CKULiuvc.js.map → config-D0W8mGFD.js.map} +1 -1
  68. package/dist/chunks/{config-CY0_6cMi.js → config-D82r782v.js} +1 -1
  69. package/dist/chunks/{config-CY0_6cMi.js.map → config-D82r782v.js.map} +1 -1
  70. package/dist/chunks/config-DBmdgoVf2.js.map +1 -0
  71. package/dist/chunks/{config-WTNhdh6T.js → config-DCq4JySZ.js} +2 -2
  72. package/dist/chunks/{config-WTNhdh6T.js.map → config-DCq4JySZ.js.map} +1 -1
  73. package/dist/chunks/{config-C8tVRv8i.js → config-DGC00bTp.js} +13 -13
  74. package/dist/chunks/config-DGC00bTp.js.map +1 -0
  75. package/dist/chunks/{config-BsPDQ0dS.js → config-DIDz_E5m.js} +9 -9
  76. package/dist/chunks/config-DIDz_E5m.js.map +1 -0
  77. package/dist/chunks/{config-Dguto_6o.js → config-DM0lsduD.js} +6 -6
  78. package/dist/chunks/config-DM0lsduD.js.map +1 -0
  79. package/dist/chunks/{config-BfsBepkH.js → config-DNDgp9bB.js} +5 -5
  80. package/dist/chunks/config-DNDgp9bB.js.map +1 -0
  81. package/dist/chunks/{config-DpeQchsV.js → config-DO8mjeIo.js} +2 -2
  82. package/dist/chunks/{config-DpeQchsV.js.map → config-DO8mjeIo.js.map} +1 -1
  83. package/dist/chunks/{config-Baj7Wvx-.js → config-DRbojEzO.js} +4 -4
  84. package/dist/chunks/config-DRbojEzO.js.map +1 -0
  85. package/dist/chunks/{config-CQzGyi1C.js → config-DWL81-aM.js} +1 -1
  86. package/dist/chunks/{config-CQzGyi1C.js.map → config-DWL81-aM.js.map} +1 -1
  87. package/dist/chunks/{config-esdviAPL.js → config-DZCUPHPU.js} +1 -1
  88. package/dist/chunks/{config-esdviAPL.js.map → config-DZCUPHPU.js.map} +1 -1
  89. package/dist/chunks/{config-DKdlqXiY.js → config-DcfWZOi5.js} +5 -5
  90. package/dist/chunks/config-DcfWZOi5.js.map +1 -0
  91. package/dist/chunks/{config-BC8d_smz.js → config-DeyT9dJl.js} +3 -3
  92. package/dist/chunks/{config-BC8d_smz.js.map → config-DeyT9dJl.js.map} +1 -1
  93. package/dist/chunks/{config-Cwd3yjRw.js → config-DnF472Ox.js} +6 -4
  94. package/dist/chunks/config-DnF472Ox.js.map +1 -0
  95. package/dist/chunks/{config-B_qi4Fma.js → config-DolULhjJ.js} +5 -5
  96. package/dist/chunks/config-DolULhjJ.js.map +1 -0
  97. package/dist/chunks/{config-CIcynHGr.js → config-DpAYidyY2.js} +1 -1
  98. package/dist/chunks/config-DpAYidyY2.js.map +1 -0
  99. package/dist/chunks/{config-DYgfMrIF.js → config-Dpk-eVkS.js} +1 -1
  100. package/dist/chunks/{config-DYgfMrIF.js.map → config-Dpk-eVkS.js.map} +1 -1
  101. package/dist/chunks/config-Dv_r92GL.js +35 -0
  102. package/dist/chunks/config-Dv_r92GL.js.map +1 -0
  103. package/dist/chunks/{config-B4w5gBD0.js → config-DwABJHEo.js} +2 -2
  104. package/dist/chunks/config-DwABJHEo.js.map +1 -0
  105. package/dist/chunks/{config-zjeAJ4ho2.js → config-MmPym-Z72.js} +5 -5
  106. package/dist/chunks/config-MmPym-Z72.js.map +1 -0
  107. package/dist/chunks/{config-DCFvmHEv.js → config-T3-DMXYm.js} +9 -7
  108. package/dist/chunks/config-T3-DMXYm.js.map +1 -0
  109. package/dist/chunks/{config-BoNR7_PD.js → config-Yy67uWHY.js} +1 -1
  110. package/dist/chunks/{config-BoNR7_PD.js.map → config-Yy67uWHY.js.map} +1 -1
  111. package/dist/chunks/{config-BFJIxE8b.js → config-Z5LeUXys.js} +1 -1
  112. package/dist/chunks/{config-BFJIxE8b.js.map → config-Z5LeUXys.js.map} +1 -1
  113. package/dist/chunks/{config-DWN4x6_e.js → config-_QF0O1vq.js} +9 -9
  114. package/dist/chunks/config-_QF0O1vq.js.map +1 -0
  115. package/dist/chunks/{config-Cp0DE0GH.js → config-_jO3q1Le.js} +1 -1
  116. package/dist/chunks/{config-Cp0DE0GH.js.map → config-_jO3q1Le.js.map} +1 -1
  117. package/dist/chunks/{config-DGCMHPCR.js → config-g8-JGZ_Y.js} +1 -1
  118. package/dist/chunks/{config-DGCMHPCR.js.map → config-g8-JGZ_Y.js.map} +1 -1
  119. package/dist/chunks/{config-BTCOJO5z2.js → config-jyr6AIZt2.js} +3 -3
  120. package/dist/chunks/{config-BTCOJO5z2.js.map → config-jyr6AIZt2.js.map} +1 -1
  121. package/dist/chunks/{config-BtXRpAtq.js → config-mlheIMtV.js} +3 -6
  122. package/dist/chunks/config-mlheIMtV.js.map +1 -0
  123. package/dist/chunks/{config-BEVBsvni2.js → config-rLkc9Zn2.js} +1 -1
  124. package/dist/chunks/config-rLkc9Zn2.js.map +1 -0
  125. package/dist/chunks/{config-T3qdQBgU.js → config-tiUtEn4Q.js} +1 -1
  126. package/dist/chunks/{config-T3qdQBgU.js.map → config-tiUtEn4Q.js.map} +1 -1
  127. package/dist/chunks/{config-BViooYNv.js → config-uzUuosv7.js} +7 -2
  128. package/dist/chunks/config-uzUuosv7.js.map +1 -0
  129. package/dist/chunks/{config-BbY2SKGE.js → config-vYMJ3Cr1.js} +11 -9
  130. package/dist/chunks/config-vYMJ3Cr1.js.map +1 -0
  131. package/dist/chunks/context-BfIQv7m1.js.map +1 -0
  132. package/dist/chunks/{generated-CJe6hdiE.js → generated-DJ2dJ__C.js} +48 -0
  133. package/dist/chunks/generated-DJ2dJ__C.js.map +1 -0
  134. package/dist/chunks/{grBadgeStyles-C1S56Alo.js → grBadgeStyles-D8Mz73B5.js} +4 -4
  135. package/dist/chunks/grBadgeStyles-D8Mz73B5.js.map +1 -0
  136. package/dist/chunks/{config-D7zgE_Gr.js → grChipStyles-3JZApw03.js} +21 -43
  137. package/dist/chunks/grChipStyles-3JZApw03.js.map +1 -0
  138. package/dist/chunks/{grDropdownMenuStyles-D1LOkdVj.js → grDropdownMenuStyles-DG3aYHkT.js} +3 -3
  139. package/dist/chunks/grDropdownMenuStyles-DG3aYHkT.js.map +1 -0
  140. package/dist/chunks/{grIconStyles-BwJrml2L.js → grIconStyles-B6BRqUld.js} +1 -1
  141. package/dist/chunks/{grIconStyles-BwJrml2L.js.map → grIconStyles-B6BRqUld.js.map} +1 -1
  142. package/dist/chunks/{grInputStyles-CJeMhUe5.js → grInputStyles-CAk3xKIb.js} +4 -4
  143. package/dist/chunks/grInputStyles-CAk3xKIb.js.map +1 -0
  144. package/dist/chunks/{grKbdStyles-CeZhGQHr.js → grKbdStyles-DENu8pUK.js} +5 -0
  145. package/dist/chunks/grKbdStyles-DENu8pUK.js.map +1 -0
  146. package/dist/chunks/{grLinkStyles-BoL8QYcV.js → grLinkStyles-FME_qMpi.js} +4 -4
  147. package/dist/chunks/grLinkStyles-FME_qMpi.js.map +1 -0
  148. package/dist/chunks/{grLoadingStyles-DEmji2wv.js → grLoadingStyles-CnQaf5ry.js} +1 -1
  149. package/dist/chunks/{grLoadingStyles-DEmji2wv.js.map → grLoadingStyles-CnQaf5ry.js.map} +1 -1
  150. package/dist/chunks/{grPopoverStyles-Cke_BZsM.js → grPopoverStyles-Djh5RNhn.js} +4 -4
  151. package/dist/chunks/grPopoverStyles-Djh5RNhn.js.map +1 -0
  152. package/dist/chunks/{grRadioStyles-BTjGNhtU.js → grRadioStyles-D4gnU65n.js} +4 -4
  153. package/dist/chunks/grRadioStyles-D4gnU65n.js.map +1 -0
  154. package/dist/chunks/{grSelectStyles-eTz4uPMP.js → grSelectStyles-Cdtd10eY.js} +9 -9
  155. package/dist/chunks/grSelectStyles-Cdtd10eY.js.map +1 -0
  156. package/dist/chunks/{grTableStyles-C-iaqQUN.js → grTableStyles-uuMPSOBR.js} +2 -2
  157. package/dist/chunks/{grTableStyles-C-iaqQUN.js.map → grTableStyles-uuMPSOBR.js.map} +1 -1
  158. package/dist/chunks/{grTextareaStyles-iOcHuVMM.js → grTextareaStyles-Bp35BGna.js} +4 -4
  159. package/dist/chunks/grTextareaStyles-Bp35BGna.js.map +1 -0
  160. package/dist/chunks/{granular-provider-BaHkLjFX.js → granular-provider-DvvRayEh.js} +67 -67
  161. package/dist/chunks/{granular-provider-BaHkLjFX.js.map → granular-provider-DvvRayEh.js.map} +1 -1
  162. package/dist/chunks/numericStep-Bq2lj4ew.js +23 -0
  163. package/dist/chunks/numericStep-Bq2lj4ew.js.map +1 -0
  164. package/dist/chunks/overlayTransition-0Fj5tQbq.js +36 -0
  165. package/dist/chunks/overlayTransition-0Fj5tQbq.js.map +1 -0
  166. package/dist/chunks/{safelist-CudBLyAD.js → safelist-BOq5Li7p.js} +1 -1
  167. package/dist/chunks/{safelist-CudBLyAD.js.map → safelist-BOq5Li7p.js.map} +1 -1
  168. package/dist/chunks/{safelist-DOfCQR5O.js → safelist-CtiHPgrj.js} +2 -2
  169. package/dist/chunks/{safelist-DOfCQR5O.js.map → safelist-CtiHPgrj.js.map} +1 -1
  170. package/dist/chunks/{safelist-CkF4v7DC.js → safelist-Y3zrlhOa.js} +1 -1
  171. package/dist/chunks/{safelist-CkF4v7DC.js.map → safelist-Y3zrlhOa.js.map} +1 -1
  172. package/dist/chunks/{useMenuItemsFocus-OyOnIAlr.js → useMenuItemsFocus-B6TldmGf.js} +1 -43
  173. package/dist/chunks/useMenuItemsFocus-B6TldmGf.js.map +1 -0
  174. package/dist/chunks/useTypeahead-mxPtPBf2.js +44 -0
  175. package/dist/chunks/useTypeahead-mxPtPBf2.js.map +1 -0
  176. package/dist/components/GrAlert/chunks/{GrAlert-B21QGele.js → GrAlert-FAVf-ksH.js} +1 -1
  177. package/dist/components/GrAlert/chunks/{GrAlert-B21QGele.js.map → GrAlert-FAVf-ksH.js.map} +1 -1
  178. package/dist/components/GrAlert/index.js +1 -1
  179. package/dist/components/GrAutocomplete/chunks/{GrAutocomplete-D9c9BNFg.js → GrAutocomplete-BwhUTqmG.js} +88 -81
  180. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-BwhUTqmG.js.map +1 -0
  181. package/dist/components/GrAutocomplete/index.js +2 -2
  182. package/dist/components/GrAutocomplete/styles.css +1 -1
  183. package/dist/components/GrAvatar/chunks/{GrAvatar-BbdKRX8i.js → GrAvatar-CNmLmgcr.js} +1 -1
  184. package/dist/components/GrAvatar/chunks/{GrAvatar-BbdKRX8i.js.map → GrAvatar-CNmLmgcr.js.map} +1 -1
  185. package/dist/components/GrAvatar/index.js +2 -2
  186. package/dist/components/GrBadge/chunks/{GrBadge-_9rCHuE1.js → GrBadge-BM3f9PME.js} +2 -2
  187. package/dist/components/GrBadge/chunks/GrBadge-BM3f9PME.js.map +1 -0
  188. package/dist/components/GrBadge/index.js +3 -3
  189. package/dist/components/GrBadge/styles.css +1 -1
  190. package/dist/components/GrBadgeWrap/chunks/{GrBadgeWrap-DDoFQscR.js → GrBadgeWrap-B-A3PRkE.js} +1 -1
  191. package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-B-A3PRkE.js.map +1 -0
  192. package/dist/components/GrBadgeWrap/index.js +2 -2
  193. package/dist/components/GrBottomNav/chunks/{GrBottomNav-JUu4ylYv.js → GrBottomNav-wtFatLjB.js} +1 -1
  194. package/dist/components/GrBottomNav/chunks/{GrBottomNav-JUu4ylYv.js.map → GrBottomNav-wtFatLjB.js.map} +1 -1
  195. package/dist/components/GrBottomNav/index.js +2 -2
  196. package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-CQ44iU2o.js → GrBreadcrumbs-jtSnMEtg.js} +2 -2
  197. package/dist/components/GrBreadcrumbs/chunks/{GrBreadcrumbs-CQ44iU2o.js.map → GrBreadcrumbs-jtSnMEtg.js.map} +1 -1
  198. package/dist/components/GrBreadcrumbs/index.js +2 -2
  199. package/dist/components/GrButton/chunks/{GrButton-DCz-Wn-V.js → GrButton-Bw2AH4uX.js} +1 -1
  200. package/dist/components/GrButton/chunks/GrButton-Bw2AH4uX.js.map +1 -0
  201. package/dist/components/GrButton/index.js +3 -3
  202. package/dist/components/GrButtonGroup/chunks/{GrButtonGroup-BQo5VQ_c.js → GrButtonGroup-CKyiAV8K.js} +1 -1
  203. package/dist/components/GrButtonGroup/chunks/GrButtonGroup-CKyiAV8K.js.map +1 -0
  204. package/dist/components/GrButtonGroup/index.js +3 -3
  205. package/dist/components/GrCard/chunks/{GrCard-aQIjk6I9.js → GrCard-DR3ehBt8.js} +1 -1
  206. package/dist/components/GrCard/chunks/GrCard-DR3ehBt8.js.map +1 -0
  207. package/dist/components/GrCard/index.js +2 -2
  208. package/dist/components/GrCheckbox/index.js +1 -1
  209. package/dist/components/GrCheckboxGroup/index.js +1 -1
  210. package/dist/components/GrChip/chunks/{GrChip-BnL2FedO.js → GrChip-Df4orxRH.js} +15 -4
  211. package/dist/components/GrChip/chunks/GrChip-Df4orxRH.js.map +1 -0
  212. package/dist/components/GrChip/index.js +2 -2
  213. package/dist/components/GrChipGroup/chunks/{GrChipGroup-DefmSdY9.js → GrChipGroup-C78Vcwos.js} +2 -2
  214. package/dist/components/GrChipGroup/chunks/{GrChipGroup-DefmSdY9.js.map → GrChipGroup-C78Vcwos.js.map} +1 -1
  215. package/dist/components/GrChipGroup/index.js +2 -2
  216. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-CyptiEo4.js → GrCodeBlock-Dkvkr91t.js} +2 -2
  217. package/dist/components/GrCodeBlock/chunks/{GrCodeBlock-CyptiEo4.js.map → GrCodeBlock-Dkvkr91t.js.map} +1 -1
  218. package/dist/components/GrCodeBlock/index.js +2 -2
  219. package/dist/components/GrCollapse/chunks/{GrCollapse-DUROgAgc.js → GrCollapse-CytiA2Sx.js} +3 -3
  220. package/dist/components/GrCollapse/chunks/{GrCollapse-DUROgAgc.js.map → GrCollapse-CytiA2Sx.js.map} +1 -1
  221. package/dist/components/GrCollapse/index.js +2 -2
  222. package/dist/components/GrColorPicker/chunks/{GrColorPicker-CDaJRVIM.js → GrColorPicker-0n_KGeUy.js} +4 -4
  223. package/dist/components/GrColorPicker/chunks/{GrColorPicker-CDaJRVIM.js.map → GrColorPicker-0n_KGeUy.js.map} +1 -1
  224. package/dist/components/GrColorPicker/index.js +2 -2
  225. package/dist/components/GrCommandPalette/chunks/{GrCommandPalette-BPsVN_XU.js → GrCommandPalette-C5abL2Y7.js} +3 -3
  226. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-C5abL2Y7.js.map +1 -0
  227. package/dist/components/GrCommandPalette/index.js +2 -2
  228. package/dist/components/GrCommandPalette/styles.css +1 -1
  229. package/dist/components/GrConfigProvider/chunks/GrConfigProvider-BF7R3hgg.js.map +1 -1
  230. package/dist/components/GrConfirmDialog/chunks/{GrConfirmDialog-CwXNLyzk.js → GrConfirmDialog-B9mIU78E.js} +4 -4
  231. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-B9mIU78E.js.map +1 -0
  232. package/dist/components/GrConfirmDialog/index.js +1 -1
  233. package/dist/components/GrContextMenu/chunks/{GrContextMenu-BbAJholy.js → GrContextMenu-DDAUvrDK.js} +3 -3
  234. package/dist/components/GrContextMenu/chunks/GrContextMenu-DDAUvrDK.js.map +1 -0
  235. package/dist/components/GrContextMenu/index.js +1 -1
  236. package/dist/components/GrDataTable/chunks/{GrDataTable-NRbrXpdx.js → GrDataTable-DU00V44y.js} +14 -4
  237. package/dist/components/GrDataTable/chunks/GrDataTable-DU00V44y.js.map +1 -0
  238. package/dist/components/GrDataTable/index.js +2 -2
  239. package/dist/components/GrDelta/chunks/{GrDelta-NE5HhXoo.js → GrDelta-04j9WmEY.js} +0 -0
  240. package/dist/components/GrDelta/chunks/{GrDelta-NE5HhXoo.js.map → GrDelta-04j9WmEY.js.map} +1 -1
  241. package/dist/components/GrDelta/index.js +2 -2
  242. package/dist/components/GrDescriptionList/chunks/{GrDescriptionList-1mICfrqX.js → GrDescriptionList-BMeCgFV3.js} +1 -1
  243. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-BMeCgFV3.js.map +1 -0
  244. package/dist/components/GrDescriptionList/index.js +2 -2
  245. package/dist/components/GrDialog/chunks/{GrDialog-5Y5K87ss.js → GrDialog-bOUDYfmh.js} +2 -2
  246. package/dist/components/GrDialog/chunks/GrDialog-bOUDYfmh.js.map +1 -0
  247. package/dist/components/GrDialog/index.js +2 -2
  248. package/dist/components/GrDialogService/chunks/{GrDialogService-CHVR4sOk.js → GrDialogService-B--br5so.js} +4 -4
  249. package/dist/components/GrDialogService/chunks/{GrDialogService-CHVR4sOk.js.map → GrDialogService-B--br5so.js.map} +1 -1
  250. package/dist/components/GrDialogService/index.js +1 -1
  251. package/dist/components/GrDivider/chunks/{GrDivider-CAhm9jbE.js → GrDivider-BXavGcMX.js} +1 -1
  252. package/dist/components/GrDivider/chunks/GrDivider-BXavGcMX.js.map +1 -0
  253. package/dist/components/GrDivider/index.js +2 -2
  254. package/dist/components/GrDrawer/chunks/{GrDrawer-CXy3-SVd.js → GrDrawer-BCreL-eq.js} +3 -3
  255. package/dist/components/GrDrawer/chunks/{GrDrawer-CXy3-SVd.js.map → GrDrawer-BCreL-eq.js.map} +1 -1
  256. package/dist/components/GrDrawer/index.js +2 -2
  257. package/dist/components/GrDropdown/chunks/{GrDropdown-BfTmdPyh.js → GrDropdown-13Wt9eB_.js} +16 -8
  258. package/dist/components/GrDropdown/chunks/GrDropdown-13Wt9eB_.js.map +1 -0
  259. package/dist/components/GrDropdown/index.js +2 -2
  260. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenu-l5HEqzjr.js → GrDropdownMenu-5zoOL8Oj.js} +3 -3
  261. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-5zoOL8Oj.js.map +1 -0
  262. package/dist/components/GrDropdownMenu/chunks/{GrDropdownMenuList-BGA_xNVo.js → GrDropdownMenuList-CT_1TQJo.js} +1 -1
  263. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-CT_1TQJo.js.map +1 -0
  264. package/dist/components/GrDropdownMenu/index.js +3 -3
  265. package/dist/components/GrEmptyState/chunks/{GrEmptyState-CS9do8eM.js → GrEmptyState-D4T5pzXA.js} +2 -2
  266. package/dist/components/GrEmptyState/chunks/{GrEmptyState-CS9do8eM.js.map → GrEmptyState-D4T5pzXA.js.map} +1 -1
  267. package/dist/components/GrEmptyState/index.js +2 -2
  268. package/dist/components/GrFilePreview/chunks/{GrFilePreview-D0Bt-0nn.js → GrFilePreview-C9Z7hMK8.js} +1 -1
  269. package/dist/components/GrFilePreview/chunks/{GrFilePreview-D0Bt-0nn.js.map → GrFilePreview-C9Z7hMK8.js.map} +1 -1
  270. package/dist/components/GrFilePreview/index.js +2 -2
  271. package/dist/components/GrFileUpload/chunks/{GrFileUpload-wNXzHb5N.js → GrFileUpload-FjbaYGjL.js} +2 -2
  272. package/dist/components/GrFileUpload/chunks/{GrFileUpload-wNXzHb5N.js.map → GrFileUpload-FjbaYGjL.js.map} +1 -1
  273. package/dist/components/GrFileUpload/index.js +2 -2
  274. package/dist/components/GrForm/chunks/{GrForm-CAlJg-wb.js → GrForm-CrnfCsgj.js} +8 -2
  275. package/dist/components/GrForm/chunks/GrForm-CrnfCsgj.js.map +1 -0
  276. package/dist/components/GrForm/index.js +1 -1
  277. package/dist/components/GrFormField/chunks/GrFormField-DSylU7IU.js.map +1 -1
  278. package/dist/components/GrFormField/index.js +1 -1
  279. package/dist/components/GrFormFile/chunks/{GrFormFile-DhVkB2gm.js → GrFormFile-ChdKlN83.js} +3 -3
  280. package/dist/components/GrFormFile/chunks/{GrFormFile-DhVkB2gm.js.map → GrFormFile-ChdKlN83.js.map} +1 -1
  281. package/dist/components/GrFormFile/index.js +2 -2
  282. package/dist/components/GrFormSection/chunks/{GrFormSection-CdGWvzXO.js → GrFormSection-ejieOg9H.js} +1 -1
  283. package/dist/components/GrFormSection/chunks/{GrFormSection-CdGWvzXO.js.map → GrFormSection-ejieOg9H.js.map} +1 -1
  284. package/dist/components/GrFormSection/index.js +2 -2
  285. package/dist/components/GrIcon/chunks/{GrIcon-bQwtZtYT.js → GrIcon-Bn1XEriL.js} +1 -1
  286. package/dist/components/GrIcon/chunks/GrIcon-Bn1XEriL.js.map +1 -0
  287. package/dist/components/GrIcon/index.js +2 -2
  288. package/dist/components/GrImageViewer/chunks/{GrImageViewer-ng7el4wn.js → GrImageViewer-COUcpOgR.js} +2 -2
  289. package/dist/components/GrImageViewer/chunks/GrImageViewer-COUcpOgR.js.map +1 -0
  290. package/dist/components/GrImageViewer/index.js +2 -2
  291. package/dist/components/GrInput/chunks/{GrInput-Bb_pxqpT.js → GrInput-c53iltz0.js} +1 -1
  292. package/dist/components/GrInput/chunks/{GrInput-Bb_pxqpT.js.map → GrInput-c53iltz0.js.map} +1 -1
  293. package/dist/components/GrInput/index.js +2 -2
  294. package/dist/components/GrInputTag/chunks/{GrInputTag-UI8kIB_F.js → GrInputTag-LP3smqOv.js} +46 -49
  295. package/dist/components/GrInputTag/chunks/GrInputTag-LP3smqOv.js.map +1 -0
  296. package/dist/components/GrInputTag/index.js +2 -2
  297. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-jk3ylOTc.js → GrJsonViewer-ClTvjlFx.js} +4 -4
  298. package/dist/components/GrJsonViewer/chunks/{GrJsonViewer-jk3ylOTc.js.map → GrJsonViewer-ClTvjlFx.js.map} +1 -1
  299. package/dist/components/GrJsonViewer/index.js +2 -2
  300. package/dist/components/GrKbd/chunks/{GrKbd-BXbhsH0M.js → GrKbd-D2ga1H9i.js} +1 -1
  301. package/dist/components/GrKbd/chunks/{GrKbd-BXbhsH0M.js.map → GrKbd-D2ga1H9i.js.map} +1 -1
  302. package/dist/components/GrKbd/index.js +2 -2
  303. package/dist/components/GrLink/chunks/{GrLink-BQb7U4so.js → GrLink-DAGCFYO7.js} +2 -2
  304. package/dist/components/GrLink/chunks/GrLink-DAGCFYO7.js.map +1 -0
  305. package/dist/components/GrLink/index.js +2 -2
  306. package/dist/components/GrList/chunks/{GrList-B5bclmHV.js → GrList-DrXrKU37.js} +3 -3
  307. package/dist/components/GrList/chunks/GrList-DrXrKU37.js.map +1 -0
  308. package/dist/components/GrList/index.js +2 -2
  309. package/dist/components/GrList/styles.css +1 -1
  310. package/dist/components/GrLoading/chunks/{GrLoading-DeBFTvFX.js → GrLoading-DDD8WAIH.js} +2 -2
  311. package/dist/components/GrLoading/chunks/{GrLoading-DeBFTvFX.js.map → GrLoading-DDD8WAIH.js.map} +1 -1
  312. package/dist/components/GrLoading/index.js +2 -2
  313. package/dist/components/GrModal/index.js +1 -1
  314. package/dist/components/GrNavbar/chunks/{GrNavbar-DPj30sHX.js → GrNavbar-DhswlYyh.js} +3 -3
  315. package/dist/components/GrNavbar/chunks/{GrNavbar-DPj30sHX.js.map → GrNavbar-DhswlYyh.js.map} +1 -1
  316. package/dist/components/GrNavbar/index.js +2 -2
  317. package/dist/components/GrNumberInput/chunks/{GrNumberInput-V2mZvDDC.js → GrNumberInput-Daud9Jdm.js} +3 -14
  318. package/dist/components/GrNumberInput/chunks/GrNumberInput-Daud9Jdm.js.map +1 -0
  319. package/dist/components/GrNumberInput/index.js +2 -2
  320. package/dist/components/GrPagination/chunks/{GrPagination-DG7kp6VL.js → GrPagination-CaNTZc-v.js} +3 -3
  321. package/dist/components/GrPagination/chunks/{GrPagination-DG7kp6VL.js.map → GrPagination-CaNTZc-v.js.map} +1 -1
  322. package/dist/components/GrPagination/index.js +2 -2
  323. package/dist/components/GrPopover/chunks/{GrPopover-DDChM1jD.js → GrPopover-CofG-Tfe.js} +16 -8
  324. package/dist/components/GrPopover/chunks/GrPopover-CofG-Tfe.js.map +1 -0
  325. package/dist/components/GrPopover/index.js +2 -2
  326. package/dist/components/GrProgressBar/index.js +1 -1
  327. package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-BeUx1g1f.js → GrProgressCircle-D3yWXYDa.js} +1 -1
  328. package/dist/components/GrProgressCircle/chunks/{GrProgressCircle-BeUx1g1f.js.map → GrProgressCircle-D3yWXYDa.js.map} +1 -1
  329. package/dist/components/GrProgressCircle/index.js +2 -2
  330. package/dist/components/GrPromptDialog/chunks/{GrPromptDialog-BGuMUzlv.js → GrPromptDialog-DMhALhSS.js} +6 -6
  331. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-DMhALhSS.js.map +1 -0
  332. package/dist/components/GrPromptDialog/index.js +1 -1
  333. package/dist/components/GrRadio/chunks/{GrRadio-BdhknbO8.js → GrRadio-C_rESc5g.js} +1 -1
  334. package/dist/components/GrRadio/chunks/GrRadio-C_rESc5g.js.map +1 -0
  335. package/dist/components/GrRadio/index.js +2 -2
  336. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-7w4bXIg_.js → GrRadioGroup-CdQO4G-U.js} +2 -2
  337. package/dist/components/GrRadioGroup/chunks/{GrRadioGroup-7w4bXIg_.js.map → GrRadioGroup-CdQO4G-U.js.map} +1 -1
  338. package/dist/components/GrRadioGroup/index.js +1 -1
  339. package/dist/components/GrRating/chunks/{GrRating-BSEtaibx.js → GrRating-IEiTOdnF.js} +1 -1
  340. package/dist/components/GrRating/chunks/{GrRating-BSEtaibx.js.map → GrRating-IEiTOdnF.js.map} +1 -1
  341. package/dist/components/GrRating/index.js +2 -2
  342. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DA4q90Zt.js → GrResponseErrorBanner-C_skObtv.js} +1 -1
  343. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-DA4q90Zt.js.map → GrResponseErrorBanner-C_skObtv.js.map} +1 -1
  344. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BhP-xw2P.js → GrResponseErrorBanner-DudGc9LO.js} +4 -4
  345. package/dist/components/GrResponseErrorBanner/chunks/{GrResponseErrorBanner-BhP-xw2P.js.map → GrResponseErrorBanner-DudGc9LO.js.map} +1 -1
  346. package/dist/components/GrResponseErrorBanner/index.js +2 -2
  347. package/dist/components/GrSegmented/chunks/{GrSegmented-DKpo3cnC.js → GrSegmented-CB-VR-yL.js} +1 -1
  348. package/dist/components/GrSegmented/chunks/{GrSegmented-DKpo3cnC.js.map → GrSegmented-CB-VR-yL.js.map} +1 -1
  349. package/dist/components/GrSegmented/index.js +2 -2
  350. package/dist/components/GrSelect/chunks/{GrSelect-BA1wfX3c.js → GrSelect-BE1VNTiY.js} +96 -89
  351. package/dist/components/GrSelect/chunks/GrSelect-BE1VNTiY.js.map +1 -0
  352. package/dist/components/GrSelect/index.js +2 -2
  353. package/dist/components/GrSelect/styles.css +1 -1
  354. package/dist/components/GrSidebar/chunks/{GrSidebar-DY-LgIbS.js → GrSidebar-DxPhIiWs.js} +3 -3
  355. package/dist/components/GrSidebar/chunks/{GrSidebar-DY-LgIbS.js.map → GrSidebar-DxPhIiWs.js.map} +1 -1
  356. package/dist/components/GrSidebar/index.js +2 -2
  357. package/dist/components/GrSlider/chunks/{GrSlider-s99yAyz6.js → GrSlider-DJfeEl4h.js} +5 -4
  358. package/dist/components/GrSlider/chunks/GrSlider-DJfeEl4h.js.map +1 -0
  359. package/dist/components/GrSlider/index.js +2 -2
  360. package/dist/components/GrSortableList/chunks/{GrSortableList-BMXyxmRc.js → GrSortableList-DGs3Pi2J.js} +2 -2
  361. package/dist/components/GrSortableList/chunks/{GrSortableList-BMXyxmRc.js.map → GrSortableList-DGs3Pi2J.js.map} +1 -1
  362. package/dist/components/GrSortableList/index.js +2 -2
  363. package/dist/components/GrSplitter/chunks/{GrSplitter-B9_JrT7q.js → GrSplitter-MltjaADn.js} +1 -1
  364. package/dist/components/GrSplitter/chunks/{GrSplitter-B9_JrT7q.js.map → GrSplitter-MltjaADn.js.map} +1 -1
  365. package/dist/components/GrSplitter/index.js +2 -2
  366. package/dist/components/GrStatistic/chunks/{GrStatistic-BJQv5aOS.js → GrStatistic-qHVasK37.js} +2 -2
  367. package/dist/components/GrStatistic/chunks/GrStatistic-qHVasK37.js.map +1 -0
  368. package/dist/components/GrStatistic/index.js +2 -2
  369. package/dist/components/GrSteps/chunks/{GrSteps-Cce4rfr3.js → GrSteps-C2jxpZoN.js} +1 -1
  370. package/dist/components/GrSteps/chunks/{GrSteps-Cce4rfr3.js.map → GrSteps-C2jxpZoN.js.map} +1 -1
  371. package/dist/components/GrSteps/index.js +2 -2
  372. package/dist/components/GrSwitch/chunks/{GrSwitch-CHiIj9GT.js → GrSwitch-KRlRMwgp.js} +1 -1
  373. package/dist/components/GrSwitch/chunks/{GrSwitch-CHiIj9GT.js.map → GrSwitch-KRlRMwgp.js.map} +1 -1
  374. package/dist/components/GrSwitch/index.js +2 -2
  375. package/dist/components/GrTabPanels/chunks/GrTabPanels-BZQS8-JM.js.map +1 -1
  376. package/dist/components/GrTable/chunks/{GrTable-f3qCWa99.js → GrTable-Zcdz2St_.js} +1 -1
  377. package/dist/components/GrTable/chunks/GrTable-Zcdz2St_.js.map +1 -0
  378. package/dist/components/GrTable/index.js +2 -2
  379. package/dist/components/GrTabs/chunks/{GrTabs-CBHZkOFY.js → GrTabs-ugDnkk-2.js} +2 -2
  380. package/dist/components/GrTabs/chunks/{GrTabs-CBHZkOFY.js.map → GrTabs-ugDnkk-2.js.map} +1 -1
  381. package/dist/components/GrTabs/index.js +2 -2
  382. package/dist/components/GrTextarea/chunks/{GrTextarea-CNnkcIG1.js → GrTextarea-KREK75Bu.js} +1 -1
  383. package/dist/components/GrTextarea/chunks/{GrTextarea-CNnkcIG1.js.map → GrTextarea-KREK75Bu.js.map} +1 -1
  384. package/dist/components/GrTextarea/index.js +2 -2
  385. package/dist/components/GrTimeline/chunks/{GrTimeline-DIDdkTn7.js → GrTimeline-BiHpArsg.js} +1 -1
  386. package/dist/components/GrTimeline/chunks/{GrTimeline-DIDdkTn7.js.map → GrTimeline-BiHpArsg.js.map} +1 -1
  387. package/dist/components/GrTimeline/index.js +2 -2
  388. package/dist/components/GrToaster/chunks/{GrToaster-CC49q3a4.js → GrToaster-CUi3ldJ0.js} +6 -6
  389. package/dist/components/GrToaster/chunks/GrToaster-CUi3ldJ0.js.map +1 -0
  390. package/dist/components/GrToaster/index.js +2 -2
  391. package/dist/components/GrToaster/styles.css +1 -1
  392. package/dist/components/GrTooltip/chunks/{GrTooltip-B6AwE_UX.js → GrTooltip-BKFjqu0E.js} +4 -4
  393. package/dist/components/GrTooltip/chunks/GrTooltip-BKFjqu0E.js.map +1 -0
  394. package/dist/components/GrTooltip/index.js +2 -2
  395. package/dist/components/GrTree/chunks/{GrTree-J5q8aCya.js → GrTree-D5ozu6U4.js} +15 -25
  396. package/dist/components/GrTree/chunks/GrTree-D5ozu6U4.js.map +1 -0
  397. package/dist/components/GrTree/index.js +1 -1
  398. package/dist/components/GrTree/styles.css +1 -1
  399. package/dist/components/GrTreeSelect/chunks/{GrTreeSelect-DEfxWAc3.js → GrTreeSelect-Db_uKdNa.js} +18 -10
  400. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-Db_uKdNa.js.map +1 -0
  401. package/dist/components/GrTreeSelect/index.js +2 -2
  402. package/dist/components/GrValue/chunks/{GrValue-CZsuZ4x-.js → GrValue-ezkQM05Q.js} +1 -1
  403. package/dist/components/GrValue/chunks/{GrValue-CZsuZ4x-.js.map → GrValue-ezkQM05Q.js.map} +1 -1
  404. package/dist/components/GrValue/index.js +2 -2
  405. package/dist/directives/loading.js +1 -1
  406. package/dist/granular-provider-node.js +1 -1
  407. package/dist/granular-provider.js +1 -1
  408. package/dist/index.js +143 -143
  409. package/dist/styles/tokens.css +11 -0
  410. package/dist/theme.js +1 -1
  411. package/dist/tokens.js +1 -1
  412. package/dist/types/components/GrAutocomplete/GrAutocomplete.vue.d.ts +4 -3
  413. package/dist/types/components/GrAutocomplete/grAutocompleteStyles.d.ts +2 -2
  414. package/dist/types/components/GrBadge/GrBadge.vue.d.ts +3 -3
  415. package/dist/types/components/GrBadgeWrap/GrBadgeWrap.vue.d.ts +3 -3
  416. package/dist/types/components/GrBadgeWrap/grBadgeWrapStyles.d.ts +1 -1
  417. package/dist/types/components/GrBottomNav/grBottomNavStyles.d.ts +1 -1
  418. package/dist/types/components/GrButton/GrButton.vue.d.ts +7 -7
  419. package/dist/types/components/GrButtonGroup/GrButtonGroup.vue.d.ts +3 -3
  420. package/dist/types/components/GrCard/GrCard.vue.d.ts +7 -9
  421. package/dist/types/components/GrCheckbox/GrCheckbox.vue.d.ts +1 -1
  422. package/dist/types/components/GrCheckboxGroup/GrCheckboxGroup.vue.d.ts +1 -1
  423. package/dist/types/components/GrChip/GrChip.vue.d.ts +19 -1
  424. package/dist/types/components/GrChip/grChipStyles.d.ts +10 -6
  425. package/dist/types/components/GrChipGroup/GrChipGroup.vue.d.ts +2 -2
  426. package/dist/types/components/GrCollapse/GrCollapseItem.vue.d.ts +9 -11
  427. package/dist/types/components/GrColorPicker/GrColorPicker.vue.d.ts +1 -1
  428. package/dist/types/components/GrCommandPalette/GrCommandPalette.vue.d.ts +13 -13
  429. package/dist/types/components/GrCommandPalette/grCommandPaletteStyles.d.ts +5 -5
  430. package/dist/types/components/GrConfigProvider/GrConfigProvider.vue.d.ts +3 -3
  431. package/dist/types/components/GrConfirmDialog/GrConfirmDialog.vue.d.ts +9 -9
  432. package/dist/types/components/GrContextMenu/GrContextMenu.vue.d.ts +9 -9
  433. package/dist/types/components/GrDataTable/GrDataTable.vue.d.ts +9 -17
  434. package/dist/types/components/GrDescriptionList/GrDescriptionList.vue.d.ts +16 -13
  435. package/dist/types/components/GrDialog/GrDialogFooter.vue.d.ts +3 -3
  436. package/dist/types/components/GrDivider/GrDivider.vue.d.ts +3 -3
  437. package/dist/types/components/GrDrawer/grDrawerStyles.d.ts +1 -1
  438. package/dist/types/components/GrDropdown/GrDropdown.vue.d.ts +16 -20
  439. package/dist/types/components/GrDropdownMenu/GrDropdownMenu.vue.d.ts +16 -19
  440. package/dist/types/components/GrDropdownMenu/GrDropdownMenuColumn.vue.d.ts +3 -3
  441. package/dist/types/components/GrDropdownMenu/GrDropdownMenuColumns.vue.d.ts +3 -3
  442. package/dist/types/components/GrDropdownMenu/GrDropdownMenuGroup.vue.d.ts +3 -3
  443. package/dist/types/components/GrDropdownMenu/GrDropdownMenuHeader.vue.d.ts +3 -3
  444. package/dist/types/components/GrDropdownMenu/GrDropdownMenuItem.vue.d.ts +7 -7
  445. package/dist/types/components/GrDropdownMenu/GrDropdownMenuList.vue.d.ts +3 -3
  446. package/dist/types/components/GrDropdownMenu/grDropdownMenuStyles.d.ts +3 -3
  447. package/dist/types/components/GrForm/GrForm.vue.d.ts +5 -1
  448. package/dist/types/components/GrFormField/GrFormField.vue.d.ts +11 -11
  449. package/dist/types/components/GrFormFile/GrFormFile.vue.d.ts +1 -1
  450. package/dist/types/components/GrFormSection/grFormSectionStyles.d.ts +2 -2
  451. package/dist/types/components/GrIcon/GrIcon.vue.d.ts +3 -3
  452. package/dist/types/components/GrImageViewer/GrImageViewer.vue.d.ts +6 -25
  453. package/dist/types/components/GrInput/GrInput.vue.d.ts +1 -1
  454. package/dist/types/components/GrInput/grInputStyles.d.ts +4 -4
  455. package/dist/types/components/GrInputTag/GrInputTag.vue.d.ts +2 -2
  456. package/dist/types/components/GrInputTag/grInputTagStyles.d.ts +0 -6
  457. package/dist/types/components/GrKbd/GrKbd.vue.d.ts +3 -3
  458. package/dist/types/components/GrKbd/grKbdStyles.d.ts +5 -0
  459. package/dist/types/components/GrLink/GrLink.vue.d.ts +3 -3
  460. package/dist/types/components/GrList/GrList.vue.d.ts +12 -6
  461. package/dist/types/components/GrList/GrListItem.vue.d.ts +9 -9
  462. package/dist/types/components/GrList/grListStyles.d.ts +3 -3
  463. package/dist/types/components/GrNavbar/grNavbarStyles.d.ts +1 -1
  464. package/dist/types/components/GrNumberInput/GrNumberInput.vue.d.ts +1 -1
  465. package/dist/types/components/GrNumberInput/numberInputMath.d.ts +1 -6
  466. package/dist/types/components/GrPopover/GrPopover.vue.d.ts +16 -17
  467. package/dist/types/components/GrPromptDialog/GrPromptDialog.vue.d.ts +9 -9
  468. package/dist/types/components/GrRadio/GrRadio.vue.d.ts +6 -8
  469. package/dist/types/components/GrRadioGroup/GrRadioGroup.vue.d.ts +1 -1
  470. package/dist/types/components/GrRating/GrRating.vue.d.ts +1 -1
  471. package/dist/types/components/GrSegmented/GrSegmented.vue.d.ts +1 -1
  472. package/dist/types/components/GrSelect/grSelectStyles.d.ts +1 -1
  473. package/dist/types/components/GrSidebar/GrSidebar.vue.d.ts +7 -7
  474. package/dist/types/components/GrSidebar/grSidebarStyles.d.ts +4 -4
  475. package/dist/types/components/GrSlider/GrSlider.vue.d.ts +1 -1
  476. package/dist/types/components/GrSortableList/grSortableListStyles.d.ts +2 -2
  477. package/dist/types/components/GrSplitter/GrSplitter.vue.d.ts +1 -1
  478. package/dist/types/components/GrStatistic/GrStatistic.vue.d.ts +13 -13
  479. package/dist/types/components/GrSteps/grStepsStyles.d.ts +2 -2
  480. package/dist/types/components/GrSwitch/GrSwitch.vue.d.ts +1 -1
  481. package/dist/types/components/GrTabPanels/GrTabPanel.vue.d.ts +3 -3
  482. package/dist/types/components/GrTabPanels/GrTabPanels.vue.d.ts +3 -3
  483. package/dist/types/components/GrTable/GrTable.vue.d.ts +13 -13
  484. package/dist/types/components/GrTextarea/GrTextarea.vue.d.ts +1 -1
  485. package/dist/types/components/GrTreeSelect/grTreeSelectStyles.d.ts +1 -1
  486. package/dist/types/components/shared/classTokens.d.ts +8 -0
  487. package/dist/types/components/shared/numericStep.d.ts +14 -0
  488. package/dist/types/components/shared/overlayTransition.d.ts +33 -0
  489. package/dist/web-types.json +292 -218
  490. package/package.json +2 -2
  491. package/tokens/foundation.json +41 -1
  492. package/dist/chunks/classTokens-BzazaERD.js +0 -6
  493. package/dist/chunks/classTokens-BzazaERD.js.map +0 -1
  494. package/dist/chunks/config-9PYRZlKE.js.map +0 -1
  495. package/dist/chunks/config-B4w5gBD0.js.map +0 -1
  496. package/dist/chunks/config-BEVBsvni2.js.map +0 -1
  497. package/dist/chunks/config-BN4sXYXn.js.map +0 -1
  498. package/dist/chunks/config-BViooYNv.js.map +0 -1
  499. package/dist/chunks/config-B_qi4Fma.js.map +0 -1
  500. package/dist/chunks/config-Baj7Wvx-.js.map +0 -1
  501. package/dist/chunks/config-BbY2SKGE.js.map +0 -1
  502. package/dist/chunks/config-BfsBepkH.js.map +0 -1
  503. package/dist/chunks/config-Bpt9Xbxm.js.map +0 -1
  504. package/dist/chunks/config-BsPDQ0dS.js.map +0 -1
  505. package/dist/chunks/config-BtXRpAtq.js.map +0 -1
  506. package/dist/chunks/config-BuGlNPE92.js.map +0 -1
  507. package/dist/chunks/config-C8tVRv8i.js.map +0 -1
  508. package/dist/chunks/config-CIcynHGr.js.map +0 -1
  509. package/dist/chunks/config-CN2ULSQL.js.map +0 -1
  510. package/dist/chunks/config-CN970ZcJ.js.map +0 -1
  511. package/dist/chunks/config-COvrUfhR.js.map +0 -1
  512. package/dist/chunks/config-Cl4ST6Qd.js.map +0 -1
  513. package/dist/chunks/config-Cwd3yjRw.js.map +0 -1
  514. package/dist/chunks/config-D7zgE_Gr.js.map +0 -1
  515. package/dist/chunks/config-D94Z9po5.js.map +0 -1
  516. package/dist/chunks/config-DAX8Deh1.js.map +0 -1
  517. package/dist/chunks/config-DBmdgoVf.js.map +0 -1
  518. package/dist/chunks/config-DCFvmHEv.js.map +0 -1
  519. package/dist/chunks/config-DGWFal5h.js.map +0 -1
  520. package/dist/chunks/config-DKdlqXiY.js.map +0 -1
  521. package/dist/chunks/config-DSJY6aEl.js.map +0 -1
  522. package/dist/chunks/config-DWN4x6_e.js.map +0 -1
  523. package/dist/chunks/config-Dgj1Q6JY.js.map +0 -1
  524. package/dist/chunks/config-Dguto_6o.js.map +0 -1
  525. package/dist/chunks/config-DtgYuGUn2.js.map +0 -1
  526. package/dist/chunks/config-rkcKArZQ.js.map +0 -1
  527. package/dist/chunks/config-vSji8w90.js.map +0 -1
  528. package/dist/chunks/config-zjeAJ4ho2.js.map +0 -1
  529. package/dist/chunks/context-BfIQv7m12.js.map +0 -1
  530. package/dist/chunks/generated-CJe6hdiE.js.map +0 -1
  531. package/dist/chunks/grBadgeStyles-C1S56Alo.js.map +0 -1
  532. package/dist/chunks/grDropdownMenuStyles-D1LOkdVj.js.map +0 -1
  533. package/dist/chunks/grInputStyles-CJeMhUe5.js.map +0 -1
  534. package/dist/chunks/grKbdStyles-CeZhGQHr.js.map +0 -1
  535. package/dist/chunks/grLinkStyles-BoL8QYcV.js.map +0 -1
  536. package/dist/chunks/grPopoverStyles-Cke_BZsM.js.map +0 -1
  537. package/dist/chunks/grRadioStyles-BTjGNhtU.js.map +0 -1
  538. package/dist/chunks/grSelectStyles-eTz4uPMP.js.map +0 -1
  539. package/dist/chunks/grTextareaStyles-iOcHuVMM.js.map +0 -1
  540. package/dist/chunks/useMenuItemsFocus-OyOnIAlr.js.map +0 -1
  541. package/dist/components/GrAutocomplete/chunks/GrAutocomplete-D9c9BNFg.js.map +0 -1
  542. package/dist/components/GrBadge/chunks/GrBadge-_9rCHuE1.js.map +0 -1
  543. package/dist/components/GrBadgeWrap/chunks/GrBadgeWrap-DDoFQscR.js.map +0 -1
  544. package/dist/components/GrButton/chunks/GrButton-DCz-Wn-V.js.map +0 -1
  545. package/dist/components/GrButtonGroup/chunks/GrButtonGroup-BQo5VQ_c.js.map +0 -1
  546. package/dist/components/GrCard/chunks/GrCard-aQIjk6I9.js.map +0 -1
  547. package/dist/components/GrChip/chunks/GrChip-BnL2FedO.js.map +0 -1
  548. package/dist/components/GrCommandPalette/chunks/GrCommandPalette-BPsVN_XU.js.map +0 -1
  549. package/dist/components/GrConfirmDialog/chunks/GrConfirmDialog-CwXNLyzk.js.map +0 -1
  550. package/dist/components/GrContextMenu/chunks/GrContextMenu-BbAJholy.js.map +0 -1
  551. package/dist/components/GrDataTable/chunks/GrDataTable-NRbrXpdx.js.map +0 -1
  552. package/dist/components/GrDescriptionList/chunks/GrDescriptionList-1mICfrqX.js.map +0 -1
  553. package/dist/components/GrDialog/chunks/GrDialog-5Y5K87ss.js.map +0 -1
  554. package/dist/components/GrDivider/chunks/GrDivider-CAhm9jbE.js.map +0 -1
  555. package/dist/components/GrDropdown/chunks/GrDropdown-BfTmdPyh.js.map +0 -1
  556. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenu-l5HEqzjr.js.map +0 -1
  557. package/dist/components/GrDropdownMenu/chunks/GrDropdownMenuList-BGA_xNVo.js.map +0 -1
  558. package/dist/components/GrForm/chunks/GrForm-CAlJg-wb.js.map +0 -1
  559. package/dist/components/GrIcon/chunks/GrIcon-bQwtZtYT.js.map +0 -1
  560. package/dist/components/GrImageViewer/chunks/GrImageViewer-ng7el4wn.js.map +0 -1
  561. package/dist/components/GrInputTag/chunks/GrInputTag-UI8kIB_F.js.map +0 -1
  562. package/dist/components/GrLink/chunks/GrLink-BQb7U4so.js.map +0 -1
  563. package/dist/components/GrList/chunks/GrList-B5bclmHV.js.map +0 -1
  564. package/dist/components/GrNumberInput/chunks/GrNumberInput-V2mZvDDC.js.map +0 -1
  565. package/dist/components/GrPopover/chunks/GrPopover-DDChM1jD.js.map +0 -1
  566. package/dist/components/GrPromptDialog/chunks/GrPromptDialog-BGuMUzlv.js.map +0 -1
  567. package/dist/components/GrRadio/chunks/GrRadio-BdhknbO8.js.map +0 -1
  568. package/dist/components/GrSelect/chunks/GrSelect-BA1wfX3c.js.map +0 -1
  569. package/dist/components/GrSlider/chunks/GrSlider-s99yAyz6.js.map +0 -1
  570. package/dist/components/GrStatistic/chunks/GrStatistic-BJQv5aOS.js.map +0 -1
  571. package/dist/components/GrTable/chunks/GrTable-f3qCWa99.js.map +0 -1
  572. package/dist/components/GrToaster/chunks/GrToaster-CC49q3a4.js.map +0 -1
  573. package/dist/components/GrTooltip/chunks/GrTooltip-B6AwE_UX.js.map +0 -1
  574. package/dist/components/GrTree/chunks/GrTree-J5q8aCya.js.map +0 -1
  575. package/dist/components/GrTreeSelect/chunks/GrTreeSelect-DEfxWAc3.js.map +0 -1
  576. /package/dist/chunks/{config-BuGlNPE92.js → config-BuGlNPE9.js} +0 -0
  577. /package/dist/chunks/{config-DBmdgoVf.js → config-DBmdgoVf2.js} +0 -0
  578. /package/dist/chunks/{context-BfIQv7m12.js → context-BfIQv7m1.js} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrDropdown-BfTmdPyh.js","names":[],"sources":["../../../../src/components/GrDropdown/GrDropdown.vue","../../../../src/components/GrDropdown/GrDropdown.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useMenuItemsFocus } from '../../composables/internal/useMenuItemsFocus'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport type GrDropdownTrigger = 'click' | 'hover'\n\nexport interface GrDropdownProps {\n /** Размещение панели относительно триггера; `flip` при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Панель не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n}\n\nexport interface GrDropdownEmits {\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: undefined,\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownEmits>()\n\n// Имя `isOpen` сохранено: читатели работают с computed-Ref.\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst panelId = useId()\n\n// Кольцо фокуса и поиск по буквам — общие с `GrContextMenu`: паттерн `menu`\n// один, и вторая его реализация разошлась бы с первой незаметно для тестов.\nconst menu = useMenuItemsFocus({\n container: () => panelEl.value,\n close: () => close(),\n})\n\nasync function openWithFocus(first: boolean): Promise<void> {\n if (props.disabled)\n return\n\n setOpen(true)\n await nextTick()\n menu.focusAt(first ? 0 : -1)\n}\n\n/**\n * Пропсы для реального фокусируемого триггера (кнопки). Консьюмер биндит их на\n * элемент внутри слота `#trigger`: `<GrButton v-bind=\"triggerProps\">`. Даёт\n * `aria-haspopup`/`aria-expanded`/`aria-controls`, клавиатуру и **клик**.\n *\n * Клик живёт здесь, а не на обёртке слота: обёртка ловила бы и клики по\n * вложенным кнопкам и ссылкам, переключая панель мимо намерения пользователя.\n */\nconst triggerProps = computed(() => ({\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'aria-disabled': props.disabled ? true : undefined,\n 'onClick': toggle,\n 'onKeydown': onTriggerKeydown,\n}))\n\nfunction onTriggerKeydown(event: KeyboardEvent): void {\n if (props.disabled)\n return\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault()\n void openWithFocus(true)\n break\n case 'ArrowUp':\n event.preventDefault()\n void openWithFocus(false)\n break\n case 'Escape':\n if (isOpen.value) {\n event.preventDefault()\n close()\n }\n break\n }\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n // Геттер, а не значение: иначе проп замрёт на моменте `setup`.\n get offsetPx() { return props.offset },\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\n// ————— Открытие по наведению. Задержки нужны обе: без `openDelay` панель\n// выпрыгивает на любое пересечение курсором, без `closeDelay` её не удержать\n// при переходе с триггера на панель — между ними зазор `offset`.\nlet hoverTimer: ReturnType<typeof setTimeout> | undefined\n\nfunction open(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(true)\n}\n\nfunction toggle(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(!isOpen.value)\n}\n\nfunction close(): void {\n clearTimeout(hoverTimer)\n setOpen(false)\n}\n\nfunction scheduleHover(next: boolean, delayMs: number): void {\n clearTimeout(hoverTimer)\n\n if (delayMs <= 0) {\n setOpen(next)\n return\n }\n\n hoverTimer = setTimeout(setOpen, delayMs, next)\n}\n\nfunction onHoverEnter(): void {\n if (props.disabled || props.trigger !== 'hover')\n return\n scheduleHover(true, props.openDelay)\n}\n\nfunction onHoverLeave(): void {\n if (props.trigger !== 'hover')\n return\n scheduleHover(false, props.closeDelay)\n}\n\n// Возврат фокуса — из контракта слоя: он запоминает активный элемент при\n// открытии и возвращает фокус, только если на момент закрытия тот всё ещё\n// внутри панели. Прежняя эвристика «возвращать, если открыли с клавиатуры»\n// промахивалась в обе стороны.\nuseOverlayLayer(isOpen, close, { root: panelEl })\n\nwatch(\n () => [props.placement, props.offset],\n () => {\n if (isOpen.value) updateFloatingPosition()\n },\n)\n\nwatch(\n () => props.disabled,\n (value) => {\n if (value) close()\n },\n)\n\nfunction toCssLength(value: GrDropdownWidth): string | undefined {\n if (value === 'auto')\n return undefined\n if (typeof value === 'number')\n return `${value}px`\n\n // Строка без единиц браузер просто отбросит, поэтому трактуем её как пиксели\n // — и предупреждаем: `width=\"48\"` легко прочесть как токен шкалы `w-48`.\n const bare = value.trim()\n if (/^\\d+$/.test(bare)) {\n if (__GR_DEV__) {\n console.warn(\n `[GrDropdown] width=\"${value}\" трактуется как ${bare}px. `\n + 'Шкалы tailwind-токенов (w-48) у пропа больше нет — укажите единицы: '\n + `width=\"${bare}px\" или :width=\"${bare}\".`,\n )\n }\n return `${bare}px`\n }\n\n return value\n}\n\nconst panelStyle = computed(() => {\n const width = toCssLength(props.width)\n return width ? { ...floatingStyle.value, width } : floatingStyle.value\n})\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => grDropdownOriginClass(resolvedPlacement.value))\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n\n// Триггер без `v-bind=\"triggerProps\"` — это триггер без клика, без клавиатуры и\n// без ARIA. Молчать об этом нельзя: панель просто не открывалась бы, и искать\n// причину пришлось бы в чужом коде.\nonMounted(() => {\n if (!__GR_DEV__)\n return\n if (rootEl.value?.querySelector('[aria-haspopup]'))\n return\n\n console.warn(\n '[GrDropdown] триггер не привязан: добавьте `v-bind=\"triggerProps\"` на элемент '\n + 'внутри слота #trigger — <template #trigger=\"{ triggerProps }\">'\n + '<GrButton v-bind=\"triggerProps\">…</GrButton></template>. '\n + 'Без этого у триггера нет ни клика, ни клавиатуры, ни aria-haspopup/aria-expanded.',\n )\n})\n\nonBeforeUnmount(() => {\n menu.reset()\n clearTimeout(hoverTimer)\n})\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(() => props.teleportTo)\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\ndefineExpose({ open, close, toggle })\n</script>\n\n<template>\n <div data-gr-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen, exclude: clickOutsideExclude }\"\n data-gr-dropdown-trigger\n class=\"inline-block max-w-full\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <slot name=\"trigger\" :open=\"isOpen\" :toggle=\"toggle\" :close=\"close\" :trigger-props=\"triggerProps\" />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n enter-active-class=\"transition ease-[var(--gr-ease-out)] duration-[var(--gr-duration-fast)]\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-[var(--gr-ease-in)] duration-[var(--gr-duration-fast)]\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-dropdown-panel\n data-gr-overlay-root\n role=\"menu\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n @keydown=\"menu.onKeydown\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <div data-gr-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from 'vue'\n\nimport { usePortalTarget } from '../../composables/usePortalTarget'\n\nimport { vClickOutside } from '../../directives'\nimport { useFloating, type UseFloatingPlacement } from '../../composables/useFloating'\nimport { useOverlayLayer } from '../../composables/useOverlayLayer'\nimport { useControlledOpen } from '../../composables/internal/useControlledOpen'\nimport { useMenuItemsFocus } from '../../composables/internal/useMenuItemsFocus'\nimport {\n grDropdownContentClass,\n grDropdownOriginClass,\n type GrDropdownWidth,\n} from './grDropdownStyles'\n\nexport type GrDropdownTrigger = 'click' | 'hover'\n\nexport interface GrDropdownProps {\n /** Размещение панели относительно триггера; `flip` при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Панель не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Закрывать панель по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы контейнера content. */\n contentClass?: string\n /**\n * Точечное переопределение точки монтирования. По умолчанию — общий портал\n * оверлеев (`#gr-portal` либо `portalTarget` из `GrConfigProvider`).\n */\n teleportTo?: string | HTMLElement\n /**\n * Контролируемое состояние панели (`v-model:open`). Без пропа панель ведёт\n * себя сама (uncontrolled), с ним — слушайте `update:open` и меняйте проп.\n */\n open?: boolean\n}\n\nexport interface GrDropdownEmits {\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nimport { useGrThemeAttrs } from '../GrConfigProvider/context'\n\nconst props = withDefaults(defineProps<GrDropdownProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n closeOnContentClick: true,\n contentClass: '',\n teleportTo: undefined,\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownEmits>()\n\n// Имя `isOpen` сохранено: читатели работают с computed-Ref.\nconst { open: isOpen, setOpen } = useControlledOpen(\n () => props.open,\n next => emit('update:open', next),\n)\n\nconst rootEl = ref<HTMLElement | null>(null)\nconst panelEl = ref<HTMLElement | null>(null)\nconst clickOutsideExclude = [() => panelEl.value]\n\nconst panelId = useId()\n\n// Кольцо фокуса и поиск по буквам — общие с `GrContextMenu`: паттерн `menu`\n// один, и вторая его реализация разошлась бы с первой незаметно для тестов.\nconst menu = useMenuItemsFocus({\n container: () => panelEl.value,\n close: () => close(),\n})\n\nasync function openWithFocus(first: boolean): Promise<void> {\n if (props.disabled)\n return\n\n setOpen(true)\n await nextTick()\n menu.focusAt(first ? 0 : -1)\n}\n\n/**\n * Пропсы для реального фокусируемого триггера (кнопки). Консьюмер биндит их на\n * элемент внутри слота `#trigger`: `<GrButton v-bind=\"triggerProps\">`. Даёт\n * `aria-haspopup`/`aria-expanded`/`aria-controls`, клавиатуру и **клик**.\n *\n * Клик живёт здесь, а не на обёртке слота: обёртка ловила бы и клики по\n * вложенным кнопкам и ссылкам, переключая панель мимо намерения пользователя.\n */\nconst triggerProps = computed(() => ({\n 'aria-haspopup': 'menu' as const,\n 'aria-expanded': isOpen.value,\n 'aria-controls': isOpen.value ? panelId : undefined,\n 'aria-disabled': props.disabled ? true : undefined,\n 'onClick': toggle,\n 'onKeydown': onTriggerKeydown,\n}))\n\nfunction onTriggerKeydown(event: KeyboardEvent): void {\n if (props.disabled)\n return\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n case 'ArrowDown':\n event.preventDefault()\n void openWithFocus(true)\n break\n case 'ArrowUp':\n event.preventDefault()\n void openWithFocus(false)\n break\n case 'Escape':\n if (isOpen.value) {\n event.preventDefault()\n close()\n }\n break\n }\n}\n\nconst { floatingStyle, resolvedPlacement, update: updateFloatingPosition } = useFloating(\n rootEl,\n panelEl,\n isOpen,\n {\n placement: () => props.placement,\n // Геттер, а не значение: иначе проп замрёт на моменте `setup`.\n get offsetPx() { return props.offset },\n zIndexVar: '--gr-z-dropdown',\n },\n)\n\n// ————— Открытие по наведению. Задержки нужны обе: без `openDelay` панель\n// выпрыгивает на любое пересечение курсором, без `closeDelay` её не удержать\n// при переходе с триггера на панель — между ними зазор `offset`.\nlet hoverTimer: ReturnType<typeof setTimeout> | undefined\n\nfunction open(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(true)\n}\n\nfunction toggle(): void {\n if (props.disabled)\n return\n\n clearTimeout(hoverTimer)\n setOpen(!isOpen.value)\n}\n\nfunction close(): void {\n clearTimeout(hoverTimer)\n setOpen(false)\n}\n\nfunction scheduleHover(next: boolean, delayMs: number): void {\n clearTimeout(hoverTimer)\n\n if (delayMs <= 0) {\n setOpen(next)\n return\n }\n\n hoverTimer = setTimeout(setOpen, delayMs, next)\n}\n\nfunction onHoverEnter(): void {\n if (props.disabled || props.trigger !== 'hover')\n return\n scheduleHover(true, props.openDelay)\n}\n\nfunction onHoverLeave(): void {\n if (props.trigger !== 'hover')\n return\n scheduleHover(false, props.closeDelay)\n}\n\n// Возврат фокуса — из контракта слоя: он запоминает активный элемент при\n// открытии и возвращает фокус, только если на момент закрытия тот всё ещё\n// внутри панели. Прежняя эвристика «возвращать, если открыли с клавиатуры»\n// промахивалась в обе стороны.\nuseOverlayLayer(isOpen, close, { root: panelEl })\n\nwatch(\n () => [props.placement, props.offset],\n () => {\n if (isOpen.value) updateFloatingPosition()\n },\n)\n\nwatch(\n () => props.disabled,\n (value) => {\n if (value) close()\n },\n)\n\nfunction toCssLength(value: GrDropdownWidth): string | undefined {\n if (value === 'auto')\n return undefined\n if (typeof value === 'number')\n return `${value}px`\n\n // Строка без единиц браузер просто отбросит, поэтому трактуем её как пиксели\n // — и предупреждаем: `width=\"48\"` легко прочесть как токен шкалы `w-48`.\n const bare = value.trim()\n if (/^\\d+$/.test(bare)) {\n if (__GR_DEV__) {\n console.warn(\n `[GrDropdown] width=\"${value}\" трактуется как ${bare}px. `\n + 'Шкалы tailwind-токенов (w-48) у пропа больше нет — укажите единицы: '\n + `width=\"${bare}px\" или :width=\"${bare}\".`,\n )\n }\n return `${bare}px`\n }\n\n return value\n}\n\nconst panelStyle = computed(() => {\n const width = toCssLength(props.width)\n return width ? { ...floatingStyle.value, width } : floatingStyle.value\n})\n\nconst contentClasses = computed(() => grDropdownContentClass(props.contentClass))\n\nconst panelClasses = computed(() => grDropdownOriginClass(resolvedPlacement.value))\n\nfunction onContentClick(): void {\n if (props.closeOnContentClick) {\n close()\n }\n}\n\n// Триггер без `v-bind=\"triggerProps\"` — это триггер без клика, без клавиатуры и\n// без ARIA. Молчать об этом нельзя: панель просто не открывалась бы, и искать\n// причину пришлось бы в чужом коде.\nonMounted(() => {\n if (!__GR_DEV__)\n return\n if (rootEl.value?.querySelector('[aria-haspopup]'))\n return\n\n console.warn(\n '[GrDropdown] триггер не привязан: добавьте `v-bind=\"triggerProps\"` на элемент '\n + 'внутри слота #trigger — <template #trigger=\"{ triggerProps }\">'\n + '<GrButton v-bind=\"triggerProps\">…</GrButton></template>. '\n + 'Без этого у триггера нет ни клика, ни клавиатуры, ни aria-haspopup/aria-expanded.',\n )\n})\n\nonBeforeUnmount(() => {\n menu.reset()\n clearTimeout(hoverTimer)\n})\n\n// Телепорт включается только ПОСЛЕ монтирования: иначе первый клиентский\n// рендер не совпадает с серверным и ломается гидрация (см. композабл).\nconst { target: portalTarget, enabled: teleportEnabled } = usePortalTarget(() => props.teleportTo)\n\n// Тема поддерева на телепортированную панель: в DOM она уезжает в `body`, то\n// есть вне обёртки провайдера, и `data-theme` с неё не наследуется. В дереве\n// компонентов панель остаётся внутри — `inject` доходит, и тему она ставит себе\n// сама.\nconst themeAttrs = useGrThemeAttrs()\n\ndefineExpose({ open, close, toggle })\n</script>\n\n<template>\n <div data-gr-dropdown>\n <div\n ref=\"rootEl\"\n v-click-outside=\"{ handler: close, enabled: isOpen, exclude: clickOutsideExclude }\"\n data-gr-dropdown-trigger\n class=\"inline-block max-w-full\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <slot name=\"trigger\" :open=\"isOpen\" :toggle=\"toggle\" :close=\"close\" :trigger-props=\"triggerProps\" />\n </div>\n\n <teleport :to=\"portalTarget\" :disabled=\"!teleportEnabled\">\n <transition\n enter-active-class=\"transition ease-[var(--gr-ease-out)] duration-[var(--gr-duration-fast)]\"\n enter-from-class=\"transform opacity-0 scale-95\"\n enter-to-class=\"transform opacity-100 scale-100\"\n leave-active-class=\"transition ease-[var(--gr-ease-in)] duration-[var(--gr-duration-fast)]\"\n leave-from-class=\"transform opacity-100 scale-100\"\n leave-to-class=\"transform opacity-0 scale-95\"\n >\n <div\n v-show=\"isOpen\"\n :id=\"panelId\"\n ref=\"panelEl\"\n v-bind=\"themeAttrs\"\n data-gr-dropdown-panel\n data-gr-overlay-root\n role=\"menu\"\n tabindex=\"-1\"\n :class=\"panelClasses\"\n :style=\"panelStyle\"\n @click=\"onContentClick\"\n @keydown=\"menu.onKeydown\"\n @mouseenter=\"onHoverEnter\"\n @mouseleave=\"onHoverLeave\"\n >\n <div data-gr-dropdown-content :class=\"contentClasses\">\n <slot name=\"content\" :close=\"close\" />\n </div>\n </div>\n </transition>\n </teleport>\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrDropdownMenu-l5HEqzjr.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenu.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumn.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuColumns.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n// Типы размещения и ширины — из владельца API, а не переобъявлением: расхождение\n// обнаружилось бы только рантаймом.\nimport type { GrDropdownTrigger } from '../GrDropdown/GrDropdown.vue'\nimport type { GrDropdownWidth } from '../GrDropdown/grDropdownStyles'\nimport type { UseFloatingPlacement } from '../../composables/useFloating'\n\nimport GrDropdownMenuEntries from './GrDropdownMenuEntries.vue'\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\n\nexport interface GrDropdownMenuProps {\n /** Размещение панели относительно триггера; переворот при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Меню не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Куда телепортировать панель (`body` по умолчанию). */\n /** Точечное переопределение точки монтирования; по умолчанию — общий портал. */\n teleportTo?: string | HTMLElement\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера. */\n contentClass?: string\n /**\n * Декларативное меню: пункты, группы и разделители массивом. Слот по\n * умолчанию сильнее — он для меню, которое из модели не собирается.\n */\n items?: GrDropdownMenuEntry[]\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n /**\n * Контролируемое состояние панели (`v-model:open`) — прокидывается в\n * `GrDropdown`. Без пропа меню ведёт себя само (uncontrolled).\n */\n open?: boolean\n}\n\nexport interface GrDropdownMenuEmits {\n /** Выбран пункт декларативного меню. */\n (e: 'select', item: GrDropdownMenuAction): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n teleportTo: undefined,\n closeOnContentClick: true,\n // Поле панели принадлежит панели. Гасить его отсюда своим `p-0` нельзя: оба\n // класса попадают в один атрибут с равной специфичностью, и победителя\n // выбирает порядок правил в сгенерированном CSS, а не разметка. Пункт вписан\n // в это поле собственным радиусом — см. `itemBaseClass`.\n contentClass: '',\n items: undefined,\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownMenuEmits>()\n\n</script>\n\n<template>\n <GrDropdown\n data-gr-dropdown-menu\n :placement=\"placement\"\n :offset=\"offset\"\n :width=\"width\"\n :trigger=\"trigger\"\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n :disabled=\"disabled\"\n :teleport-to=\"teleportTo\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n :open=\"open\"\n @update:open=\"emit('update:open', $event)\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\">\n <GrDropdownMenuEntries :items=\"items\" @select=\"emit('select', $event)\" />\n </slot>\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport GrDropdown from '../GrDropdown/GrDropdown.vue'\n// Типы размещения и ширины — из владельца API, а не переобъявлением: расхождение\n// обнаружилось бы только рантаймом.\nimport type { GrDropdownTrigger } from '../GrDropdown/GrDropdown.vue'\nimport type { GrDropdownWidth } from '../GrDropdown/grDropdownStyles'\nimport type { UseFloatingPlacement } from '../../composables/useFloating'\n\nimport GrDropdownMenuEntries from './GrDropdownMenuEntries.vue'\nimport GrDropdownMenuList from './GrDropdownMenuList.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\n\nexport interface GrDropdownMenuProps {\n /** Размещение панели относительно триггера; переворот при нехватке места остаётся. */\n placement?: UseFloatingPlacement\n /** Зазор между триггером и панелью, px. */\n offset?: number\n /** Ширина панели: число — пиксели, строка — CSS-длина, `auto` — по контенту. */\n width?: GrDropdownWidth\n /** Чем открывается панель. В любом режиме работают клик и клавиатура. */\n trigger?: GrDropdownTrigger\n /** Задержка открытия по наведению, мс. */\n openDelay?: number\n /** Задержка закрытия после ухода курсора, мс. */\n closeDelay?: number\n /** Меню не открывается ничем; триггер остаётся фокусируемым. */\n disabled?: boolean\n /** Куда телепортировать панель (`body` по умолчанию). */\n /** Точечное переопределение точки монтирования; по умолчанию — общий портал. */\n teleportTo?: string | HTMLElement\n /** Закрывать по клику внутри content. */\n closeOnContentClick?: boolean\n /** Дополнительные классы content-контейнера. */\n contentClass?: string\n /**\n * Декларативное меню: пункты, группы и разделители массивом. Слот по\n * умолчанию сильнее — он для меню, которое из модели не собирается.\n */\n items?: GrDropdownMenuEntry[]\n\n // list wrapper\n /** Разделители между пунктами. */\n dividers?: boolean\n /** Верхний бордер контейнера списка. */\n borderTop?: boolean\n /** Нижний бордер контейнера списка. */\n borderBottom?: boolean\n /** Дополнительные классы для wrapper'а списка. */\n listClass?: string\n /**\n * Контролируемое состояние панели (`v-model:open`) — прокидывается в\n * `GrDropdown`. Без пропа меню ведёт себя само (uncontrolled).\n */\n open?: boolean\n}\n\nexport interface GrDropdownMenuEmits {\n /** Выбран пункт декларативного меню. */\n (e: 'select', item: GrDropdownMenuAction): void\n /** Панель открылась/закрылась (`v-model:open`). */\n (e: 'update:open', value: boolean): void\n}\n\nwithDefaults(defineProps<GrDropdownMenuProps>(), {\n placement: 'bottom-end',\n offset: 8,\n width: '12rem',\n trigger: 'click',\n openDelay: 120,\n closeDelay: 160,\n disabled: false,\n teleportTo: undefined,\n closeOnContentClick: true,\n // Поле панели принадлежит панели. Гасить его отсюда своим `p-0` нельзя: оба\n // класса попадают в один атрибут с равной специфичностью, и победителя\n // выбирает порядок правил в сгенерированном CSS, а не разметка. Пункт вписан\n // в это поле собственным радиусом — см. `itemBaseClass`.\n contentClass: '',\n items: undefined,\n dividers: false,\n borderTop: false,\n borderBottom: false,\n listClass: '',\n open: undefined,\n})\n\nconst emit = defineEmits<GrDropdownMenuEmits>()\n\n</script>\n\n<template>\n <GrDropdown\n data-gr-dropdown-menu\n :placement=\"placement\"\n :offset=\"offset\"\n :width=\"width\"\n :trigger=\"trigger\"\n :open-delay=\"openDelay\"\n :close-delay=\"closeDelay\"\n :disabled=\"disabled\"\n :teleport-to=\"teleportTo\"\n :close-on-content-click=\"closeOnContentClick\"\n :content-class=\"contentClass\"\n :open=\"open\"\n @update:open=\"emit('update:open', $event)\"\n >\n <template #trigger=\"slotProps\">\n <slot name=\"trigger\" v-bind=\"slotProps\" />\n </template>\n\n <template #content=\"slotProps\">\n <GrDropdownMenuList\n :dividers=\"dividers\"\n :border-top=\"borderTop\"\n :border-bottom=\"borderBottom\"\n :class=\"listClass\"\n >\n <slot v-bind=\"slotProps\">\n <GrDropdownMenuEntries :items=\"items\" @select=\"emit('select', $event)\" />\n </slot>\n </GrDropdownMenuList>\n </template>\n </GrDropdown>\n</template>\n","<script setup lang=\"ts\">\nimport { alignClass, columnBaseClass, type GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-column\n role=\"none\"\n :class=\"[columnBaseClass, alignClass[align]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { alignClass, columnBaseClass, type GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuColumnAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnProps {\n align?: GrDropdownMenuColumnAlign\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnProps>(), {\n align: 'center',\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-column\n role=\"none\"\n :class=\"[columnBaseClass, alignClass[align]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { colsClass, columnsBaseClass, type GrDropdownMenuColumnsCount } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: GrDropdownMenuColumnsCount\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-columns\n role=\"none\"\n :class=\"[columnsBaseClass, colsClass[cols]]\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { colsClass, columnsBaseClass, type GrDropdownMenuColumnsCount } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuColumnsProps {\n cols?: GrDropdownMenuColumnsCount\n}\n\nwithDefaults(defineProps<GrDropdownMenuColumnsProps>(), {\n cols: 2,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-columns\n role=\"none\"\n :class=\"[columnsBaseClass, colsClass[cols]]\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsFA,MAAM,OAAO;;uBAKX,YA+Ba,oBAAA;IA9BX,yBAAA;IACC,WAAW,QAAA;IACX,QAAQ,QAAA;IACR,OAAO,QAAA;IACP,SAAS,QAAA;IACT,cAAY,QAAA;IACZ,eAAa,QAAA;IACb,UAAU,QAAA;IACV,eAAa,QAAA;IACb,0BAAwB,QAAA;IACxB,iBAAe,QAAA;IACf,MAAM,QAAA;IACN,iBAAW,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,eAAgB,MAAM;;IAE7B,SAAO,SAAE,cAAS,CAC3B,WAA0C,KAAA,QAAA,WAAA,eAAA,mBAAb,SAAS,CAAA,CAAA,CAAA,CAAA;IAG7B,SAAO,SAAE,cAAS,CAC3B,YASqB,4BAAA;KARlB,UAAU,QAAA;KACV,cAAY,QAAA;KACZ,iBAAe,QAAA;KACf,OAAK,eAAE,QAAA,SAAS;;4BAIV,CAFP,WAEO,KAAA,QAAA,WAAA,eAAA,mBAFO,SAAS,CAAA,SAEhB,CADL,YAAyE,+BAAA;MAAjD,OAAO,QAAA;MAAQ,UAAM,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,UAAW,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBEvG5E,mBAMM,OAAA;IALJ,gCAAA;IACA,MAAK;IACJ,OAAK,eAAA,CAAG,MAAA,eAAA,GAAiB,MAAA,UAAA,CAAU,CAAC,QAAA,MAAK,CAAA;OAE1C,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA;;;;;;;;;;;uBEPV,mBAMM,OAAA;IALJ,iCAAA;IACA,MAAK;IACJ,OAAK,eAAA,CAAG,MAAA,gBAAA,GAAkB,MAAA,SAAA,CAAS,CAAC,QAAA,KAAI,CAAA;OAEzC,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrDropdownMenuList-BGA_xNVo.js","names":[],"sources":["../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuDivider.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuHeader.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuGroup.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuItem.vue","../../../../src/components/GrDropdownMenu/menuModel.ts","../../../../src/components/GrDropdownMenu/GrDropdownMenuEntries.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuEntries.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue","../../../../src/components/GrDropdownMenu/GrDropdownMenuList.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { dividerClass, dividerInsetClass } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-divider\n role=\"separator\"\n :class=\"[dividerClass, inset ? dividerInsetClass : '']\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { dividerClass, dividerInsetClass } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuDividerProps {\n inset?: boolean\n}\n\nwithDefaults(defineProps<GrDropdownMenuDividerProps>(), {\n inset: false,\n})\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-divider\n role=\"separator\"\n :class=\"[dividerClass, inset ? dividerInsetClass : '']\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nimport { headerClass, textAlignClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\n/**\n * Заголовок — подпись, а не пункт меню: `role=\"presentation\"` убирает его из\n * числа потомков `role=\"menu\"`. Имя группе он даёт через `aria-labelledby`\n * у `GrDropdownMenuGroup`.\n */\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-gr-dropdown-menu-header\n role=\"presentation\"\n :class=\"[headerClass, textAlignClass[align], { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useSlots } from 'vue'\n\nimport { headerClass, textAlignClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport type { GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuHeaderProps {\n title?: string\n align?: GrDropdownMenuHeaderAlign\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuHeaderProps>(), {\n title: undefined,\n align: 'left',\n uppercase: true,\n})\n\n/**\n * Заголовок — подпись, а не пункт меню: `role=\"presentation\"` убирает его из\n * числа потомков `role=\"menu\"`. Имя группе он даёт через `aria-labelledby`\n * у `GrDropdownMenuGroup`.\n */\nconst slots = useSlots()\nconst isVisible = computed(() => Boolean(props.title) || Boolean(slots.default))\n</script>\n\n<template>\n <div\n v-if=\"isVisible\"\n data-gr-dropdown-menu-header\n role=\"presentation\"\n :class=\"[headerClass, textAlignClass[align], { uppercase }]\"\n >\n <slot>{{ title }}</slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useId } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport { dividersClass, listBaseClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst titleId = useId()\n// Имя группы читается диктором при входе в неё; без заголовка называть нечем.\nconst labelledBy = computed(() => (props.title ? titleId : undefined))\n\nconst itemsClass = computed(() => [\n listBaseClass,\n props.dividers ? dividersClass : '',\n].filter(Boolean).join(' '))\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-group\n role=\"group\"\n :aria-labelledby=\"labelledBy\"\n class=\"w-full\"\n >\n <GrDropdownMenuHeader\n v-if=\"title\"\n :id=\"titleId\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div role=\"none\" :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useId } from 'vue'\n\nimport GrDropdownMenuHeader from './GrDropdownMenuHeader.vue'\nimport { dividersClass, listBaseClass, type GrDropdownMenuHeaderAlign } from './grDropdownMenuStyles'\n\nexport interface GrDropdownMenuGroupProps {\n title?: string\n titleAlign?: GrDropdownMenuHeaderAlign\n dividers?: boolean\n uppercase?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuGroupProps>(), {\n title: undefined,\n titleAlign: 'left',\n dividers: false,\n uppercase: true,\n})\n\nconst titleId = useId()\n// Имя группы читается диктором при входе в неё; без заголовка называть нечем.\nconst labelledBy = computed(() => (props.title ? titleId : undefined))\n\nconst itemsClass = computed(() => [\n listBaseClass,\n props.dividers ? dividersClass : '',\n].filter(Boolean).join(' '))\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-group\n role=\"group\"\n :aria-labelledby=\"labelledBy\"\n class=\"w-full\"\n >\n <GrDropdownMenuHeader\n v-if=\"title\"\n :id=\"titleId\"\n :title=\"title\"\n :align=\"titleAlign\"\n :uppercase=\"uppercase\"\n />\n <div role=\"none\" :class=\"itemsClass\">\n <slot />\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\nimport IconCheck from '~icons/lucide/check'\n\nimport {\n grDropdownMenuItemClass,\n itemIndicatorClass,\n itemShortcutClass,\n type GrDropdownMenuItemAlign,\n type GrDropdownMenuItemVariant,\n} from './grDropdownMenuStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type { GrDropdownMenuItemAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Роль пункта. `menuitemcheckbox`/`menuitemradio` — пункты-переключатели: они\n * обязаны нести `aria-checked`, иначе AT прочитает их как обычные команды.\n */\nexport type GrDropdownMenuItemRole = 'menuitem' | 'menuitemcheckbox' | 'menuitemradio'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n /** Пункт-ссылка. У выключенного пункта не рендерится: ссылка осталась бы рабочей. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя. Осмысленно с `role=\"menuitemcheckbox|radio\"`. */\n checked?: boolean\n /** Иконка слева. Слот `#icon` сильнее. */\n icon?: Component\n /** Подпись сочетания клавиш справа. Слот `#shortcut` сильнее. */\n shortcut?: string\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n align: 'left',\n variant: 'default',\n role: 'menuitem',\n checked: undefined,\n icon: undefined,\n shortcut: undefined,\n})\n\nconst attrs = useAttrs()\n\n// Полиморфный корень: явный `as` сильнее всего, иначе `href` сам делает пункт\n// ссылкой — как у `GrButton`, чтобы не приходилось задавать `as=\"a\"` вручную.\nconst renderAs = computed<string | Component>(() => {\n if (props.as && props.as !== 'button')\n return props.as\n return props.href ? 'a' : 'button'\n})\n\nconst isNativeButton = computed(() => renderAs.value === 'button')\n\n// Выключенный пункт остаётся ссылкой, если оставить ему `href`: средняя кнопка и\n// контекстное меню браузера обойдут любой перехват клика (тот же приём в `GrButton`).\nconst resolvedHref = computed(() => (props.disabled ? undefined : props.href))\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() =>\n props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined),\n)\n// Отметка занимает место всегда, когда пункт переключаемый: иначе строки\n// «включено» и «выключено» разъезжаются по горизонтали.\nconst isCheckable = computed(() => props.role !== 'menuitem')\n\nconst className = computed(() => grDropdownMenuItemClass({\n align: props.align,\n variant: props.variant,\n disabled: props.disabled,\n}))\n\n/**\n * Roving tabindex паттерна menu: табируемым остаётся триггер, а внутри панели\n * фокусом распоряжаются стрелки (`GrDropdown` наводит его программно). Без\n * этого `Tab` ходил бы по пунктам, и меню было бы списком кнопок, а не меню.\n *\n * Выключённый пункт из обхода **не** выпадает: `aria-disabled` вместо нативного\n * `disabled` оставляет его фокусируемым, и пользователь узнаёт, что действие\n * существует, но сейчас недоступно (рекомендация WAI-ARIA APG).\n */\nconst resolvedTabindex = computed(() => (attrs.tabindex as number | string | undefined) ?? -1)\n\nfunction onClickCapture(e: MouseEvent): void {\n if (!props.disabled)\n return\n\n e.preventDefault()\n // `stopImmediatePropagation`, а не `stopPropagation`: обработчик, навешенный\n // на сам пункт через `v-bind=\"attrs\"`, живёт на этом же элементе, и обычная\n // остановка всплытия его не отменяет.\n e.stopImmediatePropagation()\n}\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n v-bind=\"attrs\"\n data-gr-dropdown-menu-item\n :role=\"role\"\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :href=\"resolvedHref\"\n :target=\"resolvedHref ? resolvedTarget : undefined\"\n :rel=\"resolvedHref ? resolvedRel : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-checked=\"isCheckable ? (checked ? 'true' : 'false') : undefined\"\n :tabindex=\"resolvedTabindex\"\n @click.capture=\"onClickCapture\"\n >\n <span\n v-if=\"isCheckable\"\n data-gr-dropdown-menu-item-indicator\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"checked\" :class=\"itemIndicatorClass\" />\n </span>\n\n <slot name=\"icon\">\n <component\n :is=\"icon\"\n v-if=\"icon\"\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n />\n </slot>\n\n <slot />\n\n <slot name=\"shortcut\">\n <span v-if=\"shortcut\" data-gr-dropdown-menu-item-shortcut :class=\"itemShortcutClass\">{{ shortcut }}</span>\n </slot>\n </component>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, useAttrs } from 'vue'\nimport type { Component } from 'vue'\n\nimport IconCheck from '~icons/lucide/check'\n\nimport {\n grDropdownMenuItemClass,\n itemIndicatorClass,\n itemShortcutClass,\n type GrDropdownMenuItemAlign,\n type GrDropdownMenuItemVariant,\n} from './grDropdownMenuStyles'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nexport type { GrDropdownMenuItemAlign, GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Роль пункта. `menuitemcheckbox`/`menuitemradio` — пункты-переключатели: они\n * обязаны нести `aria-checked`, иначе AT прочитает их как обычные команды.\n */\nexport type GrDropdownMenuItemRole = 'menuitem' | 'menuitemcheckbox' | 'menuitemradio'\n\nexport interface GrDropdownMenuItemProps {\n as?: string | Component\n disabled?: boolean\n /** Пункт-ссылка. У выключенного пункта не рендерится: ссылка осталась бы рабочей. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n align?: GrDropdownMenuItemAlign\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя. Осмысленно с `role=\"menuitemcheckbox|radio\"`. */\n checked?: boolean\n /** Иконка слева. Слот `#icon` сильнее. */\n icon?: Component\n /** Подпись сочетания клавиш справа. Слот `#shortcut` сильнее. */\n shortcut?: string\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuItemProps>(), {\n as: 'button',\n disabled: false,\n href: undefined,\n target: undefined,\n rel: undefined,\n external: false,\n align: 'left',\n variant: 'default',\n role: 'menuitem',\n checked: undefined,\n icon: undefined,\n shortcut: undefined,\n})\n\nconst attrs = useAttrs()\n\n// Полиморфный корень: явный `as` сильнее всего, иначе `href` сам делает пункт\n// ссылкой — как у `GrButton`, чтобы не приходилось задавать `as=\"a\"` вручную.\nconst renderAs = computed<string | Component>(() => {\n if (props.as && props.as !== 'button')\n return props.as\n return props.href ? 'a' : 'button'\n})\n\nconst isNativeButton = computed(() => renderAs.value === 'button')\n\n// Выключенный пункт остаётся ссылкой, если оставить ему `href`: средняя кнопка и\n// контекстное меню браузера обойдут любой перехват клика (тот же приём в `GrButton`).\nconst resolvedHref = computed(() => (props.disabled ? undefined : props.href))\nconst resolvedTarget = computed(() => props.target ?? (props.external ? '_blank' : undefined))\nconst resolvedRel = computed(() =>\n props.rel ?? (resolvedTarget.value === '_blank' ? 'noopener noreferrer' : undefined),\n)\n// Отметка занимает место всегда, когда пункт переключаемый: иначе строки\n// «включено» и «выключено» разъезжаются по горизонтали.\nconst isCheckable = computed(() => props.role !== 'menuitem')\n\nconst className = computed(() => grDropdownMenuItemClass({\n align: props.align,\n variant: props.variant,\n disabled: props.disabled,\n}))\n\n/**\n * Roving tabindex паттерна menu: табируемым остаётся триггер, а внутри панели\n * фокусом распоряжаются стрелки (`GrDropdown` наводит его программно). Без\n * этого `Tab` ходил бы по пунктам, и меню было бы списком кнопок, а не меню.\n *\n * Выключённый пункт из обхода **не** выпадает: `aria-disabled` вместо нативного\n * `disabled` оставляет его фокусируемым, и пользователь узнаёт, что действие\n * существует, но сейчас недоступно (рекомендация WAI-ARIA APG).\n */\nconst resolvedTabindex = computed(() => (attrs.tabindex as number | string | undefined) ?? -1)\n\nfunction onClickCapture(e: MouseEvent): void {\n if (!props.disabled)\n return\n\n e.preventDefault()\n // `stopImmediatePropagation`, а не `stopPropagation`: обработчик, навешенный\n // на сам пункт через `v-bind=\"attrs\"`, живёт на этом же элементе, и обычная\n // остановка всплытия его не отменяет.\n e.stopImmediatePropagation()\n}\n</script>\n\n<template>\n <component\n :is=\"renderAs\"\n v-bind=\"attrs\"\n data-gr-dropdown-menu-item\n :role=\"role\"\n :class=\"className\"\n :type=\"isNativeButton ? (attrs.type as any) ?? 'button' : undefined\"\n :href=\"resolvedHref\"\n :target=\"resolvedHref ? resolvedTarget : undefined\"\n :rel=\"resolvedHref ? resolvedRel : undefined\"\n :aria-disabled=\"disabled ? 'true' : undefined\"\n :aria-checked=\"isCheckable ? (checked ? 'true' : 'false') : undefined\"\n :tabindex=\"resolvedTabindex\"\n @click.capture=\"onClickCapture\"\n >\n <span\n v-if=\"isCheckable\"\n data-gr-dropdown-menu-item-indicator\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n >\n <IconCheck v-if=\"checked\" :class=\"itemIndicatorClass\" />\n </span>\n\n <slot name=\"icon\">\n <component\n :is=\"icon\"\n v-if=\"icon\"\n :class=\"itemIndicatorClass\"\n aria-hidden=\"true\"\n />\n </slot>\n\n <slot />\n\n <slot name=\"shortcut\">\n <span v-if=\"shortcut\" data-gr-dropdown-menu-item-shortcut :class=\"itemShortcutClass\">{{ shortcut }}</span>\n </slot>\n </component>\n</template>\n","import type { Component } from 'vue'\n\nimport type { GrDropdownMenuItemRole } from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuItemVariant } from './grDropdownMenuStyles'\n\n/**\n * Декларативная модель меню.\n *\n * Композиция из подкомпонентов остаётся основным способом — она нужна там, где\n * пункт нестандартный. Но девять меню из десяти однотипны («иконка, подпись,\n * шорткат, иногда разделитель»), и собирать их из пяти компонентов вручную\n * значит каждый раз заново решать, где `role`, где `disabled`, где ключ.\n */\nexport interface GrDropdownMenuAction {\n /** Ключ пункта — он же приходит в `select`. */\n key: string\n label: string\n icon?: Component\n shortcut?: string\n disabled?: boolean\n variant?: GrDropdownMenuItemVariant\n role?: GrDropdownMenuItemRole\n /** Состояние переключателя для `menuitemcheckbox`/`menuitemradio`. */\n checked?: boolean\n /** Пункт-ссылка: рендерится как `<a>` с этим `href`. */\n href?: string\n target?: string\n rel?: string\n /** Шорткат для `target=\"_blank\"` + `rel=\"noopener noreferrer\"`. */\n external?: boolean\n}\n\nexport interface GrDropdownMenuSeparator {\n type: 'divider'\n inset?: boolean\n}\n\nexport interface GrDropdownMenuSection {\n type: 'group'\n title?: string\n items: GrDropdownMenuAction[]\n}\n\nexport type GrDropdownMenuEntry = GrDropdownMenuAction | GrDropdownMenuSeparator | GrDropdownMenuSection\n\nexport function isMenuSeparator(entry: GrDropdownMenuEntry): entry is GrDropdownMenuSeparator {\n return 'type' in entry && entry.type === 'divider'\n}\n\nexport function isMenuSection(entry: GrDropdownMenuEntry): entry is GrDropdownMenuSection {\n return 'type' in entry && entry.type === 'group'\n}\n\nexport function isMenuAction(entry: GrDropdownMenuEntry): entry is GrDropdownMenuAction {\n return !isMenuSeparator(entry) && !isMenuSection(entry)\n}\n","<script setup lang=\"ts\">\n/**\n * Рендер декларативной модели меню — без обёртки списка: её ставит потребитель,\n * потому что `dividers`/`borderTop` принадлежат конкретному меню, а не модели.\n *\n * Вынесено из `GrDropdownMenu` ради `GrContextMenu`: модель у них общая, и\n * вторая копия цикла разошлась бы с первой при первом же новом поле пункта.\n */\nimport GrDropdownMenuDivider from './GrDropdownMenuDivider.vue'\nimport GrDropdownMenuGroup from './GrDropdownMenuGroup.vue'\nimport GrDropdownMenuItem from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\nimport { isMenuAction, isMenuSection, isMenuSeparator } from './menuModel'\n\nexport interface GrDropdownMenuEntriesProps {\n items?: GrDropdownMenuEntry[]\n}\n\nexport interface GrDropdownMenuEntriesEmits {\n (e: 'select', item: GrDropdownMenuAction): void\n}\n\ndefineProps<GrDropdownMenuEntriesProps>()\n\nconst emit = defineEmits<GrDropdownMenuEntriesEmits>()\n\nfunction itemProps(item: GrDropdownMenuAction): Record<string, unknown> {\n return {\n href: item.href,\n target: item.target,\n rel: item.rel,\n external: item.external,\n disabled: item.disabled,\n variant: item.variant,\n role: item.role,\n checked: item.checked,\n icon: item.icon,\n shortcut: item.shortcut,\n }\n}\n\nfunction onSelect(item: GrDropdownMenuAction): void {\n if (item.disabled)\n return\n\n emit('select', item)\n}\n</script>\n\n<template>\n <template v-for=\"(entry, index) in items ?? []\">\n <GrDropdownMenuDivider\n v-if=\"isMenuSeparator(entry)\"\n :key=\"`divider-${index}`\"\n :inset=\"entry.inset\"\n />\n\n <GrDropdownMenuGroup\n v-else-if=\"isMenuSection(entry)\"\n :key=\"`group-${entry.title ?? index}`\"\n :title=\"entry.title\"\n >\n <GrDropdownMenuItem\n v-for=\"item in entry.items\"\n :key=\"item.key\"\n v-bind=\"itemProps(item)\"\n @click=\"onSelect(item)\"\n >\n {{ item.label }}\n </GrDropdownMenuItem>\n </GrDropdownMenuGroup>\n\n <GrDropdownMenuItem\n v-else-if=\"isMenuAction(entry)\"\n :key=\"entry.key\"\n v-bind=\"itemProps(entry)\"\n @click=\"onSelect(entry)\"\n >\n {{ entry.label }}\n </GrDropdownMenuItem>\n </template>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Рендер декларативной модели меню — без обёртки списка: её ставит потребитель,\n * потому что `dividers`/`borderTop` принадлежат конкретному меню, а не модели.\n *\n * Вынесено из `GrDropdownMenu` ради `GrContextMenu`: модель у них общая, и\n * вторая копия цикла разошлась бы с первой при первом же новом поле пункта.\n */\nimport GrDropdownMenuDivider from './GrDropdownMenuDivider.vue'\nimport GrDropdownMenuGroup from './GrDropdownMenuGroup.vue'\nimport GrDropdownMenuItem from './GrDropdownMenuItem.vue'\nimport type { GrDropdownMenuAction, GrDropdownMenuEntry } from './menuModel'\nimport { isMenuAction, isMenuSection, isMenuSeparator } from './menuModel'\n\nexport interface GrDropdownMenuEntriesProps {\n items?: GrDropdownMenuEntry[]\n}\n\nexport interface GrDropdownMenuEntriesEmits {\n (e: 'select', item: GrDropdownMenuAction): void\n}\n\ndefineProps<GrDropdownMenuEntriesProps>()\n\nconst emit = defineEmits<GrDropdownMenuEntriesEmits>()\n\nfunction itemProps(item: GrDropdownMenuAction): Record<string, unknown> {\n return {\n href: item.href,\n target: item.target,\n rel: item.rel,\n external: item.external,\n disabled: item.disabled,\n variant: item.variant,\n role: item.role,\n checked: item.checked,\n icon: item.icon,\n shortcut: item.shortcut,\n }\n}\n\nfunction onSelect(item: GrDropdownMenuAction): void {\n if (item.disabled)\n return\n\n emit('select', item)\n}\n</script>\n\n<template>\n <template v-for=\"(entry, index) in items ?? []\">\n <GrDropdownMenuDivider\n v-if=\"isMenuSeparator(entry)\"\n :key=\"`divider-${index}`\"\n :inset=\"entry.inset\"\n />\n\n <GrDropdownMenuGroup\n v-else-if=\"isMenuSection(entry)\"\n :key=\"`group-${entry.title ?? index}`\"\n :title=\"entry.title\"\n >\n <GrDropdownMenuItem\n v-for=\"item in entry.items\"\n :key=\"item.key\"\n v-bind=\"itemProps(item)\"\n @click=\"onSelect(item)\"\n >\n {{ item.label }}\n </GrDropdownMenuItem>\n </GrDropdownMenuGroup>\n\n <GrDropdownMenuItem\n v-else-if=\"isMenuAction(entry)\"\n :key=\"entry.key\"\n v-bind=\"itemProps(entry)\"\n @click=\"onSelect(entry)\"\n >\n {{ entry.label }}\n </GrDropdownMenuItem>\n </template>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { grDropdownMenuListClass } from './grDropdownMenuStyles'\n\n/**\n * `role=\"none\"` на обёртке обязателен: `role=\"menu\"` у панели объявляет своих\n * потомков презентационными, и любой div между панелью и пунктом ломает\n * `aria-required-children`, а пункты теряют принадлежность к меню.\n */\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => grDropdownMenuListClass({\n dividers: props.dividers,\n borderTop: props.borderTop,\n borderBottom: props.borderBottom,\n}))\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-list\n role=\"none\"\n :class=\"className\"\n >\n <slot />\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { grDropdownMenuListClass } from './grDropdownMenuStyles'\n\n/**\n * `role=\"none\"` на обёртке обязателен: `role=\"menu\"` у панели объявляет своих\n * потомков презентационными, и любой div между панелью и пунктом ломает\n * `aria-required-children`, а пункты теряют принадлежность к меню.\n */\n\nexport interface GrDropdownMenuListProps {\n dividers?: boolean\n borderTop?: boolean\n borderBottom?: boolean\n}\n\nconst props = withDefaults(defineProps<GrDropdownMenuListProps>(), {\n dividers: false,\n borderTop: false,\n borderBottom: false,\n})\n\nconst className = computed(() => grDropdownMenuListClass({\n dividers: props.dividers,\n borderTop: props.borderTop,\n borderBottom: props.borderBottom,\n}))\n</script>\n\n<template>\n <div\n data-gr-dropdown-menu-list\n role=\"none\"\n :class=\"className\"\n >\n <slot />\n </div>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrForm-CAlJg-wb.js","names":[],"sources":["../../../../src/components/GrForm/modelSnapshot.ts","../../../../src/components/GrForm/GrForm.vue","../../../../src/components/GrForm/GrForm.vue"],"sourcesContent":["/**\n * Снимок модели формы: клон для `resetFields` и отпечаток для `isDirty`.\n *\n * Чистый модуль без Vue: обе операции читают «сквозь» reactive-прокси и\n * тестируются без монтирования.\n *\n * Почему не `JSON.parse(JSON.stringify(...))` и не `structuredClone`: первый\n * теряет `File` (у файла нет ни перечислимых собственных свойств, ни `toJSON`,\n * поэтому в снимок попадал `{}`), второй падает на прокси с `DataCloneError`.\n */\n\n/** `File` и прочие `Blob` — двоичные значения, для которых клон бессмыслен. */\nfunction isBinary(value: unknown): value is Blob {\n return typeof Blob !== 'undefined' && value instanceof Blob\n}\n\nfunction cloneValue(value: unknown): unknown {\n if (typeof value === 'function' || typeof value === 'symbol') return undefined\n if (value === null || typeof value !== 'object') return value\n\n // По ссылке: содержимое файла клонировать нечем, а идентичность как раз и\n // нужна — `resetFields` обязан вернуть тот самый файл, а не его подобие.\n if (isBinary(value)) return value\n\n if (Array.isArray(value)) {\n // Как у `JSON.stringify`: не-сериализуемый элемент массива становится `null`,\n // иначе сброс сдвинул бы индексы.\n return value.map((item) => {\n const cloned = cloneValue(item)\n return cloned === undefined ? null : cloned\n })\n }\n\n // `Date` и прочие носители `toJSON` ведут себя ровно как раньше.\n const toJSON = (value as { toJSON?: unknown }).toJSON\n if (typeof toJSON === 'function') return cloneValue((value as { toJSON: () => unknown }).toJSON())\n\n const out: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) {\n const cloned = cloneValue(item)\n if (cloned !== undefined) out[key] = cloned\n }\n return out\n}\n\n/** Клон значения модели: JSON-семантика плюс сохранённые по ссылке файлы. */\nexport function cloneModelValue<T>(value: T): T {\n return value === undefined ? value : (cloneValue(value) as T)\n}\n\n/**\n * Отпечаток файла для сравнения. Тождество здесь не годится: `resetFields`\n * кладёт в модель клон снимка, и сравнение по ссылке считало бы форму грязной\n * сразу после сброса. Тройки «имя, размер, время» достаточно, чтобы отличить\n * один выбранный файл от другого.\n */\nfunction binaryFingerprint(value: Blob): string {\n if (typeof File !== 'undefined' && value instanceof File)\n return `gr-file:${value.name}:${value.size}:${value.lastModified}`\n\n return `gr-blob:${value.size}:${value.type}`\n}\n\n/**\n * Строка, по которой сравниваются модель и снимок. Без неё любой `File`\n * сериализовался в `{}`, и «выбрал документ» было неотличимо от «не трогал».\n */\nexport function modelFingerprint(value: unknown): string {\n return JSON.stringify(value, (_key, item) => isBinary(item) ? binaryFingerprint(item) : item) ?? ''\n}\n","<script setup lang=\"ts\" generic=\"TModel extends object = Record<string, unknown>\">\nimport { computed, onBeforeUnmount, provide, ref, watch } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { GR_FORM_KEY } from './context'\nimport { cloneModelValue, modelFingerprint } from './modelSnapshot'\nimport {\n getByPath,\n createGrFormMessageResolver,\n rulesForTrigger,\n rulesRequired,\n runFieldRules,\n setByPath,\n toRuleArray,\n type GrFormRule,\n type GrFormRules,\n type GrFormTrigger,\n} from './validation'\n\nexport type {\n GrFormFileRule,\n GrFormRule,\n GrFormRules,\n GrFormTrigger,\n GrFormValidatorResult,\n} from './validation'\n\n/**\n * Публичный GR-примитив «Form» — оркестрация валидации над `GrFormField`.\n *\n * Модель формы (`v-model`-объект приложения) + декларативные `rules` по имени поля.\n * Форма прогоняет правила, раскладывает ошибки по контексту, скроллит к первой\n * ошибке и эмитит `submit` только при валидной форме. Императивный API — через\n * template ref (`validate` / `validateField` / `clearValidate` / `resetFields` /\n * `scrollToField`).\n */\nexport interface GrFormProps<TModel extends object = Record<string, unknown>> {\n /**\n * Реактивный объект данных формы. Поля адресуются по `name` (`GrFormField`),\n * в т.ч. dot-path.\n *\n * Тип дженерик, а не `Record<string, unknown>`: моделью бывает объект чужой\n * библиотеки (`useForm` Inertia, стор), у которого рядом с полями лежат\n * собственные методы. Под словарь он не подходит, и потребителю пришлось бы\n * приводить его через `as unknown as` в каждой форме.\n */\n model: TModel\n /** Правила валидации по имени поля: `{ email: [{ required: true, type: 'email' }] }`. */\n rules?: GrFormRules\n /** Валидировать поле при потере фокуса. */\n validateOnBlur?: boolean\n /** Валидировать поле при каждом изменении значения. */\n validateOnChange?: boolean\n /** Скроллить к первому невалидному полю после `validate()`. */\n scrollToError?: boolean\n scrollBehavior?: ScrollBehavior\n /**\n * Выключить форму целиком — типично на время отправки. Доезжает до контролов\n * через контекст поля, поэтому обходить их по одному не нужно.\n */\n disabled?: boolean\n}\n\nexport interface GrFormEmits<TModel extends object = Record<string, unknown>> {\n /** Форма прошла валидацию по submit. Отдаёт `model`. */\n (e: 'submit', model: TModel): void\n /** Результат валидации одного поля. */\n (e: 'validate', name: string, valid: boolean, message: string | undefined): void\n /**\n * Submit не прошёл валидацию. Без этого события «форма невалидна» и «ничего\n * не произошло» выглядят для потребителя одинаково.\n */\n (e: 'invalid', errors: Record<string, string>): void\n}\n\nconst props = withDefaults(\n defineProps<GrFormProps<TModel>>(),\n {\n rules: undefined,\n validateOnBlur: true,\n validateOnChange: false,\n scrollToError: true,\n scrollBehavior: 'smooth',\n disabled: false,\n },\n)\n\nconst emit = defineEmits<GrFormEmits<TModel>>()\n\nconst { t } = useGranularityTranslations()\n\n/**\n * Модель наружу дженерик, а адресация полей внутри работает по строковому пути.\n * Приведение безопасно: форма читает и пишет только по именам, объявленным\n * полями (`GrFormField name`), а не по всему объекту.\n */\nconst modelRecord = computed(() => props.model as Record<string, unknown>)\n\n// ————— Ошибки и реестр полей.\nconst errors = ref<Record<string, string | undefined>>({})\nconst fieldRegistry = new Map<string, () => HTMLElement | null>()\n\n/**\n * Поля, объявившие себя обязательными собственным пропом `required` — без\n * правила в `rules`. До этого они рисовали звёздочку, но submit пропускал их\n * пустыми: обязательность и валидация жили в разных местах.\n */\nconst selfRequiredFields = ref<Set<string>>(new Set())\n\n/** Поля с идущей асинхронной проверкой. */\nconst validatingSet = ref<Set<string>>(new Set())\nconst validatingFields = computed(() => validatingSet.value)\n\nfunction getRules(name: string): GrFormRule[] {\n return toRuleArray(props.rules?.[name])\n}\n\nfunction getValue(name: string): unknown {\n return getByPath(modelRecord.value, name)\n}\n\nconst requiredFields = computed(() => {\n const set = new Set<string>(selfRequiredFields.value)\n for (const name of Object.keys(props.rules ?? {})) {\n if (rulesRequired(getRules(name))) set.add(name)\n }\n return set\n})\n\n/** Все поля, которые форма обязана проверить: с правилами и обязательные без них. */\nconst validatedNames = computed(() => [\n ...new Set([...Object.keys(props.rules ?? {}), ...selfRequiredFields.value]),\n])\n\n/**\n * Правила поля с учётом неявной обязательности: `<GrFormField required>` без\n * записи в `rules` проверяется тем же `required`-правилом и тем же сообщением,\n * что и явное.\n */\nconst IMPLICIT_REQUIRED_RULE: GrFormRule = { required: true }\n\nfunction effectiveRules(name: string): GrFormRule[] {\n const rules = getRules(name)\n if (rules.length) return rules\n return selfRequiredFields.value.has(name) ? [IMPLICIT_REQUIRED_RULE] : []\n}\n\n// Дефолтные i18n-сообщения (перекрываются `rule.message`) — общие с любым\n// потребителем движка правил, не только с формой.\nconst resolveMessage = createGrFormMessageResolver(t)\n\n// ————— Валидация.\n// Счётчик поколений на имя поля: перекрывающиеся асинхронные прогоны пишут\n// результат в порядке РАЗРЕШЕНИЯ промисов, и без него медленный ответ про\n// старое значение затирал бы свежий (приём — `searchSeq` в GrAutocomplete).\nconst validationSeq = new Map<string, number>()\n// Последний стартовавший прогон поля: вытесненному нечего сказать о текущем\n// значении, и он отдаёт вердикт того, кто его вытеснил, — иначе `validate()`\n// собрал бы «валидно» из карты ошибок, куда новый прогон ещё не записал.\nconst validationRuns = new Map<string, { seq: number, promise: Promise<boolean> }>()\n\nasync function validateField(name: string, trigger?: GrFormTrigger): Promise<boolean> {\n if (trigger === 'blur' && !props.validateOnBlur) return !errors.value[name]\n\n const rules = rulesForTrigger(effectiveRules(name), trigger)\n if (!rules.length) return !errors.value[name]\n\n const seq = (validationSeq.get(name) ?? 0) + 1\n validationSeq.set(name, seq)\n\n const run = runValidation(name, seq, rules)\n validationRuns.set(name, { seq, promise: run })\n return run\n}\n\nasync function runValidation(name: string, seq: number, rules: GrFormRule[]): Promise<boolean> {\n // Признак «идёт проверка» нужен именно асинхронным правилам: без него поле\n // молчит до ответа сервера, и пользователь не знает, что что-то происходит.\n validatingSet.value = new Set(validatingSet.value).add(name)\n try {\n const message = await runFieldRules(getValue(name), rules, modelRecord.value, resolveMessage)\n\n // Устаревший прогон: его результат — про прежнее значение, не применять.\n if (validationSeq.get(name) !== seq) {\n const current = validationRuns.get(name)\n // Цепочка конечна: каждый следующий прогон новее предыдущего. Своего\n // прогона в реестре нет только после `clearValidate` — там проверять\n // нечего, форма уже чиста.\n return current && current.seq !== seq ? current.promise : !errors.value[name]\n }\n\n errors.value = { ...errors.value, [name]: message }\n emit('validate', name, !message, message)\n return !message\n }\n finally {\n if (validationSeq.get(name) === seq) {\n const next = new Set(validatingSet.value)\n next.delete(name)\n validatingSet.value = next\n }\n }\n}\n\nasync function validate(): Promise<boolean> {\n const results = await Promise.all(validatedNames.value.map(name => validateField(name)))\n const valid = results.every(Boolean)\n if (!valid && props.scrollToError) scrollToFirstError()\n return valid\n}\n\n/**\n * Отменить летящие проверки: их ответ относится к состоянию до сброса, и\n * записать его в очищенную форму значило бы вернуть пользователю ошибку,\n * которую он только что убрал. Заодно снимаем «проверяем» — ждать сервер,\n * чтобы погасить индикатор на сброшенном поле, не за чем.\n */\nfunction invalidateValidation(names?: string[]): void {\n const list = names ?? [...validationSeq.keys()]\n if (!list.length) return\n\n const nextValidating = new Set(validatingSet.value)\n for (const name of list) {\n validationSeq.set(name, (validationSeq.get(name) ?? 0) + 1)\n validationRuns.delete(name)\n nextValidating.delete(name)\n }\n validatingSet.value = nextValidating\n}\n\nfunction clearValidate(names?: string | string[]): void {\n if (!names) {\n invalidateValidation()\n errors.value = {}\n return\n }\n const list = Array.isArray(names) ? names : [names]\n invalidateValidation(list)\n const next = { ...errors.value }\n for (const name of list) delete next[name]\n errors.value = next\n}\n\nconst initialSnapshot = ref<Record<string, unknown>>(cloneModelValue(modelRecord.value))\n\n/**\n * Переснять «исходное» состояние. Нужен формам редактирования: модель там\n * наполняется после ответа сервера, а снимок в `setup` фиксировал пустой\n * объект — и `resetFields()` возвращал не «как было при загрузке», а пустоту.\n */\nfunction setSnapshot(model?: Record<string, unknown>): void {\n initialSnapshot.value = cloneModelValue((model ?? props.model) as Record<string, unknown>)\n}\n\n/**\n * Удаление ключа модели. Вынесено в функцию не ради красоты: модель — проп, и\n * прямое `delete props.model[key]` линтер справедливо считает мутацией пропа.\n * Мутируем мы при этом по контракту — `model` у формы и есть общий объект\n * данных приложения, ради которого форма и существует.\n */\nfunction removeKey(model: Record<string, unknown>, key: string): void {\n delete model[key]\n}\n\nfunction resetFields(names?: string | string[]): void {\n const snapshot = initialSnapshot.value\n const model = modelRecord.value\n const list = names ? (Array.isArray(names) ? names : [names]) : undefined\n\n // Ключи объединяем: поле, появившееся после снимка, надо **удалить**, а не\n // выставить в `undefined` — иначе «сброс» оставляет за собой мусор.\n const keys = list ?? [...new Set([...Object.keys(model), ...Object.keys(snapshot)])]\n\n // Метод не удаляем, даже если его нет в снимке. Снимок строится клоном, а клон\n // отбрасывает функции — то есть для внешней модели (`useForm` Inertia, стор)\n // «нет в снимке» означает «это её метод», и сброс снёс бы саму модель.\n for (const key of keys) {\n if (key in snapshot) setByPath(model, key, cloneModelValue(snapshot[key]))\n else if (typeof model[key] !== 'function') removeKey(model, key)\n }\n\n clearValidate(list)\n}\n\n/** Модель отличается от снимка. Файлы сравниваются отпечатком, а не ссылкой. */\nconst isDirty = computed(() => modelFingerprint(modelRecord.value) !== modelFingerprint(initialSnapshot.value))\n\n/**\n * Известных ошибок нет. Это не «валидация прошла»: до первого `validate()`\n * ошибок нет просто потому, что никто не проверял.\n */\nconst isValid = computed(() => Object.values(errors.value).every(message => !message))\n\n// ————— Scroll-to-error.\nfunction scrollToField(name: string): void {\n const el = fieldRegistry.get(name)?.()\n if (!el) return\n el.scrollIntoView({ behavior: props.scrollBehavior, block: 'center' })\n const focusable = el.querySelector<HTMLElement>('input, select, textarea, button, [tabindex]:not([tabindex=\"-1\"])')\n focusable?.focus?.()\n}\n\nfunction scrollToFirstError(): void {\n const elements = [...fieldRegistry.entries()]\n .filter(([name]) => errors.value[name])\n .map(([, getEl]) => getEl())\n .filter((el): el is HTMLElement => Boolean(el))\n\n // Первое по порядку в DOM — «самое верхнее» невалидное поле на экране.\n elements.sort((a, b) =>\n (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1,\n )\n\n const first = elements[0]\n if (!first) return\n first.scrollIntoView({ behavior: props.scrollBehavior, block: 'center' })\n first.querySelector<HTMLElement>('input, select, textarea, button, [tabindex]:not([tabindex=\"-1\"])')?.focus?.()\n}\n\n// ————— «Умный» change: чистим ошибку по мере исправления; валидируем при validateOnChange.\nlet stopWatchers: Array<() => void> = []\nwatch(\n // Ключ — строка имён, а не массив: идентичность массива меняется на каждый\n // пересчёт геттера, и все пер-полевые watcher'ы пересоздавались впустую.\n () => validatedNames.value.join(' '),\n () => {\n stopWatchers.forEach(stop => stop())\n stopWatchers = validatedNames.value.map(name =>\n watch(\n () => getValue(name),\n () => {\n if (props.validateOnChange) void validateField(name, 'change')\n else if (errors.value[name]) void validateField(name) // ре-валидация, чтобы снять ошибку\n },\n { deep: true },\n ),\n )\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => stopWatchers.forEach(stop => stop()))\n\n// ————— Контекст для `GrFormField`.\nprovide(GR_FORM_KEY, {\n errors,\n requiredFields,\n validatingFields,\n disabled: computed(() => props.disabled),\n hasField: (name: string) => effectiveRules(name).length > 0,\n registerField: (name, getEl, registration) => {\n fieldRegistry.set(name, getEl)\n\n const stopRequired = registration?.required\n ? watch(\n registration.required,\n (required) => {\n const next = new Set(selfRequiredFields.value)\n if (required) next.add(name)\n else next.delete(name)\n selfRequiredFields.value = next\n },\n { immediate: true },\n )\n : undefined\n\n return () => {\n fieldRegistry.delete(name)\n // Иначе счётчики поколений копятся на динамических именах\n // (`items.417.email`) до размонтирования формы.\n validationSeq.delete(name)\n validationRuns.delete(name)\n stopRequired?.()\n const next = new Set(selfRequiredFields.value)\n next.delete(name)\n selfRequiredFields.value = next\n }\n },\n validateField,\n})\n\nfunction onSubmit(): void {\n void validate().then((valid) => {\n if (valid) {\n emit('submit', props.model)\n return\n }\n\n const failed: Record<string, string> = {}\n for (const [name, message] of Object.entries(errors.value)) {\n if (message) failed[name] = message\n }\n emit('invalid', failed)\n })\n}\n\ndefineExpose({\n validate,\n validateField,\n clearValidate,\n resetFields,\n scrollToField,\n setSnapshot,\n isDirty,\n isValid,\n validatingFields,\n})\n</script>\n\n<template>\n <form data-gr-form novalidate @submit.prevent=\"onSubmit\">\n <slot\n :validate=\"validate\"\n :errors=\"errors\"\n :is-dirty=\"isDirty\"\n :is-valid=\"isValid\"\n :validating-fields=\"validatingFields\"\n :reset-fields=\"resetFields\"\n :set-snapshot=\"setSnapshot\"\n />\n </form>\n</template>\n","<script setup lang=\"ts\" generic=\"TModel extends object = Record<string, unknown>\">\nimport { computed, onBeforeUnmount, provide, ref, watch } from 'vue'\n\nimport { useGranularityTranslations } from '../../internal/granularityI18n'\nimport { GR_FORM_KEY } from './context'\nimport { cloneModelValue, modelFingerprint } from './modelSnapshot'\nimport {\n getByPath,\n createGrFormMessageResolver,\n rulesForTrigger,\n rulesRequired,\n runFieldRules,\n setByPath,\n toRuleArray,\n type GrFormRule,\n type GrFormRules,\n type GrFormTrigger,\n} from './validation'\n\nexport type {\n GrFormFileRule,\n GrFormRule,\n GrFormRules,\n GrFormTrigger,\n GrFormValidatorResult,\n} from './validation'\n\n/**\n * Публичный GR-примитив «Form» — оркестрация валидации над `GrFormField`.\n *\n * Модель формы (`v-model`-объект приложения) + декларативные `rules` по имени поля.\n * Форма прогоняет правила, раскладывает ошибки по контексту, скроллит к первой\n * ошибке и эмитит `submit` только при валидной форме. Императивный API — через\n * template ref (`validate` / `validateField` / `clearValidate` / `resetFields` /\n * `scrollToField`).\n */\nexport interface GrFormProps<TModel extends object = Record<string, unknown>> {\n /**\n * Реактивный объект данных формы. Поля адресуются по `name` (`GrFormField`),\n * в т.ч. dot-path.\n *\n * Тип дженерик, а не `Record<string, unknown>`: моделью бывает объект чужой\n * библиотеки (`useForm` Inertia, стор), у которого рядом с полями лежат\n * собственные методы. Под словарь он не подходит, и потребителю пришлось бы\n * приводить его через `as unknown as` в каждой форме.\n */\n model: TModel\n /** Правила валидации по имени поля: `{ email: [{ required: true, type: 'email' }] }`. */\n rules?: GrFormRules\n /** Валидировать поле при потере фокуса. */\n validateOnBlur?: boolean\n /** Валидировать поле при каждом изменении значения. */\n validateOnChange?: boolean\n /** Скроллить к первому невалидному полю после `validate()`. */\n scrollToError?: boolean\n scrollBehavior?: ScrollBehavior\n /**\n * Выключить форму целиком — типично на время отправки. Доезжает до контролов\n * через контекст поля, поэтому обходить их по одному не нужно.\n */\n disabled?: boolean\n}\n\nexport interface GrFormEmits<TModel extends object = Record<string, unknown>> {\n /** Форма прошла валидацию по submit. Отдаёт `model`. */\n (e: 'submit', model: TModel): void\n /** Результат валидации одного поля. */\n (e: 'validate', name: string, valid: boolean, message: string | undefined): void\n /**\n * Submit не прошёл валидацию. Без этого события «форма невалидна» и «ничего\n * не произошло» выглядят для потребителя одинаково.\n */\n (e: 'invalid', errors: Record<string, string>): void\n}\n\nconst props = withDefaults(\n defineProps<GrFormProps<TModel>>(),\n {\n rules: undefined,\n validateOnBlur: true,\n validateOnChange: false,\n scrollToError: true,\n scrollBehavior: 'smooth',\n disabled: false,\n },\n)\n\nconst emit = defineEmits<GrFormEmits<TModel>>()\n\nconst { t } = useGranularityTranslations()\n\n/**\n * Модель наружу дженерик, а адресация полей внутри работает по строковому пути.\n * Приведение безопасно: форма читает и пишет только по именам, объявленным\n * полями (`GrFormField name`), а не по всему объекту.\n */\nconst modelRecord = computed(() => props.model as Record<string, unknown>)\n\n// ————— Ошибки и реестр полей.\nconst errors = ref<Record<string, string | undefined>>({})\nconst fieldRegistry = new Map<string, () => HTMLElement | null>()\n\n/**\n * Поля, объявившие себя обязательными собственным пропом `required` — без\n * правила в `rules`. До этого они рисовали звёздочку, но submit пропускал их\n * пустыми: обязательность и валидация жили в разных местах.\n */\nconst selfRequiredFields = ref<Set<string>>(new Set())\n\n/** Поля с идущей асинхронной проверкой. */\nconst validatingSet = ref<Set<string>>(new Set())\nconst validatingFields = computed(() => validatingSet.value)\n\nfunction getRules(name: string): GrFormRule[] {\n return toRuleArray(props.rules?.[name])\n}\n\nfunction getValue(name: string): unknown {\n return getByPath(modelRecord.value, name)\n}\n\nconst requiredFields = computed(() => {\n const set = new Set<string>(selfRequiredFields.value)\n for (const name of Object.keys(props.rules ?? {})) {\n if (rulesRequired(getRules(name))) set.add(name)\n }\n return set\n})\n\n/** Все поля, которые форма обязана проверить: с правилами и обязательные без них. */\nconst validatedNames = computed(() => [\n ...new Set([...Object.keys(props.rules ?? {}), ...selfRequiredFields.value]),\n])\n\n/**\n * Правила поля с учётом неявной обязательности: `<GrFormField required>` без\n * записи в `rules` проверяется тем же `required`-правилом и тем же сообщением,\n * что и явное.\n */\nconst IMPLICIT_REQUIRED_RULE: GrFormRule = { required: true }\n\nfunction effectiveRules(name: string): GrFormRule[] {\n const rules = getRules(name)\n if (rules.length) return rules\n return selfRequiredFields.value.has(name) ? [IMPLICIT_REQUIRED_RULE] : []\n}\n\n// Дефолтные i18n-сообщения (перекрываются `rule.message`) — общие с любым\n// потребителем движка правил, не только с формой.\nconst resolveMessage = createGrFormMessageResolver(t)\n\n// ————— Валидация.\n// Счётчик поколений на имя поля: перекрывающиеся асинхронные прогоны пишут\n// результат в порядке РАЗРЕШЕНИЯ промисов, и без него медленный ответ про\n// старое значение затирал бы свежий (приём — `searchSeq` в GrAutocomplete).\nconst validationSeq = new Map<string, number>()\n// Последний стартовавший прогон поля: вытесненному нечего сказать о текущем\n// значении, и он отдаёт вердикт того, кто его вытеснил, — иначе `validate()`\n// собрал бы «валидно» из карты ошибок, куда новый прогон ещё не записал.\nconst validationRuns = new Map<string, { seq: number, promise: Promise<boolean> }>()\n\nasync function validateField(name: string, trigger?: GrFormTrigger): Promise<boolean> {\n if (trigger === 'blur' && !props.validateOnBlur) return !errors.value[name]\n\n const rules = rulesForTrigger(effectiveRules(name), trigger)\n if (!rules.length) return !errors.value[name]\n\n const seq = (validationSeq.get(name) ?? 0) + 1\n validationSeq.set(name, seq)\n\n const run = runValidation(name, seq, rules)\n validationRuns.set(name, { seq, promise: run })\n return run\n}\n\nasync function runValidation(name: string, seq: number, rules: GrFormRule[]): Promise<boolean> {\n // Признак «идёт проверка» нужен именно асинхронным правилам: без него поле\n // молчит до ответа сервера, и пользователь не знает, что что-то происходит.\n validatingSet.value = new Set(validatingSet.value).add(name)\n try {\n const message = await runFieldRules(getValue(name), rules, modelRecord.value, resolveMessage)\n\n // Устаревший прогон: его результат — про прежнее значение, не применять.\n if (validationSeq.get(name) !== seq) {\n const current = validationRuns.get(name)\n // Цепочка конечна: каждый следующий прогон новее предыдущего. Своего\n // прогона в реестре нет только после `clearValidate` — там проверять\n // нечего, форма уже чиста.\n return current && current.seq !== seq ? current.promise : !errors.value[name]\n }\n\n errors.value = { ...errors.value, [name]: message }\n emit('validate', name, !message, message)\n return !message\n }\n finally {\n if (validationSeq.get(name) === seq) {\n const next = new Set(validatingSet.value)\n next.delete(name)\n validatingSet.value = next\n }\n }\n}\n\nasync function validate(): Promise<boolean> {\n const results = await Promise.all(validatedNames.value.map(name => validateField(name)))\n const valid = results.every(Boolean)\n if (!valid && props.scrollToError) scrollToFirstError()\n return valid\n}\n\n/**\n * Отменить летящие проверки: их ответ относится к состоянию до сброса, и\n * записать его в очищенную форму значило бы вернуть пользователю ошибку,\n * которую он только что убрал. Заодно снимаем «проверяем» — ждать сервер,\n * чтобы погасить индикатор на сброшенном поле, не за чем.\n */\nfunction invalidateValidation(names?: string[]): void {\n const list = names ?? [...validationSeq.keys()]\n if (!list.length) return\n\n const nextValidating = new Set(validatingSet.value)\n for (const name of list) {\n validationSeq.set(name, (validationSeq.get(name) ?? 0) + 1)\n validationRuns.delete(name)\n nextValidating.delete(name)\n }\n validatingSet.value = nextValidating\n}\n\nfunction clearValidate(names?: string | string[]): void {\n if (!names) {\n invalidateValidation()\n errors.value = {}\n return\n }\n const list = Array.isArray(names) ? names : [names]\n invalidateValidation(list)\n const next = { ...errors.value }\n for (const name of list) delete next[name]\n errors.value = next\n}\n\nconst initialSnapshot = ref<Record<string, unknown>>(cloneModelValue(modelRecord.value))\n\n/**\n * Переснять «исходное» состояние. Нужен формам редактирования: модель там\n * наполняется после ответа сервера, а снимок в `setup` фиксировал пустой\n * объект — и `resetFields()` возвращал не «как было при загрузке», а пустоту.\n */\nfunction setSnapshot(model?: Record<string, unknown>): void {\n initialSnapshot.value = cloneModelValue((model ?? props.model) as Record<string, unknown>)\n}\n\n/**\n * Удаление ключа модели. Вынесено в функцию не ради красоты: модель — проп, и\n * прямое `delete props.model[key]` линтер справедливо считает мутацией пропа.\n * Мутируем мы при этом по контракту — `model` у формы и есть общий объект\n * данных приложения, ради которого форма и существует.\n */\nfunction removeKey(model: Record<string, unknown>, key: string): void {\n delete model[key]\n}\n\nfunction resetFields(names?: string | string[]): void {\n const snapshot = initialSnapshot.value\n const model = modelRecord.value\n const list = names ? (Array.isArray(names) ? names : [names]) : undefined\n\n // Ключи объединяем: поле, появившееся после снимка, надо **удалить**, а не\n // выставить в `undefined` — иначе «сброс» оставляет за собой мусор.\n const keys = list ?? [...new Set([...Object.keys(model), ...Object.keys(snapshot)])]\n\n // Метод не удаляем, даже если его нет в снимке. Снимок строится клоном, а клон\n // отбрасывает функции — то есть для внешней модели (`useForm` Inertia, стор)\n // «нет в снимке» означает «это её метод», и сброс снёс бы саму модель.\n for (const key of keys) {\n if (key in snapshot) setByPath(model, key, cloneModelValue(snapshot[key]))\n else if (typeof model[key] !== 'function') removeKey(model, key)\n }\n\n clearValidate(list)\n}\n\n/** Модель отличается от снимка. Файлы сравниваются отпечатком, а не ссылкой. */\nconst isDirty = computed(() => modelFingerprint(modelRecord.value) !== modelFingerprint(initialSnapshot.value))\n\n/**\n * Известных ошибок нет. Это не «валидация прошла»: до первого `validate()`\n * ошибок нет просто потому, что никто не проверял.\n */\nconst isValid = computed(() => Object.values(errors.value).every(message => !message))\n\n// ————— Scroll-to-error.\nfunction scrollToField(name: string): void {\n const el = fieldRegistry.get(name)?.()\n if (!el) return\n el.scrollIntoView({ behavior: props.scrollBehavior, block: 'center' })\n const focusable = el.querySelector<HTMLElement>('input, select, textarea, button, [tabindex]:not([tabindex=\"-1\"])')\n focusable?.focus?.()\n}\n\nfunction scrollToFirstError(): void {\n const elements = [...fieldRegistry.entries()]\n .filter(([name]) => errors.value[name])\n .map(([, getEl]) => getEl())\n .filter((el): el is HTMLElement => Boolean(el))\n\n // Первое по порядку в DOM — «самое верхнее» невалидное поле на экране.\n elements.sort((a, b) =>\n (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1,\n )\n\n const first = elements[0]\n if (!first) return\n first.scrollIntoView({ behavior: props.scrollBehavior, block: 'center' })\n first.querySelector<HTMLElement>('input, select, textarea, button, [tabindex]:not([tabindex=\"-1\"])')?.focus?.()\n}\n\n// ————— «Умный» change: чистим ошибку по мере исправления; валидируем при validateOnChange.\nlet stopWatchers: Array<() => void> = []\nwatch(\n // Ключ — строка имён, а не массив: идентичность массива меняется на каждый\n // пересчёт геттера, и все пер-полевые watcher'ы пересоздавались впустую.\n () => validatedNames.value.join(' '),\n () => {\n stopWatchers.forEach(stop => stop())\n stopWatchers = validatedNames.value.map(name =>\n watch(\n () => getValue(name),\n () => {\n if (props.validateOnChange) void validateField(name, 'change')\n else if (errors.value[name]) void validateField(name) // ре-валидация, чтобы снять ошибку\n },\n { deep: true },\n ),\n )\n },\n { immediate: true },\n)\n\nonBeforeUnmount(() => stopWatchers.forEach(stop => stop()))\n\n// ————— Контекст для `GrFormField`.\nprovide(GR_FORM_KEY, {\n errors,\n requiredFields,\n validatingFields,\n disabled: computed(() => props.disabled),\n hasField: (name: string) => effectiveRules(name).length > 0,\n registerField: (name, getEl, registration) => {\n fieldRegistry.set(name, getEl)\n\n const stopRequired = registration?.required\n ? watch(\n registration.required,\n (required) => {\n const next = new Set(selfRequiredFields.value)\n if (required) next.add(name)\n else next.delete(name)\n selfRequiredFields.value = next\n },\n { immediate: true },\n )\n : undefined\n\n return () => {\n fieldRegistry.delete(name)\n // Иначе счётчики поколений копятся на динамических именах\n // (`items.417.email`) до размонтирования формы.\n validationSeq.delete(name)\n validationRuns.delete(name)\n stopRequired?.()\n const next = new Set(selfRequiredFields.value)\n next.delete(name)\n selfRequiredFields.value = next\n }\n },\n validateField,\n})\n\nfunction onSubmit(): void {\n void validate().then((valid) => {\n if (valid) {\n emit('submit', props.model)\n return\n }\n\n const failed: Record<string, string> = {}\n for (const [name, message] of Object.entries(errors.value)) {\n if (message) failed[name] = message\n }\n emit('invalid', failed)\n })\n}\n\ndefineExpose({\n validate,\n validateField,\n clearValidate,\n resetFields,\n scrollToField,\n setSnapshot,\n isDirty,\n isValid,\n validatingFields,\n})\n</script>\n\n<template>\n <form data-gr-form novalidate @submit.prevent=\"onSubmit\">\n <slot\n :validate=\"validate\"\n :errors=\"errors\"\n :is-dirty=\"isDirty\"\n :is-valid=\"isValid\"\n :validating-fields=\"validatingFields\"\n :reset-fields=\"resetFields\"\n :set-snapshot=\"setSnapshot\"\n />\n </form>\n</template>\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"GrIcon-bQwtZtYT.js","names":[],"sources":["../../../../src/components/GrIcon/GrIcon.vue","../../../../src/components/GrIcon/GrIcon.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport {\n grIconToneClass,\n iconBaseClass,\n iconSizeVarBySize,\n iconSpinClass,\n type GrIconSize,\n type GrIconTone,\n} from './grIconStyles'\n\nexport type { GrIconSize, GrIconTone } from './grIconStyles'\n\nexport interface GrIconProps {\n /** Размер по шкале пакета либо произвольный в пикселях. */\n size?: GrIconSize | number\n /**\n * Имя значимой иконки. Задан — иконка объявляется `role=\"img\"` и перестаёт\n * быть скрытой. Не задан — иконка декоративна.\n */\n label?: string\n /** Цвет из палитры. `current` — наследовать цвет текста родителя. */\n tone?: GrIconTone\n /** Вращение — для спиннеров. */\n spin?: boolean\n}\n\nconst props = withDefaults(\n defineProps<GrIconProps>(),\n {\n size: undefined,\n label: undefined,\n tone: 'current',\n spin: false,\n },\n)\n\n// Число — «локальный» escape-hatch мимо конфига; шкала идёт через провайдер.\nconst resolvedScaleSize = useGrComponentSize(\n () => (typeof props.size === 'number' ? undefined : props.size),\n { component: 'GrIcon' },\n)\n\nconst iconStyle = computed(() => ({\n '--gr-icon-size': typeof props.size === 'number'\n ? `${props.size}px`\n : iconSizeVarBySize[resolvedScaleSize.value],\n} as Record<string, string>))\n\nconst iconClass = computed(() => [\n iconBaseClass,\n grIconToneClass(props.tone),\n props.spin ? iconSpinClass : '',\n].filter(Boolean))\n\n/**\n * Иконка декоративна по умолчанию.\n *\n * В библиотеке она почти всегда сопровождает текст, и каждое место вызова\n * ставило `aria-hidden` вручную. Достаточно забыть один раз — и диктор\n * прочитает `<title>` из SVG вместо ничего. Значимой иконку делает `label`:\n * тогда у неё появляются роль и имя, а скрытие снимается.\n *\n * Переопределить это потребитель по-прежнему может: fallthrough-атрибут\n * сильнее собственной привязки.\n */\nconst ariaHidden = computed(() => (props.label ? undefined : 'true'))\n</script>\n\n<template>\n <span\n data-gr-icon\n :class=\"iconClass\"\n :style=\"iconStyle\"\n :role=\"label ? 'img' : undefined\"\n :aria-label=\"label\"\n :aria-hidden=\"ariaHidden\"\n >\n <slot />\n </span>\n</template>\n\n<style>\n/*\n * Стиль намеренно глобальный, а не scoped: иконка приходит слотом (SVG\n * потребителя), и scoped-правило до него не достаёт — пришлось бы писать\n * `:deep` в каждом месте вызова.\n *\n * Размер живёт в одной переменной: и обёртка, и вложенный SVG считают себя от\n * неё, поэтому шкала настраивается темой, а не пропами разметки.\n */\n:where(.gr-icon) {\n --gr-icon-size: var(--gr-icon-size-md, 18px);\n width: var(--gr-icon-size);\n min-width: var(--gr-icon-size);\n height: var(--gr-icon-size);\n line-height: 0;\n flex: none;\n}\n\n:where(.gr-icon svg) {\n width: 100%;\n height: 100%;\n display: block;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\n\nimport { useGrComponentSize } from '../GrConfigProvider/context'\nimport {\n grIconToneClass,\n iconBaseClass,\n iconSizeVarBySize,\n iconSpinClass,\n type GrIconSize,\n type GrIconTone,\n} from './grIconStyles'\n\nexport type { GrIconSize, GrIconTone } from './grIconStyles'\n\nexport interface GrIconProps {\n /** Размер по шкале пакета либо произвольный в пикселях. */\n size?: GrIconSize | number\n /**\n * Имя значимой иконки. Задан — иконка объявляется `role=\"img\"` и перестаёт\n * быть скрытой. Не задан — иконка декоративна.\n */\n label?: string\n /** Цвет из палитры. `current` — наследовать цвет текста родителя. */\n tone?: GrIconTone\n /** Вращение — для спиннеров. */\n spin?: boolean\n}\n\nconst props = withDefaults(\n defineProps<GrIconProps>(),\n {\n size: undefined,\n label: undefined,\n tone: 'current',\n spin: false,\n },\n)\n\n// Число — «локальный» escape-hatch мимо конфига; шкала идёт через провайдер.\nconst resolvedScaleSize = useGrComponentSize(\n () => (typeof props.size === 'number' ? undefined : props.size),\n { component: 'GrIcon' },\n)\n\nconst iconStyle = computed(() => ({\n '--gr-icon-size': typeof props.size === 'number'\n ? `${props.size}px`\n : iconSizeVarBySize[resolvedScaleSize.value],\n} as Record<string, string>))\n\nconst iconClass = computed(() => [\n iconBaseClass,\n grIconToneClass(props.tone),\n props.spin ? iconSpinClass : '',\n].filter(Boolean))\n\n/**\n * Иконка декоративна по умолчанию.\n *\n * В библиотеке она почти всегда сопровождает текст, и каждое место вызова\n * ставило `aria-hidden` вручную. Достаточно забыть один раз — и диктор\n * прочитает `<title>` из SVG вместо ничего. Значимой иконку делает `label`:\n * тогда у неё появляются роль и имя, а скрытие снимается.\n *\n * Переопределить это потребитель по-прежнему может: fallthrough-атрибут\n * сильнее собственной привязки.\n */\nconst ariaHidden = computed(() => (props.label ? undefined : 'true'))\n</script>\n\n<template>\n <span\n data-gr-icon\n :class=\"iconClass\"\n :style=\"iconStyle\"\n :role=\"label ? 'img' : undefined\"\n :aria-label=\"label\"\n :aria-hidden=\"ariaHidden\"\n >\n <slot />\n </span>\n</template>\n\n<style>\n/*\n * Стиль намеренно глобальный, а не scoped: иконка приходит слотом (SVG\n * потребителя), и scoped-правило до него не достаёт — пришлось бы писать\n * `:deep` в каждом месте вызова.\n *\n * Размер живёт в одной переменной: и обёртка, и вложенный SVG считают себя от\n * неё, поэтому шкала настраивается темой, а не пропами разметки.\n */\n:where(.gr-icon) {\n --gr-icon-size: var(--gr-icon-size-md, 18px);\n width: var(--gr-icon-size);\n min-width: var(--gr-icon-size);\n height: var(--gr-icon-size);\n line-height: 0;\n flex: none;\n}\n\n:where(.gr-icon svg) {\n width: 100%;\n height: 100%;\n display: block;\n}\n</style>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;EA6BA,MAAM,QAAQ;EAWd,MAAM,oBAAoB,yBACjB,OAAO,MAAM,SAAS,WAAW,KAAA,IAAY,MAAM,MAC1D,EAAE,WAAW,SAAS,CACxB;EAEA,MAAM,YAAY,gBAAgB,EAChC,kBAAkB,OAAO,MAAM,SAAS,WACpC,GAAG,MAAM,KAAK,MACd,kBAAkB,kBAAkB,OAC1C,EAA4B;EAE5B,MAAM,YAAY,eAAe;GAC/B;GACA,gBAAgB,MAAM,IAAI;GAC1B,MAAM,OAAO,gBAAgB;EAC/B,CAAC,CAAC,OAAO,OAAO,CAAC;;;;;;;;;;;;EAajB,MAAM,aAAa,eAAgB,MAAM,QAAQ,KAAA,IAAY,MAAO;;uBAIlE,mBASO,QAAA;IARL,gBAAA;IACC,OAAK,eAAE,UAAA,KAAS;IAChB,OAAK,eAAE,UAAA,KAAS;IAChB,MAAM,QAAA,QAAK,QAAW,KAAA;IACtB,cAAY,QAAA;IACZ,eAAa,WAAA;OAEd,WAAQ,KAAA,QAAA,SAAA,CAAA,GAAA,IAAA,UAAA"}