@jbpark/live-editor 4.6.1 → 5.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 (81) hide show
  1. package/README.ko.md +2 -2
  2. package/README.md +2 -2
  3. package/dist/{boundary-BLB80tyw.js → boundary-6_nTsWxP.js} +2 -2
  4. package/dist/{boundary-BLB80tyw.js.map → boundary-6_nTsWxP.js.map} +1 -1
  5. package/dist/{compile-Dxas-D05.js → compile-DwOyWrmI.js} +8 -7
  6. package/dist/compile-DwOyWrmI.js.map +1 -0
  7. package/dist/constants-D-XKuEY2.js +58 -0
  8. package/dist/constants-D-XKuEY2.js.map +1 -0
  9. package/dist/{context-B8MzP7_p.js → context-DDR1xVKo.js} +3 -3
  10. package/dist/{context-B8MzP7_p.js.map → context-DDR1xVKo.js.map} +1 -1
  11. package/dist/{core-Bgfek364.js → core-CKazr4tT.js} +2 -2
  12. package/dist/core-CKazr4tT.js.map +1 -0
  13. package/dist/{detect-typescript-Dr_oLniM.js → detect-typescript-CoAO-QUJ.js} +2 -2
  14. package/dist/{detect-typescript-Dr_oLniM.js.map → detect-typescript-CoAO-QUJ.js.map} +1 -1
  15. package/dist/dnd/index.d.ts +2 -2
  16. package/dist/dnd/index.js +2 -2
  17. package/dist/{dnd-V8NAxd_R.js → dnd-BlC1gqUy.js} +2558 -867
  18. package/dist/dnd-BlC1gqUy.js.map +1 -0
  19. package/dist/document-BQhb7YR8.d.ts +17 -0
  20. package/dist/{document-CHO215iP.js → document-DcwIEHRV.js} +189 -104
  21. package/dist/document-DcwIEHRV.js.map +1 -0
  22. package/dist/editor/index.js +2 -2
  23. package/dist/{editor-CMElfHer.js → editor-Bty5XzpV.js} +2 -2
  24. package/dist/{editor-CMElfHer.js.map → editor-Bty5XzpV.js.map} +1 -1
  25. package/dist/error/index.d.ts +1 -1
  26. package/dist/error/index.js +2 -2
  27. package/dist/{error-CN_GCnXB.js → error-DyYx2NQ2.js} +17 -31
  28. package/dist/error-DyYx2NQ2.js.map +1 -0
  29. package/dist/{index-CiWB0zFb.d.ts → index-0VB5C3Jk.d.ts} +28 -50
  30. package/dist/{index-DpDU1IAw.d.ts → index-92L7F440.d.ts} +2 -2
  31. package/dist/index-C8h8TcIl.d.ts +15 -0
  32. package/dist/{index-DQkL37eL.d.ts → index-Cl79M7ZJ.d.ts} +6 -4
  33. package/dist/{index-CRwEhJ7w.d.ts → index-kKUjo9lr.d.ts} +2 -2
  34. package/dist/{index-DrWtSKXu.d.ts → index-tAiuHZsC.d.ts} +2 -2
  35. package/dist/index.d.ts +9 -9
  36. package/dist/index.js +6 -6
  37. package/dist/index.js.map +1 -1
  38. package/dist/{messages-CSrMI4Rm.js → messages-Bt5WXKTE.js} +5 -2
  39. package/dist/messages-Bt5WXKTE.js.map +1 -0
  40. package/dist/{messages-IBPs4TkZ.d.ts → messages-Yb3b7YJt.d.ts} +5 -2
  41. package/dist/preview/index.d.ts +1 -1
  42. package/dist/preview/index.js +2 -2
  43. package/dist/{preview-CtyG5UbH.js → preview-DC0pyOdu.js} +4 -4
  44. package/dist/preview-DC0pyOdu.js.map +1 -0
  45. package/dist/provider/index.d.ts +2 -2
  46. package/dist/provider/index.js +2 -2
  47. package/dist/{sections-jYuqS4KB.js → sections-4uirsXRU.js} +4 -7
  48. package/dist/sections-4uirsXRU.js.map +1 -0
  49. package/dist/style.css +776 -346
  50. package/dist/{validate-DB59Z_Nx.d.ts → types-Czps1Txy.d.ts} +12 -28
  51. package/dist/update-2PJbwoS8.d.ts +68 -0
  52. package/dist/{items-BXXtMUNI.js → update-DNInQSM7.js} +143 -392
  53. package/dist/update-DNInQSM7.js.map +1 -0
  54. package/dist/{use-dynamic-tailwind-BP1toJkW.js → use-dynamic-tailwind-CSYKXDmX.js} +301 -273
  55. package/dist/use-dynamic-tailwind-CSYKXDmX.js.map +1 -0
  56. package/dist/utils/ast/index.d.ts +47 -4
  57. package/dist/utils/ast/index.js +4 -64
  58. package/dist/utils/ast/index.js.map +1 -1
  59. package/dist/utils/index.d.ts +13 -32
  60. package/dist/utils/index.js +4 -26
  61. package/dist/validate-CZz30Pnb.js +122 -0
  62. package/dist/validate-CZz30Pnb.js.map +1 -0
  63. package/dist/validate-CiA1LF6S.d.ts +33 -0
  64. package/package.json +9 -9
  65. package/dist/compile-Dxas-D05.js.map +0 -1
  66. package/dist/constants-DU17Tdwo.js +0 -1459
  67. package/dist/constants-DU17Tdwo.js.map +0 -1
  68. package/dist/core-Bgfek364.js.map +0 -1
  69. package/dist/dnd-V8NAxd_R.js.map +0 -1
  70. package/dist/document-CHO215iP.js.map +0 -1
  71. package/dist/document-DqRSCtsx.d.ts +0 -1614
  72. package/dist/error-CN_GCnXB.js.map +0 -1
  73. package/dist/index-C_PfR4X9.d.ts +0 -734
  74. package/dist/items-BXXtMUNI.js.map +0 -1
  75. package/dist/messages-CSrMI4Rm.js.map +0 -1
  76. package/dist/preview-CtyG5UbH.js.map +0 -1
  77. package/dist/sections-jYuqS4KB.js.map +0 -1
  78. package/dist/use-dynamic-tailwind-BP1toJkW.js.map +0 -1
  79. package/dist/utils/index.js.map +0 -1
  80. package/dist/validate-iLo8IONY.js +0 -64
  81. package/dist/validate-iLo8IONY.js.map +0 -1
