@jbpark/live-editor 4.3.0 → 4.4.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 (45) hide show
  1. package/README.ko.md +2 -7
  2. package/README.md +2 -7
  3. package/dist/{ast-BFbDWO-l.js → ast-dYb78955.js} +128 -38
  4. package/dist/ast-dYb78955.js.map +1 -0
  5. package/dist/{compile-0Dvp8zp5.js → compile-DDfk5P25.js} +3 -3
  6. package/dist/{compile-0Dvp8zp5.js.map → compile-DDfk5P25.js.map} +1 -1
  7. package/dist/{constants-CKvdqZtO.js → constants-h1JAgOeW.js} +4 -2
  8. package/dist/constants-h1JAgOeW.js.map +1 -0
  9. package/dist/{context-93X3gyfJ.js → context-DB5kW3qe.js} +2 -2
  10. package/dist/{context-93X3gyfJ.js.map → context-DB5kW3qe.js.map} +1 -1
  11. package/dist/{core-B3ruccKb.js → core-CRsAGpei.js} +2 -2
  12. package/dist/{core-B3ruccKb.js.map → core-CRsAGpei.js.map} +1 -1
  13. package/dist/{detect-typescript-5MV4mCM7.js → detect-typescript-CCj9ALXc.js} +2 -2
  14. package/dist/{detect-typescript-5MV4mCM7.js.map → detect-typescript-CCj9ALXc.js.map} +1 -1
  15. package/dist/dnd/index.d.ts +2 -2
  16. package/dist/dnd/index.js +1 -1
  17. package/dist/{dnd-Z1KS16Fy.js → dnd-BE5ZizqX.js} +168 -44
  18. package/dist/dnd-BE5ZizqX.js.map +1 -0
  19. package/dist/{document-cEEdFERz.js → document-BDn_f08_.js} +42 -41
  20. package/dist/document-BDn_f08_.js.map +1 -0
  21. package/dist/editor/index.js +2 -2
  22. package/dist/{editor-DvMruljw.js → editor-DQ8Q--qR.js} +2 -2
  23. package/dist/{editor-DvMruljw.js.map → editor-DQ8Q--qR.js.map} +1 -1
  24. package/dist/{index-CtlUYnWq.d.ts → index-Dgh1JTX3.d.ts} +13 -4
  25. package/dist/{index-w3kLcCXl.d.ts → index-f7ijuNTa.d.ts} +17 -5
  26. package/dist/index.d.ts +4 -3
  27. package/dist/index.js +4 -4
  28. package/dist/index.js.map +1 -1
  29. package/dist/preview/index.js +2 -2
  30. package/dist/{preview-C_UzpGWh.js → preview-BnaCEFsF.js} +2 -2
  31. package/dist/{preview-C_UzpGWh.js.map → preview-BnaCEFsF.js.map} +1 -1
  32. package/dist/provider/index.js +1 -1
  33. package/dist/{sections-GJQ63uEB.js → sections-CBVMO8Jl.js} +3 -3
  34. package/dist/{sections-GJQ63uEB.js.map → sections-CBVMO8Jl.js.map} +1 -1
  35. package/dist/{use-dynamic-tailwind-DpbjmATF.js → use-dynamic-tailwind-Bcipc1hL.js} +43 -2
  36. package/dist/use-dynamic-tailwind-Bcipc1hL.js.map +1 -0
  37. package/dist/utils/ast/index.d.ts +2 -2
  38. package/dist/utils/ast/index.js +3 -3
  39. package/dist/utils/index.js +4 -4
  40. package/package.json +6 -6
  41. package/dist/ast-BFbDWO-l.js.map +0 -1
  42. package/dist/constants-CKvdqZtO.js.map +0 -1
  43. package/dist/dnd-Z1KS16Fy.js.map +0 -1
  44. package/dist/document-cEEdFERz.js.map +0 -1
  45. package/dist/use-dynamic-tailwind-DpbjmATF.js.map +0 -1
@@ -1,3 +1,3 @@
1
- import { t as Core } from "../core-B3ruccKb.js";
2
- import { t as Editor } from "../editor-DvMruljw.js";
1
+ import { t as Core } from "../core-CRsAGpei.js";
2
+ import { t as Editor } from "../editor-DQ8Q--qR.js";
3
3
  export { Core, Editor as default };
@@ -1,5 +1,5 @@
1
1
  import { i as usePreview, r as useError } from "./states-Ci1AvoQ9.js";
2
- import { n as useFormatCode, t as Core } from "./core-B3ruccKb.js";
2
+ import { n as useFormatCode, t as Core } from "./core-CRsAGpei.js";
3
3
  import { useCallback, useState } from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { useDebouncedCallback } from "@jbpark/use-hooks";
@@ -63,4 +63,4 @@ Editor.Core = Core;
63
63
  //#endregion
64
64
  export { Editor as t };
65
65
 
