@nuforge/editor 0.1.3 → 0.3.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.
- package/dist/index.cjs +190 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +252 -3
- package/dist/index.mjs +186 -1
- package/dist/index.mjs.map +1 -0
- package/dist/react.cjs +338 -5
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.ts +210 -4
- package/dist/react.mjs +338 -7
- package/dist/react.mjs.map +1 -0
- package/package.json +7 -7
package/dist/react.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { ReactNode } from 'react';
|
|
|
3
3
|
import * as t from '@nuforge/types';
|
|
4
4
|
import { MutationEntry } from '@nuforge/reactivity';
|
|
5
5
|
|
|
6
|
+
/** A control hint for auto-generating inspector fields from a block's props. */
|
|
6
7
|
interface PropSchemaField {
|
|
7
8
|
name: string;
|
|
8
9
|
type: 'string' | 'number' | 'boolean' | 'expression' | 'enum';
|
|
@@ -10,6 +11,11 @@ interface PropSchemaField {
|
|
|
10
11
|
default?: string | number | boolean;
|
|
11
12
|
options?: string[];
|
|
12
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* A reusable element/block in the palette. `create()` returns a fresh template
|
|
16
|
+
* subtree to insert. `icon` is a name (not a component) so the registry stays
|
|
17
|
+
* framework-agnostic; the UI maps the name to its own icon set.
|
|
18
|
+
*/
|
|
13
19
|
interface Block {
|
|
14
20
|
id: string;
|
|
15
21
|
label: string;
|
|
@@ -27,6 +33,35 @@ declare class BlockRegistry {
|
|
|
27
33
|
byCategory(): Record<string, Block[]>;
|
|
28
34
|
}
|
|
29
35
|
|
|
36
|
+
/** Where a dragged node is dropped relative to a target. */
|
|
37
|
+
type DropPosition = 'before' | 'after' | 'inside';
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Wire protocol for `RemoteCanvasHost` <-> `createCanvasReceiver`: a genuinely
|
|
41
|
+
* navigated `/canvas/[id]`-style iframe has its own JS realm, so state and
|
|
42
|
+
* interaction can't cross as direct object references the way `IframeCanvas`'s
|
|
43
|
+
* portal allows — everything here is a structured-clone-safe plain message.
|
|
44
|
+
*
|
|
45
|
+
* Deliberately generic: only the shapes the editor primitive itself needs
|
|
46
|
+
* (state sync, ready handshake, the core interaction events) are typed. Host
|
|
47
|
+
* concerns like theme/preview-mode/overrides ride through `CanvasUiMessage`'s
|
|
48
|
+
* opaque `payload` — this package relays it, never interprets it.
|
|
49
|
+
*/
|
|
50
|
+
declare const CANVAS_CHANNEL = "nuforge-canvas";
|
|
51
|
+
declare const CANVAS_PROTOCOL_VERSION = 1;
|
|
52
|
+
interface CanvasKeydownMessage {
|
|
53
|
+
channel: typeof CANVAS_CHANNEL;
|
|
54
|
+
v: typeof CANVAS_PROTOCOL_VERSION;
|
|
55
|
+
type: 'keydown';
|
|
56
|
+
key: string;
|
|
57
|
+
code: string;
|
|
58
|
+
ctrlKey: boolean;
|
|
59
|
+
metaKey: boolean;
|
|
60
|
+
shiftKey: boolean;
|
|
61
|
+
altKey: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** A named action a UI can discover and bind to (toolbar buttons, shortcuts). */
|
|
30
65
|
interface Command {
|
|
31
66
|
id: string;
|
|
32
67
|
label: string;
|
|
@@ -43,40 +78,68 @@ declare class CommandRegistry {
|
|
|
43
78
|
run(id: string): void;
|
|
44
79
|
}
|
|
45
80
|
|
|
46
|
-
type DropPosition = 'before' | 'after' | 'inside';
|
|
47
|
-
|
|
48
81
|
interface CreateEditorOptions {
|
|
82
|
+
/** Extra blocks to add to the palette. */
|
|
49
83
|
blocks?: Block[];
|
|
84
|
+
/** Include the built-in DEFAULT_BLOCKS (default true). */
|
|
50
85
|
defaultBlocks?: boolean;
|
|
51
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* A high-level facade over a {@link Nu} runtime for building visual page
|
|
89
|
+
* editors. Every mutation goes through `nu.change`, so it is transactional and
|
|
90
|
+
* undoable. Reach for these instead of hand-splicing the AST.
|
|
91
|
+
*/
|
|
52
92
|
declare class Editor {
|
|
53
93
|
readonly nu: Nu;
|
|
54
94
|
readonly blocks: BlockRegistry;
|
|
55
95
|
readonly commands: CommandRegistry;
|
|
56
96
|
constructor(nu: Nu, opts?: CreateEditorOptions);
|
|
97
|
+
/** Append (or insert at `index`) `child` into `parent`'s children. */
|
|
57
98
|
insertNode(parent: t.Template, child: t.Template, index?: number): void;
|
|
99
|
+
/** Remove a node from its parent. Returns false if it has no parent. */
|
|
58
100
|
removeNode(node: t.Template): boolean;
|
|
101
|
+
/** Move `dragged` before/after/inside `target`. Refuses to nest into self. */
|
|
59
102
|
moveNode(dragged: t.Template, target: t.Template, position: DropPosition): boolean;
|
|
60
103
|
private clipboardNode;
|
|
104
|
+
/** Put a node on the editor clipboard (a clone is made on paste). */
|
|
61
105
|
copyNode(node: t.Template): void;
|
|
106
|
+
/** Copy a node, then remove it. */
|
|
62
107
|
cutNode(node: t.Template): boolean;
|
|
108
|
+
/** Whether there is something on the clipboard to paste. */
|
|
63
109
|
canPaste(): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Paste a fresh copy (new ids) of the clipboard node before/after/inside
|
|
112
|
+
* `target`. Returns the inserted node, or null if nothing was pasted.
|
|
113
|
+
*/
|
|
64
114
|
pasteNode(target: t.Template, position?: DropPosition): t.Template | null;
|
|
115
|
+
/** Duplicate a node in place (inserted right after it). Returns the copy. */
|
|
65
116
|
duplicateNode(node: t.Template): t.Template | null;
|
|
117
|
+
/**
|
|
118
|
+
* Insert a detached node before/after/inside a target (undoable). The core of
|
|
119
|
+
* canvas drag-and-drop: a drop computes a target + position, then calls this.
|
|
120
|
+
* Returns the inserted node.
|
|
121
|
+
*/
|
|
66
122
|
insertNodeAt(node: t.Template, target: t.Template, position: DropPosition): t.Template | null;
|
|
123
|
+
/** Create a block and insert it before/after/inside a target. */
|
|
67
124
|
insertBlockAt(blockId: string, target: t.Template, position: DropPosition): t.Template | null;
|
|
68
125
|
private insertCloneRelativeTo;
|
|
126
|
+
/** Set several props at once. */
|
|
69
127
|
updateProps(node: t.Template, props: Record<string, t.Expression>): void;
|
|
70
128
|
setProp(node: t.Template, key: string, expr: t.Expression): void;
|
|
71
129
|
removeProp(node: t.Template, key: string): void;
|
|
130
|
+
/** Parse `source` as a nuforge expression and assign it to `key`. */
|
|
72
131
|
setExpression(node: t.Template, key: string, source: string): boolean;
|
|
132
|
+
/** Update a text node's literal value. */
|
|
73
133
|
setText(node: t.Template, value: string): boolean;
|
|
74
134
|
setTag(node: t.TagTemplate, tag: string): void;
|
|
75
135
|
addClass(node: t.Template, name: string): void;
|
|
136
|
+
/** Parse `source` and set the condition under which class `name` applies. */
|
|
76
137
|
setClassCondition(node: t.Template, name: string, source: string): boolean;
|
|
77
138
|
removeClass(node: t.Template, name: string): void;
|
|
139
|
+
/** Set the `@if` condition from source. */
|
|
78
140
|
setCondition(node: t.Template, source: string): boolean;
|
|
79
141
|
clearCondition(node: t.Template): void;
|
|
142
|
+
/** Repeat a node over `iterator` (a list expression), binding each `alias`. */
|
|
80
143
|
setEach(node: t.Template, iterator: string, alias?: string, indexName?: string): boolean;
|
|
81
144
|
clearEach(node: t.Template): void;
|
|
82
145
|
addState(component: t.NuComponent, name?: string, init?: string): t.Val;
|
|
@@ -85,9 +148,12 @@ declare class Editor {
|
|
|
85
148
|
addComponentProp(component: t.NuComponent, name?: string, init?: string): t.ComponentProp;
|
|
86
149
|
removeComponentProp(component: t.NuComponent, prop: t.ComponentProp): void;
|
|
87
150
|
setComponentPropInit(prop: t.ComponentProp, source: string): boolean;
|
|
151
|
+
/** Create a block's template and insert it into `parent`. */
|
|
88
152
|
insertBlock(blockId: string, parent: t.Template, index?: number): t.Template | null;
|
|
89
153
|
private uniqueName;
|
|
154
|
+
/** Add a new component (a "page"). */
|
|
90
155
|
addComponent(name?: string): t.NuComponent;
|
|
156
|
+
/** Rename a component, updating `<Name/>` references across the program. */
|
|
91
157
|
renameComponent(component: t.NuComponent, name: string): boolean;
|
|
92
158
|
removeComponent(component: t.NuComponent): boolean;
|
|
93
159
|
duplicateComponent(component: t.NuComponent): t.NuComponent;
|
|
@@ -98,11 +164,15 @@ declare class Editor {
|
|
|
98
164
|
getChildren(node: t.Template): t.Template[];
|
|
99
165
|
getSiblings(node: t.Template): t.Template[];
|
|
100
166
|
getNodeIndex(node: t.Template): number;
|
|
167
|
+
/** Full path from the State root to this node (for selections/serialization). */
|
|
101
168
|
getNodePath(node: t.Type): Array<string | number>;
|
|
169
|
+
/** Fires with the raw field-level writes of every change (incl. undo/redo). */
|
|
102
170
|
onChange(cb: (entries: MutationEntry[]) => void): () => void;
|
|
171
|
+
/** Fires only when the tree shape changes (a child array was mutated). */
|
|
103
172
|
onStructureChange(cb: () => void): () => void;
|
|
104
173
|
private spliceFromParent;
|
|
105
174
|
private applyMove;
|
|
175
|
+
/** Insert an already-detached node relative to `target` (no removal). */
|
|
106
176
|
private insertRelativeTo;
|
|
107
177
|
}
|
|
108
178
|
|
|
@@ -112,27 +182,77 @@ interface Rect {
|
|
|
112
182
|
width: number;
|
|
113
183
|
height: number;
|
|
114
184
|
}
|
|
185
|
+
interface CanvasWindow {
|
|
186
|
+
/** The canvas's own document — the iframe's, inside `IframeCanvas`. */
|
|
187
|
+
doc: Document | null;
|
|
188
|
+
/** The canvas's own window — the iframe's, inside `IframeCanvas`. */
|
|
189
|
+
window: Window | null;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The real `window`/`document` a canvas-rendered element visually lives in.
|
|
193
|
+
* `IframeCanvas` portals its content into an `<iframe>`, but a portal only
|
|
194
|
+
* relocates DOM nodes — the JS building them still runs in the host page's
|
|
195
|
+
* realm. Any library that reads a bare `window`/`document` global (scroll
|
|
196
|
+
* listeners, `matchMedia`, `ResizeObserver`/`IntersectionObserver` defaults)
|
|
197
|
+
* silently ends up watching the HOST page, not the iframe the user actually
|
|
198
|
+
* sees and scrolls. Build refs/options from `useCanvasWindow()` instead of the
|
|
199
|
+
* ambient global so they resolve to the right realm — this works identically
|
|
200
|
+
* outside `IframeCanvas` too (e.g. `NuFrame`'s direct, non-iframe render),
|
|
201
|
+
* where it's just the ambient `window`/`document`.
|
|
202
|
+
*/
|
|
203
|
+
declare function useCanvasWindow(): CanvasWindow;
|
|
204
|
+
/** Reactive renderer for a frame, decorating each element with `data-nu-id`. */
|
|
115
205
|
declare const EditorFrame: (props: {
|
|
116
206
|
frame: Frame;
|
|
117
207
|
}) => ReactNode;
|
|
208
|
+
/** Map a DOM node (or event target) back to its template id. */
|
|
118
209
|
declare function templateIdFromElement(target: EventTarget | null): string | null;
|
|
210
|
+
/** Sensible default styling for the isolated canvas document. */
|
|
119
211
|
declare const DEFAULT_CANVAS_CSS = "\n *, *::before, *::after { box-sizing: border-box; }\n html, body { margin: 0; }\n body { font-family: ui-sans-serif, system-ui, -apple-system, sans-serif; color: #111; line-height: 1.5; padding: 28px; }\n h1 { font-size: 2rem; font-weight: 700; margin: .5em 0; }\n h2 { font-size: 1.5rem; font-weight: 600; margin: .6em 0; }\n h3 { font-size: 1.2rem; font-weight: 600; margin: .7em 0; }\n p { margin: .8em 0; }\n ul { list-style: disc; padding-left: 1.5em; margin: .8em 0; }\n ol { list-style: decimal; padding-left: 1.5em; margin: .8em 0; }\n a { color: #2563eb; text-decoration: underline; }\n button { border: 1px solid #d4d4d8; border-radius: 6px; padding: 4px 12px; background: #fafafa; cursor: pointer; font: inherit; }\n button:hover { background: #f4f4f5; }\n input, textarea, select { border: 1px solid #d4d4d8; border-radius: 6px; padding: 4px 8px; font: inherit; }\n section { display: flex; align-items: center; gap: .75rem; margin: .8em 0; }\n img { max-width: 100%; }\n [data-nu-id] { cursor: default; }\n";
|
|
120
212
|
interface IframeCanvasProps {
|
|
121
213
|
frame: Frame;
|
|
122
214
|
selectedId?: string | null;
|
|
123
215
|
hoveredId?: string | null;
|
|
216
|
+
/** Bump to force the overlay to recompute (e.g. on every committed change). */
|
|
124
217
|
revision?: number;
|
|
218
|
+
/**
|
|
219
|
+
* Turn the canvas into a live, interactive preview. When `true`, the editing
|
|
220
|
+
* affordances are switched off: clicks and hovers pass through to the real
|
|
221
|
+
* elements (buttons fire, links work, inputs focus), drag-and-drop editing is
|
|
222
|
+
* disabled, and no overlay is drawn. When `false` (the default) the canvas is
|
|
223
|
+
* in edit mode — clicks select instead of activating, hover highlights, and
|
|
224
|
+
* `onDropOnNode` / `renderBox` are live. The same reactive `frame` is shown in
|
|
225
|
+
* both modes, so toggling is instant and state is preserved.
|
|
226
|
+
*/
|
|
125
227
|
previewMode?: boolean;
|
|
126
228
|
onSelect?: (id: string | null) => void;
|
|
127
229
|
onHover?: (id: string | null) => void;
|
|
230
|
+
/**
|
|
231
|
+
* Enable drop-on-canvas: fired when something is dropped onto a node. Compute
|
|
232
|
+
* a block to insert and call `editor.insertBlockAt(blockId, target, position)`.
|
|
233
|
+
*/
|
|
128
234
|
onDropOnNode?: (targetId: string, position: DropPosition, event: DragEvent) => void;
|
|
235
|
+
/** CSS injected into the isolated document (defaults to DEFAULT_CANVAS_CSS). */
|
|
129
236
|
baseCss?: string;
|
|
237
|
+
/**
|
|
238
|
+
* Initial HTML for the iframe document — put anything in the `<head>` (CDN
|
|
239
|
+
* stylesheets, web fonts, `<script>` tags, a `<base>`, meta). The frame is
|
|
240
|
+
* portaled into its `<body>`. `baseCss` is still appended on top; pass
|
|
241
|
+
* `baseCss=""` to fully control styling from here.
|
|
242
|
+
*/
|
|
130
243
|
srcDoc?: string;
|
|
131
244
|
className?: string;
|
|
132
245
|
containerClassName?: string;
|
|
246
|
+
/**
|
|
247
|
+
* Build the overlay from the computed selection / hover / drop rects and the
|
|
248
|
+
* selected element's tag. Omit it for no overlay. The overlay container is
|
|
249
|
+
* pointer-events:none — set `pointerEvents: 'auto'` on interactive bits (e.g.
|
|
250
|
+
* an action toolbar) so they receive clicks.
|
|
251
|
+
*/
|
|
133
252
|
renderBox?: (rects: {
|
|
134
253
|
selected: Rect | null;
|
|
135
254
|
hovered: Rect | null;
|
|
255
|
+
/** Tag name of the selected element, e.g. `"div"`. */
|
|
136
256
|
selectedLabel: string | null;
|
|
137
257
|
drop: {
|
|
138
258
|
rect: Rect;
|
|
@@ -140,17 +260,103 @@ interface IframeCanvasProps {
|
|
|
140
260
|
} | null;
|
|
141
261
|
}) => ReactNode;
|
|
142
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* A style-isolated editor canvas: the frame is portaled into an `<iframe>` so
|
|
265
|
+
* the host's CSS can't leak into the preview (and vice-versa). Selection/hover
|
|
266
|
+
* use native capture listeners on the iframe document, so element handlers stay
|
|
267
|
+
* inert while editing. Selection/hover rects are computed (in a layout effect,
|
|
268
|
+
* after the iframe commits) and handed to `renderBox` for the overlay.
|
|
269
|
+
*/
|
|
143
270
|
declare function IframeCanvas({ frame, selectedId, hoveredId, revision, previewMode, onSelect, onHover, onDropOnNode, baseCss, srcDoc, className, containerClassName, renderBox, }: IframeCanvasProps): ReactNode;
|
|
271
|
+
interface RemoteCanvasHostProps {
|
|
272
|
+
/** The host's `Nu` instance — flattened and pushed to the canvas realm on
|
|
273
|
+
* every committed change. Never referenced directly by the canvas realm: a
|
|
274
|
+
* real `src` navigation puts it in a separate JS realm with no shared
|
|
275
|
+
* object identity, unlike `IframeCanvas`'s portal. */
|
|
276
|
+
nu: Nu;
|
|
277
|
+
/** Which component the canvas should render (`Nu.createFrame`'s `component.name`). */
|
|
278
|
+
activeComponent: string;
|
|
279
|
+
/** The canvas route's URL, e.g. `/canvas/my-project`. The `BroadcastChannel`
|
|
280
|
+
* name is derived from it, so `createCanvasReceiver` on the other end just
|
|
281
|
+
* needs the SAME `src` — no separate id to keep in sync. */
|
|
282
|
+
src: string;
|
|
283
|
+
selectedId?: string | null;
|
|
284
|
+
hoveredId?: string | null;
|
|
285
|
+
/** Bump to force the overlay to recompute (e.g. on every committed change). */
|
|
286
|
+
revision?: number;
|
|
287
|
+
/**
|
|
288
|
+
* Mirrors `IframeCanvas`'s `previewMode`: when `true`, the canvas is a live,
|
|
289
|
+
* interactive preview (its own DSL `onClick` handlers run against the
|
|
290
|
+
* canvas's local `Nu`, since that instance is genuinely loaded and mutable —
|
|
291
|
+
* see `createCanvasReceiver`'s docs). Toggling this (either direction) forces
|
|
292
|
+
* a fresh `init` instead of an incremental `patch`, so any preview-only
|
|
293
|
+
* local mutation never lingers once you're back in edit mode.
|
|
294
|
+
*/
|
|
295
|
+
previewMode?: boolean;
|
|
296
|
+
/** Opaque host-defined payload (theme CSS, hide/lock overrides, ...) pushed
|
|
297
|
+
* to the canvas via a `ui` message whenever this reference changes. */
|
|
298
|
+
uiPayload?: unknown;
|
|
299
|
+
onSelect?: (id: string | null) => void;
|
|
300
|
+
onHover?: (id: string | null) => void;
|
|
301
|
+
onDropOnNode?: (targetId: string, position: DropPosition) => void;
|
|
302
|
+
onKeydownRelay?: (e: Omit<CanvasKeydownMessage, 'channel' | 'v' | 'type'>) => void;
|
|
303
|
+
onLinkClick?: (href: string) => void;
|
|
304
|
+
className?: string;
|
|
305
|
+
containerClassName?: string;
|
|
306
|
+
/**
|
|
307
|
+
* Build the overlay from the computed selection / hover rects and the
|
|
308
|
+
* selected element's tag — same contract as `IframeCanvas`'s `renderBox`
|
|
309
|
+
* (no `drop` rect: the canvas realm renders its own drop indicator locally,
|
|
310
|
+
* since it already has the DOM geometry and relaying it every `dragover`
|
|
311
|
+
* tick would add a message-per-frame the local realm doesn't need). Reading
|
|
312
|
+
* these rects is a same-origin DOM read (`iframe.contentDocument`), which a
|
|
313
|
+
* real `src` navigation doesn't block — only shared JS object identity is
|
|
314
|
+
* blocked, not DOM geometry reads.
|
|
315
|
+
*/
|
|
316
|
+
renderBox?: (rects: {
|
|
317
|
+
selected: Rect | null;
|
|
318
|
+
hovered: Rect | null;
|
|
319
|
+
selectedLabel: string | null;
|
|
320
|
+
}) => ReactNode;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* The `IframeCanvas` alternative for when a canvas needs its OWN genuine JS
|
|
324
|
+
* realm — e.g. so a third-party library reading bare `window`/`document` at
|
|
325
|
+
* module scope (an animation library's scroll-linked internals, a gesture
|
|
326
|
+
* library, ...) resolves against the canvas's real globals instead of
|
|
327
|
+
* silently binding to the host page's. A portal can't fix this (see
|
|
328
|
+
* `useCanvasWindow`'s docs for that half of the problem) because it only
|
|
329
|
+
* relocates DOM nodes, not the JS module graph building them.
|
|
330
|
+
*
|
|
331
|
+
* Renders a genuinely-`src`-navigated `<iframe>` — no `createPortal`, so
|
|
332
|
+
* nothing here shares object identity with the canvas's own React tree. State
|
|
333
|
+
* flows one-way, host -> canvas, over a `BroadcastChannel` as `t.flatten`'d
|
|
334
|
+
* JSON (see `./canvas-protocol`); interaction (select/hover/drop/keydown/
|
|
335
|
+
* link-click) relays back the other way as small typed messages. Pair with
|
|
336
|
+
* `createCanvasReceiver` (`./canvas-client`) on the canvas route's own end.
|
|
337
|
+
*/
|
|
338
|
+
declare function RemoteCanvasHost({ nu, activeComponent, src, selectedId, hoveredId, revision, previewMode, uiPayload, onSelect, onHover, onDropOnNode, onKeydownRelay, onLinkClick, className, containerClassName, renderBox, }: RemoteCanvasHostProps): ReactNode;
|
|
339
|
+
/** Re-render only when the tree shape changes (add/remove/move). */
|
|
144
340
|
declare function useStructureRevision(editor: Pick<Editor, 'onStructureChange'>): number;
|
|
341
|
+
/** Re-render on every committed change (for undo state, inspectors, …). */
|
|
145
342
|
declare function useEditorRevision(editor: Pick<Editor, 'onChange'>): number;
|
|
146
343
|
type PropFieldValue = string | number | boolean | undefined;
|
|
147
344
|
interface PropFieldsProps {
|
|
345
|
+
/** The control schema (e.g. a block's `props`). */
|
|
148
346
|
fields: PropSchemaField[];
|
|
347
|
+
/** Current value per field name. */
|
|
149
348
|
values: Record<string, PropFieldValue>;
|
|
349
|
+
/** Called when a control changes. Wire to `editor.setProp`/`setExpression`. */
|
|
150
350
|
onChange: (name: string, value: string | number | boolean) => void;
|
|
151
351
|
className?: string;
|
|
152
352
|
}
|
|
353
|
+
/**
|
|
354
|
+
* A headless inspector renderer: builds a control per {@link PropSchemaField}
|
|
355
|
+
* (text / number / checkbox / select / expression) so you don't hand-write a
|
|
356
|
+
* form per block. Style via `className` and your own CSS; wire `onChange` to the
|
|
357
|
+
* editor's mutation methods.
|
|
358
|
+
*/
|
|
153
359
|
declare function PropFields({ fields, values, onChange, className, }: PropFieldsProps): ReactNode;
|
|
154
360
|
|
|
155
|
-
export { DEFAULT_CANVAS_CSS, EditorFrame, IframeCanvas, PropFields, templateIdFromElement, useEditorRevision, useStructureRevision };
|
|
156
|
-
export type { IframeCanvasProps, PropFieldValue, PropFieldsProps, Rect };
|
|
361
|
+
export { DEFAULT_CANVAS_CSS, EditorFrame, IframeCanvas, PropFields, RemoteCanvasHost, templateIdFromElement, useCanvasWindow, useEditorRevision, useStructureRevision };
|
|
362
|
+
export type { CanvasWindow, IframeCanvasProps, PropFieldValue, PropFieldsProps, Rect, RemoteCanvasHostProps };
|