react-grab 0.1.28 → 0.1.30

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 (432) hide show
  1. package/README.md +8 -138
  2. package/dist/core/index.cjs +9 -1
  3. package/dist/core/index.d.cts +11 -3
  4. package/dist/core/index.d.ts +11 -3
  5. package/dist/core/index.js +9 -1
  6. package/dist/core--H_JZk7a.js +16 -0
  7. package/dist/core-1AoeBJ2R.cjs +4386 -0
  8. package/dist/core-4VC4A94S.js +4249 -0
  9. package/dist/core-5Q_6LVh_.cjs +16 -0
  10. package/dist/core-6sOn3YNs.js +16 -0
  11. package/dist/core-B3FYVaHv.cjs +16 -0
  12. package/dist/core-B3I0upO1.js +4250 -0
  13. package/dist/core-B3ndcALq.cjs +4386 -0
  14. package/dist/core-B9GWVp1Q.js +16 -0
  15. package/dist/core-BGIMywNa.js +16 -0
  16. package/dist/core-BGK4C6ju.js +16 -0
  17. package/dist/core-BGXprTx7.cjs +16 -0
  18. package/dist/core-BKt5SHzo.js +16 -0
  19. package/dist/core-BMObVYUv.cjs +16 -0
  20. package/dist/core-BNMx90Sn.js +16 -0
  21. package/dist/core-BWQ6C5g9.js +4268 -0
  22. package/dist/core-BcwRbSfO.js +16 -0
  23. package/dist/core-Be-1ubQn.cjs +16 -0
  24. package/dist/core-BfpPi7c6.cjs +16 -0
  25. package/dist/core-BiIoWLRk.js +16 -0
  26. package/dist/core-BjpyJHlW.js +16 -0
  27. package/dist/core-Bqf3D4Ra.cjs +16 -0
  28. package/dist/core-Bs0wekHY.cjs +4284 -0
  29. package/dist/core-Bvqgv6Zr.js +16 -0
  30. package/dist/core-Bw0-Cecq.cjs +16 -0
  31. package/dist/core-BzRpJ5QI.cjs +4284 -0
  32. package/dist/core-C0ZgNdUR.cjs +4386 -0
  33. package/dist/core-C191WXKe.cjs +16 -0
  34. package/dist/core-C4yYleJn.js +16 -0
  35. package/dist/core-C758xgeI.js +16 -0
  36. package/dist/core-CAZ8ENTv.js +16 -0
  37. package/dist/core-CBUFmwfx.cjs +4386 -0
  38. package/dist/core-CDV48I9C.js +4249 -0
  39. package/dist/core-CGXCsSkm.js +4280 -0
  40. package/dist/core-CHsFU9FZ.js +16 -0
  41. package/dist/core-CJOQfSzq.js +4495 -0
  42. package/dist/core-CLW9tl4L.js +4249 -0
  43. package/dist/core-CP1yCnSB.js +16 -0
  44. package/dist/core-CRLyvQCt.cjs +16 -0
  45. package/dist/core-CZX3EijL.js +16 -0
  46. package/dist/core-Ccli-yLf.cjs +16 -0
  47. package/dist/core-Ce4pBUSh.js +16 -0
  48. package/dist/core-CgCGjXfB.cjs +16 -0
  49. package/dist/core-CiQl2PfF.cjs +16 -0
  50. package/dist/core-CnPpGWUc.js +16 -0
  51. package/dist/core-Co9954wQ.cjs +16 -0
  52. package/dist/core-Cr4qVf2a.js +16 -0
  53. package/dist/core-CrQCbm00.js +16 -0
  54. package/dist/core-CsCg35MW.js +16 -0
  55. package/dist/core-Cshs0orb.js +16 -0
  56. package/dist/core-CthjfoZX.cjs +16 -0
  57. package/dist/core-CtvavOAt.cjs +16 -0
  58. package/dist/core-CvoFTVjy.cjs +16 -0
  59. package/dist/core-CzE8I9NL.cjs +16 -0
  60. package/dist/core-CzGijRTx.js +16 -0
  61. package/dist/core-CzosrDdO.cjs +16 -0
  62. package/dist/core-D--fM7Xq.cjs +16 -0
  63. package/dist/core-D-UGQb_Z.cjs +16 -0
  64. package/dist/core-D0UqPwu_.cjs +16 -0
  65. package/dist/core-D2LzIluw.js +4495 -0
  66. package/dist/core-D4z4W-Qz.cjs +16 -0
  67. package/dist/core-D7NwJuzy.js +16 -0
  68. package/dist/core-DCqMIKkK.js +16 -0
  69. package/dist/core-DFrvwczh.cjs +4284 -0
  70. package/dist/core-DGxxKKPR.cjs +16 -0
  71. package/dist/core-DGyQeEXa.js +4495 -0
  72. package/dist/core-DH8Uvag-.js +4249 -0
  73. package/dist/core-DHZBYfsC.js +16 -0
  74. package/dist/core-DKVj078o.js +4249 -0
  75. package/dist/core-DMRsaGr7.js +16 -0
  76. package/dist/core-DRUnXCNA.cjs +16 -0
  77. package/dist/core-DRlG4zYm.cjs +16 -0
  78. package/dist/core-DSqJwwdV.cjs +4284 -0
  79. package/dist/core-DXqmRz53.cjs +16 -0
  80. package/dist/core-DcRxqPad.js +16 -0
  81. package/dist/core-DdNOX4pt.js +16 -0
  82. package/dist/core-Df7CMRnd.cjs +4315 -0
  83. package/dist/core-DiIZA6Hx.js +4495 -0
  84. package/dist/core-DiVnlonK.cjs +4284 -0
  85. package/dist/core-Dj1WV911.js +4495 -0
  86. package/dist/core-DjPDxMID.cjs +16 -0
  87. package/dist/core-DjcnHWor.cjs +16 -0
  88. package/dist/core-DkWjrEUZ.cjs +16 -0
  89. package/dist/core-Dq-CCsij.cjs +4303 -0
  90. package/dist/core-DsVAkMs2.js +16 -0
  91. package/dist/core-DueMb4P6.js +4249 -0
  92. package/dist/core-DvJt5JmX.js +16 -0
  93. package/dist/core-Dz8Hrc33.js +4249 -0
  94. package/dist/core-ESHKG2mL.cjs +4285 -0
  95. package/dist/core-Ij_B_RWV.cjs +16 -0
  96. package/dist/core-JyczI7kP.cjs +16 -0
  97. package/dist/core-K0XuILjf.cjs +4284 -0
  98. package/dist/core-N9HyYpZv.cjs +16 -0
  99. package/dist/core-PW2DC2Tb.js +4495 -0
  100. package/dist/core-Q84EBsQ8.cjs +16 -0
  101. package/dist/core-TSuD8D7m.js +16 -0
  102. package/dist/core-WN76m9V0.cjs +16 -0
  103. package/dist/core-YRKn-0AV.js +16 -0
  104. package/dist/core-fC6GdbUJ.js +16 -0
  105. package/dist/core-h5q7bqH-.cjs +4284 -0
  106. package/dist/core-hkgBRD_T.js +16 -0
  107. package/dist/core-k9l5c9Hk.cjs +16 -0
  108. package/dist/core-mNhkpUYQ.cjs +16 -0
  109. package/dist/core-qCvYE9Ox.cjs +4386 -0
  110. package/dist/core-rvs2FEMH.js +16 -0
  111. package/dist/core-sXzUCmoJ.js +16 -0
  112. package/dist/core-t7gaYHyj.cjs +4386 -0
  113. package/dist/core-thci-YqL.js +16 -0
  114. package/dist/core-xokESdbC.cjs +16 -0
  115. package/dist/core-yW0MN96-.cjs +16 -0
  116. package/dist/core-ydFCYlV4.js +16 -0
  117. package/dist/core-zQ4jjKHw.cjs +16 -0
  118. package/dist/extract-element-css-B-R_28uM.cjs +10 -0
  119. package/dist/extract-element-css-B732tro7.js +10 -0
  120. package/dist/extract-element-css-B9Xh1wUd.js +10 -0
  121. package/dist/extract-element-css-BGZPWnck.js +10 -0
  122. package/dist/extract-element-css-BIniUwQh.js +319 -0
  123. package/dist/extract-element-css-BOQUDYB3.cjs +10 -0
  124. package/dist/extract-element-css-BTzDGIs3.cjs +336 -0
  125. package/dist/extract-element-css-BWUnsvjZ.js +10 -0
  126. package/dist/extract-element-css-BceTcL6y.cjs +10 -0
  127. package/dist/extract-element-css-Bi1y8V4z.cjs +336 -0
  128. package/dist/extract-element-css-Bra6hEzg.js +319 -0
  129. package/dist/extract-element-css-BuJ3zqGO.js +10 -0
  130. package/dist/extract-element-css-C8lBuGP7.js +10 -0
  131. package/dist/extract-element-css-CBHVjrBq.cjs +10 -0
  132. package/dist/extract-element-css-CGxXdwim.js +10 -0
  133. package/dist/extract-element-css-CJx4cesM.js +10 -0
  134. package/dist/extract-element-css-CQBJAbFD.cjs +10 -0
  135. package/dist/extract-element-css-CQV8FsMB.cjs +10 -0
  136. package/dist/extract-element-css-CQx4Biqa.cjs +336 -0
  137. package/dist/extract-element-css-CTy2pRfA.js +10 -0
  138. package/dist/extract-element-css-CchtITXx.cjs +336 -0
  139. package/dist/extract-element-css-CjY9vDS6.js +10 -0
  140. package/dist/extract-element-css-ClnG20sN.cjs +10 -0
  141. package/dist/extract-element-css-CmMetO-q.cjs +10 -0
  142. package/dist/extract-element-css-CmOD6UeE.cjs +10 -0
  143. package/dist/extract-element-css-CnY9b0vB.js +10 -0
  144. package/dist/extract-element-css-CoQLNjVI.js +10 -0
  145. package/dist/extract-element-css-CqjmXl0Y.cjs +10 -0
  146. package/dist/extract-element-css-Cr29xtzW.cjs +10 -0
  147. package/dist/extract-element-css-CzNVoJEM.js +319 -0
  148. package/dist/extract-element-css-CzgC7nM9.cjs +10 -0
  149. package/dist/extract-element-css-D3Dy-3Qz.js +10 -0
  150. package/dist/extract-element-css-D5qqKVc-.cjs +10 -0
  151. package/dist/extract-element-css-D5zsPw09.cjs +10 -0
  152. package/dist/extract-element-css-D6UwJjf4.cjs +336 -0
  153. package/dist/extract-element-css-DEuA2W6G.js +10 -0
  154. package/dist/extract-element-css-DKkUiIlS.cjs +10 -0
  155. package/dist/extract-element-css-DM0EhhXw.cjs +10 -0
  156. package/dist/extract-element-css-DPA6C_o-.cjs +10 -0
  157. package/dist/extract-element-css-DU45xRGh.js +10 -0
  158. package/dist/extract-element-css-DUvYlz4T.js +10 -0
  159. package/dist/extract-element-css-DVDr5Tn6.cjs +10 -0
  160. package/dist/extract-element-css-Di9hCigW.js +319 -0
  161. package/dist/extract-element-css-DivFxCRt.js +319 -0
  162. package/dist/extract-element-css-DlDbU4YM.cjs +10 -0
  163. package/dist/extract-element-css-DsssOqcQ.cjs +10 -0
  164. package/dist/extract-element-css-EnvrIHtf.cjs +336 -0
  165. package/dist/extract-element-css-FI71J_KB.js +10 -0
  166. package/dist/extract-element-css-GdDDlzTf.js +10 -0
  167. package/dist/extract-element-css-U3MgLHty.cjs +10 -0
  168. package/dist/extract-element-css-U4oxl-UP.js +10 -0
  169. package/dist/extract-element-css-VyMIgOZy.js +10 -0
  170. package/dist/extract-element-css-XGv0WWIL.js +319 -0
  171. package/dist/extract-element-css-Y-x4luJL.cjs +10 -0
  172. package/dist/extract-element-css-Zz_CgLqY.js +319 -0
  173. package/dist/extract-element-css-_aFPl5y4.cjs +336 -0
  174. package/dist/extract-element-css-_uZRVqCT.cjs +10 -0
  175. package/dist/extract-element-css-i8nzXODQ.js +10 -0
  176. package/dist/extract-element-css-jh1iLRzJ.js +10 -0
  177. package/dist/extract-element-css-nkJQc3j1.js +10 -0
  178. package/dist/freeze-updates--K1ecmFi.cjs +44 -0
  179. package/dist/freeze-updates-1FTXgIdb.js +44 -0
  180. package/dist/freeze-updates-3QjTocF-.cjs +2267 -0
  181. package/dist/freeze-updates-81f5sY45.js +44 -0
  182. package/dist/freeze-updates-B1mPDmJB.js +44 -0
  183. package/dist/freeze-updates-B5h8teL6.cjs +44 -0
  184. package/dist/freeze-updates-BAYe0Nlx.js +44 -0
  185. package/dist/freeze-updates-BDhlBp3V.js +44 -0
  186. package/dist/freeze-updates-BGa9CqrW.cjs +2267 -0
  187. package/dist/freeze-updates-BQH6Y8E1.cjs +44 -0
  188. package/dist/freeze-updates-BQjWBzy4.cjs +53 -0
  189. package/dist/freeze-updates-BSOSfpXo.js +44 -0
  190. package/dist/freeze-updates-BT-s67nK.js +53 -0
  191. package/dist/freeze-updates-BUJeYIm5.js +44 -0
  192. package/dist/freeze-updates-BVDrqUzf.js +2498 -0
  193. package/dist/freeze-updates-BVX0QSXz.cjs +44 -0
  194. package/dist/freeze-updates-BXMr6a9g.cjs +2912 -0
  195. package/dist/freeze-updates-BZpmCVDl.cjs +2267 -0
  196. package/dist/freeze-updates-BbbID39H.js +1866 -0
  197. package/dist/freeze-updates-BdnJ5RrP.js +1866 -0
  198. package/dist/freeze-updates-Bj59uWit.cjs +44 -0
  199. package/dist/freeze-updates-Bla3E0Kv.js +53 -0
  200. package/dist/freeze-updates-BoYyIB3V.cjs +44 -0
  201. package/dist/freeze-updates-C2TqDiTp.cjs +44 -0
  202. package/dist/freeze-updates-C6Tg4EoW.js +44 -0
  203. package/dist/freeze-updates-C7c9TRvJ.cjs +44 -0
  204. package/dist/freeze-updates-CPNAwtsl.cjs +2267 -0
  205. package/dist/freeze-updates-CTP39zuf.js +44 -0
  206. package/dist/freeze-updates-Cm3EVm_J.cjs +53 -0
  207. package/dist/freeze-updates-CnSZEKoI.cjs +44 -0
  208. package/dist/freeze-updates-CrKe4F0s.js +44 -0
  209. package/dist/freeze-updates-CtYFeM4D.cjs +2267 -0
  210. package/dist/freeze-updates-CxYFvPj9.cjs +53 -0
  211. package/dist/freeze-updates-D10Qj9Ec.cjs +44 -0
  212. package/dist/freeze-updates-D6o46vBw.cjs +44 -0
  213. package/dist/freeze-updates-D7XFQ3_T.js +53 -0
  214. package/dist/freeze-updates-D8H25gFt.js +44 -0
  215. package/dist/freeze-updates-DCpGX7lt.cjs +44 -0
  216. package/dist/freeze-updates-DG3hLEL2.cjs +44 -0
  217. package/dist/freeze-updates-DO_M76qf.js +44 -0
  218. package/dist/freeze-updates-Db4Id665.cjs +2267 -0
  219. package/dist/freeze-updates-DbL_EXkN.js +1866 -0
  220. package/dist/freeze-updates-DcvNGCcR.cjs +44 -0
  221. package/dist/freeze-updates-Dh4GiYXz.cjs +44 -0
  222. package/dist/freeze-updates-DkKJK_nh.cjs +44 -0
  223. package/dist/freeze-updates-DmB-ndqy.cjs +44 -0
  224. package/dist/freeze-updates-DnAA3QYp.cjs +44 -0
  225. package/dist/freeze-updates-Dpj8jndD.js +44 -0
  226. package/dist/freeze-updates-DuHXIi3M.js +44 -0
  227. package/dist/freeze-updates-DwERlFID.js +1866 -0
  228. package/dist/freeze-updates-HHyWtz8f.cjs +44 -0
  229. package/dist/freeze-updates-JRZCAR0q.js +1866 -0
  230. package/dist/freeze-updates-KLyCac_c.js +44 -0
  231. package/dist/freeze-updates-MaNDvTJS.js +1866 -0
  232. package/dist/freeze-updates-REe44rww.js +44 -0
  233. package/dist/freeze-updates-TPRkNnYY.js +44 -0
  234. package/dist/freeze-updates-WfKs4yF4.js +44 -0
  235. package/dist/freeze-updates-d9yH0V6A.cjs +44 -0
  236. package/dist/freeze-updates-nzZkxjqN.js +44 -0
  237. package/dist/freeze-updates-q_DMlHq7.js +44 -0
  238. package/dist/index-0hhKx6KA.d.ts +534 -0
  239. package/dist/index-5oOhE8Ae.d.cts +123 -0
  240. package/dist/index-BA23Z7zi.d.ts +77 -0
  241. package/dist/index-BAbHDCJb.d.ts +190 -0
  242. package/dist/index-BN1ZJhWK.d.cts +471 -0
  243. package/dist/index-BNt_9BO7.d.ts +77 -0
  244. package/dist/index-BQIO-ZFv.d.cts +190 -0
  245. package/dist/index-BTQxeAz1.d.cts +123 -0
  246. package/dist/index-BxsI0BlT.d.ts +471 -0
  247. package/dist/index-BzzHoNRc.d.cts +77 -0
  248. package/dist/index-C0Scq3kL.d.ts +458 -0
  249. package/dist/index-CAHLDDjY.d.ts +190 -0
  250. package/dist/index-CIJ7ossb.d.ts +190 -0
  251. package/dist/index-CJqujqsv.d.cts +190 -0
  252. package/dist/index-CJrVDk2d.d.ts +470 -0
  253. package/dist/index-CQBZI4f5.d.cts +458 -0
  254. package/dist/index-CS3VHZ8R.d.cts +77 -0
  255. package/dist/index-CWd5aKyK.d.ts +123 -0
  256. package/dist/index-DM3Ga1zc.d.ts +123 -0
  257. package/dist/index-DYp_9VQ_.d.cts +470 -0
  258. package/dist/index-DrK-HiGj.d.ts +203 -0
  259. package/dist/index-GwiDNOsl.d.ts +457 -0
  260. package/dist/index-QLMT7NRw.d.cts +203 -0
  261. package/dist/index-QLi1BtdI.d.cts +190 -0
  262. package/dist/index-sM3yy652.d.cts +534 -0
  263. package/dist/index-zvkV7Xwg.d.cts +457 -0
  264. package/dist/index.cjs +2 -2
  265. package/dist/index.d.cts +21 -12
  266. package/dist/index.d.ts +21 -12
  267. package/dist/index.global.js +26 -101
  268. package/dist/index.iife.js +43 -0
  269. package/dist/index.js +2 -2
  270. package/dist/primitives.cjs +2 -2
  271. package/dist/primitives.d.cts +20 -13
  272. package/dist/primitives.d.ts +20 -13
  273. package/dist/primitives.js +2 -2
  274. package/dist/renderer--AVNuclr.js +9 -0
  275. package/dist/renderer--bWj0AZJ.js +4101 -0
  276. package/dist/renderer--cF4pvND.js +9 -0
  277. package/dist/renderer-0mo5bvxE.js +4126 -0
  278. package/dist/renderer-4Wa-UMC5.cjs +9 -0
  279. package/dist/renderer-6D9KbSAS.js +9 -0
  280. package/dist/renderer-7mjLlkgX.cjs +9 -0
  281. package/dist/renderer-B0v-2J0H.js +9 -0
  282. package/dist/renderer-B0yJsSRz.js +9 -0
  283. package/dist/renderer-B660bBKn.cjs +9 -0
  284. package/dist/renderer-B6m2pWq1.cjs +4102 -0
  285. package/dist/renderer-BA_yjKW4.cjs +9 -0
  286. package/dist/renderer-BDCne7IL.cjs +9 -0
  287. package/dist/renderer-BDKG-8eW.js +9 -0
  288. package/dist/renderer-BEisX7lt.js +9 -0
  289. package/dist/renderer-BEnSHrkN.cjs +9 -0
  290. package/dist/renderer-BJQHCki_.js +9 -0
  291. package/dist/renderer-BLEQ0lBg.js +9 -0
  292. package/dist/renderer-BQMe9vbO.cjs +9 -0
  293. package/dist/renderer-BZfQAWt2.cjs +9 -0
  294. package/dist/renderer-BZypunFM.cjs +9 -0
  295. package/dist/renderer-Be1I1mDW.cjs +9 -0
  296. package/dist/renderer-Bhrtihjr.cjs +9 -0
  297. package/dist/renderer-Bp3dRMPA.js +9 -0
  298. package/dist/renderer-BqYgf0tD.js +9 -0
  299. package/dist/renderer-BwD9ZaGr.cjs +9 -0
  300. package/dist/renderer-BxCRcsEK.cjs +4125 -0
  301. package/dist/renderer-C1Wrh8hn.js +9 -0
  302. package/dist/renderer-C6pztTyv.js +9 -0
  303. package/dist/renderer-C9bCr3pC.js +4101 -0
  304. package/dist/renderer-CEmrAuyA.js +9 -0
  305. package/dist/renderer-CG1lpM8J.cjs +9 -0
  306. package/dist/renderer-CIJhv1xD.js +9 -0
  307. package/dist/renderer-CJ3EovD7.js +9 -0
  308. package/dist/renderer-CJVIzi67.js +4114 -0
  309. package/dist/renderer-CKAmRN9i.cjs +9 -0
  310. package/dist/renderer-CNa9jW2d.js +9 -0
  311. package/dist/renderer-CS6q5sh-.cjs +4101 -0
  312. package/dist/renderer-CTip7L4z.cjs +4114 -0
  313. package/dist/renderer-Cdh6G3WO.cjs +4101 -0
  314. package/dist/renderer-Cfnc_J-x.js +9 -0
  315. package/dist/renderer-CidbOiiO.js +9 -0
  316. package/dist/renderer-CooL8OD4.cjs +9 -0
  317. package/dist/renderer-Cp8W_Vpj.cjs +4101 -0
  318. package/dist/renderer-Ctq4IL1w.cjs +9 -0
  319. package/dist/renderer-D0gZDp8v.js +9 -0
  320. package/dist/renderer-D2Ius1-3.cjs +9 -0
  321. package/dist/renderer-D2gUuAUv.cjs +9 -0
  322. package/dist/renderer-D6qQGrNF.js +9 -0
  323. package/dist/renderer-D9RBf9He.js +9 -0
  324. package/dist/renderer-DDpyudCh.js +9 -0
  325. package/dist/renderer-DEo9eIZj.cjs +9 -0
  326. package/dist/renderer-DHBz10-G.js +9 -0
  327. package/dist/renderer-DM6gVYD_.cjs +4126 -0
  328. package/dist/renderer-DS5wjL1R.cjs +9 -0
  329. package/dist/renderer-DWZQjHeF.cjs +4101 -0
  330. package/dist/renderer-DZ-EdxOj.cjs +9 -0
  331. package/dist/renderer-DblZTrea.js +9 -0
  332. package/dist/renderer-DcPiCh7r.js +4114 -0
  333. package/dist/renderer-Dfj6tfg9.cjs +4139 -0
  334. package/dist/renderer-DhoYb1PY.js +4103 -0
  335. package/dist/renderer-Dl6awT_I.cjs +9 -0
  336. package/dist/renderer-DmOXobMF.js +4101 -0
  337. package/dist/renderer-DmlAyeq6.cjs +4114 -0
  338. package/dist/renderer-DnwizF3I.cjs +9 -0
  339. package/dist/renderer-Dpzs-uao.js +4125 -0
  340. package/dist/renderer-Ds21virZ.cjs +4145 -0
  341. package/dist/renderer-DslAAsKS.js +4101 -0
  342. package/dist/renderer-DtBv4wTu.js +4102 -0
  343. package/dist/renderer-DxuOYfZN.cjs +9 -0
  344. package/dist/renderer-DyrsoA_r.js +9 -0
  345. package/dist/renderer-GlgUXTaV.js +9 -0
  346. package/dist/renderer-KL2bSyIW.cjs +9 -0
  347. package/dist/renderer-N_yFJNWi.cjs +9 -0
  348. package/dist/renderer-TkTQ8ZzV.cjs +4101 -0
  349. package/dist/renderer-WtWG_Uzr.js +4139 -0
  350. package/dist/renderer-YPWUo91d.cjs +9 -0
  351. package/dist/renderer-foaHR93_.js +9 -0
  352. package/dist/renderer-irss7gH9.js +9 -0
  353. package/dist/renderer-kNWgh9RH.js +9 -0
  354. package/dist/renderer-l2DsHbX5.js +4145 -0
  355. package/dist/renderer-lRGat4eI.js +9 -0
  356. package/dist/renderer-m1ynwV5m.cjs +9 -0
  357. package/dist/renderer-oDWZTt10.cjs +9 -0
  358. package/dist/renderer-ruVxrW9_.cjs +9 -0
  359. package/dist/renderer-tLg9bC5E.cjs +4103 -0
  360. package/dist/renderer-wKL03A96.cjs +9 -0
  361. package/dist/renderer-xY7WwwPb.cjs +9 -0
  362. package/dist/renderer-yNfPLGJa.js +4101 -0
  363. package/dist/renderer-zFA8Xsqn.js +9 -0
  364. package/dist/state-0zvRag7o.js +1832 -0
  365. package/dist/state-1bNOTRwX.js +9 -0
  366. package/dist/state-4KlM-876.cjs +9 -0
  367. package/dist/state-5YzsfKSg.js +9 -0
  368. package/dist/state-B2sO7SGs.cjs +9 -0
  369. package/dist/state-B30FVO9-.cjs +9 -0
  370. package/dist/state-BBF5Yd6R.cjs +1488 -0
  371. package/dist/state-BHM_hL69.cjs +9 -0
  372. package/dist/state-BKkU5MYC.js +9 -0
  373. package/dist/state-B_xrj8fC.js +9 -0
  374. package/dist/state-BaTqKR5-.js +1832 -0
  375. package/dist/state-Bb1Wechu.js +9 -0
  376. package/dist/state-BfgVpFaG.cjs +9 -0
  377. package/dist/state-BoRPcmmD.js +9 -0
  378. package/dist/state-BqB3gaPk.js +9 -0
  379. package/dist/state-Bt9zarML.js +1832 -0
  380. package/dist/state-Bw07Ecsm.js +9 -0
  381. package/dist/state-Bw9Y8zmt.js +9 -0
  382. package/dist/state-ByV_XBwX.js +9 -0
  383. package/dist/state-C4nNE_SS.js +9 -0
  384. package/dist/state-C4uusDVL.cjs +9 -0
  385. package/dist/state-CMwBL8Lh.cjs +9 -0
  386. package/dist/state-C_KJ10Ip.cjs +9 -0
  387. package/dist/state-ClLJ5ade.cjs +1488 -0
  388. package/dist/state-CpWrjvjx.js +277 -0
  389. package/dist/state-CwguFqss.cjs +9 -0
  390. package/dist/state-Cxj7mpyT.cjs +9 -0
  391. package/dist/state-CyWfuYBm.js +9 -0
  392. package/dist/state-Cz4euNVW.js +1832 -0
  393. package/dist/state-D1eYdbOV.js +9 -0
  394. package/dist/state-D231Xq-p.js +9 -0
  395. package/dist/state-D2nMXLig.cjs +9 -0
  396. package/dist/state-D3NnAU-G.js +9 -0
  397. package/dist/state-D4g0zX0j.cjs +9 -0
  398. package/dist/state-D5n1XOr-.cjs +372 -0
  399. package/dist/state-DPKTXrbJ.cjs +9 -0
  400. package/dist/state-DREKPmRw.cjs +9 -0
  401. package/dist/state-DT0Nzp9g.cjs +9 -0
  402. package/dist/state-Deun4HK-.cjs +9 -0
  403. package/dist/state-DfcZ51t9.js +9 -0
  404. package/dist/state-DgvhS6KW.cjs +1488 -0
  405. package/dist/state-DkjLMcvP.cjs +9 -0
  406. package/dist/state-DspBT1Sv.js +9 -0
  407. package/dist/state-DtgVqpBv.js +9 -0
  408. package/dist/state-DycsTHAk.cjs +9 -0
  409. package/dist/state-EWoHHdWu.js +9 -0
  410. package/dist/state-HWOltPgB.js +9 -0
  411. package/dist/state-JJNPE2tU.js +277 -0
  412. package/dist/state-KDd3Eouo.js +9 -0
  413. package/dist/state-Kmc6BtLp.cjs +9 -0
  414. package/dist/state-Q4M-6UjH.cjs +9 -0
  415. package/dist/state-U8yVy4Ad.cjs +9 -0
  416. package/dist/state-Uwm9KEi1.js +1832 -0
  417. package/dist/state-XYH8BGBU.cjs +372 -0
  418. package/dist/state-aBiYx-N-.cjs +9 -0
  419. package/dist/state-arg5pYvx.cjs +1488 -0
  420. package/dist/state-dFAAWOP9.cjs +1488 -0
  421. package/dist/state-daFKdtG6.js +9 -0
  422. package/dist/state-muKg33Sx.cjs +9 -0
  423. package/dist/state-wvjxc3BL.js +9 -0
  424. package/dist/styles.css +1 -1
  425. package/package.json +16 -23
  426. package/dist/chunk-5RMV2HA7.js +0 -101
  427. package/dist/chunk-QEVSATMF.cjs +0 -101
  428. package/dist/chunk-XWCIDYJD.cjs +0 -26
  429. package/dist/chunk-XYTXUEOE.js +0 -26
  430. package/dist/index-CN8HkCli.d.cts +0 -547
  431. package/dist/index-CN8HkCli.d.ts +0 -547
  432. package/scripts/postinstall.cjs +0 -23