66
- //# sourceMappingURL=editor-DvMruljw.js.map
66
+ //# sourceMappingURL=editor-DQ8Q--qR.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"editor-DvMruljw.js","names":["Editor","EditorImpl"],"sources":["../src/components/editor/editor.tsx","../src/components/editor/index.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\n\nimport { useDebouncedCallback } from '@jbpark/use-hooks';\n\nimport { useError, usePreview } from '~/components/context/states';\n\nimport Core, { type Props as CoreProps } from './core';\nimport { useFormatCode } from './use-format-code';\n\nexport interface EditorRenderData {\n value: string;\n onChange: (value: string) => void;\n // Same prettier-based formatting Core's own Cmd+S uses - reused rather\n // than reimplemented, so a custom editor can offer equivalent\n // format-on-save behavior without duplicating the prettier wiring.\n formatCode: (code: string) => Promise<string>;\n}\n\nexport interface Props extends Omit<CoreProps, 'value' | 'onSave' | 'onError'> {\n value?: string;\n defaultValue?: string;\n debounce?: number;\n // Full replacement for the built-in CodeMirror editor. Editor still owns\n // syncing `value` to the shared preview code (debounced), regardless of\n // which UI renders it - only the editing surface itself is customizable.\n renderEditor?: (data: EditorRenderData) => React.ReactNode;\n}\n\nconst Editor = ({\n defaultValue,\n value: _value,\n debounce = 1000,\n onChange: _onChange,\n renderEditor,\n fragment,\n prettierOptions,\n ...props\n}: Props) => {\n const { code, setCode } = usePreview();\n const { setError } = useError();\n\n // Controlled, the host owns the document. Uncontrolled, the provider does\n // (#341): `draft` shows each keystroke at once, while the provider only\n // hears about it after `debounce`. Without a draft, the editor had nowhere\n // to keep what was typed, so an uncontrolled editor dropped every edit.\n const controlled = _value !== undefined;\n const [draft, setDraft] = useState(() => defaultValue ?? code);\n\n // The last code this editor pushed, and the provider code it has already\n // seen. A provider change that isn't this editor's own push came from\n // somewhere else sharing the provider — an uncontrolled DnD, say — and the\n // draft follows it. Adjusted during render so no frame shows the old one.\n const [pushed, setPushed] = useState<string | null>(null);\n const [seenCode, setSeenCode] = useState(code);\n\n if (code !== seenCode) {\n setSeenCode(code);\n\n if (!controlled && code !== pushed) {\n setDraft(code);\n }\n }\n\n const value = controlled ? _value : draft;\n\n const pushCode = useCallback(\n (next: string) => {\n setPushed(next);\n setCode(next);\n },\n [setCode],\n );\n\n const onChange = useCallback(\n (next: string) => {\n if (!controlled) {\n setDraft(next);\n }\n\n _onChange?.(next);\n },\n [_onChange, controlled],\n );\n\n // Formatting on save reaches the provider at once, ahead of the debounce.\n const onSave = useCallback(\n (formattedCode: string) => {\n pushCode(formattedCode);\n },\n [pushCode],\n );\n\n const onError = useCallback(\n (error: string | null) => {\n setError(error);\n },\n [setError],\n );\n\n const formatCode = useFormatCode({ fragment, prettierOptions });\n\n // Pushes `value` to the provider `debounce` ms after it stops changing,\n // and at once on mount. A pending push is never dropped: it runs when the\n // editor unmounts, and when focus leaves it — so clicking into another\n // surface right after typing edits a document that includes the typing.\n const push = useDebouncedCallback(\n () => pushCode(value),\n { delay: debounce, flushOnUnmount: true },\n [value],\n );\n\n // `display: contents` so the wrapper adds a blur listener without adding a\n // box: the editor lays out against this element's parent, as before.\n return (\n <div style={{ display: 'contents' }} onBlur={push.flush}>\n {renderEditor ? (\n renderEditor({ value, onChange, formatCode })\n ) : (\n <Core\n value={value}\n onChange={onChange}\n onSave={onSave}\n onError={onError}\n fragment={fragment}\n prettierOptions={prettierOptions}\n {...props}\n />\n )}\n </div>\n );\n};\n\nexport default Editor;\n","import Core, { type Props as CoreProps } from './core';\nimport EditorImpl, { type EditorRenderData, type Props } from './editor';\n\ntype EditorComponent = typeof EditorImpl & { Core: typeof Core };\n\nconst Editor = EditorImpl as EditorComponent;\n\nEditor.Core = Core;\n\nexport { Core };\nexport type { Props, CoreProps, EditorRenderData };\nexport default Editor;\n"],"mappings":";;;;;;AA4BA,MAAMA,YAAU,EACd,cACA,OAAO,QACP,WAAW,KACX,UAAU,WACV,cACA,UACA,iBACA,GAAG,YACQ;CACX,MAAM,EAAE,MAAM,YAAY,WAAW;CACrC,MAAM,EAAE,aAAa,SAAS;CAM9B,MAAM,aAAa,WAAW,KAAA;CAC9B,MAAM,CAAC,OAAO,YAAY,eAAe,gBAAgB,IAAI;CAM7D,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,CAAC,UAAU,eAAe,SAAS,IAAI;CAE7C,IAAI,SAAS,UAAU;EACrB,YAAY,IAAI;EAEhB,IAAI,CAAC,cAAc,SAAS,QAC1B,SAAS,IAAI;CAEjB;CAEA,MAAM,QAAQ,aAAa,SAAS;CAEpC,MAAM,WAAW,aACd,SAAiB;EAChB,UAAU,IAAI;EACd,QAAQ,IAAI;CACd,GACA,CAAC,OAAO,CACV;CAEA,MAAM,WAAW,aACd,SAAiB;EAChB,IAAI,CAAC,YACH,SAAS,IAAI;EAGf,YAAY,IAAI;CAClB,GACA,CAAC,WAAW,UAAU,CACxB;CAGA,MAAM,SAAS,aACZ,kBAA0B;EACzB,SAAS,aAAa;CACxB,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,UAAU,aACb,UAAyB;EACxB,SAAS,KAAK;CAChB,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,aAAa,cAAc;EAAE;EAAU;CAAgB,CAAC;CAM9D,MAAM,OAAO,2BACL,SAAS,KAAK,GACpB;EAAE,OAAO;EAAU,gBAAgB;CAAK,GACxC,CAAC,KAAK,CACR;CAIA,OACE,oBAAC,OAAD;EAAK,OAAO,EAAE,SAAS,WAAW;EAAG,QAAQ,KAAK;EAC/C,UAAA,eACC,aAAa;GAAE;GAAO;GAAU;EAAW,CAAC,IAE5C,oBAAC,MAAD;GACS;GACG;GACF;GACC;GACC;GACO;GACjB,GAAI;EACL,CAAA;CAEA,CAAA;AAET;;;AC7HA,MAAM,SAASC;AAEf,OAAO,OAAO"}
1
+ {"version":3,"file":"editor-DQ8Q--qR.js","names":["Editor","EditorImpl"],"sources":["../src/components/editor/editor.tsx","../src/components/editor/index.ts"],"sourcesContent":["import { useCallback, useState } from 'react';\n\nimport { useDebouncedCallback } from '@jbpark/use-hooks';\n\nimport { useError, usePreview } from '~/components/context/states';\n\nimport Core, { type Props as CoreProps } from './core';\nimport { useFormatCode } from './use-format-code';\n\nexport interface EditorRenderData {\n value: string;\n onChange: (value: string) => void;\n // Same prettier-based formatting Core's own Cmd+S uses - reused rather\n // than reimplemented, so a custom editor can offer equivalent\n // format-on-save behavior without duplicating the prettier wiring.\n formatCode: (code: string) => Promise<string>;\n}\n\nexport interface Props extends Omit<CoreProps, 'value' | 'onSave' | 'onError'> {\n value?: string;\n defaultValue?: string;\n debounce?: number;\n // Full replacement for the built-in CodeMirror editor. Editor still owns\n // syncing `value` to the shared preview code (debounced), regardless of\n // which UI renders it - only the editing surface itself is customizable.\n renderEditor?: (data: EditorRenderData) => React.ReactNode;\n}\n\nconst Editor = ({\n defaultValue,\n value: _value,\n debounce = 1000,\n onChange: _onChange,\n renderEditor,\n fragment,\n prettierOptions,\n ...props\n}: Props) => {\n const { code, setCode } = usePreview();\n const { setError } = useError();\n\n // Controlled, the host owns the document. Uncontrolled, the provider does\n // (#341): `draft` shows each keystroke at once, while the provider only\n // hears about it after `debounce`. Without a draft, the editor had nowhere\n // to keep what was typed, so an uncontrolled editor dropped every edit.\n const controlled = _value !== undefined;\n const [draft, setDraft] = useState(() => defaultValue ?? code);\n\n // The last code this editor pushed, and the provider code it has already\n // seen. A provider change that isn't this editor's own push came from\n // somewhere else sharing the provider — an uncontrolled DnD, say — and the\n // draft follows it. Adjusted during render so no frame shows the old one.\n const [pushed, setPushed] = useState<string | null>(null);\n const [seenCode, setSeenCode] = useState(code);\n\n if (code !== seenCode) {\n setSeenCode(code);\n\n if (!controlled && code !== pushed) {\n setDraft(code);\n }\n }\n\n const value = controlled ? _value : draft;\n\n const pushCode = useCallback(\n (next: string) => {\n setPushed(next);\n setCode(next);\n },\n [setCode],\n );\n\n const onChange = useCallback(\n (next: string) => {\n if (!controlled) {\n setDraft(next);\n }\n\n _onChange?.(next);\n },\n [_onChange, controlled],\n );\n\n // Formatting on save reaches the provider at once, ahead of the debounce.\n const onSave = useCallback(\n (formattedCode: string) => {\n pushCode(formattedCode);\n },\n [pushCode],\n );\n\n const onError = useCallback(\n (error: string | null) => {\n setError(error);\n },\n [setError],\n );\n\n const formatCode = useFormatCode({ fragment, prettierOptions });\n\n // Pushes `value` to the provider `debounce` ms after it stops changing,\n // and at once on mount. A pending push is never dropped: it runs when the\n // editor unmounts, and when focus leaves it — so clicking into another\n // surface right after typing edits a document that includes the typing.\n const push = useDebouncedCallback(\n () => pushCode(value),\n { delay: debounce, flushOnUnmount: true },\n [value],\n );\n\n // `display: contents` so the wrapper adds a blur listener without adding a\n // box: the editor lays out against this element's parent, as before.\n return (\n <div style={{ display: 'contents' }} onBlur={push.flush}>\n {renderEditor ? (\n renderEditor({ value, onChange, formatCode })\n ) : (\n <Core\n value={value}\n onChange={onChange}\n onSave={onSave}\n onError={onError}\n fragment={fragment}\n prettierOptions={prettierOptions}\n {...props}\n />\n )}\n </div>\n );\n};\n\nexport default Editor;\n","import Core, { type Props as CoreProps } from './core';\nimport EditorImpl, { type EditorRenderData, type Props } from './editor';\n\ntype EditorComponent = typeof EditorImpl & { Core: typeof Core };\n\nconst Editor = EditorImpl as EditorComponent;\n\nEditor.Core = Core;\n\nexport { Core };\nexport type { Props, CoreProps, EditorRenderData };\nexport default Editor;\n"],"mappings":";;;;;;AA4BA,MAAMA,YAAU,EACd,cACA,OAAO,QACP,WAAW,KACX,UAAU,WACV,cACA,UACA,iBACA,GAAG,YACQ;CACX,MAAM,EAAE,MAAM,YAAY,WAAW;CACrC,MAAM,EAAE,aAAa,SAAS;CAM9B,MAAM,aAAa,WAAW,KAAA;CAC9B,MAAM,CAAC,OAAO,YAAY,eAAe,gBAAgB,IAAI;CAM7D,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,CAAC,UAAU,eAAe,SAAS,IAAI;CAE7C,IAAI,SAAS,UAAU;EACrB,YAAY,IAAI;EAEhB,IAAI,CAAC,cAAc,SAAS,QAC1B,SAAS,IAAI;CAEjB;CAEA,MAAM,QAAQ,aAAa,SAAS;CAEpC,MAAM,WAAW,aACd,SAAiB;EAChB,UAAU,IAAI;EACd,QAAQ,IAAI;CACd,GACA,CAAC,OAAO,CACV;CAEA,MAAM,WAAW,aACd,SAAiB;EAChB,IAAI,CAAC,YACH,SAAS,IAAI;EAGf,YAAY,IAAI;CAClB,GACA,CAAC,WAAW,UAAU,CACxB;CAGA,MAAM,SAAS,aACZ,kBAA0B;EACzB,SAAS,aAAa;CACxB,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,UAAU,aACb,UAAyB;EACxB,SAAS,KAAK;CAChB,GACA,CAAC,QAAQ,CACX;CAEA,MAAM,aAAa,cAAc;EAAE;EAAU;CAAgB,CAAC;CAM9D,MAAM,OAAO,2BACL,SAAS,KAAK,GACpB;EAAE,OAAO;EAAU,gBAAgB;CAAK,GACxC,CAAC,KAAK,CACR;CAIA,OACE,oBAAC,OAAD;EAAK,OAAO,EAAE,SAAS,WAAW;EAAG,QAAQ,KAAK;EAC/C,UAAA,eACC,aAAa;GAAE;GAAO;GAAU;EAAW,CAAC,IAE5C,oBAAC,MAAD;GACS;GACG;GACF;GACC;GACC;GACO;GACjB,GAAI;EACL,CAAA;CAEA,CAAA;AAET;;;AC7HA,MAAM,SAASC;AAEf,OAAO,OAAO"}
@@ -1,4 +1,4 @@
1
- import { $ as BindingWidget, Q as BindingType, Y as BindingOption, Z as BindingRenderMap, et as DataAttrNode, f as UpdateFailure } from "./index-w3kLcCXl.js";
1
+ import { ct as BindingWidget, f as UpdateFailure, it as BindingRegistry, lt as DataAttrNode, nt as BindingOption, ot as BindingRenderMap, rt as BindingOptions, st as BindingType, tt as BindingKeyMap } from "./index-f7ijuNTa.js";
2
2
  import { v as Section } from "./document-Ct4jW78J.js";
