efficient-easel 27.1.0 → 27.2.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/AddSidePanel-DoCx-ZrM.d.ts +1994 -0
- package/dist/{ScreenDocumentContext-DPW_6gOC.d.ts → ScreenDocumentContext-JQr4hTeP.d.ts} +7 -5
- package/dist/{chunk-P3HXHLES.js → chunk-2Y4CAWZQ.js} +3 -3
- package/dist/{chunk-RTMDZJNE.js → chunk-3RGHXL5V.js} +1 -1
- package/dist/chunk-64NREOML.js +1 -0
- package/dist/chunk-DCBUJ36Q.js +5 -0
- package/dist/{chunk-SEC6NV6Y.js → chunk-DQSRGKSM.js} +4 -4
- package/dist/{chunk-L36E2WCO.js → chunk-HGTDDSFJ.js} +15 -15
- package/dist/{chunk-LAJYMOY3.js → chunk-I4Z75MCX.js} +1 -1
- package/dist/{chunk-QPNNWQ24.js → chunk-JI7GUM3C.js} +1 -1
- package/dist/chunk-LK56FUFT.js +1 -0
- package/dist/chunk-M5UCPD66.js +1 -0
- package/dist/{chunk-XESNAMI3.js → chunk-MMHYTIUY.js} +3 -3
- package/dist/chunk-OSF2H3LO.js +1 -0
- package/dist/{chunk-3FANFZ4D.js → chunk-PTTQWCD7.js} +1 -1
- package/dist/{chunk-WL57KM5C.js → chunk-SR2535CN.js} +17 -17
- package/dist/{chunk-SEH3Q3EL.js → chunk-XGTO4LHI.js} +1 -1
- package/dist/chunk-YCYGY54I.js +8 -0
- package/dist/chunk-ZSP4ZAQ2.js +64 -0
- package/dist/drag/index.js +1 -1
- package/dist/easel/index.js +1 -1
- package/dist/screen/components/AddBlockRow.js +1 -1
- package/dist/screen/components/AddSidePanel.d.ts +2 -4
- package/dist/screen/components/AddSidePanel.js +1 -1
- package/dist/screen/components/NodeContextMenu.d.ts +2 -4
- package/dist/screen/components/NodeContextMenu.js +1 -1
- package/dist/screen/components/SaveControls.d.ts +2 -4
- package/dist/screen/components/ScreenChrome.js +1 -1
- package/dist/screen/components/ScreenDocumentContext.d.ts +1 -1
- package/dist/screen/components/ScreenMount.d.ts +2 -4
- package/dist/screen/components/ScreenMount.js +1 -1
- package/dist/screen/components/ScreenStoreProvider.d.ts +2 -4
- package/dist/screen/components/ScreenStoreProvider.js +1 -1
- package/dist/screen/components/SectionScreenShell.js +17 -17
- package/dist/screen/components/usePartBridge.d.ts +2 -4
- package/dist/screen/components/usePartBridge.js +1 -1
- package/dist/screen/index.d.ts +2 -4
- package/dist/screen/index.js +1 -1
- package/dist/screen/lib/document/add-target-types.d.ts +37 -55
- package/dist/screen/lib/document/block-set-host.js +1 -1
- package/dist/screen/lib/document/block-size-fields.d.ts +1 -1
- package/dist/screen/lib/document/block-size-fields.js +1 -1
- package/dist/screen/lib/document/box-fields.d.ts +1 -1
- package/dist/screen/lib/document/box-fields.js +1 -1
- package/dist/screen/lib/document/button-fields.d.ts +1 -1
- package/dist/screen/lib/document/button-fields.js +1 -1
- package/dist/screen/lib/document/image-fields.d.ts +1 -1
- package/dist/screen/lib/document/image-fields.js +4 -4
- package/dist/screen/lib/document/new-child.d.ts +58 -0
- package/dist/screen/lib/document/new-child.js +1 -0
- package/dist/screen/lib/document/palette-sections.d.ts +2 -4
- package/dist/screen/lib/document/shadow-fields.d.ts +1 -1
- package/dist/screen/lib/document/shadow-fields.js +2 -2
- package/dist/screen/lib/document/slot-section-spec.d.ts +37 -96
- package/dist/screen/lib/document/style-clipboard.d.ts +2 -4
- package/dist/screen/lib/document/style-clipboard.js +1 -1
- package/dist/screen/lib/document/style-fields.d.ts +1 -1
- package/dist/screen/lib/document/style-fields.js +1 -1
- package/dist/screen/lib/document/use-section-ops.js +1 -1
- package/dist/screen/lib/document-addressing.d.ts +1 -1
- package/dist/screen/lib/host.d.ts +1 -1
- package/dist/screen/lib/key-scope.js +1 -1
- package/dist/screen/lib/media-panel.d.ts +1 -1
- package/dist/screen/lib/media-picker.d.ts +1 -1
- package/dist/screen/lib/screen-parts.d.ts +20 -1827
- package/dist/screen/lib/screen-parts.js +1 -1
- package/package.json +7 -1
- package/dist/chunk-DTEYSPJE.js +0 -64
- package/dist/chunk-GJ427TZL.js +0 -8
- package/dist/chunk-J5VPNHOW.js +0 -1
- package/dist/chunk-TUIBPB77.js +0 -5
- package/dist/chunk-WW24O7HT.js +0 -1
- package/dist/chunk-XT75WETI.js +0 -1
|
@@ -1,34 +1,33 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import { EaselSession } from './session.js';
|
|
19
|
-
import { AddTarget } from './document/add-target-types.js';
|
|
20
|
-
import { SlotConfigView, SlotChild } from './document/content-tree.js';
|
|
21
|
-
import '../../words-SD4neL0n.js';
|
|
1
|
+
import 'react';
|
|
2
|
+
import '../../blocks/index.js';
|
|
3
|
+
import '../../watch-Unf6SfUf.js';
|
|
4
|
+
import '../../types-SrGNzYeO.js';
|
|
5
|
+
import '../../types-Dq180WRV.js';
|
|
6
|
+
import '../../CanvasDragLayer-DXeQGrwJ.js';
|
|
7
|
+
import '../../copy-place-CQIemdtU.js';
|
|
8
|
+
import '../../types-BbOBWXMP.js';
|
|
9
|
+
import '../../types-Cy7rdmXt.js';
|
|
10
|
+
import '../../style-clipboard/index.js';
|
|
11
|
+
import '../../types-CoUTWUwB.js';
|
|
12
|
+
export { C as CopyItemAction, a as CopyItemRequest, N as NodeDefaults, S as SELECTION_MODE, b as ScreenBlockLook, c as ScreenBlockRules, d as ScreenBridges, e as ScreenCanvas, f as ScreenCanvasDrag, g as ScreenCanvasDragContext, h as ScreenCanvasHeadProps, i as ScreenCanvasTargetProvider, j as ScreenDevices, k as ScreenDocumentOps, l as ScreenDragItem, m as ScreenInspector, n as ScreenInspectorMode, o as ScreenInspectorPanelProps, p as ScreenLeftPanel, q as ScreenLeftView, r as ScreenLeftViewFrame, s as ScreenLeftViewRules, t as ScreenMainAction, u as ScreenMediaDrop, v as ScreenMediaFile, w as ScreenMenuItem, x as ScreenMenuRows, y as ScreenNewNode, z as ScreenNode, A as ScreenNodeActions, B as ScreenNodeAt, D as ScreenNodeLevel, E as ScreenNodeMaker, F as ScreenPartMode, G as ScreenParts, H as ScreenPartsProvider, I as ScreenPinnedBand, J as ScreenPinnedNodes, K as ScreenRailItem, L as ScreenSelector, M as ScreenSharedSections, O as ScreenSlot, P as ScreenSlotAction, Q as ScreenSlotMode, R as ScreenStyleClipboard, T as ScreenStyleDocument, U as ScreenStylePastePlan, V as ScreenToastExtra, W as ScreenTree, X as ScreenTreeFolds, Y as ScreenTreeRows, Z as isPinnedFirst, _ as isPinnedLast, $ as isSelectionMode, a0 as isSlotMode, a1 as sameInspectorMode, a2 as screenSlotsOf, a3 as shownChildSlotsOf, a4 as shownSlotFieldsOf, a5 as useScreenBlockLook, a6 as useScreenBlockRules, a7 as useScreenBridges, a8 as useScreenCanvasDrag, a9 as useScreenCanvasFrame, aa as useScreenCanvasHead, ab as useScreenCanvasTarget, ac as useScreenDevices, ad as useScreenDocumentLabel, ae as useScreenDocumentPass, af as useScreenInspectorPanel, ag as useScreenLeftView, ah as useScreenNodeKeys, ai as useScreenNotify, aj as useScreenOwnerName, ak as useScreenParts, al as useScreenPickFollowsSelection, am as useScreenPinned, an as useScreenSaveSwitch, ao as useScreenStorageNamespace, ap as useScreenStyleClipboard, aq as useStandaloneScreenBridges } from '../../AddSidePanel-DoCx-ZrM.js';
|
|
13
|
+
import '../../ScreenDocumentContext-JQr4hTeP.js';
|
|
14
|
+
import './host-chrome.js';
|
|
15
|
+
import './session.js';
|
|
16
|
+
import './shared-section-types.js';
|
|
17
|
+
import './document/content-tree.js';
|
|
22
18
|
import '../../types-BljCVdzR.js';
|
|
23
19
|
import '../../data/index.js';
|
|
24
20
|
import '../../phone-order-CRKvsTsz.js';
|
|
25
21
|
import '../../plan-D0DgSLnY.js';
|
|
26
22
|
import '../../edit-lock/index.js';
|
|
27
23
|
import '../../panelWidths-DgQXiPXU.js';
|
|
24
|
+
import '../../words-SD4neL0n.js';
|
|
28
25
|
import '../../wordFit-7XpmhcaW.js';
|
|
29
26
|
import '../../words-CnnHb9jo.js';
|
|
30
27
|
import 'efficient-shell/ui';
|
|
31
28
|
import '../../words-Cl9xMUYY.js';
|
|
29
|
+
import './section-template-types.js';
|
|
30
|
+
import './document/block-choice.js';
|
|
32
31
|
import './document-contract.js';
|
|
33
32
|
import './document-switch.js';
|
|
34
33
|
import '../../engine-CvXpFE86.js';
|
|
@@ -36,1809 +35,3 @@ import './admin-bridge.js';
|
|
|
36
35
|
import './backend-error.js';
|
|
37
36
|
import './links/link-filters.js';
|
|
38
37
|
import './document-hooks.js';
|
|
39
|
-
import './document/slot-section-spec.js';
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* WHAT THE WEBSITE HANDS THE EDITOR'S SCREEN — the parts of the screen that
|
|
43
|
-
* know there is a website, given to it instead of imported by it
|
|
44
|
-
* (doc/adr/0003).
|
|
45
|
-
*
|
|
46
|
-
* The screen — the frame, the panels, the tree, the add panel, the inspector —
|
|
47
|
-
* is being made to hold nothing a website has that an email does not: no page,
|
|
48
|
-
* no site theme, no pinned header, no chat bubble. What it used to import and
|
|
49
|
-
* wire itself, the website layer now wires and hands over here, and a screen
|
|
50
|
-
* mounted with no layer above it draws none of it.
|
|
51
|
-
*
|
|
52
|
-
* This is NOT `EaselChrome` (lib/host-chrome): that is what a HOST stands
|
|
53
|
-
* round the editor — the storefront's cart, its header's settings — built in
|
|
54
|
-
* the host and absent on the ambient session. These parts are the builder's
|
|
55
|
-
* own website layer, the same for every host, and present on every mount of
|
|
56
|
-
* the screen (`ScreenStoreProvider` supplies them, from whoever mounts it).
|
|
57
|
-
*
|
|
58
|
-
* Fixed for the life of a mount, like the session: `useBridges`,
|
|
59
|
-
* `useStandaloneBridges`, `useDocumentPass` and `blockLook.useProducts` are
|
|
60
|
-
* called as hooks, and `Canvas` and `Inspector` are rendered as element types,
|
|
61
|
-
* so the provider's value must not change while the screen is mounted.
|
|
62
|
-
*/
|
|
63
|
-
/** A node of the document as the screen hands it to a layer: its type and its
|
|
64
|
-
* props, its id among them. */
|
|
65
|
-
interface ScreenNode {
|
|
66
|
-
type: string;
|
|
67
|
-
props: {
|
|
68
|
-
id: string;
|
|
69
|
-
[key: string]: unknown;
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* A panel of the layer's own, as the screen holds it: a kind, and whatever
|
|
74
|
-
* else the layer put beside it to say WHICH one (the node a panel is about).
|
|
75
|
-
* The screen stores it and hands it back, and reads no further into it than
|
|
76
|
-
* `kind`.
|
|
77
|
-
*/
|
|
78
|
-
type ScreenInspectorMode = {
|
|
79
|
-
kind: string;
|
|
80
|
-
};
|
|
81
|
-
/**
|
|
82
|
-
* THE SELECTION'S OWN PANEL — the one mode the screen names for itself. In it
|
|
83
|
-
* the inspector follows the selection: a node's settings, or the document's
|
|
84
|
-
* with nothing selected. Every other mode is a panel of a layer's, which the
|
|
85
|
-
* screen stores and hands back; this is the one it puts the inspector back to
|
|
86
|
-
* when the selection changes, and on every press of a row of its own.
|
|
87
|
-
*
|
|
88
|
-
* ONE object for the module's life, so setting it while it is the mode already
|
|
89
|
-
* bails out of the state update. A layer whose inspector names this mode names
|
|
90
|
-
* THIS object (the website's `SELECTION_MODE`, components/SectionEditor, is it), so
|
|
91
|
-
* "is the panel showing the selection's own?" has one answer on both sides.
|
|
92
|
-
* The kind is `"selection"`; its old spelling went in easel 22.0.0.
|
|
93
|
-
*/
|
|
94
|
-
declare const SELECTION_MODE: {
|
|
95
|
-
readonly kind: "selection";
|
|
96
|
-
};
|
|
97
|
-
/** Is this the selection's own panel? */
|
|
98
|
-
declare function isSelectionMode(mode: {
|
|
99
|
-
kind: string;
|
|
100
|
-
}): boolean;
|
|
101
|
-
/** The inspector drilled into one PART of a node (lib/document/part-id): the mode
|
|
102
|
-
* the screen's part bridge (components/usePartBridge) opens and closes. The
|
|
103
|
-
* website's inspector modes include it (components/SectionEditor
|
|
104
|
-
* `InspectorMode`). */
|
|
105
|
-
type ScreenPartMode = {
|
|
106
|
-
kind: "part";
|
|
107
|
-
nodeId: string;
|
|
108
|
-
propKey: string;
|
|
109
|
-
};
|
|
110
|
-
/** Are two panels the same panel: the same kind, about the same thing? Asked
|
|
111
|
-
* member by member, so the screen can answer without knowing what a layer
|
|
112
|
-
* keeps beside the kind. */
|
|
113
|
-
declare function sameInspectorMode(a: ScreenInspectorMode, b: ScreenInspectorMode): boolean;
|
|
114
|
-
/**
|
|
115
|
-
* A SLOT's own panel (0.105.0): the mode the screen opens when the row of a
|
|
116
|
-
* slot it draws as a rung is pressed (`ScreenSlot.panel`) — the campaign
|
|
117
|
-
* designer's Column inspector. `kind` is the layer's (`panel`), and beside it
|
|
118
|
-
* the node the slot is a slot of and the slot's own name. The screen makes it
|
|
119
|
-
* and hands it back to the layer's inspector; a layer may name one itself to
|
|
120
|
-
* `ScreenInspector.select`.
|
|
121
|
-
*/
|
|
122
|
-
interface ScreenSlotMode extends ScreenInspectorMode {
|
|
123
|
-
nodeId: string;
|
|
124
|
-
slot: string;
|
|
125
|
-
}
|
|
126
|
-
/** Is a panel a slot's own ({@link ScreenSlotMode}) — about a node's slot, not
|
|
127
|
-
* the node? */
|
|
128
|
-
declare function isSlotMode(mode: ScreenInspectorMode): mode is ScreenSlotMode;
|
|
129
|
-
/** An address of a node the screen selects, as its own ops spell one: its
|
|
130
|
-
* index, in the list `zone` names (left out for the top-level list); or null,
|
|
131
|
-
* for nothing selected. */
|
|
132
|
-
type ScreenSelector = {
|
|
133
|
-
index: number;
|
|
134
|
-
zone?: string;
|
|
135
|
-
} | null;
|
|
136
|
-
/** The inspector, as far as a layer needs it: which panel it shows, and how to
|
|
137
|
-
* show one of the layer's own. */
|
|
138
|
-
interface ScreenInspector {
|
|
139
|
-
/** The kind of panel showing now. */
|
|
140
|
-
kind: string;
|
|
141
|
-
/** The panel showing now, whole: what `open` was handed, given back. */
|
|
142
|
-
mode: ScreenInspectorMode;
|
|
143
|
-
/** Show a panel of the layer's own and reveal the inspector, leaving the
|
|
144
|
-
* selection where it is. The same panel already showing stays, as the
|
|
145
|
-
* object it was (`sameInspectorMode`). */
|
|
146
|
-
open: (mode: ScreenInspectorMode) => void;
|
|
147
|
-
/**
|
|
148
|
-
* Put a panel of the layer's own in the inspector and leave the inspector as
|
|
149
|
-
* it stands, in view or hidden: with `reveal` after it, what a press on one
|
|
150
|
-
* of the screen's own rows does. `open` is for a handler registered once: it
|
|
151
|
-
* never changes identity, so it cannot ask whether the inspector is hidden
|
|
152
|
-
* and brings it out every time.
|
|
153
|
-
*/
|
|
154
|
-
show: (mode: ScreenInspectorMode) => void;
|
|
155
|
-
/** Bring the inspector into view if it is hidden. What it shows stays. */
|
|
156
|
-
reveal: () => void;
|
|
157
|
-
/**
|
|
158
|
-
* Move the selection AND put a panel of the layer's own in the inspector, in
|
|
159
|
-
* one step (0.105.0): what the campaign designer's Column needs, which is a
|
|
160
|
-
* slot and not a node — nothing is selected (`null`) and the Column
|
|
161
|
-
* inspector shows. `show` then a selection would not hold: the screen puts
|
|
162
|
-
* the inspector back to the selection's own panel whenever the selection
|
|
163
|
-
* changes, so the mode is kept pending and that reset honours it for this
|
|
164
|
-
* one change. The inspector is left as it stands, in view or hidden, as
|
|
165
|
-
* `show` leaves it. A slot's own panel ({@link ScreenSlotMode}) for a slot
|
|
166
|
-
* the tree draws as a rung also unfolds the tree to that rung's row.
|
|
167
|
-
*/
|
|
168
|
-
select: (selector: ScreenSelector, mode: ScreenInspectorMode) => void;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* What the screen hands THE INSPECTOR it mounts in its right panel
|
|
172
|
-
* (`ScreenParts.Inspector`): the panel to show, the ways out of a panel,
|
|
173
|
-
* and what the screen's own furniture offers one. The names are the ones the
|
|
174
|
-
* screen has always passed, two of them in a website's words: they are the
|
|
175
|
-
* doors the bridges hand back (`openSettings`, `openStyles`).
|
|
176
|
-
*/
|
|
177
|
-
interface ScreenInspectorPanelProps {
|
|
178
|
-
/** The panel to show: the selection's own (`SELECTION_MODE`), or one of the
|
|
179
|
-
* layer's, handed back as the screen was handed it. */
|
|
180
|
-
mode: ScreenInspectorMode;
|
|
181
|
-
/** The way to the settings of the whole document, from a panel that edits
|
|
182
|
-
* one part of it (`ScreenBridges.openSettings`). */
|
|
183
|
-
onOpenWebsiteSettings: () => void;
|
|
184
|
-
/** The way to the styles a part of a block can follow, from that part's own
|
|
185
|
-
* panel (`ScreenBridges.openStyles`). Omitted where there is nowhere to
|
|
186
|
-
* keep them, and the panel draws no door. */
|
|
187
|
-
onOpenSiteStyles?: () => void;
|
|
188
|
-
/** The way to THIS document's own styles (`ScreenBridges.openPageStyles`),
|
|
189
|
-
* for a panel with nothing selected to point at. Omitted where the layer
|
|
190
|
-
* hands none. */
|
|
191
|
-
onOpenPageStyles?: () => void;
|
|
192
|
-
/** Select a node and show ITS OWN settings: the way out of a panel that was
|
|
193
|
-
* scoped down to part of that node. */
|
|
194
|
-
onSelectNode: (nodeId: string) => void;
|
|
195
|
-
/** Withhold the head's duplicate and remove. Set by the screen whose
|
|
196
|
-
* document is ONE node, which a second node or none would break. */
|
|
197
|
-
hideNodeActions?: boolean;
|
|
198
|
-
/** Say one line through the screen's toast. Omitted by a screen with none. */
|
|
199
|
-
onNotify?: (msg: string, tone?: "success" | "error") => void;
|
|
200
|
-
/** Hide the panel: the last button of its head. Omitted by a screen whose
|
|
201
|
-
* inspector is always in view. */
|
|
202
|
-
onHidePanel?: () => void;
|
|
203
|
-
/**
|
|
204
|
-
* Which of the head's two node actions the selected node's BLOCK allows
|
|
205
|
-
* (0.103.0): its config's `permissions.duplicate` and `permissions.delete`,
|
|
206
|
-
* each true unless the config says false — the answer the screen's own tree
|
|
207
|
-
* rows and menu honour, handed on so the head the layer draws honours it
|
|
208
|
-
* too, hiding or greying a refused one. With nothing selected both are true.
|
|
209
|
-
* Handed by the page screen; a layer that never reads it draws its head as
|
|
210
|
-
* it did.
|
|
211
|
-
*/
|
|
212
|
-
nodeActions?: ScreenNodeActions;
|
|
213
|
-
}
|
|
214
|
-
/** What a block's config allows of the two actions that make another node or
|
|
215
|
-
* take one away (`ComponentConfig.permissions`): `false` only where the config
|
|
216
|
-
* says so (lib/document/content-tree `blockNodeActions`). */
|
|
217
|
-
interface ScreenNodeActions {
|
|
218
|
-
duplicate: boolean;
|
|
219
|
-
delete: boolean;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* The document and its tree of rows, as far as a layer needs them to wire and
|
|
223
|
-
* draw the parts of ONE block that are not nodes of their own: what is
|
|
224
|
-
* selected, where a node sits, and the three things a press on such a part's
|
|
225
|
-
* row does to the node it belongs to. Handed to the bridges on every render,
|
|
226
|
-
* so each member is that render's.
|
|
227
|
-
*/
|
|
228
|
-
interface ScreenTree {
|
|
229
|
-
/** The document, as the rules are handed it. */
|
|
230
|
-
data: unknown;
|
|
231
|
-
/** The node selected now, or null. */
|
|
232
|
-
selected: ScreenNode | null;
|
|
233
|
-
/** The key of the list a node sits in, by the node's id. */
|
|
234
|
-
zoneOf: (id: string) => string | undefined;
|
|
235
|
-
/** Somebody else holds the document: nothing may be moved. */
|
|
236
|
-
readOnly: boolean;
|
|
237
|
-
/** Select the top-level node at `index` the way a press on its row does: the
|
|
238
|
-
* inspector goes back to the selection's own panel, then the selection
|
|
239
|
-
* moves. */
|
|
240
|
-
select: (index: number) => void;
|
|
241
|
-
/** Write the top-level node at `index` back, whole. */
|
|
242
|
-
replace: (index: number, node: ScreenNode) => void;
|
|
243
|
-
/** Bring the canvas to a node, as selecting its row does. */
|
|
244
|
-
scrollTo: (id: string) => void;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* The canvas, as far as a layer needs it: which device it is being looked at
|
|
248
|
-
* on, and how often its frame has been rebuilt. The switch, its state and the
|
|
249
|
-
* Refresh are the screen's; a layer whose own fields or preview ask "which
|
|
250
|
-
* view is this?", or which puts the canvas somewhere of its own accord, is
|
|
251
|
-
* told here. Handed to the bridges on every render.
|
|
252
|
-
*/
|
|
253
|
-
interface ScreenCanvas {
|
|
254
|
-
/** The id of the device the switch is on: one of the layer's own
|
|
255
|
-
* (`ScreenDevices.options`). */
|
|
256
|
-
device: string;
|
|
257
|
-
/** How many times the screen has rebuilt the canvas's frame (its Refresh).
|
|
258
|
-
* It changes with each one and with nothing else: a layer that put the
|
|
259
|
-
* canvas somewhere as the document opened lists it as a dependency, and
|
|
260
|
-
* puts it there again in the fresh frame. */
|
|
261
|
-
refreshes: number;
|
|
262
|
-
}
|
|
263
|
-
/**
|
|
264
|
-
* The left panel, as far as a layer needs it: to put it on a view and to bring
|
|
265
|
-
* it out. Which view it is on, whether it is open and what a press on the rail
|
|
266
|
-
* does to either are the screen's. Handed to the bridges on every render.
|
|
267
|
-
*/
|
|
268
|
-
interface ScreenLeftPanel {
|
|
269
|
-
/** Put the panel on a view, by its id: one of the layer's own
|
|
270
|
-
* (`ScreenLeftView`) or one of the screen's. Whether the panel is in view
|
|
271
|
-
* stays, and the screen keeps the choice as it keeps any other. */
|
|
272
|
-
setView: (view: string) => void;
|
|
273
|
-
/** Bring the panel into view if it is hidden. What it shows stays. */
|
|
274
|
-
reveal: () => void;
|
|
275
|
-
}
|
|
276
|
-
/**
|
|
277
|
-
* What a line of the screen's toast may carry besides its words (owner
|
|
278
|
-
* 2026-10-14: a delete goes at once and its toast offers "Undo" for 8 s). The
|
|
279
|
-
* shell's `toast` takes all three (`efficient-shell` 7.24); a host's own
|
|
280
|
-
* `notify` is handed them and should pass them on, or the Undo is lost.
|
|
281
|
-
*/
|
|
282
|
-
interface ScreenToastExtra {
|
|
283
|
-
/** One action after the words: "Undo". */
|
|
284
|
-
action?: {
|
|
285
|
-
label: string;
|
|
286
|
-
onClick: () => void;
|
|
287
|
-
};
|
|
288
|
-
/** How long the line stays, in ms. */
|
|
289
|
-
duration?: number;
|
|
290
|
-
/** Told once how the line went: its action, its time, or a tap. */
|
|
291
|
-
onClose?: (how: "action" | "timeout" | "dismissed") => void;
|
|
292
|
-
}
|
|
293
|
-
/** What a view of the layer's is handed when the left panel draws it: what the
|
|
294
|
-
* screen hands the heads of its own views. */
|
|
295
|
-
interface ScreenLeftViewFrame {
|
|
296
|
-
/** Hide the whole left panel: the last button of every view's head. */
|
|
297
|
-
onHide: () => void;
|
|
298
|
-
/** Say one line through the screen's toast — with its Undo and its time
|
|
299
|
-
* where it has them (`extra`, 7.0.0: a page deleted from the layer's own
|
|
300
|
-
* Pages panel offers Undo through the same door as a section). */
|
|
301
|
-
notify: (msg: string, tone?: "success" | "error", extra?: ScreenToastExtra) => void;
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* A VIEW of the left panel that is the layer's own: a button in the rail, and
|
|
305
|
-
* what the panel shows while the view is the one it is on. The screen lights
|
|
306
|
-
* the button and switches to the view exactly as it does for its own Layers,
|
|
307
|
-
* and draws no frame round what `panel` returns: a view draws its own head.
|
|
308
|
-
*/
|
|
309
|
-
interface ScreenLeftView {
|
|
310
|
-
/** The view's id: what the screen holds as the view the panel is on, and
|
|
311
|
-
* what is kept between mounts (`ScreenLeftViewRules`), so one in use is
|
|
312
|
-
* never renamed. The rail button's id as well. */
|
|
313
|
-
id: string;
|
|
314
|
-
/** The rail button's name. */
|
|
315
|
-
label: string;
|
|
316
|
-
/** …and its glyph. */
|
|
317
|
-
icon: ReactNode;
|
|
318
|
-
/** The view, for the screen to place in the left panel as it comes back. A
|
|
319
|
-
* function called where the panel is drawn and not a component of its own:
|
|
320
|
-
* what it returns is mounted in the screen's place, with nothing between. */
|
|
321
|
-
panel: (frame: ScreenLeftViewFrame) => ReactNode;
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* What a layer stands in the rail: a view of its own, or a button that is NOT
|
|
325
|
-
* a view of the left panel — one that opens something of the layer's
|
|
326
|
-
* elsewhere. That one is the engine's own rail item (efficient-easel/rail),
|
|
327
|
-
* drawn as it is handed: the layer says whether it is lit and what a press
|
|
328
|
-
* does.
|
|
329
|
-
*/
|
|
330
|
-
type ScreenRailItem = ScreenLeftView | EaselRailItem;
|
|
331
|
-
/**
|
|
332
|
-
* The screen's own writes of the document, as far as a layer's pass over a
|
|
333
|
-
* document needs them. They are the writes every surface of the screen makes
|
|
334
|
-
* (lib/document/use-section-ops), refused the same way while somebody else holds
|
|
335
|
-
* the document, and ONE object from render to render until that changes — so a
|
|
336
|
-
* pass may list it as a dependency and run no oftener for it.
|
|
337
|
-
*
|
|
338
|
-
* Every write is FOLDED into the history entry it happens in (1.0.1,
|
|
339
|
-
* `foldIntoHistory`): what a pass gives a document as it opens is part of the
|
|
340
|
-
* document the history starts at, never an undo step that one Undo takes back
|
|
341
|
-
* out. Autosave still hears each write.
|
|
342
|
-
*/
|
|
343
|
-
interface ScreenDocumentOps {
|
|
344
|
-
/** Replace the whole working document, unrecorded. */
|
|
345
|
-
setDocument: (data: Data) => void;
|
|
346
|
-
/** Insert a node of `type`, as its own defaults, into the top-level list;
|
|
347
|
-
* returns the id it was given. */
|
|
348
|
-
insertSection: (type: string, index: number) => string;
|
|
349
|
-
/** Insert a FULL node — its type and its props, slot children inline — into
|
|
350
|
-
* the list `zone` names; returns the id it was given. */
|
|
351
|
-
insertNode: (zone: string, index: number, node: ScreenNode) => string;
|
|
352
|
-
/** Write the node at a place back, whole. */
|
|
353
|
-
replaceComponent: (zone: string, index: number, node: ScreenNode) => void;
|
|
354
|
-
}
|
|
355
|
-
/** What the tree lends a layer that draws a row in it: the row's own click,
|
|
356
|
-
* for a pointer landing outside its name. */
|
|
357
|
-
interface ScreenTreeRows {
|
|
358
|
-
rowClick: (select: () => void) => (e: MouseEvent<HTMLElement>) => void;
|
|
359
|
-
}
|
|
360
|
-
/** …and, for a layer that draws rows which fold, the tree's own fold state.
|
|
361
|
-
* The ids are the layer's to make; the tree keeps them with its own. */
|
|
362
|
-
interface ScreenTreeFolds extends ScreenTreeRows {
|
|
363
|
-
isCollapsed: (id: string) => boolean;
|
|
364
|
-
toggleCollapse: (id: string) => void;
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* A layer's main action, as data (`ScreenBridges.mainAction`, 8.0.0). The
|
|
368
|
-
* screen draws it; the layer draws nothing. Words are the layer's, already in
|
|
369
|
-
* its language.
|
|
370
|
-
*/
|
|
371
|
-
interface ScreenMainAction {
|
|
372
|
-
/** The main half's word: "Publish", "Save and close". */
|
|
373
|
-
label: string;
|
|
374
|
-
/** Its Tooltip while it can be pressed ("Saves your changes and goes back to
|
|
375
|
-
* the campaign. Nothing is sent."). */
|
|
376
|
-
tooltip?: string;
|
|
377
|
-
/** What a press does. */
|
|
378
|
-
onPress: () => void;
|
|
379
|
-
/**
|
|
380
|
-
* The quiet form, while there is nothing for the action to do: the main
|
|
381
|
-
* half becomes secondary, with a check glyph, these words, and off with
|
|
382
|
-
* `reason` ("Published" / "Everything is live"). The chevron still opens.
|
|
383
|
-
* Absent or null: never quiet.
|
|
384
|
-
*/
|
|
385
|
-
quiet?: {
|
|
386
|
-
label: string;
|
|
387
|
-
reason: string;
|
|
388
|
-
} | null;
|
|
389
|
-
/** A reason of the layer's own to turn the main half off, besides the
|
|
390
|
-
* screen's (a lock, a refused save, offline, a failed save). */
|
|
391
|
-
disabledReason?: string | null;
|
|
392
|
-
/** What the menu's status row says after the save ("Saved 2 seconds ago ·
|
|
393
|
-
* Changes not live yet"): "Changes not live yet", "Everything is live",
|
|
394
|
-
* "Never published", "Draft, nothing is sent". */
|
|
395
|
-
status?: string | null;
|
|
396
|
-
/**
|
|
397
|
-
* What the action will put live, one short line each, in the layer's words
|
|
398
|
-
* ("Home", "Site styles", "Main menu"): the website editor's one Publish
|
|
399
|
-
* puts the whole site live, and the merchant sees what it holds before the
|
|
400
|
-
* press. The save menu draws each line as a status row (the shell's
|
|
401
|
-
* `status` entry: muted, not a menu item) under the status row. Absent or
|
|
402
|
-
* empty: no list.
|
|
403
|
-
*/
|
|
404
|
-
goingLive?: readonly string[];
|
|
405
|
-
/**
|
|
406
|
-
* The layer's own rows of the ▾ menu ("Version history"): drawn last, under
|
|
407
|
-
* Save now and one divider, as the shell's menu items. A press closes the
|
|
408
|
-
* menu, then runs `onSelect`. Absent or empty: the menu is as before, with
|
|
409
|
-
* no divider of their own.
|
|
410
|
-
*/
|
|
411
|
-
menuItems?: readonly ScreenMenuItem[];
|
|
412
|
-
/** The action is running: the main half shows the shell's spinner. */
|
|
413
|
-
busy?: boolean;
|
|
414
|
-
}
|
|
415
|
-
/** One of the layer's rows in the ▾ menu ({@link ScreenMainAction.menuItems}). */
|
|
416
|
-
interface ScreenMenuItem {
|
|
417
|
-
/** Unique among the layer's rows. */
|
|
418
|
-
key: string;
|
|
419
|
-
/** The row's words, in the layer's language ("Version history"). */
|
|
420
|
-
label: string;
|
|
421
|
-
/** The shell glyph before the words. */
|
|
422
|
-
icon?: ReactNode;
|
|
423
|
-
/** What a press does, after the menu has closed. */
|
|
424
|
-
onSelect: () => void;
|
|
425
|
-
/** Turns the row off. */
|
|
426
|
-
disabled?: boolean;
|
|
427
|
-
}
|
|
428
|
-
/** What a layer's bridges give back for the screen to place. */
|
|
429
|
-
interface ScreenBridges {
|
|
430
|
-
/** A row under the Add panel's tiles, for something that is not a block.
|
|
431
|
-
* Handed the way to leave Add, for a row that opens a panel. */
|
|
432
|
-
addPanelRow?: (leaveAdd: () => void) => ReactNode;
|
|
433
|
-
/**
|
|
434
|
-
* Rows at the END of a top-level node's own children, for a part of that
|
|
435
|
-
* block which is not a node: "layer, do you draw anything under this row?".
|
|
436
|
-
* Asked only where the node's child rows are drawn, and what comes back is
|
|
437
|
-
* placed as it is — the layer draws with the tree's own row.
|
|
438
|
-
*/
|
|
439
|
-
partRows?: (node: ScreenNode, rows: ScreenTreeRows) => ReactNode;
|
|
440
|
-
/**
|
|
441
|
-
* Does the layer draw a subtree of its OWN under this top-level node — rows
|
|
442
|
-
* for things the block keeps in its props and not in a slot? Such a row
|
|
443
|
-
* folds like any other, so the screen asks before it draws the caret.
|
|
444
|
-
*/
|
|
445
|
-
hasOwnRows?: (node: ScreenNode) => boolean;
|
|
446
|
-
/** That subtree's rows, for the node at `index`. Asked only when
|
|
447
|
-
* `hasOwnRows` said yes and the row is unfolded. */
|
|
448
|
-
ownRows?: (node: ScreenNode, index: number, rows: ScreenTreeFolds) => ReactNode;
|
|
449
|
-
/**
|
|
450
|
-
* The row of a top-level node was pressed, and the screen has selected it:
|
|
451
|
-
* a layer that keeps a focus of its own INSIDE one block puts it back to the
|
|
452
|
-
* block. Called between the selection and the canvas's scroll. The node is
|
|
453
|
-
* the one at the pressed index, if there is one.
|
|
454
|
-
*/
|
|
455
|
-
sectionPressed?: (node: ScreenNode | undefined) => void;
|
|
456
|
-
/**
|
|
457
|
-
* The layer's own controls in the top bar's right cluster. The screen draws
|
|
458
|
-
* that cluster as the save icon and the main button (8.0.0; it was the save
|
|
459
|
-
* pill, Refresh and the main button); a layer has two places in it.
|
|
460
|
-
* `barLead` stands FIRST among the actions, right after the save icon:
|
|
461
|
-
* something done with the whole document that only the layer has. What
|
|
462
|
-
* comes back is placed as it is, and a layer with nothing to offer just now
|
|
463
|
-
* returns nothing.
|
|
464
|
-
*/
|
|
465
|
-
barLead?: () => ReactNode;
|
|
466
|
-
/** …and `barTrail` stands just before the main button: a way out to where
|
|
467
|
-
* the document is read (the website's Preview, the email designer's "Send
|
|
468
|
-
* a test email"). */
|
|
469
|
-
barTrail?: () => ReactNode;
|
|
470
|
-
/** …and `barView` stands in the CENTRE cluster, right after Refresh: a way
|
|
471
|
-
* to look at the document drawn as an icon beside the preview's own
|
|
472
|
-
* controls (the website's Preview, owner 2026-10-25). A layer that has one
|
|
473
|
-
* hands it here instead of `barTrail`. */
|
|
474
|
-
barView?: () => ReactNode;
|
|
475
|
-
/**
|
|
476
|
-
* …and `barMain` IS the main button, in its place at the end of the cluster
|
|
477
|
-
* (0.103.0): the layer's own way to finish with the document — the campaign
|
|
478
|
-
* designer's Done — where the screen draws Publish (a document that
|
|
479
|
-
* publishes) or Save. What comes back is placed as it is, nothing round it,
|
|
480
|
-
* and returning nothing leaves the place empty. Absent, the screen draws its
|
|
481
|
-
* own button, as it always has.
|
|
482
|
-
*/
|
|
483
|
-
barMain?: () => ReactNode;
|
|
484
|
-
/**
|
|
485
|
-
* THE MAIN ACTION, AS DATA (8.0.0, card [DESIGN] A Clearer Save In Both
|
|
486
|
-
* Editors): what the layer's main button says and does, for the screen to
|
|
487
|
-
* draw as the shell's `SplitButton` with the save menu on its chevron. The
|
|
488
|
-
* website's is Publish (quiet as "Published" while everything is live); the
|
|
489
|
-
* email designer's is Save and close. The screen turns the main half off,
|
|
490
|
-
* with the reason, while the document is locked, frozen, refused, offline or
|
|
491
|
-
* holding a failed save; the chevron always opens. Handed back each render,
|
|
492
|
-
* so it follows the layer's state. Wins over `barMain`; with neither, the
|
|
493
|
-
* screen's own Done (`screen.done`) stands in the same split button.
|
|
494
|
-
*/
|
|
495
|
-
mainAction?: ScreenMainAction | null;
|
|
496
|
-
/**
|
|
497
|
-
* The layer's own buttons in the rail. The screen draws the rail as Add, its
|
|
498
|
-
* own Layers and the host's Media library; a layer has two places in it.
|
|
499
|
-
* `railLead` stands between Add and Layers. Each list is the buttons THIS
|
|
500
|
-
* document has, in the order they are drawn: one it does not have is left
|
|
501
|
-
* out, and a view left out is a view the panel cannot be on.
|
|
502
|
-
*/
|
|
503
|
-
railLead?: ReadonlyArray<ScreenRailItem>;
|
|
504
|
-
/** …and `railTrail` stands between Layers and Media. */
|
|
505
|
-
railTrail?: ReadonlyArray<ScreenRailItem>;
|
|
506
|
-
/**
|
|
507
|
-
* Which view the left panel ACTUALLY shows, given the one it is set to: the
|
|
508
|
-
* view kept from another document may be one this document does not have,
|
|
509
|
-
* and the panel then shows the screen's Layers. The layer answers, because
|
|
510
|
-
* some of the views are its own and which of them a document has is its to
|
|
511
|
-
* know. The screen has no media view (the media library is a popup,
|
|
512
|
-
* harness UI-20): a stored "media" view resolves to Layers like any other
|
|
513
|
-
* view this document does not have.
|
|
514
|
-
*/
|
|
515
|
-
resolveLeftView?: (view: string) => string;
|
|
516
|
-
/**
|
|
517
|
-
* A tool of the layer's own at the foot of the Layers tree, under the last
|
|
518
|
-
* row: something that reads the whole document and is not a row of it.
|
|
519
|
-
* Placed as it comes back.
|
|
520
|
-
*/
|
|
521
|
-
treeFoot?: () => ReactNode;
|
|
522
|
-
/**
|
|
523
|
-
* Two doors out of the inspector's panels, onto wherever the layer keeps what
|
|
524
|
-
* they lead to: a view of its own in the left panel, a panel of its own in
|
|
525
|
-
* the inspector. The screen hands them to the inspector it mounts and does
|
|
526
|
-
* not know where they go. `openSettings` is the way to the settings of the
|
|
527
|
-
* whole document, from a panel that edits one part of it. The inspector
|
|
528
|
-
* cannot do without it, so with no layer it is handed one that leads nowhere.
|
|
529
|
-
*/
|
|
530
|
-
openSettings?: () => void;
|
|
531
|
-
/** …and `openStyles` the way to the styles a part of a block can follow,
|
|
532
|
-
* from that part's own panel. A layer with nowhere to keep them hands none,
|
|
533
|
-
* and the panel draws no door. */
|
|
534
|
-
openStyles?: () => void;
|
|
535
|
-
/**
|
|
536
|
-
* The way to THIS document's own styles — the website's Styles ▸ Basics, the This page group,
|
|
537
|
-
* the email's Styles — from the tree ground's menu (`screen.pageStyles`).
|
|
538
|
-
* The tree keeps no row for the document's settings (Lewis, 2026-10-26:
|
|
539
|
-
* the tree's first row goes), so this is the menu's one door to them. A layer
|
|
540
|
-
* that hands none gets no row.
|
|
541
|
-
*/
|
|
542
|
-
openPageStyles?: () => void;
|
|
543
|
-
/**
|
|
544
|
-
* THE LAYER'S OWN ROWS IN A NODE'S RIGHT-CLICK MENU (0.105.0), by the group
|
|
545
|
-
* each joins (`ScreenMenuRows`): the campaign designer's "Check this image
|
|
546
|
-
* loads" and its phone rows. Asked of the node the menu was opened on, and
|
|
547
|
-
* where it sits, every time the menu is drawn; what comes back is placed at
|
|
548
|
-
* the end of its group, after the screen's own rows, as it is handed — a row
|
|
549
|
-
* that writes runs a component or an op of the layer's that reaches the
|
|
550
|
-
* document itself. Nothing handed back adds nothing. Absent: the screen's
|
|
551
|
-
* rows alone, as the menu has always drawn them.
|
|
552
|
-
*/
|
|
553
|
-
menuRows?: (node: ScreenNode, zone: string, index: number) => ScreenMenuRows | null | undefined;
|
|
554
|
-
/**
|
|
555
|
-
* THE ROW'S OWN ACTIONS ON A DRAWN COPY (card copy typing, 2026-10-30). A
|
|
556
|
-
* card template is drawn once per row of its owner's data, each copy in a
|
|
557
|
-
* `data-sf-repeat` wrapper; the rows are the layer's, never the document's.
|
|
558
|
-
* Given, a right-click on a block in a copy offers, in the node's one menu,
|
|
559
|
-
* Add item after, Move item earlier, Move item later (the way a row cannot
|
|
560
|
-
* go greyed) and Delete item, and a press comes here with the copy's place.
|
|
561
|
-
* Withheld while nothing may be written. Absent: the menu is as before.
|
|
562
|
-
*/
|
|
563
|
-
onCopyItem?: (request: CopyItemRequest) => void;
|
|
564
|
-
/** The layer's own context, stood round the whole screen. What it is handed
|
|
565
|
-
* is the screen; what it returns is rendered in the screen's place. */
|
|
566
|
-
wrap?: (screen: ReactNode) => ReactNode;
|
|
567
|
-
}
|
|
568
|
-
/** The document's half of a shared section (`ScreenPinnedNodes.shared`). */
|
|
569
|
-
interface ScreenSharedSections {
|
|
570
|
-
/** The pages that use this top-level node, this page among them, when it is
|
|
571
|
-
* a shared section; null when it is this page's own, or the header or
|
|
572
|
-
* footer. */
|
|
573
|
-
usedOn: (node: ScreenNode) => readonly SharedSectionUse[] | null;
|
|
574
|
-
/** Open one of those pages (a press in On N pages ▸). */
|
|
575
|
-
openPage: (page: SharedSectionUse) => void;
|
|
576
|
-
/** MAKE SHARED: the store made `section` from `node`. From now on the layer
|
|
577
|
-
* holds `node`, where it stands, as that shared section; the page looks the
|
|
578
|
-
* same, and its row turns green. */
|
|
579
|
-
adopt: (node: ScreenNode, section: SharedSection) => void;
|
|
580
|
-
/** What Add puts on the page for `section` — the node the layer holds as it
|
|
581
|
-
* — or null when it cannot go on this page: it is on it already (once per
|
|
582
|
-
* page). */
|
|
583
|
-
nodeOf: (section: SharedSection) => ScreenNode | null;
|
|
584
|
-
/** DETACH FROM SHARED: this page's own copy of the shared `node`, every id
|
|
585
|
-
* fresh (efficient-easel/data `copyNode`). The screen puts it in the node's
|
|
586
|
-
* place, one undo step, and the layer holds it as the page's own from then
|
|
587
|
-
* on. The other pages keep the shared section. */
|
|
588
|
-
detach: (node: ScreenNode) => ScreenNode;
|
|
589
|
-
/** A shared section was deleted: every page that used it now holds its own
|
|
590
|
-
* copy, this one included, and the layer takes that in. Optional. */
|
|
591
|
-
removed?: (section: SharedSection) => void;
|
|
592
|
-
}
|
|
593
|
-
/** What a press on a drawn copy's item row asks (`ScreenBridges.onCopyItem`). */
|
|
594
|
-
type CopyItemAction = "addAfter" | "moveEarlier" | "moveLater" | "delete";
|
|
595
|
-
/** The copy a row was pressed on, and what to do to its row. */
|
|
596
|
-
interface CopyItemRequest {
|
|
597
|
-
/** The block whose slot is drawn once per row. */
|
|
598
|
-
ownerId: string;
|
|
599
|
-
/** That slot (`template`). */
|
|
600
|
-
slot: string;
|
|
601
|
-
/** The row the copy is drawn for; 0 is the main copy. */
|
|
602
|
-
index: number;
|
|
603
|
-
/** The copy of an outer template this copy's owner is drawn in, when
|
|
604
|
-
* there is one (`RepeatCopy.outer`, `efficient-easel/easel`): the inner
|
|
605
|
-
* index alone names no row. */
|
|
606
|
-
outer?: RepeatCopy;
|
|
607
|
-
action: CopyItemAction;
|
|
608
|
-
}
|
|
609
|
-
/** A layer's own rows in a node's menu, by the group of the menu each goes at
|
|
610
|
-
* the end of (efficient-easel/node-ops `nodeMenuItems`' `extras`): `pick`
|
|
611
|
-
* (Select layer), `make` (Duplicate … Paste), `change` (Rename, Hide …) and
|
|
612
|
-
* `remove` (Delete). */
|
|
613
|
-
type ScreenMenuRows = Partial<Record<"pick" | "make" | "change" | "remove", EaselContextMenuItem[]>>;
|
|
614
|
-
/** A block type's own default props, read off the config the screen holds.
|
|
615
|
-
* The screen's to look up and a layer's to be lent: a layer that reached into
|
|
616
|
-
* the config for itself would be holding a second copy of it. */
|
|
617
|
-
type NodeDefaults = (type: string) => Record<string, unknown>;
|
|
618
|
-
/** What the screen lends a rule that builds a node. All four are the screen's
|
|
619
|
-
* own and none is a block's: the rule states the node, the screen says what a
|
|
620
|
-
* type defaults to, what its next id is, what it is called and whether the
|
|
621
|
-
* host offers it. */
|
|
622
|
-
interface ScreenNodeMaker {
|
|
623
|
-
/** A type's default props, from the config. */
|
|
624
|
-
nodeDefaults: NodeDefaults;
|
|
625
|
-
/** A fresh id for one node of a type. Called once per node, in the order the
|
|
626
|
-
* nodes are written. */
|
|
627
|
-
newNodeId: (type: string) => string;
|
|
628
|
-
/** What a top-level node of a type is called, as the tree and the toast say
|
|
629
|
-
* it. */
|
|
630
|
-
sectionLabel: (type: string) => string;
|
|
631
|
-
/** Does this editor's host offer the type? A rule that would lay down a block
|
|
632
|
-
* the host left out asks first. */
|
|
633
|
-
blockIsOffered: (type: string) => boolean;
|
|
634
|
-
}
|
|
635
|
-
/** A node as a rule hands it back: a type and its props, slot children inline
|
|
636
|
-
* in them. The screen inserts it whole. */
|
|
637
|
-
interface ScreenNewNode {
|
|
638
|
-
type: string;
|
|
639
|
-
props: Record<string, unknown>;
|
|
640
|
-
}
|
|
641
|
-
/** The node a `canAddTo` question is asked of: its id, and the document it is in. */
|
|
642
|
-
interface ScreenNodeAt {
|
|
643
|
-
id: string;
|
|
644
|
-
data: unknown;
|
|
645
|
-
}
|
|
646
|
-
/**
|
|
647
|
-
* The rules of particular blocks, asked by the screen and never stated in it:
|
|
648
|
-
* the screen is handed nodes and is not told which blocks exist. Plain
|
|
649
|
-
* functions of what they are passed, and the same object for the life of a
|
|
650
|
-
* mount, so the screen may call them anywhere without listing them as a
|
|
651
|
-
* dependency.
|
|
652
|
-
*/
|
|
653
|
-
interface ScreenBlockRules {
|
|
654
|
-
/** A block that is what its section IS: it may be selected and edited, and
|
|
655
|
-
* never removed, hidden, duplicated or dragged. `node` is the node itself,
|
|
656
|
-
* where the screen asks of one (every place it does, since 18.1.0): a rule
|
|
657
|
-
* that locks ONE node, not a whole type — a shared section another tab
|
|
658
|
-
* holds (Shared section design v4). A rule that reads the type alone locks
|
|
659
|
-
* by type, as it always did. */
|
|
660
|
-
isLockedBlock: (type: string | undefined, node?: ScreenNode) => boolean;
|
|
661
|
-
/** Why a second one of this node cannot be made in this document, or null —
|
|
662
|
-
* a rule of the block's own. */
|
|
663
|
-
duplicateBlocked: (data: unknown, node: unknown) => string | null;
|
|
664
|
-
/**
|
|
665
|
-
* How many nodes of its own kind the node with `id` already sits inside, for
|
|
666
|
-
* a block that limits its own nesting; 0 for every other. It is the depth the
|
|
667
|
-
* add lookup is asked at, so every surface that adds into one node offers the
|
|
668
|
-
* same list.
|
|
669
|
-
*/
|
|
670
|
-
nestDepth: (data: unknown, type: string, id: string) => number;
|
|
671
|
-
/**
|
|
672
|
-
* What a new top-level section of `type` STARTS AS, when that is more than
|
|
673
|
-
* its own defaults — an arrangement of several blocks, or a prop no default
|
|
674
|
-
* carries — as ONE node for the screen to insert in one step; or null, and
|
|
675
|
-
* the screen inserts the type by itself. Where it goes, selecting it and
|
|
676
|
-
* announcing it stay the screen's.
|
|
677
|
-
*/
|
|
678
|
-
newSectionNode: (type: string, make: ScreenNodeMaker) => ScreenNewNode | null;
|
|
679
|
-
/**
|
|
680
|
-
* What can go in a node of `nodeType`, sitting `nestDepth` nodes of its own
|
|
681
|
-
* kind deep (0 when not said): the slot its children are kept on, and the
|
|
682
|
-
* menu's rows or the one child type a button adds — or null for a node that
|
|
683
|
-
* takes no children. THE ONE ANSWER every add surface of the screen asks (the
|
|
684
|
-
* tree, the panel, the menu, the Add panel), so no two of them can come to
|
|
685
|
-
* offer one node different lists; what each of the layer's blocks takes is
|
|
686
|
-
* the layer's catalogue, and the screen is not told it.
|
|
687
|
-
*
|
|
688
|
-
* `slot` (0.105.0) is asked where the screen means ONE slot of a node that
|
|
689
|
-
* has several: a gap or an empty slot in the tree, a slot place Add was
|
|
690
|
-
* opened at, a drop into a slot. The answer is that slot's (the campaign
|
|
691
|
-
* designer's Column 2 answers `col2`); a layer that keeps one slot per node
|
|
692
|
-
* may ignore it, and the screen then offers that slot alone, as before.
|
|
693
|
-
*
|
|
694
|
-
* `at` (24.2.0) is the ONE node asked of, where the screen means one: its
|
|
695
|
-
* id and the document it is in (Add opened in it, its rows in the tree, a
|
|
696
|
-
* drop or an insert into it). Two nodes of one type may take different
|
|
697
|
-
* children — the campaign designer's Box takes any email block, a Box in a
|
|
698
|
-
* Banner only what the Banner's bake can draw. A layer whose nodes of one
|
|
699
|
-
* type all take the same may ignore it. Absent where the question is about
|
|
700
|
-
* a type, not a node (the Add panel's catalogue).
|
|
701
|
-
*/
|
|
702
|
-
canAddTo: (nodeType: string, nestDepth?: number, slot?: string, at?: ScreenNodeAt) => AddTarget | null;
|
|
703
|
-
/**
|
|
704
|
-
* THE SLOTS OF A NODE, IN ORDER, AS THE SCREEN DRAWS THEM (0.105.0). A slot
|
|
705
|
-
* that is a `rung` is a row of its own in the Layers tree, with its children
|
|
706
|
-
* under it, a level of the Select layer flyout and a place of its own in a
|
|
707
|
-
* drag: the campaign designer's section draws Column 1 and Column 2 so from
|
|
708
|
-
* two columns up, and its lone column not at all. Every other slot's children
|
|
709
|
-
* hang straight off the node's row, as they do today. A slot left out of the
|
|
710
|
-
* answer is not drawn (a column the section's layout hides). The tree, the
|
|
711
|
-
* Add panel's "Adding to …", the drag and the flyout read it; where a node's
|
|
712
|
-
* children are FOUND (the menu, a write, a drop's checks) is still every
|
|
713
|
-
* slot field.
|
|
714
|
-
*
|
|
715
|
-
* Answered for every node the tree draws; null or undefined for one is the
|
|
716
|
-
* screen's own reading of it, so a layer may answer for its sections alone.
|
|
717
|
-
* Absent: every slot field the config declares, in its order, none of them a
|
|
718
|
-
* rung — the tree the website has.
|
|
719
|
-
*/
|
|
720
|
-
slotsOf?: (node: ScreenNode) => ReadonlyArray<ScreenSlot> | null | undefined;
|
|
721
|
-
/**
|
|
722
|
-
* A RUNG MOVED (0.105.0): the rung at `from` in the node's run of rungs (its
|
|
723
|
-
* place among `slotsOf`'s rungs) dropped so it rests at `to` — a drag in the
|
|
724
|
-
* tree, or ⌥↑ / ⌥↓ on its row. The layer writes the move (the campaign
|
|
725
|
-
* designer swaps two columns' blocks, or reorders the phone stack) and may
|
|
726
|
-
* answer the slot to select after it, which the screen selects as a press
|
|
727
|
-
* on that rung's row does. Absent: no rung is picked up.
|
|
728
|
-
*/
|
|
729
|
-
moveSlot?: (nodeId: string, from: number, to: number) => string | null | void;
|
|
730
|
-
/**
|
|
731
|
-
* What a rung's row offers besides its fold (0.105.0): the campaign
|
|
732
|
-
* designer's Duplicate and Delete of a column, drawn in the order handed,
|
|
733
|
-
* among the row's actions. The screen confirms nothing: what a press asks
|
|
734
|
-
* first (Delete a column that still holds blocks) is the layer's `run`.
|
|
735
|
-
* Withheld while the document is read-only. Absent, or nothing handed: the
|
|
736
|
-
* row has none.
|
|
737
|
-
*/
|
|
738
|
-
slotActions?: (node: ScreenNode, slot: string) => ReadonlyArray<ScreenSlotAction> | null | undefined;
|
|
739
|
-
/**
|
|
740
|
-
* Does the host of this editor offer the type? Asked of the editor's own
|
|
741
|
-
* session where the screen holds it, else of the editor on the page. Where
|
|
742
|
-
* no host chose its blocks, every type is.
|
|
743
|
-
*/
|
|
744
|
-
blockIsOffered: (type: string, session?: EaselSession) => boolean;
|
|
745
|
-
/**
|
|
746
|
-
* Is a new block RESOLVED as it goes in (0.103.0)? With true, every insert
|
|
747
|
-
* the screen makes — a section, a block into a slot, a saved template, a
|
|
748
|
-
* seeded slot child — is followed by `easel.resolveNode(id, { trigger:
|
|
749
|
-
* 'insert' })`, as the campaign designer's own inserts are: the block's
|
|
750
|
-
* `resolveData` runs the moment it arrives (seeding its children, stamping a
|
|
751
|
-
* default), in the insert's own undo step, not at its first edit or the next
|
|
752
|
-
* time the document opens. Absent, false: an insert runs no resolver, as
|
|
753
|
-
* the website's never has.
|
|
754
|
-
*/
|
|
755
|
-
resolveOnInsert?: boolean;
|
|
756
|
-
/**
|
|
757
|
-
* CLEAN A COPY (0.106.0): handed every node the screen COPIES into the
|
|
758
|
-
* document — the menu's Duplicate and Paste, ⌘V (a cut block pasted back
|
|
759
|
-
* too), a saved section put in from Add — one node at a time, a copied
|
|
760
|
-
* section's blocks each as well, and it answers the node as the copy should
|
|
761
|
-
* hold it: what only the original may hold taken out. The campaign
|
|
762
|
-
* designer's image block releases the hosted picture it baked (`bakedId`):
|
|
763
|
-
* the next bake deletes the asset that id names, so two blocks holding one
|
|
764
|
-
* would destroy each other's picture. It must keep the node's id (the copy's
|
|
765
|
-
* own, already fresh) and its type. Absent: a copy is its original, prop for
|
|
766
|
-
* prop, but its ids, as before.
|
|
767
|
-
*/
|
|
768
|
-
stripCopy?: (node: ScreenNode) => ScreenNode;
|
|
769
|
-
}
|
|
770
|
-
/**
|
|
771
|
-
* ONE SLOT OF A NODE, as the screen draws it (`ScreenBlockRules.slotsOf`,
|
|
772
|
-
* 0.105.0). Only `slot` and `rung` are read of a slot that is not a rung.
|
|
773
|
-
*/
|
|
774
|
-
interface ScreenSlot {
|
|
775
|
-
/** The slot field's name (`col2`): its children are `props[slot]`, its list
|
|
776
|
-
* is `${nodeId}:${slot}`. */
|
|
777
|
-
slot: string;
|
|
778
|
-
/** What the rung's row says ("Column 2"), and the flyout, and Add's
|
|
779
|
-
* "Adding to …". */
|
|
780
|
-
label: string;
|
|
781
|
-
/** The rung's glyph, drawn as handed. Absent: none. */
|
|
782
|
-
glyph?: ReactNode;
|
|
783
|
-
/** Drawn as a row of its own, its children under it. False: its children
|
|
784
|
-
* hang straight off the node's row. */
|
|
785
|
-
rung: boolean;
|
|
786
|
-
/**
|
|
787
|
-
* The kind of the layer's panel this rung is edited in (the Column
|
|
788
|
-
* inspector): a press on its row selects nothing and shows that panel, as a
|
|
789
|
-
* {@link ScreenSlotMode} naming the node and the slot, and the row is lit
|
|
790
|
-
* while it shows; the flyout lists it as a level. Absent: the rung only
|
|
791
|
-
* folds, its press selects the node it is a slot of, and the flyout leaves
|
|
792
|
-
* it out.
|
|
793
|
-
*/
|
|
794
|
-
panel?: string;
|
|
795
|
-
/** A pill after the name ("2 of 3", the phone stack's place). */
|
|
796
|
-
badge?: ReactNode;
|
|
797
|
-
/** The hint the row shows when it may be dragged. Absent: the tree's own. */
|
|
798
|
-
dragHint?: string;
|
|
799
|
-
/** Drawn above the rung's row, as handed: the campaign designer's "Phone
|
|
800
|
-
* order" label over its first column. */
|
|
801
|
-
heading?: ReactNode;
|
|
802
|
-
/** False: the rung keeps its place, and is not picked up (a pinned
|
|
803
|
-
* section's columns). Absent: it moves where `moveSlot` is handed. */
|
|
804
|
-
movable?: boolean;
|
|
805
|
-
}
|
|
806
|
-
/** What a rung's row offers (`ScreenBlockRules.slotActions`, 0.105.0). */
|
|
807
|
-
interface ScreenSlotAction {
|
|
808
|
-
/** Which action: the screen draws its glyph, and the delete in its red. */
|
|
809
|
-
kind: "duplicate" | "delete";
|
|
810
|
-
/** Its tooltip and accessible name: "Duplicate Column 2", or why not. */
|
|
811
|
-
label: string;
|
|
812
|
-
/** Drawn, and not pressed: the label says why. */
|
|
813
|
-
disabled?: boolean;
|
|
814
|
-
/**
|
|
815
|
-
* The action, the layer's whole: it asks what it must ask first and writes.
|
|
816
|
-
* It may answer the slot to select after it (the copy, the column that took
|
|
817
|
-
* a deleted one's place), which the screen selects as a press on that rung's
|
|
818
|
-
* row does; nothing, and the selection stays.
|
|
819
|
-
*/
|
|
820
|
-
run: () => string | null | void | Promise<string | null | void>;
|
|
821
|
-
}
|
|
822
|
-
/**
|
|
823
|
-
* The slot fields of `node` whose row the panel shows, in the config's order —
|
|
824
|
-
* THE ONE READER of "does a slot follow its row" (plan 2026-10-23 §6.0, "Batch
|
|
825
|
-
* 3 must do" item 2, GG 2026-10-26). A slot field that carries the shell's
|
|
826
|
-
* show-when rule (`./fields` `fieldIsShown`) and reads false for the node's own
|
|
827
|
-
* values is left out: the panel hides that row, so no Layers tree lists blocks
|
|
828
|
-
* the section no longer draws (the Product Grid's hand-picked products once its
|
|
829
|
-
* content is a Category). Nothing is deleted; the blocks come back with the row.
|
|
830
|
-
*
|
|
831
|
-
* Every Layers tree reads it: {@link screenSlotsOf} (the page editor's), the
|
|
832
|
-
* page tree's run with no `slotsOf`, and the one-section editor's. Where a
|
|
833
|
-
* node's children are FOUND — a drop, the address map, dedupe — is still
|
|
834
|
-
* content-tree's `childSlotsOf`, every slot field.
|
|
835
|
-
*/
|
|
836
|
-
declare function shownSlotFieldsOf(config: SlotConfigView, node: ScreenNode): string[];
|
|
837
|
-
/** The children a Layers tree lists under `node`: those of its shown slots
|
|
838
|
-
* ({@link shownSlotFieldsOf}), addressed as `childSlotsOf` addresses them. */
|
|
839
|
-
declare function shownChildSlotsOf(config: SlotConfigView, node: ScreenNode): SlotChild[];
|
|
840
|
-
/**
|
|
841
|
-
* The slots of `node` as the screen draws them: the layer's answer
|
|
842
|
-
* (`slotsOf`), else — with no `slotsOf`, or none for this node — the slots
|
|
843
|
-
* {@link shownSlotFieldsOf} answers, in the config's order, none of them a rung.
|
|
844
|
-
*/
|
|
845
|
-
declare function screenSlotsOf(rules: ScreenBlockRules, config: SlotConfigView, node: ScreenNode): ReadonlyArray<ScreenSlot>;
|
|
846
|
-
/** The tier a node is NAMED at: a node at the top of the document is a section,
|
|
847
|
-
* a node inside another is a block. */
|
|
848
|
-
type ScreenNodeLevel = "section" | "block";
|
|
849
|
-
/**
|
|
850
|
-
* How the layer's blocks are NAMED AND DRAWN in the screen: the tree's rows and
|
|
851
|
-
* the Add panel's tiles put a word, a glyph and a cover on a block, and which
|
|
852
|
-
* word and which drawing is known only to the layer that knows every block it
|
|
853
|
-
* has. The screen is handed a type and asks.
|
|
854
|
-
*
|
|
855
|
-
* The same object for the life of a mount, and its two components the same two
|
|
856
|
-
* functions throughout: the screen renders them as element types, and a type
|
|
857
|
-
* that changed identity would remount every row and tile that wears one.
|
|
858
|
-
*/
|
|
859
|
-
interface ScreenBlockLook {
|
|
860
|
-
/**
|
|
861
|
-
* What a node of `type` is called at a level, given `base` — the label the
|
|
862
|
-
* config holds for the type, which is the name of every node the layer does
|
|
863
|
-
* not name by where it sits.
|
|
864
|
-
*/
|
|
865
|
-
labelAtLevel: (type: string, level: ScreenNodeLevel, base: string) => string;
|
|
866
|
-
/** The Add panel's one-line blurb for a section, by type. A type with none
|
|
867
|
-
* has no entry. */
|
|
868
|
-
descriptions: Record<string, string>;
|
|
869
|
-
/** The Add panel's short heading for a group of sections, by the group's
|
|
870
|
-
* key, where the layer has one; undefined, and the registry's own title for
|
|
871
|
-
* the group is its heading. */
|
|
872
|
-
categoryLabel: (id: string) => string | undefined;
|
|
873
|
-
/** The blank section: the Add panel offers it first in its own group, with
|
|
874
|
-
* the ungrouped blocks after it, and the blocks it takes (and they take)
|
|
875
|
-
* are the blocks Add offers beyond the catalogue (11.0.0). Null: every
|
|
876
|
-
* section stands in its group in the catalogue's order, and the blocks are
|
|
877
|
-
* what every section takes. */
|
|
878
|
-
firstSection: string | null;
|
|
879
|
-
/**
|
|
880
|
-
* What the row of a block says when the block is named by its own content
|
|
881
|
-
* and not by the slot-child rule (lib/document/slot-child-name): the layer reads
|
|
882
|
-
* the content, and `compLabel` — the config's label for a type, lent by the
|
|
883
|
-
* screen — is the word for a block it has no rule for.
|
|
884
|
-
*/
|
|
885
|
-
blockRowName: (child: {
|
|
886
|
-
type: string;
|
|
887
|
-
props: Record<string, unknown>;
|
|
888
|
-
}, compLabel: (type: string) => string) => string;
|
|
889
|
-
/**
|
|
890
|
-
* The plain words of a block's stored copy, every mark of the layer's markup
|
|
891
|
-
* unwrapped: what a tree row prints of a name the author typed, where no mark
|
|
892
|
-
* can be drawn (lib/document/slot-child-name `slotChildRowName`). Which marks
|
|
893
|
-
* there are is the layer's grammar — a website's is not an email's.
|
|
894
|
-
*/
|
|
895
|
-
plainText: (copy: string) => string;
|
|
896
|
-
/** The glyph of a block or section type, as a tree row and a block tile wear
|
|
897
|
-
* it. */
|
|
898
|
-
Icon: ComponentType<{
|
|
899
|
-
type: string;
|
|
900
|
-
size?: number;
|
|
901
|
-
className?: string;
|
|
902
|
-
}>;
|
|
903
|
-
/** The cover picture of a section type, filling the Add panel's card — or
|
|
904
|
-
* of a preset row, asked with the preset's key (`presets`). */
|
|
905
|
-
Thumbnail: ComponentType<{
|
|
906
|
-
type: string;
|
|
907
|
-
}>;
|
|
908
|
-
/**
|
|
909
|
-
* ADD ROWS THAT ARE PRESETS, NOT BLOCK TYPES (GG ruling 2026-10-30, owner
|
|
910
|
-
* item C36): each with its own key, label, group, blurb and cover, and an
|
|
911
|
-
* `insert` that builds the node it lays down, in one step. Searched,
|
|
912
|
-
* pressed after a ➕ and dragged like a section's row; it goes in the page's
|
|
913
|
-
* own list only. Absent: every row is a block type, as before
|
|
914
|
-
* (lib/document/palette-sections `PalettePreset`).
|
|
915
|
-
*/
|
|
916
|
-
presets?: readonly PalettePreset[];
|
|
917
|
-
/**
|
|
918
|
-
* The products a row may be named after when its block holds only a
|
|
919
|
-
* product's handle: null until they arrive, and for good when there are
|
|
920
|
-
* none. A HOOK — the one member here that is — called once per render where
|
|
921
|
-
* the screen read the products itself, so its effect keeps its place.
|
|
922
|
-
*/
|
|
923
|
-
useProducts: () => readonly HostProduct[] | null;
|
|
924
|
-
/**
|
|
925
|
-
* THE LAYER'S LAST WORD ON WHAT A LAYERS ROW SAYS (0.103.0): handed a node,
|
|
926
|
-
* the level it is named at and `fallback` — what the screen's own naming
|
|
927
|
-
* rule answered (lib/document/slot-child-name: a name the node carries, else its
|
|
928
|
-
* type's label; a pinned row's word) — it answers the row's name. Asked of
|
|
929
|
-
* every node row the page screen's Layers tree draws, and of the menu's
|
|
930
|
-
* Select layer flyout, a block's canvas handle and a section's own list of
|
|
931
|
-
* its children in the inspector, which say the same words. The campaign
|
|
932
|
-
* designer's rows read its own labels ("Section 2", "Header"). Absent: the
|
|
933
|
-
* screen's rule, as it named every row.
|
|
934
|
-
*/
|
|
935
|
-
rowName?: (node: ScreenNode, level: ScreenNodeLevel, fallback: string) => string;
|
|
936
|
-
/**
|
|
937
|
-
* THE PROP A RENAME WRITES, by the layer (0.105.0; owner ruling R11, Victor
|
|
938
|
-
* Mau, 2026-10-09: Rename works on top-level sections in both editors). The
|
|
939
|
-
* write side of `rowName`: handed a node, the level it is named at and
|
|
940
|
-
* `base` — what the screen's own rule answered (lib/document/slot-child-name
|
|
941
|
-
* `slotChildRenameProp` for a block, `sectionRenameProp` for a section) — it
|
|
942
|
-
* answers the prop the Layers row's rename box writes, or null for a node
|
|
943
|
-
* that has no name of its own, which takes Rename out of its menu. Answer the
|
|
944
|
-
* prop `rowName` reads, so a renamed row says its new name: the campaign
|
|
945
|
-
* designer's sections are named by their `label` ("Section name"). Asked of
|
|
946
|
-
* every node the menu opens on, a pinned node and a section group's too.
|
|
947
|
-
* Absent: the screen's rule — a block's declared name, and a section's
|
|
948
|
-
* `name`, which its row reads.
|
|
949
|
-
*/
|
|
950
|
-
renamePropOf?: (node: ScreenNode, level: ScreenNodeLevel, base: string | null) => string | null;
|
|
951
|
-
/**
|
|
952
|
-
* The quieter words a node row draws after its name (`TreeRow`'s
|
|
953
|
-
* `preview`): a node's own first words, so a tree of rows all called
|
|
954
|
-
* "Section" can be told apart by eye. The layer chooses and shortens them;
|
|
955
|
-
* nothing (null, undefined, "") draws nothing. Absent: no row has any.
|
|
956
|
-
*/
|
|
957
|
-
rowPreview?: (node: ScreenNode) => string | null | undefined;
|
|
958
|
-
/**
|
|
959
|
-
* The small marks a node row draws right after its name (`TreeRow`'s
|
|
960
|
-
* `marks`): a state the row only SHOWS, such as "Shown on phones only".
|
|
961
|
-
* Absent, or nothing handed back: no marks.
|
|
962
|
-
*/
|
|
963
|
-
rowMarks?: (node: ScreenNode) => ReadonlyArray<TreeRowMark> | null | undefined;
|
|
964
|
-
/**
|
|
965
|
-
* The layer's own buttons on a node row, by the node and where it sits:
|
|
966
|
-
* `TreeRowAction`s (efficient-easel/tree), placed between the screen's trash
|
|
967
|
-
* and its eye — the campaign designer's phone switch. Asked of every node
|
|
968
|
-
* row, a locked one and a pinned one too, so the layer decides; what comes
|
|
969
|
-
* back is placed as it is, and nothing draws nothing. A button that writes
|
|
970
|
-
* renders a component of the layer's that reaches the document itself.
|
|
971
|
-
* Absent: the screen's two, as it drew them.
|
|
972
|
-
*/
|
|
973
|
-
rowActions?: (node: ScreenNode, zone: string, index: number) => ReactNode;
|
|
974
|
-
}
|
|
975
|
-
/**
|
|
976
|
-
* THE DEVICES the canvas can be looked at on. That the top bar has a switch,
|
|
977
|
-
* and that the canvas is fitted to the pane and framed, is the screen's: any
|
|
978
|
-
* editor's canvas is looked at on more than one. WHICH devices there are, what
|
|
979
|
-
* each is called and how wide it is drawn is the layer's — a website has three
|
|
980
|
-
* view tiers where an email has two.
|
|
981
|
-
*
|
|
982
|
-
* The same object for the life of a mount: the screen reads the device it
|
|
983
|
-
* starts on from it once, and draws the switch from it on every render.
|
|
984
|
-
*/
|
|
985
|
-
interface ScreenDevices {
|
|
986
|
-
/** What the switch offers, in the order it draws them: an id, a name and a
|
|
987
|
-
* glyph each (efficient-easel/chrome `DeviceSwitch`). */
|
|
988
|
-
options: ReadonlyArray<DeviceOption>;
|
|
989
|
-
/** The device a mount starts on. */
|
|
990
|
-
initial: string;
|
|
991
|
-
/**
|
|
992
|
-
* The ONE device with no width of its own: the canvas draws it at the
|
|
993
|
-
* pane's width, so it reflows as the pane is dragged, where every other is
|
|
994
|
-
* a fixed width scaled to fit the pane. Its frame is the plain one; every
|
|
995
|
-
* other device's wears a class named for its id.
|
|
996
|
-
*/
|
|
997
|
-
fluid: string;
|
|
998
|
-
/** The width each device is drawn at, in CSS px, by id. For `fluid` it is
|
|
999
|
-
* only the width of the frame before the pane has been measured. */
|
|
1000
|
-
widths: Readonly<Record<string, number>>;
|
|
1001
|
-
/**
|
|
1002
|
-
* How a fixed device is fitted to the pane (0.105.0). `"fill"`: scaled to
|
|
1003
|
-
* the pane's width, up to twice its size, so a phone reads big and clear in
|
|
1004
|
-
* a wide pane — the website's view tiers. `"shrink"`: scaled DOWN when the
|
|
1005
|
-
* pane is narrower than the device and never up, so a device is drawn at its
|
|
1006
|
-
* real size or smaller — the campaign designer's phone, a mail preview of
|
|
1007
|
-
* the width the recipient's phone has. The fluid device is drawn at the
|
|
1008
|
-
* pane's width either way. Absent: `"fill"`.
|
|
1009
|
-
*/
|
|
1010
|
-
fit?: "fill" | "shrink";
|
|
1011
|
-
}
|
|
1012
|
-
/**
|
|
1013
|
-
* WHAT A DRAG ON THE PAGE SCREEN CARRIES (0.105.0): a node of the document —
|
|
1014
|
-
* its id, the list it sits in (a zone key, `<parentId>:<slot>`), its index
|
|
1015
|
-
* there and its type — or, with `add`, a NEW one from the Add panel, which
|
|
1016
|
-
* has no place yet. One kind of thing for the ONE drag the Layers tree, the
|
|
1017
|
-
* canvas and the Add panel share, so a block picked up on one lands on
|
|
1018
|
-
* another. A layer's own canvas sources (`ScreenCanvasDrag.model`) carry it
|
|
1019
|
-
* too; a thing of the layer's that is not a node (the campaign designer's
|
|
1020
|
-
* column) is told apart by a `zone` and a `type` of the layer's own — a list
|
|
1021
|
-
* the document has none of, so the screen's writes find no node there and
|
|
1022
|
-
* do nothing, and the Layers tree, which draws no gap in it, takes none. A
|
|
1023
|
-
* layer that offers one answers for it on the canvas (`canDrop`, `drop`,
|
|
1024
|
-
* `pick`).
|
|
1025
|
-
*/
|
|
1026
|
-
interface ScreenDragItem {
|
|
1027
|
-
id: string;
|
|
1028
|
-
zone: string;
|
|
1029
|
-
index: number;
|
|
1030
|
-
type: string;
|
|
1031
|
-
add?: AddKey;
|
|
1032
|
-
/** A slot the Layers tree draws as a row of its own (`slotsOf`, a rung),
|
|
1033
|
-
* picked up by its row: `index` is its place in its node's run of rungs. */
|
|
1034
|
-
rung?: {
|
|
1035
|
-
nodeId: string;
|
|
1036
|
-
slot: string;
|
|
1037
|
-
};
|
|
1038
|
-
/** A file carried out of the host's media popup (`ScreenCanvasDrag.media`):
|
|
1039
|
-
* `add` is what it becomes between things, and a drop on a thing that
|
|
1040
|
-
* takes it puts it there instead. */
|
|
1041
|
-
media?: true;
|
|
1042
|
-
}
|
|
1043
|
-
/** A file from the host's media library, dropped on the canvas (harness
|
|
1044
|
-
* UI-20, 2026-10-23), as the host's pick path gave it back (`MediaPlace`):
|
|
1045
|
-
* `url` is what draws. */
|
|
1046
|
-
interface ScreenMediaFile {
|
|
1047
|
-
id: string;
|
|
1048
|
-
url: string;
|
|
1049
|
-
kind: "image" | "video";
|
|
1050
|
-
name: string;
|
|
1051
|
-
}
|
|
1052
|
-
/**
|
|
1053
|
-
* A FILE FROM THE MEDIA POPUP, DROPPED ON THE CANVAS (`ScreenCanvasDrag.media`,
|
|
1054
|
-
* harness UI-20, owner decision Lewis 2026-10-23). The drag is the screen's:
|
|
1055
|
-
* it hears a file carried out of the host's popup, offers the places a new
|
|
1056
|
-
* picture may go — the lines Add's tiles get — and outlines a thing the file
|
|
1057
|
-
* may land ON. What a picture IS in this document is the layer's; what the
|
|
1058
|
-
* file becomes in the host first is the host's (`MediaPanelProvider` `place`,
|
|
1059
|
-
* its pick path: a website copies in a file another website holds).
|
|
1060
|
-
*/
|
|
1061
|
-
interface ScreenMediaDrop {
|
|
1062
|
-
/** What a file dropped BETWEEN things becomes: Add's entry for the layer's
|
|
1063
|
-
* picture block, offered at exactly the places Add would offer it. */
|
|
1064
|
-
adds: {
|
|
1065
|
-
kind: "section" | "block";
|
|
1066
|
-
type: string;
|
|
1067
|
-
};
|
|
1068
|
-
/** May a file land ON this node, its picture replaced by it? */
|
|
1069
|
-
takes: (node: ScreenNode) => boolean;
|
|
1070
|
-
/** The node's props with the file as its picture. */
|
|
1071
|
-
replace: (node: ScreenNode, file: ScreenMediaFile) => Record<string, unknown>;
|
|
1072
|
-
/** A new node of `adds` holding the file, for a drop between things, made
|
|
1073
|
-
* with what the screen lends a rule that builds a node (its defaults, its
|
|
1074
|
-
* ids). */
|
|
1075
|
-
create: (file: ScreenMediaFile, maker: ScreenNodeMaker) => ScreenNode;
|
|
1076
|
-
}
|
|
1077
|
-
/**
|
|
1078
|
-
* What the screen tells a layer's canvas drag each time it asks
|
|
1079
|
-
* (`ScreenCanvasDrag`, 0.105.0). Its rules are plain functions, the same for
|
|
1080
|
-
* the life of the mount like the block rules, so what they reason about is
|
|
1081
|
-
* handed to them: the document as it stands, the device the canvas is drawn
|
|
1082
|
-
* as, and — for a drop or a pick that does what the screen's own would not —
|
|
1083
|
-
* the screen's writes and its inspector.
|
|
1084
|
-
*/
|
|
1085
|
-
interface ScreenCanvasDragContext {
|
|
1086
|
-
/** The working document (`{ root, content, zones }`), as the store holds it
|
|
1087
|
-
* now: what the measure and the model are of. */
|
|
1088
|
-
data: unknown;
|
|
1089
|
-
/** The device the canvas is drawn as, one of the layer's own
|
|
1090
|
-
* (`ScreenDevices.options`): a phone may stack what a desktop lays across. */
|
|
1091
|
-
device: string;
|
|
1092
|
-
/** The screen's writes (`ScreenDocumentOps`, refused while somebody else
|
|
1093
|
-
* holds the document), for a drop of the layer's own. */
|
|
1094
|
-
ops: ScreenDocumentOps;
|
|
1095
|
-
/** The inspector, for a drop or a pick that opens a panel of the layer's
|
|
1096
|
-
* own on what it moved or named (a column's). */
|
|
1097
|
-
inspector: ScreenInspector;
|
|
1098
|
-
}
|
|
1099
|
-
/**
|
|
1100
|
-
* THE CANVAS DRAG, AS A LAYER HAS IT (`ScreenParts.canvasDrag`, 0.105.0).
|
|
1101
|
-
* That there is a drag on the canvas — the handle on the smallest box under
|
|
1102
|
-
* the pointer, the one drop line, the catch surface, the session it shares
|
|
1103
|
-
* with the Layers tree and the Add panel — is the screen's
|
|
1104
|
-
* (efficient-easel/drag `CanvasDragLayer`). How the canvas is MEASURED, what
|
|
1105
|
-
* may be picked up on it and what may land where on it may be the layer's: an
|
|
1106
|
-
* email lays its sections out in columns, measured from cells of its own, and
|
|
1107
|
-
* a column is grabbed by a strip down its edge that is the column's and not its
|
|
1108
|
-
* blocks'.
|
|
1109
|
-
*
|
|
1110
|
-
* Each member is optional and falls back on the screen's own; each is handed
|
|
1111
|
-
* the screen's own answer (`base`) as well, so a layer may add to it, narrow it
|
|
1112
|
-
* or answer only for what is its own and leave the rest to the screen. They
|
|
1113
|
-
* answer for the canvas only: a drop on the Layers tree is the tree's rules',
|
|
1114
|
-
* whatever surface the thing was picked up on.
|
|
1115
|
-
*
|
|
1116
|
-
* Plain functions, the same object for the life of the mount, like the block
|
|
1117
|
-
* rules; what they reason about is handed to them (`ScreenCanvasDragContext`).
|
|
1118
|
-
*/
|
|
1119
|
-
interface ScreenCanvasDrag {
|
|
1120
|
-
/** How the canvas is measured into boxes, in the coordinates of `layer`
|
|
1121
|
-
* (the element the drag layer draws in). Absent: the old library's markers, the slots
|
|
1122
|
-
* and the blocks directly in them (efficient-easel/drag `measureCanvas`). */
|
|
1123
|
-
measure?: (canvas: CanvasTarget, layer: Element, context: ScreenCanvasDragContext) => MeasuredCanvas;
|
|
1124
|
-
/**
|
|
1125
|
-
* What may be picked up on what was measured, and which lists take drops,
|
|
1126
|
-
* handed the screen's own model of it (`base`: every node but the pinned
|
|
1127
|
-
* ones — asked through `isPinnedFirst` / `isPinnedLast` — a locked block, a
|
|
1128
|
-
* group of sections, and a section with nothing to trade places with). It
|
|
1129
|
-
* is asked of an EMPTY measure too, before the frame is first measured.
|
|
1130
|
-
* Absent: `base`.
|
|
1131
|
-
*/
|
|
1132
|
-
model?: (measured: MeasuredCanvas, base: CanvasDragModel<ScreenDragItem>, context: ScreenCanvasDragContext) => CanvasDragModel<ScreenDragItem>;
|
|
1133
|
-
/** May the thing in hand land at `to` on the canvas? Handed the screen's
|
|
1134
|
-
* own rule (`base`, the Layers tree's). Absent: `base`. */
|
|
1135
|
-
canDrop?: (item: ScreenDragItem, to: Place, base: (item: ScreenDragItem, to: Place) => boolean, context: ScreenCanvasDragContext) => boolean;
|
|
1136
|
-
/** Land it, at a place `canDrop` said yes to. Handed the screen's own write
|
|
1137
|
-
* (`base`, the tree's: a section moved, a block moved, a new one added).
|
|
1138
|
-
* Absent: `base`. */
|
|
1139
|
-
drop?: (item: ScreenDragItem, to: Place, base: (item: ScreenDragItem, to: Place) => void, context: ScreenCanvasDragContext) => void;
|
|
1140
|
-
/** A handle CLICKED, not dragged: select what it names. Handed the screen's
|
|
1141
|
-
* own (`base`: the node, as a press on its row selects it). Absent: `base`. */
|
|
1142
|
-
pick?: (item: ScreenDragItem, base: (item: ScreenDragItem) => void, context: ScreenCanvasDragContext) => void;
|
|
1143
|
-
/** A file carried out of the host's media popup lands on the canvas
|
|
1144
|
-
* (`ScreenMediaDrop`). Absent: the canvas takes no such file. */
|
|
1145
|
-
media?: ScreenMediaDrop;
|
|
1146
|
-
}
|
|
1147
|
-
/** What a layer's head over the canvas is handed (`ScreenParts.CanvasHead`,
|
|
1148
|
-
* 0.105.0): the device the canvas is drawn as, so it can say what is the
|
|
1149
|
-
* device's (the campaign designer's mail-app switch is desktop's only). */
|
|
1150
|
-
interface ScreenCanvasHeadProps {
|
|
1151
|
-
device: string;
|
|
1152
|
-
}
|
|
1153
|
-
/**
|
|
1154
|
-
* WHAT IS PINNED in the document's top-level list. That the list has a BAND
|
|
1155
|
-
* its sections keep to — one node pinned ahead of it at most, and one behind —
|
|
1156
|
-
* is the screen's: where a new section lands, where a dragged one may be put
|
|
1157
|
-
* down, which nodes the canvas offers a handle on and what the menu withholds
|
|
1158
|
-
* are all read off that band, and the arithmetic of it is written once, in the
|
|
1159
|
-
* screen. WHICH types are pinned is the layer's: a website pins its Header
|
|
1160
|
-
* first and its Footer last, where an email pins nothing.
|
|
1161
|
-
*
|
|
1162
|
-
* And the layer's GROUPS OF SECTIONS, if it has them: a pinned top-level node
|
|
1163
|
-
* whose one list holds ordinary sections, which move among the groups' lists
|
|
1164
|
-
* and nowhere else. The screen draws a group's row and keeps its sections to
|
|
1165
|
-
* those lists; which types are groups, and what a group's list is keyed by,
|
|
1166
|
-
* it asks.
|
|
1167
|
-
*
|
|
1168
|
-
* And THE PANEL A PINNED NODE IS EDITED IN, where that is not the selection's
|
|
1169
|
-
* own: a node the layer pins may carry no fields, the layer keeping its
|
|
1170
|
-
* settings and showing them in a panel of the layer's. Which node, and which
|
|
1171
|
-
* panel, is the layer's to say; the screen asks by type where a node is
|
|
1172
|
-
* selected and where a pinned node's row is pressed, and shows what it is
|
|
1173
|
-
* handed.
|
|
1174
|
-
*
|
|
1175
|
-
* And HOW THE LAYERS TREE FRAMES THEM (0.103.0): which node is pinned where it
|
|
1176
|
-
* is not one type (`isFirst`, `isLast` — the campaign designer's Header and
|
|
1177
|
-
* Footer are both sections, told apart by a prop), how the first one's row is
|
|
1178
|
-
* drawn (`firstRow`) and what the band of sections between them looks like
|
|
1179
|
-
* (`band`). Each is optional, and its default is the tree the website has.
|
|
1180
|
-
*
|
|
1181
|
-
* The same object for the life of a mount, its functions plain functions of
|
|
1182
|
-
* what they are passed: the screen reads it anywhere, inside the callbacks and
|
|
1183
|
-
* effects it does not rebuild for it.
|
|
1184
|
-
*/
|
|
1185
|
-
interface ScreenPinnedNodes {
|
|
1186
|
-
/** The type of the node pinned FIRST: the band starts after it. Null when
|
|
1187
|
-
* the layer pins none. */
|
|
1188
|
-
first: string | null;
|
|
1189
|
-
/** The type of the node pinned LAST: the band ends at it. */
|
|
1190
|
-
last: string | null;
|
|
1191
|
-
/**
|
|
1192
|
-
* Is this top-level node the one pinned first (0.103.0)? Where every node
|
|
1193
|
-
* of the pinned type is not pinned — the campaign designer's Header is an
|
|
1194
|
-
* `EmailSection` with `_region: "header"`, beside body sections of the same
|
|
1195
|
-
* type — the layer says which. The page screen asks it wherever it tested
|
|
1196
|
-
* a node against `first`: the band, the tree, the canvas handles, the menu.
|
|
1197
|
-
* (The section screen, which holds one node, still asks the type.) The
|
|
1198
|
-
* first node that answers yes is the one. Absent: a node of type `first`.
|
|
1199
|
-
*/
|
|
1200
|
-
isFirst?: (node: ScreenNode) => boolean;
|
|
1201
|
-
/** …and the one pinned last (the Footer). Absent: a node of type `last`. */
|
|
1202
|
-
isLast?: (node: ScreenNode) => boolean;
|
|
1203
|
-
/**
|
|
1204
|
-
* May a block cross into and out of the node pinned LAST (0.106.0) — dragged
|
|
1205
|
-
* in the Layers tree or on the canvas, or pasted? Absent or false, the
|
|
1206
|
-
* website's Footer: its blocks reorder within their own slot and nothing
|
|
1207
|
-
* from the page's sections lands in it, nor leaves it. True, the campaign
|
|
1208
|
-
* designer's Footer, a section whose columns hold any block: its slots are
|
|
1209
|
-
* lists like every other's, asked what they take (the slot's own list, the
|
|
1210
|
-
* depth, never into itself). The node itself stays pinned either way.
|
|
1211
|
-
*/
|
|
1212
|
-
lastIsOpen?: boolean;
|
|
1213
|
-
/**
|
|
1214
|
-
* How the Layers tree draws the node pinned first (0.103.0). `"panel"`: a
|
|
1215
|
-
* row of its own that opens the layer's panel for it (`panelOf`), drawn
|
|
1216
|
-
* whether or not the document holds the node, and none of its children —
|
|
1217
|
-
* the website's Header, whose settings are a panel. `"node"`: the node
|
|
1218
|
-
* itself, selected by its row and folding open into its children, exactly
|
|
1219
|
-
* as the node pinned last is drawn — the campaign designer's Header, a
|
|
1220
|
-
* section with blocks in it. Absent: `"panel"`.
|
|
1221
|
-
*/
|
|
1222
|
-
firstRow?: "panel" | "node";
|
|
1223
|
-
/** What the band of sections between the two pins looks like in the tree
|
|
1224
|
-
* (0.103.0). Absent: a group label in the screen's words, the sections at
|
|
1225
|
-
* the tree's own depth, and no row after them. */
|
|
1226
|
-
band?: ScreenPinnedBand;
|
|
1227
|
-
/**
|
|
1228
|
-
* HEADER AND FOOTER EDITED IN PLACE (8.2.0, owner 2026-10-15). The words of
|
|
1229
|
-
* the canvas TAB on a pinned node — "Header · on every page" — or null for
|
|
1230
|
-
* a node that has none. Asked of each node pinned first or last and of each
|
|
1231
|
-
* group of sections. The screen draws the tab on the band's top edge while
|
|
1232
|
-
* the pointer is anywhere in it or anything in it is selected, at its true
|
|
1233
|
-
* size whatever the device is scaled by, kept inside the canvas when the
|
|
1234
|
-
* band starts above it; a click on the tab selects the band. Handing it
|
|
1235
|
-
* also makes a group of sections NO STEP of the canvas's click-through
|
|
1236
|
-
* chain: a click inside walks from the group's sections in, as on the page.
|
|
1237
|
-
* Absent: no tab, and the click chain as it was.
|
|
1238
|
-
*/
|
|
1239
|
-
groupTab?: (node: ScreenNode) => string | null;
|
|
1240
|
-
/**
|
|
1241
|
-
* …the badge on the Layers row of each pinned node and group ("Every
|
|
1242
|
-
* page"). Handing it draws the in-place tree: the header and footer are
|
|
1243
|
-
* their own rows, with no "Header" / "Footer" group labels over them, and
|
|
1244
|
-
* no row that opens the footer somewhere else. Hidden while the left panel
|
|
1245
|
-
* is narrower than 240px, where the name needs the room. Absent: the tree
|
|
1246
|
-
* as it was.
|
|
1247
|
-
*/
|
|
1248
|
-
groupBadge?: string;
|
|
1249
|
-
/**
|
|
1250
|
-
* SHARED, AND HOW FAR (Shared section design v4, Lewis 2026-10-21): how far
|
|
1251
|
-
* a top-level node reaches when many pages use it live — "On every page",
|
|
1252
|
-
* "On 3 pages" — or null for a node that is this page's own. Asked of each
|
|
1253
|
-
* top-level node, the header and footer and their groups included. For a
|
|
1254
|
-
* node it answers, the screen draws ONE look, green with the shell's
|
|
1255
|
-
* `shared` mark, colour never alone:
|
|
1256
|
-
* · its Layers row in the shell's shared tone, the mark at the row's end
|
|
1257
|
-
* and these words in the mark's Tooltip — in place of `groupBadge`;
|
|
1258
|
-
* · its canvas tab, while it or anything in it is selected or under the
|
|
1259
|
-
* pointer: the green badge with the mark and the row's name, these words
|
|
1260
|
-
* in the tab's Tooltip — in place of `groupTab`'s words;
|
|
1261
|
-
* · its selected and hover outline on the canvas in green
|
|
1262
|
-
* (`CanvasSharedContext`).
|
|
1263
|
-
* `groupTab` and `groupBadge` still say what they switch (the in-place tree,
|
|
1264
|
-
* the click chain). Absent: nothing is shared, and the screen is as it was.
|
|
1265
|
-
*/
|
|
1266
|
-
sharedReach?: (node: ScreenNode) => string | null;
|
|
1267
|
-
/**
|
|
1268
|
-
* …and the DOCUMENT'S HALF of a shared section (Shared section design v4,
|
|
1269
|
-
* Lewis 2026-10-21): the layer holds which top-level nodes are shared
|
|
1270
|
-
* sections, and how a page's document stores them (a reference in its top
|
|
1271
|
-
* level, the section in a document of its own). The screen draws the rows
|
|
1272
|
-
* and asks the store (lib/shared-sections); what changes in the document is
|
|
1273
|
-
* asked here. Handed with a store (`SessionBackend.sharedSections`), the
|
|
1274
|
-
* screen offers:
|
|
1275
|
-
* · a page's own section's menu: Make shared — a name asked in a dialog,
|
|
1276
|
-
* the store makes the shared section, `adopt` takes the node in;
|
|
1277
|
-
* · a shared section's menu: On N pages ▸ (`usedOn`, a press `openPage`),
|
|
1278
|
-
* Detach from shared (`detach`), and Remove from this page in place of
|
|
1279
|
-
* Delete, its Layers trash saying so too;
|
|
1280
|
-
* · Add's "Shared sections" group above "Your templates": a card puts
|
|
1281
|
-
* `nodeOf` on the page (a reference, never a copy), and the card's menu
|
|
1282
|
-
* deletes the shared section (`removed`).
|
|
1283
|
-
* Absent: none of these. The header and footer are shared (`sharedReach`)
|
|
1284
|
-
* but answer `usedOn` with null: they keep the menu they have.
|
|
1285
|
-
*/
|
|
1286
|
-
shared?: ScreenSharedSections;
|
|
1287
|
-
/**
|
|
1288
|
-
* …what the screen says ONCE per editing session (the easel session), the
|
|
1289
|
-
* first time an edit changes a pinned node or a group of sections: the
|
|
1290
|
-
* shell's toast, with Undo ("Changed on every page"). A seed, a load or an
|
|
1291
|
-
* undo says nothing. Absent: nothing is said.
|
|
1292
|
-
*/
|
|
1293
|
-
changeNotice?: string;
|
|
1294
|
-
/**
|
|
1295
|
-
* WHAT A GROUP OF SECTIONS TAKES (8.3.0): may a section of `sectionType` go
|
|
1296
|
-
* into a group of `groupType` that holds `countNow` sections BEFORE it goes
|
|
1297
|
-
* in? Asked of every way a section arrives in a group: a new one from Add (a
|
|
1298
|
-
* click on a tile, a drag of one, and which tiles Add shows), a section dragged
|
|
1299
|
-
* there from the other group, and a paste. A section moved within its own group
|
|
1300
|
-
* is not asked: nothing arrives. The website's header takes up to 3 light
|
|
1301
|
-
* sections and its footer up to 6. Absent: a group takes any section, as before.
|
|
1302
|
-
*/
|
|
1303
|
-
groupAccepts?: (groupType: string, sectionType: string, countNow: number) => boolean;
|
|
1304
|
-
/** The type of the group of sections pinned first, ahead of everything. */
|
|
1305
|
-
firstGroup: string | null;
|
|
1306
|
-
/** …and of the one pinned last. */
|
|
1307
|
-
lastGroup: string | null;
|
|
1308
|
-
/** Is a node of this type a group of sections? */
|
|
1309
|
-
isSectionGroup: (type: string | undefined) => boolean;
|
|
1310
|
-
/** The key of the list a group keeps its sections in, by the group's id. */
|
|
1311
|
-
sectionGroupZone: (groupId: string) => string;
|
|
1312
|
-
/**
|
|
1313
|
-
* The panel of the layer's own that a node of this type is edited in, or
|
|
1314
|
-
* null: the node is edited by its own fields, in the selection's own panel
|
|
1315
|
-
* (`SELECTION_MODE`). What comes back is what the screen stores, so it is
|
|
1316
|
-
* the SAME object every time the same type is asked about. Asked with no
|
|
1317
|
-
* type where nothing is selected, and answered null.
|
|
1318
|
-
*/
|
|
1319
|
-
panelOf: (type: string | null | undefined) => ScreenInspectorMode | null;
|
|
1320
|
-
}
|
|
1321
|
-
/**
|
|
1322
|
-
* THE BAND, AS THE LAYERS TREE FRAMES IT (`ScreenPinnedNodes.band`, 0.103.0):
|
|
1323
|
-
* the sections between the two pins. Where the band starts and ends is the
|
|
1324
|
-
* screen's arithmetic either way; this is only how it is drawn.
|
|
1325
|
-
*/
|
|
1326
|
-
interface ScreenPinnedBand {
|
|
1327
|
-
/** What the band is called. Absent: the screen's words, `screen.pageSections`
|
|
1328
|
-
* ("Page") on a document with the edit guard and
|
|
1329
|
-
* `screen.templateSections` ("Template") on one without. */
|
|
1330
|
-
label?: string;
|
|
1331
|
-
/** The band is a ROW that folds, its sections under it — the campaign
|
|
1332
|
-
* designer's Body. Absent or false: a group label over the sections, which
|
|
1333
|
-
* sit at the tree's own depth. */
|
|
1334
|
-
foldable?: boolean;
|
|
1335
|
-
}
|
|
1336
|
-
/** Is `node` the one the layer pins FIRST — its own test (`isFirst`), else a
|
|
1337
|
-
* node of the `first` type, the test the screen has always made. */
|
|
1338
|
-
declare function isPinnedFirst(pinned: ScreenPinnedNodes, node: ScreenNode): boolean;
|
|
1339
|
-
/** …and LAST (`isLast`, else a node of the `last` type). */
|
|
1340
|
-
declare function isPinnedLast(pinned: ScreenPinnedNodes, node: ScreenNode): boolean;
|
|
1341
|
-
/**
|
|
1342
|
-
* THE VIEW THE LEFT PANEL IS ON, from one mount to the next. That the panel
|
|
1343
|
-
* has views, that one of them is current and that the choice is kept is the
|
|
1344
|
-
* screen's: it holds the view in state and mirrors it from ONE effect, the
|
|
1345
|
-
* only writer. WHERE it is kept, which view a first mount opens on and what a
|
|
1346
|
-
* selection does to it are the layer's — a website opens on its page list,
|
|
1347
|
-
* and keeps the choice under a key of its own.
|
|
1348
|
-
*
|
|
1349
|
-
* The same object for the life of a mount: the screen seeds its state from
|
|
1350
|
-
* `read` once, and calls the other two from an effect and a callback it does
|
|
1351
|
-
* not rebuild for them.
|
|
1352
|
-
*/
|
|
1353
|
-
interface ScreenLeftViewRules {
|
|
1354
|
-
/** The view a mount opens on: the one kept, or the layer's first. */
|
|
1355
|
-
read: () => string;
|
|
1356
|
-
/** Keep the view for the next mount. */
|
|
1357
|
-
write: (view: string) => void;
|
|
1358
|
-
/** What a change of the selection does to the view: handed the id of the
|
|
1359
|
-
* node selected, if one is, and the view the panel is on, it answers the
|
|
1360
|
-
* view to be on. */
|
|
1361
|
-
forSelection: (selectedId: string | null | undefined, current: string) => string;
|
|
1362
|
-
}
|
|
1363
|
-
/** What a style clipboard's scope is read off (`ScreenStyleClipboard.scope`):
|
|
1364
|
-
* the document the screen has open. */
|
|
1365
|
-
interface ScreenStyleDocument {
|
|
1366
|
-
/** What the screen is pointed at: a website's page, or a host's own
|
|
1367
|
-
* document (`{ kind: "document", record }`). */
|
|
1368
|
-
target: AnyScreenTarget;
|
|
1369
|
-
/** The website the page belongs to, or null. */
|
|
1370
|
-
siteId: string | null;
|
|
1371
|
-
/** The backend's id of the loaded document, or null while it loads. */
|
|
1372
|
-
docId: string | null;
|
|
1373
|
-
}
|
|
1374
|
-
/** What a Paste style onto one node would do: its new props, whether they
|
|
1375
|
-
* changed, how many rows were pasted, and the words the merchant reads. */
|
|
1376
|
-
interface ScreenStylePastePlan {
|
|
1377
|
-
props: Record<string, unknown>;
|
|
1378
|
-
changed: boolean;
|
|
1379
|
-
pasted: number;
|
|
1380
|
-
message: string;
|
|
1381
|
-
}
|
|
1382
|
-
/**
|
|
1383
|
-
* COPY STYLE / PASTE STYLE, where it is the layer's (0.105.0, seam E10). The
|
|
1384
|
-
* clipboard, the matching rule, the menu rows, their words and the ⌥⌘C / ⌥⌘V
|
|
1385
|
-
* keys are efficient-easel/style-clipboard's and the screen's; WHICH rows of a
|
|
1386
|
-
* node are its look, and how far a copied look travels (its scope), are the
|
|
1387
|
-
* layer's — the website's look is its Style and Layout tabs and travels across
|
|
1388
|
-
* one site's pages, the campaign designer's is its own panels' and stays in
|
|
1389
|
-
* one campaign. Each member is optional, and one left out is the website's
|
|
1390
|
-
* (lib/document/style-clipboard): a layer may hand only its scope. Plain functions,
|
|
1391
|
-
* the same object for the life of the mount.
|
|
1392
|
-
*/
|
|
1393
|
-
interface ScreenStyleClipboard {
|
|
1394
|
-
/** The clipboard's scope for the open document: in another scope nothing is
|
|
1395
|
-
* held. Absent: `siteStyleScope(siteId)`, one site across its pages. */
|
|
1396
|
-
scope?: (doc: ScreenStyleDocument) => string;
|
|
1397
|
-
/** A node's look, as rows the clipboard holds and matches. Absent: the
|
|
1398
|
-
* website's (`nodeStyleRows`), the Style and Layout tabs. */
|
|
1399
|
-
rows?: (config: unknown, node: ScreenNode) => StyleRow[];
|
|
1400
|
-
/** Copy a node's look into `scope`, named `label` (the menu's word for it).
|
|
1401
|
-
* Absent: its `rows`, copied as they are stored. */
|
|
1402
|
-
copy?: (scope: string, node: ScreenNode, label: string, config: unknown) => void;
|
|
1403
|
-
/** What a paste onto a node would do, or null when nothing is held in
|
|
1404
|
-
* `scope`. The screen writes `props` through its one replace op when
|
|
1405
|
-
* `changed`, and always shows `message`. Absent: the held look laid over the
|
|
1406
|
-
* node's `rows` (efficient-easel/style-clipboard `planPaste`). */
|
|
1407
|
-
plan?: (scope: string, node: ScreenNode, label: string, config: unknown) => ScreenStylePastePlan | null;
|
|
1408
|
-
}
|
|
1409
|
-
interface ScreenParts {
|
|
1410
|
-
/**
|
|
1411
|
-
* The name a panel's head gives what is being edited — the website's name,
|
|
1412
|
-
* a campaign's — as the hook the head calls, through `useScreenOwnerName`.
|
|
1413
|
-
*/
|
|
1414
|
-
useOwnerName?: () => string;
|
|
1415
|
-
/**
|
|
1416
|
-
* The Layers head's context line — what the open document is, under the
|
|
1417
|
-
* word "Layers" — as the hook the head calls (0.103.0). The campaign
|
|
1418
|
-
* designer's names the campaign and its variant. Absent: the document's
|
|
1419
|
-
* address, `/${slug}`, as the website's head has always said it.
|
|
1420
|
-
*/
|
|
1421
|
-
useDocumentLabel?: () => string;
|
|
1422
|
-
/**
|
|
1423
|
-
* The layer's wiring between the inspector and what the layer draws in the
|
|
1424
|
-
* canvas, as ONE hook the screen calls where it used to hold that wiring: a
|
|
1425
|
-
* click on the layer's furniture in the canvas opens its panel, and the open
|
|
1426
|
-
* panel outlines the furniture. And its wiring for the parts of one block
|
|
1427
|
-
* that are not nodes: what selecting one does, and the rows it has in the
|
|
1428
|
-
* tree. And its own controls in the top bar, with whatever they run on. And
|
|
1429
|
-
* its buttons in the rail, with the views of the left panel they open.
|
|
1430
|
-
*/
|
|
1431
|
-
useBridges?: (inspector: ScreenInspector, tree: ScreenTree, canvas: ScreenCanvas, left: ScreenLeftPanel) => ScreenBridges;
|
|
1432
|
-
/**
|
|
1433
|
-
* The same, for the screen that holds ONE node as its whole document
|
|
1434
|
-
* (SectionScreenShell). A hook of its own and not `useBridges` with less
|
|
1435
|
-
* handed in: that screen wired less — no site-wide furniture, no tree of
|
|
1436
|
-
* sections — and a hook cannot leave out half of itself by what it is
|
|
1437
|
-
* passed.
|
|
1438
|
-
*/
|
|
1439
|
-
useStandaloneBridges?: (inspector: ScreenInspector) => ScreenBridges;
|
|
1440
|
-
/**
|
|
1441
|
-
* The layer's own pass over a document as it opens: what it lays down in one
|
|
1442
|
-
* that lacks it, and takes out of one that holds it twice. A hook of its own
|
|
1443
|
-
* and not one more thing the bridges run, because of WHERE it must run: the
|
|
1444
|
-
* bridges stand early among the screen's hooks, and this pass writes the
|
|
1445
|
-
* document, so it is called LAST of the screen's own passes over it — after
|
|
1446
|
-
* the slot seeding and the duplicate-id heal, which address top-level nodes
|
|
1447
|
-
* by index and would be thrown out by a node laid down ahead of them. Lent
|
|
1448
|
-
* the screen's writes and the config it holds, for the engine's node maker.
|
|
1449
|
-
*/
|
|
1450
|
-
useDocumentPass?: (ops: ScreenDocumentOps, config: unknown) => void;
|
|
1451
|
-
/**
|
|
1452
|
-
* The layer's block rules. Handed here and NOT registered at import: what a
|
|
1453
|
-
* registry holds depends on which modules have loaded, and that order is not
|
|
1454
|
-
* the same in the app and in a script that loads one file, so a rule could
|
|
1455
|
-
* answer in one and be absent in the other.
|
|
1456
|
-
*/
|
|
1457
|
-
blockRules?: ScreenBlockRules;
|
|
1458
|
-
/** How the layer's blocks are named and drawn. Handed here for the reason
|
|
1459
|
-
* the rules are. */
|
|
1460
|
-
blockLook?: ScreenBlockLook;
|
|
1461
|
-
/** The devices the layer's canvas is looked at on. Data, and handed here
|
|
1462
|
-
* for the reason the rules are. */
|
|
1463
|
-
devices?: ScreenDevices;
|
|
1464
|
-
/** Where the left panel's view is kept, and which one a mount opens on.
|
|
1465
|
-
* Plain functions, and handed here for the reason the rules are. */
|
|
1466
|
-
leftView?: ScreenLeftViewRules;
|
|
1467
|
-
/** Which node types are pinned in the top-level list, which are groups of
|
|
1468
|
-
* sections, and which are edited in a panel of the layer's. Data and three
|
|
1469
|
-
* plain functions, and handed here for the reason the rules are. */
|
|
1470
|
-
pinned?: ScreenPinnedNodes;
|
|
1471
|
-
/**
|
|
1472
|
-
* May the operator pause the autosave (0.103.0)? Since 8.0.0 the switch is
|
|
1473
|
-
* the save menu's Auto-save check box (the main button's ▾), where it was
|
|
1474
|
-
* the save pill; a layer whose editor always saves says false, and the menu
|
|
1475
|
-
* offers Save now alone. "Retry now" stays after a failed save either way.
|
|
1476
|
-
* Absent, true: the switch, as both editors have it.
|
|
1477
|
-
*/
|
|
1478
|
-
saveSwitch?: boolean;
|
|
1479
|
-
/**
|
|
1480
|
-
* Does a field's media pick give way to a change of selection (0.103.0)? A
|
|
1481
|
-
* field of the selected block asks the host's panel to choose (lib/
|
|
1482
|
-
* media-panel); with true, selecting another block, or none, while it waits
|
|
1483
|
-
* leaves pick mode and settles the field with null, as Cancel would — the
|
|
1484
|
-
* campaign designer's picker belongs to the block it was opened for. Absent,
|
|
1485
|
-
* false: a pick outlives a change of selection, as the website's does.
|
|
1486
|
-
*/
|
|
1487
|
-
pickFollowsSelection?: boolean;
|
|
1488
|
-
/**
|
|
1489
|
-
* WHERE A PERSON'S PANEL WIDTHS AND TREE FOLDS ARE KEPT (0.106.0): the
|
|
1490
|
-
* first part of the two `localStorage` keys, `<namespace>-panel-widths` and
|
|
1491
|
-
* `<namespace>-collapsed-sections`, so an editor beside the website's keeps
|
|
1492
|
-
* its own — the campaign designer's panels and folds are not the website
|
|
1493
|
-
* editor's. Read once, as the screen mounts. Absent (or empty): the website
|
|
1494
|
-
* editor's keys, `sf-editor-panel-widths` and
|
|
1495
|
-
* `sf-editor-collapsed-sections`, so a website's layout is what it was.
|
|
1496
|
-
*/
|
|
1497
|
-
storageNamespace?: string;
|
|
1498
|
-
/** Copy style / Paste style's scope and a node's look, where they are the
|
|
1499
|
-
* layer's (0.105.0; `ScreenStyleClipboard`). Absent: the website's. */
|
|
1500
|
-
styleClipboard?: ScreenStyleClipboard;
|
|
1501
|
-
/**
|
|
1502
|
-
* Do ⌘C / ⌘X / ⌘V (Ctrl on Windows) copy, cut and paste the SELECTED block
|
|
1503
|
-
* (0.105.0)? The keyboard door to the menu's Copy, Cut and Paste rows, which
|
|
1504
|
-
* print these keys beside them: the menu's rules, the menu's place for a
|
|
1505
|
-
* paste, and a paste with nowhere to go there refused aloud
|
|
1506
|
-
* (`screen.pasteRefused`). Heard on the editor and in the canvas frame, never
|
|
1507
|
-
* where a person types or has words selected, nor with ⌥ (Copy style) or ⇧
|
|
1508
|
-
* held. Nothing is cut or pasted on a document this editor cannot write; a
|
|
1509
|
-
* copy is allowed there.
|
|
1510
|
-
*
|
|
1511
|
-
* Owner ruling R12/R13 (Victor Mau, 2026-10-09): Copy and Paste work the same
|
|
1512
|
-
* way in both editors. So the keys are on unless the layer says false.
|
|
1513
|
-
*/
|
|
1514
|
-
nodeKeys?: boolean;
|
|
1515
|
-
/**
|
|
1516
|
-
* THE HOST'S OWN TOASTS (0.105.0; owner ruling R17, Victor Mau, 2026-10-09).
|
|
1517
|
-
* Every line the screen would say in its toast — "Copied Text", "Added
|
|
1518
|
-
* “Hero” section", a refused paste, a pasted style, what a panel of the
|
|
1519
|
-
* layer's or the inspector says through the screen's toast — goes to the host
|
|
1520
|
-
* instead, with its tone: `"error"` for what went wrong, `"info"` for the
|
|
1521
|
-
* rest; and the screen draws no toast of its own. The campaign designer
|
|
1522
|
-
* hands the admin portal's toast, so the designer's lines stand where every
|
|
1523
|
-
* other window's do. Called as each line is said, so it may change between
|
|
1524
|
-
* renders. Absent: the shell's `toast` (efficient-shell/ui, harness UI-24;
|
|
1525
|
-
* up to 0.106.0 the screen drew a toast of its own, `.sf-toast`).
|
|
1526
|
-
*/
|
|
1527
|
-
notify?: (message: string, tone: "info" | "error", extra?: ScreenToastExtra) => void;
|
|
1528
|
-
/**
|
|
1529
|
-
* THE CANVAS the screen frames: the engine's, as the layer dresses it — the
|
|
1530
|
-
* layer's own sheet and theme in the frame, its own say over the outline
|
|
1531
|
-
* round a block. The screen places it in the pane it has measured, hands it
|
|
1532
|
-
* nothing, and remounts it by key to rebuild the frame; where the frame
|
|
1533
|
-
* stands, how it is fitted and what is laid over it are the screen's.
|
|
1534
|
-
*
|
|
1535
|
-
* ONE function for the life of a mount: the screen renders it as an element
|
|
1536
|
-
* type, and a type that changed identity would remount the whole canvas.
|
|
1537
|
-
*
|
|
1538
|
-
* The frame it draws is published to it, and to the head over it
|
|
1539
|
-
* (`CanvasHead`), as the screen found it: `useScreenCanvasTarget()`.
|
|
1540
|
-
*/
|
|
1541
|
-
Canvas?: ComponentType;
|
|
1542
|
-
/**
|
|
1543
|
-
* A HEAD OVER THE CANVAS (0.105.0): the layer's own row above the frame, in
|
|
1544
|
-
* the canvas's well and at its own size — never scaled with a device — such
|
|
1545
|
-
* as the campaign designer's Subject line, its mail-app switch and its dark
|
|
1546
|
-
* mail app's bar, which sit above the email the way an inbox shows them. The
|
|
1547
|
-
* frame fills what is left of the well under it, and is fitted to that. It is
|
|
1548
|
-
* handed the device the canvas is drawn as. Absent: nothing is drawn above
|
|
1549
|
-
* the frame, and the frame fills the well.
|
|
1550
|
-
*
|
|
1551
|
-
* ONE function for the life of a mount, for the reason `Canvas` is.
|
|
1552
|
-
*/
|
|
1553
|
-
CanvasHead?: ComponentType<ScreenCanvasHeadProps>;
|
|
1554
|
-
/**
|
|
1555
|
-
* The canvas drag's measure, model and rules, where they are the layer's
|
|
1556
|
-
* (0.105.0; `ScreenCanvasDrag`). Each member absent, and the whole object
|
|
1557
|
-
* absent, is the screen's own: the old library's markers, every node but the pinned
|
|
1558
|
-
* ones, the Layers tree's rules. Plain functions, and handed here for the
|
|
1559
|
-
* reason the rules are.
|
|
1560
|
-
*/
|
|
1561
|
-
canvasDrag?: ScreenCanvasDrag;
|
|
1562
|
-
/**
|
|
1563
|
-
* THE INSPECTOR the screen mounts in its right panel: the panel of whatever
|
|
1564
|
-
* is selected and, in its place, each panel of the layer's own — frame, head
|
|
1565
|
-
* and body, since the screen draws nothing round it. The screen holds WHICH
|
|
1566
|
-
* panel is showing and hands it over (`mode`), with the ways out of a panel
|
|
1567
|
-
* and its own toast and Hide button; what a mode draws is the layer's.
|
|
1568
|
-
*
|
|
1569
|
-
* ONE function for the life of a mount: the screen renders it as an element
|
|
1570
|
-
* type, and a type that changed identity would remount the panel and drop
|
|
1571
|
-
* what a merchant has open in it.
|
|
1572
|
-
*/
|
|
1573
|
-
Inspector?: ComponentType<ScreenInspectorPanelProps>;
|
|
1574
|
-
}
|
|
1575
|
-
declare function ScreenPartsProvider({ parts, children }: {
|
|
1576
|
-
parts: ScreenParts;
|
|
1577
|
-
children?: ReactNode;
|
|
1578
|
-
}): react.JSX.Element;
|
|
1579
|
-
/** The layer's parts; none when the screen stands by itself. */
|
|
1580
|
-
declare function useScreenParts(): ScreenParts;
|
|
1581
|
-
/** The layer's bridges, run in the screen. With no layer, nothing runs. */
|
|
1582
|
-
/** The name a panel's head gives what is being edited (`useOwnerName`). */
|
|
1583
|
-
declare function useScreenOwnerName(): string;
|
|
1584
|
-
/** The Layers head's context line (`useDocumentLabel`), or null with no
|
|
1585
|
-
* layer's, and the screen says the document's address. */
|
|
1586
|
-
declare function useScreenDocumentLabel(): string | null;
|
|
1587
|
-
declare function useScreenBridges(inspector: ScreenInspector, tree: ScreenTree, canvas: ScreenCanvas, left: ScreenLeftPanel): ScreenBridges;
|
|
1588
|
-
/** The layer's bridges for the screen that holds one node by itself. With no
|
|
1589
|
-
* layer, nothing runs. */
|
|
1590
|
-
declare function useStandaloneScreenBridges(inspector: ScreenInspector): ScreenBridges;
|
|
1591
|
-
/** The layer's pass over a document as it opens, run in the screen. With no
|
|
1592
|
-
* layer, nothing runs. */
|
|
1593
|
-
declare function useScreenDocumentPass(ops: ScreenDocumentOps, config: unknown): void;
|
|
1594
|
-
/** The layer's block rules. With no layer, the rules of an editor that has no
|
|
1595
|
-
* blocks of its own. */
|
|
1596
|
-
declare function useScreenBlockRules(): ScreenBlockRules;
|
|
1597
|
-
/** How the layer's blocks are named and drawn. With no layer, by what the
|
|
1598
|
-
* config says of them and with no drawing. */
|
|
1599
|
-
declare function useScreenBlockLook(): ScreenBlockLook;
|
|
1600
|
-
/** The devices the layer's canvas is looked at on. With no layer, the one that
|
|
1601
|
-
* fills the pane. */
|
|
1602
|
-
declare function useScreenDevices(): ScreenDevices;
|
|
1603
|
-
/** Where the layer keeps the left panel's view. With no layer, nowhere: every
|
|
1604
|
-
* mount opens on the Layers tree. */
|
|
1605
|
-
declare function useScreenLeftView(): ScreenLeftViewRules;
|
|
1606
|
-
/** Which node types the layer pins in the top-level list, and which are its
|
|
1607
|
-
* groups of sections. With no layer, none. */
|
|
1608
|
-
declare function useScreenPinned(): ScreenPinnedNodes;
|
|
1609
|
-
/** Whether the save pill is the autosave's switch. With no layer, it is, as
|
|
1610
|
-
* the screen has always drawn it. */
|
|
1611
|
-
declare function useScreenSaveSwitch(): boolean;
|
|
1612
|
-
/** Leave a field's pick when `selection` changes, if the layer says a pick
|
|
1613
|
-
* follows the selection (`pickFollowsSelection`). With no layer, a pick
|
|
1614
|
-
* outlives a change of selection, as it always has. */
|
|
1615
|
-
declare function useScreenPickFollowsSelection(selection: unknown): void;
|
|
1616
|
-
/** Where widths and folds are kept (`storageNamespace`), or undefined: the
|
|
1617
|
-
* website editor's keys. */
|
|
1618
|
-
declare function useScreenStorageNamespace(): string | undefined;
|
|
1619
|
-
/** The layer's style clipboard (`styleClipboard`), or null: the website's. */
|
|
1620
|
-
declare function useScreenStyleClipboard(): ScreenStyleClipboard | null;
|
|
1621
|
-
/** Whether ⌘C / ⌘X / ⌘V reach the selected block (`nodeKeys`). They do
|
|
1622
|
-
* unless the layer says not (owner ruling R12/R13). */
|
|
1623
|
-
declare function useScreenNodeKeys(): boolean;
|
|
1624
|
-
/** The host's toast (`notify`), or null: with none, the screen says its lines
|
|
1625
|
-
* in its own (R17). */
|
|
1626
|
-
declare function useScreenNotify(): ((message: string, tone: "info" | "error", extra?: ScreenToastExtra) => void) | null;
|
|
1627
|
-
/** The canvas the layer dresses for the screen to frame. With no layer, the
|
|
1628
|
-
* engine's plain one. */
|
|
1629
|
-
declare function useScreenCanvasFrame(): ComponentType;
|
|
1630
|
-
/** The layer's head over the canvas (`CanvasHead`), or null: with no layer's,
|
|
1631
|
-
* nothing is drawn above the frame. */
|
|
1632
|
-
declare function useScreenCanvasHead(): ComponentType<ScreenCanvasHeadProps> | null;
|
|
1633
|
-
/** The layer's canvas drag (`canvasDrag`), or null: with no layer's, every
|
|
1634
|
-
* answer is the screen's own. */
|
|
1635
|
-
declare function useScreenCanvasDrag(): ScreenCanvasDrag | null;
|
|
1636
|
-
/** Publishes the frame the page screen found. The screen's own: it stands round
|
|
1637
|
-
* the chrome, and adds nothing to the page. */
|
|
1638
|
-
declare function ScreenCanvasTargetProvider({ target, children }: {
|
|
1639
|
-
target: CanvasTarget | null;
|
|
1640
|
-
children?: ReactNode;
|
|
1641
|
-
}): react.JSX.Element;
|
|
1642
|
-
/** The canvas frame the page screen found: its frame, document and window, or
|
|
1643
|
-
* null while there is none — and always null outside the page screen (the
|
|
1644
|
-
* section screen watches for no frame). */
|
|
1645
|
-
declare function useScreenCanvasTarget(): CanvasTarget | null;
|
|
1646
|
-
/** The inspector the layer draws for the screen to mount. With no layer, the
|
|
1647
|
-
* engine's plain rows for the selection. */
|
|
1648
|
-
declare function useScreenInspectorPanel(): ComponentType<ScreenInspectorPanelProps>;
|
|
1649
|
-
|
|
1650
|
-
/**
|
|
1651
|
-
* A PALETTE ROW THAT IS A PRESET, NOT A BLOCK TYPE (GG ruling 2026-10-30,
|
|
1652
|
-
* owner item C36). The website's Contact / Locations section is offered as TWO
|
|
1653
|
-
* rows, "City pictures" and "City maps": each lays down its own arrangement of
|
|
1654
|
-
* ordinary blocks, and there is no block type behind either. So a row may be a
|
|
1655
|
-
* preset — its own key, label, group, blurb and cover — and pressing it lays
|
|
1656
|
-
* down what `insert` builds, in ONE insert, so one Undo takes it back (the way
|
|
1657
|
-
* a splittable section's press already lands: `newSectionNode`).
|
|
1658
|
-
*
|
|
1659
|
-
* The layer hands these in (`PaletteLook.presets`); the screen states none.
|
|
1660
|
-
* What the arrangement IS stays where the layer keeps arrangements (the
|
|
1661
|
-
* website: `SECTION_PRESETS`); this says only where the row sits and what it
|
|
1662
|
-
* is called.
|
|
1663
|
-
*/
|
|
1664
|
-
interface PalettePreset {
|
|
1665
|
-
/** The row's own key, unique among presets. It names NO block type: a
|
|
1666
|
-
* preset whose key is a registered type is not offered (a type row and a
|
|
1667
|
-
* preset row would be one key with two meanings). The cover is the layer's
|
|
1668
|
-
* `Thumbnail`, asked with this key. */
|
|
1669
|
-
key: string;
|
|
1670
|
-
/** What the row is called. Also what the toast says when it is added. */
|
|
1671
|
-
label: string;
|
|
1672
|
-
/** The key of the category (`config.categories`) it is grouped under. A
|
|
1673
|
-
* category the config does not have, or does not offer, offers no preset. */
|
|
1674
|
-
cat: string;
|
|
1675
|
-
/** The block type in that category the row follows; absent, or not in the
|
|
1676
|
-
* category, and the row closes its group. */
|
|
1677
|
-
after?: string;
|
|
1678
|
-
/** The one-line blurb, shown and searched. */
|
|
1679
|
-
desc?: string;
|
|
1680
|
-
/** More words it is found by, searched but never shown. */
|
|
1681
|
-
alias?: string;
|
|
1682
|
-
/** The node it lays down — one node, slot children inline, every id fresh
|
|
1683
|
-
* from `make.newNodeId` — or null, and nothing is added. Lent the same
|
|
1684
|
-
* four things `newSectionNode` is. */
|
|
1685
|
-
insert: (make: ScreenNodeMaker) => ScreenNewNode | null;
|
|
1686
|
-
}
|
|
1687
|
-
/** One offerable section, with the category it is grouped under. */
|
|
1688
|
-
type PaletteSection = {
|
|
1689
|
-
/** The block type — or, on a preset row, the preset's key (`preset`). */
|
|
1690
|
-
type: string;
|
|
1691
|
-
cat: string;
|
|
1692
|
-
name: string;
|
|
1693
|
-
desc: string;
|
|
1694
|
-
/**
|
|
1695
|
-
* The heading of the category this section sits under, resolved once at build
|
|
1696
|
-
* time — SEARCHED, and already SHOWN as the nav row this card sits beneath.
|
|
1697
|
-
*
|
|
1698
|
-
* ⚠️ IT IS HERE BECAUSE THE NAV AND THE SEARCH DISAGREED. Seven of the
|
|
1699
|
-
* thirteen category names returned NOTHING when typed: "Blog & journal" reads
|
|
1700
|
-
* 5 in the nav, and "blog" found 0, because not one of Issue Header, Featured
|
|
1701
|
-
* Cover, Article Text, Recurring Columns or Latest Posts carries the word. Same
|
|
1702
|
-
* for shop, about, promotions, navigation, legal and layout. A merchant reads
|
|
1703
|
-
* the word off the screen, types it, and is told no section matches.
|
|
1704
|
-
*
|
|
1705
|
-
* Resolved HERE, not in `matchesQuery`, because the label needs the `config`
|
|
1706
|
-
* (`categoryLabel`) and the matcher is given only a section — passing config
|
|
1707
|
-
* into the matcher would make every caller carry it.
|
|
1708
|
-
*/
|
|
1709
|
-
catLabel: string;
|
|
1710
|
-
/**
|
|
1711
|
-
* Another word this section is known by, searched but never shown.
|
|
1712
|
-
*
|
|
1713
|
-
* ⚠️ THIS EXISTS FOR ONE NODE AND ONE REASON. `Flex` is offered here as
|
|
1714
|
-
* "Blank section" and is called "Box" everywhere it is nested — so a merchant
|
|
1715
|
-
* who met it in a Layers row, or in last week's handoff, types "box" and must
|
|
1716
|
-
* still find it. Without this they would find NOTHING: the card is pinned out
|
|
1717
|
-
* of its group, so a search that misses it misses it completely.
|
|
1718
|
-
*/
|
|
1719
|
-
alias?: string;
|
|
1720
|
-
/** Set on a PRESET row only: the preset it lays down. Absent on every
|
|
1721
|
-
* type row, so a type row is the row it always was. */
|
|
1722
|
-
preset?: PalettePreset;
|
|
1723
|
-
};
|
|
1724
|
-
/**
|
|
1725
|
-
* What the layer says of its sections for the palette: the word for a type at
|
|
1726
|
-
* a level, a group's short heading where it has one, and the blurbs. The
|
|
1727
|
-
* screen's `blockLook` is one (lib/screen-parts); so is the website's own
|
|
1728
|
-
* (lib/document/add-palette).
|
|
1729
|
-
*/
|
|
1730
|
-
interface PaletteLook {
|
|
1731
|
-
/** What a node of `type` is called at a level, given the label the config
|
|
1732
|
-
* holds for it. */
|
|
1733
|
-
labelAtLevel: (type: string, level: "section" | "block", base: string) => string;
|
|
1734
|
-
/** A group's short heading, by its key, where the layer has one; undefined,
|
|
1735
|
-
* and the config's own title is the heading. */
|
|
1736
|
-
categoryLabel: (id: string) => string | undefined;
|
|
1737
|
-
/** The one-line blurb for a section, by type. */
|
|
1738
|
-
descriptions: Record<string, string>;
|
|
1739
|
-
/** Rows that are presets, not block types (`PalettePreset`). Absent: every
|
|
1740
|
-
* row is a type, as before. */
|
|
1741
|
-
presets?: readonly PalettePreset[];
|
|
1742
|
-
}
|
|
1743
|
-
/**
|
|
1744
|
-
* Flatten `config.categories` into an ordered section list.
|
|
1745
|
-
*
|
|
1746
|
-
* Grouping and order ARE the category order in the config — which is the
|
|
1747
|
-
* catalog's order — so this adds no opinion of its own. A component listed in a
|
|
1748
|
-
* category but absent from `components` is skipped: a stale catalog row cannot
|
|
1749
|
-
* render and certainly cannot insert, so offering it would be a card that fails
|
|
1750
|
-
* on click.
|
|
1751
|
-
*
|
|
1752
|
-
* Child-only blocks (HeroSlide / CollectionCard / ProductRef) and the four
|
|
1753
|
-
* generic primitives (Heading / Text / ImageBlock / ButtonBlock) sit in NO
|
|
1754
|
-
* category on purpose, so they never appear here — they are added from their
|
|
1755
|
-
* parent's slot instead. See the note above `categories:` in lib/document/config.tsx.
|
|
1756
|
-
*
|
|
1757
|
-
* A category the config marks `visible: false` is NOT offered (0.105.0, seam
|
|
1758
|
-
* E9): it is a registry's way of keeping blocks it has out of the picker — the
|
|
1759
|
-
* campaign designer's Product parts, its retired blocks, its Sections — and a
|
|
1760
|
-
* palette that listed them would offer things that may not be put on a page.
|
|
1761
|
-
* The old library's own palette read the flag the same way. No website category carries
|
|
1762
|
-
* it, so the website's palette is the list it was.
|
|
1763
|
-
*/
|
|
1764
|
-
declare function buildPaletteSections(config: Config, look: PaletteLook): PaletteSection[];
|
|
1765
|
-
/** A category's display label — the layer's short one where there is one, else the config's title. */
|
|
1766
|
-
declare function categoryLabel(config: Config, id: string, shortLabel: (id: string) => string | undefined): string;
|
|
1767
|
-
/**
|
|
1768
|
-
* Does a section match a search query?
|
|
1769
|
-
*
|
|
1770
|
-
* The query is matched against the NAME, any ALIAS, the blurb, the component
|
|
1771
|
-
* TYPE and the CATEGORY HEADING — the type because a merchant who knows the
|
|
1772
|
-
* section by the word they saw in a handoff should still find it, the alias
|
|
1773
|
-
* because one node is called something else everywhere it is nested (see
|
|
1774
|
-
* `PaletteSection.alias`), and the category because it is PRINTED IN THE NAV
|
|
1775
|
-
* BESIDE THE RESULTS: seven of thirteen headings used to match nothing at all
|
|
1776
|
-
* (see `PaletteSection.catLabel`). A word a merchant can read off this screen
|
|
1777
|
-
* must find what it is labelling.
|
|
1778
|
-
*
|
|
1779
|
-
* `q` is expected already lower-cased and trimmed; an empty query matches
|
|
1780
|
-
* everything.
|
|
1781
|
-
*/
|
|
1782
|
-
declare function matchesQuery(s: PaletteSection, q: string): boolean;
|
|
1783
|
-
/** The pinned section, or `null` if the layer pins none or the config does not offer it. */
|
|
1784
|
-
declare function pinnedSection(sections: PaletteSection[], pinned: string | null): PaletteSection | null;
|
|
1785
|
-
/** Every OTHER section — what the grouped grid below the pinned card draws. */
|
|
1786
|
-
declare function paletteWithoutPinned(sections: PaletteSection[], pinned: string | null): PaletteSection[];
|
|
1787
|
-
|
|
1788
|
-
/** What a tile adds, parsed back out of its key. */
|
|
1789
|
-
type AddKey = {
|
|
1790
|
-
kind: "section";
|
|
1791
|
-
type: string;
|
|
1792
|
-
} | {
|
|
1793
|
-
kind: "template";
|
|
1794
|
-
template: SectionTemplate;
|
|
1795
|
-
} | {
|
|
1796
|
-
kind: "shared";
|
|
1797
|
-
section: SharedSection;
|
|
1798
|
-
}
|
|
1799
|
-
/** A row that is a preset, not a block type (the layer's `presets`): what
|
|
1800
|
-
* it lays down is its `insert`'s. */
|
|
1801
|
-
| {
|
|
1802
|
-
kind: "preset";
|
|
1803
|
-
preset: PalettePreset;
|
|
1804
|
-
} | {
|
|
1805
|
-
kind: "block";
|
|
1806
|
-
type: string;
|
|
1807
|
-
};
|
|
1808
|
-
declare const sectionKey: (type: string) => string;
|
|
1809
|
-
declare const blockKey: (type: string) => string;
|
|
1810
|
-
declare const templateKey: (id: string) => string;
|
|
1811
|
-
declare const sharedKey: (id: string) => string;
|
|
1812
|
-
declare const presetKey: (key: string) => string;
|
|
1813
|
-
type AddSidePanelProps<I> = {
|
|
1814
|
-
/** Where the next thing goes, when the panel was opened at a place. */
|
|
1815
|
-
at?: {
|
|
1816
|
-
label: string;
|
|
1817
|
-
onClear: () => void;
|
|
1818
|
-
};
|
|
1819
|
-
/** At a place in a list of blocks: the blocks that list takes. They are in
|
|
1820
|
-
* the one list whatever the catalogue holds, so a place can always be
|
|
1821
|
-
* filled from it. */
|
|
1822
|
-
placeBlocks?: readonly BlockChoice[];
|
|
1823
|
-
/** At a place: may what a tile names go there? Null when it may, else why
|
|
1824
|
-
* not, in the panel's words — the tile is then dimmed and says so. Absent
|
|
1825
|
-
* (no place): every tile is offered, to drag. */
|
|
1826
|
-
canTake?: (key: AddKey) => string | null;
|
|
1827
|
-
/** At a place: put what a pressed tile names there. Absent (no place): a
|
|
1828
|
-
* press adds nothing, and a tile is only dragged. */
|
|
1829
|
-
onPick?: (key: AddKey) => void;
|
|
1830
|
-
/** The drag item for what a tile names — a drag in the editor's session. */
|
|
1831
|
-
itemFor: (key: AddKey) => I;
|
|
1832
|
-
session: DragSession<I>;
|
|
1833
|
-
/** A row under the tiles for something that is not a block, drawn by the
|
|
1834
|
-
* layer that owns it (the website: the Live chat bubble). */
|
|
1835
|
-
siteWide?: ReactNode;
|
|
1836
|
-
/** Leave Add — back to the view underneath (the head's "Done"). */
|
|
1837
|
-
onClose: () => void;
|
|
1838
|
-
/** Hide the left panel (the head's last button, as on every panel). */
|
|
1839
|
-
onHide?: () => void;
|
|
1840
|
-
readOnly?: boolean;
|
|
1841
|
-
};
|
|
1842
|
-
declare function AddSidePanel<I>({ at, placeBlocks, canTake, onPick, itemFor, session, siteWide, onClose, onHide, readOnly, }: AddSidePanelProps<I>): react.JSX.Element;
|
|
1843
|
-
|
|
1844
|
-
export { type AddKey as A, type CopyItemAction, type CopyItemRequest, type NodeDefaults, type PaletteLook as P, SELECTION_MODE, type ScreenBlockLook, type ScreenBlockRules, type ScreenBridges, type ScreenCanvas, type ScreenCanvasDrag, type ScreenCanvasDragContext, type ScreenCanvasHeadProps, ScreenCanvasTargetProvider, type ScreenDevices, type ScreenDocumentOps, type ScreenDragItem, type ScreenInspector, type ScreenInspectorMode, type ScreenInspectorPanelProps, type ScreenLeftPanel, type ScreenLeftView, type ScreenLeftViewFrame, type ScreenLeftViewRules, type ScreenMainAction, type ScreenMediaDrop, type ScreenMediaFile, type ScreenMenuItem, type ScreenMenuRows, type ScreenNewNode, type ScreenNode, type ScreenNodeActions, type ScreenNodeAt, type ScreenNodeLevel, type ScreenNodeMaker, type ScreenPartMode, type ScreenParts, ScreenPartsProvider, type ScreenPinnedBand, type ScreenPinnedNodes, type ScreenRailItem, type ScreenSelector, type ScreenSharedSections, type ScreenSlot, type ScreenSlotAction, type ScreenSlotMode, type ScreenStyleClipboard, type ScreenStyleDocument, type ScreenStylePastePlan, type ScreenToastExtra, type ScreenTree, type ScreenTreeFolds, type ScreenTreeRows, type PalettePreset as a, type PaletteSection as b, buildPaletteSections as c, categoryLabel as d, pinnedSection as e, type AddSidePanelProps as f, blockKey as g, AddSidePanel as h, presetKey as i, isPinnedFirst, isPinnedLast, isSelectionMode, isSlotMode, sharedKey as j, matchesQuery as m, paletteWithoutPinned as p, sectionKey as s, sameInspectorMode, screenSlotsOf, shownChildSlotsOf, shownSlotFieldsOf, templateKey as t, useScreenBlockLook, useScreenBlockRules, useScreenBridges, useScreenCanvasDrag, useScreenCanvasFrame, useScreenCanvasHead, useScreenCanvasTarget, useScreenDevices, useScreenDocumentLabel, useScreenDocumentPass, useScreenInspectorPanel, useScreenLeftView, useScreenNodeKeys, useScreenNotify, useScreenOwnerName, useScreenParts, useScreenPickFollowsSelection, useScreenPinned, useScreenSaveSwitch, useScreenStorageNamespace, useScreenStyleClipboard, useStandaloneScreenBridges };
|