@frontlit/page-builder 0.1.0-alpha.1 → 0.1.0-alpha.3

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 (116) hide show
  1. package/README.md +38 -2
  2. package/dist/blocks/index.d.ts +35 -21
  3. package/dist/blocks/index.js +4 -3
  4. package/dist/builder/index.d.ts +8 -11
  5. package/dist/builder/index.js +7 -5
  6. package/dist/{button-C3VrMJkr.d.ts → button-OLKN3wPf.d.ts} +3 -3
  7. package/dist/{chunk-7W6Q4WA7.js → chunk-36QHCIPM.js} +252 -282
  8. package/dist/chunk-36QHCIPM.js.map +1 -0
  9. package/dist/{chunk-GTY75HW2.js → chunk-ATNM5JHI.js} +2 -2
  10. package/dist/chunk-ATNM5JHI.js.map +1 -0
  11. package/dist/chunk-BBI7UHOA.js +56 -0
  12. package/dist/chunk-BBI7UHOA.js.map +1 -0
  13. package/dist/{chunk-MO76KZY2.js → chunk-GIKTOAQS.js} +661 -423
  14. package/dist/chunk-GIKTOAQS.js.map +1 -0
  15. package/dist/chunk-HWOVSHIW.js +4 -0
  16. package/dist/{chunk-RUYOL7JZ.js.map → chunk-HWOVSHIW.js.map} +1 -1
  17. package/dist/{chunk-SSQWYMQR.js → chunk-IU4KATI2.js} +74 -129
  18. package/dist/chunk-IU4KATI2.js.map +1 -0
  19. package/dist/chunk-J7Z4UW45.js +3418 -0
  20. package/dist/chunk-J7Z4UW45.js.map +1 -0
  21. package/dist/{chunk-7KIX4WAO.js → chunk-K4WCLHMS.js} +1435 -1382
  22. package/dist/chunk-K4WCLHMS.js.map +1 -0
  23. package/dist/chunk-XU7ALPGQ.js +22 -0
  24. package/dist/chunk-XU7ALPGQ.js.map +1 -0
  25. package/dist/components/index.d.ts +33 -8
  26. package/dist/components/index.js +43 -2
  27. package/dist/components/index.js.map +1 -1
  28. package/dist/data-slots.d.ts +3 -3
  29. package/dist/data-slots.js +1 -1
  30. package/dist/fonts/archivo/archivo-latin-variable.woff2 +0 -0
  31. package/dist/fonts/hanken-grotesk/hanken-grotesk-latin-variable.woff2 +0 -0
  32. package/dist/fonts/jetbrains-mono/jetbrains-mono-latin-variable.woff2 +0 -0
  33. package/dist/fonts/spline-sans-mono/spline-sans-mono-latin-variable.woff2 +0 -0
  34. package/dist/heading-DQCxQt38.d.ts +20 -0
  35. package/dist/image-Bk8kPXwP.d.ts +52 -0
  36. package/dist/index.d.ts +18 -11
  37. package/dist/index.js +9 -7
  38. package/dist/media-CnLImjVC.d.ts +21 -0
  39. package/dist/models/index.d.ts +6 -6
  40. package/dist/models/index.js +2 -1
  41. package/dist/{page-DfVl_aHX.d.ts → page-B5Gmm-Ys.d.ts} +2 -3
  42. package/dist/primitives/index.d.ts +287 -61
  43. package/dist/primitives/index.js +2 -1
  44. package/dist/renderer/index.d.ts +12 -8
  45. package/dist/renderer/index.js +6 -4
  46. package/dist/{section-background-BgOCp5l3.d.ts → section-background-6V_LCi5e.d.ts} +1 -1
  47. package/dist/server/index.d.ts +103 -0
  48. package/dist/server/index.js +2649 -0
  49. package/dist/server/index.js.map +1 -0
  50. package/dist/server/islands/code-snippet.d.ts +17 -0
  51. package/dist/server/islands/code-snippet.js +72 -0
  52. package/dist/server/islands/code-snippet.js.map +1 -0
  53. package/dist/server/islands/email-form.d.ts +50 -0
  54. package/dist/server/islands/email-form.js +406 -0
  55. package/dist/server/islands/email-form.js.map +1 -0
  56. package/dist/server/islands/header-mobile-menu.d.ts +22 -0
  57. package/dist/server/islands/header-mobile-menu.js +422 -0
  58. package/dist/server/islands/header-mobile-menu.js.map +1 -0
  59. package/dist/server/islands/inline-embed.d.ts +28 -0
  60. package/dist/server/islands/inline-embed.js +84 -0
  61. package/dist/server/islands/inline-embed.js.map +1 -0
  62. package/dist/server/islands/marquee-track.d.ts +18 -0
  63. package/dist/server/islands/marquee-track.js +67 -0
  64. package/dist/server/islands/marquee-track.js.map +1 -0
  65. package/dist/server/islands/nav-link.d.ts +37 -0
  66. package/dist/server/islands/nav-link.js +67 -0
  67. package/dist/server/islands/nav-link.js.map +1 -0
  68. package/dist/server/islands/support-form.d.ts +17 -0
  69. package/dist/server/islands/support-form.js +469 -0
  70. package/dist/server/islands/support-form.js.map +1 -0
  71. package/dist/server/islands/theme-mode-switcher.d.ts +38 -0
  72. package/dist/server/islands/theme-mode-switcher.js +169 -0
  73. package/dist/server/islands/theme-mode-switcher.js.map +1 -0
  74. package/dist/server/islands/video-with-preview.d.ts +13 -0
  75. package/dist/server/islands/video-with-preview.js +269 -0
  76. package/dist/server/islands/video-with-preview.js.map +1 -0
  77. package/dist/server/primitives.d.ts +200 -0
  78. package/dist/server/primitives.js +888 -0
  79. package/dist/server/primitives.js.map +1 -0
  80. package/dist/server/schema.d.ts +11308 -0
  81. package/dist/server/schema.js +6179 -0
  82. package/dist/server/schema.js.map +1 -0
  83. package/dist/server/theme-CF3fIKvw.d.ts +9 -0
  84. package/dist/{theme-style-39nxXQy0.d.ts → server/theme-style-5_AGy-4V.d.ts} +43 -1
  85. package/dist/server/theme-style-BPaMwk88.d.ts +183 -0
  86. package/dist/server/theme.d.ts +28 -0
  87. package/dist/{chunk-RBJBODQP.js → server/theme.js} +903 -1243
  88. package/dist/server/theme.js.map +1 -0
  89. package/dist/server/widget-YH9BrOwY.d.ts +77 -0
  90. package/dist/styles.css +4016 -8317
  91. package/dist/theme-style-BVd5tOsc.d.ts +183 -0
  92. package/dist/theme.css +186 -191
  93. package/dist/{widget--uEOpdq3.d.ts → widget-CpE2HdgU.d.ts} +25 -18
  94. package/package.json +71 -11
  95. package/schema/page.v1.json +3855 -0
  96. package/schema/site.v1.json +3811 -0
  97. package/dist/alignment-dZDzN96G.d.ts +0 -5
  98. package/dist/chunk-7KIX4WAO.js.map +0 -1
  99. package/dist/chunk-7W6Q4WA7.js.map +0 -1
  100. package/dist/chunk-GTY75HW2.js.map +0 -1
  101. package/dist/chunk-MO76KZY2.js.map +0 -1
  102. package/dist/chunk-RBJBODQP.js.map +0 -1
  103. package/dist/chunk-RUYOL7JZ.js +0 -4
  104. package/dist/chunk-SSQWYMQR.js.map +0 -1
  105. package/dist/fonts/montserrat/montserrat-latin-100-normal.woff2 +0 -0
  106. package/dist/fonts/montserrat/montserrat-latin-200-normal.woff2 +0 -0
  107. package/dist/fonts/montserrat/montserrat-latin-300-normal.woff2 +0 -0
  108. package/dist/fonts/montserrat/montserrat-latin-400-normal.woff2 +0 -0
  109. package/dist/fonts/montserrat/montserrat-latin-500-normal.woff2 +0 -0
  110. package/dist/fonts/montserrat/montserrat-latin-600-normal.woff2 +0 -0
  111. package/dist/fonts/montserrat/montserrat-latin-700-normal.woff2 +0 -0
  112. package/dist/fonts/montserrat/montserrat-latin-800-normal.woff2 +0 -0
  113. package/dist/fonts/montserrat/montserrat-latin-900-normal.woff2 +0 -0
  114. package/dist/fonts/source-sans-3/source-sans-3-latin-400-normal.woff2 +0 -0
  115. package/dist/image-D7GlnOio.d.ts +0 -30
  116. package/dist/media-Njv378j7.d.ts +0 -13
