@sonordev/site-kit 7.1.1 → 7.2.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 (282) hide show
  1. package/AGENTS.md +3 -3
  2. package/CHANGELOG.md +68 -3426
  3. package/README.md +9 -8
  4. package/agent-manifest.json +12 -4
  5. package/dist/{AnalyticsProvider-3MI5RCTL.js → AnalyticsProvider-SLFFBRPE.js} +4 -4
  6. package/dist/{ArticleViewTracker-CMBSJR3N.js → ArticleViewTracker-TM5AMGN2.js} +3 -3
  7. package/dist/{BlocksPopup-X3OAAK2L.js → BlocksPopup-YJNJIVPO.js} +5 -5
  8. package/dist/ChatWidget-XKOSH66S.js +17 -0
  9. package/dist/{FileField-QRSEGO6D.js → FileField-CI4UL5SH.js} +3 -3
  10. package/dist/{FormSpotlight-XKV7VTN4.js → FormSpotlight-F2AAEGBN.js} +20 -6
  11. package/dist/{FormStage-C3YGYAUZ.js → FormStage-BI5R5CNC.js} +27 -7
  12. package/dist/ManagedForm-G6COGHXL.js +16 -0
  13. package/dist/{ManagedNewsletterForm-LPIKGJF4.js → ManagedNewsletterForm-BO3WCGXX.js} +7 -5
  14. package/dist/{SignalCore-ICXXZBYI.js → SignalCore-ZA6WHKBR.js} +3 -3
  15. package/dist/SiteChat-YJADDTKG.js +5 -0
  16. package/dist/{SiteDesignReporter-A7MS2CIP.js → SiteDesignReporter-5YAW36AQ.js} +5 -5
  17. package/dist/SitePopups-ST5PMKZE.js +10 -0
  18. package/dist/SitemapSync-RJTEBINX.js +8 -0
  19. package/dist/SitemapSync.d.ts +1 -1
  20. package/dist/_client/booking-widget.js +5 -5
  21. package/dist/_client/testimonial-section.d.ts +1 -1
  22. package/dist/affiliates/api.d.ts +1 -1
  23. package/dist/affiliates/index.js +3 -3
  24. package/dist/analytics/AnalyticsProvider.d.ts +1 -1
  25. package/dist/analytics/index.js +4 -4
  26. package/dist/analytics/send-gate.d.ts +13 -26
  27. package/dist/articles/Article.d.ts +1 -1
  28. package/dist/articles/ArticleList.d.ts +1 -1
  29. package/dist/articles/ClusterLandingPage.d.ts +2 -2
  30. package/dist/articles/PublicationLayout.d.ts +1 -1
  31. package/dist/articles/PublicationSidebar.d.ts +1 -1
  32. package/dist/articles/RelatedPosts.d.ts +1 -1
  33. package/dist/articles/author-schema.d.ts +1 -1
  34. package/dist/articles/excerpt.d.ts +3 -4
  35. package/dist/articles/index.d.ts +2 -2
  36. package/dist/articles/index.js +2 -2
  37. package/dist/articles/news-sitemap.d.ts +1 -1
  38. package/dist/articles/processArticleHtml.d.ts +1 -1
  39. package/dist/articles/server-core.d.ts +4 -4
  40. package/dist/articles/server-ui.js +3 -2
  41. package/dist/articles/server.d.ts +4 -4
  42. package/dist/articles/server.js +2 -1
  43. package/dist/articles/types.d.ts +1 -1
  44. package/dist/{engage → chat}/ChatWidget.d.ts +8 -7
  45. package/dist/{engage → chat}/EchoUiActions.d.ts +4 -4
  46. package/dist/chat/SiteChat.d.ts +25 -0
  47. package/dist/{engage → chat}/brand-color.d.ts +2 -2
  48. package/dist/{engage → chat}/chat-messages.d.ts +1 -1
  49. package/dist/{engage → chat}/echo-config.d.ts +1 -1
  50. package/dist/chat/index.d.ts +10 -6
  51. package/dist/chat/index.js +14 -8
  52. package/dist/{engage → chat}/launcher-placement.d.ts +1 -7
  53. package/dist/{engage → chat}/socket-loader.d.ts +2 -2
  54. package/dist/chat/types.d.ts +136 -0
  55. package/dist/chunk-27FISYK4.js +4 -0
  56. package/dist/{chunk-QPEEKFCA.js → chunk-4NTBQNHA.js} +249 -80
  57. package/dist/{chunk-RK7GF7PQ.js → chunk-5V2V5C3Y.js} +2 -4
  58. package/dist/{chunk-ICFRH2ED.js → chunk-5YCEMV2L.js} +1 -1
  59. package/dist/{chunk-V4HUSHZO.js → chunk-64DKGVEI.js} +41 -7
  60. package/dist/{chunk-GLHQ3LRO.js → chunk-6U3VLV2C.js} +1 -1
  61. package/dist/{chunk-ZETJTCMV.js → chunk-BC4Y3S3D.js} +1 -1
  62. package/dist/{chunk-JSZN6LDZ.js → chunk-BF7TZYC3.js} +38 -31
  63. package/dist/{chunk-EFPS56JA.js → chunk-BKY2ZNM7.js} +1 -1
  64. package/dist/{chunk-AQSNPZY4.js → chunk-C2FZBUSS.js} +80 -1
  65. package/dist/{chunk-H42PZKVC.js → chunk-CF5QNFYU.js} +2 -2
  66. package/dist/{chunk-JC7KXNNM.js → chunk-D5DCBD4Y.js} +2 -2
  67. package/dist/{chunk-PXZ7LAOY.js → chunk-D6ZC7XKZ.js} +2 -2
  68. package/dist/chunk-EJVQJCG5.js +370 -0
  69. package/dist/{chunk-6OL23QYD.js → chunk-F24FNCTK.js} +1 -1
  70. package/dist/{chunk-NEKEH4CK.js → chunk-FR6BYFPC.js} +53 -21
  71. package/dist/{chunk-KOPVJQ2P.js → chunk-GEXT7BTE.js} +1 -1
  72. package/dist/{chunk-ZAWANWUS.js → chunk-GGORNBSC.js} +18 -6
  73. package/dist/{chunk-DUQMSNF2.js → chunk-HGFAEDG3.js} +1 -1
  74. package/dist/chunk-HODO5BX5.js +28 -0
  75. package/dist/chunk-HW7B43E5.js +14 -0
  76. package/dist/{chunk-EQBZ24VH.js → chunk-IAM3D3RL.js} +43 -24
  77. package/dist/{chunk-ODADQM6Z.js → chunk-JJ3DELUL.js} +2 -2
  78. package/dist/{chunk-542MIHNP.js → chunk-JMLK6MH7.js} +1 -1
  79. package/dist/{chunk-7FWA3I6A.js → chunk-JWTQS5F5.js} +1 -1
  80. package/dist/{chunk-OUNRFXDC.js → chunk-K4ZHAURD.js} +1 -1
  81. package/dist/chunk-NV72HZ4W.js +45 -0
  82. package/dist/{chunk-4Y5FWDPM.js → chunk-NZ4RXN3G.js} +55 -7
  83. package/dist/chunk-OWZ7ATLZ.js +187 -0
  84. package/dist/{chunk-TXBAOEKG.js → chunk-PKGN32AU.js} +5 -4
  85. package/dist/chunk-Q6E4OPGG.js +40 -0
  86. package/dist/{chunk-J4D6ZXRW.js → chunk-QL6XNPSD.js} +3 -3
  87. package/dist/{chunk-HAG4YIZY.js → chunk-R46IQIGK.js} +6 -6
  88. package/dist/{chunk-R3VKF43H.js → chunk-RPZ7OQGD.js} +1 -1
  89. package/dist/{chunk-Q3S26EQA.js → chunk-S54ECQGY.js} +1 -1
  90. package/dist/{chunk-JIL5VY2R.js → chunk-VHKEF5ZB.js} +1 -1
  91. package/dist/{chunk-ILAW3XKD.js → chunk-VO3JYRT5.js} +43 -29
  92. package/dist/chunk-VWWITFWM.js +300 -0
  93. package/dist/{chunk-OPRBF7VE.js → chunk-ZTLMPUO6.js} +3 -2
  94. package/dist/client/index.js +3 -3
  95. package/dist/cms/CmsPreview.d.ts +2 -2
  96. package/dist/cms/index.d.ts +3 -3
  97. package/dist/cms/server-api.d.ts +1 -1
  98. package/dist/cms/types.d.ts +1 -1
  99. package/dist/commerce/EventCheckout.d.ts +1 -1
  100. package/dist/commerce/EventsAgenda.d.ts +3 -3
  101. package/dist/commerce/api.d.ts +1 -1
  102. package/dist/commerce/index.js +4 -4
  103. package/dist/commerce/server.d.ts +3 -4
  104. package/dist/contracts/color.d.ts +1 -1
  105. package/dist/contracts/entries.d.ts +1 -1
  106. package/dist/contracts/error-page.d.ts +183 -0
  107. package/dist/contracts/fleet.d.ts +9 -9
  108. package/dist/contracts/forms.d.ts +4 -10
  109. package/dist/contracts/llms.d.ts +2 -1
  110. package/dist/contracts/portfolio.d.ts +11 -15
  111. package/dist/contracts/proposal-sitemap.d.ts +130 -0
  112. package/dist/contracts/schema-placeholders.d.ts +87 -0
  113. package/dist/contracts/seo-meta.d.ts +11 -12
  114. package/dist/contracts/seo-pages.d.ts +12 -18
  115. package/dist/contracts/site-cache.d.ts +4 -4
  116. package/dist/contracts/sites-normalize.d.ts +2 -4
  117. package/dist/contracts/sites.d.ts +3 -5
  118. package/dist/contracts/slot-content.d.ts +2 -2
  119. package/dist/contracts/slots.d.ts +6 -6
  120. package/dist/contracts/voice.d.ts +56 -0
  121. package/dist/contracts/website.d.ts +2 -2
  122. package/dist/engage/EngageWidget.d.ts +13 -12
  123. package/dist/engage/index.d.ts +10 -9
  124. package/dist/engage/index.js +31 -35
  125. package/dist/engage/types.d.ts +19 -244
  126. package/dist/fleet/FleetHeartbeat.d.ts +2 -2
  127. package/dist/fleet/index.js +4 -4
  128. package/dist/forms/FormEnhancer.d.ts +25 -12
  129. package/dist/forms/FormSpotlight.d.ts +2 -2
  130. package/dist/forms/ManagedForm.d.ts +1 -1
  131. package/dist/forms/ServerForm.d.ts +11 -10
  132. package/dist/forms/StaticForm.d.ts +4 -2
  133. package/dist/forms/field-autocomplete.d.ts +28 -0
  134. package/dist/forms/field-interactions.d.ts +2 -2
  135. package/dist/forms/form-dom-values.d.ts +42 -0
  136. package/dist/forms/form-loaded-at.d.ts +2 -2
  137. package/dist/forms/formsApi.d.ts +2 -2
  138. package/dist/forms/index.d.ts +1 -1
  139. package/dist/forms/index.js +11 -9
  140. package/dist/forms/server.d.ts +1 -1
  141. package/dist/forms/server.js +6 -4
  142. package/dist/forms/static.js +3 -2
  143. package/dist/forms/submitForm.d.ts +9 -2
  144. package/dist/forms/types.d.ts +44 -5
  145. package/dist/forms/useForm.d.ts +21 -4
  146. package/dist/forms/webmcp.d.ts +38 -0
  147. package/dist/images/ManagedFavicon.d.ts +1 -1
  148. package/dist/images/ManagedImage.d.ts +4 -4
  149. package/dist/images/api.d.ts +1 -1
  150. package/dist/images/index.d.ts +2 -2
  151. package/dist/images/index.js +4 -4
  152. package/dist/index.d.ts +4 -1
  153. package/dist/index.js +1 -1
  154. package/dist/landing/contract.d.ts +3 -4
  155. package/dist/layout/SiteKitClientProviders.d.ts +4 -4
  156. package/dist/layout/SiteKitLayout.d.ts +11 -11
  157. package/dist/layout/client.d.ts +4 -4
  158. package/dist/layout/client.js +7 -7
  159. package/dist/layout/index.js +8 -8
  160. package/dist/layout/types.d.ts +7 -6
  161. package/dist/llms/SpeakableSchema.d.ts +2 -2
  162. package/dist/llms/agent-access.d.ts +2 -2
  163. package/dist/llms/aiRobots.d.ts +4 -4
  164. package/dist/llms/api.d.ts +2 -2
  165. package/dist/llms/contract.js +1 -1
  166. package/dist/llms/generateLLMsTxt.d.ts +1 -1
  167. package/dist/llms/index.js +6 -6
  168. package/dist/llms/links.d.ts +1 -1
  169. package/dist/llms/revalidate.d.ts +1 -1
  170. package/dist/llms/seo-revalidate.d.ts +2 -3
  171. package/dist/llms/types.d.ts +6 -6
  172. package/dist/llms/writeLLMsTxt.d.ts +10 -10
  173. package/dist/manifest/index.d.ts +8 -8
  174. package/dist/maps/index.js +3 -3
  175. package/dist/mcp/WebMcpTools.d.ts +1 -1
  176. package/dist/mcp/index.js +2 -14
  177. package/dist/mcp/report.d.ts +2 -2
  178. package/dist/mcp/serverCard.d.ts +1 -1
  179. package/dist/mcp/sonor.d.ts +5 -6
  180. package/dist/mcp/sonor.js +14 -11
  181. package/dist/mcp/transport.d.ts +1 -2
  182. package/dist/mcp/types.d.ts +4 -5
  183. package/dist/motion/engine.d.ts +2 -3
  184. package/dist/motion/failsafe.d.ts +1 -2
  185. package/dist/motion/gsap.d.ts +2 -2
  186. package/dist/motion/three.d.ts +1 -1
  187. package/dist/og/config.d.ts +4 -4
  188. package/dist/og/contrast.d.ts +2 -2
  189. package/dist/og/pages.d.ts +5 -5
  190. package/dist/og/route-fit.d.ts +2 -2
  191. package/dist/og/route.d.ts +1 -2
  192. package/dist/og/template.d.ts +1 -1
  193. package/dist/proxy/index.d.ts +2 -2
  194. package/dist/proxy/securityHeaders.d.ts +10 -12
  195. package/dist/redirects/index.d.ts +7 -7
  196. package/dist/reputation/TestimonialSection.d.ts +1 -1
  197. package/dist/reputation/api.d.ts +1 -1
  198. package/dist/revalidate/index.js +2 -2
  199. package/dist/robots/index.d.ts +5 -5
  200. package/dist/robots/indexnow.d.ts +2 -3
  201. package/dist/seo/ManagedScripts.d.ts +2 -2
  202. package/dist/seo/client.js +4 -4
  203. package/dist/seo/getManagedMetadata.d.ts +1 -1
  204. package/dist/seo/groundingSchema.d.ts +2 -2
  205. package/dist/seo/index.js +15 -8
  206. package/dist/seo/llms/contract.js +1 -1
  207. package/dist/seo/llms.js +6 -6
  208. package/dist/seo/register-sitemap-cli-impl.d.ts +1 -1
  209. package/dist/seo/register-sitemap-cli.d.ts +1 -1
  210. package/dist/seo/register-sitemap-cli.js +2 -2
  211. package/dist/seo/schema-filter.d.ts +5 -6
  212. package/dist/seo/server-api.d.ts +1 -1
  213. package/dist/seo/sitemap.js +4 -4
  214. package/dist/seo/types.d.ts +4 -4
  215. package/dist/seo/withManagedMetadata.d.ts +4 -4
  216. package/dist/server/index.js +2 -2
  217. package/dist/server/mint-site-token.d.ts +1 -2
  218. package/dist/server/server-fetch.d.ts +5 -5
  219. package/dist/shared/build-entries.d.ts +4 -4
  220. package/dist/shared/dialog.d.ts +27 -0
  221. package/dist/shared/frame.d.ts +8 -9
  222. package/dist/shared/fresh-fetch.d.ts +1 -2
  223. package/dist/shared/identity.d.ts +1 -1
  224. package/dist/shared/layers.d.ts +7 -0
  225. package/dist/shared/mid-form.d.ts +53 -0
  226. package/dist/shared/next-files.d.ts +1 -1
  227. package/dist/shared/publishCredential.d.ts +1 -1
  228. package/dist/shared/reporting-gate.d.ts +1 -1
  229. package/dist/shared/uuid.d.ts +1 -2
  230. package/dist/shared/version.d.ts +1 -1
  231. package/dist/shared/visual-viewport-gap.d.ts +3 -3
  232. package/dist/signal/index.js +2 -2
  233. package/dist/signal/types.d.ts +1 -1
  234. package/dist/site-config/index.d.ts +2 -2
  235. package/dist/sitemap/index.d.ts +13 -13
  236. package/dist/sitemap/index.js +4 -4
  237. package/dist/sitemap/shared.d.ts +3 -3
  238. package/dist/sites/site-param.d.ts +2 -2
  239. package/dist/slots/ManagedRichText.d.ts +1 -1
  240. package/dist/slots/ManagedSlot.d.ts +1 -1
  241. package/dist/slots/index.d.ts +1 -3
  242. package/dist/{socket-loader-R24ZSRSQ.js → socket-loader-CGIPEG74.js} +1 -1
  243. package/dist/sync/index.js +5 -5
  244. package/dist/types.d.ts +4 -2
  245. package/dist/website/BlocksPopup.d.ts +1 -1
  246. package/dist/website/PopupBlocks.d.ts +8 -6
  247. package/dist/website/SitePopups.d.ts +25 -0
  248. package/dist/website/images.js +4 -4
  249. package/dist/website/index.js +6 -6
  250. package/dist/website/popup-rules.d.ts +46 -0
  251. package/dist/website/popup-types.d.ts +113 -0
  252. package/dist/website/popups.d.ts +2 -6
  253. package/dist/website/popups.js +6 -14
  254. package/dist/{writeLLMsTxt-QR23OQUE.js → writeLLMsTxt-OV24LQVL.js} +3 -3
  255. package/docs/MIGRATING-TO-7.md +50 -22
  256. package/docs.json +2 -1
  257. package/package.json +2 -2
  258. package/src/admin-auth/README.md +3 -3
  259. package/src/analytics/README.md +9 -11
  260. package/src/articles/README.md +10 -7
  261. package/src/{engage → chat}/README.md +63 -62
  262. package/src/cta-bar/README.md +11 -11
  263. package/src/forms/README.md +60 -12
  264. package/src/layout/README.md +8 -5
  265. package/src/llms/README.md +3 -3
  266. package/src/mcp/README.md +7 -7
  267. package/src/motion/README.md +1 -1
  268. package/src/og/README.md +26 -27
  269. package/src/proxy/README.md +14 -14
  270. package/src/seo/README.md +4 -2
  271. package/src/slots/README.md +1 -1
  272. package/src/sync/README.md +10 -0
  273. package/src/website/README.md +133 -0
  274. package/dist/ChatWidget-JMFBXJ75.js +0 -15
  275. package/dist/EngageWidget-A3QKZ3SU.js +0 -11
  276. package/dist/ManagedForm-2GSSDJPP.js +0 -14
  277. package/dist/SitemapSync-4U654SEA.js +0 -8
  278. package/dist/chunk-B73QPZPH.js +0 -837
  279. package/dist/chunk-NDF4A5JM.js +0 -37
  280. package/dist/chunk-RTMMHTEQ.js +0 -100
  281. package/dist/engage/DesignRenderer.d.ts +0 -57
  282. package/dist/engage/element-rules.d.ts +0 -38
