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