@jbpark/live-editor 1.7.0 → 1.8.1

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.
package/dist/index.d.mts CHANGED
@@ -49,6 +49,7 @@ interface Props$6 {
49
49
  children: React$1.ReactNode;
50
50
  fallback?: (message?: string) => React$1.ReactNode;
51
51
  onError?: (e: Error, info: React$1.ErrorInfo) => void;
52
+ resetKeys?: readonly unknown[];
52
53
  }
53
54
  interface State {
54
55
  hasError: boolean;
@@ -58,6 +59,7 @@ declare class ErrorBoundary extends React$1.Component<Props$6, State> {
58
59
  constructor(props: Props$6);
59
60
  static getDerivedStateFromError(error: Error): State;
60
61
  componentDidCatch(error: Error, errorInfo: React$1.ErrorInfo): void;
62
+ componentDidUpdate(prevProps: Props$6): void;
61
63
  render(): string | number | bigint | boolean | react_jsx_runtime0.JSX.Element | Iterable<React$1.ReactNode> | Promise<string | number | bigint | boolean | React$1.ReactPortal | React$1.ReactElement<unknown, string | React$1.JSXElementConstructor<any>> | Iterable<React$1.ReactNode> | null | undefined> | null | undefined;
62
64
  }
63
65
  //#endregion
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { _ as DRAGGABLE_ITEMS, b as __toESM, d as require_lib$1, f as require_lib, g as DEFAULT_TEMPLATE, p as BINDING_PROP } from "./document-kU_tXfS_.mjs";
2
- import { a as detectTypeScript, c as generateSections, d as replaceSections, i as compile, l as getCachedScriptBlob, n as clearCompilationCache, o as extractSections, r as cn, s as generateSection, t as baseModules, u as preloadScripts } from "./utils-qt78kxvP.mjs";
3
- import { _ as parseArrayExpression, c as extract, d as getCurrentValue, f as parseBinding, g as extractObjectProperties, h as extractNodeValue, i as replaceIds, l as nanoid, m as createNodeFromValue, n as clone, o as update, p as arrayExpressionToCode, r as fillIds, t as validateBindingValue, u as findEditableChildren, v as parseValue, y as generateCode } from "./ast-DxgO-X_f.mjs";
1
+ import { _ as DRAGGABLE_ITEMS, b as __toESM, d as require_lib$1, f as require_lib, g as DEFAULT_TEMPLATE, p as BINDING_PROP } from "./document-DJDRM79h.mjs";
2
+ import { a as detectTypeScript, c as generateSections, d as replaceSections, i as compile, l as getCachedScriptBlob, n as clearCompilationCache, o as extractSections, r as cn, s as generateSection, t as baseModules, u as preloadScripts } from "./utils-D1tlgtgj.mjs";
3
+ import { _ as parseArrayExpression, c as extract, d as getCurrentValue, f as parseBinding, g as extractObjectProperties, h as extractNodeValue, i as replaceIds, l as nanoid, m as createNodeFromValue, n as clone, o as update, p as arrayExpressionToCode, r as fillIds, t as validateBindingValue, u as findEditableChildren, v as parseValue, y as generateCode } from "./ast-DiVN0l7x.mjs";
4
4
  import { generateTailwindCSS } from "./utils/tailwind/index.mjs";
5
5
  import "@jbpark/ui-kit/style.css";
6
6
  import React, { createContext, memo, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
@@ -44,8 +44,12 @@ const useError = () => {
44
44
  //#endregion
45
45
  //#region src/components/context/context.tsx
46
46
  const ContextProvider = ({ children }) => {
47
- const [code, setCode] = useState(DEFAULT_TEMPLATE);
47
+ const [code, setCodeState] = useState(DEFAULT_TEMPLATE);
48
48
  const [error, setError] = useState(null);
49
+ const setCode = useCallback((next) => {
50
+ setError(null);
51
+ setCodeState(next);
52
+ }, []);
49
53
  useEffect(() => {
50
54
  return () => {
51
55
  clearCompilationCache();
@@ -72,7 +76,9 @@ const EMPTY_STRING_ARRAY = [];
72
76
  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 }) => {
73
77
  const iframeRef = useRef(null);
74
78
  const [mountNode, setMountNode] = useState(null);
75
- const scriptsLoadedRef = useRef(false);
79
+ const loadedScriptsRef = useRef(/* @__PURE__ */ new Set());
80
+ const prevStyleCountRef = useRef(0);
81
+ const prevStylesheetCountRef = useRef(0);
76
82
  const shouldAutoHeight = autoHeight && style.height == null;
77
83
  const styleManagerRef = useRef({
78
84
  copiedLinks: /* @__PURE__ */ new Set(),
@@ -129,9 +135,10 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
129
135
  }
130
136
  setMountNode(node);
131
137
  applyStyle();
132
- if (scripts.length && !scriptsLoadedRef.current) {
133
- scriptsLoadedRef.current = true;
134
- Promise.all(scripts.map(getCachedScriptBlob)).then((blobUrls) => {
138
+ const pendingScripts = scripts.filter((src) => !loadedScriptsRef.current.has(src));
139
+ if (pendingScripts.length) {
140
+ pendingScripts.forEach((src) => loadedScriptsRef.current.add(src));
141
+ Promise.all(pendingScripts.map(getCachedScriptBlob)).then((blobUrls) => {
135
142
  if (!doc.head) return;
136
143
  const fragment = doc.createDocumentFragment();
137
144
  blobUrls.forEach((blobUrl) => {
@@ -184,6 +191,8 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
184
191
  }
185
192
  if (styleEl.textContent !== css) styleEl.textContent = css;
186
193
  });
194
+ for (let index = styles.length; index < prevStyleCountRef.current; index++) doc.getElementById(`injected-style-${index}`)?.remove();
195
+ prevStyleCountRef.current = styles.length;
187
196
  stylesheets.forEach((href, index) => {
188
197
  const linkId = `injected-stylesheet-${index}`;
189
198
  let linkEl = doc.getElementById(linkId);
@@ -195,6 +204,8 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
195
204
  }
196
205
  if (linkEl.href !== href) linkEl.href = href;
197
206
  });
207
+ for (let index = stylesheets.length; index < prevStylesheetCountRef.current; index++) doc.getElementById(`injected-stylesheet-${index}`)?.remove();
208
+ prevStylesheetCountRef.current = stylesheets.length;
198
209
  }, [styles, stylesheets]);
199
210
  useEffect(() => {
200
211
  if (!shouldAutoHeight || !mountNode || !iframeRef.current) return;
@@ -295,41 +306,6 @@ const Shadow = ({ children }) => {
295
306
  renderTargetRef.current = target;
296
307
  setRenderTarget(target);
297
308
  }
298
- const onClick = (e) => {
299
- const eventInit = {
300
- bubbles: true,
301
- cancelable: true,
302
- composed: true
303
- };
304
- let newEvent;
305
- if (e instanceof MouseEvent) newEvent = new MouseEvent(e.type, {
306
- ...eventInit,
307
- clientX: e.clientX,
308
- clientY: e.clientY,
309
- button: e.button
310
- });
311
- else if (e instanceof PointerEvent) newEvent = new PointerEvent(e.type, {
312
- ...eventInit,
313
- clientX: e.clientX,
314
- clientY: e.clientY,
315
- pointerId: e.pointerId
316
- });
317
- else newEvent = new Event(e.type, eventInit);
318
- hostRef.current?.dispatchEvent(newEvent);
319
- };
320
- const eventTypes = [
321
- "click",
322
- "pointerdown",
323
- "pointerup"
324
- ];
325
- eventTypes.forEach((type) => {
326
- target.addEventListener(type, onClick, true);
327
- });
328
- return () => {
329
- eventTypes.forEach((type) => {
330
- target?.removeEventListener(type, onClick, true);
331
- });
332
- };
333
309
  }, []);
334
310
  useLayoutEffect(() => {
335
311
  if (renderTargetRef.current && !renderTarget) setRenderTarget(renderTargetRef.current);
@@ -402,7 +378,16 @@ const Renderer = ({ preview, headers, modules, frame, provider }) => {
402
378
  ...baseModules,
403
379
  ...modules
404
380
  }), [modules]);
405
- const module = useMemo(() => compile(preview, memoizedModules), [preview, memoizedModules]);
381
+ const module = useMemo(() => {
382
+ try {
383
+ return compile(preview, memoizedModules);
384
+ } catch (e) {
385
+ return {
386
+ exports: {},
387
+ error: e instanceof Error ? e.message : "Module transformation error"
388
+ };
389
+ }
390
+ }, [preview, memoizedModules]);
406
391
  const renderProvider = (component) => {
407
392
  return provider ? provider(component) : component;
408
393
  };
@@ -11722,6 +11707,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
11722
11707
  };
11723
11708
  const addItem = () => {
11724
11709
  const firstItem = objectItems[0];
11710
+ if (!firstItem) return;
11725
11711
  const clonedElement = cloneObjectItemElement(firstItem);
11726
11712
  const editableProperties = extractObjectProperties(clonedElement);
11727
11713
  const nextItems = [...objectItems];
@@ -11845,6 +11831,7 @@ const Items = ({ value, render, onChange, onChildChange }) => {
11845
11831
  icon: /* @__PURE__ */ jsx(Plus, {}),
11846
11832
  variant: "solid",
11847
11833
  color: "green",
11834
+ disabled: objectItems.length === 0,
11848
11835
  onClick: addItem,
11849
11836
  children: "Add Item"
11850
11837
  })]
@@ -12382,7 +12369,7 @@ const Field = ({ binding, id, value, onChange }) => {
12382
12369
  return;
12383
12370
  }
12384
12371
  setValidationError(null);
12385
- if (next && next !== value) onChange?.({
12372
+ if (next !== value) onChange?.({
12386
12373
  id,
12387
12374
  label: binding.label,
12388
12375
  value: next
@@ -12472,7 +12459,7 @@ const Field = ({ binding, id, value, onChange }) => {
12472
12459
  return;
12473
12460
  }
12474
12461
  setValidationError(null);
12475
- if (next && next !== value) onChange?.({
12462
+ if (next !== value) onChange?.({
12476
12463
  id,
12477
12464
  label: binding.label,
12478
12465
  value: next
@@ -12493,7 +12480,7 @@ const Field = ({ binding, id, value, onChange }) => {
12493
12480
  return;
12494
12481
  }
12495
12482
  setValidationError(null);
12496
- if (next && next !== value) onChange?.({
12483
+ if (next !== value) onChange?.({
12497
12484
  id,
12498
12485
  label: binding.label,
12499
12486
  value: next
@@ -12933,6 +12920,15 @@ var ErrorBoundary = class extends React.Component {
12933
12920
  console.error("🚨 [Boundary] Rendering error:", error, errorInfo);
12934
12921
  this.props.onError?.(error, errorInfo);
12935
12922
  }
12923
+ componentDidUpdate(prevProps) {
12924
+ if (!this.state.hasError) return;
12925
+ const prevKeys = prevProps.resetKeys ?? [];
12926
+ const nextKeys = this.props.resetKeys ?? [];
12927
+ if (prevKeys.length !== nextKeys.length || nextKeys.some((key, i) => key !== prevKeys[i])) this.setState({
12928
+ hasError: false,
12929
+ error: void 0
12930
+ });
12931
+ }
12936
12932
  render() {
12937
12933
  if (this.state.hasError) return this.props.fallback ? /* @__PURE__ */ jsx(Fragment, { children: this.props.fallback(this.state.error?.message) }) : /* @__PURE__ */ jsx(Error$2, {
12938
12934
  message: this.state.error?.message,
@@ -12954,7 +12950,7 @@ const Guard = ({ children, onError }) => {
12954
12950
  const errorHandled = useRef(false);
12955
12951
  useEffect(() => {
12956
12952
  if (!containerRef.current) return;
12957
- const onError = (event) => {
12953
+ const handleWindowError = (event) => {
12958
12954
  if (errorHandled.current) return;
12959
12955
  errorHandled.current = true;
12960
12956
  const errorMessage = event.error?.message || event.message || "Unknown error";
@@ -12967,7 +12963,7 @@ const Guard = ({ children, onError }) => {
12967
12963
  }, 100);
12968
12964
  return true;
12969
12965
  };
12970
- const onUnhandledRejection = (event) => {
12966
+ const handleUnhandledRejection = (event) => {
12971
12967
  if (errorHandled.current) return;
12972
12968
  errorHandled.current = true;
12973
12969
  const errorMessage = event.reason?.message || "Promise rejection";
@@ -12978,11 +12974,11 @@ const Guard = ({ children, onError }) => {
12978
12974
  errorHandled.current = false;
12979
12975
  }, 100);
12980
12976
  };
12981
- window.addEventListener("error", onError, true);
12982
- window.addEventListener("unhandledrejection", onUnhandledRejection, true);
12977
+ window.addEventListener("error", handleWindowError, true);
12978
+ window.addEventListener("unhandledrejection", handleUnhandledRejection, true);
12983
12979
  return () => {
12984
- window.removeEventListener("error", onError, true);
12985
- window.removeEventListener("unhandledrejection", onUnhandledRejection, true);
12980
+ window.removeEventListener("error", handleWindowError, true);
12981
+ window.removeEventListener("unhandledrejection", handleUnhandledRejection, true);
12986
12982
  };
12987
12983
  }, [onError]);
12988
12984
  if (error) return /* @__PURE__ */ jsx(Error$2, {
@@ -13041,9 +13037,10 @@ const Client = ({ code: _code = "", className, showError, props = {}, modules =
13041
13037
  ...baseModules,
13042
13038
  ...modules
13043
13039
  };
13040
+ const effectiveCode = _code || code;
13044
13041
  let module = null;
13045
- if (_code || code) try {
13046
- module = compile(_code || code, mergedModules);
13042
+ if (effectiveCode) try {
13043
+ module = compile(effectiveCode, mergedModules);
13047
13044
  } catch (e) {
13048
13045
  module = {
13049
13046
  exports: {},
@@ -13068,6 +13065,7 @@ const Client = ({ code: _code = "", className, showError, props = {}, modules =
13068
13065
  children: /* @__PURE__ */ jsx(Frame, {
13069
13066
  ...frame,
13070
13067
  children: (container) => /* @__PURE__ */ jsx(Error$1.Boundary, {
13068
+ resetKeys: [effectiveCode],
13071
13069
  onError: (e) => setError(e.message),
13072
13070
  children: renderProvider(/* @__PURE__ */ jsx(Error$1.Guard, {
13073
13071
  onError: (e) => setError(e.message),
@@ -13086,6 +13084,7 @@ const Client = ({ code: _code = "", className, showError, props = {}, modules =
13086
13084
  containerType: "inline-size"
13087
13085
  },
13088
13086
  children: /* @__PURE__ */ jsx(Error$1.Boundary, {
13087
+ resetKeys: [effectiveCode],
13089
13088
  onError: (e) => setError(e.message),
13090
13089
  children: renderProvider(/* @__PURE__ */ jsx(Error$1.Guard, {
13091
13090
  onError: (e) => setError(e.message),
@@ -13100,12 +13099,23 @@ const Client = ({ code: _code = "", className, showError, props = {}, modules =
13100
13099
  const Preview = ({ code, props = {}, modules = {}, dynamicTailwind = false, provider, ...restProps }) => {
13101
13100
  const [runtimeError, setRuntimeError] = useState(null);
13102
13101
  const [dynamicCSS, setDynamicCSS] = useState("");
13102
+ const [prevCode, setPrevCode] = useState(code);
13103
+ if (code !== prevCode) {
13104
+ setPrevCode(code);
13105
+ setRuntimeError(null);
13106
+ }
13103
13107
  const renderProvider = (component) => {
13104
13108
  return provider ? provider(component) : component;
13105
13109
  };
13106
13110
  useEffect(() => {
13107
13111
  if (!code || !dynamicTailwind) return;
13108
- generateTailwindCSS(code).then(setDynamicCSS);
13112
+ let cancelled = false;
13113
+ generateTailwindCSS(code).then((css) => {
13114
+ if (!cancelled) setDynamicCSS(css);
13115
+ });
13116
+ return () => {
13117
+ cancelled = true;
13118
+ };
13109
13119
  }, [code, dynamicTailwind]);
13110
13120
  if (runtimeError) return /* @__PURE__ */ jsx(Error$1, {
13111
13121
  title: "Runtime Error",
@@ -13114,10 +13124,18 @@ const Preview = ({ code, props = {}, modules = {}, dynamicTailwind = false, prov
13114
13124
  onReset: () => setRuntimeError(null)
13115
13125
  });
13116
13126
  if (code) {
13117
- const module = compile(code, {
13118
- ...baseModules,
13119
- ...modules
13120
- });
13127
+ let module;
13128
+ try {
13129
+ module = compile(code, {
13130
+ ...baseModules,
13131
+ ...modules
13132
+ });
13133
+ } catch (e) {
13134
+ module = {
13135
+ exports: {},
13136
+ error: e instanceof Error ? e.message : "Module transformation error"
13137
+ };
13138
+ }
13121
13139
  if (module.error) return /* @__PURE__ */ jsx(Error$1, {
13122
13140
  title: "Compile Error",
13123
13141
  message: module.error,
@@ -13129,13 +13147,14 @@ const Preview = ({ code, props = {}, modules = {}, dynamicTailwind = false, prov
13129
13147
  className: "mx-5 mt-25"
13130
13148
  });
13131
13149
  return /* @__PURE__ */ jsx(Error$1.Boundary, {
13150
+ resetKeys: [code],
13132
13151
  fallback: (message) => /* @__PURE__ */ jsx(Error$1, {
13133
13152
  title: "Rendering Error",
13134
13153
  message
13135
13154
  }),
13136
13155
  children: renderProvider(/* @__PURE__ */ jsxs(Error$1.Guard, {
13137
13156
  onError: (e) => setRuntimeError(e.message),
13138
- children: [/* @__PURE__ */ jsx(Component, { ...props }), dynamicCSS && /* @__PURE__ */ jsx("style", { children: dynamicCSS })]
13157
+ children: [/* @__PURE__ */ jsx(Component, { ...props }), dynamicTailwind && dynamicCSS && /* @__PURE__ */ jsx("style", { children: dynamicCSS })]
13139
13158
  }))
13140
13159
  });
13141
13160
  }