3
3
  import { t as FrameProps } from "./index-DpDU1IAw.js";
4
4
  import { useMultiSelect } from "@jbpark/use-hooks";
@@ -56,6 +56,7 @@ interface DndInspector {
56
56
  deactivate: () => void;
57
57
  toggle: () => void;
58
58
  picked: DndNodePick | null;
59
+ highlight: (id: string | null) => void;
59
60
  }
60
61
  declare const useDndInspector: () => DndInspector;
61
62
  //#endregion
@@ -88,8 +89,13 @@ interface PanelBinding {
88
89
  rawValue: string;
89
90
  canEditValue?: boolean;
90
91
  present?: boolean;
92
+ element?: PanelBindingElement;
91
93
  onChange: (value: unknown) => void;
92
94
  }
95
+ interface PanelBindingElement {
96
+ tagName: string;
97
+ text: string;
98
+ }
93
99
  type PanelBindingData = Omit<PanelBinding, 'onChange'>;
94
100
  interface PanelBindingSource {
95
101
  id: string;
@@ -124,6 +130,7 @@ interface DndPanel {
124
130
  onNodeChange: PanelNodeChange;
125
131
  onNodesChange: PanelNodesChange;
126
132
  readOnly: boolean;
133
+ bindingOptions: BindingOptions;
127
134
  }
128
135
  interface Props extends Omit<React.ComponentPropsWithRef<'div'>, 'onChange'> {
129
136
  value?: string;
@@ -141,10 +148,12 @@ interface Props extends Omit<React.ComponentPropsWithRef<'div'>, 'onChange'> {
141
148
  onBeforeDelete?: (section: Section) => boolean | Promise<boolean>;
142
149
  sectionNameFallback?: (index: number) => string;
143
150
  containerId?: string;
151
+ bindings?: BindingRegistry;
152
+ bindingKeys?: BindingKeyMap;
144
153
  onNodePick?: (pick: DndNodePick) => void;
145
154
  children?: React.ReactNode;
146
155
  }
147
- declare const Dnd$1: ({ value: _value, props, modules: _modules, onChange: _onChange, className, items, frame, dynamicTailwind, provider, renderField, onEditError, renderSectionFallback, shouldForceSectionFallback, onBeforeDelete, sectionNameFallback, containerId, onNodePick, children, ...restProps }: Props) => import("react").JSX.Element;
156
+ declare const Dnd$1: ({ value: _value, props, modules: _modules, onChange: _onChange, className, items, frame, dynamicTailwind, provider, renderField, onEditError, renderSectionFallback, shouldForceSectionFallback, onBeforeDelete, sectionNameFallback, containerId, bindings: bindingRegistry, bindingKeys, onNodePick, children, ...restProps }: Props) => import("react").JSX.Element;
148
157
  //#endregion
149
158
  //#region src/components/dnd/draggable.d.ts
150
159
  interface DraggableItemDragState {
@@ -309,5 +318,5 @@ type ChildrenEditor = DndChildren;
309
318
  /** @deprecated Renamed to `DndChildrenOptions`. */
310
319
  type ChildrenEditorOptions = DndChildrenOptions;
311
320
  //#endregion
312
- export { DndNodePick as $, useDndPanel as A, DndPalette as B, useDndItems as C, DndLayout as D, useDndChildren as E, Palette as F, PanelBinding as G, Props as H, Panel as I, PanelNodeChange as J, PanelBindingData as K, DraggableItem as L, DndLayoutProps as M, DndRegionProps as N, useDndLayout as O, Layout as P, DndInspector as Q, DraggableItemDragState as R, DndItemsOptions as S, DndChildrenOptions as T, DndRenderSectionFallback as U, DndPanel as V, DndSectionFallbackArgs as W, resolvePanelBindings as X, PanelNodesChange as Y, withPanelCommit as Z, DndItemsActions as _, ItemsEditorActions as a, DndItemsNestedElement as b, ItemsEditorNestedGroup as c, useItemsEditor as d, useDndInspector as et, FieldKind as f, DndItems as g, isStructuralFieldKind as h, ItemsEditor as i, FieldProps as it, Canvas as j, useDndPalette as k, ItemsEditorOptions as l, getFieldKind as m, ChildrenEditorOptions as n, DndRenderField as nt, ItemsEditorItem as o, FieldKindBinding as p, PanelBindingSource as q, Dnd as r, Field as rt, ItemsEditorNestedElement as s, ChildrenEditor as t, DndEditError as tt, useChildrenEditor as u, DndItemsExpansion as v, DndChildren as w, DndItemsNestedGroup as x, DndItemsItem as y, DraggableItemProps as z };
313
- //# sourceMappingURL=index-CtlUYnWq.d.ts.map
321
+ export { DndInspector as $, useDndPanel as A, DndPalette as B, useDndItems as C, DndLayout as D, useDndChildren as E, Palette as F, PanelBinding as G, Props as H, Panel as I, PanelBindingSource as J, PanelBindingData as K, DraggableItem as L, DndLayoutProps as M, DndRegionProps as N, useDndLayout as O, Layout as P, withPanelCommit as Q, DraggableItemDragState as R, DndItemsOptions as S, DndChildrenOptions as T, DndRenderSectionFallback as U, DndPanel as V, DndSectionFallbackArgs as W, PanelNodesChange as X, PanelNodeChange as Y, resolvePanelBindings as Z, DndItemsActions as _, ItemsEditorActions as a, FieldProps as at, DndItemsNestedElement as b, ItemsEditorNestedGroup as c, useItemsEditor as d, DndNodePick as et, FieldKind as f, DndItems as g, isStructuralFieldKind as h, ItemsEditor as i, Field as it, Canvas as j, useDndPalette as k, ItemsEditorOptions as l, getFieldKind as m, ChildrenEditorOptions as n, DndEditError as nt, ItemsEditorItem as o, FieldKindBinding as p, PanelBindingElement as q, Dnd as r, DndRenderField as rt, ItemsEditorNestedElement as s, ChildrenEditor as t, useDndInspector as tt, useChildrenEditor as u, DndItemsExpansion as v, DndChildren as w, DndItemsNestedGroup as x, DndItemsItem as y, DraggableItemProps as z };
322
+ //# sourceMappingURL=index-Dgh1JTX3.d.ts.map
@@ -61,6 +61,13 @@ interface BindingItem extends BindingFieldSpec {
61
61
  label: string;
62
62
  property: string;
63
63
  }
64
+ type BindingComponentName = `${string}.${string}` | Capitalize<string>;
65
+ type BindingRegistry = Partial<Record<BindingComponentName, BindingItem[]>>;
66
+ type BindingKeyMap = Record<string, BindingItem[]>;
67
+ interface BindingOptions {
68
+ bindings?: BindingRegistry;
69
+ bindingKeys?: BindingKeyMap;
70
+ }
64
71
  type NodeValueType = 'boolean' | 'number' | 'string' | 'null' | 'array' | 'object' | 'unknown';
65
72
  type EditableNodeValueType = 'boolean' | 'number' | 'string' | 'null';
66
73
  interface ExtractedNodeValue {
@@ -69,10 +76,15 @@ interface ExtractedNodeValue {
69
76
  }
70
77
  //#endregion
71
78
  //#region src/utils/ast/binding.d.ts
79
+ declare const isComponentTagName: (tagName: string) => boolean;
80
+ declare const getRegistryBindings: (registry: BindingRegistry | undefined, tagName: string) => BindingItem[] | undefined;
81
+ declare const getKeyBindings: (bindingKeys: BindingKeyMap | undefined, key: string) => BindingItem[] | undefined;
82
+ declare const resolveBindings: (own: BindingItem[] | undefined, key: string | null | undefined, tagName: string, options?: BindingOptions) => BindingItem[];
72
83
  declare const parseBinding: (bindingValue: string | null) => BindingItem[];
73
84
  declare const parseBindingExpression: (expression: ArrayExpression) => BindingItem[];
74
85
  declare const getCurrentValue: (node: DataAttrNode, property: string) => string;
75
86
  declare const getStructuredValue: (node: DataAttrNode, property: string, type?: BindingType) => unknown;
87
+ declare const readNodeBindings: (node: DataAttrNode) => BindingItem[];
76
88
  declare const findEditableChildren: (node: DataAttrNode) => DataAttrNode[];
77
89
  //#endregion
78
90
  //#region src/utils/ast/value.d.ts
@@ -117,7 +129,7 @@ declare const duplicateArrayItems: (code: string, indices: Set<number>, generate
117
129
  declare const appendArrayItem: (code: string, kind: ItemKind, generateId?: () => string) => string | null;
118
130
  //#endregion
119
131
  //#region src/utils/ast/extract.d.ts
120
- declare function extract(raw: string): DataAttrNode[];
132
+ declare function extract(raw: string, options?: BindingOptions): DataAttrNode[];
121
133
  declare function clearExtractCache(): void;
122
134
  //#endregion
123
135
  //#region src/utils/ast/update.d.ts
@@ -164,7 +176,7 @@ interface UpdateResult {
164
176
  failure?: UpdateFailure;
165
177
  failures?: UpdateFailure[];
166
178
  }
167
- declare const update: (code: string, dataId: string, label: string, value: unknown, property?: string) => UpdateResult;
179
+ declare const update: (code: string, dataId: string, label: string, value: unknown, property?: string, options?: BindingOptions) => UpdateResult;
168
180
  interface UpdateEntry {
169
181
  dataId: string;
170
182
  label: string;
@@ -180,7 +192,7 @@ type UpdateAllResult = {
180
192
  failure: UpdateFailure;
181
193
  index: number;
182
194
  };
183
- declare const updateAll: (raw: string, entries: UpdateEntry[]) => UpdateAllResult;
195
+ declare const updateAll: (raw: string, entries: UpdateEntry[], options?: BindingOptions) => UpdateAllResult;
184
196
  /**
185
197
  * @deprecated Not atomic: when an entry fails, the ones before and after it
186
198
  * are still applied, and the returned `code` carries them. Use `updateAll`,
@@ -251,5 +263,5 @@ interface ValidationResult {
251
263
  }
252
264
  declare const validateBindingValue: (binding: BindingItem, value: unknown) => ValidationResult;
253
265
  //#endregion
254
- export { BindingWidget as $, EditablePathSegment as A, parseValue as B, moveArrayItem as C, updateArrayItemProperty as D, removeArrayItems as E, createNodeFromValue as F, parseBinding as G, findEditableChildren as H, extractNodeValue as I, BindingItem as J, parseBindingExpression as K, extractObjectProperties as L, EditableValueEntry as M, arrayExpressionToCode as N, updateArrayItemValue as O, canLosslesslyEvaluateSource as P, BindingType as Q, flattenEditableValue as R, duplicateArrayItems as S, parseItems as T, getCurrentValue as U, setEditableValue as V, getStructuredValue as W, BindingRenderLeaf as X, BindingOption as Y, BindingRenderMap as Z, clearExtractCache as _, replaceIds as a, ItemKind as b, ChildrenEdit as c, UpdateEntry as d, DataAttrNode as et, UpdateFailure as f, updateAll as g, update as h, fillIds as i, EditablePrimitive as j, generateCode as k, getChildrenSignatures as l, bulkUpdate as m, validateBindingValue as n, ExtractedNodeValue as nt, canStructurallyEditArray as o, UpdateResult as p, BindingFieldSpec as q, clone as r, NodeValueType as rt, ChildrenAction as s, ValidationResult as t, EditableNodeValueType as tt, UpdateAllResult as u, extract as v, moveArrayItems as w, appendArrayItem as x, ArrayItem as y, parseArrayExpression as z };
255
- //# sourceMappingURL=index-w3kLcCXl.d.ts.map
266
+ export { BindingFieldSpec as $, EditablePathSegment as A, parseValue as B, moveArrayItem as C, updateArrayItemProperty as D, removeArrayItems as E, createNodeFromValue as F, getRegistryBindings as G, findEditableChildren as H, extractNodeValue as I, parseBinding as J, getStructuredValue as K, extractObjectProperties as L, EditableValueEntry as M, arrayExpressionToCode as N, updateArrayItemValue as O, canLosslesslyEvaluateSource as P, BindingComponentName as Q, flattenEditableValue as R, duplicateArrayItems as S, parseItems as T, getCurrentValue as U, setEditableValue as V, getKeyBindings as W, readNodeBindings as X, parseBindingExpression as Y, resolveBindings as Z, clearExtractCache as _, replaceIds as a, BindingRenderLeaf as at, ItemKind as b, ChildrenEdit as c, BindingWidget as ct, UpdateEntry as d, ExtractedNodeValue as dt, BindingItem as et, UpdateFailure as f, NodeValueType as ft, updateAll as g, update as h, fillIds as i, BindingRegistry as it, EditablePrimitive as j, generateCode as k, getChildrenSignatures as l, DataAttrNode as lt, bulkUpdate as m, validateBindingValue as n, BindingOption as nt, canStructurallyEditArray as o, BindingRenderMap as ot, UpdateResult as p, isComponentTagName as q, clone as r, BindingOptions as rt, ChildrenAction as s, BindingType as st, ValidationResult as t, BindingKeyMap as tt, UpdateAllResult as u, EditableNodeValueType as ut, extract as v, moveArrayItems as w, appendArrayItem as x, ArrayItem as y, parseArrayExpression as z };
267
+ //# sourceMappingURL=index-f7ijuNTa.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import { it as BindingRegistry, rt as BindingOptions, tt as BindingKeyMap } from "./index-f7ijuNTa.js";
1
2
  import { v as Section } from "./document-Ct4jW78J.js";
2
3
  import { t as FrameProps } from "./index-DpDU1IAw.js";
3
- import { $ as DndNodePick, B as DndPalette, D as DndLayout, F as Palette, G as PanelBinding, H as Props, I as Panel, J as PanelNodeChange, P as Layout, Q as DndInspector, S as DndItemsOptions, U as DndRenderSectionFallback, V as DndPanel, W as DndSectionFallbackArgs, Y as PanelNodesChange, g as DndItems, i as ItemsEditor, it as FieldProps, j as Canvas, l as ItemsEditorOptions, nt as DndRenderField, o as ItemsEditorItem, r as Dnd, tt as DndEditError, y as DndItemsItem, z as DraggableItemProps } from "./index-CtlUYnWq.js";
4
+ import { $ as DndInspector, B as DndPalette, D as DndLayout, F as Palette, G as PanelBinding, H as Props, I as Panel, P as Layout, S as DndItemsOptions, U as DndRenderSectionFallback, V as DndPanel, W as DndSectionFallbackArgs, X as PanelNodesChange, Y as PanelNodeChange, at as FieldProps, et as DndNodePick, g as DndItems, i as ItemsEditor, j as Canvas, l as ItemsEditorOptions, nt as DndEditError, o as ItemsEditorItem, r as Dnd, rt as DndRenderField, y as DndItemsItem, z as DraggableItemProps } from "./index-Dgh1JTX3.js";
4
5
  import { a as Props$2, n as EditorRenderData, r as Props$1, t as Editor } from "./index-13BDSrQc.js";
5
6
  import { a as Props$5, n as Props$4, o as Props$3, s as ErrorBoundary, t as Error } from "./index-C4SGQ3Ci.js";
6
7
  import { n as Preview, r as Props$6 } from "./index-DQkL37eL.js";
@@ -19,7 +20,7 @@ declare const App: {
19
20
  Editor: (({ defaultValue, value: _value, debounce, onChange: _onChange, renderEditor, fragment, prettierOptions, ...props }: Props$1) => import("react").JSX.Element) & {
20
21
  Core: ({ value, theme, height, className, prettierOptions, fragment, raw, onChange, onSave, onError, ...props }: Props$2) => import("react").JSX.Element;
21
22
  };
22
- Dnd: (({ value: _value, props, modules: _modules, onChange: _onChange, className, items, frame, dynamicTailwind, provider, renderField, onEditError, renderSectionFallback, shouldForceSectionFallback, onBeforeDelete, sectionNameFallback, containerId, onNodePick, children, ...restProps }: Props) => import("react").JSX.Element) & {
23
+ Dnd: (({ value: _value, props, modules: _modules, onChange: _onChange, className, items, frame, dynamicTailwind, provider, renderField, onEditError, renderSectionFallback, shouldForceSectionFallback, onBeforeDelete, sectionNameFallback, containerId, bindings: bindingRegistry, bindingKeys, onNodePick, children, ...restProps }: Props) => import("react").JSX.Element) & {
23
24
  DraggableItem: ({ item, children }: DraggableItemProps) => import("react").ReactNode;
24
25
  Field: (props: FieldProps) => import("react").JSX.Element;
25
26
  Palette: typeof Palette;
@@ -30,5 +31,5 @@ declare const App: {
30
31
  };
31
32
  declare const LiveRenderer: ({ code, props, modules, dynamicTailwind, provider, ...restProps }: Props$6) => import("react").JSX.Element;
32
33
  //#endregion
33
- export { type DndEditError, type DndInspector, type DndItems, type DndItemsItem, type DndItemsOptions, type DndLayout, type DndNodePick, type DndPalette, type DndPanel, type DndRenderField, type DndRenderSectionFallback, type DndSectionFallbackArgs, type EditorRenderData, type FieldProps, type FrameProps, type ItemsEditor, type ItemsEditorItem, type ItemsEditorOptions, Dnd as LiveDnd, Editor as LiveEditor, Error as LiveError, Preview as LivePreview, App as LiveProvider, App as default, LiveRenderer, type PanelBinding, type PanelNodeChange, type PanelNodesChange, type Section };
34
+ export { type BindingKeyMap, type BindingOptions, type BindingRegistry, type DndEditError, type DndInspector, type DndItems, type DndItemsItem, type DndItemsOptions, type DndLayout, type DndNodePick, type DndPalette, type DndPanel, type DndRenderField, type DndRenderSectionFallback, type DndSectionFallbackArgs, type EditorRenderData, type FieldProps, type FrameProps, type ItemsEditor, type ItemsEditorItem, type ItemsEditorOptions, Dnd as LiveDnd, Editor as LiveEditor, Error as LiveError, Preview as LivePreview, App as LiveProvider, App as default, LiveRenderer, type PanelBinding, type PanelNodeChange, type PanelNodesChange, type Section };
34
35
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { t as ContextProvider } from "./context-93X3gyfJ.js";
2
- import { t as Dnd } from "./dnd-Z1KS16Fy.js";
3
- import { t as Editor } from "./editor-DvMruljw.js";
1
+ import { t as ContextProvider } from "./context-DB5kW3qe.js";
2
+ import { t as Dnd } from "./dnd-BE5ZizqX.js";
3
+ import { t as Editor } from "./editor-DQ8Q--qR.js";
4
4
  import { t as Error } from "./error-DWhxQEom.js";
5
- import { t as Preview } from "./preview-C_UzpGWh.js";
5
+ import { t as Preview } from "./preview-BnaCEFsF.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  //#region src/index.tsx
8
8
  const App = ({ children }) => {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["Context","LivePreview","LiveError","LiveEditor","LiveDnd"],"sources":["../src/index.tsx"],"sourcesContent":["import './index.css';\n\nimport Context from './components/context';\nimport LiveDnd, {\n type DndEditError,\n type DndInspector,\n type DndItems,\n type DndItemsItem,\n type DndItemsOptions,\n type DndLayout,\n type DndNodePick,\n type DndPalette,\n type DndPanel,\n type DndRenderField,\n type DndRenderSectionFallback,\n type DndSectionFallbackArgs,\n type FieldProps,\n type ItemsEditor,\n type ItemsEditorItem,\n type ItemsEditorOptions,\n type PanelBinding,\n type PanelNodeChange,\n type PanelNodesChange,\n} from './components/dnd';\nimport LiveEditor, { type EditorRenderData } from './components/editor';\nimport LiveError from './components/error';\nimport { type FrameProps } from './components/frame';\nimport LivePreview from './components/preview';\nimport type { Section } from './types';\n\nconst App = ({ children }: { children?: React.ReactNode }) => {\n return <Context>{children}</Context>;\n};\n\nconst LiveRenderer = LivePreview;\n\nexport {\n LivePreview,\n LiveError,\n LiveEditor,\n LiveDnd,\n LiveRenderer,\n App as LiveProvider,\n //\n};\n\nexport type {\n DndEditError,\n DndRenderField,\n DndRenderSectionFallback,\n DndSectionFallbackArgs,\n DndPalette,\n DndPanel,\n DndLayout,\n DndInspector,\n DndNodePick,\n PanelBinding,\n PanelNodeChange,\n PanelNodesChange,\n FieldProps,\n DndItems,\n DndItemsItem,\n DndItemsOptions,\n // Deprecated aliases of the three above, kept until the next major.\n ItemsEditor,\n ItemsEditorItem,\n ItemsEditorOptions,\n EditorRenderData,\n FrameProps,\n Section,\n};\n\nApp.Preview = LivePreview;\nApp.Renderer = LiveRenderer;\nApp.Error = LiveError;\nApp.Editor = LiveEditor;\nApp.Dnd = LiveDnd;\n\nexport default App;\n"],"mappings":";;;;;;;AA8BA,MAAM,OAAO,EAAE,eAA+C;CAC5D,OAAO,oBAACA,iBAAD,EAAU,SAAkB,CAAA;AACrC;AAEA,MAAM,eAAeC;AAsCrB,IAAI,UAAUA;AACd,IAAI,WAAW;AACf,IAAI,QAAQC;AACZ,IAAI,SAASC;AACb,IAAI,MAAMC"}
1
+ {"version":3,"file":"index.js","names":["Context","LivePreview","LiveError","LiveEditor","LiveDnd"],"sources":["../src/index.tsx"],"sourcesContent":["import './index.css';\n\nimport Context from './components/context';\nimport LiveDnd, {\n type DndEditError,\n type DndInspector,\n type DndItems,\n type DndItemsItem,\n type DndItemsOptions,\n type DndLayout,\n type DndNodePick,\n type DndPalette,\n type DndPanel,\n type DndRenderField,\n type DndRenderSectionFallback,\n type DndSectionFallbackArgs,\n type FieldProps,\n type ItemsEditor,\n type ItemsEditorItem,\n type ItemsEditorOptions,\n type PanelBinding,\n type PanelNodeChange,\n type PanelNodesChange,\n} from './components/dnd';\nimport LiveEditor, { type EditorRenderData } from './components/editor';\nimport LiveError from './components/error';\nimport { type FrameProps } from './components/frame';\nimport LivePreview from './components/preview';\nimport type { Section } from './types';\nimport type {\n BindingKeyMap,\n BindingOptions,\n BindingRegistry,\n} from './utils/ast';\n\nconst App = ({ children }: { children?: React.ReactNode }) => {\n return <Context>{children}</Context>;\n};\n\nconst LiveRenderer = LivePreview;\n\nexport {\n LivePreview,\n LiveError,\n LiveEditor,\n LiveDnd,\n LiveRenderer,\n App as LiveProvider,\n //\n};\n\nexport type {\n DndEditError,\n DndRenderField,\n DndRenderSectionFallback,\n DndSectionFallbackArgs,\n DndPalette,\n DndPanel,\n DndLayout,\n DndInspector,\n DndNodePick,\n PanelBinding,\n PanelNodeChange,\n PanelNodesChange,\n FieldProps,\n DndItems,\n DndItemsItem,\n DndItemsOptions,\n // Deprecated aliases of the three above, kept until the next major.\n ItemsEditor,\n ItemsEditorItem,\n ItemsEditorOptions,\n EditorRenderData,\n FrameProps,\n Section,\n BindingRegistry,\n BindingKeyMap,\n BindingOptions,\n};\n\nApp.Preview = LivePreview;\nApp.Renderer = LiveRenderer;\nApp.Error = LiveError;\nApp.Editor = LiveEditor;\nApp.Dnd = LiveDnd;\n\nexport default App;\n"],"mappings":";;;;;;;AAmCA,MAAM,OAAO,EAAE,eAA+C;CAC5D,OAAO,oBAACA,iBAAD,EAAU,SAAkB,CAAA;AACrC;AAEA,MAAM,eAAeC;AAyCrB,IAAI,UAAUA;AACd,IAAI,WAAW;AACf,IAAI,QAAQC;AACZ,IAAI,SAASC;AACb,IAAI,MAAMC"}
@@ -1,3 +1,3 @@
1
- import { r as baseModules } from "../use-dynamic-tailwind-DpbjmATF.js";
2
- import { t as Preview } from "../preview-C_UzpGWh.js";
1
+ import { r as baseModules } from "../use-dynamic-tailwind-Bcipc1hL.js";
2
+ import { t as Preview } from "../preview-BnaCEFsF.js";
3
3
  export { baseModules, Preview as default };
@@ -1,6 +1,6 @@
1
1
  import { i as usePreview, r as useError } from "./states-Ci1AvoQ9.js";
2
2
  import { t as cn } from "./cn-CAnad2vL.js";
3
- import { a as Frame, n as useCompiledModule, t as useDynamicTailwind } from "./use-dynamic-tailwind-DpbjmATF.js";
3
+ import { a as Frame, n as useCompiledModule, t as useDynamicTailwind } from "./use-dynamic-tailwind-Bcipc1hL.js";
4
4
  import { t as Error } from "./error-DWhxQEom.js";
5
5
  import { useMemo } from "react";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -83,4 +83,4 @@ const Preview = ({ code, props = NO_PROPS, modules = NO_MODULES, dynamicTailwind
83
83
  //#endregion
84
84
  export { Preview as t };
85
85
 
86
- //# sourceMappingURL=preview-C_UzpGWh.js.map
86
+ //# sourceMappingURL=preview-BnaCEFsF.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"preview-C_UzpGWh.js","names":["LiveError"],"sources":["../src/components/preview/defaults.ts","../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["// Stable defaults for optional object props. A `= {}` default is a new\n// object on every render, which re-runs every memo keyed on it — the merged\n// module map, and so `compile()` — even when the caller passed nothing (#348).\nexport const NO_PROPS: Record<string, unknown> = {};\nexport const NO_MODULES: Record<string, unknown> = {};\n","'use client';\n\nimport { useMemo } from 'react';\n\nimport { useError, usePreview } from '~/components/context/states';\nimport LiveError from '~/components/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { cn } from '~/utils/cn';\n\nimport { NO_MODULES, NO_PROPS } from './defaults';\nimport { type Props } from './preview';\nimport { useCompiledModule } from './use-compiled-module';\nimport { useDynamicTailwind } from './use-dynamic-tailwind';\n\nconst Client = ({\n code: _code,\n className,\n showError,\n props = NO_PROPS,\n modules = NO_MODULES,\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n const { code } = usePreview();\n const { error, setError } = useError();\n const isError = !!showError && !!error;\n\n const classNames = cn(isError && 'hidden', className);\n\n const effectiveCode = _code === undefined ? code : _code;\n\n const module = useCompiledModule(effectiveCode, modules);\n\n // Attached to the wrapper below; scans the rendered DOM so classes coming\n // from an imported component are picked up too. See the hook for details.\n const { ref: contentRef, css: dynamicCSS } = useDynamicTailwind(\n effectiveCode,\n dynamicTailwind,\n );\n\n const componentProps = useMemo(\n () => ({\n ...props,\n }),\n [props],\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n if (module && module.error) {\n return (\n <>\n <div className={cn('relative h-full w-full', classNames)}>\n <LiveError message={module.error} title=\"Compile Error\" />\n </div>\n <LiveError.Runtime open={isError} />\n </>\n );\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <>\n {frame ? (\n <div className={cn('h-full w-full', classNames)}>\n <Frame {...(frame as FrameProps)}>\n {container => (\n <div ref={contentRef} style={{ display: 'contents' }}>\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={(e: Error) => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} container={container} />\n {dynamicTailwind && dynamicCSS && (\n <style>{dynamicCSS}</style>\n )}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n </Frame>\n </div>\n ) : (\n <div\n ref={contentRef}\n className={cn(\n 'relative h-full w-full overflow-x-hidden overflow-y-auto',\n classNames,\n )}\n style={{\n isolation: 'isolate',\n transform: 'translateZ(0)',\n containerType: 'inline-size',\n }}\n >\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={e => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n <LiveError.Runtime open={isError} />\n </>\n );\n};\n\nexport default Client;\n","import type React from 'react';\n\nimport type { FrameProps } from '../frame';\nimport Client from './client';\nimport { NO_MODULES, NO_PROPS } from './defaults';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n code?: string;\n showError?: boolean;\n props?: Record<string, unknown>;\n container?: HTMLElement | null;\n frame?: boolean | FrameProps;\n modules?: Record<string, unknown>;\n dynamicTailwind?: boolean;\n provider?: (children: React.ReactNode) => React.ReactNode;\n}\n\n// A thin wrapper around Client, which does the actual compiling, error\n// handling, and frame wrapping. This used to have its own duplicate\n// compile-and-render branch for the `code` prop that never wrapped its\n// output in <Frame>, so `frame` was silently ignored whenever `code` was\n// passed — see #187. Client already handles `code` (falling back to\n// context when absent) and `frame`, so there is only one render path now.\nconst Preview = ({\n code,\n props = NO_PROPS,\n modules = NO_MODULES,\n dynamicTailwind = false,\n provider,\n ...restProps\n}: Props) => {\n return (\n <Client\n code={code}\n props={props}\n modules={modules}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...restProps}\n />\n );\n};\n\nexport default Preview;\n"],"mappings":";;;;;;;AAGA,MAAa,WAAoC,CAAC;AAClD,MAAa,aAAsC,CAAC;;;ACUpD,MAAM,UAAU,EACd,MAAM,OACN,WACA,WACA,QAAQ,UACR,UAAU,YACV,OACA,kBAAkB,OAClB,eACW;CACX,MAAM,EAAE,SAAS,WAAW;CAC5B,MAAM,EAAE,OAAO,aAAa,SAAS;CACrC,MAAM,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;CAEjC,MAAM,aAAa,GAAG,WAAW,UAAU,SAAS;CAEpD,MAAM,gBAAgB,UAAU,KAAA,IAAY,OAAO;CAEnD,MAAM,SAAS,kBAAkB,eAAe,OAAO;CAIvD,MAAM,EAAE,KAAK,YAAY,KAAK,eAAe,mBAC3C,eACA,eACF;CAEA,MAAM,iBAAiB,eACd,EACL,GAAG,MACL,IACA,CAAC,KAAK,CACR;CAEA,MAAM,kBAAkB,cAA+B;EACrD,OAAO,WAAW,SAAS,SAAS,IAAI;CAC1C;CAEA,IAAI,UAAU,OAAO,OACnB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAW,GAAG,0BAA0B,UAAU;EACrD,UAAA,oBAACA,OAAD;GAAW,SAAS,OAAO;GAAO,OAAM;EAAiB,CAAA;CACtD,CAAA,GACL,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;CAIN,MAAM,YAAY,QAAQ,SAAS;CAEnC,IAAI,CAAC,WACH,OAAO;CAGT,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,QACC,oBAAC,OAAD;EAAK,WAAW,GAAG,iBAAiB,UAAU;EAC5C,UAAA,oBAAC,OAAD;GAAO,GAAK;GACT,WAAA,cACC,oBAAC,OAAD;IAAK,KAAK;IAAY,OAAO,EAAE,SAAS,WAAW;IACjD,UAAA,oBAACA,MAAU,UAAX;KACE,WAAW,CAAC,aAAa;KACzB,UAAU,MAAa,SAAS,EAAE,OAAO;KAExC,UAAA,eACC,qBAACA,MAAU,OAAX;MAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;MAAjD,UAAA,CACE,oBAAC,WAAD;OAAW,GAAI;OAA2B;MAAY,CAAA,GACrD,mBAAmB,cAClB,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAEb;KACnB,CAAA,CAAA;IACkB,CAAA;GACjB,CAAA;EAEF,CAAA;CACJ,CAAA,IAEL,oBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,4DACA,UACF;EACA,OAAO;GACL,WAAW;GACX,WAAW;GACX,eAAe;EACjB;EAEA,UAAA,oBAACA,MAAU,UAAX;GACE,WAAW,CAAC,aAAa;GACzB,UAAS,MAAK,SAAS,EAAE,OAAO;GAE/B,UAAA,eACC,qBAACA,MAAU,OAAX;IAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;IAAjD,UAAA,CACE,oBAAC,WAAD,EAAW,GAAI,eAAiB,CAAA,GAC/B,mBAAmB,cAAc,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAC7C;GACnB,CAAA,CAAA;EACkB,CAAA;CACjB,CAAA,GAEP,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;AAEN;;;ACnGA,MAAM,WAAW,EACf,MACA,QAAQ,UACR,UAAU,YACV,kBAAkB,OAClB,UACA,GAAG,gBACQ;CACX,OACE,oBAAC,QAAD;EACQ;EACC;EACE;EACQ;EACP;EACV,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"preview-BnaCEFsF.js","names":["LiveError"],"sources":["../src/components/preview/defaults.ts","../src/components/preview/client.tsx","../src/components/preview/preview.tsx"],"sourcesContent":["// Stable defaults for optional object props. A `= {}` default is a new\n// object on every render, which re-runs every memo keyed on it — the merged\n// module map, and so `compile()` — even when the caller passed nothing (#348).\nexport const NO_PROPS: Record<string, unknown> = {};\nexport const NO_MODULES: Record<string, unknown> = {};\n","'use client';\n\nimport { useMemo } from 'react';\n\nimport { useError, usePreview } from '~/components/context/states';\nimport LiveError from '~/components/error';\nimport Frame, { type FrameProps } from '~/components/frame';\nimport { cn } from '~/utils/cn';\n\nimport { NO_MODULES, NO_PROPS } from './defaults';\nimport { type Props } from './preview';\nimport { useCompiledModule } from './use-compiled-module';\nimport { useDynamicTailwind } from './use-dynamic-tailwind';\n\nconst Client = ({\n code: _code,\n className,\n showError,\n props = NO_PROPS,\n modules = NO_MODULES,\n frame,\n dynamicTailwind = false,\n provider,\n}: Props) => {\n const { code } = usePreview();\n const { error, setError } = useError();\n const isError = !!showError && !!error;\n\n const classNames = cn(isError && 'hidden', className);\n\n const effectiveCode = _code === undefined ? code : _code;\n\n const module = useCompiledModule(effectiveCode, modules);\n\n // Attached to the wrapper below; scans the rendered DOM so classes coming\n // from an imported component are picked up too. See the hook for details.\n const { ref: contentRef, css: dynamicCSS } = useDynamicTailwind(\n effectiveCode,\n dynamicTailwind,\n );\n\n const componentProps = useMemo(\n () => ({\n ...props,\n }),\n [props],\n );\n\n const renderProvider = (component: React.ReactNode) => {\n return provider ? provider(component) : component;\n };\n\n if (module && module.error) {\n return (\n <>\n <div className={cn('relative h-full w-full', classNames)}>\n <LiveError message={module.error} title=\"Compile Error\" />\n </div>\n <LiveError.Runtime open={isError} />\n </>\n );\n }\n\n const Component = module?.exports?.default;\n\n if (!Component) {\n return null;\n }\n\n return (\n <>\n {frame ? (\n <div className={cn('h-full w-full', classNames)}>\n <Frame {...(frame as FrameProps)}>\n {container => (\n <div ref={contentRef} style={{ display: 'contents' }}>\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={(e: Error) => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} container={container} />\n {dynamicTailwind && dynamicCSS && (\n <style>{dynamicCSS}</style>\n )}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n </Frame>\n </div>\n ) : (\n <div\n ref={contentRef}\n className={cn(\n 'relative h-full w-full overflow-x-hidden overflow-y-auto',\n classNames,\n )}\n style={{\n isolation: 'isolate',\n transform: 'translateZ(0)',\n containerType: 'inline-size',\n }}\n >\n <LiveError.Boundary\n resetKeys={[effectiveCode]}\n onError={e => setError(e.message)}\n >\n {renderProvider(\n <LiveError.Guard onError={e => setError(e.message)}>\n <Component {...componentProps} />\n {dynamicTailwind && dynamicCSS && <style>{dynamicCSS}</style>}\n </LiveError.Guard>,\n )}\n </LiveError.Boundary>\n </div>\n )}\n <LiveError.Runtime open={isError} />\n </>\n );\n};\n\nexport default Client;\n","import type React from 'react';\n\nimport type { FrameProps } from '../frame';\nimport Client from './client';\nimport { NO_MODULES, NO_PROPS } from './defaults';\n\nexport interface Props extends React.ComponentPropsWithRef<'div'> {\n code?: string;\n showError?: boolean;\n props?: Record<string, unknown>;\n container?: HTMLElement | null;\n frame?: boolean | FrameProps;\n modules?: Record<string, unknown>;\n dynamicTailwind?: boolean;\n provider?: (children: React.ReactNode) => React.ReactNode;\n}\n\n// A thin wrapper around Client, which does the actual compiling, error\n// handling, and frame wrapping. This used to have its own duplicate\n// compile-and-render branch for the `code` prop that never wrapped its\n// output in <Frame>, so `frame` was silently ignored whenever `code` was\n// passed — see #187. Client already handles `code` (falling back to\n// context when absent) and `frame`, so there is only one render path now.\nconst Preview = ({\n code,\n props = NO_PROPS,\n modules = NO_MODULES,\n dynamicTailwind = false,\n provider,\n ...restProps\n}: Props) => {\n return (\n <Client\n code={code}\n props={props}\n modules={modules}\n dynamicTailwind={dynamicTailwind}\n provider={provider}\n {...restProps}\n />\n );\n};\n\nexport default Preview;\n"],"mappings":";;;;;;;AAGA,MAAa,WAAoC,CAAC;AAClD,MAAa,aAAsC,CAAC;;;ACUpD,MAAM,UAAU,EACd,MAAM,OACN,WACA,WACA,QAAQ,UACR,UAAU,YACV,OACA,kBAAkB,OAClB,eACW;CACX,MAAM,EAAE,SAAS,WAAW;CAC5B,MAAM,EAAE,OAAO,aAAa,SAAS;CACrC,MAAM,UAAU,CAAC,CAAC,aAAa,CAAC,CAAC;CAEjC,MAAM,aAAa,GAAG,WAAW,UAAU,SAAS;CAEpD,MAAM,gBAAgB,UAAU,KAAA,IAAY,OAAO;CAEnD,MAAM,SAAS,kBAAkB,eAAe,OAAO;CAIvD,MAAM,EAAE,KAAK,YAAY,KAAK,eAAe,mBAC3C,eACA,eACF;CAEA,MAAM,iBAAiB,eACd,EACL,GAAG,MACL,IACA,CAAC,KAAK,CACR;CAEA,MAAM,kBAAkB,cAA+B;EACrD,OAAO,WAAW,SAAS,SAAS,IAAI;CAC1C;CAEA,IAAI,UAAU,OAAO,OACnB,OACE,qBAAA,UAAA,EAAA,UAAA,CACE,oBAAC,OAAD;EAAK,WAAW,GAAG,0BAA0B,UAAU;EACrD,UAAA,oBAACA,OAAD;GAAW,SAAS,OAAO;GAAO,OAAM;EAAiB,CAAA;CACtD,CAAA,GACL,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;CAIN,MAAM,YAAY,QAAQ,SAAS;CAEnC,IAAI,CAAC,WACH,OAAO;CAGT,OACE,qBAAA,UAAA,EAAA,UAAA,CACG,QACC,oBAAC,OAAD;EAAK,WAAW,GAAG,iBAAiB,UAAU;EAC5C,UAAA,oBAAC,OAAD;GAAO,GAAK;GACT,WAAA,cACC,oBAAC,OAAD;IAAK,KAAK;IAAY,OAAO,EAAE,SAAS,WAAW;IACjD,UAAA,oBAACA,MAAU,UAAX;KACE,WAAW,CAAC,aAAa;KACzB,UAAU,MAAa,SAAS,EAAE,OAAO;KAExC,UAAA,eACC,qBAACA,MAAU,OAAX;MAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;MAAjD,UAAA,CACE,oBAAC,WAAD;OAAW,GAAI;OAA2B;MAAY,CAAA,GACrD,mBAAmB,cAClB,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAEb;KACnB,CAAA,CAAA;IACkB,CAAA;GACjB,CAAA;EAEF,CAAA;CACJ,CAAA,IAEL,oBAAC,OAAD;EACE,KAAK;EACL,WAAW,GACT,4DACA,UACF;EACA,OAAO;GACL,WAAW;GACX,WAAW;GACX,eAAe;EACjB;EAEA,UAAA,oBAACA,MAAU,UAAX;GACE,WAAW,CAAC,aAAa;GACzB,UAAS,MAAK,SAAS,EAAE,OAAO;GAE/B,UAAA,eACC,qBAACA,MAAU,OAAX;IAAiB,UAAS,MAAK,SAAS,EAAE,OAAO;IAAjD,UAAA,CACE,oBAAC,WAAD,EAAW,GAAI,eAAiB,CAAA,GAC/B,mBAAmB,cAAc,oBAAC,SAAD,EAAA,UAAQ,WAAkB,CAAA,CAC7C;GACnB,CAAA,CAAA;EACkB,CAAA;CACjB,CAAA,GAEP,oBAACA,MAAU,SAAX,EAAmB,MAAM,QAAU,CAAA,CACnC,EAAA,CAAA;AAEN;;;ACnGA,MAAM,WAAW,EACf,MACA,QAAQ,UACR,UAAU,YACV,kBAAkB,OAClB,UACA,GAAG,gBACQ;CACX,OACE,oBAAC,QAAD;EACQ;EACC;EACE;EACQ;EACP;EACV,GAAI;CACL,CAAA;AAEL"}
@@ -1,2 +1,2 @@
1
- import { t as ContextProvider } from "../context-93X3gyfJ.js";
1
+ import { t as ContextProvider } from "../context-DB5kW3qe.js";
2
2
  export { ContextProvider as default };
@@ -1,5 +1,5 @@
1
- import { a as generateSectionPreview, l as parseDocument, o as generateSectionPreviews, s as getSections, u as replaceDocumentSections } from "./document-cEEdFERz.js";
2
- import { i as DEFAULT_CONTAINER_ID, u as documentTemplate } from "./constants-CKvdqZtO.js";
1
+ import { a as generateSectionPreview, l as parseDocument, o as generateSectionPreviews, s as getSections, u as replaceDocumentSections } from "./document-BDn_f08_.js";
2
+ import { i as DEFAULT_CONTAINER_ID, u as documentTemplate } from "./constants-h1JAgOeW.js";
3
3
  //#region src/utils/sections.ts
4
4
  const extractSections = (code, options) => {
5
5
  const doc = parseDocument(code, options);
@@ -21,4 +21,4 @@ const createDocument = ({ containerId = DEFAULT_CONTAINER_ID } = {}) => {
21
21
  //#endregion
22
22
  export { replaceSections as a, generateSections as i, extractSections as n, generateSection as r, createDocument as t };
23
23
 
24
- //# sourceMappingURL=sections-GJQ63uEB.js.map
24
+ //# sourceMappingURL=sections-CBVMO8Jl.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sections-GJQ63uEB.js","names":[],"sources":["../src/utils/sections.ts"],"sourcesContent":["import { DEFAULT_CONTAINER_ID, documentTemplate } from '~/constants';\nimport type { Section } from '~/types';\n\nimport {\n type DocumentOptions,\n type SectionOptions,\n createSectionPreviewCache,\n generateSectionPreview,\n generateSectionPreviews,\n getSections,\n parseDocument,\n replaceDocumentSections,\n} from './ast/document';\n\nexport const extractSections = (\n code: string,\n options?: SectionOptions,\n): Section[] => {\n const doc = parseDocument(code, options);\n\n return doc ? getSections(doc, options) : [];\n};\n\nexport const replaceSections = (\n code: string,\n sections: string[],\n options?: DocumentOptions,\n): string => {\n return replaceDocumentSections(code, sections, options);\n};\n\nexport const generateSection = (\n code: string,\n fullCode: string,\n options?: DocumentOptions,\n) => {\n return generateSectionPreview(fullCode, code, options);\n};\n\n// Batched form of generateSection() — computes every section's preview from\n// a single parse of fullCode instead of one parseDocument call per section\n// (see generateSectionPreviews). Unchanged sections come back byte-identical\n// to their previous preview string, which is what lets a caller pass each\n// one down as a stable prop (see Renderer's React.memo).\nexport const generateSections = (\n codes: string[],\n fullCode: string,\n options?: DocumentOptions,\n): string[] => {\n return generateSectionPreviews(fullCode, codes, options);\n};\n\n// A new, empty document `Live.Dnd` can add sections to: an `App` component\n// rendering the container element and nothing else. Start a controlled\n// `Live.Dnd` from this rather than an empty string, which has no container,\n// so nothing dropped on the canvas would land anywhere (#449). Pass the same\n// `containerId` you give `Live.Dnd`.\nexport const createDocument = ({\n containerId = DEFAULT_CONTAINER_ID,\n}: DocumentOptions = {}): string => {\n // The id is written into a JSX attribute as-is, so anything that could end\n // the attribute or the tag is refused rather than producing broken source.\n if (!/^[^\\s\"'<>{}]+$/.test(containerId)) {\n throw new Error(\n `createDocument: containerId must be a plain element id, got ${JSON.stringify(containerId)}`,\n );\n }\n\n return documentTemplate(containerId);\n};\n\n// Incremental counterpart to generateSections() — see createSectionPreviewCache\n// (#131). Pass a fresh instance's `compute` in place of generateSections()\n// where the caller can keep it alive across renders (e.g. Dnd holds one via\n// `useState(() => createSectionPreviewCache())`).\nexport { createSectionPreviewCache };\nexport type {\n DocumentOptions,\n SectionOptions,\n SectionPreviewCache,\n} from './ast/document';\n"],"mappings":";;;AAcA,MAAa,mBACX,MACA,YACc;CACd,MAAM,MAAM,cAAc,MAAM,OAAO;CAEvC,OAAO,MAAM,YAAY,KAAK,OAAO,IAAI,CAAC;AAC5C;AAEA,MAAa,mBACX,MACA,UACA,YACW;CACX,OAAO,wBAAwB,MAAM,UAAU,OAAO;AACxD;AAEA,MAAa,mBACX,MACA,UACA,YACG;CACH,OAAO,uBAAuB,UAAU,MAAM,OAAO;AACvD;AAOA,MAAa,oBACX,OACA,UACA,YACa;CACb,OAAO,wBAAwB,UAAU,OAAO,OAAO;AACzD;AAOA,MAAa,kBAAkB,EAC7B,cAAc,yBACK,CAAC,MAAc;CAGlC,IAAI,CAAC,iBAAiB,KAAK,WAAW,GACpC,MAAM,IAAI,MACR,+DAA+D,KAAK,UAAU,WAAW,GAC3F;CAGF,OAAO,iBAAiB,WAAW;AACrC"}
1
+ {"version":3,"file":"sections-CBVMO8Jl.js","names":[],"sources":["../src/utils/sections.ts"],"sourcesContent":["import { DEFAULT_CONTAINER_ID, documentTemplate } from '~/constants';\nimport type { Section } from '~/types';\n\nimport {\n type DocumentOptions,\n type SectionOptions,\n createSectionPreviewCache,\n generateSectionPreview,\n generateSectionPreviews,\n getSections,\n parseDocument,\n replaceDocumentSections,\n} from './ast/document';\n\nexport const extractSections = (\n code: string,\n options?: SectionOptions,\n): Section[] => {\n const doc = parseDocument(code, options);\n\n return doc ? getSections(doc, options) : [];\n};\n\nexport const replaceSections = (\n code: string,\n sections: string[],\n options?: DocumentOptions,\n): string => {\n return replaceDocumentSections(code, sections, options);\n};\n\nexport const generateSection = (\n code: string,\n fullCode: string,\n options?: DocumentOptions,\n) => {\n return generateSectionPreview(fullCode, code, options);\n};\n\n// Batched form of generateSection() — computes every section's preview from\n// a single parse of fullCode instead of one parseDocument call per section\n// (see generateSectionPreviews). Unchanged sections come back byte-identical\n// to their previous preview string, which is what lets a caller pass each\n// one down as a stable prop (see Renderer's React.memo).\nexport const generateSections = (\n codes: string[],\n fullCode: string,\n options?: DocumentOptions,\n): string[] => {\n return generateSectionPreviews(fullCode, codes, options);\n};\n\n// A new, empty document `Live.Dnd` can add sections to: an `App` component\n// rendering the container element and nothing else. Start a controlled\n// `Live.Dnd` from this rather than an empty string, which has no container,\n// so nothing dropped on the canvas would land anywhere (#449). Pass the same\n// `containerId` you give `Live.Dnd`.\nexport const createDocument = ({\n containerId = DEFAULT_CONTAINER_ID,\n}: DocumentOptions = {}): string => {\n // The id is written into a JSX attribute as-is, so anything that could end\n // the attribute or the tag is refused rather than producing broken source.\n if (!/^[^\\s\"'<>{}]+$/.test(containerId)) {\n throw new Error(\n `createDocument: containerId must be a plain element id, got ${JSON.stringify(containerId)}`,\n );\n }\n\n return documentTemplate(containerId);\n};\n\n// Incremental counterpart to generateSections() — see createSectionPreviewCache\n// (#131). Pass a fresh instance's `compute` in place of generateSections()\n// where the caller can keep it alive across renders (e.g. Dnd holds one via\n// `useState(() => createSectionPreviewCache())`).\nexport { createSectionPreviewCache };\nexport type {\n DocumentOptions,\n SectionOptions,\n SectionPreviewCache,\n} from './ast/document';\n"],"mappings":";;;AAcA,MAAa,mBACX,MACA,YACc;CACd,MAAM,MAAM,cAAc,MAAM,OAAO;CAEvC,OAAO,MAAM,YAAY,KAAK,OAAO,IAAI,CAAC;AAC5C;AAEA,MAAa,mBACX,MACA,UACA,YACW;CACX,OAAO,wBAAwB,MAAM,UAAU,OAAO;AACxD;AAEA,MAAa,mBACX,MACA,UACA,YACG;CACH,OAAO,uBAAuB,UAAU,MAAM,OAAO;AACvD;AAOA,MAAa,oBACX,OACA,UACA,YACa;CACb,OAAO,wBAAwB,UAAU,OAAO,OAAO;AACzD;AAOA,MAAa,kBAAkB,EAC7B,cAAc,yBACK,CAAC,MAAc;CAGlC,IAAI,CAAC,iBAAiB,KAAK,WAAW,GACpC,MAAM,IAAI,MACR,+DAA+D,KAAK,UAAU,WAAW,GAC3F;CAGF,OAAO,iBAAiB,WAAW;AACrC"}
@@ -1,4 +1,4 @@
1
- import { n as compile, s as withScriptBlobs } from "./compile-0Dvp8zp5.js";
1
+ import { n as compile, s as withScriptBlobs } from "./compile-DDfk5P25.js";
2
2
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import * as ui from "@jbpark/ui-kit";
@@ -90,6 +90,30 @@ const reconcileStyles = (sourceDocument, target, manager, enabled, transformStyl
90
90
  previous = clone;
91
91
  });
92
92
  };
93
+ const createRootAttributeSync = () => ({
94
+ attributes: /* @__PURE__ */ new Set(),
95
+ classes: /* @__PURE__ */ new Set()
96
+ });
97
+ const isMirroredAttribute = (name) => name.startsWith("data-");
98
+ const reconcileRootAttributes = (source, target, sync, enabled) => {
99
+ const attributes = enabled ? Array.from(source.attributes).filter(({ name }) => isMirroredAttribute(name)) : [];
100
+ const classes = enabled ? Array.from(source.classList) : [];
101
+ const attributeNames = new Set(attributes.map(({ name }) => name));
102
+ const classNames = new Set(classes);
103
+ sync.attributes.forEach((name) => {
104
+ if (!attributeNames.has(name)) target.removeAttribute(name);
105
+ });
106
+ attributes.forEach(({ name, value }) => {
107
+ if (target.getAttribute(name) !== value) target.setAttribute(name, value);
108
+ });
109
+ sync.classes.forEach((name) => {
110
+ if (!classNames.has(name)) target.classList.remove(name);
111
+ });
112
+ classes.forEach((name) => target.classList.add(name));
113
+ if (!target.classList.length) target.removeAttribute("class");
114
+ sync.attributes = attributeNames;
115
+ sync.classes = classNames;
116
+ };
93
117
  //#endregion
94
118
  //#region src/components/frame/viewport-units.ts
95
119
  const UNIT_MAP = {
@@ -149,6 +173,7 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
149
173
  const iframeRef = useRef(null);
150
174
  const [mountNode, setMountNode] = useState(null);
151
175
  const loadedScriptsRef = useRef(/* @__PURE__ */ new Set());
176
+ const loadedScriptsDocRef = useRef(null);
152
177
  const prevStyleCountRef = useRef(0);
153
178
  const prevStylesheetCountRef = useRef(0);
154
179
  const trackedAnimationsRef = useRef(/* @__PURE__ */ new WeakSet());
@@ -156,10 +181,12 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
156
181
  const lastProbeHeightRef = useRef(void 0);
157
182
  const shouldAutoHeight = autoHeight && style.height == null;
158
183
  const styleManagerRef = useRef(createStyleSyncManager());
184
+ const rootAttributeSyncRef = useRef(createRootAttributeSync());
159
185
  const applyStyle = useCallback(() => {
160
186
  const doc = iframeRef.current?.contentDocument;
161
187
  if (!doc) return;
162
188
  reconcileStyles(document, doc, styleManagerRef.current, syncStyle, convertViewportUnits, doc.getElementById(CONTAINER_STYLE_ID));
189
+ reconcileRootAttributes(document.documentElement, doc.documentElement, rootAttributeSyncRef.current, syncStyle);
163
190
  }, [syncStyle]);
164
191
  const applyStyleTimeoutRef = useRef(void 0);
165
192
  const debouncedApplyStyle = useCallback(() => {
@@ -175,12 +202,20 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
175
202
  subtree: true,
176
203
  attributes: true
177
204
  });
205
+ useMutationObserver(document.documentElement, debouncedApplyStyle, {
206
+ enabled: syncStyle,
207
+ attributes: true
208
+ });
178
209
  useEffect(() => {
179
210
  const $iframe = iframeRef.current;
180
211
  if (!$iframe) return;
181
212
  const onLoad = () => {
182
213
  const doc = $iframe.contentDocument;
183
214
  if (!doc) return;
215
+ if (loadedScriptsDocRef.current !== doc) {
216
+ loadedScriptsDocRef.current = doc;
217
+ loadedScriptsRef.current = /* @__PURE__ */ new Set();
218
+ }
184
219
  doc.body.style.overflowX = "hidden";
185
220
  doc.body.style.margin = "0";
186
221
  let node = doc.getElementById("iframe-root");
@@ -318,6 +353,12 @@ const IFrame = ({ title = "Live Preview", sandbox, style = {}, scripts = EMPTY_S
318
353
  if (shouldAutoHeight) return;
319
354
  iframeRef.current?.contentDocument?.getElementById(CONTAINER_STYLE_ID)?.remove();
320
355
  }, [shouldAutoHeight]);
356
+ useEffect(() => {
357
+ const body = iframeRef.current?.contentDocument?.body;
358
+ if (!body || !mountNode) return;
359
+ if (shouldAutoHeight) body.style.removeProperty("overflow-y");
360
+ else body.style.setProperty("overflow-y", "auto");
361
+ }, [shouldAutoHeight, mountNode]);
321
362
  useEffect(() => {
322
363
  const doc = iframeRef.current?.contentDocument;
323
364
  if (!doc?.head) return;
@@ -527,4 +568,4 @@ const useDynamicTailwind = (code, enabled) => {
527
568
  //#endregion
528
569
  export { Frame as a, useStableModules as i, useCompiledModule as n, baseModules as r, useDynamicTailwind as t };
529
570
 
530
- //# sourceMappingURL=use-dynamic-tailwind-DpbjmATF.js.map
571
+ //# sourceMappingURL=use-dynamic-tailwind-Bcipc1hL.js.map