@@ -1,95 +1,154 @@
1
1
  "use client";
2
- import { Button2, Button } from './chunk-RBJBODQP.js';
3
- import * as React2 from 'react';
4
- import { useRef, useState, useId, useEffect } from 'react';
2
+ import { cn } from './chunk-J7Z4UW45.js';
5
3
  import { jsx, jsxs } from 'react/jsx-runtime';
6
- import { Play, X, Sun, Moon } from 'lucide-react';
7
- export { TextRenderer, truncateTextEditorContent } from '@frontlit/text-editor';
4
+ import * as React from 'react';
5
+ import { useState, useEffect, useRef } from 'react';
6
+ export { TextRenderer } from '@frontlit/text-editor/renderer';
7
+ import { Play, X } from 'lucide-react';
8
8
 
9
- var SandboxedEmbed = ({
10
- content,
11
- className,
12
- style,
13
- id
14
- }) => {
15
- const iframeRef = useRef(null);
16
- const [height, setHeight] = useState("100px");
17
- const generatedId = useId();
18
- const iframeId = id || generatedId;
19
- useEffect(() => {
20
- const handleMessage = (event) => {
21
- if (event.data?.type === "embed-resize" && event.data?.id === iframeId && event.data?.height) {
22
- setHeight(`${event.data.height}px`);
9
+ var imageAttributesResolver = null;
10
+ function setImageAttributesResolver(resolver) {
11
+ imageAttributesResolver = resolver;
12
+ }
13
+ var roundedMap = {
14
+ 0: "rounded-none",
15
+ 1: "rounded-sm",
16
+ 2: "rounded",
17
+ 3: "rounded-md",
18
+ 4: "rounded-lg",
19
+ 5: "rounded-xl",
20
+ 6: "rounded-2xl",
21
+ 7: "rounded-3xl",
22
+ 8: "rounded-full"
23
+ };
24
+ var objectFitClass = {
25
+ cover: "object-cover",
26
+ contain: "object-contain",
27
+ fill: "object-fill",
28
+ none: "object-none",
29
+ "scale-down": "object-scale-down"
30
+ };
31
+ var Image = (props) => {
32
+ const {
33
+ src,
34
+ alt = "",
35
+ defaultImage,
36
+ priority = false,
37
+ loading = priority ? "eager" : "lazy",
38
+ sizes,
39
+ noDefaultImage = false,
40
+ className = "",
41
+ classes = "",
42
+ width = "w-full",
43
+ height = "h-auto",
44
+ objectFit = "cover",
45
+ borderRadius
46
+ } = props;
47
+ const source = src || defaultImage;
48
+ const radiusClass = typeof borderRadius === "number" ? roundedMap[borderRadius] ?? "rounded" : borderRadius;
49
+ if (!source) {
50
+ if (noDefaultImage) return null;
51
+ return /* @__PURE__ */ jsx(
52
+ "div",
53
+ {
54
+ className: cn(
55
+ "relative aspect-video overflow-hidden bg-muted",
56
+ width,
57
+ height,
58
+ radiusClass,
59
+ classes,
60
+ className
61
+ )
23
62
  }
24
- };
25
- window.addEventListener("message", handleMessage);
26
- return () => window.removeEventListener("message", handleMessage);
27
- }, [iframeId]);
28
- const srcDoc = `
29
- <!DOCTYPE html>
30
- <html>
31
- <head>
32
- <style>
33
- html, body { margin: 0; padding: 0; overflow: hidden; }
34
- #content-wrapper { overflow: hidden; height: auto; }
35
- </style>
36
- </head>
37
- <body>
38
- <div id="content-wrapper">
39
- ${content || ""}
40
- </div>
41
- <script>
42
- const iframeId = "${iframeId}";
43
-
44
- function sendHeight() {
45
- const wrapper = document.getElementById('content-wrapper');
46
- const height = wrapper ? wrapper.scrollHeight : document.body.scrollHeight;
47
- window.parent.postMessage({ type: "embed-resize", id: iframeId, height: height }, "*");
48
- }
49
-
50
- // Use a ResizeObserver to detect size changes
51
- const resizeObserver = new ResizeObserver(entries => {
52
- sendHeight();
53
- });
54
- const target = document.getElementById('content-wrapper') || document.body;
55
- resizeObserver.observe(target);
56
-
57
- // Use MutationObserver to detect DOM changes
58
- const mutationObserver = new MutationObserver(() => {
59
- sendHeight();
60
- });
61
- mutationObserver.observe(target, { childList: true, subtree: true, attributes: true });
62
-
63
- // Poll for a few seconds to catch late-loading content
64
- let interval = setInterval(sendHeight, 500);
65
- setTimeout(() => clearInterval(interval), 10000);
66
-
67
- window.addEventListener('load', sendHeight);
68
- window.addEventListener('resize', sendHeight);
69
-
70
- // Initial send
71
- sendHeight();
72
- </script>
73
- </body>
74
- </html>
75
- `;
63
+ );
64
+ }
65
+ const optimized = imageAttributesResolver?.({ src: source, alt, sizes, priority });
76
66
  return /* @__PURE__ */ jsx(
77
- "iframe",
67
+ "div",
78
68
  {
79
- ref: iframeRef,
80
- srcDoc,
81
- className,
82
- style: {
83
- width: "100%",
69
+ className: cn(
70
+ "relative aspect-video overflow-hidden",
71
+ width,
84
72
  height,
85
- border: "none",
86
- ...style
87
- },
88
- sandbox: "allow-scripts allow-popups allow-forms allow-same-origin",
89
- title: "Embedded Content"
73
+ radiusClass,
74
+ classes,
75
+ className
76
+ ),
77
+ children: /* @__PURE__ */ jsx(
78
+ "img",
79
+ {
80
+ src: source,
81
+ alt,
82
+ sizes,
83
+ loading,
84
+ decoding: "async",
85
+ fetchPriority: priority ? "high" : void 0,
86
+ ...optimized,
87
+ className: cn(
88
+ "absolute inset-0 h-full w-full",
89
+ radiusClass,
90
+ objectFitClass[objectFit]
91
+ )
92
+ }
93
+ )
90
94
  }
91
95
  );
92
96
  };
97
+ var LINK_CONTEXT_KEY = /* @__PURE__ */ Symbol.for("@frontlit/page-builder/link-context");
98
+ var globalRegistry = globalThis;
99
+ var PageBuilderLinkContext = globalRegistry[LINK_CONTEXT_KEY] ?? (globalRegistry[LINK_CONTEXT_KEY] = React.createContext(null));
100
+ function PageBuilderLinkProvider({
101
+ component,
102
+ children
103
+ }) {
104
+ return /* @__PURE__ */ jsx(PageBuilderLinkContext.Provider, { value: component ?? null, children });
105
+ }
106
+ function usePageBuilderLinkComponent() {
107
+ return React.useContext(PageBuilderLinkContext);
108
+ }
109
+ function NavLink({
110
+ href,
111
+ children,
112
+ openInSameTab = true,
113
+ style,
114
+ className = "",
115
+ onClick
116
+ }) {
117
+ const LinkComponent = usePageBuilderLinkComponent();
118
+ const isInternal = Boolean(href && href.startsWith("/"));
119
+ const isInPageNavigation = Boolean(href && href.startsWith("#"));
120
+ const target = openInSameTab ? void 0 : "_blank";
121
+ const rel = target === "_blank" ? "noopener noreferrer" : void 0;
122
+ const handleClick = () => {
123
+ onClick?.();
124
+ };
125
+ if (!isInPageNavigation && isInternal && LinkComponent) {
126
+ return /* @__PURE__ */ jsx(
127
+ LinkComponent,
128
+ {
129
+ href,
130
+ style,
131
+ className,
132
+ onClick: handleClick,
133
+ target,
134
+ rel,
135
+ children
136
+ }
137
+ );
138
+ }
139
+ return /* @__PURE__ */ jsx(
140
+ "a",
141
+ {
142
+ href,
143
+ style,
144
+ className,
145
+ target,
146
+ rel,
147
+ onClick: handleClick,
148
+ children
149
+ }
150
+ );
151
+ }
93
152
 
94
153
  // src/utils/extract-video-id.ts
95
154
  var YOUTUBE_HOSTNAMES = /* @__PURE__ */ new Set([
@@ -101,11 +160,7 @@ var YOUTUBE_HOSTNAMES = /* @__PURE__ */ new Set([
101
160
  "www.youtube-nocookie.com",
102
161
  "youtu.be"
103
162
  ]);
104
- var VIMEO_HOSTNAMES = /* @__PURE__ */ new Set([
105
- "vimeo.com",
106
- "www.vimeo.com",
107
- "player.vimeo.com"
108
- ]);
163
+ var VIMEO_HOSTNAMES = /* @__PURE__ */ new Set(["vimeo.com", "www.vimeo.com", "player.vimeo.com"]);
109
164
  var isNumeric = (value) => /^\d+$/.test(value);
110
165
  var extractYouTubeVideoId = (parsedUrl) => {
111
166
  const hostname = parsedUrl.hostname.toLowerCase();
@@ -259,65 +314,52 @@ function VideoWithPreview({
259
314
  }
260
315
  };
261
316
  return /* @__PURE__ */ jsxs("div", { className: aspectRatio === "9/16" ? "max-w-xs mx-auto" : "", children: [
262
- /* @__PURE__ */ jsx(
263
- "div",
264
- {
265
- className: "relative overflow-hidden",
266
- style: aspectRatioStyle(),
267
- children: !modal && isPlaying ? (
268
- // In-place video player
269
- /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: videoType !== "self-hosted" ? /* @__PURE__ */ jsx(
270
- "iframe",
271
- {
272
- src: getEmbedUrl(),
273
- className: "w-full h-full",
274
- allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
275
- allowFullScreen: true
276
- }
277
- ) : /* @__PURE__ */ jsx(
278
- "video",
279
- {
280
- src: videoUrl,
281
- controls: true,
282
- controlsList: "nodownload",
283
- onContextMenu: (e) => e.preventDefault(),
284
- autoPlay: true,
285
- className: "w-full h-full",
286
- children: "Your browser does not support the video tag."
287
- }
288
- ) })
289
- ) : (
290
- // Thumbnail with play button
291
- /* @__PURE__ */ jsxs(
292
- "div",
293
- {
294
- className: "cursor-pointer group w-full h-full",
295
- onClick: handleThumbnailClick,
296
- children: [
297
- /* @__PURE__ */ jsx(
298
- "img",
299
- {
300
- src: getThumbnailUrl() || "/placeholder.svg",
301
- alt: `Thumbnail for ${title}`,
302
- className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
303
- }
304
- ),
305
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/30 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
306
- /* @__PURE__ */ jsx("span", { className: "absolute -inset-1.5 rounded-full bg-gray-200/50 animate-pulse duration-[3000ms]" }),
307
- /* @__PURE__ */ jsx("div", { className: "relative z-1 rounded-full bg-primary p-4 text-primary-foreground", children: /* @__PURE__ */ jsx(
308
- Play,
309
- {
310
- className: "h-8 w-8",
311
- fill: "currentColor"
312
- }
313
- ) })
314
- ] }) })
315
- ]
316
- }
317
- )
318
- )
319
- }
320
- ),
317
+ /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden", style: aspectRatioStyle(), children: !modal && isPlaying ? (
318
+ // In-place video player
319
+ /* @__PURE__ */ jsx("div", { className: "w-full h-full", children: videoType !== "self-hosted" ? /* @__PURE__ */ jsx(
320
+ "iframe",
321
+ {
322
+ src: getEmbedUrl(),
323
+ className: "w-full h-full",
324
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
325
+ allowFullScreen: true
326
+ }
327
+ ) : /* @__PURE__ */ jsx(
328
+ "video",
329
+ {
330
+ src: videoUrl,
331
+ controls: true,
332
+ controlsList: "nodownload",
333
+ onContextMenu: (e) => e.preventDefault(),
334
+ autoPlay: true,
335
+ className: "w-full h-full",
336
+ children: "Your browser does not support the video tag."
337
+ }
338
+ ) })
339
+ ) : (
340
+ // Thumbnail with play button
341
+ /* @__PURE__ */ jsxs(
342
+ "div",
343
+ {
344
+ className: "cursor-pointer group w-full h-full",
345
+ onClick: handleThumbnailClick,
346
+ children: [
347
+ /* @__PURE__ */ jsx(
348
+ "img",
349
+ {
350
+ src: getThumbnailUrl() || "/placeholder.svg",
351
+ alt: `Thumbnail for ${title}`,
352
+ className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105"
353
+ }
354
+ ),
355
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/30 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
356
+ /* @__PURE__ */ jsx("span", { className: "absolute -inset-1.5 rounded-full bg-gray-200/50 animate-pulse duration-[3000ms]" }),
357
+ /* @__PURE__ */ jsx("div", { className: "relative z-1 rounded-full bg-primary p-4 text-primary-foreground", children: /* @__PURE__ */ jsx(Play, { className: "h-8 w-8", fill: "currentColor" }) })
358
+ ] }) })
359
+ ]
360
+ }
361
+ )
362
+ ) }),
321
363
  modal && isModalOpen && /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 bg-black/95 z-50 flex items-center justify-center p-4 sm:p-6 md:p-10", children: [
