@sonordev/site-kit 7.4.0 → 8.0.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 (227) hide show
  1. package/AGENTS.md +40 -12
  2. package/CHANGELOG.md +67 -0
  3. package/README.md +44 -18
  4. package/agent-manifest.json +111 -56
  5. package/dist/AnalyticsProvider-LYFDQRRJ.js +13 -0
  6. package/dist/{ArticleViewTracker-3DH53RSB.js → ArticleViewTracker-HG7IIRJY.js} +6 -5
  7. package/dist/{BlocksPopup-FGWYVHCH.js → BlocksPopup-GFX3GZIK.js} +6 -5
  8. package/dist/{ChatWidget-CDQZCLVH.js → ChatWidget-DVS7MLBN.js} +8 -5
  9. package/dist/{FileField-IPJ7L2W6.js → FileField-DVN7NUBI.js} +5 -5
  10. package/dist/{FormSpotlight-CQI2DBWI.js → FormSpotlight-W4SXKKO6.js} +3 -3
  11. package/dist/{FormStage-4WHD6ED4.js → FormStage-JTEE5MZD.js} +3 -3
  12. package/dist/ManagedForm-ZAUHIHGP.js +19 -0
  13. package/dist/{ManagedNewsletterForm-3D2BK3KQ.js → ManagedNewsletterForm-DQIB5Z4Y.js} +9 -6
  14. package/dist/{SignalCore-HEQYITTM.js → SignalCore-W5PYYMGX.js} +7 -7
  15. package/dist/SiteChat-MY2GATWC.js +6 -0
  16. package/dist/SiteDesignReporter-ICZWEGCY.js +12 -0
  17. package/dist/SitePopups-TGULLAER.js +13 -0
  18. package/dist/SitemapSync-AN2OBJE6.js +9 -0
  19. package/dist/_client/booking-widget.js +6 -5
  20. package/dist/_client/testimonial-section.js +3 -2
  21. package/dist/affiliates/index.js +6 -6
  22. package/dist/analytics/index.js +73 -7
  23. package/dist/articles/index.js +2 -2
  24. package/dist/articles/server-ui.js +3 -3
  25. package/dist/articles/server.js +2 -2
  26. package/dist/brand.css +1 -1
  27. package/dist/chat/index.d.ts +1 -1
  28. package/dist/chat/index.js +39 -8
  29. package/dist/chunk-3G7YABRA.js +25 -0
  30. package/dist/{chunk-CGWUXUYZ.js → chunk-3RDJKIYO.js} +2 -2
  31. package/dist/{chunk-J4FSB4OG.js → chunk-3YKQLC7J.js} +5 -2
  32. package/dist/{chunk-3E3PPSNR.js → chunk-56VDS2RP.js} +2 -2
  33. package/dist/chunk-5ROTTMBL.js +19 -0
  34. package/dist/{chunk-KHQ5GD6T.js → chunk-5S2XDG5O.js} +1 -1
  35. package/dist/chunk-5TM3WPCI.js +7 -0
  36. package/dist/{chunk-7HPZSWS4.js → chunk-6CJGZFOU.js} +1 -1
  37. package/dist/{chunk-RYVDGXC2.js → chunk-6KU7STM3.js} +3 -1
  38. package/dist/{chunk-FUQTV5O6.js → chunk-6QFINXLH.js} +3 -3
  39. package/dist/{chunk-AH4AXO4P.js → chunk-6ZXJ3SXR.js} +1 -1
  40. package/dist/{chunk-XA2BNW5M.js → chunk-7YEEOIWI.js} +1 -1
  41. package/dist/{chunk-IE5SSOCN.js → chunk-BQ2CXKTQ.js} +3 -11
  42. package/dist/{chunk-X6F6SO4S.js → chunk-C7TLGL3R.js} +21 -1
  43. package/dist/{chunk-43OCZ3JA.js → chunk-CAH4Y4PY.js} +4 -2
  44. package/dist/{chunk-PXKIGZ2F.js → chunk-EATJPSTS.js} +1 -1
  45. package/dist/{chunk-OOD6GMT4.js → chunk-GNSXOTIK.js} +6 -4
  46. package/dist/{chunk-EHR4NIMX.js → chunk-ICAVVF6D.js} +3 -3
  47. package/dist/{chunk-MHGAZ3LL.js → chunk-IJQ767JS.js} +3 -5
  48. package/dist/{chunk-CKW4HFJG.js → chunk-J65N34YM.js} +3 -3
  49. package/dist/{chunk-4BHRA7TI.js → chunk-JIH32RH2.js} +3 -3
  50. package/dist/{chunk-D2RGEWHS.js → chunk-K22OLAPC.js} +2 -2
  51. package/dist/{chunk-CG4ETW5Y.js → chunk-KRBBH64S.js} +3 -3
  52. package/dist/{chunk-JRCNUUNG.js → chunk-LBIQ5LTC.js} +1 -1
  53. package/dist/{chunk-MDP7EB4J.js → chunk-LKH44GI3.js} +5 -5
  54. package/dist/{chunk-ZTLMPUO6.js → chunk-LNSF6BJC.js} +1 -1
  55. package/dist/{chunk-5O62CER4.js → chunk-M62U7TJF.js} +1 -1
  56. package/dist/{chunk-EDYHROQ7.js → chunk-NFRJTOTB.js} +3 -3
  57. package/dist/{chunk-4DJMJ4V5.js → chunk-OE3NXEOF.js} +1 -1
  58. package/dist/{chunk-AV4QAK5F.js → chunk-OGK7OL3T.js} +5 -4
  59. package/dist/{chunk-YCFW2OQO.js → chunk-PD7K54EQ.js} +2 -2
  60. package/dist/{chunk-PF64OEXC.js → chunk-PIX7FAMX.js} +2 -2
  61. package/dist/{chunk-XEMHGJEG.js → chunk-ROAOI6GG.js} +10 -10
  62. package/dist/{chunk-6LLTLLEJ.js → chunk-S7SSYGUJ.js} +6 -5
  63. package/dist/{chunk-ATE6IFVK.js → chunk-SBPAXWLF.js} +1 -1
  64. package/dist/{chunk-DA5XC7Y6.js → chunk-TOSZGJEQ.js} +1 -1
  65. package/dist/{chunk-4NTBQNHA.js → chunk-TYAVHRWH.js} +80 -81
  66. package/dist/{chunk-ZTLU3BSW.js → chunk-TZ5RTANX.js} +2 -2
  67. package/dist/{chunk-4YTYGG2C.js → chunk-URJN75ZG.js} +29 -16
  68. package/dist/{chunk-CSN45MHO.js → chunk-UUWUAMUC.js} +13 -16
  69. package/dist/{chunk-PKGN32AU.js → chunk-XPTJRVL2.js} +1 -1
  70. package/dist/{chunk-662ILEZ6.js → chunk-Y35BWW2C.js} +3 -7
  71. package/dist/{chunk-PQDJNIHR.js → chunk-ZHNQFNO3.js} +2 -2
  72. package/dist/chunk-ZKADJNR2.js +52 -0
  73. package/dist/{chunk-GK7TV7EK.js → chunk-ZLFGXKLG.js} +1 -1
  74. package/dist/client/index.js +6 -5
  75. package/dist/contracts/entries.d.ts +1 -1
  76. package/dist/contracts/sentences.d.ts +46 -0
  77. package/dist/contracts/site-cache.d.ts +2 -0
  78. package/dist/cta-bar/index.js +1 -1
  79. package/dist/fleet/index.js +6 -5
  80. package/dist/forms/field-autocomplete.d.ts +16 -8
  81. package/dist/forms/index.d.ts +5 -0
  82. package/dist/forms/index.js +17 -17
  83. package/dist/forms/server.js +7 -7
  84. package/dist/forms/static.js +2 -2
  85. package/dist/forms/submitForm.d.ts +5 -0
  86. package/dist/images/index.js +4 -4
  87. package/dist/index.d.ts +3 -7
  88. package/dist/index.js +1 -1
  89. package/dist/layout/SiteKitLayout.d.ts +2 -1
  90. package/dist/layout/client.js +11 -9
  91. package/dist/layout/index.js +13 -11
  92. package/dist/llms/index.js +7 -6
  93. package/dist/maps/index.js +6 -6
  94. package/dist/mcp/sonor.d.ts +47 -3
  95. package/dist/mcp/sonor.js +30 -20
  96. package/dist/proxy/index.d.ts +3 -3
  97. package/dist/proxy/index.js +1 -1
  98. package/dist/reputation/index.js +3 -2
  99. package/dist/reputation/server.js +2 -1
  100. package/dist/revalidate/index.js +3 -3
  101. package/dist/robots/indexnow.js +2 -2
  102. package/dist/runtime/index.d.ts +32 -0
  103. package/dist/runtime/index.js +7 -0
  104. package/dist/seo/api.d.ts +0 -4
  105. package/dist/seo/client.js +6 -5
  106. package/dist/seo/getManagedMetadata.d.ts +24 -0
  107. package/dist/seo/index.d.ts +2 -3
  108. package/dist/seo/index.js +14 -132
  109. package/dist/seo/indexnow.js +2 -2
  110. package/dist/seo/llms.js +7 -6
  111. package/dist/seo/register-sitemap-cli.js +2 -2
  112. package/dist/seo/server-api.d.ts +0 -6
  113. package/dist/seo/server.d.ts +1 -1
  114. package/dist/seo/server.js +4 -4
  115. package/dist/seo/sitemap.js +4 -3
  116. package/dist/seo/types.d.ts +9 -30
  117. package/dist/server/index.d.ts +8 -1
  118. package/dist/server/index.js +4 -3
  119. package/dist/server/mint-site-token.d.ts +0 -11
  120. package/dist/server/server-fetch.d.ts +19 -0
  121. package/dist/server-api-EGOKC7Q3.js +9 -0
  122. package/dist/shared/build-entries.d.ts +21 -9
  123. package/dist/shared/clientApiConfig.d.ts +56 -0
  124. package/dist/shared/identity-reader.d.ts +26 -0
  125. package/dist/shared/identity-storage.d.ts +30 -0
  126. package/dist/shared/identity.d.ts +13 -13
  127. package/dist/shared/import-specifiers.d.ts +26 -0
  128. package/dist/shared/sonorFetch.d.ts +4 -3
  129. package/dist/shared/version.d.ts +1 -1
  130. package/dist/signal/index.js +2 -2
  131. package/dist/sitemap/index.js +4 -3
  132. package/dist/slots/index.js +3 -3
  133. package/dist/sync/index.js +6 -5
  134. package/dist/types.d.ts +0 -1
  135. package/dist/website/cta-bar.js +1 -1
  136. package/dist/website/images.js +4 -4
  137. package/dist/website/index.js +7 -6
  138. package/dist/website/popups.js +10 -7
  139. package/dist/website/slots.js +3 -3
  140. package/dist/{writeLLMsTxt-OL4KQERZ.js → writeLLMsTxt-UZGN6IBU.js} +3 -2
  141. package/docs/MIGRATING-TO-7.md +5 -2
  142. package/docs/MIGRATING-TO-8.md +183 -0
  143. package/docs.json +4 -8
  144. package/package.json +15 -44
  145. package/skills/site-kit/SKILL.md +41 -11
  146. package/src/analytics/README.md +14 -14
  147. package/src/chat/README.md +7 -7
  148. package/src/forms/README.md +61 -6
  149. package/src/mcp/README.md +61 -20
  150. package/src/proxy/README.md +5 -4
  151. package/src/revalidate/README.md +2 -2
  152. package/src/runtime/README.md +51 -0
  153. package/src/seo/README.md +24 -8
  154. package/src/sync/README.md +2 -2
  155. package/src/website/README.md +3 -2
  156. package/dist/AnalyticsProvider-BQXV3ZF3.js +0 -11
  157. package/dist/ManagedForm-7FZNH4L2.js +0 -16
  158. package/dist/SiteChat-DMPDXY3W.js +0 -5
  159. package/dist/SiteDesignReporter-Y2IOJE52.js +0 -11
  160. package/dist/SitePopups-HD2LDKVU.js +0 -10
  161. package/dist/SitemapSync-OKPZHRX6.js +0 -8
  162. package/dist/chunk-24QZEO3Q.js +0 -41
  163. package/dist/chunk-BU66S5B7.js +0 -1
  164. package/dist/chunk-G3NHWMP5.js +0 -233
  165. package/dist/chunk-HODO5BX5.js +0 -28
  166. package/dist/chunk-L3AQCDCY.js +0 -386
  167. package/dist/chunk-P5GB6NEO.js +0 -66
  168. package/dist/chunk-SWKE6FWH.js +0 -47
  169. package/dist/cms/CmsPage.d.ts +0 -17
  170. package/dist/cms/CmsPreview.d.ts +0 -37
  171. package/dist/cms/CmsSection.d.ts +0 -8
  172. package/dist/cms/PortableTextRenderer.d.ts +0 -7
  173. package/dist/cms/index.d.ts +0 -37
  174. package/dist/cms/index.js +0 -5
  175. package/dist/cms/sanity-image.d.ts +0 -47
  176. package/dist/cms/sections/CtaSection.d.ts +0 -3
  177. package/dist/cms/sections/CustomSection.d.ts +0 -7
  178. package/dist/cms/sections/FaqSection.d.ts +0 -3
  179. package/dist/cms/sections/FormSection.d.ts +0 -8
  180. package/dist/cms/sections/GallerySection.d.ts +0 -3
  181. package/dist/cms/sections/HeroSection.d.ts +0 -3
  182. package/dist/cms/sections/RichTextSection.d.ts +0 -3
  183. package/dist/cms/sections/TestimonialsSection.d.ts +0 -3
  184. package/dist/cms/sections/index.d.ts +0 -8
  185. package/dist/cms/server-api.d.ts +0 -49
  186. package/dist/cms/server.d.ts +0 -1
  187. package/dist/cms/server.js +0 -5
  188. package/dist/cms/types.d.ts +0 -104
  189. package/dist/commerce/CalendarView.d.ts +0 -43
  190. package/dist/commerce/CheckoutForm.d.ts +0 -11
  191. package/dist/commerce/EventCalendar.d.ts +0 -26
  192. package/dist/commerce/EventCheckout.d.ts +0 -42
  193. package/dist/commerce/EventEmbed.d.ts +0 -11
  194. package/dist/commerce/EventModal.d.ts +0 -43
  195. package/dist/commerce/EventTile.d.ts +0 -10
  196. package/dist/commerce/EventsAgenda.d.ts +0 -38
  197. package/dist/commerce/EventsWidget.d.ts +0 -84
  198. package/dist/commerce/OfferingCard.d.ts +0 -9
  199. package/dist/commerce/OfferingList.d.ts +0 -9
  200. package/dist/commerce/ProductDetail.d.ts +0 -38
  201. package/dist/commerce/ProductEmbed.d.ts +0 -11
  202. package/dist/commerce/ProductGrid.d.ts +0 -41
  203. package/dist/commerce/ProductPage.d.ts +0 -39
  204. package/dist/commerce/RegistrationForm.d.ts +0 -9
  205. package/dist/commerce/SizeChart.d.ts +0 -8
  206. package/dist/commerce/UpcomingEvents.d.ts +0 -9
  207. package/dist/commerce/api.d.ts +0 -179
  208. package/dist/commerce/events-extras.d.ts +0 -60
  209. package/dist/commerce/index.d.ts +0 -33
  210. package/dist/commerce/index.js +0 -8022
  211. package/dist/commerce/server.d.ts +0 -161
  212. package/dist/commerce/server.js +0 -2
  213. package/dist/commerce/types.d.ts +0 -340
  214. package/dist/commerce/useEventModal.d.ts +0 -20
  215. package/dist/commerce/utils.d.ts +0 -17
  216. package/dist/engage/EngageWidget.d.ts +0 -21
  217. package/dist/engage/index.d.ts +0 -14
  218. package/dist/engage/index.js +0 -45
  219. package/dist/engage/types.d.ts +0 -33
  220. package/dist/seo/ManagedContent.d.ts +0 -14
  221. package/dist/server-api-BVCBLJKL.js +0 -9
  222. package/dist/website/cms/server.d.ts +0 -2
  223. package/dist/website/cms/server.js +0 -5
  224. package/dist/website/cms-server.d.ts +0 -2
  225. package/dist/website/cms.d.ts +0 -2
  226. package/dist/website/cms.js +0 -5
  227. package/src/commerce/README.md +0 -109
