efficient-easel 0.0.0 → 0.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +10 -0
- package/README.md +818 -4
- package/dist/autosave/index.d.ts +101 -0
- package/dist/autosave/index.js +1 -0
- package/dist/blocks/index.d.ts +306 -0
- package/dist/blocks/index.js +0 -0
- package/dist/buckets-1vRlQceY.d.ts +13 -0
- package/dist/canvas/index.d.ts +194 -0
- package/dist/canvas/index.js +1 -0
- package/dist/chrome/chrome.css +570 -0
- package/dist/chrome/index.d.ts +219 -0
- package/dist/chrome/index.js +21 -0
- package/dist/chunk-2LUSK32B.js +1 -0
- package/dist/chunk-2OAZYSWJ.js +1 -0
- package/dist/chunk-67VZRQLG.js +13 -0
- package/dist/chunk-6OPSJGAI.js +1 -0
- package/dist/chunk-6PS6STGA.js +1 -0
- package/dist/chunk-6WY6ZXJG.js +1 -0
- package/dist/chunk-7A7O2JWQ.js +1 -0
- package/dist/chunk-BZ5ASXOL.js +1 -0
- package/dist/chunk-CERTFXCV.js +13 -0
- package/dist/chunk-D2BCHTQR.js +1 -0
- package/dist/chunk-FI23ALVJ.js +1 -0
- package/dist/chunk-GGTPNGFJ.js +1 -0
- package/dist/chunk-H4B72XCJ.js +1 -0
- package/dist/chunk-H6DDIBQ4.js +1 -0
- package/dist/chunk-KDIVA6WD.js +1 -0
- package/dist/chunk-KRXQM65X.js +1 -0
- package/dist/chunk-MCLBHENY.js +1 -0
- package/dist/chunk-MFIRYGHW.js +1 -0
- package/dist/chunk-NKB3KVAB.js +1 -0
- package/dist/chunk-O2NLQBFX.js +1 -0
- package/dist/chunk-OGZFDJ6G.js +1 -0
- package/dist/chunk-OWBO4WKA.js +0 -0
- package/dist/chunk-QB3BZIRA.js +5 -0
- package/dist/chunk-RE4LP46F.js +1 -0
- package/dist/chunk-STFMZJKU.js +14 -0
- package/dist/chunk-SUO5627P.js +1 -0
- package/dist/chunk-TDA4HH54.js +1 -0
- package/dist/chunk-WK3AFPXY.js +1 -0
- package/dist/chunk-YIMRTIBN.js +3 -0
- package/dist/chunk-YNZZYHA4.js +450 -0
- package/dist/chunk-YRLPFZW3.js +1 -0
- package/dist/chunk-ZAOM6PFH.js +1 -0
- package/dist/chunk-ZNCEOSXO.js +1 -0
- package/dist/copy/copy.css +282 -0
- package/dist/copy/index.d.ts +336 -0
- package/dist/copy/index.js +10 -0
- package/dist/data/index.d.ts +375 -0
- package/dist/data/index.js +1 -0
- package/dist/drag/drag.css +360 -0
- package/dist/drag/index.d.ts +379 -0
- package/dist/drag/index.js +18 -0
- package/dist/edit-lock/index.d.ts +354 -0
- package/dist/edit-lock/index.js +1 -0
- package/dist/editor/editor.css +58 -0
- package/dist/editor/index.d.ts +361 -0
- package/dist/editor/index.js +9 -0
- package/dist/fields/fields.css +207 -0
- package/dist/fields/index.d.ts +273 -0
- package/dist/fields/index.js +46 -0
- package/dist/gold/gold.css +196 -0
- package/dist/gold/index.d.ts +280 -0
- package/dist/gold/index.js +1 -0
- package/dist/icons/index.d.ts +474 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +1 -0
- package/dist/markup/index.d.ts +452 -0
- package/dist/markup/index.js +1 -0
- package/dist/menu/index.d.ts +49 -0
- package/dist/menu/index.js +15 -0
- package/dist/menu/menu.css +254 -0
- package/dist/node-ops/index.d.ts +91 -0
- package/dist/node-ops/index.js +1 -0
- package/dist/panel/index.d.ts +1088 -0
- package/dist/panel/index.js +16 -0
- package/dist/panel/panel.css +1460 -0
- package/dist/pick/index.d.ts +153 -0
- package/dist/pick/index.js +14 -0
- package/dist/pick/pick.css +235 -0
- package/dist/plan-DChbUXdS.d.ts +88 -0
- package/dist/rail/index.d.ts +145 -0
- package/dist/rail/index.js +1 -0
- package/dist/rail/rail.css +175 -0
- package/dist/render/index.d.ts +117 -0
- package/dist/render/index.js +5 -0
- package/dist/resolve-D68pb3Bx.d.ts +57 -0
- package/dist/shell/index.d.ts +159 -0
- package/dist/shell/index.js +1 -0
- package/dist/shell/shell.css +122 -0
- package/dist/strings/catalogue.d.ts +141 -0
- package/dist/strings/catalogue.js +1 -0
- package/dist/strings/index.d.ts +56 -0
- package/dist/strings/index.js +2 -0
- package/dist/style-clipboard/index.d.ts +184 -0
- package/dist/style-clipboard/index.js +1 -0
- package/dist/tree/index.d.ts +173 -0
- package/dist/tree/index.js +1 -0
- package/dist/tree/tree.css +618 -0
- package/dist/types-41704JE4.d.ts +112 -0
- package/dist/types-CEqUFH2j.d.ts +129 -0
- package/dist/types-CuNiSnX6.d.ts +204 -0
- package/dist/types-DNrn_w4V.d.ts +88 -0
- package/dist/types-Dy6oR6Z2.d.ts +153 -0
- package/dist/types-pGBXevBU.d.ts +131 -0
- package/dist/useNodeOps-BF0fQsif.d.ts +68 -0
- package/dist/watch-DmasQA61.d.ts +60 -0
- package/dist/wordFit-9B9nqyf3.d.ts +35 -0
- package/dist/words-B2YLaKEr.d.ts +30 -0
- package/dist/words-B87GIFWH.d.ts +86 -0
- package/dist/words-BK-npta-.d.ts +27 -0
- package/dist/words-CD3WADyb.d.ts +51 -0
- package/dist/words-CsRWXkY4.d.ts +129 -0
- package/dist/words-D9ChvbNC.d.ts +52 -0
- package/dist/words-DOhF-4D4.d.ts +35 -0
- package/dist/words-DagJdwIA.d.ts +78 -0
- package/dist/words-DfxEp_RH.d.ts +142 -0
- package/package.json +202 -3
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* efficient-easel/menu.css — the right-click menu box (card 66400.d).
|
|
3
|
+
*
|
|
4
|
+
* THE VALUES ARE NOT OURS. They are the storefront editor's shipped
|
|
5
|
+
* `.sf-blockmenu` / `.sf-blockmenu-item` — `efficient-shop/components/storefront-editor.css`,
|
|
6
|
+
* read at line 1165 — which is the look card 66400.d names for the menu Lewis
|
|
7
|
+
* approved on 2026-08-31. Each `--sf-*` there is already an alias of the
|
|
8
|
+
* matching `--es-*` here (card 66024), so the look is expressed with no new
|
|
9
|
+
* value except the three noted below. Change one only to track a deliberate
|
|
10
|
+
* change THERE. Pinned by `tests/menu-box-css.test.ts`.
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ THREE VALUES ARE UNDER A LIVE QUESTION, and each is behind ONE var so
|
|
13
|
+
* settling it is a three-line change. The drawing Lewis approved that same day
|
|
14
|
+
* (`mockups/editor-add-and-context-v1.html`, its `.ctx` rule) is a FLOATING
|
|
15
|
+
* menu, where `.sf-blockmenu` is an in-flow picker, and it holds different
|
|
16
|
+
* numbers for exactly the three things that difference would move:
|
|
17
|
+
*
|
|
18
|
+
* .sf-blockmenu (shipped) .ctx (the drawing)
|
|
19
|
+
* radius 8px 9px
|
|
20
|
+
* shadow 0 6px 18px rgba(0,0,0,.08) 0 10px 28px rgba(0,0,0,.16)
|
|
21
|
+
* min-width 220px (the admin box's own) 186px
|
|
22
|
+
*
|
|
23
|
+
* This sheet ships `.sf-blockmenu`'s, per the card's own constraint. The
|
|
24
|
+
* question is with the fork that owns the design.
|
|
25
|
+
*
|
|
26
|
+
* LIGHT only — neither editing surface has a dark mode (owner, 2026-08-06), so
|
|
27
|
+
* there is no dark counterpart block here. Do not add one.
|
|
28
|
+
*
|
|
29
|
+
* Import once from a client entry / global stylesheet:
|
|
30
|
+
* import 'efficient-easel/menu.css';
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/* ── this sheet's own vars ──────────────────────────────────────────────────
|
|
34
|
+
ON `.es-editor`, the chrome root, following `rail.css` (which owns
|
|
35
|
+
`--es-rail-*`) and `panel.css` (`--es-row-gap`): the sheet that owns the
|
|
36
|
+
rules owns its tokens, and `shell.css` stays a verbatim mirror of the
|
|
37
|
+
storefront editor's `--sf-*` block. None of these is a shell token.
|
|
38
|
+
|
|
39
|
+
⚠️ The box itself names `es-editor` (see `skin.ts`) — it is portalled to
|
|
40
|
+
`document.body`, outside the editor tree, so this is also where it picks these
|
|
41
|
+
up. Read that note before moving them.
|
|
42
|
+
|
|
43
|
+
⛔ CUSTOM PROPERTIES ONLY IN THIS BLOCK. Never a paint property.
|
|
44
|
+
|
|
45
|
+
`.es-editor` is not this package's own element — it is the class each editor
|
|
46
|
+
puts on ITS OWN chrome root, and the campaign designer puts it on a root that
|
|
47
|
+
lives INSIDE the admin portal's DOM (card 66024 made that the mechanism by
|
|
48
|
+
which the designer is themed; `CampaignDesigner.tsx` adds the class and
|
|
49
|
+
`campaignBlocks.css` aliases its `--cd-*` onto these values). A custom
|
|
50
|
+
property declared here is inert until something reads it. A `background`, a
|
|
51
|
+
`padding`, a `font` — anything that PAINTS — is not: it applies to that root
|
|
52
|
+
the moment this sheet is imported, in every editor that imports it, and in
|
|
53
|
+
the admin portal's own document.
|
|
54
|
+
|
|
55
|
+
Audited on 2026-09-02 across every sheet in this package that opens an
|
|
56
|
+
`.es-editor` block, and the honest number is zero:
|
|
57
|
+
|
|
58
|
+
shell.css 67 declarations, 67 custom, 0 paint
|
|
59
|
+
panel.css 11 declarations, 11 custom, 0 paint
|
|
60
|
+
menu.css 7 declarations, 7 custom, 0 paint
|
|
61
|
+
|
|
62
|
+
⚠️ Nothing enforces this — it is a rule with no test behind it. If you are
|
|
63
|
+
adding a declaration here, you are the check. */
|
|
64
|
+
.es-editor {
|
|
65
|
+
/* HOW FAR THE BOX FLOATS OFF THE PAGE BEHIND IT.
|
|
66
|
+
The drawing's value. `.sf-blockmenu` — the shop's shipped Add-block picker
|
|
67
|
+
— carries `0 6px 18px rgba(0,0,0,.08)`, and this is deliberately heavier:
|
|
68
|
+
that picker sits IN FLOW inside a panel, while this box FLOATS over
|
|
69
|
+
content, and a floating box has to separate itself from whatever is under
|
|
70
|
+
it. The drawing's own header cites `.sf-blockmenu`, so its author had that
|
|
71
|
+
value open and moved off it on purpose.
|
|
72
|
+
This is the CONTEXT half of the split described on `--es-menu-hover-bg`:
|
|
73
|
+
it follows the situation, not the neighbour. */
|
|
74
|
+
--es-menu-shadow: 0 10px 28px rgba(0, 0, 0, 0.16);
|
|
75
|
+
|
|
76
|
+
/* HOW SOFT ITS CORNERS ARE. The drawing's 9px, one more than the in-flow
|
|
77
|
+
picker's 8 — the same floating-vs-in-flow distinction. */
|
|
78
|
+
--es-menu-radius: 9px;
|
|
79
|
+
|
|
80
|
+
/* THE NARROWEST THE BOX MAY GET — a floor, not a width.
|
|
81
|
+
A menu that shrank to its longest label would change width with its
|
|
82
|
+
contents, so a merchant's pointer would land on a different row depending
|
|
83
|
+
on which label happened to be longest. The drawing's 186px. It is also the
|
|
84
|
+
width the flyout measures against when it decides to flip left. */
|
|
85
|
+
--es-menu-min-w: 186px;
|
|
86
|
+
|
|
87
|
+
/* WHAT A ROW DOES UNDER THE POINTER — the one thing a merchant watches move.
|
|
88
|
+
⚠️ THIS ONE DOES NOT FOLLOW THE DRAWING, AND THAT IS DELIBERATE. The
|
|
89
|
+
drawing's `.ctx` washes the row GREY and leaves the text alone. This washes
|
|
90
|
+
the accent tint and turns the text blue, which is `.sf-blockmenu` — the Add
|
|
91
|
+
menu, one keystroke away in the same editor.
|
|
92
|
+
|
|
93
|
+
Owner ruling, 2026-09-02, recorded as a dated amendment in the
|
|
94
|
+
`owner-design-rulings` skill ("the right-click menu hovers BLUE, not the
|
|
95
|
+
drawing's grey"): it was put to him rather than decided, because two menus
|
|
96
|
+
in one editor highlighting differently is a rule-zero failure. His word was
|
|
97
|
+
blue.
|
|
98
|
+
|
|
99
|
+
⛔ DO NOT "RESTORE" THE DRAWING'S GREY. The split from the three values
|
|
100
|
+
above is not an inconsistency, it is the rule:
|
|
101
|
+
|
|
102
|
+
hover interaction grammar -> follows the NEIGHBOUR
|
|
103
|
+
shadow / radius / context -> follows the SITUATION
|
|
104
|
+
min-width (this box floats; the Add
|
|
105
|
+
menu sits in flow)
|
|
106
|
+
|
|
107
|
+
Still behind a var, because that is what made asking him cost nothing. */
|
|
108
|
+
--es-menu-hover-bg: var(--es-accent-tint);
|
|
109
|
+
--es-menu-hover-fg: var(--es-accent);
|
|
110
|
+
|
|
111
|
+
/* A ROW THAT DESTROYS SOMETHING.
|
|
112
|
+
⚠️ The drawing is the ONLY reference for this one — `.sf-blockmenu` has no
|
|
113
|
+
danger row at all, so nothing is being overridden here. Its `#b91c1c` is
|
|
114
|
+
exactly `--es-danger-strong`, so it is read from the token layer rather
|
|
115
|
+
than copied as a literal. */
|
|
116
|
+
--es-menu-danger-fg: var(--es-danger-strong);
|
|
117
|
+
|
|
118
|
+
/* THE SHORTCUT COLUMN'S INK — quieter than a label, quieter than `--es-muted`,
|
|
119
|
+
because a shortcut is a reminder and never the thing being read.
|
|
120
|
+
⚠️ The one value here with no shell token behind it: the drawing's own
|
|
121
|
+
`#b6bcc4`, which is lighter than `--es-disabled` (#9ca3af). Named here
|
|
122
|
+
rather than reaching for a token that is not this colour. */
|
|
123
|
+
--es-menu-shortcut-fg: #b6bcc4;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
/* ── the box ────────────────────────────────────────────────────────────────
|
|
128
|
+
FIXED and lifted on purpose: it hangs OVER the panel it was opened from
|
|
129
|
+
rather than inside it, so a left panel dragged to its 220px minimum — which
|
|
130
|
+
clips its own overflow — cannot cut it off. Measured in Chromium at both
|
|
131
|
+
panel widths; see `tests/fixtures/menu-clipping.html`. */
|
|
132
|
+
.es-menu {
|
|
133
|
+
position: fixed;
|
|
134
|
+
z-index: 9999;
|
|
135
|
+
box-sizing: border-box;
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
gap: 1px;
|
|
139
|
+
min-width: var(--es-menu-min-w);
|
|
140
|
+
/* A box that could grow past the viewport would be unreachable on its far
|
|
141
|
+
side whatever the edge-flip did. */
|
|
142
|
+
max-width: calc(100vw - 16px);
|
|
143
|
+
padding: 4px;
|
|
144
|
+
border: 1px solid var(--es-line);
|
|
145
|
+
border-radius: var(--es-menu-radius);
|
|
146
|
+
background: var(--es-panel);
|
|
147
|
+
box-shadow: var(--es-menu-shadow);
|
|
148
|
+
font-family: var(--es-font);
|
|
149
|
+
/* For `maxHeight`. The flyout is portalled separately BECAUSE of this: a CSS
|
|
150
|
+
overflow that is not `visible` on one axis clips the other too, so an
|
|
151
|
+
in-flow flyout would be cut off at this box's edge. */
|
|
152
|
+
overflow-y: auto;
|
|
153
|
+
overscroll-behavior: contain;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* ── a row ──────────────────────────────────────────────────────────────── */
|
|
157
|
+
.es-menu-item {
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 8px;
|
|
161
|
+
width: 100%;
|
|
162
|
+
padding: 7px 9px;
|
|
163
|
+
border: none;
|
|
164
|
+
border-radius: 6px;
|
|
165
|
+
background: transparent;
|
|
166
|
+
color: var(--es-text);
|
|
167
|
+
font: inherit;
|
|
168
|
+
font-size: 12.5px;
|
|
169
|
+
text-align: left;
|
|
170
|
+
cursor: pointer;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* The one thing a merchant watches move — see `--es-menu-hover-*` above for
|
|
174
|
+
which reference this follows and why it is behind a var. */
|
|
175
|
+
.es-menu-item:hover {
|
|
176
|
+
background: var(--es-menu-hover-bg);
|
|
177
|
+
color: var(--es-menu-hover-fg);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.es-menu-item:focus-visible {
|
|
181
|
+
outline: 2px solid var(--es-accent-ring);
|
|
182
|
+
outline-offset: -2px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.es-menu-item.is-danger {
|
|
186
|
+
color: var(--es-menu-danger-fg);
|
|
187
|
+
}
|
|
188
|
+
/* The drawing gives a danger row no hover of its own: it takes the same grey as
|
|
189
|
+
every other row and KEEPS its red, rather than washing red as well. Stated as
|
|
190
|
+
its own rule because `.es-menu-item:hover` would otherwise repaint the text. */
|
|
191
|
+
.es-menu-item.is-danger:hover {
|
|
192
|
+
background: var(--es-menu-hover-bg);
|
|
193
|
+
color: var(--es-menu-danger-fg);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* ── the parts of a row ─────────────────────────────────────────────────── */
|
|
197
|
+
.es-menu-label {
|
|
198
|
+
flex: 1;
|
|
199
|
+
}
|
|
200
|
+
/* A state name in a flyout can be long; a row in the box never is. */
|
|
201
|
+
.es-menu-label-sub {
|
|
202
|
+
overflow: hidden;
|
|
203
|
+
text-overflow: ellipsis;
|
|
204
|
+
white-space: nowrap;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.es-menu-chevron {
|
|
208
|
+
color: var(--es-icon);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/* The drawing's `.ci` — a fixed 16px column so labels line up whether or not a
|
|
212
|
+
row has a glyph, exactly as the tick column does in a flyout. */
|
|
213
|
+
.es-menu-icon {
|
|
214
|
+
flex: none;
|
|
215
|
+
width: 16px;
|
|
216
|
+
text-align: center;
|
|
217
|
+
color: var(--es-muted);
|
|
218
|
+
font-size: 11px;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* The drawing's `.k`. `margin-left: auto` is what right-aligns it, so it works
|
|
222
|
+
whether or not the row also carries a chevron. */
|
|
223
|
+
.es-menu-shortcut {
|
|
224
|
+
margin-left: auto;
|
|
225
|
+
color: var(--es-menu-shortcut-fg);
|
|
226
|
+
font-size: 11px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* Present on every row of a flyout that uses one, so the labels line up whether
|
|
230
|
+
or not the row is the state you are already on. */
|
|
231
|
+
.es-menu-tick {
|
|
232
|
+
flex: none;
|
|
233
|
+
width: 12px;
|
|
234
|
+
color: var(--es-accent);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/* ── a caption, and a separator ─────────────────────────────────────────── */
|
|
238
|
+
.es-menu-header {
|
|
239
|
+
padding: 6px 9px 4px;
|
|
240
|
+
color: var(--es-muted);
|
|
241
|
+
font-size: 10px;
|
|
242
|
+
font-weight: 500;
|
|
243
|
+
letter-spacing: 0.06em;
|
|
244
|
+
text-transform: uppercase;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* AIR, NOT A LINE (card 66350). The owner has asked for divider hairlines to
|
|
248
|
+
go, more than once, and `tests/panel-no-divider-lines.test.ts` sweeps every
|
|
249
|
+
stylesheet this package ships for a one-sided border — this one included. A
|
|
250
|
+
`'—'` item still separates; it does it with a gap. With the box's own 1px
|
|
251
|
+
`gap` either side, that is 7px between groups against 1px between rows. */
|
|
252
|
+
.es-menu-divider {
|
|
253
|
+
height: 5px;
|
|
254
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export { A as AfterRemove, I as ItemSelector, N as NodeSelection, P as Planned, S as StepBounds, c as canStep, f as fromItemSelector, p as parentStep, a as planDuplicate, b as planMove, d as planPaste, e as planRemove, g as planSetProps, h as planStep, t as toItemSelector } from '../plan-DChbUXdS.js';
|
|
2
|
+
export { C as ClipboardEntry, N as NodeClipboard, a as NodeOps, b as NodeOpsHost, c as createNodeClipboard, u as useNodeOps } from '../useNodeOps-BF0fQsif.js';
|
|
3
|
+
import { ReactNode } from 'react';
|
|
4
|
+
import { E as EditorContextMenuItem } from '../types-pGBXevBU.js';
|
|
5
|
+
import { N as NodeMenuWords } from '../words-DOhF-4D4.js';
|
|
6
|
+
import '../types-41704JE4.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* nodeMenuItems — the right-click rows for a block, ONE list for both editors.
|
|
10
|
+
*
|
|
11
|
+
* The campaign designer (`blockMenuItems`) and the storefront editor
|
|
12
|
+
* (`nodeMenuItems`) each built their own, in the same row type and drawn by the
|
|
13
|
+
* same `EditorContextMenu`, and they had drifted: different group order, the
|
|
14
|
+
* layer flyout in a different group, Copy / Cut / Paste / Rename on one side
|
|
15
|
+
* only, and no pinned-block rule on the storefront. The ORDER and the GROUPS
|
|
16
|
+
* are decided here once:
|
|
17
|
+
*
|
|
18
|
+
* title | pick | make | style | change | remove
|
|
19
|
+
* pick : Select layer (when the host puts the layer flyout here)
|
|
20
|
+
* make : Add inside · Duplicate · Move up · Move down · Copy · Cut · Paste
|
|
21
|
+
* style : the host's Copy style / Paste style rows (efficient-easel/style-clipboard)
|
|
22
|
+
* change : Rename · Hide/Show · the layer flyout (when it goes here) · Up one level
|
|
23
|
+
* remove : Delete
|
|
24
|
+
*
|
|
25
|
+
* WHAT IS OFFERED IS THE HOST'S CALL, BY PRESENCE. A row appears when the host
|
|
26
|
+
* passes its action and is omitted when it does not — never drawn disabled,
|
|
27
|
+
* the rule both editors already follow. So the pinned Header and Footer, a
|
|
28
|
+
* locked block, a read-only campaign are all answered upstream, where the host
|
|
29
|
+
* knows why; a pinned block with nothing to offer gets `pinnedLine`.
|
|
30
|
+
*
|
|
31
|
+
* Every row's label, icon and shortcut can be overridden (`rows`), so each
|
|
32
|
+
* editor keeps its own words ("Hide from email", "Delete section") until the
|
|
33
|
+
* two are asked to agree. Extra host rows go into a named group (`extras`).
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
type NodeMenuRowId = 'layer' | 'addInside' | 'duplicate' | 'moveUp' | 'moveDown' | 'copy' | 'cut' | 'paste' | 'rename' | 'hide' | 'show' | 'upLevel' | 'delete';
|
|
37
|
+
type RowLook = Partial<Pick<EditorContextMenuItem, 'label' | 'icon' | 'shortcut' | 'danger'>> & {
|
|
38
|
+
/** `null` draws the row with no glyph. */
|
|
39
|
+
icon?: ReactNode | null;
|
|
40
|
+
};
|
|
41
|
+
interface NodeMenuOptions {
|
|
42
|
+
/** The menu's caption — the block's name. */
|
|
43
|
+
title: string;
|
|
44
|
+
/** The layer flyout: its entries (built by the host from the ancestor chain) and which group it sits in. */
|
|
45
|
+
layer?: {
|
|
46
|
+
items: EditorContextMenuItem[];
|
|
47
|
+
group?: 'pick' | 'change';
|
|
48
|
+
};
|
|
49
|
+
/** Each present action is offered; an absent one is not. */
|
|
50
|
+
actions: {
|
|
51
|
+
addInside?: () => void;
|
|
52
|
+
duplicate?: () => void;
|
|
53
|
+
moveUp?: () => void;
|
|
54
|
+
moveDown?: () => void;
|
|
55
|
+
copy?: () => void;
|
|
56
|
+
cut?: () => void;
|
|
57
|
+
/** `label` names what is held: "Paste ‹label›". */
|
|
58
|
+
paste?: {
|
|
59
|
+
label: string;
|
|
60
|
+
run: () => void;
|
|
61
|
+
};
|
|
62
|
+
rename?: () => void;
|
|
63
|
+
/** `hidden` says which of Hide / Show to offer. */
|
|
64
|
+
hide?: {
|
|
65
|
+
hidden: boolean;
|
|
66
|
+
run: () => void;
|
|
67
|
+
};
|
|
68
|
+
upLevel?: () => void;
|
|
69
|
+
delete?: () => void;
|
|
70
|
+
};
|
|
71
|
+
/** The host's style rows (styleMenuItems). Offered on pinned blocks too. */
|
|
72
|
+
style?: EditorContextMenuItem[];
|
|
73
|
+
/**
|
|
74
|
+
* The block cannot move or be removed: show this line when nothing else is on
|
|
75
|
+
* offer. It is a CAPTION, like the title — it says why the menu is short, and
|
|
76
|
+
* a row that looked clickable and did nothing would say the opposite.
|
|
77
|
+
*/
|
|
78
|
+
pinnedLine?: string;
|
|
79
|
+
/** Per-row look overrides: label, icon (`null` = none), shortcut, danger. */
|
|
80
|
+
rows?: Partial<Record<NodeMenuRowId, RowLook>>;
|
|
81
|
+
/** Host rows added to the end of a group. */
|
|
82
|
+
extras?: Partial<Record<'pick' | 'make' | 'change' | 'remove', EditorContextMenuItem[]>>;
|
|
83
|
+
/**
|
|
84
|
+
* The rows' own words in the host's language: `useEditorStrings().menu`
|
|
85
|
+
* (0.95.0). Left out, English. A row's `rows` override still wins.
|
|
86
|
+
*/
|
|
87
|
+
words?: NodeMenuWords;
|
|
88
|
+
}
|
|
89
|
+
declare function nodeMenuItems(options: NodeMenuOptions): EditorContextMenuItem[];
|
|
90
|
+
|
|
91
|
+
export { type NodeMenuOptions, type NodeMenuRowId, NodeMenuWords, nodeMenuItems };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DEFAULT_NODE_MENU_WORDS as e}from"../chunk-WK3AFPXY.js";export{canStep,fromItemSelector,parentStep,planDuplicate,planMove,planPaste,planRemove,planSetProps,planStep,toItemSelector,useNodeOps}from"../chunk-D2BCHTQR.js";import{TrashIcon as n,EyeIcon as t,EyeOffIcon as o,RenameIcon as p,PasteIcon as l,CopyIcon as c,MoveDownIcon as s,MoveUpIcon as a,DuplicateIcon as i,AddIcon as r,LayersIcon as u}from"../chunk-YNZZYHA4.js";import"../chunk-KRXQM65X.js";import"../chunk-NKB3KVAB.js";import{jsx as h}from"react/jsx-runtime";function d(){let e=null;const n=/* @__PURE__ */new Set;return{get:()=>e,set(t){e=t;for(const e of[...n])e()},subscribe:e=>(n.add(e),()=>n.delete(e))}}var m={layer:{icon:/* @__PURE__ */h(u,{})},addInside:{icon:/* @__PURE__ */h(r,{})},duplicate:{icon:/* @__PURE__ */h(i,{})},moveUp:{icon:/* @__PURE__ */h(a,{})},moveDown:{icon:/* @__PURE__ */h(s,{})},copy:{icon:/* @__PURE__ */h(c,{}),shortcut:"⌘C"},cut:{icon:/* @__PURE__ */h(c,{}),shortcut:"⌘X"},paste:{icon:/* @__PURE__ */h(l,{}),shortcut:"⌘V"},rename:{icon:/* @__PURE__ */h(p,{})},hide:{icon:/* @__PURE__ */h(o,{})},show:{icon:/* @__PURE__ */h(t,{})},upLevel:{},delete:{icon:/* @__PURE__ */h(n,{}),danger:!0}};function v(n){const{actions:t,rows:o={},extras:p={},words:l=e}=n,c=e=>({...m[e],label:l[e],...o[e]}),s=(e,n,t)=>{const o=c(e),p={label:t??o.label??e,onClick:n};return o.icon&&(p.icon=o.icon),o.shortcut&&(p.shortcut=o.shortcut),o.danger&&(p.danger=!0),p},a=()=>{const e=c("layer"),t={label:e.label??l.layer,onClick:()=>{},children:n.layer.items};return e.icon&&(t.icon=e.icon),t},i=[],r=[],u=[],h=[],d=!!n.layer&&n.layer.items.length>1;if(d&&"pick"===(n.layer.group??"pick")&&i.push(a()),t.addInside&&r.push(s("addInside",t.addInside)),t.duplicate&&r.push(s("duplicate",t.duplicate)),t.moveUp&&r.push(s("moveUp",t.moveUp)),t.moveDown&&r.push(s("moveDown",t.moveDown)),t.copy&&r.push(s("copy",t.copy)),t.cut&&r.push(s("cut",t.cut)),t.paste){const e=c("paste").label??l.paste;r.push(s("paste",t.paste.run,l.pasteNamed({paste:e,label:t.paste.label})))}t.rename&&u.push(s("rename",t.rename)),t.hide&&u.push(t.hide.hidden?s("show",t.hide.run):s("hide",t.hide.run)),d&&"change"===n.layer.group&&u.push(a()),t.upLevel&&u.push(s("upLevel",t.upLevel)),t.delete&&h.push(s("delete",t.delete)),i.push(...p.pick??[]),r.push(...p.make??[]),u.push(...p.change??[]),h.push(...p.remove??[]);const v=[i,r,n.style??[],u,h].filter(e=>e.length>0),g=i.length+r.length+u.length+h.length===0,k=[{label:n.title,header:!0,onClick:()=>{}}];return g&&n.pinnedLine&&k.push({label:n.pinnedLine,header:!0,onClick:()=>{}}),v.forEach((e,t)=>{(t>0||g&&n.pinnedLine)&&k.push({label:"—",onClick:()=>{}}),k.push(...e)}),k}export{d as createNodeClipboard,v as nodeMenuItems};
|