322
364
  /* @__PURE__ */ jsx(
323
365
  "button",
@@ -364,152 +406,80 @@ function VideoWithPreview({
364
406
  ] })
365
407
  ] });
366
408
  }
367
- var objectFitClass = {
368
- cover: "object-cover",
369
- contain: "object-contain",
370
- fill: "object-fill",
371
- none: "object-none",
372
- "scale-down": "object-scale-down"
373
- };
374
- var Image = (props) => {
375
- const {
376
- src,
377
- alt = "",
378
- defaultImage,
379
- loading = "lazy",
380
- noDefaultImage = false,
381
- className = "",
382
- classes = "",
383
- width = "w-full",
384
- height = "h-auto",
385
- objectFit = "cover"
386
- } = props;
387
- const source = src || defaultImage;
388
- if (!source) {
389
- if (noDefaultImage) return null;
390
- return /* @__PURE__ */ jsx(
391
- "div",
392
- {
393
- className: `relative ${width} ${height} aspect-video overflow-hidden bg-muted ${classes} ${className}`
394
- }
395
- );
396
- }
397
- return /* @__PURE__ */ jsx(
398
- "div",
399
- {
400
- className: `relative ${width} ${height} aspect-video overflow-hidden ${classes} ${className}`,
401
- children: /* @__PURE__ */ jsx(
402
- "img",
403
- {
404
- src: source,
405
- alt,
406
- loading,
407
- className: `absolute inset-0 h-full w-full ${objectFitClass[objectFit]}`
408
- }
409
- )
409
+ var HOISTED_LINK = /<link\b[^>]*(?:rel=["']?(?:preconnect|dns-prefetch|preload)|href=["'][^"']*fonts?\.)[^>]*>/gi;
410
+ function prepareEmbed(content) {
411
+ const links = content.match(HOISTED_LINK)?.join("") ?? "";
412
+ const markup = content.replace(HOISTED_LINK, "").replace(/<!doctype[^>]*>|<\/?(?:html|head|body)\b[^>]*>/gi, "").replace(
413
+ /<script\b[^>]*>(?:(?!<\/script>)[\s\S])*window\.parent[\s\S]*?<\/script>/gi,
414
+ ""
415
+ ).replace(
416
+ /<style\b([^>]*)>([\s\S]*?)<\/style>/gi,
417
+ (_, attrs, css) => {
418
+ const scoped = css.replace(/:root\b/g, ":host").replace(/(^|[\s,{}])html\.dark\b/g, "$1:host(.dark)").replace(/(^|[\s,{}])html(?=[\s,{:.[>~+])/g, "$1:host").replace(/(^|[\s,{}])body(?=[\s,{:.[>~+])/g, "$1[data-embed-body]").replace(/min-height\s*:\s*100d?vh/gi, "min-height:0").replace(/(\d*\.?\d+)vw\b/gi, "$1cqw").replace(
419
+ /@media\s+(?:only\s+)?(?:screen\s+and\s+)?(\([^{]*\bwidth\b[^{]*)\{/gi,
420
+ "@container $1{"
421
+ );
422
+ return `<style${attrs}>${scoped}</style>`;
410
423
  }
411
424
  );
412
- };
413
- var PageBuilderLinkContext = React2.createContext(null);
414
- function PageBuilderLinkProvider({
415
- component,
416
- children
417
- }) {
418
- return /* @__PURE__ */ jsx(PageBuilderLinkContext.Provider, { value: component ?? null, children });
419
- }
420
- function usePageBuilderLinkComponent() {
421
- return React2.useContext(PageBuilderLinkContext);
425
+ const body = `<style>:host{display:block;container-type:inline-size;overflow-x:clip}</style><div data-embed-body>${markup}</div>`;
426
+ return { links, body };
422
427
  }
423
- function NavLink({
424
- href,
425
- children,
426
- openInSameTab = true,
427
- style,
428
- className = "",
429
- onClick
430
- }) {
431
- const LinkComponent = usePageBuilderLinkComponent();
432
- const isInternal = Boolean(href && href.startsWith("/"));
433
- const isInPageNavigation = Boolean(href && href.startsWith("#"));
434
- const target = openInSameTab ? void 0 : "_blank";
435
- const rel = target === "_blank" ? "noopener noreferrer" : void 0;
436
- const handleClick = () => {
437
- onClick?.();
438
- };
439
- if (!isInPageNavigation && isInternal && LinkComponent) {
440
- return /* @__PURE__ */ jsx(
441
- LinkComponent,
442
- {
443
- href,
444
- style,
445
- className,
446
- onClick: handleClick,
447
- target,
448
- rel,
449
- children
450
- }
451
- );
428
+ function runScripts(root) {
429
+ for (const old of root.querySelectorAll("script")) {
430
+ const script = document.createElement("script");
431
+ for (const { name, value } of old.attributes) script.setAttribute(name, value);
432
+ script.textContent = old.textContent;
433
+ old.replaceWith(script);
452
434
  }
453
- return /* @__PURE__ */ jsx(
454
- "a",
455
- {
456
- href,
457
- style,
458
- className,
459
- target,
460
- rel,
461
- onClick: handleClick,
462
- children
463
- }
464
- );
465
435
  }
466
- function ThemeModeSwitcher({
467
- resolved,
468
- onToggle,
469
- theme,
470
- className,
471
- size,
472
- variant
473
- }) {
474
- const [mounted, setMounted] = useState(false);
436
+ var InlineEmbed = ({ content, className, style }) => {
437
+ const hostRef = useRef(null);
438
+ const appliedRef = useRef(null);
439
+ const { links, body } = prepareEmbed(content);
475
440
  useEffect(() => {
476
- setMounted(true);
477
- }, []);
478
- const painted = mounted ? resolved : "light";
479
- const next = painted === "dark" ? "light" : "dark";
480
- const label = next === "dark" ? "Switch to dark mode" : "Switch to light mode";
481
- const Icon = painted === "dark" ? Sun : Moon;
482
- if (theme) {
483
- return /* @__PURE__ */ jsx(
484
- Button2,
485
- {
486
- type: "button",
487
- variant: variant ?? "outline",
488
- size: size ?? "sm",
489
- theme,
490
- title: label,
491
- "aria-label": label,
492
- className,
493
- onClick: onToggle,
494
- children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" })
495
- }
441
+ const host = hostRef.current;
442
+ if (!host) return;
443
+ const root = host.shadowRoot ?? host.attachShadow({ mode: "open" });
444
+ if (appliedRef.current === body) return;
445
+ if (appliedRef.current !== null || !root.hasChildNodes()) {
446
+ root.innerHTML = body;
447
+ runScripts(root);
448
+ }
449
+ appliedRef.current = body;
450
+ }, [body]);
451
+ useEffect(() => {
452
+ const host = hostRef.current;
453
+ if (!host) return;
454
+ const sync = () => host.classList.toggle(
455
+ "dark",
456
+ !!host.parentElement?.closest(".dark") || document.documentElement.classList.contains("dark")
496
457
  );
497
- }
458
+ sync();
459
+ const observer = new MutationObserver(sync);
460
+ observer.observe(document.documentElement, {
461
+ attributes: true,
462
+ attributeFilter: ["class"],
463
+ subtree: true
464
+ });
465
+ return () => observer.disconnect();
466
+ }, []);
498
467
  return /* @__PURE__ */ jsx(
499
- Button,
468
+ "div",
500
469
  {
501
- type: "button",
502
- variant: "outline",
503
- size: "icon",
504
- title: label,
505
- "aria-label": label,
470
+ ref: hostRef,
506
471
  className,
507
- onClick: onToggle,
508
- children: /* @__PURE__ */ jsx(Icon, { className: "h-4 w-4" })
472
+ style,
473
+ suppressHydrationWarning: true,
474
+ dangerouslySetInnerHTML: {
475
+ // Only the HTML parser turns the template into a shadow root; on the
476
+ // client the effect attaches it instead.
477
+ __html: typeof window === "undefined" ? `${links}<template shadowrootmode="open">${body}</template>` : links
478
+ }
509
479
  }
510
480
  );
511
- }
481
+ };
512
482
 
513
- export { Image, NavLink, PageBuilderLinkProvider, SandboxedEmbed, ThemeModeSwitcher, VideoWithPreview, usePageBuilderLinkComponent };
514
- //# sourceMappingURL=chunk-7W6Q4WA7.js.map
515
- //# sourceMappingURL=chunk-7W6Q4WA7.js.map
483
+ export { Image, InlineEmbed, NavLink, PageBuilderLinkProvider, VideoWithPreview, prepareEmbed, roundedMap, setImageAttributesResolver, usePageBuilderLinkComponent };
484
+ //# sourceMappingURL=chunk-36QHCIPM.js.map
485
+ //# sourceMappingURL=chunk-36QHCIPM.js.map