@@ -1,26 +1,12 @@
1
- import { i as useLiveMessages } from "./messages-CSrMI4Rm.js";
2
- import { n as compile, s as withScriptBlobs } from "./compile-Dxas-D05.js";
1
+ import { i as useLiveMessages } from "./messages-Bt5WXKTE.js";
2
+ import { i as withScriptBlobs, n as compile } from "./compile-DwOyWrmI.js";
3
3
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
+ import { useDebouncedCallback, useEventListener, useMutationObserver, useResizeObserver, useStableValue } from "@jbpark/use-hooks";
5
6
  import * as ui from "@jbpark/ui-kit";
6
- import { useEventListener, useMutationObserver, useResizeObserver } from "@jbpark/use-hooks";
7
7
  import { createPortal } from "react-dom";
8
8
  import * as utils from "@jbpark/ui-kit/utils";
9
- //#region src/components/preview/use-stable-modules.ts
10
- const sameModules = (a, b) => {
11
- if (a === b) return true;
12
- if (!a || !b) return false;
13
- const keys = Object.keys(a);
14
- return keys.length === Object.keys(b).length && keys.every((key) => Object.hasOwn(b, key) && Object.is(a[key], b[key]));
15
- };
16
- const useStableModules = (modules) => {
17
- const [stable, setStable] = useState(modules);
18
- if (sameModules(stable, modules)) return stable;
19
- setStable(modules);
20
- return modules;
21
- };
22
- //#endregion
23
- //#region src/components/frame/measure.ts
9
+ //#region src/components/frame/auto-height/measure.ts
24
10
  const verticalInsets = (style) => [
25
11
  style.marginTop,
26
12
  style.marginBottom,
@@ -40,85 +26,13 @@ const positionedElementBottom = (top, bottom, probeHeight) => {
40
26
  return Math.min(bottom, probeHeight);
41
27
  };
42
28
  //#endregion
43
- //#region src/components/frame/style-sync.ts
44
- const SYNCED_STYLE_ATTR = "data-live-editor-synced-style";
45
- const createStyleSyncManager = () => ({ clones: /* @__PURE__ */ new Map() });
46
- const isDocument = (target) => target.nodeType === Node.DOCUMENT_NODE;
47
- const sourceStyles = (document) => Array.from(document.head.querySelectorAll("link[rel=\"stylesheet\"], style"));
48
- const copyAttributes = (source, clone, transformStyle) => {
49
- Array.from(clone.attributes).forEach((attribute) => {
50
- if (attribute.name !== SYNCED_STYLE_ATTR && !source.hasAttribute(attribute.name)) clone.removeAttribute(attribute.name);
51
- });
52
- Array.from(source.attributes).forEach((attribute) => {
53
- clone.setAttribute(attribute.name, attribute.value);
54
- });
55
- if (source.tagName === "LINK" && clone.tagName === "LINK") clone.disabled = source.disabled;
56
- clone.textContent = source.tagName === "STYLE" ? transformStyle(source.textContent || "") : source.textContent;
57
- };
58
- const createClone = (source, target, transformStyle) => {
59
- const clone = (isDocument(target) ? target : target.ownerDocument).createElement(source.tagName.toLowerCase());
60
- clone.setAttribute(SYNCED_STYLE_ATTR, "");
61
- copyAttributes(source, clone, transformStyle);
62
- return clone;
63
- };
64
- const targetContainer = (target) => isDocument(target) ? target.head : target;
65
- const isSyncedStyle = (node) => {
66
- const element = node;
67
- return (element.tagName === "LINK" || element.tagName === "STYLE") && element.hasAttribute(SYNCED_STYLE_ATTR);
68
- };
69
- const removeClone = (clone) => {
70
- clone.remove();
71
- };
72
- const reconcileStyles = (sourceDocument, target, manager, enabled, transformStyle = (content) => content, anchor = null) => {
73
- if (!enabled) {
74
- manager.clones.forEach(removeClone);
75
- manager.clones.clear();
76
- return;
77
- }
78
- const sources = sourceStyles(sourceDocument);
79
- const sourceSet = new Set(sources);
80
- const container = targetContainer(target);
81
- manager.clones.forEach((clone, source) => {
82
- if (!sourceSet.has(source)) {
83
- removeClone(clone);
84
- manager.clones.delete(source);
85
- }
86
- });
87
- let previous = null;
88
- sources.forEach((source) => {
89
- let clone = manager.clones.get(source);
90
- if (!clone) {
91
- clone = createClone(source, target, transformStyle);
92
- manager.clones.set(source, clone);
93
- } else copyAttributes(source, clone, transformStyle);
94
- const nextSibling = previous ? previous.nextSibling : Array.from(container.childNodes).find(isSyncedStyle) ?? (anchor?.parentNode === container ? anchor : null);
95
- if (clone !== nextSibling) container.insertBefore(clone, nextSibling);
96
- previous = clone;
97
- });
98
- };
99
- const createRootAttributeSync = () => ({
100
- attributes: /* @__PURE__ */ new Set(),
101
- classes: /* @__PURE__ */ new Set()
102
- });
103
- const isMirroredAttribute = (name) => name.startsWith("data-");
104
- const reconcileRootAttributes = (source, target, sync, enabled) => {
105
- const attributes = enabled ? Array.from(source.attributes).filter(({ name }) => isMirroredAttribute(name)) : [];
106
- const classes = enabled ? Array.from(source.classList) : [];
107
- const attributeNames = new Set(attributes.map(({ name }) => name));
108
- const classNames = new Set(classes);
109
- sync.attributes.forEach((name) => {
110
- if (!attributeNames.has(name)) target.removeAttribute(name);
111
- });
112
- attributes.forEach(({ name, value }) => {
113
- if (target.getAttribute(name) !== value) target.setAttribute(name, value);
114
- });
115
- sync.classes.forEach((name) => {
116
- if (!classNames.has(name)) target.classList.remove(name);
117
- });
118
- classes.forEach((name) => target.classList.add(name));
119
- if (!target.classList.length) target.removeAttribute("class");
120
- sync.attributes = attributeNames;
121
- sync.classes = classNames;
29
+ //#region src/components/frame/auto-height/animations.ts
30
+ const isCssAnimation = (win, animation) => typeof win.CSSAnimation === "function" && animation instanceof win.CSSAnimation;
31
+ const isCssTransition = (win, animation) => typeof win.CSSTransition === "function" && animation instanceof win.CSSTransition;
32
+ const hasActiveAnimation = (el) => typeof el.getAnimations === "function" && el.getAnimations().some((animation) => isAnimationActive(animation.playState));
33
+ const neverFinishes = (animation) => {
34
+ const timing = animation.effect?.getComputedTiming();
35
+ return timing?.iterations === Infinity || timing?.duration === Infinity;
122
36
  };
123
37
  //#endregion
124
38
  //#region src/components/frame/viewport-units.ts
@@ -148,16 +62,8 @@ const rewriteInlineViewportUnits = (root) => {
148
62
  });
149
63
  };