@@ -0,0 +1,4268 @@
1
+ /**
2
+ * @license MIT
3
+ *
4
+ * Copyright (c) 2025 Aiden Bai
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE file in the root directory of this source tree.
8
+ */
9
+ import { A as waitUntilNextFrame, G as MODIFIER_KEYS, I as DRAG_SELECTION_COVERAGE_THRESHOLD, J as OFFSCREEN_POSITION, K as MOUNT_ROOT_RECHECK_DELAY_MS, M as ARROW_KEYS, O as nativeCancelAnimationFrame, P as DEFAULT_ACTION_ID, S as getNearestComponentName, T as resolveSource, W as MAX_SESSION_STORAGE_SIZE_BYTES, _ as isRootElement, a as freezeGlobalAnimations, b as getElementContext, c as clearElementPositionCache, d as freezePseudoStates, dt as Z_INDEX_OVERLAY, f as resumePointerEventsFreeze, g as isValidGrabbableElement, h as clearVisibilityCache, i as freezeAnimations, j as getTagName, k as nativeRequestAnimationFrame, l as getElementAtPosition, lt as VERSION, m as unfreezePseudoStates, n as logRecoverableError, o as unfreezeGlobalAnimations, ot as TOOLBAR_DEFAULT_POSITION_RATIO, p as suspendPointerEventsFreeze, q as NEXTJS_REVALIDATION_DELAY_MS, r as freezeAllAnimations, s as openFile, t as freezeUpdates, u as getElementsAtPoint, ut as ZOOM_DETECTION_THRESHOLD, v as checkIsNextProject, w as getStackContext, y as getComponentDisplayName, z as FEEDBACK_DURATION_MS } from "./freeze-updates-MaNDvTJS.js";
10
+ import { a as isMac, g as isElementConnected, h as isKeyboardEventTriggeredByInput, i as isEventFromOverlay, m as hasTextSelectionOnPage, n as saveToolbarState, p as hasTextSelectionInInput, r as resolveActionEnabled, s as clampToRange, t as loadToolbarState } from "./state-CpWrjvjx.js";
11
+ import { n as extractElementCss, r as createElementSelector, t as disposeBaselineStyles } from "./extract-element-css-XGv0WWIL.js";
12
+ import { createComponent, memo, render } from "solid-js/web";
13
+ import { batch, createEffect, createMemo, createResource, createRoot, createSignal, on, onCleanup } from "solid-js";
14
+ import { createStore, produce } from "solid-js/store";
15
+
16
+ //#region dist/styles.css?css-text
17
+ var styles_default = "/*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root, :host {\n --font-sans: \"Geist\", ui-sans-serif, system-ui, sans-serif;\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\",\n \"Courier New\", monospace;\n --color-black: #000;\n --color-white: #fff;\n --spacing: 0.25rem;\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --radius-sm: 0.25rem;\n --ease-out: cubic-bezier(0, 0, 0.2, 1);\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: var(--font-sans);\n --default-mono-font-family: var(--font-mono);\n --transition-fast: 100ms;\n --transition-normal: 150ms;\n }\n}\n@layer base {\n *, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b, strong {\n font-weight: bolder;\n }\n code, kbd, samp, pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol, ul, menu {\n list-style: none;\n }\n img, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n }\n img, video {\n max-width: 100%;\n height: auto;\n }\n button, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button, input:where([type=\"button\"], [type=\"reset\"], [type=\"submit\"]), ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden=\"until-found\"])) {\n display: none !important;\n }\n}\n@layer utilities {\n .pointer-events-auto {\n pointer-events: auto;\n }\n .pointer-events-none {\n pointer-events: none;\n }\n .invisible {\n visibility: hidden;\n }\n .visible {\n visibility: visible;\n }\n .touch-hitbox {\n position: relative;\n &::before {\n content: \"\";\n position: absolute;\n display: block;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 100%;\n height: 100%;\n min-height: 44px;\n min-width: 44px;\n }\n }\n .absolute {\n position: absolute;\n }\n .fixed {\n position: fixed;\n }\n .relative {\n position: relative;\n }\n .-top-1 {\n top: calc(var(--spacing) * -1);\n }\n .top-0 {\n top: calc(var(--spacing) * 0);\n }\n .top-0\\.5 {\n top: calc(var(--spacing) * 0.5);\n }\n .top-1\\/2 {\n top: calc(1/2 * 100%);\n }\n .top-full {\n top: 100%;\n }\n .-right-1 {\n right: calc(var(--spacing) * -1);\n }\n .right-full {\n right: 100%;\n }\n .bottom-full {\n bottom: 100%;\n }\n .left-0 {\n left: calc(var(--spacing) * 0);\n }\n .left-0\\.5 {\n left: calc(var(--spacing) * 0.5);\n }\n .left-1\\.5 {\n left: calc(var(--spacing) * 1.5);\n }\n .left-1\\/2 {\n left: calc(1/2 * 100%);\n }\n .left-2\\.5 {\n left: calc(var(--spacing) * 2.5);\n }\n .left-full {\n left: 100%;\n }\n .z-1 {\n z-index: 1;\n }\n .z-10 {\n z-index: 10;\n }\n .container {\n width: 100%;\n @media (width >= 40rem) {\n max-width: 40rem;\n }\n @media (width >= 48rem) {\n max-width: 48rem;\n }\n @media (width >= 64rem) {\n max-width: 64rem;\n }\n @media (width >= 80rem) {\n max-width: 80rem;\n }\n @media (width >= 96rem) {\n max-width: 96rem;\n }\n }\n .m-0 {\n margin: calc(var(--spacing) * 0);\n }\n .-mx-2 {\n margin-inline: calc(var(--spacing) * -2);\n }\n .mx-0\\.5 {\n margin-inline: calc(var(--spacing) * 0.5);\n }\n .-my-1\\.5 {\n margin-block: calc(var(--spacing) * -1.5);\n }\n .my-0\\.5 {\n margin-block: calc(var(--spacing) * 0.5);\n }\n .mt-0\\.5 {\n margin-top: calc(var(--spacing) * 0.5);\n }\n .mt-2\\.5 {\n margin-top: calc(var(--spacing) * 2.5);\n }\n .mr-0\\.5 {\n margin-right: calc(var(--spacing) * 0.5);\n }\n .mr-1\\.5 {\n margin-right: calc(var(--spacing) * 1.5);\n }\n .mr-2\\.5 {\n margin-right: calc(var(--spacing) * 2.5);\n }\n .mb-0\\.5 {\n margin-bottom: calc(var(--spacing) * 0.5);\n }\n .mb-1\\.5 {\n margin-bottom: calc(var(--spacing) * 1.5);\n }\n .mb-2\\.5 {\n margin-bottom: calc(var(--spacing) * 2.5);\n }\n .-ml-\\[2px\\] {\n margin-left: calc(2px * -1);\n }\n .ml-0\\.5 {\n margin-left: calc(var(--spacing) * 0.5);\n }\n .ml-1 {\n margin-left: calc(var(--spacing) * 1);\n }\n .ml-2\\.5 {\n margin-left: calc(var(--spacing) * 2.5);\n }\n .ml-4 {\n margin-left: calc(var(--spacing) * 4);\n }\n .line-clamp-5 {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 5;\n }\n .block {\n display: block;\n }\n .flex {\n display: flex;\n }\n .grid {\n display: grid;\n }\n .hidden {\n display: none;\n }\n .inline {\n display: inline;\n }\n .inline-flex {\n display: inline-flex;\n }\n .size-4 {\n width: calc(var(--spacing) * 4);\n height: calc(var(--spacing) * 4);\n }\n .size-\\[18px\\] {\n width: 18px;\n height: 18px;\n }\n .h-0 {\n height: calc(var(--spacing) * 0);\n }\n .h-1\\.5 {\n height: calc(var(--spacing) * 1.5);\n }\n .h-2 {\n height: calc(var(--spacing) * 2);\n }\n .h-2\\.5 {\n height: calc(var(--spacing) * 2.5);\n }\n .h-3 {\n height: calc(var(--spacing) * 3);\n }\n .h-3\\.5 {\n height: calc(var(--spacing) * 3.5);\n }\n .h-\\[17px\\] {\n height: 17px;\n }\n .h-fit {\n height: fit-content;\n }\n .max-h-\\[240px\\] {\n max-height: 240px;\n }\n .min-h-0 {\n min-height: calc(var(--spacing) * 0);\n }\n .min-h-4 {\n min-height: calc(var(--spacing) * 4);\n }\n .w-0 {\n width: calc(var(--spacing) * 0);\n }\n .w-1\\.5 {\n width: calc(var(--spacing) * 1.5);\n }\n .w-2 {\n width: calc(var(--spacing) * 2);\n }\n .w-3\\.5 {\n width: calc(var(--spacing) * 3.5);\n }\n .w-5 {\n width: calc(var(--spacing) * 5);\n }\n .w-\\[calc\\(100\\%\\+16px\\)\\] {\n width: calc(100% + 16px);\n }\n .w-auto {\n width: auto;\n }\n .w-fit {\n width: fit-content;\n }\n .w-full {\n width: 100%;\n }\n .max-w-\\[280px\\] {\n max-width: 280px;\n }\n .max-w-full {\n max-width: 100%;\n }\n .min-w-0 {\n min-width: calc(var(--spacing) * 0);\n }\n .min-w-2\\.5 {\n min-width: calc(var(--spacing) * 2.5);\n }\n .min-w-\\[100px\\] {\n min-width: 100px;\n }\n .min-w-\\[150px\\] {\n min-width: 150px;\n }\n .flex-1 {\n flex: 1;\n }\n .flex-shrink {\n flex-shrink: 1;\n }\n .shrink {\n flex-shrink: 1;\n }\n .shrink-0 {\n flex-shrink: 0;\n }\n .flex-grow {\n flex-grow: 1;\n }\n .-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1/2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1/2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .scale-75 {\n --tw-scale-x: 75%;\n --tw-scale-y: 75%;\n --tw-scale-z: 75%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .scale-100 {\n --tw-scale-x: 100%;\n --tw-scale-y: 100%;\n --tw-scale-z: 100%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .-rotate-90 {\n rotate: calc(90deg * -1);\n }\n .rotate-0 {\n rotate: 0deg;\n }\n .rotate-90 {\n rotate: 90deg;\n }\n .rotate-180 {\n rotate: 180deg;\n }\n .interactive-scale {\n transition-property: transform;\n transition-duration: var(--transition-normal);\n transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);\n @media (hover: hover) and (pointer: fine) {\n &:hover {\n transform: scale(1.05);\n }\n }\n &:active {\n transform: scale(0.97);\n }\n }\n .press-scale {\n transition-property: transform;\n transition-duration: var(--transition-fast);\n transition-timing-function: ease-out;\n &:active {\n transform: scale(0.97);\n }\n }\n .transform {\n transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);\n }\n .animate-\\[hint-flip-in_var\\(--transition-normal\\)_ease-out\\] {\n animation: hint-flip-in var(--transition-normal) ease-out;\n }\n .cursor-grab {\n cursor: grab;\n }\n .cursor-grabbing {\n cursor: grabbing;\n }\n .cursor-pointer {\n cursor: pointer;\n }\n .resize {\n resize: both;\n }\n .resize-none {\n resize: none;\n }\n .grid-cols-\\[0fr\\] {\n grid-template-columns: 0fr;\n }\n .grid-cols-\\[1fr\\] {\n grid-template-columns: 1fr;\n }\n .grid-rows-\\[0fr\\] {\n grid-template-rows: 0fr;\n }\n .grid-rows-\\[1fr\\] {\n grid-template-rows: 1fr;\n }\n .flex-col {\n flex-direction: column;\n }\n .flex-wrap {\n flex-wrap: wrap;\n }\n .items-center {\n align-items: center;\n }\n .items-end {\n align-items: flex-end;\n }\n .items-start {\n align-items: flex-start;\n }\n .justify-between {\n justify-content: space-between;\n }\n .justify-center {\n justify-content: center;\n }\n .justify-end {\n justify-content: flex-end;\n }\n .gap-0\\.5 {\n gap: calc(var(--spacing) * 0.5);\n }\n .gap-1 {\n gap: calc(var(--spacing) * 1);\n }\n .gap-1\\.5 {\n gap: calc(var(--spacing) * 1.5);\n }\n .gap-2 {\n gap: calc(var(--spacing) * 2);\n }\n .gap-\\[5px\\] {\n gap: 5px;\n }\n .self-stretch {\n align-self: stretch;\n }\n .truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .overflow-hidden {\n overflow: hidden;\n }\n .overflow-visible {\n overflow: visible;\n }\n .overflow-y-auto {\n overflow-y: auto;\n }\n .rounded-\\[10px\\] {\n border-radius: 10px;\n }\n .rounded-full {\n border-radius: calc(infinity * 1px);\n }\n .rounded-sm {\n border-radius: var(--radius-sm);\n }\n .rounded-t-\\[10px\\] {\n border-top-left-radius: 10px;\n border-top-right-radius: 10px;\n }\n .rounded-t-none {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n .rounded-l-\\[10px\\] {\n border-top-left-radius: 10px;\n border-bottom-left-radius: 10px;\n }\n .rounded-l-none {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .rounded-r-\\[10px\\] {\n border-top-right-radius: 10px;\n border-bottom-right-radius: 10px;\n }\n .rounded-r-none {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .rounded-b-\\[6px\\] {\n border-bottom-right-radius: 6px;\n border-bottom-left-radius: 6px;\n }\n .rounded-b-\\[10px\\] {\n border-bottom-right-radius: 10px;\n border-bottom-left-radius: 10px;\n }\n .rounded-b-none {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n }\n .border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n .\\[border-width\\:0\\.5px\\] {\n border-width: 0.5px;\n }\n .\\[border-top-width\\:0\\.5px\\] {\n border-top-width: 0.5px;\n }\n .border-none {\n --tw-border-style: none;\n border-style: none;\n }\n .border-solid {\n --tw-border-style: solid;\n border-style: solid;\n }\n .border-\\[\\#B3B3B3\\] {\n border-color: #B3B3B3;\n }\n .border-t-\\[\\#D9D9D9\\] {\n border-top-color: #D9D9D9;\n }\n .bg-\\[\\#FEF2F2\\] {\n background-color: #FEF2F2;\n }\n .bg-black {\n background-color: var(--color-black);\n }\n .bg-black\\/5 {\n background-color: color-mix(in srgb, #000 5%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 5%, transparent);\n }\n }\n .bg-black\\/25 {\n background-color: color-mix(in srgb, #000 25%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 25%, transparent);\n }\n }\n .bg-transparent {\n background-color: transparent;\n }\n .bg-white {\n background-color: var(--color-white);\n }\n .p-0 {\n padding: calc(var(--spacing) * 0);\n }\n .px-0\\.5 {\n padding-inline: calc(var(--spacing) * 0.5);\n }\n .px-0\\.25 {\n padding-inline: calc(var(--spacing) * 0.25);\n }\n .px-1\\.5 {\n padding-inline: calc(var(--spacing) * 1.5);\n }\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n .px-\\[3px\\] {\n padding-inline: 3px;\n }\n .py-0\\.5 {\n padding-block: calc(var(--spacing) * 0.5);\n }\n .py-0\\.25 {\n padding-block: calc(var(--spacing) * 0.25);\n }\n .py-1 {\n padding-block: calc(var(--spacing) * 1);\n }\n .py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n }\n .py-2 {\n padding-block: calc(var(--spacing) * 2);\n }\n .py-px {\n padding-block: 1px;\n }\n .pt-1\\.5 {\n padding-top: calc(var(--spacing) * 1.5);\n }\n .pb-1 {\n padding-bottom: calc(var(--spacing) * 1);\n }\n .text-left {\n text-align: left;\n }\n .font-sans {\n font-family: var(--font-sans);\n }\n .text-\\[8px\\] {\n font-size: 8px;\n }\n .text-\\[10px\\] {\n font-size: 10px;\n }\n .text-\\[11px\\] {\n font-size: 11px;\n }\n .text-\\[12px\\] {\n font-size: 12px;\n }\n .text-\\[13px\\] {\n font-size: 13px;\n }\n .leading-3 {\n --tw-leading: calc(var(--spacing) * 3);\n line-height: calc(var(--spacing) * 3);\n }\n .leading-3\\.5 {\n --tw-leading: calc(var(--spacing) * 3.5);\n line-height: calc(var(--spacing) * 3.5);\n }\n .leading-4 {\n --tw-leading: calc(var(--spacing) * 4);\n line-height: calc(var(--spacing) * 4);\n }\n .leading-none {\n --tw-leading: 1;\n line-height: 1;\n }\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n .wrap-break-word {\n overflow-wrap: break-word;\n }\n .text-ellipsis {\n text-overflow: ellipsis;\n }\n .whitespace-nowrap {\n white-space: nowrap;\n }\n .text-\\[\\#71717a\\] {\n color: #71717a;\n }\n .text-\\[\\#B3B3B3\\] {\n color: #B3B3B3;\n }\n .text-\\[\\#B91C1C\\] {\n color: #B91C1C;\n }\n .text-\\[\\#B91C1C\\]\\/50 {\n color: color-mix(in oklab, #B91C1C 50%, transparent);\n }\n .text-black {\n color: var(--color-black);\n }\n .text-black\\/25 {\n color: color-mix(in srgb, #000 25%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 25%, transparent);\n }\n }\n .text-black\\/30 {\n color: color-mix(in srgb, #000 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 30%, transparent);\n }\n }\n .text-black\\/40 {\n color: color-mix(in srgb, #000 40%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 40%, transparent);\n }\n }\n .text-black\\/50 {\n color: color-mix(in srgb, #000 50%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 50%, transparent);\n }\n }\n .text-black\\/60 {\n color: color-mix(in srgb, #000 60%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 60%, transparent);\n }\n }\n .text-black\\/70 {\n color: color-mix(in srgb, #000 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 70%, transparent);\n }\n }\n .text-black\\/85 {\n color: color-mix(in srgb, #000 85%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 85%, transparent);\n }\n }\n .text-white {\n color: var(--color-white);\n }\n .tabular-nums {\n --tw-numeric-spacing: tabular-nums;\n font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);\n }\n .antialiased {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n .opacity-0 {\n opacity: 0%;\n }\n .opacity-40 {\n opacity: 40%;\n }\n .opacity-100 {\n opacity: 100%;\n }\n .shadow {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .outline {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n .blur {\n --tw-blur: blur(8px);\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n }\n .filter {\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n }\n .filter-\\[drop-shadow\\(0px_1px_2px_\\#51515140\\)\\] {\n filter: drop-shadow(0px 1px 2px #51515140);\n }\n .backdrop-filter {\n -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n }\n .transition {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-columns\\,opacity\\] {\n transition-property: grid-template-columns,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-columns\\] {\n transition-property: grid-template-columns;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-rows\\,opacity\\] {\n transition-property: grid-template-rows,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-rows\\] {\n transition-property: grid-template-rows;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[opacity\\,transform\\] {\n transition-property: opacity,transform;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[top\\,left\\,width\\,height\\,opacity\\] {\n transition-property: top,left,width,height,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[transform\\,opacity\\] {\n transition-property: transform,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-all {\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-colors {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-opacity {\n transition-property: opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-transform {\n transition-property: transform, translate, scale, rotate;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .duration-75 {\n --tw-duration: 75ms;\n transition-duration: 75ms;\n }\n .duration-100 {\n --tw-duration: 100ms;\n transition-duration: 100ms;\n }\n .duration-150 {\n --tw-duration: 150ms;\n transition-duration: 150ms;\n }\n .duration-300 {\n --tw-duration: 300ms;\n transition-duration: 300ms;\n }\n .ease-out {\n --tw-ease: var(--ease-out);\n transition-timing-function: var(--ease-out);\n }\n .will-change-\\[opacity\\,transform\\] {\n will-change: opacity,transform;\n }\n .contain-layout {\n --tw-contain-layout: layout;\n contain: var(--tw-contain-size,) var(--tw-contain-layout,) var(--tw-contain-paint,) var(--tw-contain-style,);\n }\n .outline-none {\n --tw-outline-style: none;\n outline-style: none;\n }\n .select-none {\n -webkit-user-select: none;\n user-select: none;\n }\n .\\[animation-fill-mode\\:backwards\\] {\n animation-fill-mode: backwards;\n }\n .\\[corner-shape\\:superellipse\\(1\\.25\\)\\] {\n corner-shape: superellipse(1.25);\n }\n .\\[font-synthesis\\:none\\] {\n font-synthesis: none;\n }\n .\\[scrollbar-color\\:transparent_transparent\\] {\n scrollbar-color: transparent transparent;\n }\n .\\[scrollbar-width\\:thin\\] {\n scrollbar-width: thin;\n }\n .before\\:\\!min-h-full {\n &::before {\n content: var(--tw-content);\n min-height: 100% !important;\n }\n }\n .before\\:\\!min-w-full {\n &::before {\n content: var(--tw-content);\n min-width: 100% !important;\n }\n }\n .hover\\:bg-\\[\\#F5F5F5\\] {\n &:hover {\n @media (hover: hover) {\n background-color: #F5F5F5;\n }\n }\n }\n .hover\\:bg-\\[\\#FEE2E2\\] {\n &:hover {\n @media (hover: hover) {\n background-color: #FEE2E2;\n }\n }\n }\n .hover\\:bg-black\\/10 {\n &:hover {\n @media (hover: hover) {\n background-color: color-mix(in srgb, #000 10%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 10%, transparent);\n }\n }\n }\n }\n .hover\\:text-black {\n &:hover {\n @media (hover: hover) {\n color: var(--color-black);\n }\n }\n }\n .hover\\:opacity-100 {\n &:hover {\n @media (hover: hover) {\n opacity: 100%;\n }\n }\n }\n .hover\\:\\[scrollbar-color\\:rgba\\(0\\,0\\,0\\,0\\.15\\)_transparent\\] {\n &:hover {\n @media (hover: hover) {\n scrollbar-color: rgba(0,0,0,0.15) transparent;\n }\n }\n }\n .disabled\\:cursor-default {\n &:disabled {\n cursor: default;\n }\n }\n .disabled\\:opacity-40 {\n &:disabled {\n opacity: 40%;\n }\n }\n}\n:host {\n all: initial;\n direction: ltr;\n}\n@keyframes shake {\n 0%, 100% {\n transform: translateX(0);\n }\n 15% {\n transform: translateX(-3px);\n }\n 30% {\n transform: translateX(3px);\n }\n 45% {\n transform: translateX(-3px);\n }\n 60% {\n transform: translateX(3px);\n }\n 75% {\n transform: translateX(-2px);\n }\n 90% {\n transform: translateX(2px);\n }\n}\n@keyframes success-pop {\n 0% {\n transform: scale(0.9);\n opacity: 0;\n }\n 60% {\n transform: scale(1.1);\n opacity: 1;\n }\n 80% {\n transform: scale(0.95);\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n@keyframes hint-flip-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes tooltip-fade-in {\n from {\n opacity: 0;\n transform: scale(0.97);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n@keyframes icon-loader-spin {\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n 100% {\n opacity: 0.2;\n }\n}\n.icon-loader-bar {\n animation: icon-loader-spin 0.5s linear infinite;\n}\n@keyframes shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n}\n.shimmer-text {\n background: linear-gradient( 90deg, #71717a 0%, #a1a1aa 25%, #71717a 50%, #a1a1aa 75%, #71717a 100% );\n background-size: 200% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n animation: shimmer 2.5s linear infinite;\n}\n@keyframes clock-flash {\n 0% {\n transform: scale(1);\n }\n 25% {\n transform: scale(1.2);\n }\n 50% {\n transform: scale(0.92);\n }\n 75% {\n transform: scale(1.05);\n }\n 100% {\n transform: scale(1);\n }\n}\n.animate-clock-flash {\n animation: clock-flash 400ms ease-out;\n will-change: transform;\n}\n.animate-shake {\n animation: shake 0.3s ease-out;\n will-change: transform;\n}\n.animate-success-pop {\n animation: success-pop 250ms ease-out;\n will-change: transform, opacity;\n}\n.animate-tooltip-fade-in {\n animation: tooltip-fade-in var(--transition-fast) ease-out;\n will-change: transform, opacity;\n}\n@property --tw-translate-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-scale-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n@property --tw-scale-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n@property --tw-scale-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n@property --tw-rotate-x {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-rotate-y {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-rotate-z {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-skew-x {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-skew-y {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-border-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-leading {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-font-weight {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ordinal {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-slashed-zero {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-numeric-figure {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-numeric-spacing {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-numeric-fraction {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-inset-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-inset-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-ring-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ring-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-ring-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-inset-ring-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-ring-inset {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ring-offset-width {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --tw-ring-offset-color {\n syntax: \"*\";\n inherits: false;\n initial-value: #fff;\n}\n@property --tw-ring-offset-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-outline-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-blur {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-brightness {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contrast {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-grayscale {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-hue-rotate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-invert {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-opacity {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-saturate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-sepia {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-drop-shadow-size {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-blur {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-brightness {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-contrast {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-grayscale {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-hue-rotate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-invert {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-opacity {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-saturate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-sepia {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-duration {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ease {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-size {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-layout {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-paint {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-style {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-content {\n syntax: \"*\";\n initial-value: \"\";\n inherits: false;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-scale-z: 1;\n --tw-rotate-x: initial;\n --tw-rotate-y: initial;\n --tw-rotate-z: initial;\n --tw-skew-x: initial;\n --tw-skew-y: initial;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-ordinal: initial;\n --tw-slashed-zero: initial;\n --tw-numeric-figure: initial;\n --tw-numeric-spacing: initial;\n --tw-numeric-fraction: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-outline-style: solid;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-backdrop-blur: initial;\n --tw-backdrop-brightness: initial;\n --tw-backdrop-contrast: initial;\n --tw-backdrop-grayscale: initial;\n --tw-backdrop-hue-rotate: initial;\n --tw-backdrop-invert: initial;\n --tw-backdrop-opacity: initial;\n --tw-backdrop-saturate: initial;\n --tw-backdrop-sepia: initial;\n --tw-duration: initial;\n --tw-ease: initial;\n --tw-contain-size: initial;\n --tw-contain-layout: initial;\n --tw-contain-paint: initial;\n --tw-contain-style: initial;\n --tw-content: \"\";\n }\n }\n}\n";
18
+
19
+ //#endregion
20
+ //#region src/utils/strip-translate-from-transform.ts
21
+ const isValidNumber = (value) => typeof value === "number" && !Number.isNaN(value) && Number.isFinite(value);
22
+ const parseMatrixValue = (value) => {
23
+ const trimmedValue = value.trim();
24
+ if (!trimmedValue) return null;
25
+ const parsedValue = parseFloat(trimmedValue);
26
+ return isValidNumber(parsedValue) ? parsedValue : null;
27
+ };
28
+ const parseMatrixValues = (valuesString, expectedLength) => {
29
+ const rawValues = valuesString.split(",");
30
+ if (rawValues.length !== expectedLength) return null;
31
+ const parsedValues = [];
32
+ for (const rawValue of rawValues) {
33
+ const parsedValue = parseMatrixValue(rawValue);
34
+ if (parsedValue === null) return null;
35
+ parsedValues.push(parsedValue);
36
+ }
37
+ return parsedValues;
38
+ };
39
+ const isIdentityMatrix2d = (a, b, c, d) => a === 1 && b === 0 && c === 0 && d === 1;
40
+ const isIdentityMatrix3d = (values) => values[0] === 1 && values[1] === 0 && values[2] === 0 && values[3] === 0 && values[4] === 0 && values[5] === 1 && values[6] === 0 && values[7] === 0 && values[8] === 0 && values[9] === 0 && values[10] === 1 && values[11] === 0 && values[15] === 1;
41
+ const stripTranslateFromTransformString = (transform) => {
42
+ if (!transform || transform === "none") return "none";
43
+ if (transform.startsWith("matrix")) if (transform.startsWith("matrix3d(")) {
44
+ const start = 9;
45
+ const end = transform.length - 1;
46
+ const values = parseMatrixValues(transform.slice(start, end), 16);
47
+ if (values) {
48
+ values[12] = 0;
49
+ values[13] = 0;
50
+ values[14] = 0;
51
+ if (isIdentityMatrix3d(values)) return "none";
52
+ return `matrix3d(${values[0]}, ${values[1]}, ${values[2]}, ${values[3]}, ${values[4]}, ${values[5]}, ${values[6]}, ${values[7]}, ${values[8]}, ${values[9]}, ${values[10]}, ${values[11]}, 0, 0, 0, ${values[15]})`;
53
+ }
54
+ } else {
55
+ const start = 7;
56
+ const end = transform.length - 1;
57
+ const values = parseMatrixValues(transform.slice(start, end), 6);
58
+ if (values) {
59
+ const scaleX = values[0];
60
+ const skewY = values[1];
61
+ const skewX = values[2];
62
+ const scaleY = values[3];
63
+ if (isIdentityMatrix2d(scaleX, skewY, skewX, scaleY)) return "none";
64
+ return `matrix(${scaleX}, ${skewY}, ${skewX}, ${scaleY}, 0, 0)`;
65
+ }
66
+ }
67
+ return "none";
68
+ };
69
+ const stripTranslateFromMatrix = (matrix) => {
70
+ if (matrix.isIdentity) return "none";
71
+ if (matrix.is2D) {
72
+ if (isIdentityMatrix2d(matrix.a, matrix.b, matrix.c, matrix.d)) return "none";
73
+ return `matrix(${matrix.a}, ${matrix.b}, ${matrix.c}, ${matrix.d}, 0, 0)`;
74
+ }
75
+ if (matrix.m11 === 1 && matrix.m12 === 0 && matrix.m13 === 0 && matrix.m14 === 0 && matrix.m21 === 0 && matrix.m22 === 1 && matrix.m23 === 0 && matrix.m24 === 0 && matrix.m31 === 0 && matrix.m32 === 0 && matrix.m33 === 1 && matrix.m34 === 0 && matrix.m44 === 1) return "none";
76
+ return `matrix3d(${matrix.m11}, ${matrix.m12}, ${matrix.m13}, ${matrix.m14}, ${matrix.m21}, ${matrix.m22}, ${matrix.m23}, ${matrix.m24}, ${matrix.m31}, ${matrix.m32}, ${matrix.m33}, ${matrix.m34}, 0, 0, 0, ${matrix.m44})`;
77
+ };
78
+
79
+ //#endregion
80
+ //#region src/utils/create-element-bounds.ts
81
+ let boundsCache = /* @__PURE__ */ new WeakMap();
82
+ let ancestorTransformCache = /* @__PURE__ */ new WeakMap();
83
+ let borderRadiusCache = /* @__PURE__ */ new WeakMap();
84
+ const invalidateBoundsCache = () => {
85
+ boundsCache = /* @__PURE__ */ new WeakMap();
86
+ ancestorTransformCache = /* @__PURE__ */ new WeakMap();
87
+ borderRadiusCache = /* @__PURE__ */ new WeakMap();
88
+ };
89
+ const getAncestorTransformValue = (ancestor, now) => {
90
+ const cached = ancestorTransformCache.get(ancestor);
91
+ if (cached && now - cached.timestamp < 16) return cached.transform;
92
+ const transformValue = window.getComputedStyle(ancestor).transform;
93
+ const resolvedTransform = transformValue && transformValue !== "none" ? transformValue : "none";
94
+ ancestorTransformCache.set(ancestor, {
95
+ transform: resolvedTransform,
96
+ timestamp: now
97
+ });
98
+ return resolvedTransform;
99
+ };
100
+ const getAccumulatedTransform = (element, selfTransform, now) => {
101
+ const hasSelfTransform = selfTransform && selfTransform !== "none";
102
+ let accumulated = null;
103
+ let current = element.parentElement;
104
+ let depth = 0;
105
+ while (current && current !== document.documentElement && depth < 6) {
106
+ const transformValue = getAncestorTransformValue(current, now);
107
+ if (transformValue !== "none") accumulated = accumulated ? new DOMMatrix(transformValue).multiply(accumulated) : new DOMMatrix(transformValue);
108
+ else if (!hasSelfTransform && !accumulated && depth >= 3) return "none";
109
+ current = current.parentElement;
110
+ depth++;
111
+ }
112
+ if (!accumulated) return hasSelfTransform ? stripTranslateFromTransformString(selfTransform) : "none";
113
+ if (hasSelfTransform) accumulated = accumulated.multiply(new DOMMatrix(selfTransform));
114
+ return stripTranslateFromMatrix(accumulated);
115
+ };
116
+ const getCachedBorderRadius = (element, computedStyle, now) => {
117
+ const cached = borderRadiusCache.get(element);
118
+ if (cached && now - cached.timestamp < 200) return cached.borderRadius;
119
+ const borderRadius = (computedStyle ?? window.getComputedStyle(element)).borderRadius || "0px";
120
+ borderRadiusCache.set(element, {
121
+ borderRadius,
122
+ timestamp: now
123
+ });
124
+ return borderRadius;
125
+ };
126
+ const buildBoundsFromRect = (element, rect, style, now) => {
127
+ const transform = getAccumulatedTransform(element, style.transform, now);
128
+ const borderRadius = getCachedBorderRadius(element, style, now);
129
+ if (transform !== "none" && element instanceof HTMLElement) {
130
+ const offsetWidth = element.offsetWidth;
131
+ const offsetHeight = element.offsetHeight;
132
+ if (offsetWidth > 0 && offsetHeight > 0) {
133
+ const centerX = rect.left + rect.width * .5;
134
+ const centerY = rect.top + rect.height * .5;
135
+ return {
136
+ borderRadius,
137
+ height: offsetHeight,
138
+ transform,
139
+ width: offsetWidth,
140
+ x: centerX - offsetWidth * .5,
141
+ y: centerY - offsetHeight * .5
142
+ };
143
+ }
144
+ }
145
+ return {
146
+ borderRadius,
147
+ height: rect.height,
148
+ transform,
149
+ width: rect.width,
150
+ x: rect.left,
151
+ y: rect.top
152
+ };
153
+ };
154
+ const createElementBounds = (element) => {
155
+ const now = performance.now();
156
+ const cached = boundsCache.get(element);
157
+ if (cached && now - cached.timestamp < 16) return cached.bounds;
158
+ const bounds = buildBoundsFromRect(element, element.getBoundingClientRect(), window.getComputedStyle(element), now);
159
+ boundsCache.set(element, {
160
+ bounds,
161
+ timestamp: now
162
+ });
163
+ return bounds;
164
+ };
165
+
166
+ //#endregion
167
+ //#region src/utils/get-bounds-center.ts
168
+ const getBoundsCenter = (bounds) => ({
169
+ x: bounds.x + bounds.width / 2,
170
+ y: bounds.y + bounds.height / 2
171
+ });
172
+
173
+ //#endregion
174
+ //#region src/core/store.ts
175
+ const createInitialStore = (input) => ({
176
+ current: { state: "idle" },
177
+ wasActivatedByToggle: false,
178
+ pendingCommentMode: false,
179
+ keyHoldDuration: input.keyHoldDuration,
180
+ pointer: {
181
+ x: OFFSCREEN_POSITION,
182
+ y: OFFSCREEN_POSITION
183
+ },
184
+ dragStart: {
185
+ x: OFFSCREEN_POSITION,
186
+ y: OFFSCREEN_POSITION
187
+ },
188
+ copyStart: {
189
+ x: OFFSCREEN_POSITION,
190
+ y: OFFSCREEN_POSITION
191
+ },
192
+ copyOffsetFromCenterX: 0,
193
+ detectedElement: null,
194
+ frozenElement: null,
195
+ frozenElements: [],
196
+ frozenDragRect: null,
197
+ lastGrabbedElement: null,
198
+ lastCopiedElement: null,
199
+ selectionFilePath: null,
200
+ selectionLineNumber: null,
201
+ inputText: "",
202
+ viewportVersion: 0,
203
+ grabbedBoxes: [],
204
+ labelInstances: [],
205
+ isTouchMode: false,
206
+ theme: input.theme,
207
+ activationTimestamp: null,
208
+ previouslyFocusedElement: null,
209
+ contextMenuPosition: null,
210
+ contextMenuElement: null,
211
+ contextMenuClickOffset: null
212
+ });
213
+ const createGrabStore = (input) => {
214
+ const [store, setStore] = createStore(createInitialStore(input));
215
+ const clearFrozenElement = () => {
216
+ setStore(produce((draft) => {
217
+ draft.frozenElement = null;
218
+ draft.frozenElements = [];
219
+ draft.frozenDragRect = null;
220
+ }));
221
+ };
222
+ const setActivePhase = (phase) => {
223
+ setStore("current", produce((current) => {
224
+ if (current.state === "active") current.phase = phase;
225
+ }));
226
+ };
227
+ const actions = {
228
+ startHold: (duration) => {
229
+ if (duration !== void 0) setStore("keyHoldDuration", duration);
230
+ setStore("current", {
231
+ state: "holding",
232
+ startedAt: Date.now()
233
+ });
234
+ },
235
+ releaseHold: () => {
236
+ if (store.current.state === "holding") setStore("current", { state: "idle" });
237
+ },
238
+ activate: () => {
239
+ setStore(produce((draft) => {
240
+ draft.current = {
241
+ state: "active",
242
+ phase: "hovering",
243
+ isPromptMode: false,
244
+ isPendingDismiss: false
245
+ };
246
+ draft.activationTimestamp = Date.now();
247
+ draft.previouslyFocusedElement = document.activeElement;
248
+ }));
249
+ },
250
+ deactivate: () => {
251
+ setStore(produce((draft) => {
252
+ draft.current = { state: "idle" };
253
+ draft.wasActivatedByToggle = false;
254
+ draft.pendingCommentMode = false;
255
+ draft.inputText = "";
256
+ draft.frozenElement = null;
257
+ draft.frozenElements = [];
258
+ draft.frozenDragRect = null;
259
+ draft.activationTimestamp = null;
260
+ draft.previouslyFocusedElement = null;
261
+ draft.contextMenuPosition = null;
262
+ draft.contextMenuElement = null;
263
+ draft.contextMenuClickOffset = null;
264
+ draft.lastCopiedElement = null;
265
+ }));
266
+ },
267
+ toggle: () => {
268
+ if (store.activationTimestamp !== null) actions.deactivate();
269
+ else {
270
+ setStore("wasActivatedByToggle", true);
271
+ actions.activate();
272
+ }
273
+ },
274
+ freeze: () => {
275
+ if (store.current.state === "active") {
276
+ const elementToFreeze = store.frozenElement ?? store.detectedElement;
277
+ if (elementToFreeze) setStore("frozenElement", elementToFreeze);
278
+ setActivePhase("frozen");
279
+ }
280
+ },
281
+ unfreeze: () => {
282
+ if (store.current.state === "active") {
283
+ setStore(produce((draft) => {
284
+ draft.frozenElement = null;
285
+ draft.frozenElements = [];
286
+ draft.frozenDragRect = null;
287
+ }));
288
+ setActivePhase("hovering");
289
+ }
290
+ },
291
+ startDrag: (position) => {
292
+ if (store.current.state === "active") {
293
+ clearFrozenElement();
294
+ setStore("dragStart", {
295
+ x: position.x + window.scrollX,
296
+ y: position.y + window.scrollY
297
+ });
298
+ setActivePhase("dragging");
299
+ }
300
+ },
301
+ endDrag: () => {
302
+ if (store.current.state === "active" && store.current.phase === "dragging") {
303
+ setStore("dragStart", {
304
+ x: OFFSCREEN_POSITION,
305
+ y: OFFSCREEN_POSITION
306
+ });
307
+ setActivePhase("justDragged");
308
+ }
309
+ },
310
+ cancelDrag: () => {
311
+ if (store.current.state === "active" && store.current.phase === "dragging") {
312
+ setStore("dragStart", {
313
+ x: OFFSCREEN_POSITION,
314
+ y: OFFSCREEN_POSITION
315
+ });
316
+ setActivePhase("hovering");
317
+ }
318
+ },
319
+ finishJustDragged: () => {
320
+ if (store.current.state === "active" && store.current.phase === "justDragged") setActivePhase("hovering");
321
+ },
322
+ startCopy: () => {
323
+ const wasActive = store.current.state === "active";
324
+ setStore("current", {
325
+ state: "copying",
326
+ startedAt: Date.now(),
327
+ wasActive
328
+ });
329
+ },
330
+ completeCopy: (element) => {
331
+ if (element) setStore("lastCopiedElement", element);
332
+ const wasActive = store.current.state === "copying" ? store.current.wasActive : false;
333
+ setStore("current", {
334
+ state: "justCopied",
335
+ copiedAt: Date.now(),
336
+ wasActive
337
+ });
338
+ },
339
+ finishJustCopied: () => {
340
+ if (store.current.state === "justCopied") if (store.current.wasActive && !store.wasActivatedByToggle) {
341
+ clearFrozenElement();
342
+ setStore("current", {
343
+ state: "active",
344
+ phase: "hovering",
345
+ isPromptMode: false,
346
+ isPendingDismiss: false
347
+ });
348
+ } else actions.deactivate();
349
+ },
350
+ enterPromptMode: (position, element) => {
351
+ const { x: selectionCenterX } = getBoundsCenter(createElementBounds(element));
352
+ setStore("copyStart", position);
353
+ setStore("copyOffsetFromCenterX", position.x - selectionCenterX);
354
+ setStore("pointer", position);
355
+ setStore("frozenElement", element);
356
+ setStore("wasActivatedByToggle", true);
357
+ if (store.current.state !== "active") {
358
+ setStore("current", {
359
+ state: "active",
360
+ phase: "frozen",
361
+ isPromptMode: true,
362
+ isPendingDismiss: false
363
+ });
364
+ setStore("activationTimestamp", Date.now());
365
+ setStore("previouslyFocusedElement", document.activeElement);
366
+ } else setStore("current", produce((current) => {
367
+ if (current.state === "active") {
368
+ current.isPromptMode = true;
369
+ current.phase = "frozen";
370
+ }
371
+ }));
372
+ },
373
+ exitPromptMode: () => {
374
+ if (store.current.state === "active") setStore("current", produce((current) => {
375
+ if (current.state === "active") {
376
+ current.isPromptMode = false;
377
+ current.isPendingDismiss = false;
378
+ }
379
+ }));
380
+ },
381
+ setInputText: (value) => {
382
+ setStore("inputText", value);
383
+ },
384
+ clearInputText: () => {
385
+ setStore("inputText", "");
386
+ },
387
+ setPendingDismiss: (value) => {
388
+ if (store.current.state === "active") setStore("current", produce((current) => {
389
+ if (current.state === "active") current.isPendingDismiss = value;
390
+ }));
391
+ },
392
+ setPointer: (position) => {
393
+ setStore("pointer", position);
394
+ },
395
+ setDetectedElement: (element) => {
396
+ setStore("detectedElement", element);
397
+ },
398
+ setFrozenElement: (element) => {
399
+ setStore(produce((draft) => {
400
+ draft.frozenElement = element;
401
+ draft.frozenElements = [element];
402
+ draft.frozenDragRect = null;
403
+ }));
404
+ },
405
+ setFrozenElements: (elements) => {
406
+ setStore(produce((draft) => {
407
+ draft.frozenElements = elements;
408
+ draft.frozenElement = elements.length > 0 ? elements[0] : null;
409
+ draft.frozenDragRect = null;
410
+ }));
411
+ },
412
+ setFrozenDragRect: (rect) => {
413
+ setStore("frozenDragRect", rect);
414
+ },
415
+ setCopyStart: (position, element) => {
416
+ const { x: selectionCenterX } = getBoundsCenter(createElementBounds(element));
417
+ setStore("copyStart", position);
418
+ setStore("copyOffsetFromCenterX", position.x - selectionCenterX);
419
+ },
420
+ setLastGrabbed: (element) => {
421
+ setStore("lastGrabbedElement", element);
422
+ },
423
+ clearLastCopied: () => {
424
+ setStore("lastCopiedElement", null);
425
+ },
426
+ setWasActivatedByToggle: (value) => {
427
+ setStore("wasActivatedByToggle", value);
428
+ },
429
+ setPendingCommentMode: (value) => {
430
+ setStore("pendingCommentMode", value);
431
+ },
432
+ setTouchMode: (value) => {
433
+ setStore("isTouchMode", value);
434
+ },
435
+ setSelectionSource: (filePath, lineNumber) => {
436
+ setStore(produce((draft) => {
437
+ draft.selectionFilePath = filePath;
438
+ draft.selectionLineNumber = lineNumber;
439
+ }));
440
+ },
441
+ incrementViewportVersion: () => {
442
+ setStore("viewportVersion", (version) => version + 1);
443
+ },
444
+ addGrabbedBox: (box) => {
445
+ setStore("grabbedBoxes", (boxes) => [...boxes, box]);
446
+ },
447
+ removeGrabbedBox: (boxId) => {
448
+ setStore("grabbedBoxes", (boxes) => boxes.filter((box) => box.id !== boxId));
449
+ },
450
+ clearGrabbedBoxes: () => {
451
+ setStore("grabbedBoxes", []);
452
+ },
453
+ addLabelInstance: (instance) => {
454
+ setStore("labelInstances", (instances) => [...instances, instance]);
455
+ },
456
+ updateLabelInstance: (instanceId, status, errorMessage) => {
457
+ const index = store.labelInstances.findIndex((instance) => instance.id === instanceId);
458
+ if (index !== -1) setStore("labelInstances", index, produce((instance) => {
459
+ instance.status = status;
460
+ if (errorMessage !== void 0) instance.errorMessage = errorMessage;
461
+ }));
462
+ },
463
+ removeLabelInstance: (instanceId) => {
464
+ setStore("labelInstances", (instances) => instances.filter((instance) => instance.id !== instanceId));
465
+ },
466
+ clearLabelInstances: () => {
467
+ setStore("labelInstances", []);
468
+ },
469
+ showContextMenu: (position, element) => {
470
+ const { x: centerX, y: centerY } = getBoundsCenter(createElementBounds(element));
471
+ setStore(produce((draft) => {
472
+ draft.contextMenuPosition = position;
473
+ draft.contextMenuElement = element;
474
+ draft.contextMenuClickOffset = {
475
+ x: position.x - centerX,
476
+ y: position.y - centerY
477
+ };
478
+ }));
479
+ },
480
+ hideContextMenu: () => {
481
+ setStore(produce((draft) => {
482
+ draft.contextMenuPosition = null;
483
+ draft.contextMenuElement = null;
484
+ draft.contextMenuClickOffset = null;
485
+ }));
486
+ },
487
+ updateContextMenuPosition: () => {
488
+ const element = store.contextMenuElement;
489
+ const clickOffset = store.contextMenuClickOffset;
490
+ if (!element || !clickOffset) return;
491
+ if (!isElementConnected(element)) return;
492
+ const { x: newCenterX, y: newCenterY } = getBoundsCenter(createElementBounds(element));
493
+ setStore("contextMenuPosition", {
494
+ x: newCenterX + clickOffset.x,
495
+ y: newCenterY + clickOffset.y
496
+ });
497
+ }
498
+ };
499
+ return {
500
+ store,
501
+ actions
502
+ };
503
+ };
504
+
505
+ //#endregion
506
+ //#region src/utils/mount-root.ts
507
+ const ATTRIBUTE_NAME = "data-react-grab";
508
+ const FONT_LINK_ID = "react-grab-fonts";
509
+ const FONT_LINK_URL = "https://fonts.googleapis.com/css2?family=Geist:wght@500&display=swap";
510
+ const loadFonts = () => {
511
+ if (document.getElementById(FONT_LINK_ID)) return;
512
+ if (!document.head) return;
513
+ const link = document.createElement("link");
514
+ link.id = FONT_LINK_ID;
515
+ link.rel = "stylesheet";
516
+ link.href = FONT_LINK_URL;
517
+ document.head.appendChild(link);
518
+ };
519
+ const mountRoot = (cssText) => {
520
+ loadFonts();
521
+ const mountedHost = document.querySelector(`[${ATTRIBUTE_NAME}]`);
522
+ if (mountedHost) {
523
+ const mountedRoot = mountedHost.shadowRoot?.querySelector(`[${ATTRIBUTE_NAME}]`);
524
+ if (mountedRoot instanceof HTMLDivElement && mountedHost.shadowRoot) return mountedRoot;
525
+ }
526
+ const host = document.createElement("div");
527
+ host.setAttribute(ATTRIBUTE_NAME, "true");
528
+ host.style.zIndex = String(Z_INDEX_OVERLAY);
529
+ host.style.position = "fixed";
530
+ host.style.inset = "0";
531
+ host.style.pointerEvents = "none";
532
+ const shadowRoot = host.attachShadow({ mode: "open" });
533
+ if (cssText) {
534
+ const styleElement = document.createElement("style");
535
+ styleElement.textContent = cssText;
536
+ shadowRoot.appendChild(styleElement);
537
+ }
538
+ const root = document.createElement("div");
539
+ root.setAttribute(ATTRIBUTE_NAME, "true");
540
+ shadowRoot.appendChild(root);
541
+ const doc = document.body ?? document.documentElement;
542
+ doc.appendChild(host);
543
+ setTimeout(() => {
544
+ doc.appendChild(host);
545
+ }, MOUNT_ROOT_RECHECK_DELAY_MS);
546
+ return root;
547
+ };
548
+
549
+ //#endregion
550
+ //#region src/core/noop-api.ts
551
+ const NOOP = () => {};
552
+ const createNoopApi = () => ({
553
+ activate: NOOP,
554
+ deactivate: NOOP,
555
+ toggle: NOOP,
556
+ comment: NOOP,
557
+ isActive: () => false,
558
+ isEnabled: () => false,
559
+ setEnabled: NOOP,
560
+ getToolbarState: () => null,
561
+ setToolbarState: NOOP,
562
+ onToolbarStateChange: () => NOOP,
563
+ dispose: NOOP,
564
+ copyElement: () => Promise.resolve(false),
565
+ getSource: () => Promise.resolve(null),
566
+ getStackContext: () => Promise.resolve(""),
567
+ getState: () => ({
568
+ isActive: false,
569
+ isDragging: false,
570
+ isCopying: false,
571
+ isPromptMode: false,
572
+ isSelectionBoxVisible: false,
573
+ isDragBoxVisible: false,
574
+ targetElement: null,
575
+ dragBounds: null,
576
+ grabbedBoxes: [],
577
+ labelInstances: [],
578
+ selectionFilePath: null,
579
+ toolbarState: null
580
+ }),
581
+ setOptions: NOOP,
582
+ registerPlugin: NOOP,
583
+ unregisterPlugin: NOOP,
584
+ getPlugins: () => [],
585
+ getDisplayName: () => null
586
+ });
587
+
588
+ //#endregion
589
+ //#region src/core/events.ts
590
+ const createEventListenerManager = () => {
591
+ const abortController = new AbortController();
592
+ const addWindowListener = (type, listener, options = {}) => {
593
+ window.addEventListener(type, listener, {
594
+ ...options,
595
+ signal: abortController.signal
596
+ });
597
+ };
598
+ const addDocumentListener = (type, listener, options = {}) => {
599
+ document.addEventListener(type, listener, {
600
+ ...options,
601
+ signal: abortController.signal
602
+ });
603
+ };
604
+ return {
605
+ signal: abortController.signal,
606
+ abort: () => abortController.abort(),
607
+ addWindowListener,
608
+ addDocumentListener
609
+ };
610
+ };
611
+
612
+ //#endregion
613
+ //#region src/utils/copy-content.ts
614
+ const REACT_GRAB_MIME_TYPE = "application/x-react-grab";
615
+ const escapeHtml = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
616
+ const copyContent = (content, options) => {
617
+ const elementName = options?.componentName ?? "div";
618
+ const reactGrabMetadata = {
619
+ version: VERSION,
620
+ content,
621
+ entries: options?.entries ?? [{
622
+ tagName: options?.tagName,
623
+ componentName: elementName,
624
+ content,
625
+ commentText: options?.commentText
626
+ }],
627
+ timestamp: Date.now()
628
+ };
629
+ const copyHandler = (event) => {
630
+ event.preventDefault();
631
+ event.clipboardData?.setData("text/plain", content);
632
+ event.clipboardData?.setData("text/html", `<meta charset='utf-8'><pre><code>${escapeHtml(content)}</code></pre>`);
633
+ event.clipboardData?.setData(REACT_GRAB_MIME_TYPE, JSON.stringify(reactGrabMetadata));
634
+ };
635
+ document.addEventListener("copy", copyHandler);
636
+ const textarea = document.createElement("textarea");
637
+ textarea.value = content;
638
+ textarea.style.position = "fixed";
639
+ textarea.style.left = "-9999px";
640
+ textarea.ariaHidden = "true";
641
+ document.body.appendChild(textarea);
642
+ textarea.select();
643
+ try {
644
+ if (typeof document.execCommand !== "function") return false;
645
+ return document.execCommand("copy");
646
+ } finally {
647
+ document.removeEventListener("copy", copyHandler);
648
+ textarea.remove();
649
+ }
650
+ };
651
+
652
+ //#endregion
653
+ //#region src/utils/generate-snippet.ts
654
+ const generateSnippet = async (elements, options = {}) => {
655
+ return (await Promise.allSettled(elements.map((element) => getElementContext(element, options)))).map((result) => result.status === "fulfilled" ? result.value : "");
656
+ };
657
+
658
+ //#endregion
659
+ //#region src/utils/join-snippets.ts
660
+ const joinSnippets = (snippets) => {
661
+ if (snippets.length <= 1) return snippets[0] ?? "";
662
+ return snippets.map((snippet, index) => `[${index + 1}]\n${snippet}`).join("\n\n");
663
+ };
664
+
665
+ //#endregion
666
+ //#region src/utils/normalize-error.ts
667
+ const normalizeErrorMessage = (error, fallback = "Unknown error") => error instanceof Error && error.message ? error.message : fallback;
668
+ const normalizeError = (error) => error instanceof Error ? error : new Error(String(error));
669
+
670
+ //#endregion
671
+ //#region src/core/copy.ts
672
+ const tryCopyWithFallback = async (options, hooks, elements, extraPrompt) => {
673
+ let didCopy = false;
674
+ let copiedContent = "";
675
+ await hooks.onBeforeCopy(elements);
676
+ try {
677
+ let generatedContent;
678
+ let entries;
679
+ if (options.getContent) generatedContent = await options.getContent(elements);
680
+ else {
681
+ const rawSnippets = await generateSnippet(elements, { maxLines: options.maxContextLines });
682
+ const snippetElementPairs = (await Promise.all(rawSnippets.map((snippet, index) => snippet.trim() ? hooks.transformSnippet(snippet, elements[index]) : Promise.resolve("")))).map((snippet, index) => ({
683
+ snippet,
684
+ element: elements[index]
685
+ })).filter(({ snippet }) => snippet.trim());
686
+ generatedContent = joinSnippets(snippetElementPairs.map(({ snippet }) => snippet));
687
+ entries = snippetElementPairs.map(({ snippet, element }) => ({
688
+ tagName: element.localName,
689
+ content: snippet,
690
+ commentText: extraPrompt
691
+ }));
692
+ }
693
+ if (generatedContent.trim()) {
694
+ const transformedContent = await hooks.transformCopyContent(generatedContent, elements);
695
+ copiedContent = extraPrompt ? `${extraPrompt}\n\n${transformedContent}` : transformedContent;
696
+ didCopy = copyContent(copiedContent, {
697
+ componentName: options.componentName,
698
+ entries
699
+ });
700
+ }
701
+ } catch (error) {
702
+ hooks.onCopyError(normalizeError(error));
703
+ }
704
+ if (didCopy) hooks.onCopySuccess(elements, copiedContent);
705
+ hooks.onAfterCopy(elements, didCopy);
706
+ return didCopy;
707
+ };
708
+
709
+ //#endregion
710
+ //#region src/utils/get-elements-in-drag.ts
711
+ const calculateIntersectionArea = (rect1, rect2) => {
712
+ const intersectionLeft = Math.max(rect1.left, rect2.left);
713
+ const intersectionTop = Math.max(rect1.top, rect2.top);
714
+ const intersectionRight = Math.min(rect1.right, rect2.right);
715
+ const intersectionBottom = Math.min(rect1.bottom, rect2.bottom);
716
+ return Math.max(0, intersectionRight - intersectionLeft) * Math.max(0, intersectionBottom - intersectionTop);
717
+ };
718
+ const hasIntersection = (rect1, rect2) => {
719
+ return rect1.left < rect2.right && rect1.right > rect2.left && rect1.top < rect2.bottom && rect1.bottom > rect2.top;
720
+ };
721
+ const sortByDocumentOrder = (elements) => {
722
+ return elements.sort((leftElement, rightElement) => {
723
+ if (leftElement === rightElement) return 0;
724
+ const position = leftElement.compareDocumentPosition(rightElement);
725
+ if (position & Node.DOCUMENT_POSITION_FOLLOWING) return -1;
726
+ if (position & Node.DOCUMENT_POSITION_PRECEDING) return 1;
727
+ return 0;
728
+ });
729
+ };
730
+ const createSamplePoints = (dragRect) => {
731
+ if (dragRect.width <= 0 || dragRect.height <= 0) return [];
732
+ const viewportWidth = window.innerWidth;
733
+ const viewportHeight = window.innerHeight;
734
+ const left = dragRect.x;
735
+ const top = dragRect.y;
736
+ const right = dragRect.x + dragRect.width;
737
+ const bottom = dragRect.y + dragRect.height;
738
+ const centerX = left + dragRect.width / 2;
739
+ const centerY = top + dragRect.height / 2;
740
+ const xCount = clampToRange(Math.ceil(dragRect.width / 32), 3, 20);
741
+ const yCount = clampToRange(Math.ceil(dragRect.height / 32), 3, 20);
742
+ const totalGridPoints = xCount * yCount;
743
+ const scale = totalGridPoints > 100 ? Math.sqrt(100 / totalGridPoints) : 1;
744
+ const scaledXCount = clampToRange(Math.floor(xCount * scale), 3, 20);
745
+ const scaledYCount = clampToRange(Math.floor(yCount * scale), 3, 20);
746
+ const pointKeys = /* @__PURE__ */ new Set();
747
+ const points = [];
748
+ const addPoint = (x, y) => {
749
+ const clampedX = clampToRange(Math.round(x), 0, viewportWidth - 1);
750
+ const clampedY = clampToRange(Math.round(y), 0, viewportHeight - 1);
751
+ const key = `${clampedX}:${clampedY}`;
752
+ if (pointKeys.has(key)) return;
753
+ pointKeys.add(key);
754
+ points.push({
755
+ x: clampedX,
756
+ y: clampedY
757
+ });
758
+ };
759
+ addPoint(left + 1, top + 1);
760
+ addPoint(right - 1, top + 1);
761
+ addPoint(left + 1, bottom - 1);
762
+ addPoint(right - 1, bottom - 1);
763
+ addPoint(centerX, top + 1);
764
+ addPoint(centerX, bottom - 1);
765
+ addPoint(left + 1, centerY);
766
+ addPoint(right - 1, centerY);
767
+ addPoint(centerX, centerY);
768
+ for (let xIndex = 0; xIndex < scaledXCount; xIndex += 1) {
769
+ const sampleX = left + (xIndex + .5) / scaledXCount * dragRect.width;
770
+ for (let yIndex = 0; yIndex < scaledYCount; yIndex += 1) addPoint(sampleX, top + (yIndex + .5) / scaledYCount * dragRect.height);
771
+ }
772
+ return points;
773
+ };
774
+ const filterElementsInDrag = (dragRect, isValidGrabbableElement, shouldCheckCoverage) => {
775
+ const dragBounds = {
776
+ left: dragRect.x,
777
+ top: dragRect.y,
778
+ right: dragRect.x + dragRect.width,
779
+ bottom: dragRect.y + dragRect.height
780
+ };
781
+ const candidates = /* @__PURE__ */ new Set();
782
+ const samplePoints = createSamplePoints(dragRect);
783
+ suspendPointerEventsFreeze();
784
+ try {
785
+ for (const point of samplePoints) {
786
+ const elementsAtPoint = document.elementsFromPoint(point.x, point.y);
787
+ for (const candidateElement of elementsAtPoint) candidates.add(candidateElement);
788
+ }
789
+ } finally {
790
+ resumePointerEventsFreeze();
791
+ }
792
+ const validCandidates = [];
793
+ for (const candidateElement of candidates) {
794
+ if (!shouldCheckCoverage && isRootElement(candidateElement)) continue;
795
+ if (!isValidGrabbableElement(candidateElement)) continue;
796
+ validCandidates.push(candidateElement);
797
+ }
798
+ const candidateRects = /* @__PURE__ */ new Map();
799
+ for (const candidateElement of validCandidates) candidateRects.set(candidateElement, candidateElement.getBoundingClientRect());
800
+ const matchingElements = [];
801
+ for (const candidateElement of validCandidates) {
802
+ const elementRect = candidateRects.get(candidateElement);
803
+ if (elementRect.width <= 0 || elementRect.height <= 0) continue;
804
+ const elementBounds = {
805
+ left: elementRect.left,
806
+ top: elementRect.top,
807
+ right: elementRect.left + elementRect.width,
808
+ bottom: elementRect.top + elementRect.height
809
+ };
810
+ if (shouldCheckCoverage) {
811
+ const intersectionArea = calculateIntersectionArea(dragBounds, elementBounds);
812
+ const elementArea = elementRect.width * elementRect.height;
813
+ if (elementArea > 0 && intersectionArea / elementArea >= .75) matchingElements.push(candidateElement);
814
+ } else if (hasIntersection(elementBounds, dragBounds)) matchingElements.push(candidateElement);
815
+ }
816
+ return sortByDocumentOrder(matchingElements);
817
+ };
818
+ const removeNestedElements = (elements) => {
819
+ return elements.filter((element) => {
820
+ return !elements.some((otherElement) => otherElement !== element && otherElement.contains(element));
821
+ });
822
+ };
823
+ const getElementsInDrag = (dragRect, isValidGrabbableElement, shouldCheckCoverage = true) => {
824
+ return removeNestedElements(filterElementsInDrag(dragRect, isValidGrabbableElement, shouldCheckCoverage));
825
+ };
826
+
827
+ //#endregion
828
+ //#region src/utils/get-ancestor-elements.ts
829
+ const getAncestorElements = (element) => {
830
+ const ancestors = [];
831
+ let current = element.parentElement;
832
+ while (current && !isRootElement(current)) {
833
+ ancestors.push(current);
834
+ current = current.parentElement;
835
+ }
836
+ return ancestors;
837
+ };
838
+
839
+ //#endregion
840
+ //#region src/utils/get-visible-bounds-center.ts
841
+ const getVisibleBoundsCenter = (bounds) => {
842
+ const viewportWidth = window.innerWidth;
843
+ const viewportHeight = window.innerHeight;
844
+ const visibleLeft = Math.max(0, bounds.x);
845
+ const visibleRight = Math.min(viewportWidth, bounds.x + bounds.width);
846
+ const visibleTop = Math.max(0, bounds.y);
847
+ const visibleBottom = Math.min(viewportHeight, bounds.y + bounds.height);
848
+ return {
849
+ x: (visibleLeft + visibleRight) / 2,
850
+ y: (visibleTop + visibleBottom) / 2
851
+ };
852
+ };
853
+
854
+ //#endregion
855
+ //#region src/utils/invalidate-interaction-caches.ts
856
+ const invalidateInteractionCaches = () => {
857
+ invalidateBoundsCache();
858
+ clearElementPositionCache();
859
+ clearVisibilityCache();
860
+ };
861
+
862
+ //#endregion
863
+ //#region src/utils/create-bounds-from-drag-rect.ts
864
+ const createBoundsFromDragRect = (dragRect) => ({
865
+ x: dragRect.pageX - window.scrollX,
866
+ y: dragRect.pageY - window.scrollY,
867
+ width: dragRect.width,
868
+ height: dragRect.height,
869
+ borderRadius: "0px",
870
+ transform: "none"
871
+ });
872
+ const createPageRectFromBounds = (bounds) => ({
873
+ pageX: bounds.x + window.scrollX,
874
+ pageY: bounds.y + window.scrollY,
875
+ width: bounds.width,
876
+ height: bounds.height
877
+ });
878
+ const createFlatOverlayBounds = (bounds) => ({
879
+ ...bounds,
880
+ borderRadius: "0px",
881
+ transform: "none"
882
+ });
883
+
884
+ //#endregion
885
+ //#region src/utils/get-element-bounds-center.ts
886
+ const getElementBoundsCenter = (element) => {
887
+ return { center: getBoundsCenter(createElementBounds(element)) };
888
+ };
889
+
890
+ //#endregion
891
+ //#region src/utils/get-element-center.ts
892
+ const getElementCenter = (element) => getBoundsCenter(createElementBounds(element));
893
+
894
+ //#endregion
895
+ //#region src/utils/is-c-like-key.ts
896
+ const C_LIKE_CHARACTERS = new Set([
897
+ "c",
898
+ "C",
899
+ "с",
900
+ "С",
901
+ "ȼ",
902
+ "Ȼ",
903
+ "ↄ",
904
+ "Ↄ",
905
+ "ᴄ",
906
+ "ᶜ",
907
+ "ⱼ",
908
+ "ⅽ",
909
+ "Ⅽ",
910
+ "ç",
911
+ "Ç",
912
+ "ć",
913
+ "Ć",
914
+ "č",
915
+ "Č",
916
+ "ĉ",
917
+ "Ĉ",
918
+ "ċ",
919
+ "Ċ"
920
+ ]);
921
+ const isCLikeKey = (key, code) => {
922
+ if (code === "KeyC") return true;
923
+ if (!key || key.length !== 1) return false;
924
+ return C_LIKE_CHARACTERS.has(key);
925
+ };
926
+
927
+ //#endregion
928
+ //#region src/utils/key-matches-code.ts
929
+ const keyMatchesCode = (targetKey, code) => {
930
+ const normalizedTarget = targetKey.toLowerCase();
931
+ if (code === "Space") return normalizedTarget === "space" || normalizedTarget === " ";
932
+ if (code.startsWith("Key")) return code.slice(3).toLowerCase() === normalizedTarget;
933
+ if (code.startsWith("Digit")) return code.slice(5) === normalizedTarget;
934
+ return false;
935
+ };
936
+
937
+ //#endregion
938
+ //#region src/utils/parse-activation-key.ts
939
+ const MODIFIER_MAP = {
940
+ meta: "metaKey",
941
+ cmd: "metaKey",
942
+ command: "metaKey",
943
+ win: "metaKey",
944
+ windows: "metaKey",
945
+ ctrl: "ctrlKey",
946
+ control: "ctrlKey",
947
+ shift: "shiftKey",
948
+ alt: "altKey",
949
+ option: "altKey",
950
+ opt: "altKey"
951
+ };
952
+ const parseString = (shortcut) => {
953
+ const parts = shortcut.split("+").map((part) => part.trim().toLowerCase());
954
+ const result = {
955
+ metaKey: false,
956
+ ctrlKey: false,
957
+ shiftKey: false,
958
+ altKey: false,
959
+ key: null
960
+ };
961
+ for (const part of parts) {
962
+ const modifierKey = MODIFIER_MAP[part];
963
+ if (modifierKey) result[modifierKey] = true;
964
+ else result.key = part;
965
+ }
966
+ return result;
967
+ };
968
+ const parseActivationKey = (activationKey) => {
969
+ if (typeof activationKey === "function") return activationKey;
970
+ const parsed = parseString(activationKey);
971
+ const targetKey = parsed.key;
972
+ return (event) => {
973
+ if (targetKey === null) {
974
+ const metaMatches = parsed.metaKey ? event.metaKey || event.key === "Meta" : true;
975
+ const ctrlMatches = parsed.ctrlKey ? event.ctrlKey || event.key === "Control" : true;
976
+ const shiftMatches = parsed.shiftKey ? event.shiftKey || event.key === "Shift" : true;
977
+ const altMatches = parsed.altKey ? event.altKey || event.key === "Alt" : true;
978
+ const allRequiredModifiersPressed = metaMatches && ctrlMatches && shiftMatches && altMatches;
979
+ const requiredModifierCount = [
980
+ parsed.metaKey,
981
+ parsed.ctrlKey,
982
+ parsed.shiftKey,
983
+ parsed.altKey
984
+ ].filter(Boolean).length;
985
+ const pressedModifierCount = [
986
+ event.metaKey || event.key === "Meta",
987
+ event.ctrlKey || event.key === "Control",
988
+ event.shiftKey || event.key === "Shift",
989
+ event.altKey || event.key === "Alt"
990
+ ].filter(Boolean).length;
991
+ return allRequiredModifiersPressed && pressedModifierCount >= requiredModifierCount;
992
+ }
993
+ const keyMatches = event.key?.toLowerCase() === targetKey || keyMatchesCode(targetKey, event.code);
994
+ const modifiersMatch = parsed.metaKey || parsed.ctrlKey || parsed.shiftKey || parsed.altKey ? (parsed.metaKey ? event.metaKey : true) && (parsed.ctrlKey ? event.ctrlKey : true) && (parsed.shiftKey ? event.shiftKey : true) && (parsed.altKey ? event.altKey : true) : !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;
995
+ return keyMatches && modifiersMatch;
996
+ };
997
+ };
998
+ const getModifiersFromActivationKey = (activationKey) => {
999
+ if (!activationKey || typeof activationKey === "function") return {
1000
+ metaKey: isMac(),
1001
+ ctrlKey: !isMac(),
1002
+ shiftKey: false,
1003
+ altKey: false,
1004
+ key: null
1005
+ };
1006
+ return parseString(activationKey);
1007
+ };
1008
+
1009
+ //#endregion
1010
+ //#region src/utils/is-target-key-combination.ts
1011
+ const isTargetKeyCombination = (event, options) => {
1012
+ if (options.activationKey) return parseActivationKey(options.activationKey)(event);
1013
+ const hasOnlyPlatformModifier = (isMac() ? event.metaKey : event.ctrlKey) && !event.shiftKey && !event.altKey;
1014
+ return Boolean(event.key && hasOnlyPlatformModifier && isCLikeKey(event.key, event.code));
1015
+ };
1016
+
1017
+ //#endregion
1018
+ //#region src/utils/combine-bounds.ts
1019
+ const combineBounds = (boundsList) => {
1020
+ if (boundsList.length === 0) return {
1021
+ x: 0,
1022
+ y: 0,
1023
+ width: 0,
1024
+ height: 0
1025
+ };
1026
+ if (boundsList.length === 1) return boundsList[0];
1027
+ let minX = Infinity;
1028
+ let minY = Infinity;
1029
+ let maxX = -Infinity;
1030
+ let maxY = -Infinity;
1031
+ for (const bounds of boundsList) {
1032
+ minX = Math.min(minX, bounds.x);
1033
+ minY = Math.min(minY, bounds.y);
1034
+ maxX = Math.max(maxX, bounds.x + bounds.width);
1035
+ maxY = Math.max(maxY, bounds.y + bounds.height);
1036
+ }
1037
+ return {
1038
+ x: minX,
1039
+ y: minY,
1040
+ width: maxX - minX,
1041
+ height: maxY - minY
1042
+ };
1043
+ };
1044
+
1045
+ //#endregion
1046
+ //#region src/core/theme.ts
1047
+ const DEFAULT_THEME = {
1048
+ enabled: true,
1049
+ hue: 0,
1050
+ selectionBox: { enabled: true },
1051
+ dragBox: { enabled: true },
1052
+ grabbedBoxes: { enabled: true },
1053
+ elementLabel: { enabled: true },
1054
+ toolbar: { enabled: true }
1055
+ };
1056
+ const deepMergeTheme = (baseTheme, partialTheme) => ({
1057
+ enabled: partialTheme.enabled ?? baseTheme.enabled,
1058
+ hue: partialTheme.hue ?? baseTheme.hue,
1059
+ selectionBox: { enabled: partialTheme.selectionBox?.enabled ?? baseTheme.selectionBox.enabled },
1060
+ dragBox: { enabled: partialTheme.dragBox?.enabled ?? baseTheme.dragBox.enabled },
1061
+ grabbedBoxes: { enabled: partialTheme.grabbedBoxes?.enabled ?? baseTheme.grabbedBoxes.enabled },
1062
+ elementLabel: { enabled: partialTheme.elementLabel?.enabled ?? baseTheme.elementLabel.enabled },
1063
+ toolbar: { enabled: partialTheme.toolbar?.enabled ?? baseTheme.toolbar.enabled }
1064
+ });
1065
+
1066
+ //#endregion
1067
+ //#region src/core/plugin-registry.ts
1068
+ const DEFAULT_OPTIONS = {
1069
+ activationMode: "toggle",
1070
+ keyHoldDuration: 100,
1071
+ allowActivationInsideInput: true,
1072
+ maxContextLines: 3,
1073
+ activationKey: void 0,
1074
+ getContent: void 0,
1075
+ freezeReactUpdates: true
1076
+ };
1077
+ const createPluginRegistry = (initialOptions = {}) => {
1078
+ const plugins = /* @__PURE__ */ new Map();
1079
+ const directOptionOverrides = {};
1080
+ const [store, setStore] = createStore({
1081
+ theme: DEFAULT_THEME,
1082
+ options: {
1083
+ ...DEFAULT_OPTIONS,
1084
+ ...initialOptions
1085
+ },
1086
+ actions: []
1087
+ });
1088
+ const recomputeStore = () => {
1089
+ let mergedTheme = DEFAULT_THEME;
1090
+ let mergedOptions = {
1091
+ ...DEFAULT_OPTIONS,
1092
+ ...initialOptions
1093
+ };
1094
+ const allContextMenuActions = [];
1095
+ for (const { config } of plugins.values()) {
1096
+ if (config.theme) mergedTheme = deepMergeTheme(mergedTheme, config.theme);
1097
+ if (config.options) mergedOptions = {
1098
+ ...mergedOptions,
1099
+ ...config.options
1100
+ };
1101
+ if (config.actions) for (const action of config.actions) allContextMenuActions.push(action);
1102
+ }
1103
+ mergedOptions = {
1104
+ ...mergedOptions,
1105
+ ...directOptionOverrides
1106
+ };
1107
+ setStore("theme", mergedTheme);
1108
+ setStore("options", mergedOptions);
1109
+ setStore("actions", allContextMenuActions);
1110
+ };
1111
+ const setOption = (optionKey, optionValue) => {
1112
+ directOptionOverrides[optionKey] = optionValue;
1113
+ setStore("options", optionKey, optionValue);
1114
+ };
1115
+ const SETTABLE_OPTION_KEYS = [
1116
+ "activationMode",
1117
+ "keyHoldDuration",
1118
+ "allowActivationInsideInput",
1119
+ "maxContextLines",
1120
+ "activationKey",
1121
+ "getContent",
1122
+ "freezeReactUpdates"
1123
+ ];
1124
+ const setOptions = (optionUpdates) => {
1125
+ for (const optionKey of SETTABLE_OPTION_KEYS) if (optionUpdates[optionKey] !== void 0) setOption(optionKey, optionUpdates[optionKey]);
1126
+ };
1127
+ const register = (plugin, api) => {
1128
+ if (plugins.has(plugin.name)) unregister(plugin.name);
1129
+ const config = plugin.setup?.(api, hooks) ?? {};
1130
+ if (plugin.theme) config.theme = config.theme ? deepMergeTheme(deepMergeTheme(DEFAULT_THEME, plugin.theme), config.theme) : plugin.theme;
1131
+ if (plugin.actions) config.actions = [...plugin.actions, ...config.actions ?? []];
1132
+ if (plugin.hooks) config.hooks = config.hooks ? {
1133
+ ...plugin.hooks,
1134
+ ...config.hooks
1135
+ } : plugin.hooks;
1136
+ if (plugin.options) config.options = config.options ? {
1137
+ ...plugin.options,
1138
+ ...config.options
1139
+ } : plugin.options;
1140
+ plugins.set(plugin.name, {
1141
+ plugin,
1142
+ config
1143
+ });
1144
+ recomputeStore();
1145
+ };
1146
+ const unregister = (name) => {
1147
+ const registered = plugins.get(name);
1148
+ if (!registered) return;
1149
+ if (registered.config.cleanup) registered.config.cleanup();
1150
+ plugins.delete(name);
1151
+ recomputeStore();
1152
+ };
1153
+ const getPluginNames = () => {
1154
+ return Array.from(plugins.keys());
1155
+ };
1156
+ const callHook = (hookName, ...args) => {
1157
+ for (const { config } of plugins.values()) {
1158
+ const hook = config.hooks?.[hookName];
1159
+ if (hook) hook(...args);
1160
+ }
1161
+ };
1162
+ const callHookWithHandled = (hookName, ...args) => {
1163
+ let handled = false;
1164
+ for (const { config } of plugins.values()) {
1165
+ const hook = config.hooks?.[hookName];
1166
+ if (hook) {
1167
+ if (hook(...args) === true) handled = true;
1168
+ }
1169
+ }
1170
+ return handled;
1171
+ };
1172
+ const callHookAsync = async (hookName, ...args) => {
1173
+ for (const { config } of plugins.values()) {
1174
+ const hook = config.hooks?.[hookName];
1175
+ if (hook) await hook(...args);
1176
+ }
1177
+ };
1178
+ const callHookReduce = async (hookName, initialValue, ...extraArgs) => {
1179
+ let result = initialValue;
1180
+ for (const { config } of plugins.values()) {
1181
+ const hook = config.hooks?.[hookName];
1182
+ if (hook) result = await hook(result, ...extraArgs);
1183
+ }
1184
+ return result;
1185
+ };
1186
+ const callHookReduceSync = (hookName, initialValue, ...extraArgs) => {
1187
+ let result = initialValue;
1188
+ for (const { config } of plugins.values()) {
1189
+ const hook = config.hooks?.[hookName];
1190
+ if (hook) result = hook(result, ...extraArgs);
1191
+ }
1192
+ return result;
1193
+ };
1194
+ const hooks = {
1195
+ onActivate: () => callHook("onActivate"),
1196
+ onDeactivate: () => callHook("onDeactivate"),
1197
+ onElementHover: (element) => callHook("onElementHover", element),
1198
+ onElementSelect: (element) => {
1199
+ let wasIntercepted = false;
1200
+ let pendingResult;
1201
+ for (const { config } of plugins.values()) {
1202
+ const hook = config.hooks?.onElementSelect;
1203
+ if (hook) {
1204
+ const result = hook(element);
1205
+ if (result === true) wasIntercepted = true;
1206
+ else if (result instanceof Promise) {
1207
+ wasIntercepted = true;
1208
+ pendingResult = result;
1209
+ }
1210
+ }
1211
+ }
1212
+ return {
1213
+ wasIntercepted,
1214
+ pendingResult
1215
+ };
1216
+ },
1217
+ onDragStart: (startX, startY) => callHook("onDragStart", startX, startY),
1218
+ onDragEnd: (elements, bounds) => callHook("onDragEnd", elements, bounds),
1219
+ onBeforeCopy: async (elements) => callHookAsync("onBeforeCopy", elements),
1220
+ transformCopyContent: async (content, elements) => callHookReduce("transformCopyContent", content, elements),
1221
+ onAfterCopy: (elements, success) => callHook("onAfterCopy", elements, success),
1222
+ onCopySuccess: (elements, content) => callHook("onCopySuccess", elements, content),
1223
+ onCopyError: (error) => callHook("onCopyError", error),
1224
+ onStateChange: (state) => callHook("onStateChange", state),
1225
+ onPromptModeChange: (isPromptMode, context) => callHook("onPromptModeChange", isPromptMode, context),
1226
+ onSelectionBox: (visible, bounds, element) => callHook("onSelectionBox", visible, bounds, element),
1227
+ onDragBox: (visible, bounds) => callHook("onDragBox", visible, bounds),
1228
+ onGrabbedBox: (bounds, element) => callHook("onGrabbedBox", bounds, element),
1229
+ onElementLabel: (visible, variant, context) => callHook("onElementLabel", visible, variant, context),
1230
+ onContextMenu: (element, position) => callHook("onContextMenu", element, position),
1231
+ onOpenFile: (filePath, lineNumber) => callHookWithHandled("onOpenFile", filePath, lineNumber),
1232
+ transformHtmlContent: async (html, elements) => callHookReduce("transformHtmlContent", html, elements),
1233
+ transformAgentContext: async (context, elements) => callHookReduce("transformAgentContext", context, elements),
1234
+ transformActionContext: (context) => callHookReduceSync("transformActionContext", context),
1235
+ transformOpenFileUrl: (url, filePath, lineNumber) => callHookReduceSync("transformOpenFileUrl", url, filePath, lineNumber),
1236
+ transformSnippet: async (snippet, element) => callHookReduce("transformSnippet", snippet, element)
1237
+ };
1238
+ return {
1239
+ register,
1240
+ unregister,
1241
+ getPluginNames,
1242
+ setOptions,
1243
+ store,
1244
+ hooks
1245
+ };
1246
+ };
1247
+
1248
+ //#endregion
1249
+ //#region src/core/arrow-navigation.ts
1250
+ const createArrowNavigator = (isValidGrabbableElement, createElementBounds) => {
1251
+ let navigationHistory = [];
1252
+ const findVerticalNext = (currentElement, direction) => {
1253
+ const probePoint = getVisibleBoundsCenter(createElementBounds(currentElement));
1254
+ const elementsAtPoint = getElementsAtPoint(probePoint.x, probePoint.y).filter(isValidGrabbableElement);
1255
+ const currentIndex = elementsAtPoint.indexOf(currentElement);
1256
+ if (currentIndex === -1) return null;
1257
+ return elementsAtPoint[currentIndex + direction] ?? null;
1258
+ };
1259
+ const findUp = (currentElement) => {
1260
+ const nextElement = findVerticalNext(currentElement, 1);
1261
+ if (nextElement) {
1262
+ navigationHistory.push(currentElement);
1263
+ if (navigationHistory.length > 50) navigationHistory = navigationHistory.slice(-50);
1264
+ }
1265
+ return nextElement;
1266
+ };
1267
+ const findDown = (currentElement) => {
1268
+ if (navigationHistory.length > 0) {
1269
+ const previousElement = navigationHistory.pop();
1270
+ if (isElementConnected(previousElement)) return previousElement;
1271
+ }
1272
+ return findVerticalNext(currentElement, -1);
1273
+ };
1274
+ const findHorizontal = (currentElement, isForward) => {
1275
+ const findEdgeDescendant = (parentElement) => {
1276
+ const children = Array.from(parentElement.children);
1277
+ const ordered = isForward ? children : children.reverse();
1278
+ for (const childElement of ordered) if (isForward) {
1279
+ if (isValidGrabbableElement(childElement)) return childElement;
1280
+ const descendant = findEdgeDescendant(childElement);
1281
+ if (descendant) return descendant;
1282
+ } else {
1283
+ const descendant = findEdgeDescendant(childElement);
1284
+ if (descendant) return descendant;
1285
+ if (isValidGrabbableElement(childElement)) return childElement;
1286
+ }
1287
+ return null;
1288
+ };
1289
+ const getSibling = (element) => isForward ? element.nextElementSibling : element.previousElementSibling;
1290
+ let nextElement = null;
1291
+ if (isForward) nextElement = findEdgeDescendant(currentElement);
1292
+ if (!nextElement) {
1293
+ let searchElement = currentElement;
1294
+ while (searchElement) {
1295
+ let sibling = getSibling(searchElement);
1296
+ while (sibling) {
1297
+ const descendant = findEdgeDescendant(sibling);
1298
+ if (descendant) {
1299
+ nextElement = descendant;
1300
+ break;
1301
+ }
1302
+ if (isValidGrabbableElement(sibling)) {
1303
+ nextElement = sibling;
1304
+ break;
1305
+ }
1306
+ sibling = getSibling(sibling);
1307
+ }
1308
+ if (nextElement) break;
1309
+ const parentElement = searchElement.parentElement;
1310
+ if (!isForward && parentElement && isValidGrabbableElement(parentElement)) {
1311
+ nextElement = parentElement;
1312
+ break;
1313
+ }
1314
+ searchElement = parentElement;
1315
+ }
1316
+ }
1317
+ return nextElement;
1318
+ };
1319
+ const findNext = (key, currentElement) => {
1320
+ switch (key) {
1321
+ case "ArrowUp": return findUp(currentElement);
1322
+ case "ArrowDown": return findDown(currentElement);
1323
+ case "ArrowRight": return findHorizontal(currentElement, true);
1324
+ case "ArrowLeft": return findHorizontal(currentElement, false);
1325
+ default: return null;
1326
+ }
1327
+ };
1328
+ const clearHistory = () => {
1329
+ navigationHistory = [];
1330
+ };
1331
+ return {
1332
+ findNext,
1333
+ clearHistory
1334
+ };
1335
+ };
1336
+
1337
+ //#endregion
1338
+ //#region src/core/keyboard-handlers.ts
1339
+ const getRequiredModifiers = (options) => {
1340
+ const { metaKey, ctrlKey, shiftKey, altKey } = getModifiersFromActivationKey(options.activationKey);
1341
+ return {
1342
+ metaKey,
1343
+ ctrlKey,
1344
+ shiftKey,
1345
+ altKey
1346
+ };
1347
+ };
1348
+ const setupKeyboardEventClaimer = () => {
1349
+ const claimedEvents = /* @__PURE__ */ new WeakSet();
1350
+ const originalKeyDescriptor = Object.getOwnPropertyDescriptor(KeyboardEvent.prototype, "key");
1351
+ let didPatch = false;
1352
+ if (originalKeyDescriptor?.get && !originalKeyDescriptor.get.__reactGrabPatched) {
1353
+ didPatch = true;
1354
+ const originalGetter = originalKeyDescriptor.get;
1355
+ const patchedGetter = function() {
1356
+ if (claimedEvents.has(this)) return "";
1357
+ return originalGetter.call(this);
1358
+ };
1359
+ patchedGetter.__reactGrabPatched = true;
1360
+ Object.defineProperty(KeyboardEvent.prototype, "key", {
1361
+ get: patchedGetter,
1362
+ configurable: true
1363
+ });
1364
+ }
1365
+ const restore = () => {
1366
+ if (didPatch && originalKeyDescriptor) Object.defineProperty(KeyboardEvent.prototype, "key", originalKeyDescriptor);
1367
+ };
1368
+ return {
1369
+ claimedEvents,
1370
+ originalKeyDescriptor,
1371
+ restore
1372
+ };
1373
+ };
1374
+
1375
+ //#endregion
1376
+ //#region src/core/auto-scroll.ts
1377
+ const getAutoScrollDirection = (clientX, clientY) => {
1378
+ return {
1379
+ top: clientY < 25,
1380
+ bottom: clientY > window.innerHeight - 25,
1381
+ left: clientX < 25,
1382
+ right: clientX > window.innerWidth - 25
1383
+ };
1384
+ };
1385
+ const createAutoScroller = (getMousePosition, shouldContinue) => {
1386
+ let animationId = null;
1387
+ const scroll = () => {
1388
+ if (!shouldContinue()) {
1389
+ stop();
1390
+ return;
1391
+ }
1392
+ const position = getMousePosition();
1393
+ const direction = getAutoScrollDirection(position.x, position.y);
1394
+ if (direction.top) window.scrollBy(0, -10);
1395
+ if (direction.bottom) window.scrollBy(0, 10);
1396
+ if (direction.left) window.scrollBy(-10, 0);
1397
+ if (direction.right) window.scrollBy(10, 0);
1398
+ if (direction.top || direction.bottom || direction.left || direction.right) animationId = nativeRequestAnimationFrame(scroll);
1399
+ else animationId = null;
1400
+ };
1401
+ const stop = () => {
1402
+ if (animationId !== null) {
1403
+ nativeCancelAnimationFrame(animationId);
1404
+ animationId = null;
1405
+ }
1406
+ };
1407
+ const isActive = () => animationId !== null;
1408
+ return {
1409
+ start: scroll,
1410
+ stop,
1411
+ isActive
1412
+ };
1413
+ };
1414
+
1415
+ //#endregion
1416
+ //#region src/core/logo-svg.ts
1417
+ const LOGO_SVG = `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 294 294"><path fill="#ff40e0" d="M145 47c25-20 50-27 67-17 16 9 23 30 20 60 0 2-1 5-1 7l-2 13h-1l-12-4c-8-3-17-5-25-6l-17-3c-10-1-20-1-29-1-10 0-20 0-29 1-6 8-11 16-16 24-5 9-9 17-13 26 4 9 8 18 13 26s10 16 16 24l11 14c5 7 11 13 18 19l10 8s-1 0 0 0l-11 9c-17 14-35 22-49 22-6 0-13-2-18-5-16-9-23-30-20-59 1-3 1-5 1-8-30-12-48-29-48-50 0-18 14-35 41-47 2-1 5-2 7-3 0-2 0-5-1-7-3-30 4-51 20-60 18-10 42-3 68 17M71 201c-1 2-1 4-1 5-2 24 3 41 13 47h1c11 7 30 1 51-15-10-9-18-18-26-29-13-1-26-4-38-8m9-38c-3 9-5 17-7 26 8 2 17 4 25 6-3-5-6-10-9-16-3-5-6-10-9-16m-19-53c-2 1-3 1-5 2-21 10-34 23-34 35 0 13 14 27 39 37 3-12 7-25 12-37-5-12-9-24-12-37m37-10c-8 1-17 3-25 6 2 8 4 16 7 25 3-5 6-11 9-16zm-3-61c-4-1-8 0-12 2-10 7-15 24-13 47 0 2 0 3 1 5 12-4 25-6 38-8 8-10 16-20 26-29-15-11-29-17-40-17m111 2c-4-2-8-3-12-2-11 0-25 5-40 17 10 9 19 19 26 29 13 2 26 4 39 8v-5c3-23-2-40-13-47m-61 23c-7 6-13 13-19 19h37c-6-6-12-13-18-19"/><mask id="a"><path fill="#fff" d="m235 85-133 27 28 133 133-27Z"/></mask><path fill="#ff40e0" d="m137 130 76 11c8 1 9 11 3 15l-28 16-4 32c-1 8-10 10-14 4l-41-66c-3-6 1-13 8-12" mask="url(#a)"/></svg>`;
1418
+
1419
+ //#endregion
1420
+ //#region src/utils/is-extension-context.ts
1421
+ const isExtensionContext = () => {
1422
+ const global = globalThis;
1423
+ return Boolean(global.chrome?.runtime?.id || global.browser?.runtime?.id);
1424
+ };
1425
+
1426
+ //#endregion
1427
+ //#region src/core/log-intro.ts
1428
+ const logIntro = () => {
1429
+ try {
1430
+ const version = "[DEV]";
1431
+ const logoDataUri = `data:image/svg+xml;base64,${btoa(LOGO_SVG)}`;
1432
+ console.log(`%cReact Grab${` v${version}`}%c\nhttps://react-grab.com`, `background: #330039; color: #ffffff; border: 1px solid #d75fcb; padding: 4px 4px 4px 24px; border-radius: 4px; background-image: url("${logoDataUri}"); background-size: 16px 16px; background-repeat: no-repeat; background-position: 4px center; display: inline-block; margin-bottom: 4px;`, "");
1433
+ if (navigator.onLine && !isExtensionContext()) fetch(`https://www.react-grab.com/api/version?source=browser&t=${Date.now()}`, {
1434
+ referrerPolicy: "origin",
1435
+ keepalive: true,
1436
+ priority: "low",
1437
+ cache: "no-store"
1438
+ }).then((response) => response.text()).then((latestVersion) => {
1439
+ if (latestVersion && latestVersion !== version) console.warn(`[React Grab] v${version} is outdated (latest: v${latestVersion})`);
1440
+ }).catch(() => null);
1441
+ } catch {}
1442
+ };
1443
+
1444
+ //#endregion
1445
+ //#region src/utils/on-idle.ts
1446
+ const isBackgroundTaskScheduler = (value) => {
1447
+ if (typeof value !== "object" || value === null) return false;
1448
+ if (!("postTask" in value)) return false;
1449
+ return typeof value.postTask === "function";
1450
+ };
1451
+ const onIdle = (callback) => {
1452
+ if (typeof window !== "undefined") {
1453
+ const schedulerCandidate = window.scheduler;
1454
+ if (isBackgroundTaskScheduler(schedulerCandidate)) {
1455
+ schedulerCandidate.postTask(callback, { priority: "background" });
1456
+ return;
1457
+ }
1458
+ if ("requestIdleCallback" in window) {
1459
+ requestIdleCallback(callback);
1460
+ return;
1461
+ }
1462
+ }
1463
+ setTimeout(callback, 0);
1464
+ };
1465
+
1466
+ //#endregion
1467
+ //#region src/utils/get-script-options.ts
1468
+ const isObjectRecord = (value) => {
1469
+ return typeof value === "object" && value !== null;
1470
+ };
1471
+ const parseOptionsFromJson = (rawValue) => {
1472
+ if (!isObjectRecord(rawValue)) return null;
1473
+ const parsedOptions = {};
1474
+ if (typeof rawValue.enabled === "boolean") parsedOptions.enabled = rawValue.enabled;
1475
+ if (rawValue.activationMode === "toggle" || rawValue.activationMode === "hold") parsedOptions.activationMode = rawValue.activationMode;
1476
+ if (typeof rawValue.keyHoldDuration === "number" && Number.isFinite(rawValue.keyHoldDuration)) parsedOptions.keyHoldDuration = rawValue.keyHoldDuration;
1477
+ if (typeof rawValue.allowActivationInsideInput === "boolean") parsedOptions.allowActivationInsideInput = rawValue.allowActivationInsideInput;
1478
+ if (typeof rawValue.maxContextLines === "number" && Number.isFinite(rawValue.maxContextLines)) parsedOptions.maxContextLines = rawValue.maxContextLines;
1479
+ if (typeof rawValue.activationKey === "string") parsedOptions.activationKey = rawValue.activationKey;
1480
+ if (typeof rawValue.freezeReactUpdates === "boolean") parsedOptions.freezeReactUpdates = rawValue.freezeReactUpdates;
1481
+ if (Object.keys(parsedOptions).length === 0) return null;
1482
+ return parsedOptions;
1483
+ };
1484
+ const getScriptOptions = () => {
1485
+ if (typeof window === "undefined") return null;
1486
+ try {
1487
+ const dataOptions = (document.currentScript instanceof HTMLScriptElement ? document.currentScript : null)?.getAttribute("data-options");
1488
+ if (!dataOptions) return null;
1489
+ return parseOptionsFromJson(JSON.parse(dataOptions));
1490
+ } catch {
1491
+ return null;
1492
+ }
1493
+ };
1494
+
1495
+ //#endregion
1496
+ //#region src/utils/is-enter-code.ts
1497
+ const isEnterCode = (code) => code === "Enter" || code === "NumpadEnter";
1498
+
1499
+ //#endregion
1500
+ //#region src/core/plugins/create-pending-selection-plugin.ts
1501
+ const createPendingSelectionPlugin = (config) => ({
1502
+ name: config.name,
1503
+ setup: (api, hooks) => {
1504
+ return {
1505
+ actions: [typeof config.contextMenuAction === "function" ? config.contextMenuAction(api, hooks) : config.contextMenuAction],
1506
+ cleanup: config.cleanup
1507
+ };
1508
+ }
1509
+ });
1510
+
1511
+ //#endregion
1512
+ //#region src/core/plugins/copy.ts
1513
+ const copyPlugin = createPendingSelectionPlugin({
1514
+ name: "copy",
1515
+ contextMenuAction: {
1516
+ id: "copy",
1517
+ label: "Copy",
1518
+ shortcut: "C",
1519
+ showInToolbarMenu: true,
1520
+ onAction: (context) => {
1521
+ context.copy?.();
1522
+ }
1523
+ }
1524
+ });
1525
+
1526
+ //#endregion
1527
+ //#region src/core/plugins/comment.ts
1528
+ const commentPlugin = {
1529
+ name: "comment",
1530
+ setup: () => ({ actions: [{
1531
+ id: "comment",
1532
+ label: "Comment",
1533
+ shortcut: "Enter",
1534
+ showInToolbarMenu: true,
1535
+ onAction: (context) => {
1536
+ context.enterPromptMode?.();
1537
+ }
1538
+ }] })
1539
+ };
1540
+
1541
+ //#endregion
1542
+ //#region src/core/plugins/open.ts
1543
+ const openPlugin = {
1544
+ name: "open",
1545
+ actions: [{
1546
+ id: "open",
1547
+ label: "Open",
1548
+ shortcut: "O",
1549
+ enabled: (context) => Boolean(context.filePath),
1550
+ onAction: (context) => {
1551
+ if (!context.filePath) return;
1552
+ if (!context.hooks.onOpenFile(context.filePath, context.lineNumber)) openFile(context.filePath, context.lineNumber, context.hooks.transformOpenFileUrl);
1553
+ context.hideContextMenu();
1554
+ context.cleanup();
1555
+ }
1556
+ }]
1557
+ };
1558
+
1559
+ //#endregion
1560
+ //#region src/utils/append-stack-context.ts
1561
+ const appendStackContext = (content, stackContext) => {
1562
+ if (!stackContext) return content;
1563
+ return `${content}\n${stackContext}`;
1564
+ };
1565
+
1566
+ //#endregion
1567
+ //#region src/core/plugins/copy-html.ts
1568
+ const copyHtmlPlugin = createPendingSelectionPlugin({
1569
+ name: "copy-html",
1570
+ contextMenuAction: (api) => ({
1571
+ id: "copy-html",
1572
+ label: "Copy HTML",
1573
+ showInToolbarMenu: true,
1574
+ onAction: async (context) => {
1575
+ await context.performWithFeedback(async () => {
1576
+ const combinedHtml = context.elements.map((element) => element.outerHTML).join("\n\n");
1577
+ const transformedHtml = await context.hooks.transformHtmlContent(combinedHtml, context.elements);
1578
+ if (!transformedHtml) return false;
1579
+ return copyContent(appendStackContext(transformedHtml, await api.getStackContext(context.element)), {
1580
+ componentName: context.componentName,
1581
+ tagName: context.tagName
1582
+ });
1583
+ });
1584
+ }
1585
+ })
1586
+ });
1587
+
1588
+ //#endregion
1589
+ //#region src/core/plugins/copy-styles.ts
1590
+ const copyStylesPlugin = createPendingSelectionPlugin({
1591
+ name: "copy-styles",
1592
+ contextMenuAction: (api) => ({
1593
+ id: "copy-styles",
1594
+ label: "Copy styles",
1595
+ showInToolbarMenu: true,
1596
+ onAction: async (context) => {
1597
+ await context.performWithFeedback(async () => {
1598
+ return copyContent(appendStackContext(context.elements.map(extractElementCss).join("\n\n"), await api.getStackContext(context.element)), {
1599
+ componentName: context.componentName,
1600
+ tagName: context.tagName
1601
+ });
1602
+ });
1603
+ }
1604
+ }),
1605
+ cleanup: disposeBaselineStyles
1606
+ });
1607
+
1608
+ //#endregion
1609
+ //#region src/utils/generate-id.ts
1610
+ const generateId = (prefix) => `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
1611
+
1612
+ //#endregion
1613
+ //#region src/utils/comment-storage.ts
1614
+ const COMMENT_ITEMS_KEY = "react-grab-comment-items";
1615
+ const LEGACY_COMMENT_ITEMS_KEY = "react-grab-history-items";
1616
+ const CLEAR_CONFIRMED_KEY = "react-grab-clear-confirmed";
1617
+ const migrateFromLegacyStorage = () => {
1618
+ try {
1619
+ const legacyData = sessionStorage.getItem(LEGACY_COMMENT_ITEMS_KEY);
1620
+ if (legacyData && !sessionStorage.getItem(COMMENT_ITEMS_KEY)) sessionStorage.setItem(COMMENT_ITEMS_KEY, legacyData);
1621
+ sessionStorage.removeItem(LEGACY_COMMENT_ITEMS_KEY);
1622
+ } catch {}
1623
+ };
1624
+ const loadFromSessionStorage = () => {
1625
+ try {
1626
+ const serialized = sessionStorage.getItem(COMMENT_ITEMS_KEY);
1627
+ if (!serialized) return [];
1628
+ return JSON.parse(serialized).map((commentItem) => ({
1629
+ ...commentItem,
1630
+ elementsCount: Math.max(1, commentItem.elementsCount ?? 1),
1631
+ previewBounds: commentItem.previewBounds ?? [],
1632
+ elementSelectors: commentItem.elementSelectors ?? []
1633
+ }));
1634
+ } catch (error) {
1635
+ logRecoverableError("Failed to load comments from sessionStorage", error);
1636
+ return [];
1637
+ }
1638
+ };
1639
+ const readSessionFlag = (key) => {
1640
+ try {
1641
+ return sessionStorage.getItem(key) === "1";
1642
+ } catch {
1643
+ return false;
1644
+ }
1645
+ };
1646
+ const trimToSizeLimit = (items) => {
1647
+ let trimmedItems = items;
1648
+ while (trimmedItems.length > 0) {
1649
+ const serialized = JSON.stringify(trimmedItems);
1650
+ if (new Blob([serialized]).size <= 2097152) return trimmedItems;
1651
+ trimmedItems = trimmedItems.slice(0, -1);
1652
+ }
1653
+ return trimmedItems;
1654
+ };
1655
+ const persistCommentItems = (nextItems) => {
1656
+ commentItems = trimToSizeLimit(nextItems);
1657
+ try {
1658
+ sessionStorage.setItem(COMMENT_ITEMS_KEY, JSON.stringify(commentItems));
1659
+ } catch (error) {
1660
+ logRecoverableError("Failed to save comments to sessionStorage", error);
1661
+ }
1662
+ return commentItems;
1663
+ };
1664
+ migrateFromLegacyStorage();
1665
+ let commentItems = loadFromSessionStorage();
1666
+ let didConfirmClear = readSessionFlag(CLEAR_CONFIRMED_KEY);
1667
+ const loadComments = () => commentItems;
1668
+ const addCommentItem = (item) => persistCommentItems([{
1669
+ ...item,
1670
+ id: generateId("comment")
1671
+ }, ...commentItems].slice(0, 20));
1672
+ const removeCommentItem = (itemId) => {
1673
+ persistCommentItems(commentItems.filter((innerItem) => innerItem.id !== itemId));
1674
+ };
1675
+ const clearComments = () => persistCommentItems([]);
1676
+ const isClearConfirmed = () => didConfirmClear;
1677
+ const confirmClear = () => {
1678
+ didConfirmClear = true;
1679
+ try {
1680
+ sessionStorage.setItem(CLEAR_CONFIRMED_KEY, "1");
1681
+ } catch (error) {
1682
+ logRecoverableError("Failed to save clear preference to sessionStorage", error);
1683
+ }
1684
+ };
1685
+
1686
+ //#endregion
1687
+ //#region src/utils/lock-viewport-zoom.ts
1688
+ const lockViewportZoom = () => {
1689
+ let meta = document.querySelector("meta[name=\"viewport\"]");
1690
+ const originalContent = meta?.getAttribute("content") ?? null;
1691
+ if (!meta) {
1692
+ meta = document.createElement("meta");
1693
+ meta.name = "viewport";
1694
+ document.head.appendChild(meta);
1695
+ }
1696
+ const content = originalContent ?? "";
1697
+ meta.content = /maximum-scale/.test(content) ? content.replace(/maximum-scale\s*=\s*[\d.]+/, "maximum-scale=1") : `${content}${content ? ", " : ""}maximum-scale=1`;
1698
+ return () => {
1699
+ if (originalContent !== null) meta.content = originalContent;
1700
+ else meta.remove();
1701
+ };
1702
+ };
1703
+
1704
+ //#endregion
1705
+ //#region src/utils/get-nearest-edge.ts
1706
+ const getNearestEdge = (rect) => {
1707
+ const centerX = rect.left + rect.width / 2;
1708
+ const centerY = rect.top + rect.height / 2;
1709
+ const distanceToTop = centerY;
1710
+ const distanceToBottom = window.innerHeight - centerY;
1711
+ const distanceToLeft = centerX;
1712
+ const distanceToRight = window.innerWidth - centerX;
1713
+ const minimumDistance = Math.min(distanceToTop, distanceToBottom, distanceToLeft, distanceToRight);
1714
+ if (minimumDistance === distanceToTop) return "top";
1715
+ if (minimumDistance === distanceToLeft) return "left";
1716
+ if (minimumDistance === distanceToRight) return "right";
1717
+ return "bottom";
1718
+ };
1719
+
1720
+ //#endregion
1721
+ //#region src/core/index.tsx
1722
+ const builtInPlugins = [
1723
+ copyPlugin,
1724
+ commentPlugin,
1725
+ copyHtmlPlugin,
1726
+ copyStylesPlugin,
1727
+ openPlugin
1728
+ ];
1729
+ let hasInited = false;
1730
+ const toolbarStateChangeCallbacks = /* @__PURE__ */ new Set();
1731
+ const init = (rawOptions) => {
1732
+ if (typeof window === "undefined") return createNoopApi();
1733
+ const initialOptions = {
1734
+ enabled: true,
1735
+ activationMode: "toggle",
1736
+ keyHoldDuration: 100,
1737
+ allowActivationInsideInput: true,
1738
+ maxContextLines: 3,
1739
+ ...getScriptOptions(),
1740
+ ...rawOptions
1741
+ };
1742
+ if (initialOptions.enabled === false || hasInited) return createNoopApi();
1743
+ hasInited = true;
1744
+ logIntro();
1745
+ const { enabled: _enabled, ...settableOptions } = initialOptions;
1746
+ return createRoot((dispose) => {
1747
+ let disposed = false;
1748
+ let disposeRenderer;
1749
+ const pluginRegistry = createPluginRegistry(settableOptions);
1750
+ const { store, actions } = createGrabStore({
1751
+ theme: DEFAULT_THEME,
1752
+ keyHoldDuration: pluginRegistry.store.options.keyHoldDuration ?? 100
1753
+ });
1754
+ const isHoldingKeys = createMemo(() => store.current.state === "holding");
1755
+ const isActivated = createMemo(() => store.current.state === "active");
1756
+ const isFrozenPhase = createMemo(() => store.current.state === "active" && store.current.phase === "frozen");
1757
+ const isDragging = createMemo(() => store.current.state === "active" && store.current.phase === "dragging");
1758
+ const didJustDrag = createMemo(() => store.current.state === "active" && store.current.phase === "justDragged");
1759
+ const isCopying = createMemo(() => store.current.state === "copying");
1760
+ const didJustCopy = createMemo(() => store.current.state === "justCopied");
1761
+ const isPromptMode = createMemo(() => store.current.state === "active" && Boolean(store.current.isPromptMode));
1762
+ const isCommentMode = createMemo(() => store.pendingCommentMode || isPromptMode());
1763
+ const isPendingDismiss = createMemo(() => store.current.state === "active" && Boolean(store.current.isPromptMode) && Boolean(store.current.isPendingDismiss));
1764
+ let unlockViewportZoom = null;
1765
+ createEffect(on(isActivated, (activated, previousActivated) => {
1766
+ if (activated && !previousActivated) {
1767
+ freezePseudoStates();
1768
+ freezeGlobalAnimations();
1769
+ document.body.style.touchAction = "none";
1770
+ unlockViewportZoom = lockViewportZoom();
1771
+ } else if (!activated && previousActivated) {
1772
+ unfreezePseudoStates();
1773
+ unfreezeGlobalAnimations();
1774
+ document.body.style.touchAction = "";
1775
+ unlockViewportZoom?.();
1776
+ unlockViewportZoom = null;
1777
+ }
1778
+ }));
1779
+ const savedToolbarState = loadToolbarState();
1780
+ const [isEnabled, setIsEnabled] = createSignal(savedToolbarState?.enabled ?? true);
1781
+ const [toolbarShakeCount, setToolbarShakeCount] = createSignal(0);
1782
+ const [selectionLabelShakeCount, setSelectionLabelShakeCount] = createSignal(0);
1783
+ const [currentToolbarState, setCurrentToolbarState] = createSignal(savedToolbarState);
1784
+ const [isToolbarSelectHovered, setIsToolbarSelectHovered] = createSignal(false);
1785
+ const [commentItems, setCommentItems] = createSignal(loadComments());
1786
+ const [commentsDropdownPosition, setCommentsDropdownPosition] = createSignal(null);
1787
+ const [toolbarMenuPosition, setToolbarMenuPosition] = createSignal(null);
1788
+ const [clearPromptPosition, setClearPromptPosition] = createSignal(null);
1789
+ let toolbarElement;
1790
+ let dropdownTrackingFrameId = null;
1791
+ const commentElementMap = /* @__PURE__ */ new Map();
1792
+ const [clockFlashTrigger, setClockFlashTrigger] = createSignal(0);
1793
+ const [isCommentsHoverOpen, setIsCommentsHoverOpen] = createSignal(false);
1794
+ let commentsHoverPreviews = [];
1795
+ const updateToolbarState = (updates) => {
1796
+ const currentState = currentToolbarState() ?? loadToolbarState();
1797
+ const newState = {
1798
+ edge: currentState?.edge ?? "bottom",
1799
+ ratio: currentState?.ratio ?? .5,
1800
+ collapsed: currentState?.collapsed ?? false,
1801
+ enabled: currentState?.enabled ?? true,
1802
+ defaultAction: currentState?.defaultAction ?? "comment",
1803
+ ...updates
1804
+ };
1805
+ saveToolbarState(newState);
1806
+ setCurrentToolbarState(newState);
1807
+ for (const callback of toolbarStateChangeCallbacks) callback(newState);
1808
+ };
1809
+ const getMappedCommentElements = (commentItemId) => commentElementMap.get(commentItemId) ?? [];
1810
+ const reacquireCommentElements = (commentItem) => {
1811
+ const selectors = commentItem.elementSelectors ?? [];
1812
+ if (selectors.length === 0) return [];
1813
+ const reacquiredElements = [];
1814
+ for (const selector of selectors) {
1815
+ if (!selector) continue;
1816
+ try {
1817
+ const reacquiredElement = document.querySelector(selector);
1818
+ if (isElementConnected(reacquiredElement)) reacquiredElements.push(reacquiredElement);
1819
+ } catch (error) {
1820
+ logRecoverableError("Invalid stored selector", error);
1821
+ }
1822
+ }
1823
+ return reacquiredElements;
1824
+ };
1825
+ const getConnectedCommentElements = (commentItem) => {
1826
+ const mappedElements = getMappedCommentElements(commentItem.id);
1827
+ const connectedMappedElements = mappedElements.filter((mappedElement) => isElementConnected(mappedElement));
1828
+ if (mappedElements.length > 0 && connectedMappedElements.length === mappedElements.length) return connectedMappedElements;
1829
+ const reacquiredElements = reacquireCommentElements(commentItem);
1830
+ if (reacquiredElements.length > 0) {
1831
+ commentElementMap.set(commentItem.id, reacquiredElements);
1832
+ return reacquiredElements;
1833
+ }
1834
+ return connectedMappedElements;
1835
+ };
1836
+ const getFirstConnectedCommentElement = (commentItem) => getConnectedCommentElements(commentItem)[0];
1837
+ const commentsDisconnectedItemIds = createMemo(() => {
1838
+ commentsDropdownPosition();
1839
+ const disconnectedIds = /* @__PURE__ */ new Set();
1840
+ for (const item of commentItems()) if (getConnectedCommentElements(item).length === 0) disconnectedIds.add(item.id);
1841
+ return disconnectedIds;
1842
+ }, void 0, { equals: (prev, next) => {
1843
+ if (prev.size !== next.size) return false;
1844
+ for (const id of next) if (!prev.has(id)) return false;
1845
+ return true;
1846
+ } });
1847
+ const clearHoldTimer = () => {
1848
+ if (activationHoldState.timerId !== null) {
1849
+ clearTimeout(activationHoldState.timerId);
1850
+ activationHoldState.timerId = null;
1851
+ }
1852
+ };
1853
+ const resetCopyConfirmation = () => {
1854
+ activationHoldState.copyWaiting = false;
1855
+ activationHoldState.holdTimerFired = false;
1856
+ activationHoldState.startTimestamp = null;
1857
+ };
1858
+ createEffect(() => {
1859
+ if (store.current.state !== "holding") {
1860
+ clearHoldTimer();
1861
+ return;
1862
+ }
1863
+ activationHoldState.startTimestamp = Date.now();
1864
+ activationHoldState.timerId = window.setTimeout(() => {
1865
+ activationHoldState.timerId = null;
1866
+ if (activationHoldState.copyWaiting) {
1867
+ activationHoldState.holdTimerFired = true;
1868
+ return;
1869
+ }
1870
+ actions.activate();
1871
+ }, store.keyHoldDuration);
1872
+ onCleanup(clearHoldTimer);
1873
+ });
1874
+ createEffect(() => {
1875
+ if (store.current.state !== "active" || store.current.phase !== "justDragged") return;
1876
+ const timerId = setTimeout(() => {
1877
+ actions.finishJustDragged();
1878
+ }, FEEDBACK_DURATION_MS);
1879
+ onCleanup(() => clearTimeout(timerId));
1880
+ });
1881
+ createEffect(() => {
1882
+ if (store.current.state !== "justCopied") return;
1883
+ const timerId = setTimeout(() => {
1884
+ actions.finishJustCopied();
1885
+ }, FEEDBACK_DURATION_MS);
1886
+ onCleanup(() => clearTimeout(timerId));
1887
+ });
1888
+ createEffect(on(isHoldingKeys, (currentlyHolding, previouslyHolding = false) => {
1889
+ if (!previouslyHolding || currentlyHolding || !isActivated()) return;
1890
+ if (pluginRegistry.store.options.activationMode !== "hold") actions.setWasActivatedByToggle(true);
1891
+ pluginRegistry.hooks.onActivate();
1892
+ }));
1893
+ const preparePromptMode = (element, positionX, positionY) => {
1894
+ setCopyStartPosition(element, positionX, positionY);
1895
+ actions.clearInputText();
1896
+ };
1897
+ const activatePromptMode = () => {
1898
+ const element = store.frozenElement || targetElement();
1899
+ if (element) actions.enterPromptMode({
1900
+ x: store.pointer.x,
1901
+ y: store.pointer.y
1902
+ }, element);
1903
+ };
1904
+ const setCopyStartPosition = (element, positionX, positionY) => {
1905
+ actions.setCopyStart({
1906
+ x: positionX,
1907
+ y: positionY
1908
+ }, element);
1909
+ };
1910
+ const elementDetectionState = {
1911
+ lastDetectionTimestamp: 0,
1912
+ pendingDetectionScheduledAt: 0,
1913
+ latestPointerX: 0,
1914
+ latestPointerY: 0
1915
+ };
1916
+ let dragPreviewDebounceTimerId = null;
1917
+ const [debouncedDragPointer, setDebouncedDragPointer] = createSignal(null);
1918
+ const scheduleDragPreviewUpdate = (clientX, clientY) => {
1919
+ if (dragPreviewDebounceTimerId !== null) clearTimeout(dragPreviewDebounceTimerId);
1920
+ setDebouncedDragPointer(null);
1921
+ dragPreviewDebounceTimerId = window.setTimeout(() => {
1922
+ setDebouncedDragPointer({
1923
+ x: clientX,
1924
+ y: clientY
1925
+ });
1926
+ dragPreviewDebounceTimerId = null;
1927
+ }, 32);
1928
+ };
1929
+ let keydownSpamTimerId = null;
1930
+ const activationHoldState = {
1931
+ timerId: null,
1932
+ startTimestamp: null,
1933
+ copyWaiting: false,
1934
+ holdTimerFired: false
1935
+ };
1936
+ const [isInspectMode, setIsInspectMode] = createSignal(false);
1937
+ let lastWindowFocusTimestamp = 0;
1938
+ let isCopyFeedbackCooldownActive = false;
1939
+ let copyFeedbackCooldownTimerId = null;
1940
+ const startCopyFeedbackCooldown = () => {
1941
+ isCopyFeedbackCooldownActive = true;
1942
+ if (copyFeedbackCooldownTimerId !== null) window.clearTimeout(copyFeedbackCooldownTimerId);
1943
+ copyFeedbackCooldownTimerId = window.setTimeout(() => {
1944
+ isCopyFeedbackCooldownActive = false;
1945
+ copyFeedbackCooldownTimerId = null;
1946
+ }, FEEDBACK_DURATION_MS);
1947
+ };
1948
+ const clearCopyFeedbackCooldown = () => {
1949
+ if (copyFeedbackCooldownTimerId !== null) {
1950
+ window.clearTimeout(copyFeedbackCooldownTimerId);
1951
+ copyFeedbackCooldownTimerId = null;
1952
+ }
1953
+ isCopyFeedbackCooldownActive = false;
1954
+ };
1955
+ let actionCycleIdleTimeoutId = null;
1956
+ let selectionSourceRequestVersion = 0;
1957
+ let componentNameRequestVersion = 0;
1958
+ let componentNameDebounceTimerId = null;
1959
+ let keyboardSelectedElement = null;
1960
+ let isPendingContextMenuSelect = false;
1961
+ let pendingDefaultActionId = null;
1962
+ const [debouncedElementForComponentName, setDebouncedElementForComponentName] = createSignal(null);
1963
+ const [resolvedComponentName, setResolvedComponentName] = createSignal(void 0);
1964
+ const [actionCycleItems, setActionCycleItems] = createSignal([]);
1965
+ const [actionCycleActiveIndex, setActionCycleActiveIndex] = createSignal(null);
1966
+ const [arrowNavigationElements, setArrowNavigationElements] = createSignal([]);
1967
+ const [arrowNavigationActiveIndex, setArrowNavigationActiveIndex] = createSignal(0);
1968
+ const arrowNavigator = createArrowNavigator(isValidGrabbableElement, createElementBounds);
1969
+ const autoScroller = createAutoScroller(() => store.pointer, () => isDragging());
1970
+ const isRendererActive = createMemo(() => isActivated() && !isCopying());
1971
+ const grabbedBoxTimeouts = /* @__PURE__ */ new Map();
1972
+ const showTemporaryGrabbedBox = (bounds, element) => {
1973
+ const boxId = generateId("grabbed");
1974
+ const newBox = {
1975
+ id: boxId,
1976
+ bounds,
1977
+ createdAt: Date.now(),
1978
+ element
1979
+ };
1980
+ actions.addGrabbedBox(newBox);
1981
+ pluginRegistry.hooks.onGrabbedBox(bounds, element);
1982
+ const timeoutId = window.setTimeout(() => {
1983
+ grabbedBoxTimeouts.delete(boxId);
1984
+ actions.removeGrabbedBox(boxId);
1985
+ }, FEEDBACK_DURATION_MS);
1986
+ grabbedBoxTimeouts.set(boxId, timeoutId);
1987
+ };
1988
+ const notifyElementsSelected = async (elements) => {
1989
+ const elementsPayload = await Promise.all(elements.map(async (element) => {
1990
+ const source = await resolveSource(element);
1991
+ let componentName = source?.componentName ?? null;
1992
+ const filePath = source?.filePath;
1993
+ const lineNumber = source?.lineNumber ?? void 0;
1994
+ const columnNumber = source?.columnNumber ?? void 0;
1995
+ if (!componentName) componentName = getComponentDisplayName(element);
1996
+ const textContent = element instanceof HTMLElement ? element.innerText?.slice(0, 100) : void 0;
1997
+ return {
1998
+ tagName: getTagName(element),
1999
+ id: element.id || void 0,
2000
+ className: element.getAttribute("class") || void 0,
2001
+ textContent,
2002
+ componentName: componentName ?? void 0,
2003
+ filePath,
2004
+ lineNumber,
2005
+ columnNumber
2006
+ };
2007
+ }));
2008
+ window.dispatchEvent(new CustomEvent("react-grab:element-selected", { detail: { elements: elementsPayload } }));
2009
+ };
2010
+ const labelFadeTimeouts = /* @__PURE__ */ new Map();
2011
+ const cancelLabelFade = (instanceId) => {
2012
+ const existingTimeout = labelFadeTimeouts.get(instanceId);
2013
+ if (existingTimeout !== void 0) {
2014
+ window.clearTimeout(existingTimeout);
2015
+ labelFadeTimeouts.delete(instanceId);
2016
+ }
2017
+ };
2018
+ const cancelAllLabelFades = () => {
2019
+ for (const timeoutId of labelFadeTimeouts.values()) window.clearTimeout(timeoutId);
2020
+ labelFadeTimeouts.clear();
2021
+ };
2022
+ const scheduleLabelFade = (instanceId) => {
2023
+ cancelLabelFade(instanceId);
2024
+ const timeoutId = window.setTimeout(() => {
2025
+ labelFadeTimeouts.delete(instanceId);
2026
+ actions.updateLabelInstance(instanceId, "fading");
2027
+ setTimeout(() => {
2028
+ labelFadeTimeouts.delete(instanceId);
2029
+ actions.removeLabelInstance(instanceId);
2030
+ }, 150);
2031
+ }, FEEDBACK_DURATION_MS);
2032
+ labelFadeTimeouts.set(instanceId, timeoutId);
2033
+ };
2034
+ const handleLabelInstanceHoverChange = (instanceId, isHovered) => {
2035
+ if (isHovered) cancelLabelFade(instanceId);
2036
+ else {
2037
+ const instance = store.labelInstances.find((labelInstance) => labelInstance.id === instanceId);
2038
+ if (instance && instance.status === "copied") scheduleLabelFade(instanceId);
2039
+ }
2040
+ };
2041
+ const createLabelInstance = (bounds, tagName, componentName, status, options) => {
2042
+ actions.clearLabelInstances();
2043
+ cancelAllLabelFades();
2044
+ const instanceId = generateId("label");
2045
+ const boundsCenterX = bounds.x + bounds.width / 2;
2046
+ const boundsHalfWidth = bounds.width / 2;
2047
+ const mouseX = options?.mouseX;
2048
+ const mouseXOffset = mouseX !== void 0 ? mouseX - boundsCenterX : void 0;
2049
+ const instance = {
2050
+ id: instanceId,
2051
+ bounds,
2052
+ boundsMultiple: options?.boundsMultiple,
2053
+ tagName,
2054
+ componentName,
2055
+ status,
2056
+ createdAt: Date.now(),
2057
+ element: options?.element,
2058
+ elements: options?.elements,
2059
+ mouseX,
2060
+ mouseXOffsetFromCenter: mouseXOffset,
2061
+ mouseXOffsetRatio: mouseXOffset !== void 0 && boundsHalfWidth > 0 ? mouseXOffset / boundsHalfWidth : void 0,
2062
+ hideArrow: options?.hideArrow
2063
+ };
2064
+ actions.addLabelInstance(instance);
2065
+ return instanceId;
2066
+ };
2067
+ const clearAllLabels = () => {
2068
+ cancelAllLabelFades();
2069
+ actions.clearLabelInstances();
2070
+ };
2071
+ const updateLabelAfterCopy = (labelInstanceId, didSucceed, errorMessage) => {
2072
+ if (didSucceed) actions.updateLabelInstance(labelInstanceId, "copied");
2073
+ else actions.updateLabelInstance(labelInstanceId, "error", errorMessage || "Unknown error");
2074
+ scheduleLabelFade(labelInstanceId);
2075
+ };
2076
+ const executeCopyOperation = async (clipboardOperation, labelInstanceId, copiedElement, shouldDeactivateAfter) => {
2077
+ clearCopyFeedbackCooldown();
2078
+ if (store.current.state !== "copying") actions.startCopy();
2079
+ let didSucceed = false;
2080
+ let errorMessage;
2081
+ try {
2082
+ await clipboardOperation();
2083
+ didSucceed = true;
2084
+ } catch (error) {
2085
+ errorMessage = normalizeErrorMessage(error, "Action failed");
2086
+ }
2087
+ if (labelInstanceId) updateLabelAfterCopy(labelInstanceId, didSucceed, errorMessage);
2088
+ if (store.current.state !== "copying") return;
2089
+ if (didSucceed) actions.completeCopy(copiedElement);
2090
+ if (shouldDeactivateAfter) deactivateRenderer();
2091
+ else if (didSucceed) {
2092
+ actions.activate();
2093
+ startCopyFeedbackCooldown();
2094
+ } else actions.unfreeze();
2095
+ };
2096
+ const handleCopySuccessWithComments = (options) => {
2097
+ const { copiedElements, content, extraPrompt, elementName, tagName, componentName } = options;
2098
+ pluginRegistry.hooks.onCopySuccess(copiedElements, content);
2099
+ if (!extraPrompt) return;
2100
+ const hasCopiedElements = copiedElements.length > 0;
2101
+ if (hasCopiedElements) {
2102
+ const currentItems = commentItems();
2103
+ for (const [existingItemId, mappedElements] of commentElementMap.entries()) {
2104
+ if (!(mappedElements.length === copiedElements.length && mappedElements.every((mappedElement, index) => mappedElement === copiedElements[index]))) continue;
2105
+ const existingItem = currentItems.find((item) => item.id === existingItemId);
2106
+ if (!existingItem) continue;
2107
+ if (existingItem.commentText === extraPrompt) {
2108
+ removeCommentItem(existingItemId);
2109
+ commentElementMap.delete(existingItemId);
2110
+ break;
2111
+ }
2112
+ }
2113
+ }
2114
+ const elementSelectors = copiedElements.map((copiedElement, index) => createElementSelector(copiedElement, index === 0));
2115
+ const updatedCommentItems = addCommentItem({
2116
+ content,
2117
+ elementName: elementName ?? "element",
2118
+ tagName: tagName ?? "div",
2119
+ componentName: componentName ?? void 0,
2120
+ elementsCount: copiedElements.length,
2121
+ previewBounds: copiedElements.map((copiedElement) => createElementBounds(copiedElement)),
2122
+ elementSelectors,
2123
+ commentText: extraPrompt,
2124
+ timestamp: Date.now()
2125
+ });
2126
+ setCommentItems(updatedCommentItems);
2127
+ setClockFlashTrigger((previous) => previous + 1);
2128
+ const newestCommentItem = updatedCommentItems[0];
2129
+ if (newestCommentItem && hasCopiedElements) commentElementMap.set(newestCommentItem.id, [...copiedElements]);
2130
+ const currentItemIds = new Set(updatedCommentItems.map((item) => item.id));
2131
+ for (const mapItemId of commentElementMap.keys()) if (!currentItemIds.has(mapItemId)) commentElementMap.delete(mapItemId);
2132
+ };
2133
+ const copyWithFallback = (elements, extraPrompt, resolvedComponentName) => {
2134
+ const firstElement = elements[0];
2135
+ const componentName = resolvedComponentName ?? (firstElement ? getComponentDisplayName(firstElement) : null);
2136
+ const tagName = firstElement ? getTagName(firstElement) : null;
2137
+ const elementName = componentName ?? tagName ?? void 0;
2138
+ return tryCopyWithFallback({
2139
+ maxContextLines: pluginRegistry.store.options.maxContextLines,
2140
+ getContent: pluginRegistry.store.options.getContent,
2141
+ componentName: elementName
2142
+ }, {
2143
+ onBeforeCopy: pluginRegistry.hooks.onBeforeCopy,
2144
+ transformSnippet: pluginRegistry.hooks.transformSnippet,
2145
+ transformCopyContent: pluginRegistry.hooks.transformCopyContent,
2146
+ onAfterCopy: pluginRegistry.hooks.onAfterCopy,
2147
+ onCopySuccess: (copiedElements, content) => {
2148
+ handleCopySuccessWithComments({
2149
+ copiedElements,
2150
+ content,
2151
+ extraPrompt,
2152
+ elementName,
2153
+ tagName,
2154
+ componentName
2155
+ });
2156
+ },
2157
+ onCopyError: pluginRegistry.hooks.onCopyError
2158
+ }, elements, extraPrompt);
2159
+ };
2160
+ const copyElementsToClipboard = async (targetElements, extraPrompt, resolvedComponentName) => {
2161
+ if (targetElements.length === 0) return;
2162
+ const unhandledElements = [];
2163
+ const pendingResults = [];
2164
+ for (const element of targetElements) {
2165
+ const { wasIntercepted, pendingResult } = pluginRegistry.hooks.onElementSelect(element);
2166
+ if (!wasIntercepted) unhandledElements.push(element);
2167
+ if (pendingResult) pendingResults.push(pendingResult);
2168
+ if (pluginRegistry.store.theme.grabbedBoxes.enabled) showTemporaryGrabbedBox(createElementBounds(element), element);
2169
+ }
2170
+ await waitUntilNextFrame();
2171
+ if (unhandledElements.length > 0) await copyWithFallback(unhandledElements, extraPrompt, resolvedComponentName);
2172
+ else if (pendingResults.length > 0) {
2173
+ if (!(await Promise.all(pendingResults)).every(Boolean)) throw new Error("Failed to copy");
2174
+ }
2175
+ notifyElementsSelected(targetElements);
2176
+ };
2177
+ const performCopyWithLabel = (options) => {
2178
+ const { element, cursorX, selectedElements, extraPrompt, shouldDeactivateAfter, onComplete, dragRect: passedDragRect } = options;
2179
+ const allTargetElements = selectedElements ?? [element];
2180
+ const dragRect = passedDragRect ?? store.frozenDragRect;
2181
+ const isMultiSelect = allTargetElements.length > 1;
2182
+ const selectionBounds = dragRect && isMultiSelect ? createBoundsFromDragRect(dragRect) : createFlatOverlayBounds(createElementBounds(element));
2183
+ const labelCursorX = isMultiSelect ? selectionBounds.x + selectionBounds.width / 2 : cursorX;
2184
+ const tagName = getTagName(element);
2185
+ clearCopyFeedbackCooldown();
2186
+ actions.startCopy();
2187
+ const labelInstanceId = tagName ? createLabelInstance(selectionBounds, tagName, void 0, "copying", {
2188
+ element,
2189
+ mouseX: labelCursorX,
2190
+ elements: selectedElements
2191
+ }) : null;
2192
+ getNearestComponentName(element).then(async (componentName) => {
2193
+ await executeCopyOperation(() => copyElementsToClipboard(allTargetElements, extraPrompt, componentName ?? void 0), labelInstanceId, element, shouldDeactivateAfter);
2194
+ onComplete?.();
2195
+ }).catch((error) => {
2196
+ logRecoverableError("Copy operation failed", error);
2197
+ if (labelInstanceId) updateLabelAfterCopy(labelInstanceId, false, normalizeErrorMessage(error, "Action failed"));
2198
+ if (store.current.state === "copying") actions.unfreeze();
2199
+ });
2200
+ };
2201
+ const targetElement = createMemo(() => {
2202
+ store.viewportVersion;
2203
+ if (!isRendererActive() || isDragging()) return null;
2204
+ const element = store.detectedElement;
2205
+ if (!isElementConnected(element)) return null;
2206
+ return element;
2207
+ });
2208
+ const effectiveElement = createMemo(() => store.frozenElement || (isFrozenPhase() ? null : targetElement()));
2209
+ createEffect(() => {
2210
+ const element = store.detectedElement;
2211
+ if (!element) return;
2212
+ const intervalId = setInterval(() => {
2213
+ if (!isElementConnected(element)) actions.setDetectedElement(null);
2214
+ }, 100);
2215
+ onCleanup(() => clearInterval(intervalId));
2216
+ });
2217
+ createEffect(on(effectiveElement, (element) => {
2218
+ if (componentNameDebounceTimerId !== null) {
2219
+ clearTimeout(componentNameDebounceTimerId);
2220
+ componentNameDebounceTimerId = null;
2221
+ }
2222
+ if (!element) {
2223
+ setDebouncedElementForComponentName(null);
2224
+ return;
2225
+ }
2226
+ componentNameDebounceTimerId = window.setTimeout(() => {
2227
+ componentNameDebounceTimerId = null;
2228
+ setDebouncedElementForComponentName(element);
2229
+ }, 100);
2230
+ }));
2231
+ onCleanup(() => {
2232
+ if (componentNameDebounceTimerId !== null) {
2233
+ clearTimeout(componentNameDebounceTimerId);
2234
+ componentNameDebounceTimerId = null;
2235
+ }
2236
+ });
2237
+ createEffect(() => {
2238
+ const elements = store.frozenElements;
2239
+ onCleanup(freezeAnimations(elements));
2240
+ });
2241
+ createEffect(on(isActivated, (activated) => {
2242
+ if (!activated) return;
2243
+ if (!pluginRegistry.store.options.freezeReactUpdates) return;
2244
+ onCleanup(freezeUpdates());
2245
+ }));
2246
+ const getSelectionElement = () => {
2247
+ if (store.isTouchMode && isDragging()) {
2248
+ const detected = store.detectedElement;
2249
+ if (!detected || isRootElement(detected)) return void 0;
2250
+ return detected;
2251
+ }
2252
+ const element = effectiveElement();
2253
+ if (!element || isRootElement(element)) return void 0;
2254
+ return element;
2255
+ };
2256
+ const selectionElement = createMemo(() => getSelectionElement());
2257
+ const isSelectionElementVisible = () => {
2258
+ if (!selectionElement()) return false;
2259
+ if (store.isTouchMode && isDragging()) return isRendererActive();
2260
+ return isRendererActive() && !isDragging();
2261
+ };
2262
+ const frozenElementsBounds = createMemo(() => {
2263
+ store.viewportVersion;
2264
+ const frozenElements = store.frozenElements;
2265
+ if (frozenElements.length === 0) return [];
2266
+ const dragRect = store.frozenDragRect;
2267
+ if (dragRect && frozenElements.length > 1) return [createBoundsFromDragRect(dragRect)];
2268
+ return frozenElements.filter((element) => element !== null).map((element) => createElementBounds(element));
2269
+ });
2270
+ const selectionBounds = createMemo(() => {
2271
+ store.viewportVersion;
2272
+ const frozenElements = store.frozenElements;
2273
+ if (frozenElements.length > 0) {
2274
+ const frozenBounds = frozenElementsBounds();
2275
+ if (frozenElements.length === 1) {
2276
+ const firstBounds = frozenBounds[0];
2277
+ if (firstBounds) return firstBounds;
2278
+ }
2279
+ const dragRect = store.frozenDragRect;
2280
+ if (dragRect) return frozenBounds[0] ?? createBoundsFromDragRect(dragRect);
2281
+ return createFlatOverlayBounds(combineBounds(frozenBounds));
2282
+ }
2283
+ const element = selectionElement();
2284
+ if (!element) return void 0;
2285
+ return createElementBounds(element);
2286
+ });
2287
+ const toPageCoordinates = (clientX, clientY) => ({
2288
+ pageX: clientX + window.scrollX,
2289
+ pageY: clientY + window.scrollY
2290
+ });
2291
+ const calculateDragDistance = (endX, endY) => {
2292
+ const { pageX: endPageX, pageY: endPageY } = toPageCoordinates(endX, endY);
2293
+ return {
2294
+ x: Math.abs(endPageX - store.dragStart.x),
2295
+ y: Math.abs(endPageY - store.dragStart.y)
2296
+ };
2297
+ };
2298
+ const isDraggingBeyondThreshold = createMemo(() => {
2299
+ if (!isDragging()) return false;
2300
+ const dragDistance = calculateDragDistance(store.pointer.x, store.pointer.y);
2301
+ return dragDistance.x > 2 || dragDistance.y > 2;
2302
+ });
2303
+ const calculateDragRectangle = (endX, endY) => {
2304
+ const { pageX: endPageX, pageY: endPageY } = toPageCoordinates(endX, endY);
2305
+ const dragPageX = Math.min(store.dragStart.x, endPageX);
2306
+ const dragPageY = Math.min(store.dragStart.y, endPageY);
2307
+ const dragWidth = Math.abs(endPageX - store.dragStart.x);
2308
+ const dragHeight = Math.abs(endPageY - store.dragStart.y);
2309
+ return {
2310
+ x: dragPageX - window.scrollX,
2311
+ y: dragPageY - window.scrollY,
2312
+ width: dragWidth,
2313
+ height: dragHeight
2314
+ };
2315
+ };
2316
+ const dragBounds = createMemo(() => {
2317
+ store.viewportVersion;
2318
+ if (!isDraggingBeyondThreshold()) return void 0;
2319
+ const drag = calculateDragRectangle(store.pointer.x, store.pointer.y);
2320
+ return {
2321
+ borderRadius: "0px",
2322
+ height: drag.height,
2323
+ transform: "none",
2324
+ width: drag.width,
2325
+ x: drag.x,
2326
+ y: drag.y
2327
+ };
2328
+ });
2329
+ const dragPreviewBounds = createMemo(() => {
2330
+ store.viewportVersion;
2331
+ if (!isDraggingBeyondThreshold()) return [];
2332
+ const pointer = debouncedDragPointer();
2333
+ if (!pointer) return [];
2334
+ const drag = calculateDragRectangle(pointer.x, pointer.y);
2335
+ const elements = getElementsInDrag(drag, isValidGrabbableElement);
2336
+ return (elements.length > 0 ? elements : getElementsInDrag(drag, isValidGrabbableElement, false)).map((element) => createElementBounds(element));
2337
+ });
2338
+ const selectionBoundsMultiple = createMemo(() => {
2339
+ const previewBounds = dragPreviewBounds();
2340
+ if (previewBounds.length > 0) return previewBounds;
2341
+ return frozenElementsBounds();
2342
+ });
2343
+ const inspectBounds = createMemo(() => {
2344
+ if (!isInspectMode()) return [];
2345
+ const element = effectiveElement();
2346
+ if (!element) return [];
2347
+ store.viewportVersion;
2348
+ return [...getAncestorElements(element), element].map((ancestor) => createElementBounds(ancestor));
2349
+ });
2350
+ const cursorPosition = createMemo(() => {
2351
+ if (isCopying() || isPromptMode()) {
2352
+ store.viewportVersion;
2353
+ const element = store.frozenElement || targetElement();
2354
+ if (element) {
2355
+ const { center } = getElementBoundsCenter(element);
2356
+ return {
2357
+ x: center.x + store.copyOffsetFromCenterX,
2358
+ y: store.copyStart.y
2359
+ };
2360
+ }
2361
+ return {
2362
+ x: store.copyStart.x,
2363
+ y: store.copyStart.y
2364
+ };
2365
+ }
2366
+ return {
2367
+ x: store.pointer.x,
2368
+ y: store.pointer.y
2369
+ };
2370
+ });
2371
+ createEffect(on(() => [targetElement(), store.lastGrabbedElement], ([currentElement, lastElement]) => {
2372
+ if (lastElement && currentElement && lastElement !== currentElement) actions.setLastGrabbed(null);
2373
+ if (currentElement) pluginRegistry.hooks.onElementHover(currentElement);
2374
+ }));
2375
+ createEffect(on(() => targetElement(), (element) => {
2376
+ const currentVersion = ++selectionSourceRequestVersion;
2377
+ const clearSource = () => {
2378
+ if (selectionSourceRequestVersion === currentVersion) actions.setSelectionSource(null, null);
2379
+ };
2380
+ if (!element) {
2381
+ clearSource();
2382
+ return;
2383
+ }
2384
+ resolveSource(element).then((source) => {
2385
+ if (selectionSourceRequestVersion !== currentVersion) return;
2386
+ if (!source) {
2387
+ clearSource();
2388
+ return;
2389
+ }
2390
+ actions.setSelectionSource(source.filePath, source.lineNumber);
2391
+ }).catch(() => {
2392
+ if (selectionSourceRequestVersion === currentVersion) actions.setSelectionSource(null, null);
2393
+ });
2394
+ }));
2395
+ const publicGrabbedBoxes = createMemo(() => store.grabbedBoxes.map((box) => ({
2396
+ id: box.id,
2397
+ bounds: box.bounds,
2398
+ createdAt: box.createdAt
2399
+ })));
2400
+ const publicLabelInstances = createMemo(() => store.labelInstances.map((instance) => ({
2401
+ id: instance.id,
2402
+ status: instance.status,
2403
+ tagName: instance.tagName,
2404
+ componentName: instance.componentName,
2405
+ createdAt: instance.createdAt
2406
+ })));
2407
+ createEffect(on(createMemo(() => {
2408
+ const active = isActivated();
2409
+ const dragging = isDragging();
2410
+ const copying = isCopying();
2411
+ const inputMode = isPromptMode();
2412
+ const target = targetElement();
2413
+ const drag = dragBounds();
2414
+ const themeEnabled = pluginRegistry.store.theme.enabled;
2415
+ const selectionBoxEnabled = pluginRegistry.store.theme.selectionBox.enabled;
2416
+ const dragBoxEnabled = pluginRegistry.store.theme.dragBox.enabled;
2417
+ const draggingBeyondThreshold = isDraggingBeyondThreshold();
2418
+ const effectiveTarget = effectiveElement();
2419
+ const justCopied = didJustCopy();
2420
+ return {
2421
+ isActive: active,
2422
+ isDragging: dragging,
2423
+ isCopying: copying,
2424
+ isPromptMode: inputMode,
2425
+ isSelectionBoxVisible: Boolean(themeEnabled && selectionBoxEnabled && active && !copying && !justCopied && !dragging && effectiveTarget != null),
2426
+ isDragBoxVisible: Boolean(themeEnabled && dragBoxEnabled && active && !copying && draggingBeyondThreshold),
2427
+ targetElement: target,
2428
+ dragBounds: drag ? {
2429
+ x: drag.x,
2430
+ y: drag.y,
2431
+ width: drag.width,
2432
+ height: drag.height
2433
+ } : null,
2434
+ grabbedBoxes: [...publicGrabbedBoxes()],
2435
+ labelInstances: [...publicLabelInstances()],
2436
+ selectionFilePath: store.selectionFilePath,
2437
+ toolbarState: currentToolbarState()
2438
+ };
2439
+ }), (state) => {
2440
+ pluginRegistry.hooks.onStateChange(state);
2441
+ }));
2442
+ createEffect(on(() => [
2443
+ isPromptMode(),
2444
+ store.pointer.x,
2445
+ store.pointer.y,
2446
+ targetElement()
2447
+ ], ([inputMode, x, y, target]) => {
2448
+ pluginRegistry.hooks.onPromptModeChange(inputMode, {
2449
+ x,
2450
+ y,
2451
+ targetElement: target
2452
+ });
2453
+ }));
2454
+ createEffect(on(() => [
2455
+ selectionVisible(),
2456
+ selectionBounds(),
2457
+ targetElement()
2458
+ ], ([visible, bounds, element]) => {
2459
+ pluginRegistry.hooks.onSelectionBox(Boolean(visible), bounds ?? null, element);
2460
+ }));
2461
+ createEffect(on(() => [dragVisible(), dragBounds()], ([visible, bounds]) => {
2462
+ pluginRegistry.hooks.onDragBox(Boolean(visible), bounds ?? null);
2463
+ }));
2464
+ createEffect(on(() => [
2465
+ labelVisible(),
2466
+ labelVariant(),
2467
+ cursorPosition(),
2468
+ targetElement(),
2469
+ store.selectionFilePath,
2470
+ store.selectionLineNumber
2471
+ ], ([visible, variant, position, element, filePath, lineNumber]) => {
2472
+ pluginRegistry.hooks.onElementLabel(Boolean(visible), variant, {
2473
+ x: position.x,
2474
+ y: position.y,
2475
+ content: "",
2476
+ element: element ?? void 0,
2477
+ tagName: element ? getTagName(element) || void 0 : void 0,
2478
+ filePath: filePath ?? void 0,
2479
+ lineNumber: lineNumber ?? void 0
2480
+ });
2481
+ }));
2482
+ let cursorStyleElement = null;
2483
+ const setCursorOverride = (cursor) => {
2484
+ if (cursor) {
2485
+ if (!cursorStyleElement) {
2486
+ cursorStyleElement = document.createElement("style");
2487
+ cursorStyleElement.setAttribute("data-react-grab-cursor", "");
2488
+ document.head.appendChild(cursorStyleElement);
2489
+ }
2490
+ cursorStyleElement.textContent = `* { cursor: ${cursor} !important; }`;
2491
+ } else if (cursorStyleElement) {
2492
+ cursorStyleElement.remove();
2493
+ cursorStyleElement = null;
2494
+ }
2495
+ };
2496
+ createEffect(on(() => [
2497
+ isActivated(),
2498
+ isCopying(),
2499
+ isPromptMode()
2500
+ ], ([activated, copying, promptMode]) => {
2501
+ if (copying) setCursorOverride("progress");
2502
+ else if (activated && !promptMode) setCursorOverride("crosshair");
2503
+ else setCursorOverride(null);
2504
+ }));
2505
+ const activateRenderer = () => {
2506
+ const wasInHoldingState = isHoldingKeys();
2507
+ actions.activate();
2508
+ if (!wasInHoldingState) pluginRegistry.hooks.onActivate();
2509
+ };
2510
+ const deactivateRenderer = () => {
2511
+ const wasDragging = isDragging();
2512
+ const previousFocused = store.previouslyFocusedElement;
2513
+ actions.deactivate();
2514
+ setIsInspectMode(false);
2515
+ clearArrowNavigation();
2516
+ keyboardSelectedElement = null;
2517
+ isPendingContextMenuSelect = false;
2518
+ if (wasDragging) document.body.style.userSelect = "";
2519
+ if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
2520
+ autoScroller.stop();
2521
+ if (previousFocused instanceof HTMLElement && isElementConnected(previousFocused)) previousFocused.focus();
2522
+ pluginRegistry.hooks.onDeactivate();
2523
+ };
2524
+ const forceDeactivateAll = () => {
2525
+ if (isHoldingKeys()) actions.releaseHold();
2526
+ if (isActivated()) deactivateRenderer();
2527
+ clearCopyFeedbackCooldown();
2528
+ };
2529
+ const toggleActivate = () => {
2530
+ actions.setWasActivatedByToggle(true);
2531
+ activateRenderer();
2532
+ };
2533
+ const handleInputSubmit = () => {
2534
+ actions.clearLastCopied();
2535
+ const frozenElements = [...store.frozenElements];
2536
+ const element = store.frozenElement || targetElement();
2537
+ const prompt = isPromptMode() ? store.inputText.trim() : "";
2538
+ if (!element) {
2539
+ deactivateRenderer();
2540
+ return;
2541
+ }
2542
+ const elements = frozenElements.length > 0 ? frozenElements : [element];
2543
+ const firstBounds = elements.map((selectedElement) => createElementBounds(selectedElement))[0];
2544
+ const { x: currentX, y: currentY } = getBoundsCenter(firstBounds);
2545
+ const labelPositionX = currentX + store.copyOffsetFromCenterX;
2546
+ actions.setPointer({
2547
+ x: currentX,
2548
+ y: currentY
2549
+ });
2550
+ actions.exitPromptMode();
2551
+ actions.clearInputText();
2552
+ performCopyWithLabel({
2553
+ element,
2554
+ cursorX: labelPositionX,
2555
+ selectedElements: elements,
2556
+ extraPrompt: prompt || void 0,
2557
+ shouldDeactivateAfter: true
2558
+ });
2559
+ };
2560
+ const handleInputCancel = () => {
2561
+ actions.clearLastCopied();
2562
+ if (!isPromptMode()) return;
2563
+ if (isPendingDismiss()) {
2564
+ actions.clearInputText();
2565
+ deactivateRenderer();
2566
+ return;
2567
+ }
2568
+ actions.setPendingDismiss(true);
2569
+ setSelectionLabelShakeCount((count) => count + 1);
2570
+ };
2571
+ const handleConfirmDismiss = () => {
2572
+ actions.clearInputText();
2573
+ deactivateRenderer();
2574
+ };
2575
+ const handleCancelDismiss = () => {
2576
+ actions.setPendingDismiss(false);
2577
+ };
2578
+ const handleToggleExpand = () => {
2579
+ const element = store.frozenElement || targetElement();
2580
+ if (element) preparePromptMode(element, store.pointer.x, store.pointer.y);
2581
+ activatePromptMode();
2582
+ };
2583
+ const handleToggleActive = () => {
2584
+ if (isActivated()) deactivateRenderer();
2585
+ else if (isEnabled()) {
2586
+ const defaultActionId = currentToolbarState()?.defaultAction ?? "comment";
2587
+ if (defaultActionId === "comment") actions.setPendingCommentMode(true);
2588
+ else {
2589
+ pendingDefaultActionId = defaultActionId;
2590
+ isPendingContextMenuSelect = true;
2591
+ }
2592
+ toggleActivate();
2593
+ }
2594
+ };
2595
+ const enterCommentModeForElement = (element, positionX, positionY) => {
2596
+ actions.setPendingCommentMode(false);
2597
+ actions.clearInputText();
2598
+ actions.enterPromptMode({
2599
+ x: positionX,
2600
+ y: positionY
2601
+ }, element);
2602
+ };
2603
+ const openContextMenu = (element, position) => {
2604
+ actions.showContextMenu(position, element);
2605
+ clearArrowNavigation();
2606
+ dismissAllPopups();
2607
+ pluginRegistry.hooks.onContextMenu(element, position);
2608
+ };
2609
+ const runPendingDefaultAction = (element, position) => {
2610
+ const actionId = pendingDefaultActionId;
2611
+ pendingDefaultActionId = null;
2612
+ if (!actionId) return;
2613
+ const action = pluginRegistry.store.actions.find((registeredAction) => registeredAction.id === actionId);
2614
+ if (!action) {
2615
+ handleSetDefaultAction(DEFAULT_ACTION_ID);
2616
+ openContextMenu(element, position);
2617
+ return;
2618
+ }
2619
+ const elementBounds = createElementBounds(element);
2620
+ const context = buildActionContext({
2621
+ element,
2622
+ filePath: store.selectionFilePath ?? void 0,
2623
+ lineNumber: store.selectionLineNumber ?? void 0,
2624
+ tagName: getTagName(element) || void 0,
2625
+ componentName: resolvedComponentName(),
2626
+ position,
2627
+ shouldDeferHideContextMenu: false,
2628
+ performWithFeedbackOptions: {
2629
+ fallbackBounds: elementBounds,
2630
+ fallbackSelectionBounds: [elementBounds],
2631
+ position
2632
+ }
2633
+ });
2634
+ action.onAction(context);
2635
+ };
2636
+ const handleComment = () => {
2637
+ if (!isEnabled()) return;
2638
+ if (isActivated() && isCommentMode()) {
2639
+ deactivateRenderer();
2640
+ return;
2641
+ }
2642
+ actions.setPendingCommentMode(true);
2643
+ if (!isActivated()) toggleActivate();
2644
+ };
2645
+ const handleToggleEnabled = () => {
2646
+ const newEnabled = !isEnabled();
2647
+ setIsEnabled(newEnabled);
2648
+ updateToolbarState({ enabled: newEnabled });
2649
+ if (!newEnabled) {
2650
+ forceDeactivateAll();
2651
+ dismissAllPopups();
2652
+ }
2653
+ };
2654
+ const handlePointerMove = (clientX, clientY) => {
2655
+ if (!isEnabled() || isPromptMode() || isFrozenPhase() || store.contextMenuPosition !== null) return;
2656
+ actions.setPointer({
2657
+ x: clientX,
2658
+ y: clientY
2659
+ });
2660
+ elementDetectionState.latestPointerX = clientX;
2661
+ elementDetectionState.latestPointerY = clientY;
2662
+ const now = performance.now();
2663
+ const isDetectionPending = elementDetectionState.pendingDetectionScheduledAt > 0 && now - elementDetectionState.pendingDetectionScheduledAt < 200;
2664
+ if (now - elementDetectionState.lastDetectionTimestamp >= 32 && !isDetectionPending) {
2665
+ elementDetectionState.lastDetectionTimestamp = now;
2666
+ elementDetectionState.pendingDetectionScheduledAt = now;
2667
+ onIdle(() => {
2668
+ const candidate = getElementAtPosition(elementDetectionState.latestPointerX, elementDetectionState.latestPointerY);
2669
+ if (candidate !== store.detectedElement) actions.setDetectedElement(candidate);
2670
+ elementDetectionState.pendingDetectionScheduledAt = 0;
2671
+ });
2672
+ }
2673
+ if (isDragging()) {
2674
+ scheduleDragPreviewUpdate(clientX, clientY);
2675
+ const direction = getAutoScrollDirection(clientX, clientY);
2676
+ const isNearEdge = direction.top || direction.bottom || direction.left || direction.right;
2677
+ if (isNearEdge && !autoScroller.isActive()) autoScroller.start();
2678
+ else if (!isNearEdge && autoScroller.isActive()) autoScroller.stop();
2679
+ }
2680
+ };
2681
+ const handlePointerDown = (clientX, clientY) => {
2682
+ if (!isRendererActive() || isCopying()) return false;
2683
+ actions.startDrag({
2684
+ x: clientX,
2685
+ y: clientY
2686
+ });
2687
+ actions.setPointer({
2688
+ x: clientX,
2689
+ y: clientY
2690
+ });
2691
+ document.body.style.userSelect = "none";
2692
+ scheduleDragPreviewUpdate(clientX, clientY);
2693
+ pluginRegistry.hooks.onDragStart(clientX + window.scrollX, clientY + window.scrollY);
2694
+ return true;
2695
+ };
2696
+ const handleDragSelection = (dragSelectionRect, hasModifierKeyHeld) => {
2697
+ const elements = getElementsInDrag(dragSelectionRect, isValidGrabbableElement);
2698
+ const selectedElements = elements.length > 0 ? elements : getElementsInDrag(dragSelectionRect, isValidGrabbableElement, false);
2699
+ if (selectedElements.length === 0) return;
2700
+ freezeAllAnimations(selectedElements);
2701
+ pluginRegistry.hooks.onDragEnd(selectedElements, dragSelectionRect);
2702
+ const firstElement = selectedElements[0];
2703
+ const center = getElementCenter(firstElement);
2704
+ actions.setPointer(center);
2705
+ actions.setFrozenElements(selectedElements);
2706
+ const dragRect = createPageRectFromBounds(dragSelectionRect);
2707
+ actions.setFrozenDragRect(dragRect);
2708
+ actions.freeze();
2709
+ actions.setLastGrabbed(firstElement);
2710
+ if (store.pendingCommentMode) {
2711
+ enterCommentModeForElement(firstElement, center.x, center.y);
2712
+ return;
2713
+ }
2714
+ if (isPendingContextMenuSelect) {
2715
+ isPendingContextMenuSelect = false;
2716
+ if (pendingDefaultActionId) runPendingDefaultAction(firstElement, center);
2717
+ else openContextMenu(firstElement, center);
2718
+ return;
2719
+ }
2720
+ const shouldDeactivateAfter = store.wasActivatedByToggle && !hasModifierKeyHeld;
2721
+ performCopyWithLabel({
2722
+ element: firstElement,
2723
+ cursorX: center.x,
2724
+ selectedElements,
2725
+ shouldDeactivateAfter,
2726
+ dragRect
2727
+ });
2728
+ };
2729
+ const handleSingleClick = (clientX, clientY, hasModifierKeyHeld) => {
2730
+ const validFrozenElement = isElementConnected(store.frozenElement) ? store.frozenElement : null;
2731
+ const validKeyboardSelectedElement = isElementConnected(keyboardSelectedElement) ? keyboardSelectedElement : null;
2732
+ const element = validFrozenElement ?? validKeyboardSelectedElement ?? getElementAtPosition(clientX, clientY) ?? (isElementConnected(store.detectedElement) ? store.detectedElement : null);
2733
+ if (!element) return;
2734
+ const didSelectViaKeyboard = !validFrozenElement && validKeyboardSelectedElement === element;
2735
+ let positionX;
2736
+ let positionY;
2737
+ if (validFrozenElement) {
2738
+ positionX = store.pointer.x;
2739
+ positionY = store.pointer.y;
2740
+ } else if (didSelectViaKeyboard) {
2741
+ const elementCenter = getElementCenter(element);
2742
+ positionX = elementCenter.x;
2743
+ positionY = elementCenter.y;
2744
+ } else {
2745
+ positionX = clientX;
2746
+ positionY = clientY;
2747
+ }
2748
+ keyboardSelectedElement = null;
2749
+ if (store.pendingCommentMode) {
2750
+ enterCommentModeForElement(element, positionX, positionY);
2751
+ return;
2752
+ }
2753
+ if (isPendingContextMenuSelect) {
2754
+ isPendingContextMenuSelect = false;
2755
+ const { wasIntercepted } = pluginRegistry.hooks.onElementSelect(element);
2756
+ if (wasIntercepted) return;
2757
+ freezeAllAnimations([element]);
2758
+ actions.setFrozenElement(element);
2759
+ const position = {
2760
+ x: positionX,
2761
+ y: positionY
2762
+ };
2763
+ actions.setPointer(position);
2764
+ actions.freeze();
2765
+ if (pendingDefaultActionId) runPendingDefaultAction(element, position);
2766
+ else openContextMenu(element, position);
2767
+ return;
2768
+ }
2769
+ const shouldDeactivateAfter = store.wasActivatedByToggle && !hasModifierKeyHeld;
2770
+ actions.setLastGrabbed(element);
2771
+ performCopyWithLabel({
2772
+ element,
2773
+ cursorX: positionX,
2774
+ shouldDeactivateAfter
2775
+ });
2776
+ };
2777
+ const cancelActiveDrag = () => {
2778
+ if (!isDragging()) return;
2779
+ actions.cancelDrag();
2780
+ autoScroller.stop();
2781
+ document.body.style.userSelect = "";
2782
+ };
2783
+ const handlePointerUp = (clientX, clientY, hasModifierKeyHeld) => {
2784
+ if (!isDragging()) return;
2785
+ if (dragPreviewDebounceTimerId !== null) {
2786
+ clearTimeout(dragPreviewDebounceTimerId);
2787
+ dragPreviewDebounceTimerId = null;
2788
+ }
2789
+ setDebouncedDragPointer(null);
2790
+ const dragDistance = calculateDragDistance(clientX, clientY);
2791
+ const wasDragGesture = dragDistance.x > 2 || dragDistance.y > 2;
2792
+ const dragSelectionRect = wasDragGesture ? calculateDragRectangle(clientX, clientY) : null;
2793
+ if (wasDragGesture) actions.endDrag();
2794
+ else actions.cancelDrag();
2795
+ autoScroller.stop();
2796
+ document.body.style.userSelect = "";
2797
+ if (dragSelectionRect) handleDragSelection(dragSelectionRect, hasModifierKeyHeld);
2798
+ else handleSingleClick(clientX, clientY, hasModifierKeyHeld);
2799
+ };
2800
+ const eventListenerManager = createEventListenerManager();
2801
+ const keyboardClaimer = setupKeyboardEventClaimer();
2802
+ const blockEnterIfNeeded = (event) => {
2803
+ let originalKey;
2804
+ try {
2805
+ originalKey = keyboardClaimer.originalKeyDescriptor?.get ? keyboardClaimer.originalKeyDescriptor.get.call(event) : event.key;
2806
+ } catch {
2807
+ return false;
2808
+ }
2809
+ const isEnterKey = originalKey === "Enter" || isEnterCode(event.code);
2810
+ const isOverlayActive = isActivated() || isHoldingKeys();
2811
+ if (isEnterKey && isOverlayActive && !isPromptMode() && !store.wasActivatedByToggle && clearPromptPosition() === null) {
2812
+ keyboardClaimer.claimedEvents.add(event);
2813
+ event.preventDefault();
2814
+ event.stopImmediatePropagation();
2815
+ return true;
2816
+ }
2817
+ return false;
2818
+ };
2819
+ eventListenerManager.addDocumentListener("keydown", blockEnterIfNeeded, { capture: true });
2820
+ eventListenerManager.addDocumentListener("keyup", blockEnterIfNeeded, { capture: true });
2821
+ eventListenerManager.addDocumentListener("keypress", blockEnterIfNeeded, { capture: true });
2822
+ const clearArrowNavigation = () => {
2823
+ setArrowNavigationElements([]);
2824
+ setArrowNavigationActiveIndex(0);
2825
+ arrowNavigator.clearHistory();
2826
+ };
2827
+ const selectAndFocusElement = (element) => {
2828
+ actions.setFrozenElement(element);
2829
+ actions.freeze();
2830
+ keyboardSelectedElement = element;
2831
+ const { center } = getElementBoundsCenter(element);
2832
+ actions.setPointer(center);
2833
+ if (store.contextMenuPosition !== null) actions.showContextMenu(center, element);
2834
+ };
2835
+ const openArrowNavigationMenu = (anchorElement) => {
2836
+ const probePoint = getVisibleBoundsCenter(createElementBounds(anchorElement));
2837
+ const elementsAtPoint = getElementsAtPoint(probePoint.x, probePoint.y).filter(isValidGrabbableElement).reverse();
2838
+ setArrowNavigationElements(elementsAtPoint);
2839
+ setArrowNavigationActiveIndex(Math.max(0, elementsAtPoint.indexOf(anchorElement)));
2840
+ };
2841
+ const handleArrowNavigationSelect = (index) => {
2842
+ const targetElement = arrowNavigationElements()[index];
2843
+ if (!targetElement) return;
2844
+ setArrowNavigationActiveIndex(index);
2845
+ arrowNavigator.clearHistory();
2846
+ selectAndFocusElement(targetElement);
2847
+ };
2848
+ const handleArrowNavigation = (event) => {
2849
+ if (!isActivated() || isPromptMode()) return false;
2850
+ if (!ARROW_KEYS.has(event.key)) return false;
2851
+ let currentElement = effectiveElement();
2852
+ const isInitialSelection = !currentElement;
2853
+ if (!currentElement) currentElement = getElementAtPosition(window.innerWidth / 2, window.innerHeight / 2);
2854
+ if (!currentElement) return false;
2855
+ if (!(event.key === "ArrowUp" || event.key === "ArrowDown")) {
2856
+ clearArrowNavigation();
2857
+ const nextElement = arrowNavigator.findNext(event.key, currentElement);
2858
+ if (!nextElement && !isInitialSelection) return false;
2859
+ event.preventDefault();
2860
+ event.stopPropagation();
2861
+ selectAndFocusElement(nextElement ?? currentElement);
2862
+ return true;
2863
+ }
2864
+ if (arrowNavigationElements().length === 0) openArrowNavigationMenu(currentElement);
2865
+ const elementToSelect = arrowNavigator.findNext(event.key, currentElement) ?? currentElement;
2866
+ event.preventDefault();
2867
+ event.stopPropagation();
2868
+ selectAndFocusElement(elementToSelect);
2869
+ const newIndex = arrowNavigationElements().indexOf(elementToSelect);
2870
+ if (newIndex !== -1) setArrowNavigationActiveIndex(newIndex);
2871
+ else openArrowNavigationMenu(elementToSelect);
2872
+ return true;
2873
+ };
2874
+ const handleEnterKeyActivation = (event) => {
2875
+ if (!isEnterCode(event.code)) return false;
2876
+ if (isKeyboardEventTriggeredByInput(event)) return false;
2877
+ const copiedElement = store.lastCopiedElement;
2878
+ if (!isHoldingKeys() && !isPromptMode() && !isActivated() && copiedElement && isElementConnected(copiedElement) && !store.labelInstances.some((instance) => instance.status === "copied" || instance.status === "fading")) {
2879
+ event.preventDefault();
2880
+ event.stopImmediatePropagation();
2881
+ const center = getElementCenter(copiedElement);
2882
+ actions.setPointer(center);
2883
+ preparePromptMode(copiedElement, center.x, center.y);
2884
+ actions.setFrozenElement(copiedElement);
2885
+ actions.clearLastCopied();
2886
+ activatePromptMode();
2887
+ if (!isActivated()) activateRenderer();
2888
+ return true;
2889
+ }
2890
+ if (isHoldingKeys() && !isPromptMode()) {
2891
+ event.preventDefault();
2892
+ event.stopImmediatePropagation();
2893
+ const element = store.frozenElement || targetElement();
2894
+ if (element) preparePromptMode(element, store.pointer.x, store.pointer.y);
2895
+ actions.setPointer({
2896
+ x: store.pointer.x,
2897
+ y: store.pointer.y
2898
+ });
2899
+ if (element) actions.setFrozenElement(element);
2900
+ activatePromptMode();
2901
+ if (keydownSpamTimerId !== null) {
2902
+ window.clearTimeout(keydownSpamTimerId);
2903
+ keydownSpamTimerId = null;
2904
+ }
2905
+ if (!isActivated()) activateRenderer();
2906
+ return true;
2907
+ }
2908
+ return false;
2909
+ };
2910
+ const handleOpenFileShortcut = (event) => {
2911
+ if (event.key?.toLowerCase() !== "o" || isPromptMode()) return false;
2912
+ if (!isActivated() || !(event.metaKey || event.ctrlKey)) return false;
2913
+ const filePath = store.selectionFilePath;
2914
+ const lineNumber = store.selectionLineNumber;
2915
+ if (!filePath) return false;
2916
+ event.preventDefault();
2917
+ event.stopPropagation();
2918
+ if (!pluginRegistry.hooks.onOpenFile(filePath, lineNumber ?? void 0)) openFile(filePath, lineNumber ?? void 0, pluginRegistry.hooks.transformOpenFileUrl);
2919
+ return true;
2920
+ };
2921
+ const clearActionCycleIdleTimeout = () => {
2922
+ if (actionCycleIdleTimeoutId !== null) {
2923
+ window.clearTimeout(actionCycleIdleTimeoutId);
2924
+ actionCycleIdleTimeoutId = null;
2925
+ }
2926
+ };
2927
+ const resetActionCycle = () => {
2928
+ clearActionCycleIdleTimeout();
2929
+ setActionCycleItems([]);
2930
+ setActionCycleActiveIndex(null);
2931
+ };
2932
+ const canCycleActions = createMemo(() => {
2933
+ const element = selectionElement();
2934
+ return Boolean(element) && isRendererActive() && !isPromptMode() && !isDragging() && store.contextMenuPosition === null;
2935
+ });
2936
+ const activationBaseKey = createMemo(() => {
2937
+ const { key } = getModifiersFromActivationKey(pluginRegistry.store.options.activationKey);
2938
+ return (key ?? "c").toUpperCase();
2939
+ });
2940
+ const actionCycleState = createMemo(() => ({
2941
+ items: actionCycleItems(),
2942
+ activeIndex: actionCycleActiveIndex(),
2943
+ isVisible: actionCycleActiveIndex() !== null && actionCycleItems().length > 0 && !isCommentMode()
2944
+ }));
2945
+ const arrowNavigationItems = createMemo(() => arrowNavigationElements().map((element) => ({
2946
+ tagName: getTagName(element) || "element",
2947
+ componentName: getComponentDisplayName(element) ?? void 0
2948
+ })));
2949
+ const arrowNavigationState = createMemo(() => ({
2950
+ items: arrowNavigationItems(),
2951
+ activeIndex: arrowNavigationActiveIndex(),
2952
+ isVisible: arrowNavigationElements().length > 0
2953
+ }));
2954
+ const inspectAncestorElements = createMemo(() => {
2955
+ if (!isInspectMode()) return [];
2956
+ const element = effectiveElement();
2957
+ if (!element) return [];
2958
+ return [...getAncestorElements(element).reverse(), element];
2959
+ });
2960
+ const inspectNavigationItems = createMemo(() => inspectAncestorElements().map((element) => ({
2961
+ tagName: getTagName(element) || "element",
2962
+ componentName: getComponentDisplayName(element) ?? void 0
2963
+ })));
2964
+ const [inspectActiveIndex, setInspectActiveIndex] = createSignal(-1);
2965
+ createEffect(on(inspectAncestorElements, (elements) => {
2966
+ setInspectActiveIndex(elements.length - 1);
2967
+ }));
2968
+ const inspectNavigationState = createMemo(() => {
2969
+ const elements = inspectAncestorElements();
2970
+ return {
2971
+ items: inspectNavigationItems(),
2972
+ activeIndex: inspectActiveIndex(),
2973
+ isVisible: isInspectMode() && elements.length > 0
2974
+ };
2975
+ });
2976
+ const handleInspectSelect = (index) => {
2977
+ setInspectActiveIndex(index);
2978
+ };
2979
+ createEffect(on(selectionElement, () => {
2980
+ resetActionCycle();
2981
+ }));
2982
+ createEffect(on(canCycleActions, (isEnabled) => {
2983
+ if (!isEnabled) resetActionCycle();
2984
+ }));
2985
+ const getActionById = (actionId) => pluginRegistry.store.actions.find((action) => action.id === actionId);
2986
+ const getActionCycleContext = () => {
2987
+ const element = selectionElement();
2988
+ if (!element) return void 0;
2989
+ const fallbackBounds = selectionBounds();
2990
+ return buildActionContext({
2991
+ element,
2992
+ filePath: store.selectionFilePath ?? void 0,
2993
+ lineNumber: store.selectionLineNumber ?? void 0,
2994
+ tagName: getTagName(element) || void 0,
2995
+ componentName: resolvedComponentName(),
2996
+ position: store.pointer,
2997
+ performWithFeedbackOptions: {
2998
+ fallbackBounds,
2999
+ fallbackSelectionBounds: fallbackBounds ? [fallbackBounds] : []
3000
+ },
3001
+ shouldDeferHideContextMenu: false,
3002
+ onBeforePrompt: resetActionCycle
3003
+ });
3004
+ };
3005
+ const availableActionCycleItems = createMemo(() => {
3006
+ if (!selectionElement()) return [];
3007
+ const cycleItems = [];
3008
+ for (const action of pluginRegistry.store.actions) {
3009
+ if (typeof action.enabled === "boolean" && !action.enabled) continue;
3010
+ if (action.shortcut && action.shortcut.toUpperCase() !== activationBaseKey()) continue;
3011
+ cycleItems.push({
3012
+ id: action.id,
3013
+ label: action.label,
3014
+ shortcut: action.shortcut
3015
+ });
3016
+ }
3017
+ return cycleItems;
3018
+ });
3019
+ const scheduleActionCycleActivation = () => {
3020
+ clearActionCycleIdleTimeout();
3021
+ actionCycleIdleTimeoutId = window.setTimeout(() => {
3022
+ actionCycleIdleTimeoutId = null;
3023
+ const activeIndex = actionCycleActiveIndex();
3024
+ const items = actionCycleItems();
3025
+ if (activeIndex === null || items.length === 0) return;
3026
+ const selectedItem = items[activeIndex];
3027
+ if (!selectedItem) return;
3028
+ const action = getActionById(selectedItem.id);
3029
+ if (!action) {
3030
+ resetActionCycle();
3031
+ return;
3032
+ }
3033
+ const context = getActionCycleContext();
3034
+ if (!context || !resolveActionEnabled(action, context)) {
3035
+ resetActionCycle();
3036
+ return;
3037
+ }
3038
+ resetActionCycle();
3039
+ if (action.onAction(context) instanceof Promise) {}
3040
+ }, 600);
3041
+ };
3042
+ const advanceActionCycle = () => {
3043
+ if (!canCycleActions()) return false;
3044
+ const cycleItems = availableActionCycleItems();
3045
+ if (cycleItems.length === 0) return false;
3046
+ setActionCycleItems(cycleItems);
3047
+ const currentIndex = actionCycleActiveIndex();
3048
+ setActionCycleActiveIndex(currentIndex !== null && currentIndex < cycleItems.length ? (currentIndex + 1) % cycleItems.length : 0);
3049
+ scheduleActionCycleActivation();
3050
+ return true;
3051
+ };
3052
+ const handleActionCycleKey = (event) => {
3053
+ if (!keyMatchesCode(activationBaseKey(), event.code)) return false;
3054
+ if (event.altKey || event.repeat) return false;
3055
+ if (isKeyboardEventTriggeredByInput(event)) return false;
3056
+ if (!advanceActionCycle()) return false;
3057
+ event.preventDefault();
3058
+ event.stopPropagation();
3059
+ if (event.metaKey || event.ctrlKey) event.stopImmediatePropagation();
3060
+ return true;
3061
+ };
3062
+ const handleActivationKeys = (event) => {
3063
+ if (!pluginRegistry.store.options.allowActivationInsideInput && isKeyboardEventTriggeredByInput(event)) return;
3064
+ if (!isTargetKeyCombination(event, pluginRegistry.store.options)) {
3065
+ if ((event.metaKey || event.ctrlKey) && !MODIFIER_KEYS.includes(event.key) && !isEnterCode(event.code)) {
3066
+ if (isActivated() && !store.wasActivatedByToggle) deactivateRenderer();
3067
+ else if (isHoldingKeys()) {
3068
+ clearHoldTimer();
3069
+ resetCopyConfirmation();
3070
+ actions.releaseHold();
3071
+ }
3072
+ }
3073
+ if (!isEnterCode(event.code) || !isHoldingKeys()) return;
3074
+ }
3075
+ if ((isActivated() || isHoldingKeys()) && !isPromptMode()) {
3076
+ event.preventDefault();
3077
+ if (isEnterCode(event.code)) event.stopImmediatePropagation();
3078
+ }
3079
+ if (isActivated()) {
3080
+ if (store.wasActivatedByToggle && pluginRegistry.store.options.activationMode !== "hold") return;
3081
+ if (event.repeat) return;
3082
+ if (keydownSpamTimerId !== null) window.clearTimeout(keydownSpamTimerId);
3083
+ keydownSpamTimerId = window.setTimeout(() => {
3084
+ deactivateRenderer();
3085
+ }, 200);
3086
+ return;
3087
+ }
3088
+ if (isHoldingKeys() && event.repeat) {
3089
+ if (activationHoldState.copyWaiting) {
3090
+ const shouldActivate = activationHoldState.holdTimerFired;
3091
+ resetCopyConfirmation();
3092
+ if (shouldActivate) actions.activate();
3093
+ }
3094
+ return;
3095
+ }
3096
+ if (isCopying() || didJustCopy()) return;
3097
+ if (!isHoldingKeys()) {
3098
+ let activationDuration = pluginRegistry.store.options.keyHoldDuration ?? 100;
3099
+ if (isKeyboardEventTriggeredByInput(event)) if (hasTextSelectionInInput(event)) activationDuration += 600;
3100
+ else activationDuration += 400;
3101
+ else if (hasTextSelectionOnPage()) activationDuration += 600;
3102
+ resetCopyConfirmation();
3103
+ actions.startHold(activationDuration);
3104
+ }
3105
+ };
3106
+ eventListenerManager.addWindowListener("keydown", (event) => {
3107
+ blockEnterIfNeeded(event);
3108
+ if (event.key === "Shift" && !event.repeat && isActivated()) {
3109
+ setIsInspectMode(true);
3110
+ if (isFrozenPhase()) {
3111
+ actions.unfreeze();
3112
+ clearArrowNavigation();
3113
+ }
3114
+ }
3115
+ if (!isEnabled()) {
3116
+ if (isTargetKeyCombination(event, pluginRegistry.store.options) && !event.repeat) setToolbarShakeCount((count) => count + 1);
3117
+ return;
3118
+ }
3119
+ const isEnterToActivateInput = isEnterCode(event.code) && isHoldingKeys() && !isPromptMode();
3120
+ const isFromReactGrabInput = isEventFromOverlay(event, "data-react-grab-input");
3121
+ if (isPromptMode() && isTargetKeyCombination(event, pluginRegistry.store.options) && !event.repeat && !isFromReactGrabInput) {
3122
+ event.preventDefault();
3123
+ event.stopPropagation();
3124
+ handleInputCancel();
3125
+ return;
3126
+ }
3127
+ if (event.key === "Escape" && clearPromptPosition() !== null) return;
3128
+ if (event.key === "Escape" && commentsDropdownPosition() !== null) {
3129
+ dismissCommentsDropdown();
3130
+ return;
3131
+ }
3132
+ if (event.key === "Escape" && toolbarMenuPosition() !== null) {
3133
+ dismissToolbarMenu();
3134
+ return;
3135
+ }
3136
+ const isFromOverlay = isEventFromOverlay(event, "data-react-grab-ignore-events") && !isEnterToActivateInput;
3137
+ if (isPromptMode() || isFromOverlay) {
3138
+ if (event.key === "Escape") {
3139
+ if (isPromptMode()) handleInputCancel();
3140
+ else if (store.wasActivatedByToggle) deactivateRenderer();
3141
+ }
3142
+ if (isFromOverlay && ARROW_KEYS.has(event.key)) {
3143
+ if (handleArrowNavigation(event)) return;
3144
+ }
3145
+ return;
3146
+ }
3147
+ if (event.key === "Escape") {
3148
+ if (isHoldingKeys() || store.wasActivatedByToggle) {
3149
+ deactivateRenderer();
3150
+ return;
3151
+ }
3152
+ }
3153
+ const didWindowJustRegainFocus = Date.now() - lastWindowFocusTimestamp < 200;
3154
+ if (!didWindowJustRegainFocus && handleActionCycleKey(event)) return;
3155
+ if (handleArrowNavigation(event)) return;
3156
+ if (handleEnterKeyActivation(event)) return;
3157
+ if (handleOpenFileShortcut(event)) return;
3158
+ if (!didWindowJustRegainFocus) handleActivationKeys(event);
3159
+ }, { capture: true });
3160
+ eventListenerManager.addWindowListener("keyup", (event) => {
3161
+ if (blockEnterIfNeeded(event)) return;
3162
+ if (event.key === "Shift") setIsInspectMode(false);
3163
+ const requiredModifiers = getRequiredModifiers(pluginRegistry.store.options);
3164
+ const isReleasingModifier = requiredModifiers.metaKey || requiredModifiers.ctrlKey ? isMac() ? !event.metaKey : !event.ctrlKey : requiredModifiers.shiftKey && !event.shiftKey || requiredModifiers.altKey && !event.altKey;
3165
+ const isReleasingActivationKey = pluginRegistry.store.options.activationKey ? typeof pluginRegistry.store.options.activationKey === "function" ? pluginRegistry.store.options.activationKey(event) : parseActivationKey(pluginRegistry.store.options.activationKey)(event) : isCLikeKey(event.key, event.code);
3166
+ if (didJustCopy() || isCopyFeedbackCooldownActive) {
3167
+ if (isReleasingActivationKey || isReleasingModifier) {
3168
+ clearCopyFeedbackCooldown();
3169
+ deactivateRenderer();
3170
+ }
3171
+ return;
3172
+ }
3173
+ if (!isHoldingKeys() && !isActivated()) return;
3174
+ if (isPromptMode()) return;
3175
+ const hasCustomShortcut = Boolean(pluginRegistry.store.options.activationKey);
3176
+ const isHoldMode = pluginRegistry.store.options.activationMode === "hold";
3177
+ if (isActivated()) {
3178
+ const hasContextMenu = store.contextMenuPosition !== null;
3179
+ if (isReleasingModifier) {
3180
+ if (store.wasActivatedByToggle && pluginRegistry.store.options.activationMode !== "hold") return;
3181
+ if (hasContextMenu) return;
3182
+ deactivateRenderer();
3183
+ } else if (isHoldMode && isReleasingActivationKey) {
3184
+ if (keydownSpamTimerId !== null) {
3185
+ window.clearTimeout(keydownSpamTimerId);
3186
+ keydownSpamTimerId = null;
3187
+ }
3188
+ if (hasContextMenu) return;
3189
+ deactivateRenderer();
3190
+ } else if (!hasCustomShortcut && isReleasingActivationKey && keydownSpamTimerId !== null) {
3191
+ window.clearTimeout(keydownSpamTimerId);
3192
+ keydownSpamTimerId = null;
3193
+ }
3194
+ return;
3195
+ }
3196
+ if (isReleasingActivationKey || isReleasingModifier) {
3197
+ if (store.wasActivatedByToggle && pluginRegistry.store.options.activationMode !== "hold") return;
3198
+ if (isHoldingKeys() || activationHoldState.holdTimerFired && isReleasingModifier) {
3199
+ clearHoldTimer();
3200
+ const heldLongEnoughForActivation = (activationHoldState.startTimestamp ? Date.now() - activationHoldState.startTimestamp : 0) >= 200;
3201
+ const shouldActivateAfterCopy = activationHoldState.holdTimerFired && heldLongEnoughForActivation && (pluginRegistry.store.options.allowActivationInsideInput || !isKeyboardEventTriggeredByInput(event));
3202
+ resetCopyConfirmation();
3203
+ if (shouldActivateAfterCopy) actions.activate();
3204
+ else actions.releaseHold();
3205
+ } else deactivateRenderer();
3206
+ }
3207
+ }, { capture: true });
3208
+ eventListenerManager.addDocumentListener("copy", () => {
3209
+ if (isHoldingKeys()) activationHoldState.copyWaiting = true;
3210
+ });
3211
+ eventListenerManager.addWindowListener("keypress", blockEnterIfNeeded, { capture: true });
3212
+ eventListenerManager.addWindowListener("pointermove", (event) => {
3213
+ if (!event.isPrimary) return;
3214
+ const isTouchPointer = event.pointerType === "touch";
3215
+ actions.setTouchMode(isTouchPointer);
3216
+ if (isEventFromOverlay(event, "data-react-grab-ignore-events")) return;
3217
+ if (store.contextMenuPosition !== null) return;
3218
+ if (isTouchPointer && !isHoldingKeys() && !isActivated()) return;
3219
+ if ((isTouchPointer ? isHoldingKeys() : isActivated()) && !isPromptMode() && isFrozenPhase()) {
3220
+ actions.unfreeze();
3221
+ clearArrowNavigation();
3222
+ }
3223
+ handlePointerMove(event.clientX, event.clientY);
3224
+ }, { passive: true });
3225
+ eventListenerManager.addWindowListener("pointerdown", (event) => {
3226
+ if (event.button !== 0) return;
3227
+ if (!event.isPrimary) return;
3228
+ actions.setTouchMode(event.pointerType === "touch");
3229
+ if (isEventFromOverlay(event, "data-react-grab-ignore-events")) return;
3230
+ if (store.contextMenuPosition !== null) return;
3231
+ if (toolbarMenuPosition() !== null) return;
3232
+ if (isPromptMode()) {
3233
+ const bounds = selectionBounds();
3234
+ if (bounds && event.clientX >= bounds.x && event.clientX <= bounds.x + bounds.width && event.clientY >= bounds.y && event.clientY <= bounds.y + bounds.height) handleInputSubmit();
3235
+ else handleInputCancel();
3236
+ return;
3237
+ }
3238
+ if (handlePointerDown(event.clientX, event.clientY)) {
3239
+ document.documentElement.setPointerCapture(event.pointerId);
3240
+ event.preventDefault();
3241
+ event.stopImmediatePropagation();
3242
+ }
3243
+ }, { capture: true });
3244
+ eventListenerManager.addWindowListener("pointerup", (event) => {
3245
+ if (event.button !== 0) return;
3246
+ if (!event.isPrimary) return;
3247
+ if (isEventFromOverlay(event, "data-react-grab-ignore-events")) return;
3248
+ if (store.contextMenuPosition !== null) return;
3249
+ const isActive = isRendererActive() || isCopying() || isDragging();
3250
+ const hasModifierKeyHeld = event.metaKey || event.ctrlKey;
3251
+ handlePointerUp(event.clientX, event.clientY, hasModifierKeyHeld);
3252
+ if (isActive) {
3253
+ event.preventDefault();
3254
+ event.stopImmediatePropagation();
3255
+ }
3256
+ }, { capture: true });
3257
+ eventListenerManager.addWindowListener("contextmenu", (event) => {
3258
+ if (!isRendererActive() || isCopying() || isPromptMode()) return;
3259
+ const isFromOverlay = isEventFromOverlay(event, "data-react-grab-ignore-events");
3260
+ if (isFromOverlay && arrowNavigationElements().length > 0) clearArrowNavigation();
3261
+ else if (isFromOverlay) return;
3262
+ if (store.contextMenuPosition !== null) {
3263
+ event.preventDefault();
3264
+ return;
3265
+ }
3266
+ event.preventDefault();
3267
+ event.stopPropagation();
3268
+ const element = getElementAtPosition(event.clientX, event.clientY);
3269
+ if (!element) return;
3270
+ const existingFrozenElements = store.frozenElements;
3271
+ if (existingFrozenElements.length > 1 && existingFrozenElements.includes(element)) freezeAllAnimations(existingFrozenElements);
3272
+ else {
3273
+ freezeAllAnimations([element]);
3274
+ actions.setFrozenElement(element);
3275
+ }
3276
+ const position = {
3277
+ x: event.clientX,
3278
+ y: event.clientY
3279
+ };
3280
+ actions.setPointer(position);
3281
+ actions.freeze();
3282
+ openContextMenu(element, position);
3283
+ }, { capture: true });
3284
+ eventListenerManager.addWindowListener("pointercancel", (event) => {
3285
+ if (!event.isPrimary) return;
3286
+ cancelActiveDrag();
3287
+ });
3288
+ eventListenerManager.addWindowListener("click", (event) => {
3289
+ if (isEventFromOverlay(event, "data-react-grab-ignore-events")) return;
3290
+ if (store.contextMenuPosition !== null) return;
3291
+ if (isRendererActive() || isCopying() || didJustDrag()) {
3292
+ event.preventDefault();
3293
+ event.stopImmediatePropagation();
3294
+ if (store.wasActivatedByToggle && !isCopying() && !isPromptMode()) if (!isHoldingKeys()) deactivateRenderer();
3295
+ else actions.setWasActivatedByToggle(false);
3296
+ }
3297
+ }, { capture: true });
3298
+ eventListenerManager.addDocumentListener("visibilitychange", () => {
3299
+ if (document.hidden) {
3300
+ actions.clearGrabbedBoxes();
3301
+ const storeActivationTimestamp = store.activationTimestamp;
3302
+ if (isActivated() && !isPromptMode() && storeActivationTimestamp !== null && Date.now() - storeActivationTimestamp > 500) deactivateRenderer();
3303
+ }
3304
+ });
3305
+ eventListenerManager.addWindowListener("blur", () => {
3306
+ cancelActiveDrag();
3307
+ if (isHoldingKeys()) {
3308
+ clearHoldTimer();
3309
+ actions.releaseHold();
3310
+ resetCopyConfirmation();
3311
+ }
3312
+ });
3313
+ eventListenerManager.addWindowListener("focus", () => {
3314
+ lastWindowFocusTimestamp = Date.now();
3315
+ });
3316
+ eventListenerManager.addWindowListener("focusin", (event) => {
3317
+ if (isEventFromOverlay(event, "data-react-grab")) event.stopPropagation();
3318
+ }, { capture: true });
3319
+ const redetectElementUnderPointer = () => {
3320
+ if (store.isTouchMode && !isHoldingKeys() && !isActivated()) return;
3321
+ if (isEnabled() && !isPromptMode() && !isFrozenPhase() && !isDragging() && store.contextMenuPosition === null && store.frozenElements.length === 0) {
3322
+ const candidate = getElementAtPosition(store.pointer.x, store.pointer.y);
3323
+ actions.setDetectedElement(candidate);
3324
+ }
3325
+ };
3326
+ let boundsRecalcIntervalId = null;
3327
+ let viewportChangeFrameId = null;
3328
+ const handleViewportChange = () => {
3329
+ invalidateInteractionCaches();
3330
+ redetectElementUnderPointer();
3331
+ actions.incrementViewportVersion();
3332
+ actions.updateContextMenuPosition();
3333
+ };
3334
+ eventListenerManager.addWindowListener("scroll", handleViewportChange, { capture: true });
3335
+ let previousViewportWidth = window.innerWidth;
3336
+ let previousViewportHeight = window.innerHeight;
3337
+ eventListenerManager.addWindowListener("resize", () => {
3338
+ const currentViewportWidth = window.innerWidth;
3339
+ const currentViewportHeight = window.innerHeight;
3340
+ if (previousViewportWidth > 0 && previousViewportHeight > 0) {
3341
+ const scaleX = currentViewportWidth / previousViewportWidth;
3342
+ const scaleY = currentViewportHeight / previousViewportHeight;
3343
+ const isUniformScale = Math.abs(scaleX - scaleY) < ZOOM_DETECTION_THRESHOLD;
3344
+ const hasScaleChanged = Math.abs(scaleX - 1) > ZOOM_DETECTION_THRESHOLD;
3345
+ if (isUniformScale && hasScaleChanged) actions.setPointer({
3346
+ x: store.pointer.x * scaleX,
3347
+ y: store.pointer.y * scaleY
3348
+ });
3349
+ }
3350
+ previousViewportWidth = currentViewportWidth;
3351
+ previousViewportHeight = currentViewportHeight;
3352
+ handleViewportChange();
3353
+ });
3354
+ const visualViewport = window.visualViewport;
3355
+ if (visualViewport) {
3356
+ const { signal } = eventListenerManager;
3357
+ visualViewport.addEventListener("resize", handleViewportChange, { signal });
3358
+ visualViewport.addEventListener("scroll", handleViewportChange, { signal });
3359
+ }
3360
+ const scheduleBoundsSync = () => {
3361
+ if (viewportChangeFrameId !== null) return;
3362
+ viewportChangeFrameId = nativeRequestAnimationFrame(() => {
3363
+ viewportChangeFrameId = null;
3364
+ actions.incrementViewportVersion();
3365
+ });
3366
+ };
3367
+ createEffect(() => {
3368
+ if (pluginRegistry.store.theme.enabled && (isActivated() || isCopying() || store.labelInstances.length > 0 || store.grabbedBoxes.length > 0)) {
3369
+ if (boundsRecalcIntervalId !== null) return;
3370
+ boundsRecalcIntervalId = window.setInterval(() => {
3371
+ scheduleBoundsSync();
3372
+ }, 100);
3373
+ return;
3374
+ }
3375
+ if (boundsRecalcIntervalId !== null) {
3376
+ window.clearInterval(boundsRecalcIntervalId);
3377
+ boundsRecalcIntervalId = null;
3378
+ }
3379
+ if (viewportChangeFrameId !== null) {
3380
+ nativeCancelAnimationFrame(viewportChangeFrameId);
3381
+ viewportChangeFrameId = null;
3382
+ }
3383
+ });
3384
+ onCleanup(() => {
3385
+ if (boundsRecalcIntervalId !== null) window.clearInterval(boundsRecalcIntervalId);
3386
+ if (viewportChangeFrameId !== null) nativeCancelAnimationFrame(viewportChangeFrameId);
3387
+ });
3388
+ eventListenerManager.addDocumentListener("copy", (event) => {
3389
+ if (isPromptMode() || isEventFromOverlay(event, "data-react-grab-ignore-events")) return;
3390
+ if (isRendererActive() || isCopying()) event.preventDefault();
3391
+ }, { capture: true });
3392
+ onCleanup(() => {
3393
+ eventListenerManager.abort();
3394
+ if (dragPreviewDebounceTimerId !== null) window.clearTimeout(dragPreviewDebounceTimerId);
3395
+ if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
3396
+ clearCopyFeedbackCooldown();
3397
+ if (actionCycleIdleTimeoutId) window.clearTimeout(actionCycleIdleTimeoutId);
3398
+ if (dropdownTrackingFrameId !== null) nativeCancelAnimationFrame(dropdownTrackingFrameId);
3399
+ grabbedBoxTimeouts.forEach((timeoutId) => window.clearTimeout(timeoutId));
3400
+ grabbedBoxTimeouts.clear();
3401
+ cancelAllLabelFades();
3402
+ autoScroller.stop();
3403
+ document.body.style.userSelect = "";
3404
+ document.body.style.touchAction = "";
3405
+ unlockViewportZoom?.();
3406
+ unlockViewportZoom = null;
3407
+ setCursorOverride(null);
3408
+ keyboardClaimer.restore();
3409
+ });
3410
+ const rendererRoot = mountRoot(typeof "/*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */\n@layer properties;\n@layer theme, base, components, utilities;\n@layer theme {\n :root, :host {\n --font-sans: \"Geist\", ui-sans-serif, system-ui, sans-serif;\n --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\",\n \"Courier New\", monospace;\n --color-black: #000;\n --color-white: #fff;\n --spacing: 0.25rem;\n --font-weight-medium: 500;\n --font-weight-semibold: 600;\n --radius-sm: 0.25rem;\n --ease-out: cubic-bezier(0, 0, 0.2, 1);\n --default-transition-duration: 150ms;\n --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n --default-font-family: var(--font-sans);\n --default-mono-font-family: var(--font-mono);\n --transition-fast: 100ms;\n --transition-normal: 150ms;\n }\n}\n@layer base {\n *, ::after, ::before, ::backdrop, ::file-selector-button {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n border: 0 solid;\n }\n html, :host {\n line-height: 1.5;\n -webkit-text-size-adjust: 100%;\n tab-size: 4;\n font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\");\n font-feature-settings: var(--default-font-feature-settings, normal);\n font-variation-settings: var(--default-font-variation-settings, normal);\n -webkit-tap-highlight-color: transparent;\n }\n hr {\n height: 0;\n color: inherit;\n border-top-width: 1px;\n }\n abbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n }\n h1, h2, h3, h4, h5, h6 {\n font-size: inherit;\n font-weight: inherit;\n }\n a {\n color: inherit;\n -webkit-text-decoration: inherit;\n text-decoration: inherit;\n }\n b, strong {\n font-weight: bolder;\n }\n code, kbd, samp, pre {\n font-family: var(--default-mono-font-family, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace);\n font-feature-settings: var(--default-mono-font-feature-settings, normal);\n font-variation-settings: var(--default-mono-font-variation-settings, normal);\n font-size: 1em;\n }\n small {\n font-size: 80%;\n }\n sub, sup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n }\n sub {\n bottom: -0.25em;\n }\n sup {\n top: -0.5em;\n }\n table {\n text-indent: 0;\n border-color: inherit;\n border-collapse: collapse;\n }\n :-moz-focusring {\n outline: auto;\n }\n progress {\n vertical-align: baseline;\n }\n summary {\n display: list-item;\n }\n ol, ul, menu {\n list-style: none;\n }\n img, svg, video, canvas, audio, iframe, embed, object {\n display: block;\n vertical-align: middle;\n }\n img, video {\n max-width: 100%;\n height: auto;\n }\n button, input, select, optgroup, textarea, ::file-selector-button {\n font: inherit;\n font-feature-settings: inherit;\n font-variation-settings: inherit;\n letter-spacing: inherit;\n color: inherit;\n border-radius: 0;\n background-color: transparent;\n opacity: 1;\n }\n :where(select:is([multiple], [size])) optgroup {\n font-weight: bolder;\n }\n :where(select:is([multiple], [size])) optgroup option {\n padding-inline-start: 20px;\n }\n ::file-selector-button {\n margin-inline-end: 4px;\n }\n ::placeholder {\n opacity: 1;\n }\n @supports (not (-webkit-appearance: -apple-pay-button)) or (contain-intrinsic-size: 1px) {\n ::placeholder {\n color: currentcolor;\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, currentcolor 50%, transparent);\n }\n }\n }\n textarea {\n resize: vertical;\n }\n ::-webkit-search-decoration {\n -webkit-appearance: none;\n }\n ::-webkit-date-and-time-value {\n min-height: 1lh;\n text-align: inherit;\n }\n ::-webkit-datetime-edit {\n display: inline-flex;\n }\n ::-webkit-datetime-edit-fields-wrapper {\n padding: 0;\n }\n ::-webkit-datetime-edit, ::-webkit-datetime-edit-year-field, ::-webkit-datetime-edit-month-field, ::-webkit-datetime-edit-day-field, ::-webkit-datetime-edit-hour-field, ::-webkit-datetime-edit-minute-field, ::-webkit-datetime-edit-second-field, ::-webkit-datetime-edit-millisecond-field, ::-webkit-datetime-edit-meridiem-field {\n padding-block: 0;\n }\n ::-webkit-calendar-picker-indicator {\n line-height: 1;\n }\n :-moz-ui-invalid {\n box-shadow: none;\n }\n button, input:where([type=\"button\"], [type=\"reset\"], [type=\"submit\"]), ::file-selector-button {\n appearance: button;\n }\n ::-webkit-inner-spin-button, ::-webkit-outer-spin-button {\n height: auto;\n }\n [hidden]:where(:not([hidden=\"until-found\"])) {\n display: none !important;\n }\n}\n@layer utilities {\n .pointer-events-auto {\n pointer-events: auto;\n }\n .pointer-events-none {\n pointer-events: none;\n }\n .invisible {\n visibility: hidden;\n }\n .visible {\n visibility: visible;\n }\n .touch-hitbox {\n position: relative;\n &::before {\n content: \"\";\n position: absolute;\n display: block;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 100%;\n height: 100%;\n min-height: 44px;\n min-width: 44px;\n }\n }\n .absolute {\n position: absolute;\n }\n .fixed {\n position: fixed;\n }\n .relative {\n position: relative;\n }\n .-top-1 {\n top: calc(var(--spacing) * -1);\n }\n .top-0 {\n top: calc(var(--spacing) * 0);\n }\n .top-0\\.5 {\n top: calc(var(--spacing) * 0.5);\n }\n .top-1\\/2 {\n top: calc(1/2 * 100%);\n }\n .top-full {\n top: 100%;\n }\n .-right-1 {\n right: calc(var(--spacing) * -1);\n }\n .right-full {\n right: 100%;\n }\n .bottom-full {\n bottom: 100%;\n }\n .left-0 {\n left: calc(var(--spacing) * 0);\n }\n .left-0\\.5 {\n left: calc(var(--spacing) * 0.5);\n }\n .left-1\\.5 {\n left: calc(var(--spacing) * 1.5);\n }\n .left-1\\/2 {\n left: calc(1/2 * 100%);\n }\n .left-2\\.5 {\n left: calc(var(--spacing) * 2.5);\n }\n .left-full {\n left: 100%;\n }\n .z-1 {\n z-index: 1;\n }\n .z-10 {\n z-index: 10;\n }\n .container {\n width: 100%;\n @media (width >= 40rem) {\n max-width: 40rem;\n }\n @media (width >= 48rem) {\n max-width: 48rem;\n }\n @media (width >= 64rem) {\n max-width: 64rem;\n }\n @media (width >= 80rem) {\n max-width: 80rem;\n }\n @media (width >= 96rem) {\n max-width: 96rem;\n }\n }\n .m-0 {\n margin: calc(var(--spacing) * 0);\n }\n .-mx-2 {\n margin-inline: calc(var(--spacing) * -2);\n }\n .mx-0\\.5 {\n margin-inline: calc(var(--spacing) * 0.5);\n }\n .-my-1\\.5 {\n margin-block: calc(var(--spacing) * -1.5);\n }\n .my-0\\.5 {\n margin-block: calc(var(--spacing) * 0.5);\n }\n .mt-0\\.5 {\n margin-top: calc(var(--spacing) * 0.5);\n }\n .mt-2\\.5 {\n margin-top: calc(var(--spacing) * 2.5);\n }\n .mr-0\\.5 {\n margin-right: calc(var(--spacing) * 0.5);\n }\n .mr-1\\.5 {\n margin-right: calc(var(--spacing) * 1.5);\n }\n .mr-2\\.5 {\n margin-right: calc(var(--spacing) * 2.5);\n }\n .mb-0\\.5 {\n margin-bottom: calc(var(--spacing) * 0.5);\n }\n .mb-1\\.5 {\n margin-bottom: calc(var(--spacing) * 1.5);\n }\n .mb-2\\.5 {\n margin-bottom: calc(var(--spacing) * 2.5);\n }\n .-ml-\\[2px\\] {\n margin-left: calc(2px * -1);\n }\n .ml-0\\.5 {\n margin-left: calc(var(--spacing) * 0.5);\n }\n .ml-1 {\n margin-left: calc(var(--spacing) * 1);\n }\n .ml-2\\.5 {\n margin-left: calc(var(--spacing) * 2.5);\n }\n .ml-4 {\n margin-left: calc(var(--spacing) * 4);\n }\n .line-clamp-5 {\n overflow: hidden;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 5;\n }\n .block {\n display: block;\n }\n .flex {\n display: flex;\n }\n .grid {\n display: grid;\n }\n .hidden {\n display: none;\n }\n .inline {\n display: inline;\n }\n .inline-flex {\n display: inline-flex;\n }\n .size-4 {\n width: calc(var(--spacing) * 4);\n height: calc(var(--spacing) * 4);\n }\n .size-\\[18px\\] {\n width: 18px;\n height: 18px;\n }\n .h-0 {\n height: calc(var(--spacing) * 0);\n }\n .h-1\\.5 {\n height: calc(var(--spacing) * 1.5);\n }\n .h-2 {\n height: calc(var(--spacing) * 2);\n }\n .h-2\\.5 {\n height: calc(var(--spacing) * 2.5);\n }\n .h-3 {\n height: calc(var(--spacing) * 3);\n }\n .h-3\\.5 {\n height: calc(var(--spacing) * 3.5);\n }\n .h-\\[17px\\] {\n height: 17px;\n }\n .h-fit {\n height: fit-content;\n }\n .max-h-\\[240px\\] {\n max-height: 240px;\n }\n .min-h-0 {\n min-height: calc(var(--spacing) * 0);\n }\n .min-h-4 {\n min-height: calc(var(--spacing) * 4);\n }\n .w-0 {\n width: calc(var(--spacing) * 0);\n }\n .w-1\\.5 {\n width: calc(var(--spacing) * 1.5);\n }\n .w-2 {\n width: calc(var(--spacing) * 2);\n }\n .w-3\\.5 {\n width: calc(var(--spacing) * 3.5);\n }\n .w-5 {\n width: calc(var(--spacing) * 5);\n }\n .w-\\[calc\\(100\\%\\+16px\\)\\] {\n width: calc(100% + 16px);\n }\n .w-auto {\n width: auto;\n }\n .w-fit {\n width: fit-content;\n }\n .w-full {\n width: 100%;\n }\n .max-w-\\[280px\\] {\n max-width: 280px;\n }\n .max-w-full {\n max-width: 100%;\n }\n .min-w-0 {\n min-width: calc(var(--spacing) * 0);\n }\n .min-w-2\\.5 {\n min-width: calc(var(--spacing) * 2.5);\n }\n .min-w-\\[100px\\] {\n min-width: 100px;\n }\n .min-w-\\[150px\\] {\n min-width: 150px;\n }\n .flex-1 {\n flex: 1;\n }\n .flex-shrink {\n flex-shrink: 1;\n }\n .shrink {\n flex-shrink: 1;\n }\n .shrink-0 {\n flex-shrink: 0;\n }\n .flex-grow {\n flex-grow: 1;\n }\n .-translate-x-1\\/2 {\n --tw-translate-x: calc(calc(1/2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .-translate-y-1\\/2 {\n --tw-translate-y: calc(calc(1/2 * 100%) * -1);\n translate: var(--tw-translate-x) var(--tw-translate-y);\n }\n .scale-75 {\n --tw-scale-x: 75%;\n --tw-scale-y: 75%;\n --tw-scale-z: 75%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .scale-100 {\n --tw-scale-x: 100%;\n --tw-scale-y: 100%;\n --tw-scale-z: 100%;\n scale: var(--tw-scale-x) var(--tw-scale-y);\n }\n .-rotate-90 {\n rotate: calc(90deg * -1);\n }\n .rotate-0 {\n rotate: 0deg;\n }\n .rotate-90 {\n rotate: 90deg;\n }\n .rotate-180 {\n rotate: 180deg;\n }\n .interactive-scale {\n transition-property: transform;\n transition-duration: var(--transition-normal);\n transition-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1);\n @media (hover: hover) and (pointer: fine) {\n &:hover {\n transform: scale(1.05);\n }\n }\n &:active {\n transform: scale(0.97);\n }\n }\n .press-scale {\n transition-property: transform;\n transition-duration: var(--transition-fast);\n transition-timing-function: ease-out;\n &:active {\n transform: scale(0.97);\n }\n }\n .transform {\n transform: var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,);\n }\n .animate-\\[hint-flip-in_var\\(--transition-normal\\)_ease-out\\] {\n animation: hint-flip-in var(--transition-normal) ease-out;\n }\n .cursor-grab {\n cursor: grab;\n }\n .cursor-grabbing {\n cursor: grabbing;\n }\n .cursor-pointer {\n cursor: pointer;\n }\n .resize {\n resize: both;\n }\n .resize-none {\n resize: none;\n }\n .grid-cols-\\[0fr\\] {\n grid-template-columns: 0fr;\n }\n .grid-cols-\\[1fr\\] {\n grid-template-columns: 1fr;\n }\n .grid-rows-\\[0fr\\] {\n grid-template-rows: 0fr;\n }\n .grid-rows-\\[1fr\\] {\n grid-template-rows: 1fr;\n }\n .flex-col {\n flex-direction: column;\n }\n .flex-wrap {\n flex-wrap: wrap;\n }\n .items-center {\n align-items: center;\n }\n .items-end {\n align-items: flex-end;\n }\n .items-start {\n align-items: flex-start;\n }\n .justify-between {\n justify-content: space-between;\n }\n .justify-center {\n justify-content: center;\n }\n .justify-end {\n justify-content: flex-end;\n }\n .gap-0\\.5 {\n gap: calc(var(--spacing) * 0.5);\n }\n .gap-1 {\n gap: calc(var(--spacing) * 1);\n }\n .gap-1\\.5 {\n gap: calc(var(--spacing) * 1.5);\n }\n .gap-2 {\n gap: calc(var(--spacing) * 2);\n }\n .gap-\\[5px\\] {\n gap: 5px;\n }\n .self-stretch {\n align-self: stretch;\n }\n .truncate {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .overflow-hidden {\n overflow: hidden;\n }\n .overflow-visible {\n overflow: visible;\n }\n .overflow-y-auto {\n overflow-y: auto;\n }\n .rounded-\\[10px\\] {\n border-radius: 10px;\n }\n .rounded-full {\n border-radius: calc(infinity * 1px);\n }\n .rounded-sm {\n border-radius: var(--radius-sm);\n }\n .rounded-t-\\[10px\\] {\n border-top-left-radius: 10px;\n border-top-right-radius: 10px;\n }\n .rounded-t-none {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n }\n .rounded-l-\\[10px\\] {\n border-top-left-radius: 10px;\n border-bottom-left-radius: 10px;\n }\n .rounded-l-none {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n }\n .rounded-r-\\[10px\\] {\n border-top-right-radius: 10px;\n border-bottom-right-radius: 10px;\n }\n .rounded-r-none {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n .rounded-b-\\[6px\\] {\n border-bottom-right-radius: 6px;\n border-bottom-left-radius: 6px;\n }\n .rounded-b-\\[10px\\] {\n border-bottom-right-radius: 10px;\n border-bottom-left-radius: 10px;\n }\n .rounded-b-none {\n border-bottom-right-radius: 0;\n border-bottom-left-radius: 0;\n }\n .border {\n border-style: var(--tw-border-style);\n border-width: 1px;\n }\n .\\[border-width\\:0\\.5px\\] {\n border-width: 0.5px;\n }\n .\\[border-top-width\\:0\\.5px\\] {\n border-top-width: 0.5px;\n }\n .border-none {\n --tw-border-style: none;\n border-style: none;\n }\n .border-solid {\n --tw-border-style: solid;\n border-style: solid;\n }\n .border-\\[\\#B3B3B3\\] {\n border-color: #B3B3B3;\n }\n .border-t-\\[\\#D9D9D9\\] {\n border-top-color: #D9D9D9;\n }\n .bg-\\[\\#FEF2F2\\] {\n background-color: #FEF2F2;\n }\n .bg-black {\n background-color: var(--color-black);\n }\n .bg-black\\/5 {\n background-color: color-mix(in srgb, #000 5%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 5%, transparent);\n }\n }\n .bg-black\\/25 {\n background-color: color-mix(in srgb, #000 25%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 25%, transparent);\n }\n }\n .bg-transparent {\n background-color: transparent;\n }\n .bg-white {\n background-color: var(--color-white);\n }\n .p-0 {\n padding: calc(var(--spacing) * 0);\n }\n .px-0\\.5 {\n padding-inline: calc(var(--spacing) * 0.5);\n }\n .px-0\\.25 {\n padding-inline: calc(var(--spacing) * 0.25);\n }\n .px-1\\.5 {\n padding-inline: calc(var(--spacing) * 1.5);\n }\n .px-2 {\n padding-inline: calc(var(--spacing) * 2);\n }\n .px-\\[3px\\] {\n padding-inline: 3px;\n }\n .py-0\\.5 {\n padding-block: calc(var(--spacing) * 0.5);\n }\n .py-0\\.25 {\n padding-block: calc(var(--spacing) * 0.25);\n }\n .py-1 {\n padding-block: calc(var(--spacing) * 1);\n }\n .py-1\\.5 {\n padding-block: calc(var(--spacing) * 1.5);\n }\n .py-2 {\n padding-block: calc(var(--spacing) * 2);\n }\n .py-px {\n padding-block: 1px;\n }\n .pt-1\\.5 {\n padding-top: calc(var(--spacing) * 1.5);\n }\n .pb-1 {\n padding-bottom: calc(var(--spacing) * 1);\n }\n .text-left {\n text-align: left;\n }\n .font-sans {\n font-family: var(--font-sans);\n }\n .text-\\[8px\\] {\n font-size: 8px;\n }\n .text-\\[10px\\] {\n font-size: 10px;\n }\n .text-\\[11px\\] {\n font-size: 11px;\n }\n .text-\\[12px\\] {\n font-size: 12px;\n }\n .text-\\[13px\\] {\n font-size: 13px;\n }\n .leading-3 {\n --tw-leading: calc(var(--spacing) * 3);\n line-height: calc(var(--spacing) * 3);\n }\n .leading-3\\.5 {\n --tw-leading: calc(var(--spacing) * 3.5);\n line-height: calc(var(--spacing) * 3.5);\n }\n .leading-4 {\n --tw-leading: calc(var(--spacing) * 4);\n line-height: calc(var(--spacing) * 4);\n }\n .leading-none {\n --tw-leading: 1;\n line-height: 1;\n }\n .font-medium {\n --tw-font-weight: var(--font-weight-medium);\n font-weight: var(--font-weight-medium);\n }\n .font-semibold {\n --tw-font-weight: var(--font-weight-semibold);\n font-weight: var(--font-weight-semibold);\n }\n .wrap-break-word {\n overflow-wrap: break-word;\n }\n .text-ellipsis {\n text-overflow: ellipsis;\n }\n .whitespace-nowrap {\n white-space: nowrap;\n }\n .text-\\[\\#71717a\\] {\n color: #71717a;\n }\n .text-\\[\\#B3B3B3\\] {\n color: #B3B3B3;\n }\n .text-\\[\\#B91C1C\\] {\n color: #B91C1C;\n }\n .text-\\[\\#B91C1C\\]\\/50 {\n color: color-mix(in oklab, #B91C1C 50%, transparent);\n }\n .text-black {\n color: var(--color-black);\n }\n .text-black\\/25 {\n color: color-mix(in srgb, #000 25%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 25%, transparent);\n }\n }\n .text-black\\/30 {\n color: color-mix(in srgb, #000 30%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 30%, transparent);\n }\n }\n .text-black\\/40 {\n color: color-mix(in srgb, #000 40%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 40%, transparent);\n }\n }\n .text-black\\/50 {\n color: color-mix(in srgb, #000 50%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 50%, transparent);\n }\n }\n .text-black\\/60 {\n color: color-mix(in srgb, #000 60%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 60%, transparent);\n }\n }\n .text-black\\/70 {\n color: color-mix(in srgb, #000 70%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 70%, transparent);\n }\n }\n .text-black\\/85 {\n color: color-mix(in srgb, #000 85%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n color: color-mix(in oklab, var(--color-black) 85%, transparent);\n }\n }\n .text-white {\n color: var(--color-white);\n }\n .tabular-nums {\n --tw-numeric-spacing: tabular-nums;\n font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,);\n }\n .antialiased {\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n .opacity-0 {\n opacity: 0%;\n }\n .opacity-40 {\n opacity: 40%;\n }\n .opacity-100 {\n opacity: 100%;\n }\n .shadow {\n --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));\n box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);\n }\n .outline {\n outline-style: var(--tw-outline-style);\n outline-width: 1px;\n }\n .blur {\n --tw-blur: blur(8px);\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n }\n .filter {\n filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);\n }\n .filter-\\[drop-shadow\\(0px_1px_2px_\\#51515140\\)\\] {\n filter: drop-shadow(0px 1px 2px #51515140);\n }\n .backdrop-filter {\n -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);\n }\n .transition {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-columns\\,opacity\\] {\n transition-property: grid-template-columns,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-columns\\] {\n transition-property: grid-template-columns;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-rows\\,opacity\\] {\n transition-property: grid-template-rows,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[grid-template-rows\\] {\n transition-property: grid-template-rows;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[opacity\\,transform\\] {\n transition-property: opacity,transform;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[top\\,left\\,width\\,height\\,opacity\\] {\n transition-property: top,left,width,height,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-\\[transform\\,opacity\\] {\n transition-property: transform,opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-all {\n transition-property: all;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-colors {\n transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-opacity {\n transition-property: opacity;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .transition-transform {\n transition-property: transform, translate, scale, rotate;\n transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));\n transition-duration: var(--tw-duration, var(--default-transition-duration));\n }\n .duration-75 {\n --tw-duration: 75ms;\n transition-duration: 75ms;\n }\n .duration-100 {\n --tw-duration: 100ms;\n transition-duration: 100ms;\n }\n .duration-150 {\n --tw-duration: 150ms;\n transition-duration: 150ms;\n }\n .duration-300 {\n --tw-duration: 300ms;\n transition-duration: 300ms;\n }\n .ease-out {\n --tw-ease: var(--ease-out);\n transition-timing-function: var(--ease-out);\n }\n .will-change-\\[opacity\\,transform\\] {\n will-change: opacity,transform;\n }\n .contain-layout {\n --tw-contain-layout: layout;\n contain: var(--tw-contain-size,) var(--tw-contain-layout,) var(--tw-contain-paint,) var(--tw-contain-style,);\n }\n .outline-none {\n --tw-outline-style: none;\n outline-style: none;\n }\n .select-none {\n -webkit-user-select: none;\n user-select: none;\n }\n .\\[animation-fill-mode\\:backwards\\] {\n animation-fill-mode: backwards;\n }\n .\\[corner-shape\\:superellipse\\(1\\.25\\)\\] {\n corner-shape: superellipse(1.25);\n }\n .\\[font-synthesis\\:none\\] {\n font-synthesis: none;\n }\n .\\[scrollbar-color\\:transparent_transparent\\] {\n scrollbar-color: transparent transparent;\n }\n .\\[scrollbar-width\\:thin\\] {\n scrollbar-width: thin;\n }\n .before\\:\\!min-h-full {\n &::before {\n content: var(--tw-content);\n min-height: 100% !important;\n }\n }\n .before\\:\\!min-w-full {\n &::before {\n content: var(--tw-content);\n min-width: 100% !important;\n }\n }\n .hover\\:bg-\\[\\#F5F5F5\\] {\n &:hover {\n @media (hover: hover) {\n background-color: #F5F5F5;\n }\n }\n }\n .hover\\:bg-\\[\\#FEE2E2\\] {\n &:hover {\n @media (hover: hover) {\n background-color: #FEE2E2;\n }\n }\n }\n .hover\\:bg-black\\/10 {\n &:hover {\n @media (hover: hover) {\n background-color: color-mix(in srgb, #000 10%, transparent);\n @supports (color: color-mix(in lab, red, red)) {\n background-color: color-mix(in oklab, var(--color-black) 10%, transparent);\n }\n }\n }\n }\n .hover\\:text-black {\n &:hover {\n @media (hover: hover) {\n color: var(--color-black);\n }\n }\n }\n .hover\\:opacity-100 {\n &:hover {\n @media (hover: hover) {\n opacity: 100%;\n }\n }\n }\n .hover\\:\\[scrollbar-color\\:rgba\\(0\\,0\\,0\\,0\\.15\\)_transparent\\] {\n &:hover {\n @media (hover: hover) {\n scrollbar-color: rgba(0,0,0,0.15) transparent;\n }\n }\n }\n .disabled\\:cursor-default {\n &:disabled {\n cursor: default;\n }\n }\n .disabled\\:opacity-40 {\n &:disabled {\n opacity: 40%;\n }\n }\n}\n:host {\n all: initial;\n direction: ltr;\n}\n@keyframes shake {\n 0%, 100% {\n transform: translateX(0);\n }\n 15% {\n transform: translateX(-3px);\n }\n 30% {\n transform: translateX(3px);\n }\n 45% {\n transform: translateX(-3px);\n }\n 60% {\n transform: translateX(3px);\n }\n 75% {\n transform: translateX(-2px);\n }\n 90% {\n transform: translateX(2px);\n }\n}\n@keyframes success-pop {\n 0% {\n transform: scale(0.9);\n opacity: 0;\n }\n 60% {\n transform: scale(1.1);\n opacity: 1;\n }\n 80% {\n transform: scale(0.95);\n }\n 100% {\n transform: scale(1);\n opacity: 1;\n }\n}\n@keyframes hint-flip-in {\n from {\n opacity: 0;\n transform: translateY(4px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n@keyframes tooltip-fade-in {\n from {\n opacity: 0;\n transform: scale(0.97);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n@keyframes icon-loader-spin {\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n 100% {\n opacity: 0.2;\n }\n}\n.icon-loader-bar {\n animation: icon-loader-spin 0.5s linear infinite;\n}\n@keyframes shimmer {\n 0% {\n background-position: 200% 0;\n }\n 100% {\n background-position: -200% 0;\n }\n}\n.shimmer-text {\n background: linear-gradient( 90deg, #71717a 0%, #a1a1aa 25%, #71717a 50%, #a1a1aa 75%, #71717a 100% );\n background-size: 200% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n color: transparent;\n animation: shimmer 2.5s linear infinite;\n}\n@keyframes clock-flash {\n 0% {\n transform: scale(1);\n }\n 25% {\n transform: scale(1.2);\n }\n 50% {\n transform: scale(0.92);\n }\n 75% {\n transform: scale(1.05);\n }\n 100% {\n transform: scale(1);\n }\n}\n.animate-clock-flash {\n animation: clock-flash 400ms ease-out;\n will-change: transform;\n}\n.animate-shake {\n animation: shake 0.3s ease-out;\n will-change: transform;\n}\n.animate-success-pop {\n animation: success-pop 250ms ease-out;\n will-change: transform, opacity;\n}\n.animate-tooltip-fade-in {\n animation: tooltip-fade-in var(--transition-fast) ease-out;\n will-change: transform, opacity;\n}\n@property --tw-translate-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-translate-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 0;\n}\n@property --tw-scale-x {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n@property --tw-scale-y {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n@property --tw-scale-z {\n syntax: \"*\";\n inherits: false;\n initial-value: 1;\n}\n@property --tw-rotate-x {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-rotate-y {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-rotate-z {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-skew-x {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-skew-y {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-border-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-leading {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-font-weight {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ordinal {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-slashed-zero {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-numeric-figure {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-numeric-spacing {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-numeric-fraction {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-inset-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-inset-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-ring-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ring-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-inset-ring-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-inset-ring-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-ring-inset {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ring-offset-width {\n syntax: \"<length>\";\n inherits: false;\n initial-value: 0px;\n}\n@property --tw-ring-offset-color {\n syntax: \"*\";\n inherits: false;\n initial-value: #fff;\n}\n@property --tw-ring-offset-shadow {\n syntax: \"*\";\n inherits: false;\n initial-value: 0 0 #0000;\n}\n@property --tw-outline-style {\n syntax: \"*\";\n inherits: false;\n initial-value: solid;\n}\n@property --tw-blur {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-brightness {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contrast {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-grayscale {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-hue-rotate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-invert {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-opacity {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-saturate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-sepia {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow-color {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-drop-shadow-alpha {\n syntax: \"<percentage>\";\n inherits: false;\n initial-value: 100%;\n}\n@property --tw-drop-shadow-size {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-blur {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-brightness {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-contrast {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-grayscale {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-hue-rotate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-invert {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-opacity {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-saturate {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-backdrop-sepia {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-duration {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-ease {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-size {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-layout {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-paint {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-contain-style {\n syntax: \"*\";\n inherits: false;\n}\n@property --tw-content {\n syntax: \"*\";\n initial-value: \"\";\n inherits: false;\n}\n@layer properties {\n @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {\n *, ::before, ::after, ::backdrop {\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-translate-z: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-scale-z: 1;\n --tw-rotate-x: initial;\n --tw-rotate-y: initial;\n --tw-rotate-z: initial;\n --tw-skew-x: initial;\n --tw-skew-y: initial;\n --tw-border-style: solid;\n --tw-leading: initial;\n --tw-font-weight: initial;\n --tw-ordinal: initial;\n --tw-slashed-zero: initial;\n --tw-numeric-figure: initial;\n --tw-numeric-spacing: initial;\n --tw-numeric-fraction: initial;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-color: initial;\n --tw-shadow-alpha: 100%;\n --tw-inset-shadow: 0 0 #0000;\n --tw-inset-shadow-color: initial;\n --tw-inset-shadow-alpha: 100%;\n --tw-ring-color: initial;\n --tw-ring-shadow: 0 0 #0000;\n --tw-inset-ring-color: initial;\n --tw-inset-ring-shadow: 0 0 #0000;\n --tw-ring-inset: initial;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-outline-style: solid;\n --tw-blur: initial;\n --tw-brightness: initial;\n --tw-contrast: initial;\n --tw-grayscale: initial;\n --tw-hue-rotate: initial;\n --tw-invert: initial;\n --tw-opacity: initial;\n --tw-saturate: initial;\n --tw-sepia: initial;\n --tw-drop-shadow: initial;\n --tw-drop-shadow-color: initial;\n --tw-drop-shadow-alpha: 100%;\n --tw-drop-shadow-size: initial;\n --tw-backdrop-blur: initial;\n --tw-backdrop-brightness: initial;\n --tw-backdrop-contrast: initial;\n --tw-backdrop-grayscale: initial;\n --tw-backdrop-hue-rotate: initial;\n --tw-backdrop-invert: initial;\n --tw-backdrop-opacity: initial;\n --tw-backdrop-saturate: initial;\n --tw-backdrop-sepia: initial;\n --tw-duration: initial;\n --tw-ease: initial;\n --tw-contain-size: initial;\n --tw-contain-layout: initial;\n --tw-contain-paint: initial;\n --tw-contain-style: initial;\n --tw-content: \"\";\n }\n }\n}\n" === "string" ? styles_default : "");
3411
+ const isThemeEnabled = createMemo(() => pluginRegistry.store.theme.enabled);
3412
+ const isSelectionBoxThemeEnabled = createMemo(() => pluginRegistry.store.theme.selectionBox.enabled);
3413
+ const isElementLabelThemeEnabled = createMemo(() => pluginRegistry.store.theme.elementLabel.enabled);
3414
+ const isDragBoxThemeEnabled = createMemo(() => pluginRegistry.store.theme.dragBox.enabled);
3415
+ const isSelectionSuppressed = createMemo(() => didJustCopy() || isToolbarSelectHovered() && !isFrozenPhase());
3416
+ const hasDragPreviewBounds = createMemo(() => dragPreviewBounds().length > 0);
3417
+ const selectionVisible = createMemo(() => {
3418
+ if (!isThemeEnabled()) return false;
3419
+ if (!isSelectionBoxThemeEnabled()) return false;
3420
+ if (isSelectionSuppressed()) return false;
3421
+ if (hasDragPreviewBounds()) return true;
3422
+ return isSelectionElementVisible();
3423
+ });
3424
+ const selectionTagName = createMemo(() => {
3425
+ const element = selectionElement();
3426
+ if (!element) return void 0;
3427
+ return getTagName(element) || void 0;
3428
+ });
3429
+ createEffect(on(() => debouncedElementForComponentName(), (element) => {
3430
+ const currentVersion = ++componentNameRequestVersion;
3431
+ if (!element) {
3432
+ setResolvedComponentName(void 0);
3433
+ return;
3434
+ }
3435
+ getNearestComponentName(element).then((name) => {
3436
+ if (componentNameRequestVersion !== currentVersion) return;
3437
+ setResolvedComponentName(name ?? void 0);
3438
+ }).catch(() => {
3439
+ if (componentNameRequestVersion !== currentVersion) return;
3440
+ setResolvedComponentName(void 0);
3441
+ });
3442
+ }));
3443
+ const selectionLabelVisible = createMemo(() => {
3444
+ if (store.contextMenuPosition !== null) return false;
3445
+ if (!isElementLabelThemeEnabled()) return false;
3446
+ if (isSelectionSuppressed()) return false;
3447
+ return isSelectionElementVisible();
3448
+ });
3449
+ const labelInstanceCache = /* @__PURE__ */ new Map();
3450
+ const recomputeLabelInstance = (instance) => {
3451
+ const hasMultipleElements = instance.elements && instance.elements.length > 1;
3452
+ const instanceElement = instance.element;
3453
+ const newBounds = !hasMultipleElements && instanceElement && document.body.contains(instanceElement) ? createElementBounds(instanceElement) : instance.bounds;
3454
+ const previousInstance = labelInstanceCache.get(instance.id);
3455
+ const boundsUnchanged = previousInstance && previousInstance.bounds.x === newBounds.x && previousInstance.bounds.y === newBounds.y && previousInstance.bounds.width === newBounds.width && previousInstance.bounds.height === newBounds.height;
3456
+ if (previousInstance && previousInstance.status === instance.status && previousInstance.errorMessage === instance.errorMessage && boundsUnchanged) return previousInstance;
3457
+ const newBoundsCenterX = newBounds.x + newBounds.width / 2;
3458
+ const newBoundsHalfWidth = newBounds.width / 2;
3459
+ let newMouseX;
3460
+ if (instance.mouseXOffsetRatio !== void 0 && newBoundsHalfWidth > 0) newMouseX = newBoundsCenterX + instance.mouseXOffsetRatio * newBoundsHalfWidth;
3461
+ else if (instance.mouseXOffsetFromCenter !== void 0) newMouseX = newBoundsCenterX + instance.mouseXOffsetFromCenter;
3462
+ else newMouseX = instance.mouseX ?? newBoundsCenterX;
3463
+ const newCached = {
3464
+ ...instance,
3465
+ bounds: newBounds,
3466
+ mouseX: newMouseX
3467
+ };
3468
+ labelInstanceCache.set(instance.id, newCached);
3469
+ return newCached;
3470
+ };
3471
+ const computedLabelInstances = createMemo(() => {
3472
+ if (!isThemeEnabled()) return [];
3473
+ if (!pluginRegistry.store.theme.grabbedBoxes.enabled) return [];
3474
+ store.viewportVersion;
3475
+ const currentIds = new Set(store.labelInstances.map((instance) => instance.id));
3476
+ for (const cachedId of labelInstanceCache.keys()) if (!currentIds.has(cachedId)) labelInstanceCache.delete(cachedId);
3477
+ return store.labelInstances.map(recomputeLabelInstance);
3478
+ });
3479
+ const computedGrabbedBoxes = createMemo(() => {
3480
+ if (!isThemeEnabled()) return [];
3481
+ if (!pluginRegistry.store.theme.grabbedBoxes.enabled) return [];
3482
+ store.viewportVersion;
3483
+ return store.grabbedBoxes.map((box) => {
3484
+ if (!box.element || !document.body.contains(box.element)) return box;
3485
+ return {
3486
+ ...box,
3487
+ bounds: createElementBounds(box.element)
3488
+ };
3489
+ });
3490
+ });
3491
+ const dragVisible = createMemo(() => isThemeEnabled() && isDragBoxThemeEnabled() && isRendererActive() && isDraggingBeyondThreshold());
3492
+ const labelVariant = createMemo(() => isCopying() ? "processing" : "hover");
3493
+ const labelVisible = createMemo(() => {
3494
+ if (!isThemeEnabled()) return false;
3495
+ const themeEnabled = isElementLabelThemeEnabled();
3496
+ const inPromptMode = isPromptMode();
3497
+ const copying = isCopying();
3498
+ const rendererActive = isRendererActive();
3499
+ const dragging = isDragging();
3500
+ const hasElement = Boolean(effectiveElement());
3501
+ const toolbarSelectHovered = isToolbarSelectHovered();
3502
+ const frozen = isFrozenPhase();
3503
+ if (!themeEnabled) return false;
3504
+ if (inPromptMode) return false;
3505
+ if (toolbarSelectHovered && !frozen) return false;
3506
+ if (copying) return true;
3507
+ return rendererActive && !dragging && hasElement;
3508
+ });
3509
+ const contextMenuBounds = createMemo(() => {
3510
+ store.viewportVersion;
3511
+ const element = store.contextMenuElement;
3512
+ if (!element) return null;
3513
+ return createElementBounds(element);
3514
+ });
3515
+ const contextMenuPosition = createMemo(() => {
3516
+ store.viewportVersion;
3517
+ return store.contextMenuPosition;
3518
+ });
3519
+ const contextMenuTagName = createMemo(() => {
3520
+ const element = store.contextMenuElement;
3521
+ if (!element) return void 0;
3522
+ const frozenCount = store.frozenElements.length;
3523
+ if (frozenCount > 1) return `${frozenCount} elements`;
3524
+ return getTagName(element) || void 0;
3525
+ });
3526
+ const [contextMenuComponentName] = createResource(() => ({
3527
+ element: store.contextMenuElement,
3528
+ frozenCount: store.frozenElements.length
3529
+ }), async ({ element, frozenCount }) => {
3530
+ if (!element) return void 0;
3531
+ if (frozenCount > 1) return void 0;
3532
+ return await getNearestComponentName(element) ?? void 0;
3533
+ });
3534
+ const [contextMenuFilePath] = createResource(() => store.contextMenuElement, async (element) => {
3535
+ if (!element) return null;
3536
+ return resolveSource(element);
3537
+ });
3538
+ const createPerformWithFeedback = (element, elements, tagName, componentName, options) => {
3539
+ return async (action) => {
3540
+ const fallbackBounds = options?.fallbackBounds ?? null;
3541
+ const fallbackSelectionBounds = options?.fallbackSelectionBounds ?? [];
3542
+ const position = options?.position ?? store.contextMenuPosition ?? store.pointer;
3543
+ const frozenBounds = frozenElementsBounds();
3544
+ const singleElementBounds = contextMenuBounds() ?? fallbackBounds;
3545
+ const hasMultipleElements = elements.length > 1;
3546
+ const labelBounds = hasMultipleElements ? createFlatOverlayBounds(combineBounds(frozenBounds)) : singleElementBounds;
3547
+ const shouldDeactivateAfter = store.wasActivatedByToggle;
3548
+ let selectionBoundsForLabel;
3549
+ if (hasMultipleElements) selectionBoundsForLabel = frozenBounds;
3550
+ else if (singleElementBounds) selectionBoundsForLabel = [singleElementBounds];
3551
+ else selectionBoundsForLabel = fallbackSelectionBounds;
3552
+ actions.hideContextMenu();
3553
+ if (labelBounds) {
3554
+ const labelCursorX = hasMultipleElements ? labelBounds.x + labelBounds.width / 2 : position.x;
3555
+ const labelInstanceId = createLabelInstance(labelBounds, tagName || "element", componentName, "copying", {
3556
+ element,
3557
+ mouseX: labelCursorX,
3558
+ elements: hasMultipleElements ? elements : void 0,
3559
+ boundsMultiple: selectionBoundsForLabel
3560
+ });
3561
+ let didSucceed = false;
3562
+ let errorMessage;
3563
+ try {
3564
+ didSucceed = await action();
3565
+ if (!didSucceed) errorMessage = "Failed to copy";
3566
+ } catch (error) {
3567
+ errorMessage = normalizeErrorMessage(error, "Action failed");
3568
+ }
3569
+ updateLabelAfterCopy(labelInstanceId, didSucceed, errorMessage);
3570
+ } else try {
3571
+ await action();
3572
+ } catch (error) {
3573
+ logRecoverableError("Action failed without feedback bounds", error);
3574
+ }
3575
+ if (shouldDeactivateAfter) deactivateRenderer();
3576
+ else actions.unfreeze();
3577
+ };
3578
+ };
3579
+ const deferHideContextMenu = () => {
3580
+ setTimeout(() => {
3581
+ actions.hideContextMenu();
3582
+ }, 0);
3583
+ };
3584
+ const buildActionContext = (options) => {
3585
+ const { element, filePath, lineNumber, tagName, componentName, position, performWithFeedbackOptions, shouldDeferHideContextMenu, onBeforeCopy, onBeforePrompt, customEnterPromptMode } = options;
3586
+ const elements = store.frozenElements.length > 0 ? store.frozenElements : [element];
3587
+ const hideContextMenuAction = shouldDeferHideContextMenu ? deferHideContextMenu : actions.hideContextMenu;
3588
+ const copyAction = () => {
3589
+ onBeforeCopy?.();
3590
+ performCopyWithLabel({
3591
+ element,
3592
+ cursorX: position.x,
3593
+ selectedElements: elements.length > 1 ? elements : void 0,
3594
+ shouldDeactivateAfter: store.wasActivatedByToggle
3595
+ });
3596
+ hideContextMenuAction();
3597
+ };
3598
+ const defaultEnterPromptMode = () => {
3599
+ clearAllLabels();
3600
+ onBeforePrompt?.();
3601
+ preparePromptMode(element, position.x, position.y);
3602
+ actions.setPointer({
3603
+ x: position.x,
3604
+ y: position.y
3605
+ });
3606
+ actions.setFrozenElement(element);
3607
+ activatePromptMode();
3608
+ if (!isActivated()) activateRenderer();
3609
+ hideContextMenuAction();
3610
+ };
3611
+ const context = {
3612
+ element,
3613
+ elements,
3614
+ filePath,
3615
+ lineNumber,
3616
+ componentName,
3617
+ tagName,
3618
+ enterPromptMode: customEnterPromptMode ?? defaultEnterPromptMode,
3619
+ copy: copyAction,
3620
+ hooks: {
3621
+ transformHtmlContent: pluginRegistry.hooks.transformHtmlContent,
3622
+ onOpenFile: pluginRegistry.hooks.onOpenFile,
3623
+ transformOpenFileUrl: pluginRegistry.hooks.transformOpenFileUrl
3624
+ },
3625
+ performWithFeedback: createPerformWithFeedback(element, elements, tagName, componentName, performWithFeedbackOptions),
3626
+ hideContextMenu: hideContextMenuAction,
3627
+ cleanup: () => {
3628
+ if (store.wasActivatedByToggle) deactivateRenderer();
3629
+ else actions.unfreeze();
3630
+ }
3631
+ };
3632
+ const transformedContext = pluginRegistry.hooks.transformActionContext(context);
3633
+ return {
3634
+ ...context,
3635
+ ...transformedContext
3636
+ };
3637
+ };
3638
+ const contextMenuActionContext = createMemo(() => {
3639
+ const element = store.contextMenuElement;
3640
+ if (!element) return void 0;
3641
+ const fileInfo = contextMenuFilePath();
3642
+ const position = store.contextMenuPosition ?? store.pointer;
3643
+ return buildActionContext({
3644
+ element,
3645
+ filePath: fileInfo?.filePath,
3646
+ lineNumber: fileInfo?.lineNumber ?? void 0,
3647
+ tagName: contextMenuTagName(),
3648
+ componentName: contextMenuComponentName(),
3649
+ position,
3650
+ shouldDeferHideContextMenu: true,
3651
+ onBeforeCopy: () => {
3652
+ keyboardSelectedElement = null;
3653
+ },
3654
+ customEnterPromptMode: () => {
3655
+ clearAllLabels();
3656
+ actions.clearInputText();
3657
+ actions.enterPromptMode(position, element);
3658
+ deferHideContextMenu();
3659
+ }
3660
+ });
3661
+ });
3662
+ const handleContextMenuDismiss = () => {
3663
+ setTimeout(() => {
3664
+ actions.hideContextMenu();
3665
+ deactivateRenderer();
3666
+ }, 0);
3667
+ };
3668
+ const clearCommentsHoverPreviews = () => {
3669
+ for (const { boxId, labelId } of commentsHoverPreviews) {
3670
+ actions.removeGrabbedBox(boxId);
3671
+ if (labelId) actions.removeLabelInstance(labelId);
3672
+ }
3673
+ commentsHoverPreviews = [];
3674
+ };
3675
+ const addCommentItemPreview = (item, previewBounds, previewElements, idPrefix) => {
3676
+ if (previewBounds.length === 0) return;
3677
+ for (const [index, bounds] of previewBounds.entries()) {
3678
+ const previewElement = previewElements[index];
3679
+ const boxId = `${idPrefix}-${item.id}-${index}`;
3680
+ actions.addGrabbedBox({
3681
+ id: boxId,
3682
+ bounds,
3683
+ createdAt: 0,
3684
+ element: previewElement
3685
+ });
3686
+ let labelId = null;
3687
+ if (index === 0) {
3688
+ labelId = `${idPrefix}-label-${item.id}`;
3689
+ actions.addLabelInstance({
3690
+ id: labelId,
3691
+ bounds,
3692
+ tagName: item.tagName,
3693
+ componentName: item.componentName,
3694
+ elementsCount: item.elementsCount,
3695
+ status: "idle",
3696
+ isPromptMode: Boolean(item.commentText),
3697
+ inputValue: item.commentText ?? void 0,
3698
+ createdAt: 0,
3699
+ element: previewElement,
3700
+ mouseX: bounds.x + bounds.width / 2
3701
+ });
3702
+ }
3703
+ commentsHoverPreviews.push({
3704
+ boxId,
3705
+ labelId
3706
+ });
3707
+ }
3708
+ };
3709
+ const showCommentItemPreview = (item, idPrefix) => {
3710
+ const connectedElements = getConnectedCommentElements(item);
3711
+ addCommentItemPreview(item, connectedElements.map((element) => createElementBounds(element)), connectedElements, idPrefix);
3712
+ };
3713
+ const stopTrackingDropdownPosition = () => {
3714
+ if (dropdownTrackingFrameId !== null) {
3715
+ nativeCancelAnimationFrame(dropdownTrackingFrameId);
3716
+ dropdownTrackingFrameId = null;
3717
+ }
3718
+ };
3719
+ const startTrackingDropdownPosition = (computePosition) => {
3720
+ stopTrackingDropdownPosition();
3721
+ const updatePosition = () => {
3722
+ computePosition();
3723
+ dropdownTrackingFrameId = nativeRequestAnimationFrame(updatePosition);
3724
+ };
3725
+ updatePosition();
3726
+ };
3727
+ const computeDropdownAnchor = () => {
3728
+ if (!toolbarElement) return null;
3729
+ const toolbarRect = toolbarElement.getBoundingClientRect();
3730
+ const edge = getNearestEdge(toolbarRect);
3731
+ if (edge === "left" || edge === "right") return {
3732
+ x: edge === "left" ? toolbarRect.right : toolbarRect.left,
3733
+ y: toolbarRect.top + toolbarRect.height / 2,
3734
+ edge,
3735
+ toolbarWidth: toolbarRect.width
3736
+ };
3737
+ return {
3738
+ x: toolbarRect.left + toolbarRect.width / 2,
3739
+ y: edge === "top" ? toolbarRect.bottom : toolbarRect.top,
3740
+ edge,
3741
+ toolbarWidth: toolbarRect.width
3742
+ };
3743
+ };
3744
+ const openTrackedDropdown = (setPosition) => {
3745
+ startTrackingDropdownPosition(() => {
3746
+ const anchor = computeDropdownAnchor();
3747
+ if (anchor) setPosition(anchor);
3748
+ });
3749
+ };
3750
+ const dismissCommentsDropdown = () => {
3751
+ cancelCommentsHoverOpenTimeout();
3752
+ cancelCommentsHoverCloseTimeout();
3753
+ stopTrackingDropdownPosition();
3754
+ clearCommentsHoverPreviews();
3755
+ setCommentsDropdownPosition(null);
3756
+ setIsCommentsHoverOpen(false);
3757
+ };
3758
+ const dismissToolbarMenu = () => {
3759
+ stopTrackingDropdownPosition();
3760
+ setToolbarMenuPosition(null);
3761
+ };
3762
+ const openCommentsDropdown = () => {
3763
+ actions.hideContextMenu();
3764
+ dismissToolbarMenu();
3765
+ dismissClearPrompt();
3766
+ setCommentItems(loadComments());
3767
+ openTrackedDropdown(setCommentsDropdownPosition);
3768
+ };
3769
+ let commentsHoverOpenTimeoutId = null;
3770
+ let commentsHoverCloseTimeoutId = null;
3771
+ const cancelCommentsHoverOpenTimeout = () => {
3772
+ if (commentsHoverOpenTimeoutId !== null) {
3773
+ clearTimeout(commentsHoverOpenTimeoutId);
3774
+ commentsHoverOpenTimeoutId = null;
3775
+ }
3776
+ };
3777
+ const cancelCommentsHoverCloseTimeout = () => {
3778
+ if (commentsHoverCloseTimeoutId !== null) {
3779
+ clearTimeout(commentsHoverCloseTimeoutId);
3780
+ commentsHoverCloseTimeoutId = null;
3781
+ }
3782
+ };
3783
+ const scheduleCommentsHoverClose = () => {
3784
+ commentsHoverCloseTimeoutId = setTimeout(() => {
3785
+ commentsHoverCloseTimeoutId = null;
3786
+ dismissCommentsDropdown();
3787
+ }, 200);
3788
+ };
3789
+ const showClearPrompt = () => {
3790
+ dismissCommentsDropdown();
3791
+ dismissToolbarMenu();
3792
+ openTrackedDropdown(setClearPromptPosition);
3793
+ };
3794
+ const dismissClearPrompt = () => {
3795
+ stopTrackingDropdownPosition();
3796
+ setClearPromptPosition(null);
3797
+ };
3798
+ const dismissAllPopups = () => {
3799
+ dismissCommentsDropdown();
3800
+ dismissToolbarMenu();
3801
+ dismissClearPrompt();
3802
+ };
3803
+ const handleToggleToolbarMenu = () => {
3804
+ if (toolbarMenuPosition() !== null) dismissToolbarMenu();
3805
+ else {
3806
+ actions.hideContextMenu();
3807
+ dismissCommentsDropdown();
3808
+ dismissClearPrompt();
3809
+ openTrackedDropdown(setToolbarMenuPosition);
3810
+ }
3811
+ };
3812
+ const handleSetDefaultAction = (actionId) => {
3813
+ updateToolbarState({ defaultAction: actionId });
3814
+ };
3815
+ const handleToggleComments = () => {
3816
+ cancelCommentsHoverOpenTimeout();
3817
+ cancelCommentsHoverCloseTimeout();
3818
+ if (commentsDropdownPosition() !== null) if (isCommentsHoverOpen()) {
3819
+ clearCommentsHoverPreviews();
3820
+ setIsCommentsHoverOpen(false);
3821
+ } else dismissCommentsDropdown();
3822
+ else {
3823
+ clearCommentsHoverPreviews();
3824
+ openCommentsDropdown();
3825
+ }
3826
+ };
3827
+ const copyCommentItemContent = (item) => {
3828
+ copyContent(item.content, {
3829
+ tagName: item.tagName,
3830
+ componentName: item.componentName ?? item.elementName,
3831
+ commentText: item.commentText
3832
+ });
3833
+ const element = getFirstConnectedCommentElement(item);
3834
+ if (!element) return;
3835
+ clearAllLabels();
3836
+ nativeRequestAnimationFrame(() => {
3837
+ if (!isElementConnected(element)) return;
3838
+ const bounds = createElementBounds(element);
3839
+ const labelId = createLabelInstance(bounds, item.tagName, item.componentName, "copied", {
3840
+ element,
3841
+ mouseX: bounds.x + bounds.width / 2
3842
+ });
3843
+ if (labelId) scheduleLabelFade(labelId);
3844
+ });
3845
+ };
3846
+ const handleCommentItemSelect = (item) => {
3847
+ clearCommentsHoverPreviews();
3848
+ if (isPromptMode()) {
3849
+ actions.exitPromptMode();
3850
+ actions.clearInputText();
3851
+ }
3852
+ const element = getFirstConnectedCommentElement(item);
3853
+ if (item.commentText && element) {
3854
+ const { center } = getElementBoundsCenter(element);
3855
+ actions.enterPromptMode(center, element);
3856
+ actions.setInputText(item.commentText);
3857
+ } else copyCommentItemContent(item);
3858
+ };
3859
+ const handleCommentsCopyAll = () => {
3860
+ clearCommentsHoverPreviews();
3861
+ const currentCommentItems = commentItems();
3862
+ if (currentCommentItems.length === 0) return;
3863
+ const combinedContent = joinSnippets(currentCommentItems.map((commentItem) => commentItem.content));
3864
+ const firstItem = currentCommentItems[0];
3865
+ copyContent(combinedContent, {
3866
+ componentName: firstItem.componentName ?? firstItem.tagName,
3867
+ entries: currentCommentItems.map((commentItem) => ({
3868
+ tagName: commentItem.tagName,
3869
+ componentName: commentItem.componentName ?? commentItem.elementName,
3870
+ content: commentItem.content,
3871
+ commentText: commentItem.commentText
3872
+ }))
3873
+ });
3874
+ if (isClearConfirmed()) handleCommentsClear();
3875
+ else showClearPrompt();
3876
+ clearAllLabels();
3877
+ nativeRequestAnimationFrame(() => {
3878
+ batch(() => {
3879
+ for (const commentItem of currentCommentItems) {
3880
+ const connectedElements = getConnectedCommentElements(commentItem);
3881
+ for (const element of connectedElements) {
3882
+ const bounds = createElementBounds(element);
3883
+ const labelId = generateId("label");
3884
+ actions.addLabelInstance({
3885
+ id: labelId,
3886
+ bounds,
3887
+ tagName: commentItem.tagName,
3888
+ componentName: commentItem.componentName,
3889
+ status: "copied",
3890
+ createdAt: Date.now(),
3891
+ element,
3892
+ mouseX: bounds.x + bounds.width / 2
3893
+ });
3894
+ scheduleLabelFade(labelId);
3895
+ }
3896
+ }
3897
+ });
3898
+ });
3899
+ };
3900
+ const handleCommentItemHover = (commentItemId) => {
3901
+ clearCommentsHoverPreviews();
3902
+ if (!commentItemId) return;
3903
+ const item = commentItems().find((innerItem) => innerItem.id === commentItemId);
3904
+ if (!item) return;
3905
+ showCommentItemPreview(item, "comment-hover");
3906
+ };
3907
+ const handleCommentsButtonHover = (isHovered) => {
3908
+ cancelCommentsHoverOpenTimeout();
3909
+ clearCommentsHoverPreviews();
3910
+ if (isHovered) {
3911
+ cancelCommentsHoverCloseTimeout();
3912
+ if (commentsDropdownPosition() === null && clearPromptPosition() === null) {
3913
+ showAllCommentItemPreviews();
3914
+ commentsHoverOpenTimeoutId = setTimeout(() => {
3915
+ commentsHoverOpenTimeoutId = null;
3916
+ setIsCommentsHoverOpen(true);
3917
+ openCommentsDropdown();
3918
+ }, 200);
3919
+ }
3920
+ } else if (isCommentsHoverOpen()) scheduleCommentsHoverClose();
3921
+ };
3922
+ const handleCommentsDropdownHover = (isHovered) => {
3923
+ if (isHovered) cancelCommentsHoverCloseTimeout();
3924
+ else if (isCommentsHoverOpen()) scheduleCommentsHoverClose();
3925
+ };
3926
+ const handleCommentsCopyAllHover = (isHovered) => {
3927
+ clearCommentsHoverPreviews();
3928
+ if (isHovered) {
3929
+ cancelCommentsHoverCloseTimeout();
3930
+ showAllCommentItemPreviews();
3931
+ } else if (isCommentsHoverOpen()) scheduleCommentsHoverClose();
3932
+ };
3933
+ const showAllCommentItemPreviews = () => {
3934
+ for (const item of commentItems()) showCommentItemPreview(item, "comment-all-hover");
3935
+ };
3936
+ const handleCommentsClear = () => {
3937
+ commentElementMap.clear();
3938
+ setCommentItems(clearComments());
3939
+ dismissCommentsDropdown();
3940
+ };
3941
+ const handleShowContextMenuInstance = (instanceId) => {
3942
+ const instance = store.labelInstances.find((labelInstance) => labelInstance.id === instanceId);
3943
+ if (!instance?.element) return;
3944
+ if (!isElementConnected(instance.element)) return;
3945
+ const contextMenuElement = instance.element;
3946
+ const { center } = getElementBoundsCenter(contextMenuElement);
3947
+ const position = {
3948
+ x: instance.mouseX ?? center.x,
3949
+ y: center.y
3950
+ };
3951
+ const elementsToFreeze = instance.elements && instance.elements.length > 0 ? instance.elements.filter((element) => isElementConnected(element)) : [contextMenuElement];
3952
+ setTimeout(() => {
3953
+ if (!isActivated()) {
3954
+ actions.setWasActivatedByToggle(true);
3955
+ activateRenderer();
3956
+ }
3957
+ actions.setPointer(position);
3958
+ actions.setFrozenElements(elementsToFreeze);
3959
+ if (elementsToFreeze.length > 1 && instance.bounds) actions.setFrozenDragRect(createPageRectFromBounds(instance.bounds));
3960
+ actions.freeze();
3961
+ actions.showContextMenu(position, contextMenuElement);
3962
+ }, 0);
3963
+ };
3964
+ createEffect(() => {
3965
+ const hue = pluginRegistry.store.theme.hue;
3966
+ if (hue !== 0) rendererRoot.style.filter = `hue-rotate(${hue}deg)`;
3967
+ else rendererRoot.style.filter = "";
3968
+ });
3969
+ if (pluginRegistry.store.theme.enabled) import("./renderer-DtBv4wTu.js").then(({ ReactGrabRenderer }) => {
3970
+ if (disposed) return;
3971
+ disposeRenderer = render(() => {
3972
+ return createComponent(ReactGrabRenderer, {
3973
+ get selectionVisible() {
3974
+ return selectionVisible();
3975
+ },
3976
+ get selectionBounds() {
3977
+ return selectionBounds();
3978
+ },
3979
+ get selectionBoundsMultiple() {
3980
+ return selectionBoundsMultiple();
3981
+ },
3982
+ get selectionShouldSnap() {
3983
+ return store.frozenElements.length > 0 || dragPreviewBounds().length > 0;
3984
+ },
3985
+ get inspectVisible() {
3986
+ return memo(() => !!isInspectMode())() && inspectBounds().length > 0;
3987
+ },
3988
+ get inspectBounds() {
3989
+ return inspectBounds();
3990
+ },
3991
+ get selectionElementsCount() {
3992
+ return store.frozenElements.length;
3993
+ },
3994
+ get selectionFilePath() {
3995
+ return store.selectionFilePath ?? void 0;
3996
+ },
3997
+ get selectionLineNumber() {
3998
+ return store.selectionLineNumber ?? void 0;
3999
+ },
4000
+ get selectionTagName() {
4001
+ return selectionTagName();
4002
+ },
4003
+ get selectionComponentName() {
4004
+ return resolvedComponentName();
4005
+ },
4006
+ get selectionLabelVisible() {
4007
+ return selectionLabelVisible();
4008
+ },
4009
+ selectionLabelStatus: "idle",
4010
+ get selectionActionCycleState() {
4011
+ return actionCycleState();
4012
+ },
4013
+ get selectionArrowNavigationState() {
4014
+ return arrowNavigationState();
4015
+ },
4016
+ onArrowNavigationSelect: handleArrowNavigationSelect,
4017
+ get inspectNavigationState() {
4018
+ return inspectNavigationState();
4019
+ },
4020
+ onInspectSelect: handleInspectSelect,
4021
+ get labelInstances() {
4022
+ return computedLabelInstances();
4023
+ },
4024
+ get dragVisible() {
4025
+ return dragVisible();
4026
+ },
4027
+ get dragBounds() {
4028
+ return dragBounds();
4029
+ },
4030
+ get grabbedBoxes() {
4031
+ return computedGrabbedBoxes();
4032
+ },
4033
+ get mouseX() {
4034
+ return memo(() => store.frozenElements.length > 1)() ? void 0 : cursorPosition().x;
4035
+ },
4036
+ get isFrozen() {
4037
+ return isFrozenPhase() || isActivated() || isToolbarSelectHovered();
4038
+ },
4039
+ get inputValue() {
4040
+ return store.inputText;
4041
+ },
4042
+ get isPromptMode() {
4043
+ return isPromptMode();
4044
+ },
4045
+ onShowContextMenuInstance: handleShowContextMenuInstance,
4046
+ onLabelInstanceHoverChange: handleLabelInstanceHoverChange,
4047
+ get onInputChange() {
4048
+ return actions.setInputText;
4049
+ },
4050
+ onInputSubmit: () => void handleInputSubmit(),
4051
+ onToggleExpand: handleToggleExpand,
4052
+ get isPendingDismiss() {
4053
+ return isPendingDismiss();
4054
+ },
4055
+ get selectionLabelShakeCount() {
4056
+ return selectionLabelShakeCount();
4057
+ },
4058
+ onConfirmDismiss: handleConfirmDismiss,
4059
+ onCancelDismiss: handleCancelDismiss,
4060
+ get toolbarVisible() {
4061
+ return pluginRegistry.store.theme.toolbar.enabled;
4062
+ },
4063
+ get isActive() {
4064
+ return isActivated();
4065
+ },
4066
+ onToggleActive: handleToggleActive,
4067
+ get enabled() {
4068
+ return isEnabled();
4069
+ },
4070
+ onToggleEnabled: handleToggleEnabled,
4071
+ get shakeCount() {
4072
+ return toolbarShakeCount();
4073
+ },
4074
+ onToolbarStateChange: (state) => {
4075
+ setCurrentToolbarState(state);
4076
+ toolbarStateChangeCallbacks.forEach((callback) => callback(state));
4077
+ },
4078
+ onSubscribeToToolbarStateChanges: (callback) => {
4079
+ toolbarStateChangeCallbacks.add(callback);
4080
+ return () => {
4081
+ toolbarStateChangeCallbacks.delete(callback);
4082
+ };
4083
+ },
4084
+ onToolbarSelectHoverChange: setIsToolbarSelectHovered,
4085
+ onToolbarRef: (element) => {
4086
+ toolbarElement = element;
4087
+ },
4088
+ get contextMenuPosition() {
4089
+ return contextMenuPosition();
4090
+ },
4091
+ get contextMenuBounds() {
4092
+ return contextMenuBounds();
4093
+ },
4094
+ get contextMenuTagName() {
4095
+ return contextMenuTagName();
4096
+ },
4097
+ get contextMenuComponentName() {
4098
+ return contextMenuComponentName();
4099
+ },
4100
+ get contextMenuHasFilePath() {
4101
+ return Boolean(contextMenuFilePath()?.filePath);
4102
+ },
4103
+ get actions() {
4104
+ return pluginRegistry.store.actions;
4105
+ },
4106
+ get actionContext() {
4107
+ return contextMenuActionContext();
4108
+ },
4109
+ onContextMenuDismiss: handleContextMenuDismiss,
4110
+ onContextMenuHide: deferHideContextMenu,
4111
+ get commentItems() {
4112
+ return commentItems();
4113
+ },
4114
+ get commentsDisconnectedItemIds() {
4115
+ return commentsDisconnectedItemIds();
4116
+ },
4117
+ get commentItemCount() {
4118
+ return commentItems().length;
4119
+ },
4120
+ get clockFlashTrigger() {
4121
+ return clockFlashTrigger();
4122
+ },
4123
+ get commentsDropdownPosition() {
4124
+ return commentsDropdownPosition();
4125
+ },
4126
+ get isCommentsPinned() {
4127
+ return memo(() => commentsDropdownPosition() !== null)() && !isCommentsHoverOpen();
4128
+ },
4129
+ onToggleComments: handleToggleComments,
4130
+ onCopyAll: handleCommentsCopyAll,
4131
+ onCopyAllHover: handleCommentsCopyAllHover,
4132
+ onCommentsButtonHover: handleCommentsButtonHover,
4133
+ onCommentItemSelect: handleCommentItemSelect,
4134
+ onCommentItemHover: handleCommentItemHover,
4135
+ onCommentsCopyAll: handleCommentsCopyAll,
4136
+ onCommentsCopyAllHover: handleCommentsCopyAllHover,
4137
+ onCommentsClear: handleCommentsClear,
4138
+ onCommentsDismiss: dismissCommentsDropdown,
4139
+ onCommentsDropdownHover: handleCommentsDropdownHover,
4140
+ get toolbarMenuPosition() {
4141
+ return toolbarMenuPosition();
4142
+ },
4143
+ get toolbarMenuActions() {
4144
+ return pluginRegistry.store.actions.filter((action) => action.showInToolbarMenu === true);
4145
+ },
4146
+ get defaultActionId() {
4147
+ return currentToolbarState()?.defaultAction ?? "comment";
4148
+ },
4149
+ onSetDefaultAction: handleSetDefaultAction,
4150
+ onToggleToolbarMenu: handleToggleToolbarMenu,
4151
+ onToolbarMenuDismiss: dismissToolbarMenu,
4152
+ get clearPromptPosition() {
4153
+ return clearPromptPosition();
4154
+ },
4155
+ onClearCommentsConfirm: () => {
4156
+ confirmClear();
4157
+ dismissClearPrompt();
4158
+ handleCommentsClear();
4159
+ },
4160
+ onClearCommentsCancel: dismissClearPrompt
4161
+ });
4162
+ }, rendererRoot);
4163
+ }).catch((error) => {
4164
+ console.warn("[react-grab] Failed to load renderer:", error);
4165
+ });
4166
+ const copyElementAPI = async (elements) => {
4167
+ const elementsArray = Array.isArray(elements) ? elements : [elements];
4168
+ if (elementsArray.length === 0) return false;
4169
+ return await copyWithFallback(elementsArray);
4170
+ };
4171
+ const api = {
4172
+ activate: () => {
4173
+ actions.setPendingCommentMode(false);
4174
+ if (!isActivated() && isEnabled()) toggleActivate();
4175
+ },
4176
+ deactivate: () => {
4177
+ if (isActivated() || isCopying()) deactivateRenderer();
4178
+ },
4179
+ toggle: () => {
4180
+ if (isActivated()) deactivateRenderer();
4181
+ else if (isEnabled()) toggleActivate();
4182
+ },
4183
+ comment: handleComment,
4184
+ isActive: () => isActivated(),
4185
+ isEnabled: () => isEnabled(),
4186
+ setEnabled: (enabled) => {
4187
+ if (enabled === isEnabled()) return;
4188
+ setIsEnabled(enabled);
4189
+ if (!enabled) forceDeactivateAll();
4190
+ },
4191
+ getToolbarState: () => loadToolbarState(),
4192
+ setToolbarState: (state) => {
4193
+ const currentState = loadToolbarState();
4194
+ const newState = {
4195
+ edge: state.edge ?? currentState?.edge ?? "bottom",
4196
+ ratio: state.ratio ?? currentState?.ratio ?? .5,
4197
+ collapsed: state.collapsed ?? currentState?.collapsed ?? false,
4198
+ enabled: state.enabled ?? currentState?.enabled ?? true,
4199
+ defaultAction: state.defaultAction ?? currentState?.defaultAction ?? "comment"
4200
+ };
4201
+ saveToolbarState(newState);
4202
+ setCurrentToolbarState(newState);
4203
+ if (state.enabled !== void 0 && state.enabled !== isEnabled()) setIsEnabled(state.enabled);
4204
+ toolbarStateChangeCallbacks.forEach((callback) => callback(newState));
4205
+ },
4206
+ onToolbarStateChange: (callback) => {
4207
+ toolbarStateChangeCallbacks.add(callback);
4208
+ return () => {
4209
+ toolbarStateChangeCallbacks.delete(callback);
4210
+ };
4211
+ },
4212
+ dispose: () => {
4213
+ disposed = true;
4214
+ hasInited = false;
4215
+ disposeRenderer?.();
4216
+ cancelCommentsHoverOpenTimeout();
4217
+ cancelCommentsHoverCloseTimeout();
4218
+ stopTrackingDropdownPosition();
4219
+ toolbarStateChangeCallbacks.clear();
4220
+ dispose();
4221
+ },
4222
+ copyElement: copyElementAPI,
4223
+ getSource: async (element) => {
4224
+ const source = await resolveSource(element);
4225
+ if (!source) return null;
4226
+ return {
4227
+ filePath: source.filePath,
4228
+ lineNumber: source.lineNumber,
4229
+ componentName: source.componentName
4230
+ };
4231
+ },
4232
+ getStackContext,
4233
+ getState: () => ({
4234
+ isActive: isActivated(),
4235
+ isDragging: isDragging(),
4236
+ isCopying: isCopying(),
4237
+ isPromptMode: isPromptMode(),
4238
+ isSelectionBoxVisible: Boolean(selectionVisible()),
4239
+ isDragBoxVisible: Boolean(dragVisible()),
4240
+ targetElement: targetElement(),
4241
+ dragBounds: dragBounds() ?? null,
4242
+ grabbedBoxes: [...publicGrabbedBoxes()],
4243
+ labelInstances: [...publicLabelInstances()],
4244
+ selectionFilePath: store.selectionFilePath,
4245
+ toolbarState: currentToolbarState()
4246
+ }),
4247
+ setOptions: (newOptions) => {
4248
+ pluginRegistry.setOptions(newOptions);
4249
+ },
4250
+ registerPlugin: (plugin) => {
4251
+ pluginRegistry.register(plugin, api);
4252
+ },
4253
+ unregisterPlugin: (name) => {
4254
+ pluginRegistry.unregister(name);
4255
+ },
4256
+ getPlugins: () => pluginRegistry.getPluginNames(),
4257
+ getDisplayName: getComponentDisplayName
4258
+ };
4259
+ for (const plugin of builtInPlugins) pluginRegistry.register(plugin, api);
4260
+ setTimeout(() => {
4261
+ checkIsNextProject(true);
4262
+ }, NEXTJS_REVALIDATION_DELAY_MS);
4263
+ return api;
4264
+ });
4265
+ };
4266
+
4267
+ //#endregion
4268
+ export { generateSnippet as a, DEFAULT_THEME as i, openPlugin as n, copyContent as o, commentPlugin as r, init as t };