@@ -1,837 +0,0 @@
1
- 'use client';
2
- import { DEFAULT_ENGAGE_Z_INDEX } from './chunk-NDF4A5JM.js';
3
- import { getOrCreateVisitorId } from './chunk-24QZEO3Q.js';
4
- import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
5
- import { sonorFetch } from './chunk-PXZ7LAOY.js';
6
- import React, { useState, useEffect, useCallback, useRef, createElement } from 'react';
7
- import ReactDOM from 'react-dom';
8
- import dynamic from 'next/dynamic';
9
- import { usePathname } from 'next/navigation';
10
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
-
12
- // src/engage/element-rules.ts
13
- function hasControlOrSpace(value) {
14
- for (let i = 0; i < value.length; i++) {
15
- const code = value.charCodeAt(i);
16
- if (code <= 32 || code >= 127 && code <= 159) return true;
17
- }
18
- return false;
19
- }
20
- function isSitePath(value) {
21
- return value.startsWith("/") && !value.startsWith("//") && !value.startsWith("/\\");
22
- }
23
- function safeActionUrl(raw) {
24
- if (typeof raw !== "string") return void 0;
25
- const value = raw.trim();
26
- if (!value || hasControlOrSpace(value)) return void 0;
27
- if (value.startsWith("#") || isSitePath(value)) return value;
28
- const scheme = /^([a-z][a-z0-9+.-]*):/i.exec(value)?.[1]?.toLowerCase();
29
- return scheme && ["http", "https", "mailto", "tel"].includes(scheme) ? value : void 0;
30
- }
31
- function safeImageSrc(raw) {
32
- if (typeof raw !== "string") return void 0;
33
- const value = raw.trim();
34
- if (!value || hasControlOrSpace(value)) return void 0;
35
- if (isSitePath(value)) return value;
36
- return /^https?:\/\//i.test(value) ? value : void 0;
37
- }
38
- function matchPath(pathname, pattern) {
39
- if (pattern.endsWith("*")) return pathname.startsWith(pattern.slice(0, -1));
40
- return pathname === pattern;
41
- }
42
- function deviceFromUserAgent(ua) {
43
- if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
44
- if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return "mobile";
45
- return "desktop";
46
- }
47
- function seenKey(elementId) {
48
- return `_engage_${elementId}`;
49
- }
50
- function isEligible(element, pathname, device, store, now = Date.now()) {
51
- const pages = element.targeting?.pages;
52
- if (pages) {
53
- if (pages.exclude?.some((p) => matchPath(pathname, p))) return false;
54
- if (pages.include && !pages.include.some((p) => matchPath(pathname, p))) return false;
55
- }
56
- if (element.targeting?.devices && !element.targeting.devices.includes(device)) return false;
57
- const frequency = element.trigger?.frequency;
58
- if (frequency) {
59
- const key = seenKey(element.id);
60
- if (frequency.type === "once") {
61
- if (store.local?.getItem(key)) return false;
62
- } else if (frequency.type === "once-per-session") {
63
- if (store.session?.getItem(key)) return false;
64
- } else if (frequency.type === "every-n-days" && frequency.days) {
65
- const last = store.local?.getItem(key);
66
- if (last && now - parseInt(last, 10) < frequency.days * 864e5) return false;
67
- }
68
- }
69
- return true;
70
- }
71
- function activateElement(active, id, elements) {
72
- if (active.includes(id)) return active;
73
- const typeOf = (elementId) => elements.find((e) => e.id === elementId)?.type;
74
- if (typeOf(id) === "popup" && active.some((other) => typeOf(other) === "popup")) return active;
75
- return [...active, id];
76
- }
77
- function handleAction(action, node, onClose, onAction) {
78
- if (!action?.action || action.action === "none") return;
79
- if (onAction) {
80
- onAction(action, node);
81
- }
82
- switch (action.action) {
83
- case "link": {
84
- const url = safeActionUrl(action.url);
85
- if (url) {
86
- if (action.newTab) {
87
- window.open(url, "_blank", "noopener,noreferrer");
88
- } else {
89
- window.location.href = url;
90
- }
91
- }
92
- break;
93
- }
94
- case "scroll":
95
- if (action.target) {
96
- const element = document.querySelector(action.target);
97
- element?.scrollIntoView({ behavior: "smooth" });
98
- }
99
- break;
100
- case "close":
101
- onClose?.();
102
- break;
103
- case "copy":
104
- if (action.text) {
105
- navigator.clipboard.writeText(action.text).catch(console.error);
106
- }
107
- break;
108
- case "share":
109
- if (navigator.share) {
110
- navigator.share({
111
- title: document.title,
112
- url: window.location.href
113
- }).catch(console.error);
114
- }
115
- break;
116
- case "download": {
117
- const url = safeActionUrl(action.url);
118
- if (url) {
119
- const a = document.createElement("a");
120
- a.href = url;
121
- a.download = "";
122
- a.click();
123
- }
124
- break;
125
- }
126
- }
127
- }
128
- var animationKeyframes = `
129
- @keyframes engageFadeIn { from { opacity: 0; } to { opacity: 1; } }
130
- @keyframes engageFadeInUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } }
131
- @keyframes engageFadeInDown { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } }
132
- @keyframes engageSlideInLeft { from { opacity: 0; transform: translateX(-20px); } to { opacity: 1; transform: translateX(0); } }
133
- @keyframes engageSlideInRight { from { opacity: 0; transform: translateX(20px); } to { opacity: 1; transform: translateX(0); } }
134
- @keyframes engageSlideInUp { from { opacity: 0; transform: translateY(100%); } to { opacity: 1; transform: translateY(0); } }
135
- @keyframes engageScaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
136
- @keyframes engageBounceIn { 0% { opacity: 0; transform: scale(0.3); } 50% { transform: scale(1.05); } 70% { transform: scale(0.9); } 100% { opacity: 1; transform: scale(1); } }
137
- `;
138
- function getAnimationStyle(animation, delay, duration) {
139
- if (!animation || animation === "none") return {};
140
- const animationMap = {
141
- fadeIn: "engageFadeIn",
142
- fadeInUp: "engageFadeInUp",
143
- fadeInDown: "engageFadeInDown",
144
- slideInLeft: "engageSlideInLeft",
145
- slideInRight: "engageSlideInRight",
146
- slideInUp: "engageSlideInUp",
147
- scaleIn: "engageScaleIn",
148
- bounceIn: "engageBounceIn"
149
- };
150
- const animationName = animationMap[animation];
151
- if (!animationName) return {};
152
- return {
153
- animation: `${animationName} ${duration || 300}ms ease-out ${delay || 0}ms forwards`,
154
- opacity: 0
155
- // Start invisible, animation will show it
156
- };
157
- }
158
- function NodeRenderer({ node, onClose, onAction, context }) {
159
- const [isHovered, setIsHovered] = useState(false);
160
- const { type, props = {}, style = {}, children } = node;
161
- const computedStyle = { ...style };
162
- if (props.animation) {
163
- Object.assign(computedStyle, getAnimationStyle(
164
- props.animation,
165
- props.animationDelay,
166
- props.animationDuration
167
- ));
168
- }
169
- if (isHovered) {
170
- if (props.hoverScale && props.hoverScale !== "none") {
171
- computedStyle.transform = `scale(${props.hoverScale})`;
172
- computedStyle.transition = "transform 0.2s ease";
173
- }
174
- if (props.hoverShadow && props.hoverShadow !== "none") {
175
- const shadowMap = {
176
- sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
177
- md: "0 4px 6px -1px rgb(0 0 0 / 0.1)",
178
- lg: "0 10px 15px -3px rgb(0 0 0 / 0.1)"
179
- };
180
- computedStyle.boxShadow = shadowMap[props.hoverShadow];
181
- }
182
- }
183
- const eventHandlers = {
184
- onMouseEnter: () => setIsHovered(true),
185
- onMouseLeave: () => setIsHovered(false)
186
- };
187
- if (props.onClick) {
188
- eventHandlers.onClick = (e) => {
189
- e.preventDefault();
190
- handleAction(props.onClick, node, onClose, onAction);
191
- };
192
- computedStyle.cursor = "pointer";
193
- }
194
- const renderedChildren = children?.map((child) => /* @__PURE__ */ jsx(
195
- NodeRenderer,
196
- {
197
- node: child,
198
- onClose,
199
- onAction,
200
- context
201
- },
202
- child.id
203
- ));
204
- switch (type) {
205
- case "Container":
206
- case "Box":
207
- case "Section":
208
- return /* @__PURE__ */ jsx("div", { style: computedStyle, ...eventHandlers, children: renderedChildren });
209
- case "Text":
210
- return /* @__PURE__ */ jsx("p", { style: computedStyle, ...eventHandlers, children: resolveText(props.text, context) });
211
- case "Heading":
212
- const HeadingTag = `h${props.level || 2}`;
213
- return createElement(
214
- HeadingTag,
215
- { style: computedStyle, ...eventHandlers },
216
- resolveText(props.text, context)
217
- );
218
- case "Button":
219
- case "BookingButton":
220
- case "BuyNow":
221
- case "AddToCart":
222
- case "EventRSVP":
223
- return /* @__PURE__ */ jsx(
224
- "button",
225
- {
226
- style: computedStyle,
227
- ...eventHandlers,
228
- type: "button",
229
- "aria-label": typeof props.ariaLabel === "string" ? props.ariaLabel : void 0,
230
- children: resolveText(props.text || props.label, context) || "Button"
231
- }
232
- );
233
- case "Image":
234
- return /* @__PURE__ */ jsx(
235
- "img",
236
- {
237
- src: safeImageSrc(props.src),
238
- alt: props.alt || "",
239
- style: computedStyle,
240
- ...eventHandlers
241
- }
242
- );
243
- case "Link":
244
- return /* @__PURE__ */ jsx(
245
- "a",
246
- {
247
- href: safeActionUrl(props.href) ?? "#",
248
- target: props.newTab ? "_blank" : void 0,
249
- rel: props.newTab ? "noopener noreferrer" : void 0,
250
- style: computedStyle,
251
- ...eventHandlers,
252
- children: resolveText(props.text, context) || renderedChildren
253
- }
254
- );
255
- case "Input":
256
- return /* @__PURE__ */ jsx(
257
- "input",
258
- {
259
- type: props.inputType || "text",
260
- placeholder: props.placeholder,
261
- style: computedStyle,
262
- ...eventHandlers
263
- }
264
- );
265
- case "Divider":
266
- return /* @__PURE__ */ jsx("hr", { style: { border: "none", borderTop: "1px solid var(--sk-border, #e5e7eb)", ...computedStyle } });
267
- case "Spacer":
268
- return /* @__PURE__ */ jsx("div", { style: { ...computedStyle, width: props.width, height: props.height } });
269
- case "Icon":
270
- return /* @__PURE__ */ jsx("span", { style: computedStyle, ...eventHandlers, children: props.icon || "\u2605" });
271
- case "FormEmbed":
272
- return /* @__PURE__ */ jsx(
273
- "div",
274
- {
275
- style: computedStyle,
276
- "data-engage-form": props.form_id,
277
- ...eventHandlers,
278
- children: /* @__PURE__ */ jsxs("div", { style: { padding: "16px", background: "var(--sk-bg-elevated, #f5f5f5)", borderRadius: "8px", textAlign: "center" }, children: [
279
- "Form: ",
280
- props.form_id || "Not configured"
281
- ] })
282
- }
283
- );
284
- case "ProductCard":
285
- case "EventCard":
286
- return /* @__PURE__ */ jsx(
287
- "div",
288
- {
289
- style: computedStyle,
290
- "data-engage-offering": props.offering_id,
291
- ...eventHandlers,
292
- children: renderedChildren
293
- }
294
- );
295
- default:
296
- console.warn(`[DesignRenderer] Unknown node type: ${type}`);
297
- return /* @__PURE__ */ jsx("div", { style: computedStyle, ...eventHandlers, children: renderedChildren });
298
- }
299
- }
300
- function resolveText(text, context) {
301
- if (!text) return "";
302
- if (!context) return text;
303
- return text.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
304
- const value = getNestedValue(context, path);
305
- return value !== void 0 ? String(value) : match;
306
- });
307
- }
308
- function getNestedValue(obj, path) {
309
- return path.split(".").reduce((acc, key) => acc?.[key], obj);
310
- }
311
- function DesignRenderer({
312
- design,
313
- onClose,
314
- onAction,
315
- context
316
- }) {
317
- React.useEffect(() => {
318
- if (typeof document === "undefined") return;
319
- const styleId = "engage-design-renderer-animations";
320
- if (!document.getElementById(styleId)) {
321
- const styleSheet = document.createElement("style");
322
- styleSheet.id = styleId;
323
- styleSheet.textContent = animationKeyframes;
324
- document.head.appendChild(styleSheet);
325
- }
326
- }, []);
327
- const rootStyle = {
328
- ...design.style
329
- };
330
- return /* @__PURE__ */ jsx("div", { style: rootStyle, "data-engage-design": design.id, children: design.children?.map((node) => /* @__PURE__ */ jsx(
331
- NodeRenderer,
332
- {
333
- node,
334
- onClose,
335
- onAction,
336
- context
337
- },
338
- node.id
339
- )) });
340
- }
341
- var LazyBlocksPopup = dynamic(
342
- () => import('./BlocksPopup-X3OAAK2L.js').then((m) => ({ default: m.BlocksPopup })),
343
- { ssr: false }
344
- );
345
- var LazyChatWidget = dynamic(
346
- () => import('./ChatWidget-JMFBXJ75.js').then((m) => ({ default: m.ChatWidget })),
347
- { ssr: false }
348
- );
349
- function EngageWidget(props) {
350
- const target = resolveAnalyticsTarget(props);
351
- if (!target) return null;
352
- return /* @__PURE__ */ jsx(AllowedEngageWidget, { ...props, ...target });
353
- }
354
- function AllowedEngageWidget({
355
- apiUrl: propApiUrl,
356
- apiKey: propApiKey,
357
- projectId: propProjectId,
358
- position = "bottom-right",
359
- offsetBottom,
360
- zIndex = DEFAULT_ENGAGE_Z_INDEX,
361
- chatEnabled = true,
362
- popupsEnabled = true,
363
- debug = false
364
- }) {
365
- const pathname = usePathname();
366
- const [elements, setElements] = useState([]);
367
- const [activeElements, setActiveElements] = useState([]);
368
- const [dismissedElements, setDismissedElements] = useState(/* @__PURE__ */ new Set());
369
- const [chatReady, setChatReady] = useState(false);
370
- useEffect(() => {
371
- if (!popupsEnabled) return;
372
- async function loadElements() {
373
- const apiUrl = propApiUrl;
374
- const apiKey = propApiKey;
375
- if (!apiKey) {
376
- if (debug) console.warn("[Engage] No API key configured");
377
- return;
378
- }
379
- const visitorId = getOrCreateVisitorId();
380
- const url = typeof window !== "undefined" ? window.location.href : "";
381
- try {
382
- const response = await sonorFetch(
383
- `${apiUrl.replace(/\/$/, "")}/engage/widget/elements?url=${encodeURIComponent(url)}&visitorId=${encodeURIComponent(visitorId)}&deviceType=${getDeviceType()}`,
384
- {},
385
- { apiKey }
386
- );
387
- if (!response.ok) {
388
- if (debug) console.error("[Engage] Error loading elements:", response.statusText);
389
- return;
390
- }
391
- const json = await response.json();
392
- const elementsList = json.data?.elements ?? json.elements ?? [];
393
- if (debug) console.log("[Engage] Loaded elements:", elementsList);
394
- setElements(elementsList);
395
- } catch (error) {
396
- if (debug) console.error("[Engage] Error loading elements:", error);
397
- }
398
- }
399
- loadElements();
400
- }, [propApiUrl, propApiKey, debug, popupsEnabled]);
401
- useEffect(() => {
402
- if (!chatEnabled) return;
403
- const id = typeof requestIdleCallback !== "undefined" ? requestIdleCallback(() => setChatReady(true), { timeout: 3e3 }) : setTimeout(() => setChatReady(true), 1);
404
- return () => {
405
- typeof cancelIdleCallback !== "undefined" ? cancelIdleCallback(id) : clearTimeout(id);
406
- };
407
- }, [chatEnabled]);
408
- useEffect(() => {
409
- if (!elements.length) return;
410
- const store = { local: storageOrNull("local"), session: storageOrNull("session") };
411
- const device = getDeviceType();
412
- const eligible = elements.filter(
413
- (element) => !dismissedElements.has(element.id) && isEligible(element, pathname, device, store)
414
- );
415
- if (debug) console.log("[Engage] Eligible elements:", eligible);
416
- const eligibleIds = new Set(eligible.map((e) => e.id));
417
- setActiveElements((prev) => {
418
- const kept = prev.filter((id) => eligibleIds.has(id));
419
- return kept.length === prev.length ? prev : kept;
420
- });
421
- const activate = (id) => {
422
- setActiveElements((prev) => activateElement(prev, id, elements));
423
- };
424
- const cleanups = [];
425
- eligible.forEach((element) => {
426
- const trigger = element.trigger;
427
- if (trigger?.type === "immediate" || !trigger?.type) {
428
- activate(element.id);
429
- } else if (trigger?.type === "delay" && trigger.delay) {
430
- const timer = setTimeout(() => activate(element.id), trigger.delay * 1e3);
431
- cleanups.push(() => clearTimeout(timer));
432
- } else if (trigger?.type === "exit-intent") {
433
- const handleMouseLeave = (e) => {
434
- if (e.clientY < 10) {
435
- activate(element.id);
436
- document.removeEventListener("mouseleave", handleMouseLeave);
437
- }
438
- };
439
- document.addEventListener("mouseleave", handleMouseLeave);
440
- cleanups.push(() => document.removeEventListener("mouseleave", handleMouseLeave));
441
- } else if (trigger?.type === "scroll" && trigger.scrollPercentage) {
442
- const handleScroll = () => {
443
- const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight) * 100;
444
- if (scrollPercent >= (trigger.scrollPercentage || 50)) {
445
- activate(element.id);
446
- window.removeEventListener("scroll", handleScroll);
447
- }
448
- };
449
- window.addEventListener("scroll", handleScroll, { passive: true });
450
- cleanups.push(() => window.removeEventListener("scroll", handleScroll));
451
- }
452
- });
453
- return () => {
454
- cleanups.forEach((fn) => fn());
455
- };
456
- }, [elements, pathname, dismissedElements, debug]);
457
- const recordSeen = useCallback((elementId) => {
458
- const element = elements.find((e) => e.id === elementId);
459
- if (!element?.trigger?.frequency) return;
460
- try {
461
- if (element.trigger.frequency.type === "once-per-session") {
462
- sessionStorage.setItem(seenKey(elementId), "true");
463
- } else {
464
- localStorage.setItem(seenKey(elementId), Date.now().toString());
465
- }
466
- } catch {
467
- }
468
- }, [elements]);
469
- const handleDismiss = useCallback((elementId) => {
470
- setDismissedElements((prev) => /* @__PURE__ */ new Set([...prev, elementId]));
471
- setActiveElements((prev) => prev.filter((id) => id !== elementId));
472
- recordSeen(elementId);
473
- }, [recordSeen]);
474
- if (typeof document === "undefined") return null;
475
- return ReactDOM.createPortal(
476
- /* @__PURE__ */ jsxs(Fragment, { children: [
477
- activeElements.map((elementId) => {
478
- const element = elements.find((e) => e.id === elementId);
479
- if (!element) return null;
480
- return /* @__PURE__ */ jsx(
481
- EngageElementRenderer,
482
- {
483
- element,
484
- onDismiss: () => handleDismiss(element.id),
485
- onEngaged: () => recordSeen(element.id),
486
- zIndex,
487
- apiUrl: propApiUrl,
488
- apiKey: propApiKey
489
- },
490
- element.id
491
- );
492
- }),
493
- chatEnabled && chatReady && /* @__PURE__ */ jsx(
494
- LazyChatWidget,
495
- {
496
- projectId: propProjectId ?? void 0,
497
- config: {
498
- position,
499
- offsetBottom,
500
- zIndex,
501
- buttonColor: "#2563eb"
502
- // Default blue-600 (AA on white), overridden by --sk-primary CSS var or API brand_primary
503
- }
504
- }
505
- )
506
- ] }),
507
- document.body
508
- );
509
- }
510
- function trackEngageEvent(apiUrl, apiKey, endpoint, data) {
511
- if (!apiKey) return;
512
- const visitorId = typeof localStorage !== "undefined" ? localStorage.getItem("_sk_vid") : null;
513
- sonorFetch(`${apiUrl.replace(/\/$/, "")}/engage/widget/${endpoint}`, {
514
- method: "POST",
515
- headers: { "Content-Type": "application/json" },
516
- body: JSON.stringify({ ...data, visitorId, pageUrl: window.location.href }),
517
- keepalive: true
518
- }, { apiKey, retries: 0 }).catch(() => {
519
- });
520
- }
521
- function handleEngageAction(action, _node, element, apiUrl, apiKey) {
522
- trackEngageEvent(apiUrl, apiKey, "click", {
523
- elementId: element.id,
524
- action: action.action
525
- });
526
- switch (action.action) {
527
- case "navigate": {
528
- const url = safeActionUrl(action.url);
529
- if (url) window.location.href = url;
530
- break;
531
- }
532
- case "open-url": {
533
- const url = safeActionUrl(action.url);
534
- if (url) window.open(url, "_blank", "noopener,noreferrer");
535
- break;
536
- }
537
- case "submit-form":
538
- case "submit_form":
539
- window.dispatchEvent(new CustomEvent("engage:submit-form", {
540
- detail: { formId: action.formId || action.url, elementId: element.id }
541
- }));
542
- break;
543
- case "track-conversion":
544
- window.dispatchEvent(new CustomEvent("engage:conversion", {
545
- detail: { action, elementId: element.id }
546
- }));
547
- break;
548
- default:
549
- window.dispatchEvent(new CustomEvent("engage:action", {
550
- detail: { action, elementId: element.id }
551
- }));
552
- break;
553
- }
554
- }
555
- function EngageElementRenderer({
556
- element,
557
- onDismiss,
558
- onEngaged,
559
- zIndex,
560
- apiUrl,
561
- apiKey
562
- }) {
563
- const containerRef = useRef(null);
564
- const impressionTrackedRef = useRef(false);
565
- useEffect(() => {
566
- const el = containerRef.current;
567
- if (!el || impressionTrackedRef.current) return;
568
- const observer = new IntersectionObserver(
569
- ([entry]) => {
570
- if (entry.isIntersecting && !impressionTrackedRef.current) {
571
- impressionTrackedRef.current = true;
572
- trackEngageEvent(apiUrl, apiKey, "impression", { elementId: element.id });
573
- observer.disconnect();
574
- }
575
- },
576
- { threshold: 0.5 }
577
- );
578
- observer.observe(el);
579
- return () => observer.disconnect();
580
- }, [apiUrl, apiKey, element.id]);
581
- const onAction = useCallback(
582
- (action, node) => {
583
- if (action.action !== "close") onEngaged();
584
- handleEngageAction(action, node, element, apiUrl, apiKey);
585
- },
586
- [element, apiUrl, apiKey, onEngaged]
587
- );
588
- if (element.blocks?.length) {
589
- return /* @__PURE__ */ jsx(
590
- BlocksElement,
591
- {
592
- element,
593
- onDismiss,
594
- onEngaged,
595
- zIndex,
596
- apiUrl,
597
- apiKey,
598
- rootRef: containerRef
599
- }
600
- );
601
- }
602
- if (element.design_json) {
603
- if (element.type === "popup") {
604
- return /* @__PURE__ */ jsx(
605
- "div",
606
- {
607
- ref: containerRef,
608
- "data-engage-element": element.id,
609
- style: {
610
- position: "fixed",
611
- top: 0,
612
- left: 0,
613
- right: 0,
614
- bottom: 0,
615
- backgroundColor: "rgba(0,0,0,0.5)",
616
- display: "flex",
617
- alignItems: "center",
618
- justifyContent: "center",
619
- zIndex
620
- },
621
- onClick: onDismiss,
622
- children: /* @__PURE__ */ jsx("div", { onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(
623
- DesignRenderer,
624
- {
625
- design: element.design_json,
626
- onClose: onDismiss,
627
- onAction
628
- }
629
- ) })
630
- }
631
- );
632
- }
633
- if (element.type === "bar") {
634
- return /* @__PURE__ */ jsx(
635
- "div",
636
- {
637
- ref: containerRef,
638
- "data-engage-element": element.id,
639
- style: {
640
- position: "fixed",
641
- top: 0,
642
- left: 0,
643
- right: 0,
644
- zIndex
645
- },
646
- children: /* @__PURE__ */ jsx(
647
- DesignRenderer,
648
- {
649
- design: element.design_json,
650
- onClose: onDismiss,
651
- onAction
652
- }
653
- )
654
- }
655
- );
656
- }
657
- if (element.type === "nudge" || element.type === "slide-in") {
658
- const position = element.config?.position || "bottom-right";
659
- const positionStyles = {
660
- "bottom-right": { bottom: 20, right: 20 },
661
- "bottom-left": { bottom: 20, left: 20 },
662
- "top-right": { top: 20, right: 20 },
663
- "top-left": { top: 20, left: 20 }
664
- };
665
- return /* @__PURE__ */ jsx(
666
- "div",
667
- {
668
- ref: containerRef,
669
- "data-engage-element": element.id,
670
- style: {
671
- position: "fixed",
672
- zIndex,
673
- ...positionStyles[position]
674
- },
675
- children: /* @__PURE__ */ jsx(
676
- DesignRenderer,
677
- {
678
- design: element.design_json,
679
- onClose: onDismiss,
680
- onAction
681
- }
682
- )
683
- }
684
- );
685
- }
686
- return /* @__PURE__ */ jsx("div", { ref: containerRef, "data-engage-element": element.id, children: /* @__PURE__ */ jsx(
687
- DesignRenderer,
688
- {
689
- design: element.design_json,
690
- onClose: onDismiss,
691
- onAction
692
- }
693
- ) });
694
- }
695
- if (element.type === "popup") {
696
- return /* @__PURE__ */ jsx(
697
- "div",
698
- {
699
- style: {
700
- position: "fixed",
701
- top: 0,
702
- left: 0,
703
- right: 0,
704
- bottom: 0,
705
- backgroundColor: "rgba(0,0,0,0.5)",
706
- display: "flex",
707
- alignItems: "center",
708
- justifyContent: "center",
709
- zIndex
710
- },
711
- onClick: onDismiss,
712
- children: /* @__PURE__ */ jsxs(
713
- "div",
714
- {
715
- style: {
716
- backgroundColor: "var(--sk-bg, #ffffff)",
717
- padding: 24,
718
- borderRadius: 8,
719
- maxWidth: 500,
720
- width: "90%"
721
- },
722
- onClick: (e) => e.stopPropagation(),
723
- children: [
724
- /* @__PURE__ */ jsx(
725
- "button",
726
- {
727
- onClick: onDismiss,
728
- style: {
729
- position: "absolute",
730
- top: 8,
731
- right: 8,
732
- background: "none",
733
- border: "none",
734
- fontSize: 24,
735
- cursor: "pointer"
736
- },
737
- children: "\xD7"
738
- }
739
- ),
740
- element.config?.title && /* @__PURE__ */ jsx("h2", { children: element.config.title }),
741
- element.config?.message && /* @__PURE__ */ jsx("p", { children: element.config.message })
742
- ]
743
- }
744
- )
745
- }
746
- );
747
- }
748
- if (element.type === "bar") {
749
- return /* @__PURE__ */ jsxs(
750
- "div",
751
- {
752
- style: {
753
- position: "fixed",
754
- top: 0,
755
- left: 0,
756
- right: 0,
757
- backgroundColor: element.config?.backgroundColor || "var(--sk-primary, #2563eb)",
758
- color: element.config?.textColor || "var(--sk-bg, #ffffff)",
759
- padding: "12px 24px",
760
- display: "flex",
761
- alignItems: "center",
762
- justifyContent: "center",
763
- gap: 16,
764
- zIndex
765
- },
766
- children: [
767
- /* @__PURE__ */ jsx("span", { children: element.config?.message }),
768
- /* @__PURE__ */ jsx(
769
- "button",
770
- {
771
- onClick: onDismiss,
772
- style: {
773
- background: "none",
774
- border: "none",
775
- color: "inherit",
776
- fontSize: 20,
777
- cursor: "pointer"
778
- },
779
- children: "\xD7"
780
- }
781
- )
782
- ]
783
- }
784
- );
785
- }
786
- return null;
787
- }
788
- var PLACEMENT = {
789
- popup: "popup",
790
- bar: "bar",
791
- nudge: "slide-in",
792
- "slide-in": "slide-in"
793
- };
794
- function BlocksElement({
795
- element,
796
- onDismiss,
797
- onEngaged,
798
- zIndex,
799
- apiUrl,
800
- apiKey,
801
- rootRef
802
- }) {
803
- const layout = element.layout;
804
- const position = layout?.corner ?? element.config?.position;
805
- const corner = position === "bottom-left" || position === "top-left" || position === "top-right" ? position : "bottom-right";
806
- return /* @__PURE__ */ jsx(
807
- LazyBlocksPopup,
808
- {
809
- blocks: element.blocks,
810
- placement: layout?.placement ?? PLACEMENT[element.type] ?? "popup",
811
- edge: layout?.edge,
812
- accent: layout?.accent,
813
- corner,
814
- zIndex,
815
- rootRef,
816
- elementId: element.id,
817
- onClose: onDismiss,
818
- onButton: (url) => {
819
- onEngaged();
820
- trackEngageEvent(apiUrl, apiKey, "click", { elementId: element.id, action: "navigate", url });
821
- }
822
- }
823
- );
824
- }
825
- function getDeviceType() {
826
- if (typeof navigator === "undefined") return "desktop";
827
- return deviceFromUserAgent(navigator.userAgent);
828
- }
829
- function storageOrNull(kind) {
830
- try {
831
- return kind === "local" ? window.localStorage : window.sessionStorage;
832
- } catch {
833
- return null;
834
- }
835
- }
836
-
837
- export { DesignRenderer, EngageWidget };