150
64
  //#endregion
151
- //#region src/components/frame/iframe.tsx
65
+ //#region src/components/frame/auto-height/auto-height.ts
152
66
  const CONTAINER_STYLE_ID = "autoheight-container";
153
- const EMPTY_STRING_ARRAY = [];
154
- const isCssAnimation = (win, animation) => typeof win.CSSAnimation === "function" && animation instanceof win.CSSAnimation;
155
- const isCssTransition = (win, animation) => typeof win.CSSTransition === "function" && animation instanceof win.CSSTransition;
156
- const hasActiveAnimation = (el) => typeof el.getAnimations === "function" && el.getAnimations().some((animation) => isAnimationActive(animation.playState));
157
- const neverFinishes = (animation) => {
158
- const timing = animation.effect?.getComputedTiming();
159
- return timing?.iterations === Infinity || timing?.duration === Infinity;
160
- };
161
67
  const MEASUREMENT_OVERRIDE_STYLE_ID = "autoheight-measurement-overrides";
162
68
  const SCROLLBAR_OVERRIDE_RULES = ["html, body { scrollbar-width: none !important; }", "html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }"];
163
69
  const FREEZE_TRANSITIONS_RULE = "*, *::before, *::after { transition: none !important; }";
@@ -175,130 +81,54 @@ const withMeasurementOverrides = (doc, freezeTransitions, measure) => {
175
81
  measure();
176
82
  styleEl.media = "not all";
177
83
  };
