efficient-easel 0.0.0 → 0.97.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/LICENSE +10 -0
- package/README.md +818 -4
- package/dist/autosave/index.d.ts +101 -0
- package/dist/autosave/index.js +1 -0
- package/dist/blocks/index.d.ts +306 -0
- package/dist/blocks/index.js +0 -0
- package/dist/buckets-1vRlQceY.d.ts +13 -0
- package/dist/canvas/index.d.ts +194 -0
- package/dist/canvas/index.js +1 -0
- package/dist/chrome/chrome.css +570 -0
- package/dist/chrome/index.d.ts +219 -0
- package/dist/chrome/index.js +21 -0
- package/dist/chunk-2LUSK32B.js +1 -0
- package/dist/chunk-2OAZYSWJ.js +1 -0
- package/dist/chunk-67VZRQLG.js +13 -0
- package/dist/chunk-6OPSJGAI.js +1 -0
- package/dist/chunk-6PS6STGA.js +1 -0
- package/dist/chunk-6WY6ZXJG.js +1 -0
- package/dist/chunk-7A7O2JWQ.js +1 -0
- package/dist/chunk-BZ5ASXOL.js +1 -0
- package/dist/chunk-CERTFXCV.js +13 -0
- package/dist/chunk-D2BCHTQR.js +1 -0
- package/dist/chunk-FI23ALVJ.js +1 -0
- package/dist/chunk-GGTPNGFJ.js +1 -0
- package/dist/chunk-H4B72XCJ.js +1 -0
- package/dist/chunk-H6DDIBQ4.js +1 -0
- package/dist/chunk-KDIVA6WD.js +1 -0
- package/dist/chunk-KRXQM65X.js +1 -0
- package/dist/chunk-MCLBHENY.js +1 -0
- package/dist/chunk-MFIRYGHW.js +1 -0
- package/dist/chunk-NKB3KVAB.js +1 -0
- package/dist/chunk-O2NLQBFX.js +1 -0
- package/dist/chunk-OGZFDJ6G.js +1 -0
- package/dist/chunk-OWBO4WKA.js +0 -0
- package/dist/chunk-QB3BZIRA.js +5 -0
- package/dist/chunk-RE4LP46F.js +1 -0
- package/dist/chunk-STFMZJKU.js +14 -0
- package/dist/chunk-SUO5627P.js +1 -0
- package/dist/chunk-TDA4HH54.js +1 -0
- package/dist/chunk-WK3AFPXY.js +1 -0
- package/dist/chunk-YIMRTIBN.js +3 -0
- package/dist/chunk-YNZZYHA4.js +450 -0
- package/dist/chunk-YRLPFZW3.js +1 -0
- package/dist/chunk-ZAOM6PFH.js +1 -0
- package/dist/chunk-ZNCEOSXO.js +1 -0
- package/dist/copy/copy.css +282 -0
- package/dist/copy/index.d.ts +336 -0
- package/dist/copy/index.js +10 -0
- package/dist/data/index.d.ts +375 -0
- package/dist/data/index.js +1 -0
- package/dist/drag/drag.css +360 -0
- package/dist/drag/index.d.ts +379 -0
- package/dist/drag/index.js +18 -0
- package/dist/edit-lock/index.d.ts +354 -0
- package/dist/edit-lock/index.js +1 -0
- package/dist/editor/editor.css +58 -0
- package/dist/editor/index.d.ts +361 -0
- package/dist/editor/index.js +9 -0
- package/dist/fields/fields.css +207 -0
- package/dist/fields/index.d.ts +273 -0
- package/dist/fields/index.js +46 -0
- package/dist/gold/gold.css +196 -0
- package/dist/gold/index.d.ts +280 -0
- package/dist/gold/index.js +1 -0
- package/dist/icons/index.d.ts +474 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -0
- package/dist/markup/index.d.ts +452 -0
- package/dist/markup/index.js +1 -0
- package/dist/menu/index.d.ts +49 -0
- package/dist/menu/index.js +15 -0
- package/dist/menu/menu.css +254 -0
- package/dist/node-ops/index.d.ts +91 -0
- package/dist/node-ops/index.js +1 -0
- package/dist/panel/index.d.ts +1088 -0
- package/dist/panel/index.js +16 -0
- package/dist/panel/panel.css +1460 -0
- package/dist/pick/index.d.ts +153 -0
- package/dist/pick/index.js +14 -0
- package/dist/pick/pick.css +235 -0
- package/dist/plan-DChbUXdS.d.ts +88 -0
- package/dist/rail/index.d.ts +145 -0
- package/dist/rail/index.js +1 -0
- package/dist/rail/rail.css +175 -0
- package/dist/render/index.d.ts +117 -0
- package/dist/render/index.js +5 -0
- package/dist/resolve-D68pb3Bx.d.ts +57 -0
- package/dist/shell/index.d.ts +159 -0
- package/dist/shell/index.js +1 -0
- package/dist/shell/shell.css +122 -0
- package/dist/strings/catalogue.d.ts +141 -0
- package/dist/strings/catalogue.js +1 -0
- package/dist/strings/index.d.ts +56 -0
- package/dist/strings/index.js +2 -0
- package/dist/style-clipboard/index.d.ts +184 -0
- package/dist/style-clipboard/index.js +1 -0
- package/dist/tree/index.d.ts +173 -0
- package/dist/tree/index.js +1 -0
- package/dist/tree/tree.css +618 -0
- package/dist/types-41704JE4.d.ts +112 -0
- package/dist/types-CEqUFH2j.d.ts +129 -0
- package/dist/types-CuNiSnX6.d.ts +204 -0
- package/dist/types-DNrn_w4V.d.ts +88 -0
- package/dist/types-Dy6oR6Z2.d.ts +153 -0
- package/dist/types-pGBXevBU.d.ts +131 -0
- package/dist/useNodeOps-BF0fQsif.d.ts +68 -0
- package/dist/watch-DmasQA61.d.ts +60 -0
- package/dist/wordFit-9B9nqyf3.d.ts +35 -0
- package/dist/words-B2YLaKEr.d.ts +30 -0
- package/dist/words-B87GIFWH.d.ts +86 -0
- package/dist/words-BK-npta-.d.ts +27 -0
- package/dist/words-CD3WADyb.d.ts +51 -0
- package/dist/words-CsRWXkY4.d.ts +129 -0
- package/dist/words-D9ChvbNC.d.ts +52 -0
- package/dist/words-DOhF-4D4.d.ts +35 -0
- package/dist/words-DagJdwIA.d.ts +78 -0
- package/dist/words-DfxEp_RH.d.ts +142 -0
- package/package.json +202 -3
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
import { DataInput } from '../data/index.js';
|
|
2
|
+
import { N as NodeSelection } from '../plan-DChbUXdS.js';
|
|
3
|
+
export { I as ItemSelector } from '../plan-DChbUXdS.js';
|
|
4
|
+
import { E as EditorConfig, a as EditorView, b as EditorAction, P as Permissions, c as EditorCore, d as EditorUi } from '../types-Dy6oR6Z2.js';
|
|
5
|
+
export { A as AppState, e as EditorHistory, H as HistoryEntry, S as SetDataPatch } from '../types-Dy6oR6Z2.js';
|
|
6
|
+
import { S as SlotAddress, D as Data, P as Place } from '../types-41704JE4.js';
|
|
7
|
+
import { c as ResolveTrigger, a as ResolveCache, R as ResolvableItem } from '../resolve-D68pb3Bx.js';
|
|
8
|
+
import * as react from 'react';
|
|
9
|
+
import { ReactNode, CSSProperties, ComponentType, ReactElement } from 'react';
|
|
10
|
+
import { b as NodeOpsHost, C as ClipboardEntry } from '../useNodeOps-BF0fQsif.js';
|
|
11
|
+
import { I as InspectorFields } from '../types-CEqUFH2j.js';
|
|
12
|
+
import '../buckets-1vRlQceY.js';
|
|
13
|
+
|
|
14
|
+
interface EditorOptions<C extends EditorConfig = EditorConfig> {
|
|
15
|
+
config: C;
|
|
16
|
+
/** The document — Puck 0.20's shape, unchanged. */
|
|
17
|
+
data: DataInput | Data;
|
|
18
|
+
/** The host's own UI keys to start with (and an `itemSelector`, if any). */
|
|
19
|
+
ui?: Record<string, unknown>;
|
|
20
|
+
/** Called with the new document after every change that changed it — once
|
|
21
|
+
* per `batch`, once per undo / redo. Not called for `load`. */
|
|
22
|
+
onChange?: (data: Data) => void;
|
|
23
|
+
/** Editor-wide permissions, under each block's own (Puck's `permissions`). */
|
|
24
|
+
permissions?: Partial<Permissions>;
|
|
25
|
+
/**
|
|
26
|
+
* Changes recorded closer together than this collapse into ONE undo step —
|
|
27
|
+
* Puck's 250 ms history debounce, so a word typed into a field is undone as
|
|
28
|
+
* a word and not as letters. A `batch` is never collapsed into its
|
|
29
|
+
* neighbours. 0 records every change on its own.
|
|
30
|
+
*/
|
|
31
|
+
historyCoalesceMs?: number;
|
|
32
|
+
/** The clock, for tests. */
|
|
33
|
+
now?: () => number;
|
|
34
|
+
}
|
|
35
|
+
interface Editor<C extends EditorConfig = EditorConfig> {
|
|
36
|
+
/** What `useEditor` reads. The same object until the state changes. */
|
|
37
|
+
getState: () => EditorView<C>;
|
|
38
|
+
subscribe: (listener: () => void) => () => void;
|
|
39
|
+
/** One Puck action. Outside a `batch`, one undo step when it records. */
|
|
40
|
+
dispatch: (action: EditorAction) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Run several changes as ONE: one undo step, one `onChange`, and one
|
|
43
|
+
* notification to subscribers. Each dispatch inside sees the ones before it.
|
|
44
|
+
* Throwing inside puts everything back. Batches nest; only the outer one
|
|
45
|
+
* records.
|
|
46
|
+
*/
|
|
47
|
+
batch: (fn: () => void) => void;
|
|
48
|
+
/** Select a node by id, or nothing. Selection is not an undo step. */
|
|
49
|
+
select: (id: string | null) => void;
|
|
50
|
+
/** Select a slot — a column — or nothing. */
|
|
51
|
+
selectSlot: (address: SlotAddress | null) => void;
|
|
52
|
+
/** Apply a node-ops plan (`{ data, select }`) as one change. */
|
|
53
|
+
run: (plan: {
|
|
54
|
+
data: Data;
|
|
55
|
+
select?: NodeSelection | undefined;
|
|
56
|
+
}) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Put a different document in WITHOUT remounting anything — Puck needed a
|
|
59
|
+
* new `key` on `<Puck>` for that, which threw away every subscriber's state.
|
|
60
|
+
* The history starts again at this document unless `keepHistory`.
|
|
61
|
+
*/
|
|
62
|
+
load: (data: DataInput | Data, options?: {
|
|
63
|
+
keepHistory?: boolean;
|
|
64
|
+
selection?: NodeSelection;
|
|
65
|
+
}) => void;
|
|
66
|
+
undo: () => void;
|
|
67
|
+
redo: () => void;
|
|
68
|
+
setPermissions: (permissions: Partial<Permissions>) => void;
|
|
69
|
+
/**
|
|
70
|
+
* Run every block's `resolveData` over the document, as `<Puck>` did when it
|
|
71
|
+
* mounted (trigger `'load'`), and write what changed as ONE change folded
|
|
72
|
+
* into the step it happens in — a resolver bringing a stale document up to
|
|
73
|
+
* date is not an undo step (Puck made it one, which undid back to the stale
|
|
74
|
+
* document). `onChange` hears it, as Puck's did. `EditorProvider` runs this
|
|
75
|
+
* on mount; a node changed by hand while it ran is left as the hand left it.
|
|
76
|
+
*/
|
|
77
|
+
resolveAll: (options?: {
|
|
78
|
+
trigger?: ResolveTrigger;
|
|
79
|
+
metadata?: Record<string, unknown>;
|
|
80
|
+
}) => Promise<void>;
|
|
81
|
+
/** This editor's memory of the last change each node was resolved for —
|
|
82
|
+
* Puck kept one per editor, shared by every write that resolves. */
|
|
83
|
+
readonly resolveCache: ResolveCache;
|
|
84
|
+
/**
|
|
85
|
+
* Swap the config in place — `<Puck>` took a new `config` prop live. The
|
|
86
|
+
* website editor rebuilds a few blocks' fields when the site's gap moves; the
|
|
87
|
+
* document, the selection and the history are untouched.
|
|
88
|
+
*/
|
|
89
|
+
setConfig: (config: C) => void;
|
|
90
|
+
/** The config in force now. */
|
|
91
|
+
readonly config: C;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Puck 0.20's UI at mount (`defaultAppState.ui`), less the selection, which
|
|
95
|
+
* the store holds by id. A host's chrome reads these — the website editor
|
|
96
|
+
* opens its side panels from `leftSideBarVisible` / `rightSideBarVisible` — so
|
|
97
|
+
* a host moving off `<Puck>` finds them where they were.
|
|
98
|
+
*/
|
|
99
|
+
declare const DEFAULT_UI: Record<string, unknown>;
|
|
100
|
+
/**
|
|
101
|
+
* THE EDITOR STORE (blueprint step 5.1): the document, the selection by id and
|
|
102
|
+
* the host's UI keys, with Puck's actions, Puck's history and a `batch` Puck
|
|
103
|
+
* never had. Framework-free — `useEditor` (./react) is the React binding.
|
|
104
|
+
*/
|
|
105
|
+
declare function createEditor<C extends EditorConfig>(options: EditorOptions<C>): Editor<C>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Puck 0.20's reducer, on `efficient-easel/data` — blueprint step 5.1.
|
|
109
|
+
*
|
|
110
|
+
* Each action means what it meant to Puck, so the apps' `dispatch` calls move
|
|
111
|
+
* over unchanged (`reorder`'s and `move`'s indexes, `replaceRoot` MERGING
|
|
112
|
+
* props, `duplicate` selecting the copy, `insert` leaving the selection where
|
|
113
|
+
* it was). Two things differ, on purpose:
|
|
114
|
+
*
|
|
115
|
+
* - THE SELECTION IS BY ID. Puck held `itemSelector` — a place — so a node
|
|
116
|
+
* inserted or removed above the selected one silently moved the selection
|
|
117
|
+
* onto its neighbour, and both editors carried patches for exactly that.
|
|
118
|
+
* Here `itemSelector` is derived from the id on every read, and a
|
|
119
|
+
* selection whose node is gone becomes nothing rather than whatever now
|
|
120
|
+
* sits in its place.
|
|
121
|
+
* - A SLOT CAN BE SELECTED (a column): `ui.selectedSlot`, which Puck had no
|
|
122
|
+
* way to say.
|
|
123
|
+
*/
|
|
124
|
+
/** Whether Puck records an action in history when the action does not say:
|
|
125
|
+
* everything but the state-setters. */
|
|
126
|
+
declare function recordsByDefault(action: EditorAction): boolean;
|
|
127
|
+
/** The UI as Puck shows it: the host's keys, with the selection translated. */
|
|
128
|
+
declare function uiView(core: EditorCore, config: EditorConfig): EditorUi;
|
|
129
|
+
/** A selection that still points at something; otherwise nothing. */
|
|
130
|
+
declare function validSelection(data: Data, config: EditorConfig, selection: NodeSelection): NodeSelection;
|
|
131
|
+
/** One action, applied. Pure: the same core and action give the same core. */
|
|
132
|
+
declare function reduce(core: EditorCore, action: EditorAction, config: EditorConfig): EditorCore;
|
|
133
|
+
|
|
134
|
+
/** Puts one editor in reach of everything under it — `<Puck>`'s provider
|
|
135
|
+
* half — and, as `<Puck>` did, binds undo / redo to the page's keyboard
|
|
136
|
+
* (`hotkeys={false}` for a host that binds its own) and runs every block's
|
|
137
|
+
* `resolveData` once on mount (`resolveOnMount={false}` to skip). */
|
|
138
|
+
declare function EditorProvider({ editor, hotkeys, resolveOnMount, children, }: {
|
|
139
|
+
editor: Editor;
|
|
140
|
+
hotkeys?: boolean;
|
|
141
|
+
/** Run every block's `resolveData` once the editor mounts, as `<Puck>` did
|
|
142
|
+
* (`editor.resolveAll`). On by default. */
|
|
143
|
+
resolveOnMount?: boolean;
|
|
144
|
+
children?: ReactNode;
|
|
145
|
+
}): react.JSX.Element;
|
|
146
|
+
/** The editor itself, for handlers that read the state at the moment they run
|
|
147
|
+
* (`useGetPuck`'s job) and for `dispatch` / `batch` / `select`. */
|
|
148
|
+
declare function useEditorApi<C extends EditorConfig = EditorConfig>(): Editor<C>;
|
|
149
|
+
/**
|
|
150
|
+
* Read a slice of the editor and re-render when it changes — `usePuck` /
|
|
151
|
+
* `createUsePuck()`'s selector form, over the same state shape, so the apps'
|
|
152
|
+
* selectors move over by renaming the hook.
|
|
153
|
+
*
|
|
154
|
+
* A selector may return a fresh object; the snapshot is cached per state and
|
|
155
|
+
* per selector, so React sees the same value for the same state and does not
|
|
156
|
+
* loop. A primitive or an unchanged reference does not re-render.
|
|
157
|
+
*/
|
|
158
|
+
declare function useEditor<T, C extends EditorConfig = EditorConfig>(selector: (view: EditorView<C>) => T): T;
|
|
159
|
+
/**
|
|
160
|
+
* A typed `useEditor` for one config — `createUsePuck<Config>()`'s shape, so
|
|
161
|
+
* a file that made its own typed hook keeps the one line that made it.
|
|
162
|
+
*/
|
|
163
|
+
declare function createUseEditor<C extends EditorConfig = EditorConfig>(): <T>(selector: (view: EditorView<C>) => T) => T;
|
|
164
|
+
|
|
165
|
+
/** What a slot component accepts — Puck's. */
|
|
166
|
+
interface CanvasSlotProps {
|
|
167
|
+
className?: string;
|
|
168
|
+
style?: CSSProperties;
|
|
169
|
+
allow?: string[];
|
|
170
|
+
disallow?: string[];
|
|
171
|
+
minEmptyHeight?: number;
|
|
172
|
+
collisionAxis?: unknown;
|
|
173
|
+
}
|
|
174
|
+
interface CanvasFrameProps {
|
|
175
|
+
children?: ReactNode;
|
|
176
|
+
/** `preview-frame` by default — the id the apps' canvas watchers look for. */
|
|
177
|
+
id?: string;
|
|
178
|
+
/**
|
|
179
|
+
* The frame's accessible name. Default "Canvas", in the strings provider's
|
|
180
|
+
* language (`EditorStrings.canvas.frame`).
|
|
181
|
+
*/
|
|
182
|
+
title?: string;
|
|
183
|
+
className?: string;
|
|
184
|
+
style?: CSSProperties;
|
|
185
|
+
/** Copy the host page's stylesheets into the frame, and keep them in step.
|
|
186
|
+
* On by default: the blocks are styled by the app's own CSS. */
|
|
187
|
+
mirrorStyles?: boolean;
|
|
188
|
+
/** Called with the frame's document once it is ready, and null when it goes. */
|
|
189
|
+
onDocument?: (doc: Document | null) => void;
|
|
190
|
+
/**
|
|
191
|
+
* `'auto'` (the default, Puck's): the frame is as tall as its content, and
|
|
192
|
+
* the host's pane scrolls it — so the canvas reads like the page it is.
|
|
193
|
+
* `'fill'`: the frame fills its parent and scrolls itself.
|
|
194
|
+
*/
|
|
195
|
+
height?: 'auto' | 'fill';
|
|
196
|
+
/**
|
|
197
|
+
* The page's CSP nonce, for a host whose policy allows styles by nonce
|
|
198
|
+
* (`style-src 'nonce-…'`). The frame is the host page's own document, so the
|
|
199
|
+
* same policy applies in it, and a stylesheet without the nonce is refused.
|
|
200
|
+
* Given, it is set on every stylesheet the canvas puts in the frame: each
|
|
201
|
+
* `<style>` and `<link rel="stylesheet">` copied in from the host
|
|
202
|
+
* (`mirrorStyles`), and each sheet `useCanvasStyle` / `upsertCanvasStyle`
|
|
203
|
+
* (`efficient-easel/canvas`) creates there. Left out, nothing changes.
|
|
204
|
+
*
|
|
205
|
+
* Read when the frame is built, like `mirrorStyles`: a nonce is the page's
|
|
206
|
+
* for as long as the page lives.
|
|
207
|
+
*/
|
|
208
|
+
nonce?: string;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* An iframe of the editor's own, with the content portalled in. No `src`: the
|
|
212
|
+
* frame's first document is used — there to write into at once, with no load
|
|
213
|
+
* to wait for and nothing fetched. The host's stylesheets are copied into its
|
|
214
|
+
* head and copied again whenever the host's head changes (a route's CSS
|
|
215
|
+
* arriving late, a dev reload).
|
|
216
|
+
*
|
|
217
|
+
* ⚠️ THAT FIRST DOCUMENT HAS NO DOCTYPE, SO IT RENDERS IN QUIRKS MODE, and it
|
|
218
|
+
* is rewritten with one before anything is drawn. Puck's frame was a
|
|
219
|
+
* `<!DOCTYPE html>` srcdoc, so every block was written against standards mode;
|
|
220
|
+
* in quirks mode a `height: 100%` resolves through auto-height ancestors (an
|
|
221
|
+
* empty slot grew to the frame's full height), tables stop inheriting the
|
|
222
|
+
* page's font, and an image's line box changes. (0.89.0–0.92.0 shipped the
|
|
223
|
+
* quirks-mode frame.)
|
|
224
|
+
*/
|
|
225
|
+
declare function CanvasFrame({ children, id, title, className, style, mirrorStyles, onDocument, height, nonce, }: CanvasFrameProps): react.JSX.Element;
|
|
226
|
+
/**
|
|
227
|
+
* The whole document, for editing. Works in a `CanvasFrame` or on its own.
|
|
228
|
+
*
|
|
229
|
+
* `metadata` is the editor-wide metadata: the root's `puck.metadata`, and —
|
|
230
|
+
* under each block's own — every block's (see the header).
|
|
231
|
+
*/
|
|
232
|
+
declare function EditDocument({ metadata }: {
|
|
233
|
+
metadata?: Record<string, unknown>;
|
|
234
|
+
}): react.JSX.Element;
|
|
235
|
+
/** What a host may wrap an outline in — Puck's `componentOverlay`: render
|
|
236
|
+
* `children` to draw it, or nothing to hide it (a text part open on the
|
|
237
|
+
* block, say). */
|
|
238
|
+
type CanvasOverlay = ComponentType<{
|
|
239
|
+
componentId: string;
|
|
240
|
+
kind: 'selected' | 'hover';
|
|
241
|
+
children: ReactNode;
|
|
242
|
+
}>;
|
|
243
|
+
interface EditorCanvasProps {
|
|
244
|
+
/** Draw in an iframe of the editor's own (default), or straight into the page. */
|
|
245
|
+
frame?: boolean;
|
|
246
|
+
className?: string;
|
|
247
|
+
style?: CSSProperties;
|
|
248
|
+
/**
|
|
249
|
+
* The editor-wide metadata — what the published page passes `Render` as
|
|
250
|
+
* `metadata`. Every block reads it as `puck.metadata` (its own `metadata`
|
|
251
|
+
* laid over it) and the root as it is. Change it whenever the host's data
|
|
252
|
+
* changes: the blocks redraw in place, nothing remounts, and it never enters
|
|
253
|
+
* the document or the undo history.
|
|
254
|
+
*/
|
|
255
|
+
metadata?: Record<string, unknown>;
|
|
256
|
+
/** Copy the host's stylesheets into the frame (default true). */
|
|
257
|
+
mirrorStyles?: boolean;
|
|
258
|
+
/** The frame's height: as tall as its content (default, Puck's), or filling its parent. */
|
|
259
|
+
height?: 'auto' | 'fill';
|
|
260
|
+
/**
|
|
261
|
+
* The frame's accessible name — an iframe with none is announced as "frame".
|
|
262
|
+
* Default "Canvas", in the strings provider's language. Unused with
|
|
263
|
+
* `frame={false}`, where there is no frame to name.
|
|
264
|
+
*/
|
|
265
|
+
title?: string;
|
|
266
|
+
/** The page's CSP nonce for the frame's stylesheets — see `CanvasFrameProps.nonce`. Unused with `frame={false}`. */
|
|
267
|
+
nonce?: string;
|
|
268
|
+
onDocument?: (doc: Document | null) => void;
|
|
269
|
+
/**
|
|
270
|
+
* Wraps everything drawn in the frame, and is handed the frame's document —
|
|
271
|
+
* Puck's `overrides.iframe`: where a host syncs its theme onto the frame's
|
|
272
|
+
* `<html>` or adds frame-only CSS.
|
|
273
|
+
*/
|
|
274
|
+
frameWrapper?: ComponentType<{
|
|
275
|
+
document?: Document;
|
|
276
|
+
children: ReactNode;
|
|
277
|
+
}>;
|
|
278
|
+
/** Wraps each outline — Puck's `componentOverlay`; see `CanvasOverlay`. */
|
|
279
|
+
overlay?: CanvasOverlay;
|
|
280
|
+
/** Drawn inside the frame, after the document — a host's canvas-only layer. */
|
|
281
|
+
children?: ReactNode;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* `<Puck.Preview>`, ours: the document for editing, its outlines, and the
|
|
285
|
+
* clicks that select. Must sit under an `EditorProvider`.
|
|
286
|
+
*/
|
|
287
|
+
declare function EditorCanvas({ frame, className, style, metadata, mirrorStyles, onDocument, height, title, nonce, frameWrapper: FrameWrapper, overlay, children, }: EditorCanvasProps): ReactElement;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* THE PARTS, ON THE STORE (blueprint step 5.2).
|
|
291
|
+
*
|
|
292
|
+
* Every part built in steps 2.1–4.9 takes a HOST — what to read, how to write
|
|
293
|
+
* — so it never knew Puck. Until now each app wrote that host twice, once per
|
|
294
|
+
* editor, against Puck's store: `EmailFields` and `SiteFields` for the settings
|
|
295
|
+
* panel, the node-ops host for the menus. These are the hosts, written ONCE,
|
|
296
|
+
* against the engine's store; the parts' own APIs do not change.
|
|
297
|
+
*/
|
|
298
|
+
/** `useNodeOps` with the store as its host: reads the document, and writes one
|
|
299
|
+
* `run` — one undo step, the selection travelling with it. */
|
|
300
|
+
declare function useEditorNodeOps(options?: Omit<NodeOpsHost, 'data' | 'config' | 'commit'>): {
|
|
301
|
+
held: ClipboardEntry | null;
|
|
302
|
+
remove: (id: string) => boolean;
|
|
303
|
+
duplicate: (id: string) => boolean;
|
|
304
|
+
move: (id: string, to: Place) => boolean;
|
|
305
|
+
step: (id: string, dir: -1 | 1) => boolean;
|
|
306
|
+
canStep: (id: string, dir: -1 | 1) => boolean;
|
|
307
|
+
setProps: (id: string, patch: Record<string, unknown>) => boolean;
|
|
308
|
+
copy: (id: string, label: string) => boolean;
|
|
309
|
+
cut: (id: string, label: string) => boolean;
|
|
310
|
+
paste: (at: Place) => boolean;
|
|
311
|
+
parentOf: (selection: NodeSelection) => NodeSelection;
|
|
312
|
+
};
|
|
313
|
+
interface SelectedFields {
|
|
314
|
+
/** The selected node's id, or `"root"` with nothing selected. */
|
|
315
|
+
id: string;
|
|
316
|
+
/** The node the fields are for — the selected one, or the root as `{ type: 'root', props }`. */
|
|
317
|
+
node: ResolvableItem;
|
|
318
|
+
/** Its fields, resolved as Puck resolved them (`resolveFields` with Puck's params, parent included). */
|
|
319
|
+
fields: InspectorFields;
|
|
320
|
+
/** What the fields show. */
|
|
321
|
+
values: Record<string, unknown>;
|
|
322
|
+
/** The block's (or the root's) `edit` permission is off. */
|
|
323
|
+
readOnly: boolean;
|
|
324
|
+
/** Write one field: `resolveData` as Puck ran it, then ONE replace — one undo step. */
|
|
325
|
+
onChange: (name: string, value: unknown) => void;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* The settings panel's host: the selected node's fields and the write that
|
|
329
|
+
* changes one — what `EmailFields` and `SiteFields` each did against Puck,
|
|
330
|
+
* here once:
|
|
331
|
+
* - fields resolve through `useResolvedFields` (Puck's
|
|
332
|
+
* `useRegisterFieldsSlice`: `changed`, `lastFields`, `appState`, `parent`);
|
|
333
|
+
* - a change runs the block's `resolveData` (`resolveNodeData`, Puck's
|
|
334
|
+
* `resolveComponentData`, with this editor's own memory of the last
|
|
335
|
+
* change) and then writes ONE `replace` of the node, or ONE `replaceRoot`.
|
|
336
|
+
*
|
|
337
|
+
* The write reads the node AT THE MOMENT IT RUNS, by id: a field changed while
|
|
338
|
+
* a resolver is still running writes onto what is current, never onto what was
|
|
339
|
+
* selected when the change began.
|
|
340
|
+
*/
|
|
341
|
+
declare function useSelectedFields(): SelectedFields;
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* UNDO AND REDO ON THE KEYBOARD — Puck's own six bindings, which both editors
|
|
345
|
+
* relied on without writing any: ⌘Z / Ctrl+Z undo; ⇧⌘Z, ⌘Y, Ctrl+Shift+Z and
|
|
346
|
+
* Ctrl+Y redo.
|
|
347
|
+
*
|
|
348
|
+
* Exact combinations, read off the physical key (`code`, as Puck read it), so
|
|
349
|
+
* a layout that moves Z still undoes and ⌥⌘Z does nothing.
|
|
350
|
+
*
|
|
351
|
+
* ⚠️ PUCK FIRED THESE IN A TEXT FIELD TOO, and so does this: ⌘Z while typing
|
|
352
|
+
* in a setting undoes the editor's last step — which, since a field writes as
|
|
353
|
+
* it is typed, is the typing — and the browser's own text undo is prevented,
|
|
354
|
+
* so there are never two undo histories answering one key.
|
|
355
|
+
*
|
|
356
|
+
* Bound per DOCUMENT: the host page (`EditorProvider`) and the canvas frame
|
|
357
|
+
* (`EditorCanvas`), because a key pressed in the frame never reaches the page.
|
|
358
|
+
*/
|
|
359
|
+
declare function bindUndoKeys(doc: Document, editor: Pick<Editor, 'undo' | 'redo'>): () => void;
|
|
360
|
+
|
|
361
|
+
export { CanvasFrame, type CanvasFrameProps, type CanvasOverlay, type CanvasSlotProps, DEFAULT_UI, EditDocument, type Editor, EditorAction, EditorCanvas, type EditorCanvasProps, EditorConfig, EditorCore, type EditorOptions, EditorProvider, EditorUi, EditorView, NodeSelection, Permissions, type SelectedFields, bindUndoKeys, createEditor, createUseEditor, recordsByDefault, reduce, uiView, useEditor, useEditorApi, useEditorNodeOps, useSelectedFields, validSelection };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import{DEFAULT_CANVAS_WORDS as e}from"../chunk-GGTPNGFJ.js";import{useResolvedFields as t}from"../chunk-YRLPFZW3.js";import{toItemSelector as n,fromItemSelector as o,useNodeOps as r}from"../chunk-D2BCHTQR.js";import{useWords as i}from"../chunk-MFIRYGHW.js";import{setCanvasNonce as a}from"../chunk-ZNCEOSXO.js";import{find as s,ROOT_ID as l,getList as d,remove as c,parseZoneKey as u,move as p,duplicate as h,replaceNode as f,createNode as m,insert as v,normalizeData as y,createResolveCache as g,resolveNodeData as k,ROOT_SLOT as b}from"../chunk-KRXQM65X.js";import{topLevelSlotKeys as w,fieldsFrom as S,defaultsFrom as I}from"../chunk-NKB3KVAB.js";import{createContext as C,useEffect as x,useContext as O,useRef as D,useSyncExternalStore as E,useState as A,useLayoutEffect as z,useMemo as M,useCallback as Z}from"react";import{jsx as $,jsxs as R}from"react/jsx-runtime";import{createPortal as N}from"react-dom";function B(e){return!["setData","setUi","set"].includes(e.type)}var P=(e,t,n,o)=>{const r=d(e,t,u(n));return r?.[o]??null},j=(e,t,n,o,r)=>{const i=P(e,t,n,o);if(!i)throw new Error(`${r}: nothing at ${n}[${o}]`);return i};function K(e,t){const{selection:o}=e;return{...e.ui,itemSelector:n(e.data,t,o),selectedSlot:o&&"slot"===o.kind?{parentId:o.parentId,slot:o.slot}:null}}function L(e,t,n){return n?"node"===n.kind?s(e,t,n.id)?n:null:n.parentId===l?d(e,t,n)?n:null:s(e,t,n.parentId)&&d(e,t,n)?n:null:null}function F(e,t,n,r=!1){const{itemSelector:i,selectedSlot:a,...s}=n;let l=e.selection;var d;return"itemSelector"in n&&(l=o(e.data,t,i??null)),"selectedSlot"in n&&(a?l=(d=a)?{kind:"slot",parentId:d.parentId,slot:d.slot}:null:"slot"===l?.kind&&(l=null)),{...e,selection:l,ui:r?s:{...e.ui,...s}}}function H(e,t,n){const o=V(e,t,n);if(o===e)return e;const r=L(o.data,n,o.selection);return r===o.selection?o:{...o,selection:r}}function V(e,t,n){const{data:o}=e;switch(t.type){case"setData":{const n="function"==typeof t.data?t.data(o):t.data;return{...e,data:{...o,...n}}}case"setUi":return F(e,n,"function"==typeof t.ui?t.ui(K(e,n)):t.ui);case"set":{const r={data:o,ui:K(e,n)},i="function"==typeof t.state?t.state(r):t.state;let a=i.data?{...e,data:i.data}:e;return i.ui&&(a=F(a,n,i.ui,!0)),a}case"insert":{const r={...u(t.destinationZone),index:t.destinationIndex},i=m(n,t.componentType,{},t.id?{id:t.id}:{});return{...e,data:v(o,n,r,i)}}case"replace":{const r=j(o,n,t.destinationZone,t.destinationIndex,"replace");if(r.props.id!==t.data.props.id)throw new Error("Can't change the id during a replace action. Use remove and insert for a new node.");return{...e,data:f(o,n,r.props.id,t.data)}}case"replaceRoot":{const n={...o.root,props:{...o.root.props,...t.root.props},readOnly:t.root.readOnly};return{...e,data:{...o,root:n}}}case"duplicate":{const r=j(o,n,t.sourceZone,t.sourceIndex,"duplicate"),i=h(o,n,r.props.id),a=P(i,n,t.sourceZone,t.sourceIndex+1);return{...e,data:i,selection:a?{kind:"node",id:a.props.id}:e.selection}}case"reorder":return V(e,{...t,type:"move",sourceZone:t.destinationZone},n);case"move":{if(t.sourceZone===t.destinationZone&&t.sourceIndex===t.destinationIndex)return e;const r=P(o,n,t.sourceZone,t.sourceIndex);if(!r)return e;const i={...u(t.destinationZone),index:t.destinationIndex};return{...e,data:p(o,n,r.props.id,i)}}case"remove":{const r=j(o,n,t.zone,t.index,"remove");return{...e,data:c(o,n,r.props.id)}}default:return e}}var T={drag:!0,duplicate:!0,delete:!0,edit:!0,insert:!0},q={leftSideBarVisible:!0,rightSideBarVisible:!0,arrayState:{},componentList:{},isDragging:!1,previewMode:"edit",viewports:{current:{width:360,height:"auto"},options:[],controlsVisible:!0},field:{focus:null}},G=0,Y=()=>`history-${G+=1}`;function U(e){let t=e.config;const r=e.now??(()=>Date.now()),i=e.historyCoalesceMs??250;let a=e.permissions??{};const l=y(e.data,t);let c={data:l,selection:null,ui:{...q}};if(e.ui){const{itemSelector:n,selectedSlot:r,...i}=e.ui;c={data:l,selection:r?{kind:"slot",...r}:o(l,t,n??null),ui:{...q,...i}}}let u=[{core:c,at:-1/0,sealed:!0,id:Y()}],p=0;const h=e=>{const t=u[p],n=r();!e&&p===u.length-1&&p>0&&!t.sealed&&n-t.at<i?u=[...u.slice(0,p),{...t,core:c,at:n}]:(u=[...u.slice(0,p+1),{core:c,at:n,sealed:e,id:Y()}],p=u.length-1)},m=/* @__PURE__ */new Set;let v=null,b=null,w=0,S=null,I=!1;const C=()=>{for(const e of[...m])e()},x=()=>{u=[...u.slice(0,p),{...u[p],core:c},...u.slice(p+1)]},O=(t,n)=>{w>0?I=I||n:(n?h(!1):c!==t&&x(),c.data!==t.data&&e.onChange?.(c.data),c!==t&&C())},D=e=>{const n=c;if(c=H(c,e,t),c===n)return;const o=e.recordHistory??B(e);O(n,o&&c.data!==n.data)},E=t=>{0===w&&(S=c,I=!1),w+=1;try{t()}catch(e){throw w-=1,0===w&&S&&(c=S,S=null),e}if(w-=1,w>0||!S)return;const n=S;S=null,I&&c.data!==n.data?h(!0):c!==n&&x(),c.data!==n.data&&e.onChange?.(c.data),c!==n&&C()},A=e=>{const n=c,o=L(c.data,t,e);var r,i;(r=o,i=c.selection,r===i||r&&i&&r.kind===i.kind&&("node"===r.kind&&"node"===i.kind?r.id===i.id:"slot"===r.kind&&"slot"===i.kind&&r.parentId===i.parentId&&r.slot===i.slot))||(c={...c,selection:o},O(n,!1))},z=t=>{const n=c;p=t,c=u[p].core,c.data!==n.data&&e.onChange?.(c.data),c!==n&&C()},M=(e={})=>{const n=e.root?t.root?.permissions:t.components[e.item?.type??e.type??""]?.permissions;return{...T,...a,...n}},Z=g(),$={resolveCache:Z,async resolveAll({trigger:e="load",metadata:n}={}){const o=c.data,r={type:"root",props:{...o.root.props??{}}},i=[...o.content,...Object.values(o.zones??{}).flat()],[a,...l]=await Promise.all([k(r,t,{cache:Z,trigger:e,metadata:n}),...i.map(o=>k(o,t,{cache:Z,trigger:e,metadata:n}))]);E(()=>{const e=c;let n=c.data;l.forEach((e,r)=>{if(!e.didChange)return;const a=i[r].props.id,l=s(n,t,a)?.node;l&&l===s(o,t,a)?.node&&(n=f(n,t,a,e.node))}),a.didChange&&n.root===o.root&&(n={...n,root:{...n.root,props:a.node.props,readOnly:a.node.readOnly??n.root.readOnly}}),n!==c.data&&(c={...c,data:n,selection:L(n,t,c.selection)},O(e,!1))})},get config(){return t},getState(){if(v&&b===c)return v;const e=c,o={data:e.data,ui:K(e,t)},r="node"===e.selection?.kind?s(e.data,t,e.selection.id)?.node??null:null;return v={appState:o,selection:e.selection,selectedItem:r,config:t,dispatch:D,history:{back:()=>$.undo(),forward:()=>$.redo(),hasPast:p>0,hasFuture:p<u.length-1,histories:u.map(e=>({id:e.id,state:{data:e.core.data,ui:K(e.core,t)}})),index:p,setHistoryIndex:e=>{e>=0&&e<u.length&&e!==p&&z(e)}},getPermissions:M,getItemById:n=>s(e.data,t,n)?.node,getItemBySelector:n=>function(e,t,n){const[o,r]=(n.zone??"root:default-zone").split(/:(.*)/s);return d(e,t,{parentId:o,slot:r})?.[n.index]}(e.data,t,n),getSelectorForId:o=>{const r=n(e.data,t,{kind:"node",id:o});return r?{index:r.index,zone:r.zone??"root:default-zone"}:void 0}},b=e,v},subscribe:e=>(m.add(e),()=>{m.delete(e)}),dispatch:D,batch:E,select:e=>A(e?{kind:"node",id:e}:null),selectSlot:e=>A(e?{kind:"slot",parentId:e.parentId,slot:e.slot}:null),run(e){E(()=>{const n=c,o=void 0===e.select?c.selection:e.select;c={...c,data:e.data,selection:L(e.data,t,o)},O(n,e.data!==n.data)})},load(e,n={}){const o=c,r=y(e,t);c={...c,data:r,selection:L(r,t,n.selection??c.selection)},n.keepHistory||(u=[{core:c,at:-1/0,sealed:!0,id:Y()}],p=0),c!==o&&C()},undo(){p>0&&z(p-1)},redo(){p<u.length-1&&z(p+1)},setPermissions(e){a=e,v=null,C()},setConfig(e){e!==t&&(t=e,v=null,C())}};return $}function W(e,t){const n=e=>{if(e.altKey)return;e.metaKey!==e.ctrlKey&&("KeyZ"===e.code?(e.preventDefault(),e.shiftKey?t.redo():t.undo()):"KeyY"!==e.code||e.shiftKey||(e.preventDefault(),t.redo()))};return e.addEventListener("keydown",n),()=>e.removeEventListener("keydown",n)}var X=C(null);function Q({editor:e,hotkeys:t=!0,resolveOnMount:n=!0,children:o}){return x(()=>{n&&e.resolveAll()},[e,n]),x(()=>{if(t&&"undefined"!=typeof document)return W(document,e)},[e,t]),/* @__PURE__ */$(X.Provider,{value:e,children:o})}function J(){const e=O(X);if(!e)throw new Error("useEditor: no <EditorProvider> above this component");return e}function _(e){const t=J(),n=D({view:null,selector:null,value:void 0,has:!1}),o=()=>{const o=t.getState(),r=n.current;if(r.has&&r.view===o&&r.selector===e)return r.value;const i=e(o);return r.has&&Object.is(r.value,i)?(n.current={view:o,selector:e,value:r.value,has:!0},r.value):(n.current={view:o,selector:e,value:i,has:!0},i)};return E(t.subscribe,o,o)}function ee(){return function(e){return _(e)}}var te="data-puck-component",ne="data-puck-dropzone",oe={},re="data-es-mirror";function ie(e,t,n){for(const e of Array.from(t.head.querySelectorAll(`[${re}]`)))e.remove();for(const o of Array.from(e.head.querySelectorAll('style, link[rel="stylesheet"]'))){const e=o.cloneNode(!0);e.setAttribute(re,""),n&&e.setAttribute("nonce",n),t.head.appendChild(e)}}function ae({children:t,id:n="preview-frame",title:o,className:r,style:s,mirrorStyles:l=!0,onDocument:d,height:c="auto",nonce:u}){const p=i("canvas",e),h=D(null),[f,m]=A(null);return z(()=>{const e=h.current,t=f?.ownerDocument.defaultView;if("auto"!==c||!e||!f||!t)return;const n=()=>{e.style.height=`${Math.ceil(f.getBoundingClientRect().height)}px`};n();const o=t.ResizeObserver,r=o?new o(n):null;return r?.observe(f),()=>r?.disconnect()},[f,c]),z(()=>{let e=h.current?.contentDocument;if(!e)return;"CSS1Compat"!==e.compatMode&&(e.open(),e.write("<!DOCTYPE html><html><head></head><body></body></html>"),e.close(),e=h.current?.contentDocument??e),e.body||e.documentElement.appendChild(e.createElement("body")),e.body.style.margin="0";const t=e.createElement("div");t.setAttribute("data-puck-entry",""),t.id="frame-root","fill"===c&&t.classList.add("es-frame-fill"),e.body.appendChild(t),a(e,u),m(t),d?.(e);let n=null;const o=h.current?.ownerDocument;if(l&&o){ie(o,e,u);const t=o.defaultView;t&&"MutationObserver"in t&&(n=new t.MutationObserver(()=>ie(o,e,u)),n.observe(o.head,{childList:!0,subtree:!0,characterData:!0}))}return()=>{n?.disconnect(),t.remove(),m(null),d?.(null)}},[]),/* @__PURE__ */$("iframe",{ref:h,id:n,title:o??p.frame,className:r,style:{border:0,width:"100%",display:"block",..."fill"===c?{height:"100%"}:null,...s},children:f?N(t,f):null})}var se=C(null),le=C(oe),de=[];function ce({parentId:e,slot:t,className:n,style:o,minEmptyHeight:r=128}){const i=J(),a=_(n=>d(n.appState.data,i.config,{parentId:e,slot:t})??de),s=_(t=>"node"===t.selection?.kind&&t.selection.id===e&&e!==l),c=_(n=>"slot"===n.selection?.kind&&n.selection.parentId===e&&n.selection.slot===t),u=O(se),p=["es-zone"];return a.length&&p.push("has-children"),e===l&&p.push("is-root"),(s||c)&&p.push("is-area-selected"),null!==u&&u===e&&e!==l&&p.push("is-hovering-area"),n&&p.push(n),/* @__PURE__ */$("div",{className:p.join(" "),[ne]:`${e}:${t}`,style:{...o,"--min-empty-height":`${r}px`},children:a.map(e=>/* @__PURE__ */$(he,{node:e},e.props.id))})}function ue(e,t,n,o){const r="root"===t?e.root:e.components[t],i={...o};for(const e of w(S(r)))i[e]=function(t={}){/* @__PURE__ */
|
|
2
|
+
return $(ce,{parentId:n,slot:e,...t})};return i}function pe(e){return function({zone:t,...n}){/* @__PURE__ */
|
|
3
|
+
return $(ce,{parentId:e,slot:t,...n})}}function he({node:e}){const t=J().config,n=t.components[e.type],o=e.props.id,r=function(e){const t=D(null);return M(()=>n=>{const o=t.current;o&&o!==n&&(o.removeAttribute(te),o.removeAttribute("data-puck-dnd")),t.current=n,n&&(n.setAttribute(te,e),n.setAttribute("data-puck-dnd",e),n.style.position="relative")},[e])}(o),i=O(le);if(!n?.render)return null;const a=n.render,s=ue(t,e.type,o,{...I(n),...e.props}),l={renderDropZone:pe(o),isEditing:!0,dragRef:n.inline?r:null,metadata:{...i,...n.metadata}};return n.inline?/* @__PURE__ */$(a,{...s,puck:l,editMode:!0}):/* @__PURE__ */$("div",{[te]:o,"data-puck-dnd":o,style:{position:"relative"},children:/* @__PURE__ */$(a,{...s,puck:l,editMode:!0})})}function fe({metadata:e}){const t=_(e=>e.config),n=_(e=>e.appState.data.root).props??{},o=t.root?.render,r=/* @__PURE__ */$(ce,{parentId:l,slot:b}),i=o?/* @__PURE__ */$(o,{id:"puck-root",...ue(t,"root",l,n),puck:{renderDropZone:pe(l),isEditing:!0,dragRef:null,metadata:e??{}},editMode:!0,children:r}):r;/* @__PURE__ */
|
|
4
|
+
return $(le.Provider,{value:e??oe,children:i})}function me({id:e,kind:t,overlay:n}){const o=D(null),[r,i]=A(null);z(()=>{const t=o.current?.ownerDocument,n=t?.defaultView;if(!t||!n||!e)return void i(null);let r=0;const a=()=>{r=0;const a=function(e,t){if(!e||!t)return null;const n=e.getBoundingClientRect(),o=t.getBoundingClientRect();return{top:n.top-o.top,left:n.left-o.left,width:n.width,height:n.height}}(t.querySelector(`[${te}="${n.CSS?.escape?n.CSS.escape(e):e}"]`),o.current?.parentElement??null);i(e=>{return(t=e)===(n=a)||t&&n&&t.top===n.top&&t.left===n.left&&t.width===n.width&&t.height===n.height?e:a;var t,n})},s=()=>{r||(r=(n.requestAnimationFrame??(e=>n.setTimeout(e,16)))(a))};a();const l="MutationObserver"in n?new n.MutationObserver(s):null;l?.observe(t.body,{childList:!0,subtree:!0,attributes:!0,characterData:!0});const d="ResizeObserver"in n?new n.ResizeObserver(s):null;return d?.observe(t.documentElement),n.addEventListener("resize",s),()=>{l?.disconnect(),d?.disconnect(),n.removeEventListener("resize",s),r&&(n.cancelAnimationFrame??n.clearTimeout)(r)}},[e]);const a=/* @__PURE__ */$("div",{ref:o,"aria-hidden":"true",className:`es-canvas-outline is-${t}`,style:r?{position:"absolute",top:r.top,left:r.left,width:r.width,height:r.height}:{display:"none"}});return n&&e?/* @__PURE__ */$(n,{componentId:e,kind:t,children:a}):a}function ve({frame:e=!0,className:t,style:n,metadata:o,mirrorStyles:r,onDocument:i,height:a,title:s,nonce:l,frameWrapper:d,overlay:c,children:u}){const p=J(),[h,f]=A(void 0),m=_(e=>"node"===e.selection?.kind?e.selection.id:null),[v,y]=A(null),g=/* @__PURE__ */R("div",{className:"es-canvas-content",style:{position:"relative"},onClick:e=>{const t=e.target;t.closest?.("a[href]")&&e.preventDefault();const n=t.closest?.(`[${te}]`);n?p.select(n.getAttribute(te)):t.hasAttribute?.(ne)||p.select(null)},onMouseOver:e=>{const t=e.target.closest?.(`[${te}]`),n=t?.getAttribute(te)??null;n!==v&&y(n)},onMouseLeave:()=>y(null),children:[
|
|
5
|
+
/* @__PURE__ */$(se.Provider,{value:v,children:/* @__PURE__ */$(fe,{metadata:o})}),
|
|
6
|
+
/* @__PURE__ */R("div",{className:"es-canvas-outlines",style:{position:"absolute",top:0,left:0,pointerEvents:"none"},children:[
|
|
7
|
+
/* @__PURE__ */$(me,{id:v&&v!==m?v:null,kind:"hover",overlay:c}),
|
|
8
|
+
/* @__PURE__ */$(me,{id:m,kind:"selected",overlay:c})]}),u]}),k=d?/* @__PURE__ */$(d,{document:h,children:g}):g,b=D(null);/* @__PURE__ */
|
|
9
|
+
return $("div",{className:"es-canvas"+(t?` ${t}`:""),style:n,"data-puck-preview":"",children:e?/* @__PURE__ */$(ae,{mirrorStyles:r,onDocument:e=>{b.current?.(),b.current=e?W(e,p):null,f(e??void 0),i?.(e)},height:a,title:s,nonce:l,children:k}):/* @__PURE__ */$("div",{id:"preview-frame","data-puck-entry":"",children:k})})}function ye(e={}){const t=J(),n=_(e=>e.appState.data);return r({...e,data:n,config:t.config,commit:(e,{select:n})=>t.run({data:e,select:n})})}function ge(){const e=J(),n=_(e=>e.config),o=e.resolveCache,r=_(e=>e.selectedItem),i=_(e=>e.appState.data.root),a=r?r.props.id:"root",l=i.props??{},d=M(()=>r||{type:"root",props:l},[r,l]),c=r?n.components[r.type]:n.root,u=e.getState(),p=r?s(u.appState.data,n,a):null,h=p&&"root"!==p.place.parentId?p.place.parentId:null,f=h?u.getItemById(h)??null:null,{fields:m}=t({id:a,node:d,block:c,parent:f,appState:u.appState}),v=u.getPermissions(r?{item:r}:{root:!0}),y=Z((t,r)=>{(async()=>{const i=e.getState();if("root"!==a){const s=i.getItemById(a),l=i.getSelectorForId(a);if(!s||!l)return;const d={...s,props:{...s.props,[t]:r}},{node:c}=await k(d,n,{cache:o,trigger:"replace"}),u=e.getState().getSelectorForId(a);if(!u)return;return void e.dispatch({type:"replace",destinationZone:u.zone??"root:default-zone",destinationIndex:u.index,data:c})}const s=i.appState.data.root.props??{},{node:l}=await k({type:"root",props:{...s,[t]:r}},n,{cache:o,trigger:"replace"});e.dispatch({type:"replaceRoot",root:{props:l.props,readOnly:l.readOnly},recordHistory:!0})})()},[e,n,o,a]);return{id:a,node:d,fields:m,values:d.props,readOnly:!1===v.edit,onChange:y}}export{ae as CanvasFrame,q as DEFAULT_UI,fe as EditDocument,ve as EditorCanvas,Q as EditorProvider,W as bindUndoKeys,U as createEditor,ee as createUseEditor,B as recordsByDefault,H as reduce,K as uiView,_ as useEditor,J as useEditorApi,ye as useEditorNodeOps,ge as useSelectedFields,L as validSelection};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* efficient-easel/fields.css — the Inspector's own controls (blueprint 4.1).
|
|
3
|
+
*
|
|
4
|
+
* The rows, the tabs and the groups are `panel.css`'s (SettingsField,
|
|
5
|
+
* SettingsTabs, SettingsGroup): the panel's rhythm is defined there ONCE
|
|
6
|
+
* (`--es-row-gap`, `--es-rhythm-*`), so this file adds no spacing between rows
|
|
7
|
+
* and no spacing between groups. What it adds is what a row HOLDS where Puck
|
|
8
|
+
* used to put the browser's own: a text box, a number box, a dropdown.
|
|
9
|
+
*
|
|
10
|
+
* Every colour is a shell token (`shell.css`), so the dark editor is the same
|
|
11
|
+
* file.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/* ── the box: one line, several lines, the dropdown's button ──────────────── */
|
|
15
|
+
|
|
16
|
+
.es-fin {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
width: 100%;
|
|
19
|
+
min-width: 0;
|
|
20
|
+
height: 32px;
|
|
21
|
+
padding: 0 10px;
|
|
22
|
+
border: 1px solid var(--es-input-border);
|
|
23
|
+
border-radius: var(--es-field-radius);
|
|
24
|
+
background: var(--es-field-bg);
|
|
25
|
+
color: var(--es-field-text);
|
|
26
|
+
font: inherit;
|
|
27
|
+
font-size: 12px;
|
|
28
|
+
line-height: 1.4;
|
|
29
|
+
}
|
|
30
|
+
.es-fin::placeholder { color: var(--es-field-placeholder); }
|
|
31
|
+
.es-fin:hover:not(:disabled):not([readonly]) { border-color: var(--es-muted); }
|
|
32
|
+
.es-fin:focus-visible,
|
|
33
|
+
.es-fin:focus {
|
|
34
|
+
outline: none;
|
|
35
|
+
border-color: var(--es-accent);
|
|
36
|
+
box-shadow: 0 0 0 3px var(--es-accent-ring);
|
|
37
|
+
}
|
|
38
|
+
.es-fin[readonly],
|
|
39
|
+
.es-fin:disabled { background: var(--es-track-bg); color: var(--es-muted); }
|
|
40
|
+
|
|
41
|
+
.es-fin--area {
|
|
42
|
+
height: auto;
|
|
43
|
+
min-height: 64px;
|
|
44
|
+
padding: 8px 10px;
|
|
45
|
+
resize: vertical;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* ── a number: the box, its unit, − and + ─────────────────────────────────── */
|
|
49
|
+
|
|
50
|
+
.es-fnum {
|
|
51
|
+
display: flex;
|
|
52
|
+
align-items: center;
|
|
53
|
+
gap: 8px;
|
|
54
|
+
width: 100%;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
}
|
|
57
|
+
.es-fnum-box { flex: 0 1 96px; }
|
|
58
|
+
.es-fnum-unit { font-size: 12px; color: var(--es-muted); }
|
|
59
|
+
.es-fnum-steps { display: flex; gap: 4px; margin-left: auto; }
|
|
60
|
+
|
|
61
|
+
.es-fbtn {
|
|
62
|
+
height: 28px;
|
|
63
|
+
min-width: 28px;
|
|
64
|
+
padding: 0 8px;
|
|
65
|
+
border: 1px solid var(--es-btn-border);
|
|
66
|
+
border-radius: var(--es-field-radius);
|
|
67
|
+
background: var(--es-raised);
|
|
68
|
+
color: var(--es-btn-text);
|
|
69
|
+
font: inherit;
|
|
70
|
+
font-size: 12px;
|
|
71
|
+
cursor: pointer;
|
|
72
|
+
}
|
|
73
|
+
.es-fbtn:hover:not(:disabled) { background: var(--es-hover); }
|
|
74
|
+
.es-fbtn:disabled { color: var(--es-disabled); cursor: default; }
|
|
75
|
+
.es-fbtn:focus-visible { outline: 2px solid var(--es-accent); outline-offset: 1px; }
|
|
76
|
+
|
|
77
|
+
/* ── one of a set: the button and its list ────────────────────────────────── */
|
|
78
|
+
|
|
79
|
+
.es-fsel { position: relative; width: 100%; min-width: 0; }
|
|
80
|
+
.es-fsel-button {
|
|
81
|
+
display: flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
justify-content: space-between;
|
|
84
|
+
gap: 8px;
|
|
85
|
+
text-align: left;
|
|
86
|
+
cursor: pointer;
|
|
87
|
+
}
|
|
88
|
+
.es-fsel-value { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
89
|
+
.es-fsel-value.is-empty { color: var(--es-field-placeholder); }
|
|
90
|
+
/* The chevron is drawn, not a glyph, so it sits on the same stroke as the
|
|
91
|
+
panel's other chevrons whatever the font. */
|
|
92
|
+
.es-fsel-chev {
|
|
93
|
+
flex: none;
|
|
94
|
+
width: 7px;
|
|
95
|
+
height: 7px;
|
|
96
|
+
margin: -3px 2px 0 0;
|
|
97
|
+
border-right: 1.6px solid var(--es-icon);
|
|
98
|
+
border-bottom: 1.6px solid var(--es-icon);
|
|
99
|
+
transform: rotate(45deg);
|
|
100
|
+
}
|
|
101
|
+
.es-fsel-list {
|
|
102
|
+
position: absolute;
|
|
103
|
+
z-index: 20;
|
|
104
|
+
top: calc(100% + 4px);
|
|
105
|
+
left: 0;
|
|
106
|
+
right: 0;
|
|
107
|
+
max-height: 240px;
|
|
108
|
+
overflow-y: auto;
|
|
109
|
+
margin: 0;
|
|
110
|
+
padding: 4px;
|
|
111
|
+
list-style: none;
|
|
112
|
+
border: 1px solid var(--es-line);
|
|
113
|
+
border-radius: var(--es-row-radius);
|
|
114
|
+
background: var(--es-raised);
|
|
115
|
+
box-shadow: var(--es-panel-shadow);
|
|
116
|
+
}
|
|
117
|
+
.es-fsel-list:focus { outline: none; }
|
|
118
|
+
.es-fsel-option {
|
|
119
|
+
padding: 7px 8px;
|
|
120
|
+
border-radius: var(--es-field-radius);
|
|
121
|
+
font-size: 12px;
|
|
122
|
+
color: var(--es-text);
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
}
|
|
125
|
+
.es-fsel-option.is-active { background: var(--es-hover); }
|
|
126
|
+
.es-fsel-option.is-chosen { color: var(--es-accent-text); font-weight: 600; }
|
|
127
|
+
.es-fsel-option[aria-disabled='true'] { color: var(--es-disabled); cursor: default; }
|
|
128
|
+
|
|
129
|
+
/* ── the panel body: the tab strip and the rows (Inspector) ───────────────── */
|
|
130
|
+
|
|
131
|
+
.es-insp { display: flex; flex-direction: column; min-width: 0; }
|
|
132
|
+
|
|
133
|
+
/* The strip stays in view while the rows scroll under it, on the panel's own
|
|
134
|
+
ground so a row never shows through. */
|
|
135
|
+
.es-insp-tabs {
|
|
136
|
+
position: sticky;
|
|
137
|
+
top: 0;
|
|
138
|
+
z-index: 2;
|
|
139
|
+
background: var(--es-panel);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* A row adds NO spacing: the field inside it carries the panel's rhythm
|
|
143
|
+
(panel.css). A row that draws nothing takes no space at all, and a row on
|
|
144
|
+
another tab is out of the layout but still mounted. */
|
|
145
|
+
.es-insp-row { min-width: 0; }
|
|
146
|
+
.es-insp-row:empty,
|
|
147
|
+
.es-insp-row[hidden] { display: none; }
|
|
148
|
+
|
|
149
|
+
/* ── a list (ListField, 4.2): Layers' own rows, an add button, an open item ── */
|
|
150
|
+
|
|
151
|
+
.es-list { display: flex; flex-direction: column; gap: 8px; min-width: 0; margin-top: max(var(--es-row-gap), var(--es-rhythm-between)); }
|
|
152
|
+
.es-list-head {
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: baseline;
|
|
155
|
+
justify-content: space-between;
|
|
156
|
+
gap: 8px;
|
|
157
|
+
}
|
|
158
|
+
.es-list-label { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--es-text); }
|
|
159
|
+
.es-list-count { font-size: 11px; color: var(--es-muted); }
|
|
160
|
+
/* The rows are Layers' rows (tree.css); the list lets them reach the panel's
|
|
161
|
+
edges the way Layers' do, so a row's hover reads as the same row. */
|
|
162
|
+
.es-list-tree { margin: 0 -8px; }
|
|
163
|
+
|
|
164
|
+
.es-list-add {
|
|
165
|
+
height: 32px;
|
|
166
|
+
border: 1px dashed var(--es-btn-border);
|
|
167
|
+
border-radius: var(--es-field-radius);
|
|
168
|
+
background: none;
|
|
169
|
+
color: var(--es-text-secondary);
|
|
170
|
+
font: inherit;
|
|
171
|
+
font-size: 12px;
|
|
172
|
+
cursor: pointer;
|
|
173
|
+
}
|
|
174
|
+
.es-list-add:hover:not(:disabled) { background: var(--es-hover); }
|
|
175
|
+
.es-list-add:disabled { color: var(--es-disabled); cursor: default; }
|
|
176
|
+
.es-list-add:focus-visible { outline: 2px solid var(--es-accent); outline-offset: 1px; }
|
|
177
|
+
|
|
178
|
+
/* An item opened: the way back, its name, its own settings, its two actions. */
|
|
179
|
+
.es-list.is-open { gap: 12px; }
|
|
180
|
+
.es-list-back {
|
|
181
|
+
align-self: flex-start;
|
|
182
|
+
display: inline-flex;
|
|
183
|
+
align-items: center;
|
|
184
|
+
gap: 6px;
|
|
185
|
+
height: 28px;
|
|
186
|
+
padding: 0 8px 0 6px;
|
|
187
|
+
border: 0;
|
|
188
|
+
border-radius: var(--es-field-radius);
|
|
189
|
+
background: var(--es-hover);
|
|
190
|
+
color: var(--es-text-secondary);
|
|
191
|
+
font: inherit;
|
|
192
|
+
font-size: 12px;
|
|
193
|
+
cursor: pointer;
|
|
194
|
+
}
|
|
195
|
+
.es-list-back:focus-visible { outline: 2px solid var(--es-accent); outline-offset: 1px; }
|
|
196
|
+
.es-list-back-chev {
|
|
197
|
+
width: 6px;
|
|
198
|
+
height: 6px;
|
|
199
|
+
border-left: 1.6px solid currentColor;
|
|
200
|
+
border-bottom: 1.6px solid currentColor;
|
|
201
|
+
transform: rotate(45deg);
|
|
202
|
+
}
|
|
203
|
+
.es-list-title { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
204
|
+
.es-list-name { font-size: 14px; font-weight: 600; color: var(--es-text); }
|
|
205
|
+
.es-list-item { min-width: 0; }
|
|
206
|
+
.es-list-item-actions { display: flex; gap: 8px; margin-top: 8px; }
|
|
207
|
+
.es-fbtn--danger { color: var(--es-danger); }
|