@sonordev/site-kit 5.7.0 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (604) hide show
  1. package/README.md +3 -3
  2. package/agent-manifest.json +14 -2
  3. package/dist/AnalyticsProvider-OCXRNIVE.js +33 -0
  4. package/dist/{AnalyticsProvider-GJFG7YXA.js.map → AnalyticsProvider-OCXRNIVE.js.map} +1 -1
  5. package/dist/AnalyticsProvider-ZAUONQCX.mjs +12 -0
  6. package/dist/{AnalyticsProvider-EWF7JN2X.mjs.map → AnalyticsProvider-ZAUONQCX.mjs.map} +1 -1
  7. package/dist/{BlogViewTracker-2D3IJPJK.js → BlogViewTracker-HK5C7PU6.js} +14 -11
  8. package/dist/BlogViewTracker-HK5C7PU6.js.map +1 -0
  9. package/dist/{BlogViewTracker-CKYG6MYU.mjs → BlogViewTracker-KXRZHN3U.mjs} +13 -10
  10. package/dist/BlogViewTracker-KXRZHN3U.mjs.map +1 -0
  11. package/dist/ChatWidget-3OW5LY37.js +24 -0
  12. package/dist/{ChatWidget-AWP6GBVW.js.map → ChatWidget-3OW5LY37.js.map} +1 -1
  13. package/dist/ChatWidget-54GVS27I.mjs +15 -0
  14. package/dist/{ChatWidget-Z5QXDZP3.mjs.map → ChatWidget-54GVS27I.mjs.map} +1 -1
  15. package/dist/EngageWidget-7EUP76WE.mjs +12 -0
  16. package/dist/{EngageWidget-BKEY5TPO.mjs.map → EngageWidget-7EUP76WE.mjs.map} +1 -1
  17. package/dist/EngageWidget-DDP5UFA4.js +21 -0
  18. package/dist/{EngageWidget-VT4DYXVO.js.map → EngageWidget-DDP5UFA4.js.map} +1 -1
  19. package/dist/{FileField-JJN5QKDL.mjs → FileField-IQLN6E3C.mjs} +5 -5
  20. package/dist/{FileField-JJN5QKDL.mjs.map → FileField-IQLN6E3C.mjs.map} +1 -1
  21. package/dist/{FileField-62ZWZMQK.js → FileField-SBPL4JHP.js} +6 -6
  22. package/dist/{FileField-62ZWZMQK.js.map → FileField-SBPL4JHP.js.map} +1 -1
  23. package/dist/{FormSpotlight-OTFB6QM5.mjs → FormSpotlight-E2LKKHGV.mjs} +11 -7
  24. package/dist/FormSpotlight-E2LKKHGV.mjs.map +1 -0
  25. package/dist/{FormSpotlight-URS4XRS7.js → FormSpotlight-YTACNE57.js} +25 -21
  26. package/dist/FormSpotlight-YTACNE57.js.map +1 -0
  27. package/dist/{FormStage-FVKMIV73.js → FormStage-S277U2CP.js} +20 -15
  28. package/dist/FormStage-S277U2CP.js.map +1 -0
  29. package/dist/{FormStage-VPGOCMAV.mjs → FormStage-YSBN5XKL.mjs} +9 -4
  30. package/dist/FormStage-YSBN5XKL.mjs.map +1 -0
  31. package/dist/ManagedForm-I3QVRQ53.mjs +16 -0
  32. package/dist/{ManagedForm-CXVDJMHN.mjs.map → ManagedForm-I3QVRQ53.mjs.map} +1 -1
  33. package/dist/ManagedForm-TSYKQFLJ.js +25 -0
  34. package/dist/{ManagedForm-FGNTDGED.js.map → ManagedForm-TSYKQFLJ.js.map} +1 -1
  35. package/dist/{ManagedNewsletterForm-SQYB4BZU.mjs → ManagedNewsletterForm-T3YRAWKZ.mjs} +9 -7
  36. package/dist/ManagedNewsletterForm-T3YRAWKZ.mjs.map +1 -0
  37. package/dist/{ManagedNewsletterForm-3O5L44AZ.js → ManagedNewsletterForm-YSOPPKS6.js} +10 -8
  38. package/dist/ManagedNewsletterForm-YSOPPKS6.js.map +1 -0
  39. package/dist/{SignalCore-M2PKKIGH.mjs → SignalCore-PPSIQ4BW.mjs} +8 -14
  40. package/dist/SignalCore-PPSIQ4BW.mjs.map +1 -0
  41. package/dist/{SignalCore-RFBOBNLQ.js → SignalCore-SUZH3XWZ.js} +14 -20
  42. package/dist/SignalCore-SUZH3XWZ.js.map +1 -0
  43. package/dist/SitemapSync-HSHCOKCL.mjs +9 -0
  44. package/dist/{SitemapSync-4OVMIIGC.mjs.map → SitemapSync-HSHCOKCL.mjs.map} +1 -1
  45. package/dist/SitemapSync-LH6UVP4P.js +18 -0
  46. package/dist/{SitemapSync-RK3SQ4M2.js.map → SitemapSync-LH6UVP4P.js.map} +1 -1
  47. package/dist/analytics/AnalyticsProvider.d.ts.map +1 -1
  48. package/dist/analytics/index.js +10 -9
  49. package/dist/analytics/index.mjs +5 -4
  50. package/dist/blog/BlogLayout.d.ts +3 -1
  51. package/dist/blog/BlogLayout.d.ts.map +1 -1
  52. package/dist/blog/BlogList.d.ts +7 -1
  53. package/dist/blog/BlogList.d.ts.map +1 -1
  54. package/dist/blog/BlogPost.d.ts +20 -1
  55. package/dist/blog/BlogPost.d.ts.map +1 -1
  56. package/dist/blog/BlogSidebar.d.ts +3 -1
  57. package/dist/blog/BlogSidebar.d.ts.map +1 -1
  58. package/dist/blog/BlogViewTracker.d.ts +8 -2
  59. package/dist/blog/BlogViewTracker.d.ts.map +1 -1
  60. package/dist/blog/ClusterLandingPage.d.ts +3 -1
  61. package/dist/blog/ClusterLandingPage.d.ts.map +1 -1
  62. package/dist/blog/ClusterNavigation.d.ts +5 -2
  63. package/dist/blog/ClusterNavigation.d.ts.map +1 -1
  64. package/dist/blog/RelatedPosts.d.ts +3 -1
  65. package/dist/blog/RelatedPosts.d.ts.map +1 -1
  66. package/dist/blog/index.d.ts +1 -1
  67. package/dist/blog/index.d.ts.map +1 -1
  68. package/dist/blog/index.js +40 -31
  69. package/dist/blog/index.js.map +1 -1
  70. package/dist/blog/index.mjs +11 -6
  71. package/dist/blog/index.mjs.map +1 -1
  72. package/dist/blog/not-found.test.d.ts +2 -0
  73. package/dist/blog/not-found.test.d.ts.map +1 -0
  74. package/dist/blog/processBlogHtml.d.ts +19 -2
  75. package/dist/blog/processBlogHtml.d.ts.map +1 -1
  76. package/dist/blog/public-reads.d.ts +27 -0
  77. package/dist/blog/public-reads.d.ts.map +1 -0
  78. package/dist/blog/server-core.d.ts +76 -10
  79. package/dist/blog/server-core.d.ts.map +1 -1
  80. package/dist/blog/server-ui.js +29 -23
  81. package/dist/blog/server-ui.js.map +1 -1
  82. package/dist/blog/server-ui.mjs +12 -6
  83. package/dist/blog/server-ui.mjs.map +1 -1
  84. package/dist/blog/server.d.ts +76 -10
  85. package/dist/blog/server.d.ts.map +1 -1
  86. package/dist/blog/server.js +54 -47
  87. package/dist/blog/server.mjs +5 -2
  88. package/dist/blog/site-scope.test.d.ts +2 -0
  89. package/dist/blog/site-scope.test.d.ts.map +1 -0
  90. package/dist/brand/extract-brand-profile.d.ts +36 -2
  91. package/dist/brand/extract-brand-profile.d.ts.map +1 -1
  92. package/dist/brand/extract-brand-profile.test.d.ts +2 -0
  93. package/dist/brand/extract-brand-profile.test.d.ts.map +1 -0
  94. package/dist/{chunk-3YQILJKJ.js → chunk-2FQG2AHJ.js} +60 -35
  95. package/dist/chunk-2FQG2AHJ.js.map +1 -0
  96. package/dist/{chunk-D553G64G.js → chunk-2OQWLXDO.js} +13 -13
  97. package/dist/{chunk-D553G64G.js.map → chunk-2OQWLXDO.js.map} +1 -1
  98. package/dist/{chunk-OYOO2OO5.js → chunk-2SCDUVFJ.js} +10 -10
  99. package/dist/{chunk-OYOO2OO5.js.map → chunk-2SCDUVFJ.js.map} +1 -1
  100. package/dist/{chunk-3S5JN6KL.js → chunk-35ERUUH3.js} +6 -6
  101. package/dist/{chunk-3S5JN6KL.js.map → chunk-35ERUUH3.js.map} +1 -1
  102. package/dist/{chunk-57AFHENV.mjs → chunk-3AUFD7KR.mjs} +3 -3
  103. package/dist/{chunk-57AFHENV.mjs.map → chunk-3AUFD7KR.mjs.map} +1 -1
  104. package/dist/{chunk-L7ACQ6PC.js → chunk-3BVCF4ZF.js} +4 -4
  105. package/dist/{chunk-L7ACQ6PC.js.map → chunk-3BVCF4ZF.js.map} +1 -1
  106. package/dist/{chunk-BFJOZ3MU.mjs → chunk-3EY5E35M.mjs} +36 -71
  107. package/dist/chunk-3EY5E35M.mjs.map +1 -0
  108. package/dist/{chunk-BQGEVMIR.mjs → chunk-3SLFT453.mjs} +5 -5
  109. package/dist/{chunk-BQGEVMIR.mjs.map → chunk-3SLFT453.mjs.map} +1 -1
  110. package/dist/{chunk-ILNCUSXW.mjs → chunk-4L7OHRWB.mjs} +12 -9
  111. package/dist/chunk-4L7OHRWB.mjs.map +1 -0
  112. package/dist/chunk-4LYW6PMU.mjs +72 -0
  113. package/dist/chunk-4LYW6PMU.mjs.map +1 -0
  114. package/dist/{chunk-TSZIACRC.js → chunk-4OS6M3V4.js} +6 -12
  115. package/dist/chunk-4OS6M3V4.js.map +1 -0
  116. package/dist/{chunk-YKUEFRZI.js → chunk-4RY7JETY.js} +14 -14
  117. package/dist/{chunk-YKUEFRZI.js.map → chunk-4RY7JETY.js.map} +1 -1
  118. package/dist/chunk-4TLFZ6NR.mjs +16 -0
  119. package/dist/chunk-4TLFZ6NR.mjs.map +1 -0
  120. package/dist/{chunk-4B4S56WJ.mjs → chunk-5B4J3IBX.mjs} +75 -21
  121. package/dist/chunk-5B4J3IBX.mjs.map +1 -0
  122. package/dist/chunk-5O7JSWT6.js +8 -0
  123. package/dist/{chunk-5TXXTYXL.js.map → chunk-5O7JSWT6.js.map} +1 -1
  124. package/dist/chunk-5SANRSX3.mjs +17 -0
  125. package/dist/chunk-5SANRSX3.mjs.map +1 -0
  126. package/dist/{chunk-FBDHKYNF.mjs → chunk-5WGMXSCB.mjs} +3 -3
  127. package/dist/{chunk-FBDHKYNF.mjs.map → chunk-5WGMXSCB.mjs.map} +1 -1
  128. package/dist/chunk-5XFFUP6D.js +100 -0
  129. package/dist/chunk-5XFFUP6D.js.map +1 -0
  130. package/dist/{chunk-7ZX6TO6C.mjs → chunk-6HFFTGFP.mjs} +50 -26
  131. package/dist/chunk-6HFFTGFP.mjs.map +1 -0
  132. package/dist/{chunk-R2SXXFXZ.mjs → chunk-6SBTHS6C.mjs} +3 -3
  133. package/dist/{chunk-R2SXXFXZ.mjs.map → chunk-6SBTHS6C.mjs.map} +1 -1
  134. package/dist/{chunk-FO4KGPGF.js → chunk-7TC3GRXQ.js} +73 -38
  135. package/dist/chunk-7TC3GRXQ.js.map +1 -0
  136. package/dist/{chunk-XLPU3TEE.mjs → chunk-7THZOAUR.mjs} +4 -4
  137. package/dist/{chunk-XLPU3TEE.mjs.map → chunk-7THZOAUR.mjs.map} +1 -1
  138. package/dist/{chunk-MW2M6O7A.mjs → chunk-AOWJP25J.mjs} +4 -4
  139. package/dist/{chunk-MW2M6O7A.mjs.map → chunk-AOWJP25J.mjs.map} +1 -1
  140. package/dist/{chunk-UQ5YULFU.mjs → chunk-B2VFMPVJ.mjs} +4 -4
  141. package/dist/{chunk-UQ5YULFU.mjs.map → chunk-B2VFMPVJ.mjs.map} +1 -1
  142. package/dist/{chunk-JTF4DFUF.mjs → chunk-B35OJ7FR.mjs} +4 -4
  143. package/dist/{chunk-JTF4DFUF.mjs.map → chunk-B35OJ7FR.mjs.map} +1 -1
  144. package/dist/{chunk-2N27LCZH.js → chunk-BER36QXU.js} +9 -9
  145. package/dist/{chunk-2N27LCZH.js.map → chunk-BER36QXU.js.map} +1 -1
  146. package/dist/{chunk-47XQWV4S.mjs → chunk-BFZNLTWK.mjs} +3 -3
  147. package/dist/{chunk-47XQWV4S.mjs.map → chunk-BFZNLTWK.mjs.map} +1 -1
  148. package/dist/chunk-BQP6JIE2.mjs +28 -0
  149. package/dist/chunk-BQP6JIE2.mjs.map +1 -0
  150. package/dist/{chunk-KXGD4E7G.js → chunk-C3WU45JT.js} +7 -7
  151. package/dist/{chunk-KXGD4E7G.js.map → chunk-C3WU45JT.js.map} +1 -1
  152. package/dist/chunk-CUNZAD46.js +53 -0
  153. package/dist/chunk-CUNZAD46.js.map +1 -0
  154. package/dist/chunk-CXAXZFFW.js +157 -0
  155. package/dist/chunk-CXAXZFFW.js.map +1 -0
  156. package/dist/{chunk-H4OBGC43.mjs → chunk-DA7IANFG.mjs} +14 -3
  157. package/dist/chunk-DA7IANFG.mjs.map +1 -0
  158. package/dist/{chunk-NOU3JQJK.js → chunk-EIW6YEPY.js} +8 -8
  159. package/dist/{chunk-NOU3JQJK.js.map → chunk-EIW6YEPY.js.map} +1 -1
  160. package/dist/{chunk-RCSTDJUH.js → chunk-F6SKG34N.js} +8 -13
  161. package/dist/chunk-F6SKG34N.js.map +1 -0
  162. package/dist/{chunk-LC7AM4J5.js → chunk-FHPW7XVH.js} +77 -20
  163. package/dist/chunk-FHPW7XVH.js.map +1 -0
  164. package/dist/{chunk-JNRHTZL4.js → chunk-FVW6FT6L.js} +73 -29
  165. package/dist/chunk-FVW6FT6L.js.map +1 -0
  166. package/dist/{chunk-BFM5PEFV.js → chunk-GNDWTXLU.js} +56 -177
  167. package/dist/chunk-GNDWTXLU.js.map +1 -0
  168. package/dist/{chunk-OZ3FU4BT.js → chunk-H5NBFNND.js} +2 -2
  169. package/dist/chunk-H5NBFNND.js.map +1 -0
  170. package/dist/{chunk-RNAGCAIB.js → chunk-HAKD27AZ.js} +7 -7
  171. package/dist/{chunk-RNAGCAIB.js.map → chunk-HAKD27AZ.js.map} +1 -1
  172. package/dist/chunk-HCN3IKMW.mjs +106 -0
  173. package/dist/chunk-HCN3IKMW.mjs.map +1 -0
  174. package/dist/{chunk-V5THCFPG.mjs → chunk-HCX343AS.mjs} +4 -4
  175. package/dist/{chunk-V5THCFPG.mjs.map → chunk-HCX343AS.mjs.map} +1 -1
  176. package/dist/{chunk-TDJKGN5Q.mjs → chunk-HEOQT5SM.mjs} +216 -103
  177. package/dist/chunk-HEOQT5SM.mjs.map +1 -0
  178. package/dist/{chunk-6FC5Q4KU.mjs → chunk-HOJ4J4X2.mjs} +30 -12
  179. package/dist/chunk-HOJ4J4X2.mjs.map +1 -0
  180. package/dist/{chunk-ELQ4SRRR.js → chunk-HQOHB6QF.js} +15 -15
  181. package/dist/{chunk-ELQ4SRRR.js.map → chunk-HQOHB6QF.js.map} +1 -1
  182. package/dist/chunk-HRMGITUZ.mjs +6 -0
  183. package/dist/{chunk-QRBPT6Z6.mjs.map → chunk-HRMGITUZ.mjs.map} +1 -1
  184. package/dist/{chunk-JQ7M6CVL.mjs → chunk-HYVEIP2N.mjs} +3 -3
  185. package/dist/{chunk-JQ7M6CVL.mjs.map → chunk-HYVEIP2N.mjs.map} +1 -1
  186. package/dist/{chunk-H6YVT3BL.js → chunk-I3ND4XYW.js} +12 -9
  187. package/dist/chunk-I3ND4XYW.js.map +1 -0
  188. package/dist/{chunk-4UVM7E2W.js → chunk-JDTU2RWC.js} +3 -3
  189. package/dist/{chunk-4UVM7E2W.js.map → chunk-JDTU2RWC.js.map} +1 -1
  190. package/dist/{chunk-GZJE23Y5.mjs → chunk-JLVCWC6A.mjs} +2 -2
  191. package/dist/chunk-JLVCWC6A.mjs.map +1 -0
  192. package/dist/chunk-K4TCEAUX.js +52 -0
  193. package/dist/chunk-K4TCEAUX.js.map +1 -0
  194. package/dist/chunk-KV7XXLJV.mjs +30 -0
  195. package/dist/chunk-KV7XXLJV.mjs.map +1 -0
  196. package/dist/{chunk-C563AHZZ.mjs → chunk-L24RDT6Q.mjs} +3 -3
  197. package/dist/{chunk-C563AHZZ.mjs.map → chunk-L24RDT6Q.mjs.map} +1 -1
  198. package/dist/{chunk-FEWWGEQF.js → chunk-LBZGYF3B.js} +4 -4
  199. package/dist/{chunk-FEWWGEQF.js.map → chunk-LBZGYF3B.js.map} +1 -1
  200. package/dist/{chunk-CPY74A4F.js → chunk-LMEUYRRR.js} +72 -106
  201. package/dist/chunk-LMEUYRRR.js.map +1 -0
  202. package/dist/chunk-LVGSOW2F.js +32 -0
  203. package/dist/chunk-LVGSOW2F.js.map +1 -0
  204. package/dist/{chunk-DOB37PV4.js → chunk-M45AL7EA.js} +37 -19
  205. package/dist/chunk-M45AL7EA.js.map +1 -0
  206. package/dist/{chunk-YYDZ2TYR.js → chunk-MHX6TOAS.js} +3 -3
  207. package/dist/{chunk-YYDZ2TYR.js.map → chunk-MHX6TOAS.js.map} +1 -1
  208. package/dist/chunk-MLVHVKFT.mjs +148 -0
  209. package/dist/chunk-MLVHVKFT.mjs.map +1 -0
  210. package/dist/{chunk-M5GY2AI3.mjs → chunk-N2NZBPQ5.mjs} +4 -10
  211. package/dist/chunk-N2NZBPQ5.mjs.map +1 -0
  212. package/dist/chunk-NRBITVDK.js +114 -0
  213. package/dist/chunk-NRBITVDK.js.map +1 -0
  214. package/dist/{chunk-O2VJZOR2.mjs → chunk-O4YBWJHP.mjs} +6 -11
  215. package/dist/chunk-O4YBWJHP.mjs.map +1 -0
  216. package/dist/{chunk-BUJWXSYZ.mjs → chunk-O5ZSGBQD.mjs} +4 -4
  217. package/dist/{chunk-BUJWXSYZ.mjs.map → chunk-O5ZSGBQD.mjs.map} +1 -1
  218. package/dist/{chunk-TP7H6BSK.mjs → chunk-OE7CTIOU.mjs} +73 -30
  219. package/dist/chunk-OE7CTIOU.mjs.map +1 -0
  220. package/dist/{chunk-UJ6CHZAI.mjs → chunk-OEW2LFOV.js} +169 -25
  221. package/dist/chunk-OEW2LFOV.js.map +1 -0
  222. package/dist/chunk-P4Y75QSU.js +19 -0
  223. package/dist/chunk-P4Y75QSU.js.map +1 -0
  224. package/dist/{chunk-Q7347KP6.mjs → chunk-PK2OTGW5.mjs} +6 -12
  225. package/dist/chunk-PK2OTGW5.mjs.map +1 -0
  226. package/dist/{chunk-H65OX263.js → chunk-PRTXAIIC.js} +15 -15
  227. package/dist/{chunk-H65OX263.js.map → chunk-PRTXAIIC.js.map} +1 -1
  228. package/dist/{chunk-ABZGEHTC.mjs → chunk-PUAXHYBL.mjs} +3 -3
  229. package/dist/{chunk-ABZGEHTC.mjs.map → chunk-PUAXHYBL.mjs.map} +1 -1
  230. package/dist/chunk-QRHVMTHF.mjs +94 -0
  231. package/dist/chunk-QRHVMTHF.mjs.map +1 -0
  232. package/dist/{chunk-JTCQJKJE.js → chunk-QTJTDQYR.js} +76 -111
  233. package/dist/chunk-QTJTDQYR.js.map +1 -0
  234. package/dist/{chunk-HBN4A2N4.mjs → chunk-QVHVL7EX.mjs} +3 -3
  235. package/dist/{chunk-HBN4A2N4.mjs.map → chunk-QVHVL7EX.mjs.map} +1 -1
  236. package/dist/chunk-R7GHP3FY.js +81 -0
  237. package/dist/chunk-R7GHP3FY.js.map +1 -0
  238. package/dist/{chunk-P4TB4ROG.js → chunk-SEP5D4MI.js} +8 -2
  239. package/dist/chunk-SEP5D4MI.js.map +1 -0
  240. package/dist/{chunk-3CLP35TT.mjs → chunk-TXMVU4EY.mjs} +62 -97
  241. package/dist/chunk-TXMVU4EY.mjs.map +1 -0
  242. package/dist/{chunk-L4V6TKMJ.mjs → chunk-U2V542EO.mjs} +7 -3
  243. package/dist/chunk-U2V542EO.mjs.map +1 -0
  244. package/dist/{chunk-4WBTM6YE.js → chunk-UWHCHYCX.js} +4 -4
  245. package/dist/{chunk-4WBTM6YE.js.map → chunk-UWHCHYCX.js.map} +1 -1
  246. package/dist/{chunk-JNAXDFC4.mjs → chunk-VJ74275U.mjs} +38 -156
  247. package/dist/chunk-VJ74275U.mjs.map +1 -0
  248. package/dist/{chunk-H7274TKR.mjs → chunk-VJV7WUR2.mjs} +12 -4
  249. package/dist/chunk-VJV7WUR2.mjs.map +1 -0
  250. package/dist/{chunk-4A5V73SR.mjs → chunk-VYL6IHJA.mjs} +9 -9
  251. package/dist/{chunk-4A5V73SR.mjs.map → chunk-VYL6IHJA.mjs.map} +1 -1
  252. package/dist/{chunk-5B4FABFK.js → chunk-WS7MH3GD.js} +14 -2
  253. package/dist/chunk-WS7MH3GD.js.map +1 -0
  254. package/dist/{chunk-IPV2TUAT.js → chunk-XA2GJFVM.js} +12 -4
  255. package/dist/chunk-XA2GJFVM.js.map +1 -0
  256. package/dist/chunk-XBX2K3GA.js +33 -0
  257. package/dist/chunk-XBX2K3GA.js.map +1 -0
  258. package/dist/{chunk-F3AKYZOH.js → chunk-XCYKM2SA.js} +6 -13
  259. package/dist/chunk-XCYKM2SA.js.map +1 -0
  260. package/dist/{chunk-6CJP7BFM.js → chunk-XZO5I4RS.mjs} +147 -20
  261. package/dist/chunk-XZO5I4RS.mjs.map +1 -0
  262. package/dist/chunk-Y5QZPUL3.mjs +47 -0
  263. package/dist/chunk-Y5QZPUL3.mjs.map +1 -0
  264. package/dist/{chunk-C4PZ2R3B.js → chunk-YECDJDDD.js} +10 -10
  265. package/dist/{chunk-C4PZ2R3B.js.map → chunk-YECDJDDD.js.map} +1 -1
  266. package/dist/chunk-YN7QHLWF.js +19 -0
  267. package/dist/chunk-YN7QHLWF.js.map +1 -0
  268. package/dist/chunk-YU7QZ3PP.mjs +45 -0
  269. package/dist/chunk-YU7QZ3PP.mjs.map +1 -0
  270. package/dist/{chunk-VFGEY6FJ.js → chunk-ZEOC26LZ.js} +223 -110
  271. package/dist/chunk-ZEOC26LZ.js.map +1 -0
  272. package/dist/{chunk-RVRN5U7W.mjs → chunk-ZVI7MBVF.mjs} +73 -38
  273. package/dist/chunk-ZVI7MBVF.mjs.map +1 -0
  274. package/dist/cli/agent/checks.d.ts +15 -1
  275. package/dist/cli/agent/checks.d.ts.map +1 -1
  276. package/dist/cli/agent/sitemap-trailing-slash.test.d.ts +2 -0
  277. package/dist/cli/agent/sitemap-trailing-slash.test.d.ts.map +1 -0
  278. package/dist/cli/commands/doctor.d.ts.map +1 -1
  279. package/dist/cli/commands/og.d.ts +26 -8
  280. package/dist/cli/commands/og.d.ts.map +1 -1
  281. package/dist/cli/index.js +683 -322
  282. package/dist/cli/index.js.map +1 -1
  283. package/dist/cli/index.mjs +604 -243
  284. package/dist/cli/index.mjs.map +1 -1
  285. package/dist/client/index.js +6 -6
  286. package/dist/client/index.mjs +5 -5
  287. package/dist/commerce/CheckoutForm.d.ts.map +1 -1
  288. package/dist/commerce/ProductDetail.d.ts.map +1 -1
  289. package/dist/commerce/api.d.ts +14 -0
  290. package/dist/commerce/api.d.ts.map +1 -1
  291. package/dist/commerce/discount-checkout.test.d.ts +2 -0
  292. package/dist/commerce/discount-checkout.test.d.ts.map +1 -0
  293. package/dist/commerce/index.d.ts +1 -1
  294. package/dist/commerce/index.d.ts.map +1 -1
  295. package/dist/commerce/index.js +61 -56
  296. package/dist/commerce/index.mjs +6 -5
  297. package/dist/config/index.js +3 -3
  298. package/dist/config/index.mjs +1 -1
  299. package/dist/discover-CYXYKHZ2.mjs +4 -0
  300. package/dist/{discover-FGTKWOL3.mjs.map → discover-CYXYKHZ2.mjs.map} +1 -1
  301. package/dist/discover-NGEPXZOD.js +21 -0
  302. package/dist/{discover-NJZPWTDL.js.map → discover-NGEPXZOD.js.map} +1 -1
  303. package/dist/engage/index.js +12 -10
  304. package/dist/engage/index.js.map +1 -1
  305. package/dist/engage/index.mjs +9 -7
  306. package/dist/engage/index.mjs.map +1 -1
  307. package/dist/fleet/index.js +8 -8
  308. package/dist/fleet/index.mjs +4 -4
  309. package/dist/forms/FormClient.d.ts.map +1 -1
  310. package/dist/forms/FormField.d.ts +7 -1
  311. package/dist/forms/FormField.d.ts.map +1 -1
  312. package/dist/forms/FormSpotlight.d.ts +1 -1
  313. package/dist/forms/FormSpotlight.d.ts.map +1 -1
  314. package/dist/forms/FormStage.d.ts +1 -1
  315. package/dist/forms/FormStage.d.ts.map +1 -1
  316. package/dist/forms/experience-plan.d.ts +0 -1
  317. package/dist/forms/experience-plan.d.ts.map +1 -1
  318. package/dist/forms/field-interactions.d.ts +63 -0
  319. package/dist/forms/field-interactions.d.ts.map +1 -0
  320. package/dist/forms/field-interactions.test.d.ts +8 -0
  321. package/dist/forms/field-interactions.test.d.ts.map +1 -0
  322. package/dist/forms/field-rules.d.ts +41 -0
  323. package/dist/forms/field-rules.d.ts.map +1 -0
  324. package/dist/forms/field-rules.test.d.ts +8 -0
  325. package/dist/forms/field-rules.test.d.ts.map +1 -0
  326. package/dist/forms/form-field-focus.test.d.ts +8 -0
  327. package/dist/forms/form-field-focus.test.d.ts.map +1 -0
  328. package/dist/forms/index.js +25 -23
  329. package/dist/forms/index.js.map +1 -1
  330. package/dist/forms/index.mjs +13 -11
  331. package/dist/forms/index.mjs.map +1 -1
  332. package/dist/forms/server.js +11 -11
  333. package/dist/forms/server.mjs +9 -9
  334. package/dist/forms/static.js +8 -8
  335. package/dist/forms/static.mjs +7 -7
  336. package/dist/forms/tracking-session.d.ts +48 -3
  337. package/dist/forms/tracking-session.d.ts.map +1 -1
  338. package/dist/forms/types.d.ts +11 -0
  339. package/dist/forms/types.d.ts.map +1 -1
  340. package/dist/forms/useForm.d.ts +8 -0
  341. package/dist/forms/useForm.d.ts.map +1 -1
  342. package/dist/forms/useFormTracking.d.ts +29 -4
  343. package/dist/forms/useFormTracking.d.ts.map +1 -1
  344. package/dist/images/index.js +11 -11
  345. package/dist/images/index.mjs +4 -4
  346. package/dist/index.js +72 -68
  347. package/dist/index.js.map +1 -1
  348. package/dist/index.mjs +14 -10
  349. package/dist/index.mjs.map +1 -1
  350. package/dist/layout/client.js +10 -10
  351. package/dist/layout/client.mjs +9 -9
  352. package/dist/layout/index.js +13 -12
  353. package/dist/layout/index.js.map +1 -1
  354. package/dist/layout/index.mjs +11 -10
  355. package/dist/layout/index.mjs.map +1 -1
  356. package/dist/llms/aiRobots.d.ts +20 -4
  357. package/dist/llms/aiRobots.d.ts.map +1 -1
  358. package/dist/llms/api.d.ts +8 -3
  359. package/dist/llms/api.d.ts.map +1 -1
  360. package/dist/llms/discovery-headers.d.ts +24 -0
  361. package/dist/llms/discovery-headers.d.ts.map +1 -1
  362. package/dist/llms/generateLLMsTxt.d.ts.map +1 -1
  363. package/dist/llms/index.d.ts +2 -2
  364. package/dist/llms/index.d.ts.map +1 -1
  365. package/dist/llms/index.js +45 -96
  366. package/dist/llms/index.js.map +1 -1
  367. package/dist/llms/index.mjs +11 -81
  368. package/dist/llms/index.mjs.map +1 -1
  369. package/dist/llms/links.d.ts +26 -0
  370. package/dist/llms/links.d.ts.map +1 -0
  371. package/dist/llms/links.test.d.ts +2 -0
  372. package/dist/llms/links.test.d.ts.map +1 -0
  373. package/dist/llms/types.d.ts +15 -0
  374. package/dist/llms/types.d.ts.map +1 -1
  375. package/dist/llms/wiring.d.ts +22 -0
  376. package/dist/llms/wiring.d.ts.map +1 -1
  377. package/dist/llms/writeLLMsTxt.d.ts +9 -0
  378. package/dist/llms/writeLLMsTxt.d.ts.map +1 -1
  379. package/dist/maps/index.js +5 -5
  380. package/dist/maps/index.mjs +3 -3
  381. package/dist/motion/gsap.d.ts +54 -0
  382. package/dist/motion/gsap.d.ts.map +1 -1
  383. package/dist/motion/gsap.js +34 -4
  384. package/dist/motion/gsap.js.map +1 -1
  385. package/dist/motion/gsap.mjs +33 -5
  386. package/dist/motion/gsap.mjs.map +1 -1
  387. package/dist/motion/gsap.test.d.ts +2 -0
  388. package/dist/motion/gsap.test.d.ts.map +1 -0
  389. package/dist/og/config.d.ts +6 -0
  390. package/dist/og/config.d.ts.map +1 -1
  391. package/dist/og/contrast.d.ts +33 -0
  392. package/dist/og/contrast.d.ts.map +1 -0
  393. package/dist/og/index.d.ts +2 -0
  394. package/dist/og/index.d.ts.map +1 -1
  395. package/dist/og/index.js +26 -8
  396. package/dist/og/index.mjs +3 -1
  397. package/dist/og/pages.d.ts +101 -0
  398. package/dist/og/pages.d.ts.map +1 -1
  399. package/dist/og/route-copy.d.ts +34 -0
  400. package/dist/og/route-copy.d.ts.map +1 -0
  401. package/dist/og/route-fit.d.ts +77 -0
  402. package/dist/og/route-fit.d.ts.map +1 -0
  403. package/dist/og/route.d.ts +80 -20
  404. package/dist/og/route.d.ts.map +1 -1
  405. package/dist/og/route.js +195 -25
  406. package/dist/og/route.js.map +1 -1
  407. package/dist/og/route.mjs +193 -26
  408. package/dist/og/route.mjs.map +1 -1
  409. package/dist/og/route.test.d.ts +2 -0
  410. package/dist/og/route.test.d.ts.map +1 -0
  411. package/dist/og/template.d.ts.map +1 -1
  412. package/dist/og/wiring.d.ts +43 -3
  413. package/dist/og/wiring.d.ts.map +1 -1
  414. package/dist/proxy/index.d.ts.map +1 -1
  415. package/dist/proxy/index.js +15 -10
  416. package/dist/proxy/index.js.map +1 -1
  417. package/dist/proxy/index.mjs +12 -7
  418. package/dist/proxy/index.mjs.map +1 -1
  419. package/dist/proxy/llms-discovery.test.d.ts +2 -0
  420. package/dist/proxy/llms-discovery.test.d.ts.map +1 -0
  421. package/dist/redirects/index.d.ts +24 -0
  422. package/dist/redirects/index.d.ts.map +1 -1
  423. package/dist/redirects/index.js +11 -8
  424. package/dist/redirects/index.mjs +4 -1
  425. package/dist/redirects/index.test.d.ts +2 -0
  426. package/dist/redirects/index.test.d.ts.map +1 -0
  427. package/dist/redirects/not-found.js +8 -5
  428. package/dist/redirects/not-found.js.map +1 -1
  429. package/dist/redirects/not-found.mjs +4 -1
  430. package/dist/redirects/not-found.mjs.map +1 -1
  431. package/dist/robots/index.d.ts +2 -0
  432. package/dist/robots/index.d.ts.map +1 -1
  433. package/dist/robots/index.js +23 -3
  434. package/dist/robots/index.js.map +1 -1
  435. package/dist/robots/index.mjs +2 -2
  436. package/dist/robots/index.mjs.map +1 -1
  437. package/dist/search/index.js +4 -4
  438. package/dist/search/index.mjs +3 -3
  439. package/dist/seo/ManagedContent.d.ts +4 -2
  440. package/dist/seo/ManagedContent.d.ts.map +1 -1
  441. package/dist/seo/ManagedFAQ.d.ts.map +1 -1
  442. package/dist/seo/ManagedInternalLinks.d.ts.map +1 -1
  443. package/dist/seo/ManagedSchema.d.ts.map +1 -1
  444. package/dist/seo/client.js +6 -6
  445. package/dist/seo/client.mjs +5 -5
  446. package/dist/seo/getManagedMetadata.d.ts.map +1 -1
  447. package/dist/seo/getManagedMetadata.test.d.ts +2 -0
  448. package/dist/seo/getManagedMetadata.test.d.ts.map +1 -0
  449. package/dist/seo/index.js +59 -49
  450. package/dist/seo/index.js.map +1 -1
  451. package/dist/seo/index.mjs +29 -19
  452. package/dist/seo/index.mjs.map +1 -1
  453. package/dist/seo/managed-schema-filter.test.d.ts +2 -0
  454. package/dist/seo/managed-schema-filter.test.d.ts.map +1 -0
  455. package/dist/seo/register-sitemap-cli-impl.d.ts +32 -0
  456. package/dist/seo/register-sitemap-cli-impl.d.ts.map +1 -1
  457. package/dist/seo/register-sitemap-cli.d.ts +7 -0
  458. package/dist/seo/register-sitemap-cli.d.ts.map +1 -1
  459. package/dist/seo/register-sitemap-cli.js +273 -56
  460. package/dist/seo/register-sitemap-cli.js.map +1 -1
  461. package/dist/seo/register-sitemap-cli.mjs +269 -52
  462. package/dist/seo/register-sitemap-cli.mjs.map +1 -1
  463. package/dist/seo/register-sitemap-request.d.ts +36 -0
  464. package/dist/seo/register-sitemap-request.d.ts.map +1 -0
  465. package/dist/seo/register-sitemap-request.test.d.ts +2 -0
  466. package/dist/seo/register-sitemap-request.test.d.ts.map +1 -0
  467. package/dist/seo/routing.d.ts +2 -0
  468. package/dist/seo/routing.d.ts.map +1 -1
  469. package/dist/seo/schema-filter.d.ts +43 -0
  470. package/dist/seo/schema-filter.d.ts.map +1 -0
  471. package/dist/seo/schema-filter.test.d.ts +2 -0
  472. package/dist/seo/schema-filter.test.d.ts.map +1 -0
  473. package/dist/seo/server-api.d.ts +15 -2
  474. package/dist/seo/server-api.d.ts.map +1 -1
  475. package/dist/seo/server.js +23 -18
  476. package/dist/seo/server.mjs +7 -2
  477. package/dist/seo/site-scope.test.d.ts +2 -0
  478. package/dist/seo/site-scope.test.d.ts.map +1 -0
  479. package/dist/seo/types.d.ts +30 -0
  480. package/dist/seo/types.d.ts.map +1 -1
  481. package/dist/seo-meta/contract.d.ts +60 -0
  482. package/dist/seo-meta/contract.d.ts.map +1 -0
  483. package/dist/seo-meta/contract.js +41 -0
  484. package/dist/seo-meta/contract.js.map +1 -0
  485. package/dist/seo-meta/contract.mjs +4 -0
  486. package/dist/seo-meta/contract.mjs.map +1 -0
  487. package/dist/seo-meta/contract.test.d.ts +2 -0
  488. package/dist/seo-meta/contract.test.d.ts.map +1 -0
  489. package/dist/server/index.js +4 -3
  490. package/dist/server/index.mjs +3 -2
  491. package/dist/server/mint-site-token.d.ts +2 -32
  492. package/dist/server/mint-site-token.d.ts.map +1 -1
  493. package/dist/{server-api-RG3ZL3DV.mjs → server-api-A2EFCTZX.mjs} +7 -3
  494. package/dist/{server-api-RG3ZL3DV.mjs.map → server-api-A2EFCTZX.mjs.map} +1 -1
  495. package/dist/{server-api-RYJQAUGO.js → server-api-IWTZ7C3O.js} +25 -21
  496. package/dist/{server-api-RYJQAUGO.js.map → server-api-IWTZ7C3O.js.map} +1 -1
  497. package/dist/shared/build-entries.d.ts +2 -0
  498. package/dist/shared/build-entries.d.ts.map +1 -1
  499. package/dist/shared/fresh-fetch.d.ts +64 -0
  500. package/dist/shared/fresh-fetch.d.ts.map +1 -0
  501. package/dist/shared/fresh-fetch.test.d.ts +2 -0
  502. package/dist/shared/fresh-fetch.test.d.ts.map +1 -0
  503. package/dist/shared/next-files.d.ts +7 -0
  504. package/dist/shared/next-files.d.ts.map +1 -1
  505. package/dist/shared/page-leave.d.ts +27 -0
  506. package/dist/shared/page-leave.d.ts.map +1 -0
  507. package/dist/shared/page-leave.test.d.ts +2 -0
  508. package/dist/shared/page-leave.test.d.ts.map +1 -0
  509. package/dist/shared/source-graph.d.ts +63 -0
  510. package/dist/shared/source-graph.d.ts.map +1 -0
  511. package/dist/shared/source-graph.test.d.ts +2 -0
  512. package/dist/shared/source-graph.test.d.ts.map +1 -0
  513. package/dist/shared/version.d.ts +1 -1
  514. package/dist/signal/SignalCore.d.ts.map +1 -1
  515. package/dist/signal/index.js +11 -11
  516. package/dist/signal/index.mjs +2 -2
  517. package/dist/sitemap/index.d.ts +19 -4
  518. package/dist/sitemap/index.d.ts.map +1 -1
  519. package/dist/sitemap/index.js +53 -43
  520. package/dist/sitemap/index.js.map +1 -1
  521. package/dist/sitemap/index.mjs +37 -27
  522. package/dist/sitemap/index.mjs.map +1 -1
  523. package/dist/sitemap/shared.d.ts +65 -0
  524. package/dist/sitemap/shared.d.ts.map +1 -1
  525. package/dist/sitemap/trailing-slash.test.d.ts +2 -0
  526. package/dist/sitemap/trailing-slash.test.d.ts.map +1 -0
  527. package/dist/sites/resolve.d.ts.map +1 -1
  528. package/dist/sites/site-param.d.ts +16 -0
  529. package/dist/sites/site-param.d.ts.map +1 -0
  530. package/dist/sync/index.js +17 -17
  531. package/dist/sync/index.mjs +4 -4
  532. package/dist/writeLLMsTxt-CQ7A4AAL.js +20 -0
  533. package/dist/writeLLMsTxt-CQ7A4AAL.js.map +1 -0
  534. package/dist/writeLLMsTxt-NX5MSPYX.mjs +11 -0
  535. package/dist/writeLLMsTxt-NX5MSPYX.mjs.map +1 -0
  536. package/package.json +8 -3
  537. package/dist/AnalyticsProvider-EWF7JN2X.mjs +0 -11
  538. package/dist/AnalyticsProvider-GJFG7YXA.js +0 -32
  539. package/dist/BlogViewTracker-2D3IJPJK.js.map +0 -1
  540. package/dist/BlogViewTracker-CKYG6MYU.mjs.map +0 -1
  541. package/dist/ChatWidget-AWP6GBVW.js +0 -22
  542. package/dist/ChatWidget-Z5QXDZP3.mjs +0 -13
  543. package/dist/EngageWidget-BKEY5TPO.mjs +0 -12
  544. package/dist/EngageWidget-VT4DYXVO.js +0 -21
  545. package/dist/FormSpotlight-OTFB6QM5.mjs.map +0 -1
  546. package/dist/FormSpotlight-URS4XRS7.js.map +0 -1
  547. package/dist/FormStage-FVKMIV73.js.map +0 -1
  548. package/dist/FormStage-VPGOCMAV.mjs.map +0 -1
  549. package/dist/ManagedForm-CXVDJMHN.mjs +0 -14
  550. package/dist/ManagedForm-FGNTDGED.js +0 -23
  551. package/dist/ManagedNewsletterForm-3O5L44AZ.js.map +0 -1
  552. package/dist/ManagedNewsletterForm-SQYB4BZU.mjs.map +0 -1
  553. package/dist/SignalCore-M2PKKIGH.mjs.map +0 -1
  554. package/dist/SignalCore-RFBOBNLQ.js.map +0 -1
  555. package/dist/SitemapSync-4OVMIIGC.mjs +0 -9
  556. package/dist/SitemapSync-RK3SQ4M2.js +0 -18
  557. package/dist/chunk-3CLP35TT.mjs.map +0 -1
  558. package/dist/chunk-3UC6JETG.js +0 -32
  559. package/dist/chunk-3UC6JETG.js.map +0 -1
  560. package/dist/chunk-3YQILJKJ.js.map +0 -1
  561. package/dist/chunk-4B4S56WJ.mjs.map +0 -1
  562. package/dist/chunk-5B4FABFK.js.map +0 -1
  563. package/dist/chunk-5TXXTYXL.js +0 -8
  564. package/dist/chunk-6CJP7BFM.js.map +0 -1
  565. package/dist/chunk-6FC5Q4KU.mjs.map +0 -1
  566. package/dist/chunk-7ZX6TO6C.mjs.map +0 -1
  567. package/dist/chunk-AWK57R5S.mjs +0 -29
  568. package/dist/chunk-AWK57R5S.mjs.map +0 -1
  569. package/dist/chunk-BFJOZ3MU.mjs.map +0 -1
  570. package/dist/chunk-BFM5PEFV.js.map +0 -1
  571. package/dist/chunk-CPY74A4F.js.map +0 -1
  572. package/dist/chunk-DOB37PV4.js.map +0 -1
  573. package/dist/chunk-F3AKYZOH.js.map +0 -1
  574. package/dist/chunk-FO4KGPGF.js.map +0 -1
  575. package/dist/chunk-GZJE23Y5.mjs.map +0 -1
  576. package/dist/chunk-H4OBGC43.mjs.map +0 -1
  577. package/dist/chunk-H6YVT3BL.js.map +0 -1
  578. package/dist/chunk-H7274TKR.mjs.map +0 -1
  579. package/dist/chunk-ILNCUSXW.mjs.map +0 -1
  580. package/dist/chunk-IPV2TUAT.js.map +0 -1
  581. package/dist/chunk-JEOKDUPQ.js +0 -45
  582. package/dist/chunk-JEOKDUPQ.js.map +0 -1
  583. package/dist/chunk-JNAXDFC4.mjs.map +0 -1
  584. package/dist/chunk-JNRHTZL4.js.map +0 -1
  585. package/dist/chunk-JTCQJKJE.js.map +0 -1
  586. package/dist/chunk-L4V6TKMJ.mjs.map +0 -1
  587. package/dist/chunk-LC7AM4J5.js.map +0 -1
  588. package/dist/chunk-M5GY2AI3.mjs.map +0 -1
  589. package/dist/chunk-O2VJZOR2.mjs.map +0 -1
  590. package/dist/chunk-OZ3FU4BT.js.map +0 -1
  591. package/dist/chunk-P4TB4ROG.js.map +0 -1
  592. package/dist/chunk-Q7347KP6.mjs.map +0 -1
  593. package/dist/chunk-QJU6HBSK.mjs +0 -39
  594. package/dist/chunk-QJU6HBSK.mjs.map +0 -1
  595. package/dist/chunk-QRBPT6Z6.mjs +0 -6
  596. package/dist/chunk-RCSTDJUH.js.map +0 -1
  597. package/dist/chunk-RVRN5U7W.mjs.map +0 -1
  598. package/dist/chunk-TDJKGN5Q.mjs.map +0 -1
  599. package/dist/chunk-TP7H6BSK.mjs.map +0 -1
  600. package/dist/chunk-TSZIACRC.js.map +0 -1
  601. package/dist/chunk-UJ6CHZAI.mjs.map +0 -1
  602. package/dist/chunk-VFGEY6FJ.js.map +0 -1
  603. package/dist/discover-FGTKWOL3.mjs +0 -4
  604. package/dist/discover-NJZPWTDL.js +0 -21