178
- const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_STRING_ARRAY, styles = EMPTY_STRING_ARRAY, stylesheets = EMPTY_STRING_ARRAY, autoHeight = false, syncStyle = false, children, onLoaded, ...props }) => {
179
- const iframeRef = useRef(null);
180
- const [mountNode, setMountNode] = useState(null);
181
- const loadedScriptsRef = useRef(/* @__PURE__ */ new Set());
182
- const loadedScriptsDocRef = useRef(null);
183
- const prevStyleCountRef = useRef(0);
184
- const prevStylesheetCountRef = useRef(0);
84
+ const HIDE_SCROLLBAR_STYLE_ID = "autoheight-hide-scrollbar";
85
+ const ensureContainerStyle = (doc, probeHeight) => {
86
+ let styleEl = doc.getElementById(CONTAINER_STYLE_ID);
87
+ if (!styleEl) {
88
+ styleEl = doc.createElement("style");
89
+ styleEl.id = CONTAINER_STYLE_ID;
90
+ doc.head?.appendChild(styleEl);
91
+ }
92
+ const text = `html { container-type: size !important; height: ${probeHeight}px !important; }`;
93
+ if (styleEl.textContent !== text) styleEl.textContent = text;
94
+ };
95
+ const getProbeHeight = (iframe, win) => {
96
+ const scrollParent = iframe.closest("[data-frame-container]");
97
+ if (!scrollParent) return 812;
98
+ const scrollParentStyle = win.getComputedStyle(scrollParent);
99
+ let wrapperInsets = (parseFloat(scrollParentStyle.paddingTop) || 0) + (parseFloat(scrollParentStyle.paddingBottom) || 0);
100
+ let node = iframe;
101
+ while (node && node !== scrollParent) {
102
+ wrapperInsets += verticalInsets(win.getComputedStyle(node));
103
+ node = node.parentElement;
104
+ }
105
+ return computeProbeHeight(scrollParent.clientHeight, wrapperInsets);
106
+ };
107
+ const measureContentHeight = (mountNode, doc, win, probeHeight, freezeTransitions) => {
108
+ let contentHeight = 0;
109
+ withMeasurementOverrides(doc, freezeTransitions, () => {
110
+ ensureContainerStyle(doc, probeHeight);
111
+ rewriteInlineViewportUnits(mountNode);
112
+ contentHeight = mountNode.scrollHeight;
113
+ mountNode.querySelectorAll("*").forEach((el) => {
114
+ const style = win.getComputedStyle(el);
115
+ const isAnimating = style.opacity === "0" && hasActiveAnimation(el);
116
+ if (isVisuallyHidden(style, isAnimating)) return;
117
+ if ((style.position === "fixed" || style.position === "absolute") && el.offsetHeight > 0) {
118
+ const rect = el.getBoundingClientRect();
119
+ const bottom = positionedElementBottom(rect.top, rect.bottom, probeHeight);
120
+ if (bottom !== null) contentHeight = Math.max(contentHeight, bottom);
121
+ }
122
+ });
123
+ });
124
+ return contentHeight;
125
+ };
126
+ //#endregion
127
+ //#region src/components/frame/auto-height/use-auto-height.ts
128
+ const useAutoHeight = (iframeRef, mountNode, shouldAutoHeight) => {
185
129
  const trackedAnimationsRef = useRef(/* @__PURE__ */ new WeakSet());
186
130
  const updateHeightRef = useRef(null);
187
131
  const lastProbeHeightRef = useRef(void 0);
188
- const shouldAutoHeight = autoHeight && style.height == null;
189
- const styleManagerRef = useRef(createStyleSyncManager());
190
- const rootAttributeSyncRef = useRef(createRootAttributeSync());
191
- const applyStyle = useCallback(() => {
192
- const doc = iframeRef.current?.contentDocument;
193
- if (!doc) return;
194
- reconcileStyles(document, doc, styleManagerRef.current, syncStyle, convertViewportUnits, doc.getElementById(CONTAINER_STYLE_ID));
195
- reconcileRootAttributes(document.documentElement, doc.documentElement, rootAttributeSyncRef.current, syncStyle);
196
- }, [syncStyle]);
197
- const applyStyleTimeoutRef = useRef(void 0);
198
- const debouncedApplyStyle = useCallback(() => {
199
- clearTimeout(applyStyleTimeoutRef.current);
200
- applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);
201
- }, [applyStyle]);
202
- useEffect(() => {
203
- return () => clearTimeout(applyStyleTimeoutRef.current);
204
- }, []);
205
- useMutationObserver(document.head, debouncedApplyStyle, {
206
- enabled: syncStyle,
207
- childList: true,
208
- subtree: true,
209
- attributes: true
210
- });
211
- useMutationObserver(document.documentElement, debouncedApplyStyle, {
212
- enabled: syncStyle,
213
- attributes: true
214
- });
215
- useEffect(() => {
216
- const $iframe = iframeRef.current;
217
- if (!$iframe) return;
218
- const onLoad = () => {
219
- const doc = $iframe.contentDocument;
220
- if (!doc) return;
221
- if (loadedScriptsDocRef.current !== doc) {
222
- loadedScriptsDocRef.current = doc;
223
- loadedScriptsRef.current = /* @__PURE__ */ new Set();
224
- }
225
- doc.body.style.overflowX = "hidden";
226
- doc.body.style.margin = "0";
227
- let node = doc.getElementById("iframe-root");
228
- if (!node) {
229
- node = doc.createElement("div");
230
- node.id = "iframe-root";
231
- doc.body.appendChild(node);
232
- }
233
- setMountNode(node);
234
- applyStyle();
235
- const pendingScripts = scripts.filter((src) => !loadedScriptsRef.current.has(src));
236
- if (pendingScripts.length) {
237
- pendingScripts.forEach((src) => loadedScriptsRef.current.add(src));
238
- withScriptBlobs(pendingScripts, (blobUrls) => {
239
- if (!doc.head) return;
240
- const fragment = doc.createDocumentFragment();
241
- blobUrls.forEach((blobUrl) => {
242
- const script = doc.createElement("script");
243
- script.src = blobUrl;
244
- fragment.appendChild(script);
245
- });
246
- doc.head.appendChild(fragment);
247
- });
248
- }
249
- onLoaded?.();
250
- };
251
- $iframe.addEventListener("load", onLoad);
252
- if ($iframe.contentDocument?.readyState === "complete") onLoad();
253
- return () => {
254
- $iframe.removeEventListener("load", onLoad);
255
- };
256
- }, [
257
- scripts,
258
- onLoaded,
259
- applyStyle
260
- ]);
261
- useEffect(() => {
262
- const doc = iframeRef.current?.contentDocument;
263
- if (!doc?.head) return;
264
- styles.forEach((css, index) => {
265
- const styleId = `injected-style-${index}`;
266
- let styleEl = doc.getElementById(styleId);
267
- if (!styleEl) {
268
- styleEl = doc.createElement("style");
269
- styleEl.id = styleId;
270
- doc.head.appendChild(styleEl);
271
- }
272
- const convertedCss = convertViewportUnits(css);
273
- if (styleEl.textContent !== convertedCss) styleEl.textContent = convertedCss;
274
- });
275
- for (let index = styles.length; index < prevStyleCountRef.current; index++) doc.getElementById(`injected-style-${index}`)?.remove();
276
- prevStyleCountRef.current = styles.length;
277
- stylesheets.forEach((href, index) => {
278
- const linkId = `injected-stylesheet-${index}`;
279
- let linkEl = doc.getElementById(linkId);
280
- if (!linkEl) {
281
- linkEl = doc.createElement("link");
282
- linkEl.id = linkId;
283
- linkEl.rel = "stylesheet";
284
- doc.head.appendChild(linkEl);
285
- }
286
- if (linkEl.href !== href) linkEl.href = href;
287
- });
288
- for (let index = stylesheets.length; index < prevStylesheetCountRef.current; index++) doc.getElementById(`injected-stylesheet-${index}`)?.remove();
289
- prevStylesheetCountRef.current = stylesheets.length;
290
- }, [styles, stylesheets]);
291
- const HIDE_SCROLLBAR_STYLE_ID = "autoheight-hide-scrollbar";
292
- const ensureContainerStyle = (doc, probeHeight) => {
293
- let styleEl = doc.getElementById(CONTAINER_STYLE_ID);
294
- if (!styleEl) {
295
- styleEl = doc.createElement("style");
296
- styleEl.id = CONTAINER_STYLE_ID;
297
- doc.head?.appendChild(styleEl);
298
- }
299
- const text = `html { container-type: size !important; height: ${probeHeight}px !important; }`;
300
- if (styleEl.textContent !== text) styleEl.textContent = text;
301
- };
302
132
  const trackScriptAnimations = useCallback((doc, win) => {
303
133
  if (typeof doc.getAnimations !== "function") return;
304
134
  doc.getAnimations().forEach((animation) => {
@@ -313,44 +143,17 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
313
143
  const doc = iframe.contentDocument;
314
144
  const win = doc?.defaultView;
315
145
  if (!doc || !win) return;
316
- const scrollParent = iframe.closest("[data-frame-container]");
317
- let probeHeight;
318
- if (!scrollParent) probeHeight = 812;
319
- else {
320
- const scrollParentStyle = win.getComputedStyle(scrollParent);
321
- let wrapperInsets = (parseFloat(scrollParentStyle.paddingTop) || 0) + (parseFloat(scrollParentStyle.paddingBottom) || 0);
322
- let node = iframe;
323
- while (node && node !== scrollParent) {
324
- wrapperInsets += verticalInsets(win.getComputedStyle(node));
325
- node = node.parentElement;
326
- }
327
- const computed = computeProbeHeight(scrollParent.clientHeight, wrapperInsets);
328
- if (computed === null) return;
329
- probeHeight = computed;
330
- }
331
- let contentHeight = 0;
146
+ const probeHeight = getProbeHeight(iframe, win);
147
+ if (probeHeight === null) return;
332
148
  const freezeTransitions = probeHeight !== lastProbeHeightRef.current;
333
149
  lastProbeHeightRef.current = probeHeight;
334
150
  const previousHeight = iframe.style.height;
335
151
  iframe.style.height = `${probeHeight}px`;
336
- withMeasurementOverrides(doc, freezeTransitions, () => {
337
- ensureContainerStyle(doc, probeHeight);
338
- rewriteInlineViewportUnits(mountNode);
339
- contentHeight = mountNode.scrollHeight;
340
- mountNode.querySelectorAll("*").forEach((el) => {
341
- const style = win.getComputedStyle(el);
342
- const isAnimating = style.opacity === "0" && hasActiveAnimation(el);
343
- if (isVisuallyHidden(style, isAnimating)) return;
344
- if ((style.position === "fixed" || style.position === "absolute") && el.offsetHeight > 0) {
345
- const rect = el.getBoundingClientRect();
346
- const bottom = positionedElementBottom(rect.top, rect.bottom, probeHeight);
347
- if (bottom !== null) contentHeight = Math.max(contentHeight, bottom);
348
- }
349
- });
350
- });
152
+ const contentHeight = measureContentHeight(mountNode, doc, win, probeHeight, freezeTransitions);
351
153
  iframe.style.height = contentHeight > 0 ? `${Math.ceil(contentHeight)}px` : previousHeight;
352
154
  trackScriptAnimations(doc, win);
353
155
  }, [
156
+ iframeRef,
354
157
  shouldAutoHeight,
355
158
  mountNode,
356
159
  trackScriptAnimations
@@ -361,13 +164,17 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
361
164
  useEffect(() => {
362
165
  if (shouldAutoHeight) return;
363
166
  iframeRef.current?.contentDocument?.getElementById(CONTAINER_STYLE_ID)?.remove();
364
- }, [shouldAutoHeight]);
167
+ }, [iframeRef, shouldAutoHeight]);
365
168
  useEffect(() => {
366
169
  const body = iframeRef.current?.contentDocument?.body;
367
170
  if (!body || !mountNode) return;
368
171
  if (shouldAutoHeight) body.style.removeProperty("overflow-y");
369
172
  else body.style.setProperty("overflow-y", "auto");
370
- }, [shouldAutoHeight, mountNode]);
173
+ }, [
174
+ iframeRef,
175
+ shouldAutoHeight,
176
+ mountNode
177
+ ]);
371
178
  useEffect(() => {
372
179
  const doc = iframeRef.current?.contentDocument;
373
180
  if (!doc?.head) return;
@@ -379,9 +186,13 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
379
186
  if (existing) return;
380
187
  const styleEl = doc.createElement("style");
381
188
  styleEl.id = HIDE_SCROLLBAR_STYLE_ID;
382
- styleEl.textContent = ["html, body { scrollbar-width: none !important; }", "html::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important; }"].join("\n");
189
+ styleEl.textContent = SCROLLBAR_OVERRIDE_RULES.join("\n");
383
190
  doc.head.appendChild(styleEl);
384
- }, [shouldAutoHeight, mountNode]);
191
+ }, [
192
+ iframeRef,
193
+ shouldAutoHeight,
194
+ mountNode
195
+ ]);
385
196
  useEffect(() => {
386
197
  updateHeight();
387
198
  }, [updateHeight]);