@@ -1,386 +0,0 @@
1
- 'use client';
2
- import { getCmsPage } from './chunk-SWKE6FWH.js';
3
- import { PortableText } from '@portabletext/react';
4
- import imageUrlBuilder from '@sanity/image-url';
5
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
- import { useState, useEffect } from 'react';
7
-
8
- var _builder = null;
9
- var DEFAULT_CONFIG = {
10
- projectId: "l55lyemx",
11
- dataset: "production"
12
- };
13
- function configureSanityImages(config) {
14
- _builder = imageUrlBuilder(config);
15
- }
16
- function getBuilder() {
17
- if (!_builder) {
18
- _builder = imageUrlBuilder(DEFAULT_CONFIG);
19
- }
20
- return _builder;
21
- }
22
- function sanityImageUrl(image, options = {}) {
23
- if (!image?.asset?._ref) return "";
24
- let builder = getBuilder().image(image).auto("format");
25
- if (options.width) builder = builder.width(options.width);
26
- if (options.height) builder = builder.height(options.height);
27
- if (options.dpr) builder = builder.dpr(options.dpr);
28
- if (options.quality) builder = builder.quality(options.quality);
29
- if (options.format) builder = builder.format(options.format);
30
- if (options.fit) builder = builder.fit(options.fit);
31
- if (options.blur) builder = builder.blur(options.blur);
32
- return builder.url();
33
- }
34
- function sanityImageSrcSet(image, widths = [400, 800, 1200, 1600], options = {}) {
35
- if (!image?.asset?._ref) return "";
36
- return widths.map((w) => `${sanityImageUrl(image, { ...options, width: w })} ${w}w`).join(", ");
37
- }
38
- function hotspotToObjectPosition(image) {
39
- if (!image?.hotspot) return void 0;
40
- return `${(image.hotspot.x * 100).toFixed(1)}% ${(image.hotspot.y * 100).toFixed(1)}%`;
41
- }
42
- var defaultComponents = {
43
- block: {
44
- h1: ({ children }) => /* @__PURE__ */ jsx("h1", { className: "sonor-cms-h1", children }),
45
- h2: ({ children }) => /* @__PURE__ */ jsx("h2", { className: "sonor-cms-h2", children }),
46
- h3: ({ children }) => /* @__PURE__ */ jsx("h3", { className: "sonor-cms-h3", children }),
47
- h4: ({ children }) => /* @__PURE__ */ jsx("h4", { className: "sonor-cms-h4", children }),
48
- normal: ({ children }) => /* @__PURE__ */ jsx("p", { className: "sonor-cms-p", children }),
49
- blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { className: "sonor-cms-blockquote", children })
50
- },
51
- marks: {
52
- strong: ({ children }) => /* @__PURE__ */ jsx("strong", { children }),
53
- em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
54
- code: ({ children }) => /* @__PURE__ */ jsx("code", { className: "sonor-cms-code", children }),
55
- underline: ({ children }) => /* @__PURE__ */ jsx("u", { children }),
56
- "strike-through": ({ children }) => /* @__PURE__ */ jsx("s", { children }),
57
- link: ({ children, value }) => {
58
- const href = value?.href || "#";
59
- const isExternal = href.startsWith("http");
60
- return /* @__PURE__ */ jsx(
61
- "a",
62
- {
63
- href,
64
- className: "sonor-cms-link",
65
- ...isExternal ? { target: "_blank", rel: "noopener noreferrer" } : {},
66
- children
67
- }
68
- );
69
- },
70
- highlight: ({ children }) => /* @__PURE__ */ jsx("mark", { className: "sonor-cms-highlight", children })
71
- },
72
- list: {
73
- bullet: ({ children }) => /* @__PURE__ */ jsx("ul", { className: "sonor-cms-ul", children }),
74
- number: ({ children }) => /* @__PURE__ */ jsx("ol", { className: "sonor-cms-ol", children })
75
- },
76
- listItem: {
77
- bullet: ({ children }) => /* @__PURE__ */ jsx("li", { children }),
78
- number: ({ children }) => /* @__PURE__ */ jsx("li", { children })
79
- },
80
- types: {
81
- image: ({ value }) => {
82
- if (!value?.asset?._ref && !value?.url) return null;
83
- const src = value.url || sanityImageUrl(value, { width: 1200 });
84
- const srcSet = !value.url ? sanityImageSrcSet(value, [400, 800, 1200, 1600]) : void 0;
85
- const objectPosition = hotspotToObjectPosition(value);
86
- return /* @__PURE__ */ jsxs("figure", { className: "sonor-cms-figure", children: [
87
- /* @__PURE__ */ jsx(
88
- "img",
89
- {
90
- src,
91
- srcSet,
92
- sizes: "(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 1200px",
93
- alt: value.alt || "",
94
- className: "sonor-cms-img",
95
- loading: "lazy",
96
- style: objectPosition ? { objectPosition } : void 0
97
- }
98
- ),
99
- value.caption && /* @__PURE__ */ jsx("figcaption", { className: "sonor-cms-figcaption", children: typeof value.caption === "string" ? value.caption : null })
100
- ] });
101
- }
102
- }
103
- };
104
- function PortableTextRenderer({
105
- value,
106
- components: overrides,
107
- className
108
- }) {
109
- if (!value || !Array.isArray(value) || value.length === 0) return null;
110
- const merged = overrides ? {
111
- ...defaultComponents,
112
- block: { ...defaultComponents.block, ...overrides.block },
113
- marks: { ...defaultComponents.marks, ...overrides.marks },
114
- types: { ...defaultComponents.types, ...overrides.types },
115
- list: { ...defaultComponents.list, ...overrides.list },
116
- listItem: { ...defaultComponents.listItem, ...overrides.listItem }
117
- } : defaultComponents;
118
- return /* @__PURE__ */ jsx("div", { className: className || "sonor-cms-content", children: /* @__PURE__ */ jsx(PortableText, { value, components: merged }) });
119
- }
120
- function HeroSection({ data, portableTextComponents }) {
121
- const headline = data.headline;
122
- const subheadline = data.subheadline;
123
- const ctaText = data.ctaText;
124
- const ctaLink = data.ctaLink;
125
- const bgImage = data.backgroundImage;
126
- const bgUrl = sanityImageUrl(bgImage, { width: 1920, quality: 80 });
127
- const bgPosition = hotspotToObjectPosition(bgImage) || "50% 50%";
128
- return /* @__PURE__ */ jsxs(
129
- "section",
130
- {
131
- className: "sonor-cms-hero",
132
- style: bgUrl ? { backgroundImage: `url(${bgUrl})`, backgroundPosition: bgPosition, backgroundSize: "cover" } : void 0,
133
- children: [
134
- headline && /* @__PURE__ */ jsx(PortableTextRenderer, { value: headline, components: portableTextComponents, className: "sonor-cms-hero-headline" }),
135
- subheadline && /* @__PURE__ */ jsx(PortableTextRenderer, { value: subheadline, components: portableTextComponents, className: "sonor-cms-hero-subheadline" }),
136
- ctaText && ctaLink && /* @__PURE__ */ jsx("a", { href: ctaLink, className: "sonor-cms-hero-cta", children: ctaText })
137
- ]
138
- }
139
- );
140
- }
141
- function RichTextSection({ data, portableTextComponents }) {
142
- const content = data.content;
143
- if (!content) return null;
144
- return /* @__PURE__ */ jsx("section", { className: "sonor-cms-richtext", children: /* @__PURE__ */ jsx(PortableTextRenderer, { value: content, components: portableTextComponents }) });
145
- }
146
- function CtaSection({ data, portableTextComponents }) {
147
- const headline = data.headline;
148
- const description = data.description;
149
- const buttonText = data.buttonText;
150
- const buttonLink = data.buttonLink;
151
- return /* @__PURE__ */ jsxs("section", { className: "sonor-cms-cta", children: [
152
- headline && /* @__PURE__ */ jsx(PortableTextRenderer, { value: headline, components: portableTextComponents, className: "sonor-cms-cta-headline" }),
153
- description && /* @__PURE__ */ jsx(PortableTextRenderer, { value: description, components: portableTextComponents, className: "sonor-cms-cta-description" }),
154
- buttonText && buttonLink && /* @__PURE__ */ jsx("a", { href: buttonLink, className: "sonor-cms-cta-button", children: buttonText })
155
- ] });
156
- }
157
- function GallerySection({ data, portableTextComponents }) {
158
- const images = data.images || [];
159
- const layout = data.layout || "grid";
160
- const caption = data.caption;
161
- if (images.length === 0) return null;
162
- return /* @__PURE__ */ jsxs("section", { className: "sonor-cms-gallery", children: [
163
- /* @__PURE__ */ jsx("div", { className: `sonor-cms-gallery-${layout}`, children: images.map((img, i) => {
164
- const objectPosition = hotspotToObjectPosition(img);
165
- return /* @__PURE__ */ jsx("figure", { className: "sonor-cms-gallery-item", children: /* @__PURE__ */ jsx(
166
- "img",
167
- {
168
- src: sanityImageUrl(img, { width: 800 }),
169
- srcSet: sanityImageSrcSet(img, [400, 800, 1200]),
170
- sizes: "(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw",
171
- alt: img.alt || "",
172
- loading: "lazy",
173
- style: objectPosition ? { objectPosition } : void 0
174
- }
175
- ) }, img.asset?._ref || i);
176
- }) }),
177
- caption && /* @__PURE__ */ jsx(PortableTextRenderer, { value: caption, components: portableTextComponents, className: "sonor-cms-gallery-caption" })
178
- ] });
179
- }
180
- function TestimonialsSection({ data, portableTextComponents }) {
181
- const items = data.items || [];
182
- const layout = data.layout || "grid";
183
- if (items.length === 0) return null;
184
- return /* @__PURE__ */ jsx("section", { className: `sonor-cms-testimonials sonor-cms-testimonials-${layout}`, children: items.map((item, i) => /* @__PURE__ */ jsxs("blockquote", { className: "sonor-cms-testimonial", children: [
185
- /* @__PURE__ */ jsx(PortableTextRenderer, { value: item.quote, components: portableTextComponents, className: "sonor-cms-testimonial-quote" }),
186
- /* @__PURE__ */ jsxs("footer", { className: "sonor-cms-testimonial-footer", children: [
187
- item.avatar?.asset?._ref && /* @__PURE__ */ jsx(
188
- "img",
189
- {
190
- src: sanityImageUrl(item.avatar, { width: 80, height: 80, fit: "crop" }),
191
- alt: item.avatar.alt || item.author,
192
- className: "sonor-cms-testimonial-avatar",
193
- width: 80,
194
- height: 80,
195
- loading: "lazy"
196
- }
197
- ),
198
- /* @__PURE__ */ jsxs("cite", { className: "sonor-cms-testimonial-author", children: [
199
- item.author,
200
- item.role && /* @__PURE__ */ jsxs("span", { className: "sonor-cms-testimonial-role", children: [
201
- ", ",
202
- item.role
203
- ] })
204
- ] })
205
- ] })
206
- ] }, i)) });
207
- }
208
- function FaqSection({ data, portableTextComponents }) {
209
- const items = data.items || [];
210
- if (items.length === 0) return null;
211
- return /* @__PURE__ */ jsx("section", { className: "sonor-cms-faq", children: items.map((item, i) => /* @__PURE__ */ jsxs("details", { className: "sonor-cms-faq-item", children: [
212
- /* @__PURE__ */ jsx("summary", { className: "sonor-cms-faq-question", children: item.question }),
213
- /* @__PURE__ */ jsx("div", { className: "sonor-cms-faq-answer", children: /* @__PURE__ */ jsx(PortableTextRenderer, { value: item.answer, components: portableTextComponents }) })
214
- ] }, i)) });
215
- }
216
- function FormSection({ data, portableTextComponents }) {
217
- const formSlug = data.formSlug;
218
- const heading = data.heading;
219
- return /* @__PURE__ */ jsxs("section", { className: "sonor-cms-form", children: [
220
- heading && /* @__PURE__ */ jsx(PortableTextRenderer, { value: heading, components: portableTextComponents, className: "sonor-cms-form-heading" }),
221
- formSlug ? /* @__PURE__ */ jsx(
222
- "div",
223
- {
224
- className: "sonor-cms-form-embed",
225
- "data-form-slug": formSlug
226
- }
227
- ) : /* @__PURE__ */ jsx("p", { className: "sonor-cms-form-placeholder", children: "Form not configured" })
228
- ] });
229
- }
230
- function CustomSection({ data, displayName }) {
231
- const componentName = data.componentName;
232
- data.props || {};
233
- return /* @__PURE__ */ jsx("section", { className: "sonor-cms-custom", "data-component": componentName, children: /* @__PURE__ */ jsxs("div", { className: "sonor-cms-custom-placeholder", children: [
234
- "Custom component: ",
235
- componentName || displayName
236
- ] }) });
237
- }
238
- var defaultRenderers = {
239
- hero: HeroSection,
240
- richText: RichTextSection,
241
- cta: CtaSection,
242
- gallery: GallerySection,
243
- testimonials: TestimonialsSection,
244
- faq: FaqSection,
245
- form: FormSection,
246
- custom: CustomSection
247
- };
248
- function CmsSection({ section, sectionComponents, portableTextComponents }) {
249
- const Renderer = sectionComponents?.[section.sectionType] || defaultRenderers[section.sectionType];
250
- if (!Renderer) {
251
- if (process.env.NODE_ENV === "development") {
252
- console.warn(`@sonordev/cms: No renderer for section type: ${section.sectionType}`);
253
- }
254
- return null;
255
- }
256
- return /* @__PURE__ */ jsx(
257
- "div",
258
- {
259
- className: `sonor-cms-section sonor-cms-section-${section.sectionType}`,
260
- "data-section-id": section._id,
261
- "data-section-type": section.sectionType,
262
- children: /* @__PURE__ */ jsx(
263
- Renderer,
264
- {
265
- data: section.data,
266
- sectionType: section.sectionType,
267
- displayName: section.displayName,
268
- portableTextComponents
269
- }
270
- )
271
- }
272
- );
273
- }
274
- async function CmsPage({
275
- path,
276
- sectionComponents,
277
- portableTextComponents,
278
- fallback,
279
- className
280
- }) {
281
- const page = await getCmsPage(path);
282
- if (!page) {
283
- if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
284
- return null;
285
- }
286
- if (!page.sections || page.sections.length === 0) {
287
- if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
288
- return null;
289
- }
290
- return /* @__PURE__ */ jsx(
291
- "div",
292
- {
293
- className: className || "sonor-cms-page",
294
- "data-cms-page-id": page._id,
295
- "data-cms-path": page.path,
296
- children: page.sections.map((section) => /* @__PURE__ */ jsx(
297
- CmsSection,
298
- {
299
- section,
300
- sectionComponents,
301
- portableTextComponents
302
- },
303
- section._id
304
- ))
305
- }
306
- );
307
- }
308
- function CmsPreview({
309
- apiUrl = process.env.SONOR_API_URL || "https://api.sonor.io",
310
- apiKey,
311
- path,
312
- pollInterval = 3e3,
313
- sectionComponents,
314
- portableTextComponents,
315
- className
316
- }) {
317
- const [page, setPage] = useState(null);
318
- const [error, setError] = useState(null);
319
- useEffect(() => {
320
- let cancelled = false;
321
- async function fetchPage() {
322
- try {
323
- const res = await fetch(`${apiUrl}/api/public/cms/page`, {
324
- method: "POST",
325
- headers: {
326
- "Content-Type": "application/json",
327
- "x-api-key": apiKey
328
- },
329
- body: JSON.stringify({ path })
330
- });
331
- if (!res.ok) {
332
- setError(`Error ${res.status}`);
333
- return;
334
- }
335
- const data = await res.json();
336
- if (!cancelled && data?.found && data.page) {
337
- setPage(data.page);
338
- setError(null);
339
- }
340
- } catch (err) {
341
- if (!cancelled) {
342
- setError("Failed to load preview");
343
- }
344
- }
345
- }
346
- fetchPage();
347
- if (pollInterval > 0) {
348
- const interval = setInterval(fetchPage, pollInterval);
349
- return () => {
350
- cancelled = true;
351
- clearInterval(interval);
352
- };
353
- }
354
- return () => {
355
- cancelled = true;
356
- };
357
- }, [apiUrl, apiKey, path, pollInterval]);
358
- if (error) {
359
- return /* @__PURE__ */ jsx("div", { className: "sonor-cms-preview-error", children: /* @__PURE__ */ jsxs("p", { children: [
360
- "Preview error: ",
361
- error
362
- ] }) });
363
- }
364
- if (!page) {
365
- return /* @__PURE__ */ jsx("div", { className: "sonor-cms-preview-loading", children: /* @__PURE__ */ jsx("p", { children: "Loading preview..." }) });
366
- }
367
- return /* @__PURE__ */ jsx(
368
- "div",
369
- {
370
- className: className || "sonor-cms-page sonor-cms-preview",
371
- "data-cms-preview": "true",
372
- "data-cms-path": page.path,
373
- children: page.sections?.map((section) => /* @__PURE__ */ jsx(
374
- CmsSection,
375
- {
376
- section,
377
- sectionComponents,
378
- portableTextComponents
379
- },
380
- section._id
381
- ))
382
- }
383
- );
384
- }
385
-
386
- export { CmsPage, CmsPreview, CmsSection, CtaSection, CustomSection, FaqSection, FormSection, GallerySection, HeroSection, PortableTextRenderer, RichTextSection, TestimonialsSection, configureSanityImages, hotspotToObjectPosition, sanityImageSrcSet, sanityImageUrl };
@@ -1,66 +0,0 @@
1
- 'use client';
2
- import { trackConversion } from './chunk-LCDVPAMR.js';
3
- import { useCallback, useEffect } from 'react';
4
-
5
- function useContactTracking(options = {}) {
6
- const { autoTrack = true, debug = false } = options;
7
- const trackPhoneClick = useCallback((phoneNumber, metadata) => {
8
- if (debug) console.log("[Analytics] Phone click:", phoneNumber);
9
- trackConversion({
10
- type: "phone_call",
11
- metadata: {
12
- phoneNumber: phoneNumber.replace(/\D/g, ""),
13
- // Normalize to digits
14
- rawNumber: phoneNumber,
15
- ...metadata
16
- }
17
- });
18
- }, [debug]);
19
- const trackEmailClick = useCallback((email, metadata) => {
20
- if (debug) console.log("[Analytics] Email click:", email);
21
- trackConversion({
22
- type: "email_click",
23
- metadata: {
24
- email,
25
- ...metadata
26
- }
27
- });
28
- }, [debug]);
29
- useEffect(() => {
30
- if (!autoTrack || typeof document === "undefined") return;
31
- const handleClick = (e) => {
32
- const target = e.target;
33
- const anchor = target.closest("a");
34
- if (!anchor) return;
35
- const href = anchor.getAttribute("href");
36
- if (!href) return;
37
- if (href.startsWith("tel:")) {
38
- const phone = href.replace("tel:", "").trim();
39
- trackPhoneClick(phone, {
40
- linkText: anchor.textContent?.trim(),
41
- source: "auto"
42
- });
43
- } else if (href.startsWith("mailto:")) {
44
- const email = href.replace("mailto:", "").split("?")[0].trim();
45
- trackEmailClick(email, {
46
- linkText: anchor.textContent?.trim(),
47
- source: "auto"
48
- });
49
- }
50
- };
51
- document.addEventListener("click", handleClick, { capture: true });
52
- return () => {
53
- document.removeEventListener("click", handleClick, { capture: true });
54
- };
55
- }, [autoTrack, trackPhoneClick, trackEmailClick]);
56
- return {
57
- trackPhoneClick,
58
- trackEmailClick
59
- };
60
- }
61
- function ContactTracking({ debug = false }) {
62
- useContactTracking({ autoTrack: true, debug });
63
- return null;
64
- }
65
-
66
- export { ContactTracking, useContactTracking };
@@ -1,47 +0,0 @@
1
- import { serverApiFetch } from './chunk-X6F6SO4S.js';
2
- import { cache } from 'react';
3
- import 'server-only';
4
-
5
- var CMS_LOG_PREFIX = "@sonordev/site-kit/cms";
6
- function secureApiPost(endpoint, body = {}) {
7
- return serverApiFetch(endpoint, {
8
- method: "POST",
9
- body,
10
- revalidate: 60,
11
- requireKey: true,
12
- retry: true,
13
- logPrefix: CMS_LOG_PREFIX
14
- });
15
- }
16
- var getCmsPage = cache(
17
- async (path) => {
18
- const result = await secureApiPost("/api/public/cms/page", { path });
19
- if (!result?.found || !result.page) return null;
20
- return result.page;
21
- }
22
- );
23
- var getCmsSection = cache(
24
- async (sectionId) => {
25
- const result = await secureApiPost("/api/public/cms/section", { sectionId });
26
- if (!result?.found || !result.section) return null;
27
- return result.section;
28
- }
29
- );
30
- var getCmsPageMetadata = cache(
31
- async (path) => {
32
- const page = await getCmsPage(path);
33
- if (!page) return null;
34
- const seo = page.seo || {};
35
- return {
36
- title: seo.title || page.title,
37
- description: seo.description,
38
- robots: seo.noindex ? { index: false } : void 0,
39
- openGraph: {
40
- title: seo.title || page.title,
41
- description: seo.description
42
- }
43
- };
44
- }
45
- );
46
-
47
- export { getCmsPage, getCmsPageMetadata, getCmsSection };
@@ -1,17 +0,0 @@
1
- import React from 'react';
2
- import type { CmsPageProps } from './types';
3
- /**
4
- * Async React Server Component that fetches and renders a full CMS page.
5
- *
6
- * @example
7
- * ```tsx
8
- * // app/[...slug]/page.tsx
9
- * import { CmsPage } from '@sonordev/site-kit/cms'
10
- *
11
- * export default function Page({ params }) {
12
- * return <CmsPage path={`/${params.slug.join('/')}`} />
13
- * }
14
- * ```
15
- * @deprecated Since 7.1. Sonor retired the Sanity CMS and no longer serves CMS pages, so this renders nothing. Use managed copy from `@sonordev/site-kit/website/slots` (`ManagedRichText`, `ManagedList`). Removed in 8.0.
16
- */
17
- export declare function CmsPage({ path, sectionComponents, portableTextComponents, fallback, className, }: CmsPageProps): Promise<React.ReactElement | null>;
@@ -1,37 +0,0 @@
1
- import React from 'react';
2
- import type { SectionType, SectionRendererProps } from './types';
3
- interface CmsPreviewProps {
4
- /** Sonor API base URL */
5
- apiUrl?: string;
6
- /** API key for fetching draft content */
7
- apiKey: string;
8
- /** Page path to preview */
9
- path: string;
10
- /** Poll interval in ms (0 = no polling) */
11
- pollInterval?: number;
12
- /** Override section renderers */
13
- sectionComponents?: Partial<Record<SectionType, React.ComponentType<SectionRendererProps>>>;
14
- /** Override Portable Text components */
15
- portableTextComponents?: Record<string, React.ComponentType<any>>;
16
- /** Wrapper className */
17
- className?: string;
18
- }
19
- /**
20
- * Client component for previewing draft CMS content.
21
- * Fetches draft content from Sonor API and re-renders on changes.
22
- *
23
- * @example
24
- * ```tsx
25
- * // Used in preview mode (e.g., ?preview=true)
26
- * import { CmsPreview } from '@sonordev/site-kit/cms'
27
- *
28
- * <CmsPreview
29
- * apiKey={process.env.SONOR_API_KEY!}
30
- * path="/about"
31
- * pollInterval={3000}
32
- * />
33
- * ```
34
- * @deprecated Since 7.1. Sonor retired the Sanity CMS and no longer serves CMS pages, so this renders nothing. Use managed copy from `@sonordev/site-kit/website/slots` (`ManagedRichText`, `ManagedList`). Removed in 8.0.
35
- */
36
- export declare function CmsPreview({ apiUrl, apiKey, path, pollInterval, sectionComponents, portableTextComponents, className, }: CmsPreviewProps): React.JSX.Element;
37
- export {};
@@ -1,8 +0,0 @@
1
- import React from 'react';
2
- import type { CmsSectionProps } from './types';
3
- /**
4
- * Renders a single CMS section using the appropriate renderer for its type.
5
- * Override specific section renderers via the `sectionComponents` prop.
6
- * @deprecated Since 7.1. Sonor retired the Sanity CMS and no longer serves CMS pages, so this renders nothing. Use managed copy from `@sonordev/site-kit/website/slots` (`ManagedRichText`, `ManagedList`). Removed in 8.0.
7
- */
8
- export declare function CmsSection({ section, sectionComponents, portableTextComponents }: CmsSectionProps): React.JSX.Element | null;
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- import type { PortableTextRendererProps } from './types';
3
- /**
4
- * Renders Portable Text content with Sonor default styling.
5
- * Accepts `components` prop to override or extend defaults.
6
- */
7
- export declare function PortableTextRenderer({ value, components: overrides, className, }: PortableTextRendererProps): React.JSX.Element | null;
@@ -1,37 +0,0 @@
1
- /**
2
- * @sonordev/site-kit/cms
3
- *
4
- * DEPRECATED since 7.1, removed in 8.0. Sonor retired the Sanity CMS: no
5
- * project has CMS pages and the API no longer serves them, so these components
6
- * render nothing. Site copy is managed copy now (`@sonordev/site-kit/website/slots`:
7
- * `ManagedSlot`, `ManagedRichText`, `ManagedLink`, `ManagedList`), edited in
8
- * Sonor under Website → Content.
9
- *
10
- * REQUIRES TWO OPTIONAL PEER DEPENDENCIES. Importing this entry without them
11
- * fails the consuming site's build with "Module not found":
12
- *
13
- * npm i @portabletext/react @sanity/image-url
14
- *
15
- * They are peers rather than dependencies because they serve only this module
16
- * (~8 packages / 1.7 MB) and most sites on the fleet never render Sanity
17
- * content. The isolation that makes this safe is the subpath export: nothing
18
- * outside `src/cms/` imports them, and no shared build chunk carries them, so
19
- * a site that never imports `@sonordev/site-kit/cms` never resolves them. The
20
- * same pattern already governs `@vis.gl/react-google-maps` for `./maps`.
21
- *
22
- * Note this applies to `./cms` only — `./cms/server` has no Sanity imports and
23
- * works with no peers installed.
24
- *
25
- * Do NOT apply this pattern to a dependency reachable from a widely-imported
26
- * entry: bundlers resolve even a dynamic import at build time, so there is no
27
- * runtime fallback to hide behind. react-markdown (4.0.3; 7.0 dropped it) is
28
- * the case where exactly that made it impossible.
29
- */
30
- export { CmsPage } from './CmsPage';
31
- export { CmsSection } from './CmsSection';
32
- export { CmsPreview } from './CmsPreview';
33
- export { PortableTextRenderer } from './PortableTextRenderer';
34
- export { configureSanityImages, sanityImageUrl, sanityImageSrcSet, hotspotToObjectPosition, } from './sanity-image';
35
- export type { SanityImageConfig, ImageUrlOptions } from './sanity-image';
36
- export { HeroSection, RichTextSection, CtaSection, GallerySection, TestimonialsSection, FaqSection, FormSection, CustomSection, } from './sections';
37
- export type { CmsPageData, CmsSectionData, CmsPageSeo, CmsPageProps, CmsSectionProps, SectionRendererProps, SectionType, PortableTextRendererProps, PortableTextContent, PortableTextBlock, SanityImageRef, } from './types';
package/dist/cms/index.js DELETED
@@ -1,5 +0,0 @@
1
- export { CmsPage, CmsPreview, CmsSection, CtaSection, CustomSection, FaqSection, FormSection, GallerySection, HeroSection, PortableTextRenderer, RichTextSection, TestimonialsSection, configureSanityImages, hotspotToObjectPosition, sanityImageSrcSet, sanityImageUrl } from '../chunk-L3AQCDCY.js';
2
- import '../chunk-SWKE6FWH.js';
3
- import '../chunk-X6F6SO4S.js';
4
- import '../chunk-MH2DSGC6.js';
5
- import '../chunk-PKBMQBKP.js';
@@ -1,47 +0,0 @@
1
- import type { SanityImageRef } from './types';
2
- export interface SanityImageConfig {
3
- projectId: string;
4
- dataset: string;
5
- }
6
- /**
7
- * Initialise (or re-initialise) the image builder with project config.
8
- * Call once at app startup — e.g. at module scope in app/layout.tsx.
9
- * If never called, falls back to DEFAULT_CONFIG.
10
- */
11
- export declare function configureSanityImages(config: SanityImageConfig): void;
12
- export interface ImageUrlOptions {
13
- width?: number;
14
- height?: number;
15
- /** Device-pixel-ratio multiplier (default 1) */
16
- dpr?: number;
17
- /** Quality 0-100 (default: Sanity auto) */
18
- quality?: number;
19
- /** Force a specific format */
20
- format?: 'webp' | 'avif' | 'png' | 'jpg';
21
- /** Fit mode */
22
- fit?: 'clip' | 'crop' | 'fill' | 'fillmax' | 'max' | 'scale' | 'min';
23
- /** Apply blur (0-2000) */
24
- blur?: number;
25
- }
26
- /**
27
- * Build an optimised image URL from a SanityImageRef.
28
- * Automatically applies hotspot/crop metadata when present.
29
- *
30
- * ```ts
31
- * const url = sanityImageUrl(heroImage, { width: 1200 })
32
- * ```
33
- */
34
- export declare function sanityImageUrl(image: SanityImageRef | undefined | null, options?: ImageUrlOptions): string;
35
- /**
36
- * Generate a srcSet string for responsive images.
37
- *
38
- * ```tsx
39
- * <img srcSet={sanityImageSrcSet(img, [400, 800, 1200])} sizes="100vw" />
40
- * ```
41
- */
42
- export declare function sanityImageSrcSet(image: SanityImageRef | undefined | null, widths?: number[], options?: Omit<ImageUrlOptions, 'width'>): string;
43
- /**
44
- * Compute CSS `object-position` from a Sanity hotspot.
45
- * Returns `undefined` if no hotspot is defined.
46
- */
47
- export declare function hotspotToObjectPosition(image: SanityImageRef | undefined | null): string | undefined;
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- import type { SectionRendererProps } from '../types';
3
- export declare function CtaSection({ data, portableTextComponents }: SectionRendererProps): React.JSX.Element;