@@ -1 +1 @@
1
- {"version":3,"file":"gsap.d.ts","sourceRoot":"","sources":["../../src/motion/gsap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAG9E,KAAK,UAAU,GAAG,cAAc,MAAM,CAAC,CAAA;AACvC,KAAK,mBAAmB,GAAG,cAAc,oBAAoB,CAAC,CAAA;AAE9D,MAAM,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AACrC,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAA;AAEtE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAA;IACV,aAAa,EAAE,mBAAmB,CAAA;CACnC;AAID;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC,CAU9C;AAED,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,wGAAwG;IACxG,EAAE,EAAE,WAAW,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,OAAO,CACrB,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAClC,KAAK,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EACrD,IAAI,GAAE,cAAmB,EACzB,OAAO,GAAE,cAAmB,GAC3B,IAAI,CAqCN;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,qBAA0B,GAClC;IAAE,UAAU,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;CAAE,CAiDlD"}
1
+ {"version":3,"file":"gsap.d.ts","sourceRoot":"","sources":["../../src/motion/gsap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,OAAO,EAAqB,KAAK,cAAc,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAG9E,KAAK,UAAU,GAAG,cAAc,MAAM,CAAC,CAAA;AACvC,KAAK,mBAAmB,GAAG,cAAc,oBAAoB,CAAC,CAAA;AAE9D,MAAM,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAA;AACrC,MAAM,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,eAAe,CAAC,CAAA;AAEtE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAA;IACV,aAAa,EAAE,mBAAmB,CAAA;CACnC;AAID;;;GAGG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAAC,UAAU,CAAC,CAU9C;AAED,iGAAiG;AACjG,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;AAEtE,KAAK,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;AAE9C,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,wGAAwG;IACxG,EAAE,EAAE,WAAW,CAAA;IACf;;;OAGG;IAEH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC5B;;;;;OAKG;IACH,OAAO,EAAE,WAAW,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2FAA2F;IAC3F,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAC9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAC5B;AAUD;;;GAGG;AAEH,wBAAsB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAgB/G;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,EAAE,EAAE,WAAW,EAEf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GACpD;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,CAMxD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,OAAO,CACrB,GAAG,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAClC,KAAK,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EACrD,IAAI,GAAE,cAAmB,EACzB,OAAO,GAAE,cAAmB,GAC3B,IAAI,CAyCN;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,qBAA0B,GAClC;IAAE,UAAU,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;CAAE,CAiDlD"}
@@ -17,9 +17,39 @@ function loadGsap() {
17
17
  }
18
18
  return pending;
19
19
  }
20
+ var pluginCache = /* @__PURE__ */ new Map();
21
+ function pickPlugin(mod, name) {
22
+ const m = mod;
23
+ return (m && (m[name] ?? m.default)) ?? mod;
24
+ }
25
+ async function loadGsapPlugins(gsap, loaders = {}) {
26
+ const entries = await Promise.all(
27
+ Object.entries(loaders).map(async ([name, load]) => {
28
+ let pending2 = pluginCache.get(name);
29
+ if (!pending2) {
30
+ pending2 = load().then((mod) => pickPlugin(mod, name));
31
+ pluginCache.set(name, pending2);
32
+ }
33
+ return [name, await pending2];
34
+ })
35
+ );
36
+ const plugins = Object.fromEntries(entries);
37
+ const list = Object.values(plugins);
38
+ if (list.length) gsap.registerPlugin(...list);
39
+ return plugins;
40
+ }
41
+ function runGsapSetup(bundle, el, plugins, setup) {
42
+ let cleanup = void 0;
43
+ const context = bundle.gsap.context((self) => {
44
+ cleanup = setup({ ...bundle, el, plugins, context: self });
45
+ }, el);
46
+ return { context, cleanup };
47
+ }
20
48
  function useGsap(ref, setup, deps = [], options = {}) {
21
49
  const setupRef = react.useRef(setup);
22
50
  setupRef.current = setup;
51
+ const pluginsRef = react.useRef(options.plugins);
52
+ pluginsRef.current = options.plugins;
23
53
  const { near = "200px 0px", reducedMotion = "skip" } = options;
24
54
  react.useEffect(() => {
25
55
  const el = ref.current;
@@ -32,11 +62,9 @@ function useGsap(ref, setup, deps = [], options = {}) {
32
62
  ([entry]) => {
33
63
  if (!entry?.isIntersecting) return;
34
64
  io.disconnect();
35
- loadGsap().then(({ gsap, ScrollTrigger }) => {
65
+ loadGsap().then(async (bundle) => ({ bundle, plugins: await loadGsapPlugins(bundle.gsap, pluginsRef.current) })).then(({ bundle, plugins }) => {
36
66
  if (cancelled || !el.isConnected) return;
37
- ctx = gsap.context(() => {
38
- cleanup = setupRef.current({ gsap, ScrollTrigger, el });
39
- }, el);
67
+ ({ context: ctx, cleanup } = runGsapSetup(bundle, el, plugins, setupRef.current));
40
68
  });
41
69
  },
42
70
  { rootMargin: near }
@@ -97,6 +125,8 @@ function useExpandCollapse(isOpen, options = {}) {
97
125
  }
98
126
 
99
127
  exports.loadGsap = loadGsap;
128
+ exports.loadGsapPlugins = loadGsapPlugins;
129
+ exports.runGsapSetup = runGsapSetup;
100
130
  exports.useExpandCollapse = useExpandCollapse;
101
131
  exports.useGsap = useGsap;
102
132
  //# sourceMappingURL=gsap.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/motion/gsap.ts"],"names":["useRef","useEffect","prefersReducedMotion"],"mappings":"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","file":"gsap.js","sourcesContent":["/**\n * @sonordev/site-kit/motion/gsap — the Upforge motion standard, tier 1.\n *\n * GSAP for the moments that earn it: sequenced timelines, SplitText,\n * Flip, MorphSVG. Requires the optional peer `gsap` (all plugins are free\n * since 3.13):\n *\n * npm i gsap\n *\n * A site that never imports this subpath never installs gsap. NOTHING\n * outside this file may import from 'gsap' — that is what keeps the tier\n * boundary real (src/motion/motion.test.tsx enforces it).\n *\n * Cost and where it goes: gsap core + ScrollTrigger is ~46KB gzipped.\n * `useGsap` loads it only when its element comes within 200px of the\n * viewport, so it never sits on the LCP critical path, and it must only be\n * used BELOW the fold. First-paint content renders static.\n *\n * Not included on purpose: ScrollSmoother. It drives scrolling by\n * transforming the page body, which fights native scroll, costs INP on\n * mobile, and breaks every scroll-geometry read on the page. The engine's\n * per-scene lerp gives the liquid feel without hijacking anything.\n */\n\n'use client'\n\nimport { useEffect, useRef, type DependencyList, type RefObject } from 'react'\nimport { prefersReducedMotion } from './engine'\n\ntype GsapModule = typeof import('gsap')\ntype ScrollTriggerModule = typeof import('gsap/ScrollTrigger')\n\nexport type Gsap = GsapModule['gsap']\nexport type ScrollTriggerStatic = ScrollTriggerModule['ScrollTrigger']\n\nexport interface GsapBundle {\n gsap: Gsap\n ScrollTrigger: ScrollTriggerStatic\n}\n\nlet pending: Promise<GsapBundle> | null = null\n\n/**\n * Load gsap + ScrollTrigger once, register the plugin, and share the\n * promise. Safe to call from anywhere; resolves the same bundle every time.\n */\nexport function loadGsap(): Promise<GsapBundle> {\n if (!pending) {\n pending = Promise.all([import('gsap'), import('gsap/ScrollTrigger')]).then(([g, st]) => {\n const gsap = g.gsap ?? g.default\n const ScrollTrigger = st.ScrollTrigger ?? st.default\n gsap.registerPlugin(ScrollTrigger)\n return { gsap, ScrollTrigger }\n })\n }\n return pending\n}\n\nexport interface GsapSetupContext extends GsapBundle {\n /** The element the hook is attached to — use it as the ScrollTrigger trigger and the selector scope. */\n el: HTMLElement\n}\n\nexport interface UseGsapOptions {\n /** Preload margin: load gsap when the element is this close. Default \"200px 0px\". */\n near?: string\n /** \"skip\" (default) does nothing under prefers-reduced-motion; \"run\" lets setup decide. */\n reducedMotion?: 'skip' | 'run'\n}\n\n/**\n * Run a GSAP setup against an element, lazily and safely:\n *\n * - gsap loads only when the element nears the viewport\n * - setup runs inside `gsap.context(el)`, so selectors are scoped and\n * everything it creates is reverted on unmount (including ScrollTriggers)\n * - the element must be server-rendered and visible; hide things inside\n * `setup` with `gsap.set`, never with a stylesheet\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null)\n * useGsap(ref, ({ gsap, el }) => {\n * gsap.from(el.querySelectorAll('[data-line]'), {\n * yPercent: 100, opacity: 0, stagger: 0.06, duration: 0.8, ease: 'power3.out',\n * scrollTrigger: { trigger: el, start: 'top 80%' },\n * })\n * })\n */\nexport function useGsap(\n ref: RefObject<HTMLElement | null>,\n setup: (ctx: GsapSetupContext) => void | (() => void),\n deps: DependencyList = [],\n options: UseGsapOptions = {},\n): void {\n const setupRef = useRef(setup)\n setupRef.current = setup\n const { near = '200px 0px', reducedMotion = 'skip' } = options\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n if (reducedMotion === 'skip' && prefersReducedMotion()) return\n\n let cancelled = false\n let cleanup: (() => void) | void\n let ctx: ReturnType<Gsap['context']> | undefined\n\n const io = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return\n io.disconnect()\n loadGsap().then(({ gsap, ScrollTrigger }) => {\n if (cancelled || !el.isConnected) return\n ctx = gsap.context(() => {\n cleanup = setupRef.current({ gsap, ScrollTrigger, el })\n }, el)\n })\n },\n { rootMargin: near },\n )\n io.observe(el)\n\n return () => {\n cancelled = true\n io.disconnect()\n if (typeof cleanup === 'function') cleanup()\n ctx?.revert()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ref, near, reducedMotion, ...deps])\n}\n\nexport interface ExpandCollapseOptions {\n duration?: number\n ease?: string\n}\n\n/**\n * Animate expand/collapse without mount/unmount. Content stays in the DOM\n * (so it stays indexable) with overflow hidden; gsap animates height and\n * opacity, and loads on the first toggle, not at mount.\n *\n * @example\n * const { contentRef } = useExpandCollapse(isOpen)\n * <div ref={contentRef}>{children}</div>\n */\nexport function useExpandCollapse(\n isOpen: boolean,\n options: ExpandCollapseOptions = {},\n): { contentRef: RefObject<HTMLDivElement | null> } {\n const { duration = 0.3, ease = 'power2.inOut' } = options\n const contentRef = useRef<HTMLDivElement>(null)\n const initialized = useRef(false)\n\n useEffect(() => {\n const el = contentRef.current\n if (!el) return\n\n // First render: set the resting state with inline styles, no gsap.\n if (!initialized.current) {\n initialized.current = true\n el.style.overflow = 'hidden'\n if (!isOpen) {\n el.style.height = '0px'\n el.style.opacity = '0'\n }\n return\n }\n\n let cancelled = false\n loadGsap().then(({ gsap }) => {\n if (cancelled || !el.isConnected) return\n if (prefersReducedMotion()) {\n gsap.set(el, { height: isOpen ? 'auto' : 0, opacity: isOpen ? 1 : 0 })\n el.style.overflow = isOpen ? 'visible' : 'hidden'\n return\n }\n if (isOpen) {\n gsap.to(el, {\n height: 'auto',\n opacity: 1,\n duration,\n ease,\n onComplete() {\n el.style.overflow = 'visible'\n },\n })\n } else {\n el.style.overflow = 'hidden'\n gsap.to(el, { height: 0, opacity: 0, duration: duration * 0.85, ease })\n }\n })\n return () => {\n cancelled = true\n }\n }, [isOpen, duration, ease])\n\n return { contentRef }\n}\n"]}
1
+ {"version":3,"sources":["../../src/motion/gsap.ts"],"names":["pending","useRef","useEffect","prefersReducedMotion"],"mappings":"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","file":"gsap.js","sourcesContent":["/**\n * @sonordev/site-kit/motion/gsap — the Upforge motion standard, tier 1.\n *\n * GSAP for the moments that earn it: sequenced timelines, SplitText,\n * Flip, MorphSVG. Requires the optional peer `gsap` (all plugins are free\n * since 3.13):\n *\n * npm i gsap\n *\n * A site that never imports this subpath never installs gsap. NOTHING\n * outside this file may import from 'gsap' — that is what keeps the tier\n * boundary real (src/motion/motion.test.tsx enforces it).\n *\n * Cost and where it goes: gsap core + ScrollTrigger is ~46KB gzipped.\n * `useGsap` loads it only when its element comes within 200px of the\n * viewport, so it never sits on the LCP critical path, and it must only be\n * used BELOW the fold. First-paint content renders static.\n *\n * Not included on purpose: ScrollSmoother. It drives scrolling by\n * transforming the page body, which fights native scroll, costs INP on\n * mobile, and breaks every scroll-geometry read on the page. The engine's\n * per-scene lerp gives the liquid feel without hijacking anything.\n */\n\n'use client'\n\nimport { useEffect, useRef, type DependencyList, type RefObject } from 'react'\nimport { prefersReducedMotion } from './engine'\n\ntype GsapModule = typeof import('gsap')\ntype ScrollTriggerModule = typeof import('gsap/ScrollTrigger')\n\nexport type Gsap = GsapModule['gsap']\nexport type ScrollTriggerStatic = ScrollTriggerModule['ScrollTrigger']\n\nexport interface GsapBundle {\n gsap: Gsap\n ScrollTrigger: ScrollTriggerStatic\n}\n\nlet pending: Promise<GsapBundle> | null = null\n\n/**\n * Load gsap + ScrollTrigger once, register the plugin, and share the\n * promise. Safe to call from anywhere; resolves the same bundle every time.\n */\nexport function loadGsap(): Promise<GsapBundle> {\n if (!pending) {\n pending = Promise.all([import('gsap'), import('gsap/ScrollTrigger')]).then(([g, st]) => {\n const gsap = g.gsap ?? g.default\n const ScrollTrigger = st.ScrollTrigger ?? st.default\n gsap.registerPlugin(ScrollTrigger)\n return { gsap, ScrollTrigger }\n })\n }\n return pending\n}\n\n/** Dynamic imports of GSAP plugins, by name: `{ SplitText: () => import('gsap/SplitText') }`. */\nexport type GsapPluginLoaders = Record<string, () => Promise<unknown>>\n\ntype GsapContext = ReturnType<Gsap['context']>\n\nexport interface GsapSetupContext extends GsapBundle {\n /** The element the hook is attached to — use it as the ScrollTrigger trigger and the selector scope. */\n el: HTMLElement\n /**\n * The plugins asked for in `options.plugins`, loaded and registered before\n * setup runs, by the same names: `plugins.SplitText`.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n plugins: Record<string, any>\n /**\n * The gsap.context setup runs in. Anything setup starts asynchronously\n * (after an await, in a timer, in a plugin callback that fires later)\n * lands outside it, so wrap that work in `context.add(() => ...)` to have\n * it scoped and reverted on unmount with the rest.\n */\n context: GsapContext\n}\n\nexport interface UseGsapOptions {\n /** Preload margin: load gsap when the element is this close. Default \"200px 0px\". */\n near?: string\n /** \"skip\" (default) does nothing under prefers-reduced-motion; \"run\" lets setup decide. */\n reducedMotion?: 'skip' | 'run'\n /**\n * GSAP plugins to load alongside gsap, as dynamic imports keyed by name:\n *\n * { plugins: { SplitText: () => import('gsap/SplitText') } }\n *\n * They're loaded when gsap is, registered, and handed to setup as\n * `plugins`, so setup can stay synchronous. That matters: gsap.context\n * only records what runs synchronously inside it, so a plugin imported\n * from within setup did its work outside the context, unscoped and never\n * reverted on unmount (vsf-consulting-nextjs's SplitHeading had to build a\n * second context of its own to clean up).\n */\n plugins?: GsapPluginLoaders\n}\n\nconst pluginCache = new Map<string, Promise<unknown>>()\n\n/** The plugin object out of its module: the named export, else the default. */\nfunction pickPlugin(mod: unknown, name: string): unknown {\n const m = mod as Record<string, unknown> | null\n return (m && (m[name] ?? m.default)) ?? mod\n}\n\n/**\n * Load plugins by name, once per name for the page, and register them with\n * gsap. Resolves to the plugins keyed by the same names.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function loadGsapPlugins(gsap: Gsap, loaders: GsapPluginLoaders = {}): Promise<Record<string, any>> {\n const entries = await Promise.all(\n Object.entries(loaders).map(async ([name, load]) => {\n let pending = pluginCache.get(name)\n if (!pending) {\n pending = load().then(mod => pickPlugin(mod, name))\n pluginCache.set(name, pending)\n }\n return [name, await pending] as const\n }),\n )\n const plugins = Object.fromEntries(entries)\n const list = Object.values(plugins)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (list.length) gsap.registerPlugin(...(list as any[]))\n return plugins\n}\n\n/**\n * Run a setup inside a gsap.context scoped to `el`, synchronously. Split out\n * of useGsap so the contract (everything setup creates belongs to the\n * returned context, plugins included) is testable without a DOM.\n */\nexport function runGsapSetup(\n bundle: GsapBundle,\n el: HTMLElement,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n plugins: Record<string, any>,\n setup: (ctx: GsapSetupContext) => void | (() => void),\n): { context: GsapContext; cleanup: (() => void) | void } {\n let cleanup: (() => void) | void = undefined\n const context = bundle.gsap.context((self: GsapContext) => {\n cleanup = setup({ ...bundle, el, plugins, context: self })\n }, el)\n return { context, cleanup }\n}\n\n/**\n * Run a GSAP setup against an element, lazily and safely:\n *\n * - gsap loads only when the element nears the viewport\n * - setup runs inside `gsap.context(el)`, so selectors are scoped and\n * everything it creates is reverted on unmount (including ScrollTriggers)\n * - plugins beyond ScrollTrigger (SplitText, Flip, MorphSVG) come in through\n * `options.plugins`, loaded before setup, so setup stays synchronous and\n * inside the context. Anything setup must still start later goes through\n * `context.add()`.\n * - the element must be server-rendered and visible; hide things inside\n * `setup` with `gsap.set`, never with a stylesheet\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null)\n * useGsap(ref, ({ gsap, el }) => {\n * gsap.from(el.querySelectorAll('[data-line]'), {\n * yPercent: 100, opacity: 0, stagger: 0.06, duration: 0.8, ease: 'power3.out',\n * scrollTrigger: { trigger: el, start: 'top 80%' },\n * })\n * })\n *\n * @example With a plugin\n * useGsap(ref, ({ gsap, el, plugins: { SplitText } }) => {\n * SplitText.create(el, {\n * type: 'lines', mask: 'lines', autoSplit: true,\n * onSplit: self => gsap.from(self.lines, { yPercent: 115, stagger: 0.09, scrollTrigger: { trigger: el } }),\n * })\n * }, [], { plugins: { SplitText: () => import('gsap/SplitText') } })\n */\nexport function useGsap(\n ref: RefObject<HTMLElement | null>,\n setup: (ctx: GsapSetupContext) => void | (() => void),\n deps: DependencyList = [],\n options: UseGsapOptions = {},\n): void {\n const setupRef = useRef(setup)\n setupRef.current = setup\n // A ref, like setup: an inline `plugins` object is new every render and\n // must not re-run the effect.\n const pluginsRef = useRef(options.plugins)\n pluginsRef.current = options.plugins\n const { near = '200px 0px', reducedMotion = 'skip' } = options\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n if (reducedMotion === 'skip' && prefersReducedMotion()) return\n\n let cancelled = false\n let cleanup: (() => void) | void\n let ctx: GsapContext | undefined\n\n const io = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return\n io.disconnect()\n loadGsap()\n .then(async bundle => ({ bundle, plugins: await loadGsapPlugins(bundle.gsap, pluginsRef.current) }))\n .then(({ bundle, plugins }) => {\n if (cancelled || !el.isConnected) return\n ;({ context: ctx, cleanup } = runGsapSetup(bundle, el, plugins, setupRef.current))\n })\n },\n { rootMargin: near },\n )\n io.observe(el)\n\n return () => {\n cancelled = true\n io.disconnect()\n if (typeof cleanup === 'function') cleanup()\n ctx?.revert()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ref, near, reducedMotion, ...deps])\n}\n\nexport interface ExpandCollapseOptions {\n duration?: number\n ease?: string\n}\n\n/**\n * Animate expand/collapse without mount/unmount. Content stays in the DOM\n * (so it stays indexable) with overflow hidden; gsap animates height and\n * opacity, and loads on the first toggle, not at mount.\n *\n * @example\n * const { contentRef } = useExpandCollapse(isOpen)\n * <div ref={contentRef}>{children}</div>\n */\nexport function useExpandCollapse(\n isOpen: boolean,\n options: ExpandCollapseOptions = {},\n): { contentRef: RefObject<HTMLDivElement | null> } {\n const { duration = 0.3, ease = 'power2.inOut' } = options\n const contentRef = useRef<HTMLDivElement>(null)\n const initialized = useRef(false)\n\n useEffect(() => {\n const el = contentRef.current\n if (!el) return\n\n // First render: set the resting state with inline styles, no gsap.\n if (!initialized.current) {\n initialized.current = true\n el.style.overflow = 'hidden'\n if (!isOpen) {\n el.style.height = '0px'\n el.style.opacity = '0'\n }\n return\n }\n\n let cancelled = false\n loadGsap().then(({ gsap }) => {\n if (cancelled || !el.isConnected) return\n if (prefersReducedMotion()) {\n gsap.set(el, { height: isOpen ? 'auto' : 0, opacity: isOpen ? 1 : 0 })\n el.style.overflow = isOpen ? 'visible' : 'hidden'\n return\n }\n if (isOpen) {\n gsap.to(el, {\n height: 'auto',\n opacity: 1,\n duration,\n ease,\n onComplete() {\n el.style.overflow = 'visible'\n },\n })\n } else {\n el.style.overflow = 'hidden'\n gsap.to(el, { height: 0, opacity: 0, duration: duration * 0.85, ease })\n }\n })\n return () => {\n cancelled = true\n }\n }, [isOpen, duration, ease])\n\n return { contentRef }\n}\n"]}
@@ -15,9 +15,39 @@ function loadGsap() {
15
15
  }
16
16
  return pending;
17
17
  }
18
+ var pluginCache = /* @__PURE__ */ new Map();
19
+ function pickPlugin(mod, name) {
20
+ const m = mod;
21
+ return (m && (m[name] ?? m.default)) ?? mod;
22
+ }
23
+ async function loadGsapPlugins(gsap, loaders = {}) {
24
+ const entries = await Promise.all(
25
+ Object.entries(loaders).map(async ([name, load]) => {
26
+ let pending2 = pluginCache.get(name);
27
+ if (!pending2) {
28
+ pending2 = load().then((mod) => pickPlugin(mod, name));
29
+ pluginCache.set(name, pending2);
30
+ }
31
+ return [name, await pending2];
32
+ })
33
+ );
34
+ const plugins = Object.fromEntries(entries);
35
+ const list = Object.values(plugins);
36
+ if (list.length) gsap.registerPlugin(...list);
37
+ return plugins;
38
+ }
39
+ function runGsapSetup(bundle, el, plugins, setup) {
40
+ let cleanup = void 0;
41
+ const context = bundle.gsap.context((self) => {
42
+ cleanup = setup({ ...bundle, el, plugins, context: self });
43
+ }, el);
44
+ return { context, cleanup };
45
+ }
18
46
  function useGsap(ref, setup, deps = [], options = {}) {
19
47
  const setupRef = useRef(setup);
20
48
  setupRef.current = setup;
49
+ const pluginsRef = useRef(options.plugins);
50
+ pluginsRef.current = options.plugins;
21
51
  const { near = "200px 0px", reducedMotion = "skip" } = options;
22
52
  useEffect(() => {
23
53
  const el = ref.current;
@@ -30,11 +60,9 @@ function useGsap(ref, setup, deps = [], options = {}) {
30
60
  ([entry]) => {
31
61
  if (!entry?.isIntersecting) return;
32
62
  io.disconnect();
33
- loadGsap().then(({ gsap, ScrollTrigger }) => {
63
+ loadGsap().then(async (bundle) => ({ bundle, plugins: await loadGsapPlugins(bundle.gsap, pluginsRef.current) })).then(({ bundle, plugins }) => {
34
64
  if (cancelled || !el.isConnected) return;
35
- ctx = gsap.context(() => {
36
- cleanup = setupRef.current({ gsap, ScrollTrigger, el });
37
- }, el);
65
+ ({ context: ctx, cleanup } = runGsapSetup(bundle, el, plugins, setupRef.current));
38
66
  });
39
67
  },
40
68
  { rootMargin: near }
@@ -94,6 +122,6 @@ function useExpandCollapse(isOpen, options = {}) {
94
122
  return { contentRef };
95
123
  }
96
124
 
97
- export { loadGsap, useExpandCollapse, useGsap };
125
+ export { loadGsap, loadGsapPlugins, runGsapSetup, useExpandCollapse, useGsap };
98
126
  //# sourceMappingURL=gsap.mjs.map
99
127
  //# sourceMappingURL=gsap.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/motion/gsap.ts"],"names":[],"mappings":"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","file":"gsap.mjs","sourcesContent":["/**\n * @sonordev/site-kit/motion/gsap — the Upforge motion standard, tier 1.\n *\n * GSAP for the moments that earn it: sequenced timelines, SplitText,\n * Flip, MorphSVG. Requires the optional peer `gsap` (all plugins are free\n * since 3.13):\n *\n * npm i gsap\n *\n * A site that never imports this subpath never installs gsap. NOTHING\n * outside this file may import from 'gsap' — that is what keeps the tier\n * boundary real (src/motion/motion.test.tsx enforces it).\n *\n * Cost and where it goes: gsap core + ScrollTrigger is ~46KB gzipped.\n * `useGsap` loads it only when its element comes within 200px of the\n * viewport, so it never sits on the LCP critical path, and it must only be\n * used BELOW the fold. First-paint content renders static.\n *\n * Not included on purpose: ScrollSmoother. It drives scrolling by\n * transforming the page body, which fights native scroll, costs INP on\n * mobile, and breaks every scroll-geometry read on the page. The engine's\n * per-scene lerp gives the liquid feel without hijacking anything.\n */\n\n'use client'\n\nimport { useEffect, useRef, type DependencyList, type RefObject } from 'react'\nimport { prefersReducedMotion } from './engine'\n\ntype GsapModule = typeof import('gsap')\ntype ScrollTriggerModule = typeof import('gsap/ScrollTrigger')\n\nexport type Gsap = GsapModule['gsap']\nexport type ScrollTriggerStatic = ScrollTriggerModule['ScrollTrigger']\n\nexport interface GsapBundle {\n gsap: Gsap\n ScrollTrigger: ScrollTriggerStatic\n}\n\nlet pending: Promise<GsapBundle> | null = null\n\n/**\n * Load gsap + ScrollTrigger once, register the plugin, and share the\n * promise. Safe to call from anywhere; resolves the same bundle every time.\n */\nexport function loadGsap(): Promise<GsapBundle> {\n if (!pending) {\n pending = Promise.all([import('gsap'), import('gsap/ScrollTrigger')]).then(([g, st]) => {\n const gsap = g.gsap ?? g.default\n const ScrollTrigger = st.ScrollTrigger ?? st.default\n gsap.registerPlugin(ScrollTrigger)\n return { gsap, ScrollTrigger }\n })\n }\n return pending\n}\n\nexport interface GsapSetupContext extends GsapBundle {\n /** The element the hook is attached to — use it as the ScrollTrigger trigger and the selector scope. */\n el: HTMLElement\n}\n\nexport interface UseGsapOptions {\n /** Preload margin: load gsap when the element is this close. Default \"200px 0px\". */\n near?: string\n /** \"skip\" (default) does nothing under prefers-reduced-motion; \"run\" lets setup decide. */\n reducedMotion?: 'skip' | 'run'\n}\n\n/**\n * Run a GSAP setup against an element, lazily and safely:\n *\n * - gsap loads only when the element nears the viewport\n * - setup runs inside `gsap.context(el)`, so selectors are scoped and\n * everything it creates is reverted on unmount (including ScrollTriggers)\n * - the element must be server-rendered and visible; hide things inside\n * `setup` with `gsap.set`, never with a stylesheet\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null)\n * useGsap(ref, ({ gsap, el }) => {\n * gsap.from(el.querySelectorAll('[data-line]'), {\n * yPercent: 100, opacity: 0, stagger: 0.06, duration: 0.8, ease: 'power3.out',\n * scrollTrigger: { trigger: el, start: 'top 80%' },\n * })\n * })\n */\nexport function useGsap(\n ref: RefObject<HTMLElement | null>,\n setup: (ctx: GsapSetupContext) => void | (() => void),\n deps: DependencyList = [],\n options: UseGsapOptions = {},\n): void {\n const setupRef = useRef(setup)\n setupRef.current = setup\n const { near = '200px 0px', reducedMotion = 'skip' } = options\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n if (reducedMotion === 'skip' && prefersReducedMotion()) return\n\n let cancelled = false\n let cleanup: (() => void) | void\n let ctx: ReturnType<Gsap['context']> | undefined\n\n const io = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return\n io.disconnect()\n loadGsap().then(({ gsap, ScrollTrigger }) => {\n if (cancelled || !el.isConnected) return\n ctx = gsap.context(() => {\n cleanup = setupRef.current({ gsap, ScrollTrigger, el })\n }, el)\n })\n },\n { rootMargin: near },\n )\n io.observe(el)\n\n return () => {\n cancelled = true\n io.disconnect()\n if (typeof cleanup === 'function') cleanup()\n ctx?.revert()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ref, near, reducedMotion, ...deps])\n}\n\nexport interface ExpandCollapseOptions {\n duration?: number\n ease?: string\n}\n\n/**\n * Animate expand/collapse without mount/unmount. Content stays in the DOM\n * (so it stays indexable) with overflow hidden; gsap animates height and\n * opacity, and loads on the first toggle, not at mount.\n *\n * @example\n * const { contentRef } = useExpandCollapse(isOpen)\n * <div ref={contentRef}>{children}</div>\n */\nexport function useExpandCollapse(\n isOpen: boolean,\n options: ExpandCollapseOptions = {},\n): { contentRef: RefObject<HTMLDivElement | null> } {\n const { duration = 0.3, ease = 'power2.inOut' } = options\n const contentRef = useRef<HTMLDivElement>(null)\n const initialized = useRef(false)\n\n useEffect(() => {\n const el = contentRef.current\n if (!el) return\n\n // First render: set the resting state with inline styles, no gsap.\n if (!initialized.current) {\n initialized.current = true\n el.style.overflow = 'hidden'\n if (!isOpen) {\n el.style.height = '0px'\n el.style.opacity = '0'\n }\n return\n }\n\n let cancelled = false\n loadGsap().then(({ gsap }) => {\n if (cancelled || !el.isConnected) return\n if (prefersReducedMotion()) {\n gsap.set(el, { height: isOpen ? 'auto' : 0, opacity: isOpen ? 1 : 0 })\n el.style.overflow = isOpen ? 'visible' : 'hidden'\n return\n }\n if (isOpen) {\n gsap.to(el, {\n height: 'auto',\n opacity: 1,\n duration,\n ease,\n onComplete() {\n el.style.overflow = 'visible'\n },\n })\n } else {\n el.style.overflow = 'hidden'\n gsap.to(el, { height: 0, opacity: 0, duration: duration * 0.85, ease })\n }\n })\n return () => {\n cancelled = true\n }\n }, [isOpen, duration, ease])\n\n return { contentRef }\n}\n"]}
1
+ {"version":3,"sources":["../../src/motion/gsap.ts"],"names":["pending"],"mappings":"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","file":"gsap.mjs","sourcesContent":["/**\n * @sonordev/site-kit/motion/gsap — the Upforge motion standard, tier 1.\n *\n * GSAP for the moments that earn it: sequenced timelines, SplitText,\n * Flip, MorphSVG. Requires the optional peer `gsap` (all plugins are free\n * since 3.13):\n *\n * npm i gsap\n *\n * A site that never imports this subpath never installs gsap. NOTHING\n * outside this file may import from 'gsap' — that is what keeps the tier\n * boundary real (src/motion/motion.test.tsx enforces it).\n *\n * Cost and where it goes: gsap core + ScrollTrigger is ~46KB gzipped.\n * `useGsap` loads it only when its element comes within 200px of the\n * viewport, so it never sits on the LCP critical path, and it must only be\n * used BELOW the fold. First-paint content renders static.\n *\n * Not included on purpose: ScrollSmoother. It drives scrolling by\n * transforming the page body, which fights native scroll, costs INP on\n * mobile, and breaks every scroll-geometry read on the page. The engine's\n * per-scene lerp gives the liquid feel without hijacking anything.\n */\n\n'use client'\n\nimport { useEffect, useRef, type DependencyList, type RefObject } from 'react'\nimport { prefersReducedMotion } from './engine'\n\ntype GsapModule = typeof import('gsap')\ntype ScrollTriggerModule = typeof import('gsap/ScrollTrigger')\n\nexport type Gsap = GsapModule['gsap']\nexport type ScrollTriggerStatic = ScrollTriggerModule['ScrollTrigger']\n\nexport interface GsapBundle {\n gsap: Gsap\n ScrollTrigger: ScrollTriggerStatic\n}\n\nlet pending: Promise<GsapBundle> | null = null\n\n/**\n * Load gsap + ScrollTrigger once, register the plugin, and share the\n * promise. Safe to call from anywhere; resolves the same bundle every time.\n */\nexport function loadGsap(): Promise<GsapBundle> {\n if (!pending) {\n pending = Promise.all([import('gsap'), import('gsap/ScrollTrigger')]).then(([g, st]) => {\n const gsap = g.gsap ?? g.default\n const ScrollTrigger = st.ScrollTrigger ?? st.default\n gsap.registerPlugin(ScrollTrigger)\n return { gsap, ScrollTrigger }\n })\n }\n return pending\n}\n\n/** Dynamic imports of GSAP plugins, by name: `{ SplitText: () => import('gsap/SplitText') }`. */\nexport type GsapPluginLoaders = Record<string, () => Promise<unknown>>\n\ntype GsapContext = ReturnType<Gsap['context']>\n\nexport interface GsapSetupContext extends GsapBundle {\n /** The element the hook is attached to — use it as the ScrollTrigger trigger and the selector scope. */\n el: HTMLElement\n /**\n * The plugins asked for in `options.plugins`, loaded and registered before\n * setup runs, by the same names: `plugins.SplitText`.\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n plugins: Record<string, any>\n /**\n * The gsap.context setup runs in. Anything setup starts asynchronously\n * (after an await, in a timer, in a plugin callback that fires later)\n * lands outside it, so wrap that work in `context.add(() => ...)` to have\n * it scoped and reverted on unmount with the rest.\n */\n context: GsapContext\n}\n\nexport interface UseGsapOptions {\n /** Preload margin: load gsap when the element is this close. Default \"200px 0px\". */\n near?: string\n /** \"skip\" (default) does nothing under prefers-reduced-motion; \"run\" lets setup decide. */\n reducedMotion?: 'skip' | 'run'\n /**\n * GSAP plugins to load alongside gsap, as dynamic imports keyed by name:\n *\n * { plugins: { SplitText: () => import('gsap/SplitText') } }\n *\n * They're loaded when gsap is, registered, and handed to setup as\n * `plugins`, so setup can stay synchronous. That matters: gsap.context\n * only records what runs synchronously inside it, so a plugin imported\n * from within setup did its work outside the context, unscoped and never\n * reverted on unmount (vsf-consulting-nextjs's SplitHeading had to build a\n * second context of its own to clean up).\n */\n plugins?: GsapPluginLoaders\n}\n\nconst pluginCache = new Map<string, Promise<unknown>>()\n\n/** The plugin object out of its module: the named export, else the default. */\nfunction pickPlugin(mod: unknown, name: string): unknown {\n const m = mod as Record<string, unknown> | null\n return (m && (m[name] ?? m.default)) ?? mod\n}\n\n/**\n * Load plugins by name, once per name for the page, and register them with\n * gsap. Resolves to the plugins keyed by the same names.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport async function loadGsapPlugins(gsap: Gsap, loaders: GsapPluginLoaders = {}): Promise<Record<string, any>> {\n const entries = await Promise.all(\n Object.entries(loaders).map(async ([name, load]) => {\n let pending = pluginCache.get(name)\n if (!pending) {\n pending = load().then(mod => pickPlugin(mod, name))\n pluginCache.set(name, pending)\n }\n return [name, await pending] as const\n }),\n )\n const plugins = Object.fromEntries(entries)\n const list = Object.values(plugins)\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (list.length) gsap.registerPlugin(...(list as any[]))\n return plugins\n}\n\n/**\n * Run a setup inside a gsap.context scoped to `el`, synchronously. Split out\n * of useGsap so the contract (everything setup creates belongs to the\n * returned context, plugins included) is testable without a DOM.\n */\nexport function runGsapSetup(\n bundle: GsapBundle,\n el: HTMLElement,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n plugins: Record<string, any>,\n setup: (ctx: GsapSetupContext) => void | (() => void),\n): { context: GsapContext; cleanup: (() => void) | void } {\n let cleanup: (() => void) | void = undefined\n const context = bundle.gsap.context((self: GsapContext) => {\n cleanup = setup({ ...bundle, el, plugins, context: self })\n }, el)\n return { context, cleanup }\n}\n\n/**\n * Run a GSAP setup against an element, lazily and safely:\n *\n * - gsap loads only when the element nears the viewport\n * - setup runs inside `gsap.context(el)`, so selectors are scoped and\n * everything it creates is reverted on unmount (including ScrollTriggers)\n * - plugins beyond ScrollTrigger (SplitText, Flip, MorphSVG) come in through\n * `options.plugins`, loaded before setup, so setup stays synchronous and\n * inside the context. Anything setup must still start later goes through\n * `context.add()`.\n * - the element must be server-rendered and visible; hide things inside\n * `setup` with `gsap.set`, never with a stylesheet\n *\n * @example\n * const ref = useRef<HTMLDivElement>(null)\n * useGsap(ref, ({ gsap, el }) => {\n * gsap.from(el.querySelectorAll('[data-line]'), {\n * yPercent: 100, opacity: 0, stagger: 0.06, duration: 0.8, ease: 'power3.out',\n * scrollTrigger: { trigger: el, start: 'top 80%' },\n * })\n * })\n *\n * @example With a plugin\n * useGsap(ref, ({ gsap, el, plugins: { SplitText } }) => {\n * SplitText.create(el, {\n * type: 'lines', mask: 'lines', autoSplit: true,\n * onSplit: self => gsap.from(self.lines, { yPercent: 115, stagger: 0.09, scrollTrigger: { trigger: el } }),\n * })\n * }, [], { plugins: { SplitText: () => import('gsap/SplitText') } })\n */\nexport function useGsap(\n ref: RefObject<HTMLElement | null>,\n setup: (ctx: GsapSetupContext) => void | (() => void),\n deps: DependencyList = [],\n options: UseGsapOptions = {},\n): void {\n const setupRef = useRef(setup)\n setupRef.current = setup\n // A ref, like setup: an inline `plugins` object is new every render and\n // must not re-run the effect.\n const pluginsRef = useRef(options.plugins)\n pluginsRef.current = options.plugins\n const { near = '200px 0px', reducedMotion = 'skip' } = options\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n if (reducedMotion === 'skip' && prefersReducedMotion()) return\n\n let cancelled = false\n let cleanup: (() => void) | void\n let ctx: GsapContext | undefined\n\n const io = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return\n io.disconnect()\n loadGsap()\n .then(async bundle => ({ bundle, plugins: await loadGsapPlugins(bundle.gsap, pluginsRef.current) }))\n .then(({ bundle, plugins }) => {\n if (cancelled || !el.isConnected) return\n ;({ context: ctx, cleanup } = runGsapSetup(bundle, el, plugins, setupRef.current))\n })\n },\n { rootMargin: near },\n )\n io.observe(el)\n\n return () => {\n cancelled = true\n io.disconnect()\n if (typeof cleanup === 'function') cleanup()\n ctx?.revert()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [ref, near, reducedMotion, ...deps])\n}\n\nexport interface ExpandCollapseOptions {\n duration?: number\n ease?: string\n}\n\n/**\n * Animate expand/collapse without mount/unmount. Content stays in the DOM\n * (so it stays indexable) with overflow hidden; gsap animates height and\n * opacity, and loads on the first toggle, not at mount.\n *\n * @example\n * const { contentRef } = useExpandCollapse(isOpen)\n * <div ref={contentRef}>{children}</div>\n */\nexport function useExpandCollapse(\n isOpen: boolean,\n options: ExpandCollapseOptions = {},\n): { contentRef: RefObject<HTMLDivElement | null> } {\n const { duration = 0.3, ease = 'power2.inOut' } = options\n const contentRef = useRef<HTMLDivElement>(null)\n const initialized = useRef(false)\n\n useEffect(() => {\n const el = contentRef.current\n if (!el) return\n\n // First render: set the resting state with inline styles, no gsap.\n if (!initialized.current) {\n initialized.current = true\n el.style.overflow = 'hidden'\n if (!isOpen) {\n el.style.height = '0px'\n el.style.opacity = '0'\n }\n return\n }\n\n let cancelled = false\n loadGsap().then(({ gsap }) => {\n if (cancelled || !el.isConnected) return\n if (prefersReducedMotion()) {\n gsap.set(el, { height: isOpen ? 'auto' : 0, opacity: isOpen ? 1 : 0 })\n el.style.overflow = isOpen ? 'visible' : 'hidden'\n return\n }\n if (isOpen) {\n gsap.to(el, {\n height: 'auto',\n opacity: 1,\n duration,\n ease,\n onComplete() {\n el.style.overflow = 'visible'\n },\n })\n } else {\n el.style.overflow = 'hidden'\n gsap.to(el, { height: 0, opacity: 0, duration: duration * 0.85, ease })\n }\n })\n return () => {\n cancelled = true\n }\n }, [isOpen, duration, ease])\n\n return { contentRef }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=gsap.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gsap.test.d.ts","sourceRoot":"","sources":["../../src/motion/gsap.test.ts"],"names":[],"mappings":""}
@@ -24,6 +24,12 @@ export interface OgTheme {
24
24
  surface: string;
25
25
  /** Muted text (subtitle). Defaults derived from `text` when omitted. */
26
26
  muted?: string;
27
+ /**
28
+ * Bottom-bar text, set on `accent`. Defaults to the first of `surface`,
29
+ * `bg`, `text` that reaches WCAG AA for large text (3:1) against the
30
+ * accent (see og/contrast.ts).
31
+ */
32
+ barText?: string;
27
33
  }
28
34
  export interface OgFont {
29
35
  /** Google Fonts family name, e.g. 'Barlow Condensed'. */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/og/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/og/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @sonordev/site-kit/og — text color for the card's bottom bar.
3
+ *
4
+ * SINGLE SOURCE OF TRUTH for "what color is the bar text", shared by the
5
+ * build-time template (template.ts) and the runtime card (route.tsx). The two
6
+ * disagreed: the template set the bar in `theme.surface`, the runtime card in
7
+ * `theme.text`, and on a site whose text and accent are both strong colors the
8
+ * runtime bar came out unreadable (navy on crimson on watsonhac.com, ink on
9
+ * green on reinhart). Both sites dropped the bar rather than ship it.
10
+ *
11
+ * `theme.barText` always wins. Otherwise the first candidate that reaches
12
+ * WCAG AA for large text against the accent is used, in the order the
13
+ * template always preferred (surface, then bg, then text), so every card
14
+ * that already read well keeps its color. Failing that, the highest-contrast
15
+ * candidate.
16
+ *
17
+ * Pure: no DOM, no Node built-ins.
18
+ */
19
+ /** `#abc`, `#aabbcc`, `#aabbccdd` → [r, g, b] in 0-255, or null for anything else. */
20
+ export declare function parseHexColor(color: string): [number, number, number] | null;
21
+ /** WCAG contrast ratio of two hex colors, or null when either isn't hex. */
22
+ export declare function contrastRatio(a: string, b: string): number | null;
23
+ export interface BarTheme {
24
+ bg: string;
25
+ text: string;
26
+ accent: string;
27
+ surface?: string;
28
+ /** Explicit bar text color. Always wins. */
29
+ barText?: string;
30
+ }
31
+ /** The color to set the bottom bar's text in, on `theme.accent`. */
32
+ export declare function barTextColor(theme: BarTheme): string;
33
+ //# sourceMappingURL=contrast.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contrast.d.ts","sourceRoot":"","sources":["../../src/og/contrast.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAK5E;AAUD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMjE;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAUpD"}
@@ -5,4 +5,6 @@
5
5
  export { defineOgCard, OG_WIDTH, OG_HEIGHT } from './config';
6
6
  export type { OgCardConfig, OgTheme, OgFont, OgBackground, OgContent, OgPhoto, OgTemplateHelpers } from './config';
7
7
  export { buildOgHtml } from './template';
8
+ export { paramCardImage, paramCardUrl, codeCardImage, PARAM_CARD_DIR } from './pages';
9
+ export type { OgImageDescriptor } from './pages';
8
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/og/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAClH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/og/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAClH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AACrF,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA"}
package/dist/og/index.js CHANGED
@@ -1,25 +1,43 @@
1
1
  'use strict';
2
2
 
3
- var chunk6CJP7BFM_js = require('../chunk-6CJP7BFM.js');
3
+ var chunkOEW2LFOV_js = require('../chunk-OEW2LFOV.js');
4
+ var chunkCUNZAD46_js = require('../chunk-CUNZAD46.js');
5
+ require('../chunk-R7GHP3FY.js');
4
6
  require('../chunk-SNAQBZPT.js');
5
7
 
6
8
 
7
9
 
8
- Object.defineProperty(exports, "OG_HEIGHT", {
10
+ Object.defineProperty(exports, "PARAM_CARD_DIR", {
9
11
  enumerable: true,
10
- get: function () { return chunk6CJP7BFM_js.OG_HEIGHT; }
12
+ get: function () { return chunkOEW2LFOV_js.PARAM_CARD_DIR; }
11
13
  });
12
- Object.defineProperty(exports, "OG_WIDTH", {
14
+ Object.defineProperty(exports, "buildOgHtml", {
13
15
  enumerable: true,
14
- get: function () { return chunk6CJP7BFM_js.OG_WIDTH; }
16
+ get: function () { return chunkOEW2LFOV_js.buildOgHtml; }
15
17
  });
16
- Object.defineProperty(exports, "buildOgHtml", {
18
+ Object.defineProperty(exports, "codeCardImage", {
19
+ enumerable: true,
20
+ get: function () { return chunkOEW2LFOV_js.codeCardImage; }
21
+ });
22
+ Object.defineProperty(exports, "paramCardImage", {
23
+ enumerable: true,
24
+ get: function () { return chunkOEW2LFOV_js.paramCardImage; }
25
+ });
26
+ Object.defineProperty(exports, "paramCardUrl", {
27
+ enumerable: true,
28
+ get: function () { return chunkOEW2LFOV_js.paramCardUrl; }
29
+ });
30
+ Object.defineProperty(exports, "OG_HEIGHT", {
31
+ enumerable: true,
32
+ get: function () { return chunkCUNZAD46_js.OG_HEIGHT; }
33
+ });
34
+ Object.defineProperty(exports, "OG_WIDTH", {
17
35
  enumerable: true,
18
- get: function () { return chunk6CJP7BFM_js.buildOgHtml; }
36
+ get: function () { return chunkCUNZAD46_js.OG_WIDTH; }
19
37
  });
20
38
  Object.defineProperty(exports, "defineOgCard", {
21
39
  enumerable: true,
22
- get: function () { return chunk6CJP7BFM_js.defineOgCard; }
40
+ get: function () { return chunkCUNZAD46_js.defineOgCard; }
23
41
  });
24
42
  //# sourceMappingURL=index.js.map
25
43
  //# sourceMappingURL=index.js.map
package/dist/og/index.mjs CHANGED
@@ -1,4 +1,6 @@
1
- export { OG_HEIGHT, OG_WIDTH, buildOgHtml, defineOgCard } from '../chunk-UJ6CHZAI.mjs';
1
+ export { PARAM_CARD_DIR, buildOgHtml, codeCardImage, paramCardImage, paramCardUrl } from '../chunk-XZO5I4RS.mjs';
2
+ export { OG_HEIGHT, OG_WIDTH, defineOgCard } from '../chunk-YU7QZ3PP.mjs';
3
+ import '../chunk-4LYW6PMU.mjs';
2
4
  import '../chunk-BEXTDHO4.mjs';
3
5
  //# sourceMappingURL=index.mjs.map
4
6
  //# sourceMappingURL=index.mjs.map
@@ -37,6 +37,18 @@ export interface OgPageRoute {
37
37
  * src/og/README.md.)
38
38
  */
39
39
  export declare const DYNAMIC = "*";
40
+ /**
41
+ * Trailing brand suffix on a managed title (` | Acme`, ` - Acme`, ` — Acme`).
42
+ * Managed titles carry the brand because a SERP entry needs it; a card does
43
+ * not — the logo, the photo and the bar are already saying whose it is, and
44
+ * every character spent on the brand is one not spent on the page.
45
+ *
46
+ * Also drops the two broken suffixes managed titles turn up with, both found
47
+ * on 2026-09-15 and each worked around by hand in a site's `cards`: a
48
+ * dangling separator with no brand after it (reinhart's "About Us |", Green
49
+ * Bay's), and the domain after a comma ("Privacy Policy, abbeyglenapts.com").
50
+ */
51
+ export declare function stripBrandSuffix(title: string, brand?: string): string;
40
52
  /**
41
53
  * `/services/walk-in-closets` -> `Walk In Closets`. The no-managed-data path.
42
54
  *
@@ -84,6 +96,95 @@ export declare function slugForPath(path: string): string;
84
96
  * hand-written card with nothing said about it. The caller reports these.
85
97
  */
86
98
  export declare function unmatchedCardKeys(cards: Record<string, unknown> | undefined, paths: string[]): string[];
99
+ /**
100
+ * Does a concrete URL fall under a dynamic route pattern? One `*` matches
101
+ * exactly one segment: `/properties/tall-pines/about` is under
102
+ * `/properties/*` + `/about`, and `/floor-plans/1-bedroom` under
103
+ * `/floor-plans/*`. A key that is itself a pattern matches nothing.
104
+ */
105
+ export declare function matchesRoutePattern(path: string, pattern: string): boolean;
106
+ /**
107
+ * The `cards` keys that name one page under a dynamic route: a card per
108
+ * floor plan, per community, per sub-page of a community. Keyed by the URL
109
+ * itself (`/floor-plans/1-bedroom`), which any site can build from the same
110
+ * data its `generateStaticParams` reads.
111
+ *
112
+ * A static file in a dynamic segment covers every param of the route, so
113
+ * these can't be `opengraph-image` files. `sonor-setup og` renders each one to
114
+ * `public/_og/` (see paramCardUrl), and the page declares it with
115
+ * `paramCardImage`. The MDG property sites needed a card per floor plan and
116
+ * per community and rendered them with their own script until this existed.
117
+ *
118
+ * Returns each key with the pattern it falls under. Keys that are a real
119
+ * static route or a pattern are left to the route cards.
120
+ */
121
+ export declare function paramCardKeys(cards: Record<string, unknown> | undefined, paths: string[]): Array<{
122
+ path: string;
123
+ pattern: string;
124
+ }>;
125
+ /**
126
+ * Public directory (under `public/`) that `sonor-setup og` owns for per-URL
127
+ * cards. Generated; the command clears it on every run, so keep nothing else
128
+ * in it.
129
+ */
130
+ export declare const PARAM_CARD_DIR = "_og";
131
+ /**
132
+ * Where the per-URL card for a page is served: `/floor-plans/1-bedroom` ->
133
+ * `/_og/floor-plans/1-bedroom.jpg`. Single source of truth for the file the
134
+ * CLI writes and the URL `paramCardImage` declares.
135
+ *
136
+ * It ends in `.jpg` on purpose. Next serves a code-based `opengraph-image`
137
+ * route without an extension, and `trailingSlash: true` answers that URL with
138
+ * a 308 before the card, which some preview bots don't follow. A static file
139
+ * with an extension is never redirected.
140
+ */
141
+ export declare function paramCardUrl(path: string): string;
142
+ /** An `openGraph.images` entry. */
143
+ export interface OgImageDescriptor {
144
+ url: string;
145
+ width: number;
146
+ height: number;
147
+ type: string;
148
+ alt?: string;
149
+ }
150
+ /**
151
+ * The page's per-URL card, for its metadata:
152
+ *
153
+ * ```ts
154
+ * const card = paramCardImage(`/floor-plans/${slug}`, { config: ogConfig })
155
+ * return {
156
+ * openGraph: { ...(card && { images: [card] }) },
157
+ * twitter: { card: 'summary_large_image', ...(card && { images: [card.url] }) },
158
+ * }
159
+ * ```
160
+ *
161
+ * Pass `config` (the site's og.config) and it answers undefined for a page
162
+ * with no `cards` entry, so the page keeps its segment's static card. Without
163
+ * `config` it always answers, so only call it for URLs you gave a card.
164
+ */
165
+ export declare function paramCardImage(path: string, options?: {
166
+ config?: Pick<OgCardConfig, 'cards'>;
167
+ alt?: string;
168
+ }): OgImageDescriptor | undefined;
169
+ /**
170
+ * A code-based card (`opengraph-image.tsx`) declared at the URL the site
171
+ * actually serves it from.
172
+ *
173
+ * Next wires such a card in as `<path>/opengraph-image`, with no extension.
174
+ * With `trailingSlash: true` that URL 308-redirects to the slashed one, so
175
+ * every share preview starts with a redirect, and bots that don't follow one
176
+ * show no card (the MDG property sites, 2026-09-15). Declaring the slashed URL
177
+ * gets a 200 first time. Declared images beat the file convention, so this
178
+ * replaces Next's own entry rather than adding a second.
179
+ *
180
+ * `trailingSlash` defaults to the site's next.config. Without it, this is the
181
+ * URL Next would have used anyway.
182
+ */
183
+ export declare function codeCardImage(path: string, options?: {
184
+ trailingSlash?: boolean;
185
+ alt?: string;
186
+ contentType?: string;
187
+ }): OgImageDescriptor;
87
188
  /**
88
189
  * Build a page's card config by layering its copy over the site's card.
89
190
  *
@@ -1 +1 @@
1
- {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/og/pages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,MAAM,CAAA;AAsB1B;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAUlF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAM,GAAG,MAAM,GAAG,SAAS,CA2BrF;AAsBD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,KAAK,EAAE,MAAM,EAAE,GACd,MAAM,EAAE,CAIV;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,WAAW,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,CAsCd"}
1
+ {"version":3,"file":"pages.d.ts","sourceRoot":"","sources":["../../src/og/pages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAK5C,mCAAmC;AACnC,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,OAAO,MAAM,CAAA;AAqB1B;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAYtE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOlD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAYlF;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,SAAM,GAAG,MAAM,GAAG,SAAS,CA2BrF;AAsBD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,KAAK,EAAE,MAAM,EAAE,GACd,MAAM,EAAE,CAOV;AAQD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAK1E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,EAC1C,KAAK,EAAE,MAAM,EAAE,GACd,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAW1C;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,QAAQ,CAAA;AAEnC;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,mCAAmC;AACnC,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAO,GACnE,iBAAiB,GAAG,SAAS,CAa/B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5E,iBAAiB,CAUnB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,WAAW,EAClB,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,CAuCd"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * @sonordev/site-kit/og — what Sonor says about each route, for its card.
3
+ *
4
+ * SINGLE SOURCE OF TRUTH for the per-route Sonor lookup, shared by
5
+ * `sonor-setup og` (card copy, and which pages set managed_og_image) and the
6
+ * doctor's online `og.card` check (managed_og_image only). One lookup per
7
+ * route either way; they must not drift on which fields they read.
8
+ *
9
+ * Node-only (it's CLI code): never import from browser or client code.
10
+ */
11
+ import type { OgPageRoute } from './pages';
12
+ /** Concurrent Chrome renders and Sonor lookups. More than this thrashes. */
13
+ export declare const RENDER_CONCURRENCY = 4;
14
+ /** Run tasks with a small concurrency cap. */
15
+ export declare function pooled<T, R>(items: T[], limit: number, fn: (item: T, i: number) => Promise<R>): Promise<R[]>;
16
+ export type RouteCopy = OgPageRoute & {
17
+ /** seo_pages.managed_og_image, which overrides the route's own card. */
18
+ managedOgImage?: string;
19
+ };
20
+ /**
21
+ * Ask Sonor for each route's managed title and description, so a page card
22
+ * says what the page's own <title> says.
23
+ *
24
+ * Best effort by design: one lookup per route, capped concurrency, and any
25
+ * failure degrades that route to a path-derived title rather than failing the
26
+ * command. A site with no key still gets a full set of cards.
27
+ */
28
+ export declare function resolveRouteCopy(paths: string[]): Promise<RouteCopy[]>;
29
+ /**
30
+ * The site's static routes whose seo_pages row sets managed_og_image, or
31
+ * undefined when that can't be known (no key, no app directory).
32
+ */
33
+ export declare function readManagedOgImages(cwd: string): Promise<string[] | undefined>;
34
+ //# sourceMappingURL=route-copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-copy.d.ts","sourceRoot":"","sources":["../../src/og/route-copy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG1C,4EAA4E;AAC5E,eAAO,MAAM,kBAAkB,IAAI,CAAA;AAEnC,8CAA8C;AAC9C,wBAAsB,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAWlH;AAED,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG;IACpC,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAID;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAyB5E;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,CAOpF"}