@@ -423,6 +234,227 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
423
234
  target: mountNodeRef,
424
235
  enabled: settleListenerEnabled
425
236
  });
237
+ };
238
+ //#endregion
239
+ //#region src/components/frame/iframe/inject-assets.ts
240
+ const syncInjectedElements = (doc, idPrefix, values, previousCount, create, update) => {
241
+ values.forEach((value, index) => {
242
+ const id = `${idPrefix}${index}`;
243
+ let el = doc.getElementById(id);
244
+ if (!el) {
245
+ el = create();
246
+ el.id = id;
247
+ doc.head.appendChild(el);
248
+ }
249
+ update(el, value);
250
+ });
251
+ for (let index = values.length; index < previousCount; index++) doc.getElementById(`${idPrefix}${index}`)?.remove();
252
+ };
253
+ const syncInjectedAssets = (doc, styles, stylesheets, previous) => {
254
+ syncInjectedElements(doc, "injected-style-", styles, previous.styles, () => doc.createElement("style"), (styleEl, css) => {
255
+ const convertedCss = convertViewportUnits(css);
256
+ if (styleEl.textContent !== convertedCss) styleEl.textContent = convertedCss;
257
+ });
258
+ syncInjectedElements(doc, "injected-stylesheet-", stylesheets, previous.stylesheets, () => {
259
+ const linkEl = doc.createElement("link");
260
+ linkEl.rel = "stylesheet";
261
+ return linkEl;
262
+ }, (linkEl, href) => {
263
+ if (linkEl.href !== href) linkEl.href = href;
264
+ });
265
+ return {
266
+ styles: styles.length,
267
+ stylesheets: stylesheets.length
268
+ };
269
+ };
270
+ //#endregion
271
+ //#region src/components/frame/style-sync.ts
272
+ const SYNCED_STYLE_ATTR = "data-live-editor-synced-style";
273
+ const createStyleSyncManager = () => ({ clones: /* @__PURE__ */ new Map() });
274
+ const isDocument = (target) => target.nodeType === Node.DOCUMENT_NODE;
275
+ const sourceStyles = (document) => Array.from(document.head.querySelectorAll("link[rel=\"stylesheet\"], style"));
276
+ const copyAttributes = (source, clone, transformStyle) => {
277
+ Array.from(clone.attributes).forEach((attribute) => {
278
+ if (attribute.name !== SYNCED_STYLE_ATTR && !source.hasAttribute(attribute.name)) clone.removeAttribute(attribute.name);
279
+ });
280
+ Array.from(source.attributes).forEach((attribute) => {
281
+ clone.setAttribute(attribute.name, attribute.value);
282
+ });
283
+ if (source.tagName === "LINK" && clone.tagName === "LINK") clone.disabled = source.disabled;
284
+ clone.textContent = source.tagName === "STYLE" ? transformStyle(source.textContent || "") : source.textContent;
285
+ };
286
+ const createClone = (source, target, transformStyle) => {
287
+ const clone = (isDocument(target) ? target : target.ownerDocument).createElement(source.tagName.toLowerCase());
288
+ clone.setAttribute(SYNCED_STYLE_ATTR, "");
289
+ copyAttributes(source, clone, transformStyle);
290
+ return clone;
291
+ };
292
+ const targetContainer = (target) => isDocument(target) ? target.head : target;
293
+ const isSyncedStyle = (node) => {
294
+ const element = node;
295
+ return (element.tagName === "LINK" || element.tagName === "STYLE") && element.hasAttribute(SYNCED_STYLE_ATTR);
296
+ };
297
+ const removeClone = (clone) => {
298
+ clone.remove();
299
+ };
300
+ const reconcileStyles = (sourceDocument, target, manager, enabled, transformStyle = (content) => content, anchor = null) => {
301
+ if (!enabled) {
302
+ manager.clones.forEach(removeClone);
303
+ manager.clones.clear();
304
+ return;
305
+ }
306
+ const sources = sourceStyles(sourceDocument);
307
+ const sourceSet = new Set(sources);
308
+ const container = targetContainer(target);
309
+ manager.clones.forEach((clone, source) => {
310
+ if (!sourceSet.has(source)) {
311
+ removeClone(clone);
312
+ manager.clones.delete(source);
313
+ }
314
+ });
315
+ let previous = null;
316
+ sources.forEach((source) => {
317
+ let clone = manager.clones.get(source);
318
+ if (!clone) {
319
+ clone = createClone(source, target, transformStyle);
320
+ manager.clones.set(source, clone);
321
+ } else copyAttributes(source, clone, transformStyle);
322
+ const nextSibling = previous ? previous.nextSibling : Array.from(container.childNodes).find(isSyncedStyle) ?? (anchor?.parentNode === container ? anchor : null);
323
+ if (clone !== nextSibling) container.insertBefore(clone, nextSibling);
324
+ previous = clone;
325
+ });
326
+ };
327
+ const createRootAttributeSync = () => ({
328
+ attributes: /* @__PURE__ */ new Set(),
329
+ classes: /* @__PURE__ */ new Set()
330
+ });
331
+ const isMirroredAttribute = (name) => name.startsWith("data-");
332
+ const reconcileRootAttributes = (source, target, sync, enabled) => {
333
+ const attributes = enabled ? Array.from(source.attributes).filter(({ name }) => isMirroredAttribute(name)) : [];
334
+ const classes = enabled ? Array.from(source.classList) : [];
335
+ const attributeNames = new Set(attributes.map(({ name }) => name));
336
+ const classNames = new Set(classes);
337
+ sync.attributes.forEach((name) => {
338
+ if (!attributeNames.has(name)) target.removeAttribute(name);
339
+ });
340
+ attributes.forEach(({ name, value }) => {
341
+ if (target.getAttribute(name) !== value) target.setAttribute(name, value);
342
+ });
343
+ sync.classes.forEach((name) => {
344
+ if (!classNames.has(name)) target.classList.remove(name);
345
+ });
346
+ classes.forEach((name) => target.classList.add(name));
347
+ if (!target.classList.length) target.removeAttribute("class");
348
+ sync.attributes = attributeNames;
349
+ sync.classes = classNames;
350
+ };
351
+ //#endregion
352
+ //#region src/components/frame/iframe/use-host-style-sync.ts
353
+ const useHostStyleSync = (iframeRef, syncStyle) => {
354
+ const styleManagerRef = useRef(createStyleSyncManager());
355
+ const rootAttributeSyncRef = useRef(createRootAttributeSync());
356
+ const applyStyle = useCallback(() => {
357
+ const doc = iframeRef.current?.contentDocument;
358
+ if (!doc) return;
359
+ reconcileStyles(document, doc, styleManagerRef.current, syncStyle, convertViewportUnits, doc.getElementById(CONTAINER_STYLE_ID));
360
+ reconcileRootAttributes(document.documentElement, doc.documentElement, rootAttributeSyncRef.current, syncStyle);
361
+ }, [iframeRef, syncStyle]);
362
+ const debouncedApplyStyle = useDebouncedCallback(applyStyle, {
363
+ delay: 50,
364
+ autoInvoke: false
365
+ });
366
+ useMutationObserver(document.head, debouncedApplyStyle, {
367
+ enabled: syncStyle,
368
+ childList: true,
369
+ subtree: true,
370
+ attributes: true
371
+ });
372
+ useMutationObserver(document.documentElement, debouncedApplyStyle, {
373
+ enabled: syncStyle,
374
+ attributes: true
375
+ });
376
+ return applyStyle;
377
+ };
378
+ //#endregion
379
+ //#region src/components/frame/iframe/use-iframe-document.ts
380
+ const injectScripts = (doc, srcs) => {
381
+ withScriptBlobs(srcs, (blobUrls) => {
382
+ if (!doc.head) return;
383
+ const fragment = doc.createDocumentFragment();
384
+ blobUrls.forEach((blobUrl) => {
385
+ const script = doc.createElement("script");
386
+ script.src = blobUrl;
387
+ fragment.appendChild(script);
388
+ });
389
+ doc.head.appendChild(fragment);
390
+ });
391
+ };
392
+ const useIframeDocument = (iframeRef, { scripts, onLoaded, applyStyle }) => {
393
+ const [mountNode, setMountNode] = useState(null);
394
+ const loadedScriptsRef = useRef(/* @__PURE__ */ new Set());
395
+ const loadedScriptsDocRef = useRef(null);
396
+ useEffect(() => {
397
+ const $iframe = iframeRef.current;
398
+ if (!$iframe) return;
399
+ const onLoad = () => {
400
+ const doc = $iframe.contentDocument;
401
+ if (!doc) return;
402
+ if (loadedScriptsDocRef.current !== doc) {
403
+ loadedScriptsDocRef.current = doc;
404
+ loadedScriptsRef.current = /* @__PURE__ */ new Set();
405
+ }
406
+ doc.body.style.overflowX = "hidden";
407
+ doc.body.style.margin = "0";
408
+ let node = doc.getElementById("iframe-root");
409
+ if (!node) {
410
+ node = doc.createElement("div");
411
+ node.id = "iframe-root";
412
+ doc.body.appendChild(node);
413
+ }
414
+ setMountNode(node);
415
+ applyStyle();
416
+ const pendingScripts = scripts.filter((src) => !loadedScriptsRef.current.has(src));
417
+ if (pendingScripts.length) {
418
+ pendingScripts.forEach((src) => loadedScriptsRef.current.add(src));
419
+ injectScripts(doc, pendingScripts);
420
+ }
421
+ onLoaded?.();
422
+ };
423
+ $iframe.addEventListener("load", onLoad);
424
+ if ($iframe.contentDocument?.readyState === "complete") onLoad();
425
+ return () => {
426
+ $iframe.removeEventListener("load", onLoad);
427
+ };
428
+ }, [
429
+ iframeRef,
430
+ scripts,
431
+ onLoaded,
432
+ applyStyle
433
+ ]);
434
+ return mountNode;
435
+ };
436
+ //#endregion
437
+ //#region src/components/frame/iframe/iframe.tsx
438
+ const EMPTY_STRING_ARRAY = [];
439
+ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_STRING_ARRAY, styles = EMPTY_STRING_ARRAY, stylesheets = EMPTY_STRING_ARRAY, autoHeight = false, syncStyle = false, children, onLoaded, ...props }) => {
440
+ const iframeRef = useRef(null);
441
+ const shouldAutoHeight = autoHeight && style.height == null;
442
+ const applyStyle = useHostStyleSync(iframeRef, syncStyle);
443
+ const mountNode = useIframeDocument(iframeRef, {
444
+ scripts,
445
+ onLoaded,
446
+ applyStyle
447
+ });
448
+ const injectedCountsRef = useRef({
449
+ styles: 0,
450
+ stylesheets: 0
451
+ });
452
+ useEffect(() => {
453
+ const doc = iframeRef.current?.contentDocument;
454
+ if (!doc?.head) return;
455
+ injectedCountsRef.current = syncInjectedAssets(doc, styles, stylesheets, injectedCountsRef.current);
456
+ }, [styles, stylesheets]);
457
+ useAutoHeight(iframeRef, mountNode, shouldAutoHeight);
426
458
  const content = mountNode ? createPortal(children(mountNode), mountNode) : null;
427
459
  return /* @__PURE__ */ jsx("iframe", {
428
460
  ref: iframeRef,
@@ -480,14 +512,10 @@ const Shadow = ({ syncStyle = false, children }) => {
480
512
  if (!shadowRoot) return;
481
513
  reconcileStyles(document, shadowRoot, styleManagerRef.current, syncStyle);
482
514
  }, [syncStyle]);
483
- const applyStyleTimeoutRef = useRef(void 0);
484
- const debouncedApplyStyle = useCallback(() => {
485
- clearTimeout(applyStyleTimeoutRef.current);
486
- applyStyleTimeoutRef.current = window.setTimeout(applyStyle, 50);
487
- }, [applyStyle]);
488
- useEffect(() => {
489
- return () => clearTimeout(applyStyleTimeoutRef.current);
490
- }, []);
515
+ const debouncedApplyStyle = useDebouncedCallback(applyStyle, {
516
+ delay: 50,
517
+ autoInvoke: false
518
+ });
491
519
  useMutationObserver(document.head, debouncedApplyStyle, {
492
520
  enabled: syncStyle,
493
521
  childList: true,
@@ -542,7 +570,7 @@ const baseModules = {
542
570
  //#endregion
543
571
  //#region src/components/preview/use-compiled-module.ts
544
572
  const useCompiledModule = (code, _modules) => {
545
- const modules = useStableModules(_modules);
573
+ const modules = useStableValue(_modules);
546
574
  const { unknown } = useLiveMessages().errors;
547
575
  const mergedModules = useMemo(() => ({
548
576
  ...baseModules,
@@ -592,6 +620,6 @@ const useDynamicTailwind = (code, enabled) => {
592
620
  };
593
621
  };
594
622
  //#endregion
595
- export { useStableModules as a, Frame as i, useCompiledModule as n, baseModules as r, useDynamicTailwind as t };
623
+ export { Frame as i, useCompiledModule as n, baseModules as r, useDynamicTailwind as t };
596
624
 
597
- //# sourceMappingURL=use-dynamic-tailwind-BP1toJkW.js.map
625
+ //# sourceMappingURL=use-dynamic-tailwind-CSYKXDmX.js.map