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,618 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* efficient-easel/tree.css — the Layers tree: one row shape at every depth.
|
|
3
|
+
*
|
|
4
|
+
* EVERY VALUE HERE WAS READ OFF `efficient-shop/components/storefront-editor.css`
|
|
5
|
+
* on origin/main (release 14.24.0, 2026-09-17), where the website editor drew
|
|
6
|
+
* the tree as `.sf-tree` / `.sf-row` / `.sf-subtree` / `.sf-group-label` (the
|
|
7
|
+
* owner's "One Ladder", 2026-09-04). Its `--sf-*` tokens alias the `--es-*`
|
|
8
|
+
* tokens spent here. New with the move: `.es-tree-preview` (0.42.0), and the
|
|
9
|
+
* campaign editor's select button, marks, badge, end mark and plain action (0.44.0).
|
|
10
|
+
*
|
|
11
|
+
* Needs `efficient-easel/shell.css`.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
.es-tree {
|
|
15
|
+
flex: 1;
|
|
16
|
+
overflow-y: auto;
|
|
17
|
+
/* LEFT 8 — the inset a rounded row needs. RIGHT 11 — the room a real,
|
|
18
|
+
space-taking 11px scrollbar takes, so nothing at a row's end sits under
|
|
19
|
+
the thumb. Words inside start on one 11px column down the panel. */
|
|
20
|
+
padding: 0 11px 10px 8px;
|
|
21
|
+
/* THE TREE'S RHYTHM, under the shell's names, at the tree's own density: the
|
|
22
|
+
owner picked 10 between groups and 6 between rows by eye (2026-08-31). They
|
|
23
|
+
are declared HERE, not on the editor root, so the settings panel beside the
|
|
24
|
+
tree keeps its own values for the same names. */
|
|
25
|
+
--es-rhythm-group: 10px;
|
|
26
|
+
--es-rhythm-between: 6px;
|
|
27
|
+
}
|
|
28
|
+
/* Every seam the tree stacks, spelled out: labels and subtrees interleave with
|
|
29
|
+
rows, and a rule that knew only rows would leave those seams to chance. */
|
|
30
|
+
.es-tree > .es-tree-row + .es-tree-row,
|
|
31
|
+
.es-tree > .es-subtree + .es-tree-row {
|
|
32
|
+
margin-top: var(--es-rhythm-between);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.es-tree-group {
|
|
36
|
+
font-size: 10.5px;
|
|
37
|
+
font-weight: 600;
|
|
38
|
+
letter-spacing: 0.07em;
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
color: var(--es-muted);
|
|
41
|
+
padding: var(--es-rhythm-group) 11px var(--es-rhythm-between);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* THE ONLY THING IN THE TREE THAT SAYS DEPTH: 16px of indent and a hairline
|
|
45
|
+
that runs the height of the group. Rows inside sit exactly as far apart as
|
|
46
|
+
rows outside, so the ladder reads as one list at several depths. */
|
|
47
|
+
.es-subtree {
|
|
48
|
+
margin: var(--es-rhythm-between) 0 var(--es-rhythm-between) 16px;
|
|
49
|
+
padding-left: 9px;
|
|
50
|
+
border-left: 1px solid var(--es-line);
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
gap: var(--es-rhythm-between);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.es-tree-row {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: 8px;
|
|
60
|
+
padding: 7px 11px;
|
|
61
|
+
border-radius: var(--es-row-radius);
|
|
62
|
+
cursor: pointer;
|
|
63
|
+
transition: background 0.12s;
|
|
64
|
+
/* Anchors the drop rules and the out-of-flow drag handle. */
|
|
65
|
+
position: relative;
|
|
66
|
+
/* The ground this row is painted on, as a value its children can read: the
|
|
67
|
+
actions' fade must end in the colour really behind the row. Every rule that
|
|
68
|
+
changes the row's background changes this in the same block. */
|
|
69
|
+
--es-row-scrim: var(--es-panel);
|
|
70
|
+
}
|
|
71
|
+
.es-tree-row:hover {
|
|
72
|
+
--es-row-scrim: var(--es-hover);
|
|
73
|
+
background: var(--es-row-scrim);
|
|
74
|
+
}
|
|
75
|
+
.es-tree-row.is-dragging {
|
|
76
|
+
opacity: 0.4;
|
|
77
|
+
}
|
|
78
|
+
.es-tree-row.is-drop-before::before,
|
|
79
|
+
.es-tree-row.is-drop-after::after {
|
|
80
|
+
content: "";
|
|
81
|
+
position: absolute;
|
|
82
|
+
left: 8px;
|
|
83
|
+
right: 8px;
|
|
84
|
+
height: 2px;
|
|
85
|
+
background: var(--es-accent);
|
|
86
|
+
border-radius: 2px;
|
|
87
|
+
pointer-events: none;
|
|
88
|
+
}
|
|
89
|
+
/* THE ONE DROP LINE (0.74.0): centred in the gap, where a seam draws its own —
|
|
90
|
+
so a drop between two rows looks the same whether the pointer is over the
|
|
91
|
+
lower half of one, the gap, or the upper half of the next. */
|
|
92
|
+
.es-tree-row.is-drop-before::before {
|
|
93
|
+
top: calc(-1px - var(--es-rhythm-between) / 2);
|
|
94
|
+
}
|
|
95
|
+
.es-tree-row.is-drop-after::after {
|
|
96
|
+
bottom: calc(-1px - var(--es-rhythm-between) / 2);
|
|
97
|
+
}
|
|
98
|
+
/* An outline, not a border: a border would move every row below by 2px as the
|
|
99
|
+
pointer crossed, which reads as the list flinching. */
|
|
100
|
+
.es-tree-row.is-drop-into {
|
|
101
|
+
outline: 2px solid var(--es-accent);
|
|
102
|
+
outline-offset: -2px;
|
|
103
|
+
border-radius: 6px;
|
|
104
|
+
background: var(--es-accent-tint);
|
|
105
|
+
}
|
|
106
|
+
.es-tree-row.is-selected {
|
|
107
|
+
--es-row-scrim: var(--es-accent-tint);
|
|
108
|
+
background: var(--es-row-scrim);
|
|
109
|
+
box-shadow: inset 2px 0 0 var(--es-accent);
|
|
110
|
+
}
|
|
111
|
+
.es-tree-row.is-selected .es-tree-chip {
|
|
112
|
+
background: var(--es-raised);
|
|
113
|
+
color: var(--es-accent);
|
|
114
|
+
}
|
|
115
|
+
.es-tree-row.is-selected .es-tree-name {
|
|
116
|
+
color: var(--es-accent-text);
|
|
117
|
+
font-weight: 600;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* No ground and no rule: every row carries a glyph, so the glyph is the mark. */
|
|
121
|
+
.es-tree-chip {
|
|
122
|
+
width: 18px;
|
|
123
|
+
height: 18px;
|
|
124
|
+
border-radius: 5px;
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
font-size: 12px;
|
|
129
|
+
flex: none;
|
|
130
|
+
background: transparent;
|
|
131
|
+
color: var(--es-icon);
|
|
132
|
+
}
|
|
133
|
+
.es-tree-chip svg {
|
|
134
|
+
width: 13px;
|
|
135
|
+
height: 13px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* The name's box: what the actions are positioned against, so they cover the
|
|
139
|
+
name's tail and never the caret. */
|
|
140
|
+
.es-tree-name-box {
|
|
141
|
+
position: relative;
|
|
142
|
+
flex: 1;
|
|
143
|
+
min-width: 0;
|
|
144
|
+
display: flex;
|
|
145
|
+
align-items: center;
|
|
146
|
+
}
|
|
147
|
+
/* One size at every depth — 12px / 500, the group pill's size at a row's weight. */
|
|
148
|
+
.es-tree-name {
|
|
149
|
+
flex: 1;
|
|
150
|
+
font-size: 12px;
|
|
151
|
+
font-weight: 500;
|
|
152
|
+
color: var(--es-text);
|
|
153
|
+
white-space: nowrap;
|
|
154
|
+
overflow: hidden;
|
|
155
|
+
text-overflow: ellipsis;
|
|
156
|
+
}
|
|
157
|
+
/* NEW in 0.42.0: the thing's own first words after its type — "Text BACK IN
|
|
158
|
+
STOCK NOW" — quieter than the name, and the first thing to be cut when the
|
|
159
|
+
panel is narrow (it sits inside the name's own ellipsis). */
|
|
160
|
+
.es-tree-preview {
|
|
161
|
+
margin-left: 6px;
|
|
162
|
+
font-weight: 400;
|
|
163
|
+
color: var(--es-muted);
|
|
164
|
+
}
|
|
165
|
+
.es-tree-row.is-selected .es-tree-preview {
|
|
166
|
+
color: var(--es-accent-text);
|
|
167
|
+
font-weight: 400;
|
|
168
|
+
}
|
|
169
|
+
.es-tree-row.is-hidden .es-tree-name {
|
|
170
|
+
color: var(--es-muted);
|
|
171
|
+
text-decoration: line-through;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.es-tree-actions {
|
|
175
|
+
position: absolute;
|
|
176
|
+
right: 0;
|
|
177
|
+
top: 0;
|
|
178
|
+
bottom: 0;
|
|
179
|
+
display: flex;
|
|
180
|
+
align-items: center;
|
|
181
|
+
gap: 2px;
|
|
182
|
+
/* 22px of fade so the name dissolves under the buttons instead of being
|
|
183
|
+
chopped, ending in the ground this row is really painted on. */
|
|
184
|
+
padding-left: 22px;
|
|
185
|
+
background: linear-gradient(to right, transparent 0, var(--es-row-scrim) 22px);
|
|
186
|
+
opacity: 0;
|
|
187
|
+
pointer-events: none;
|
|
188
|
+
transition: opacity 0.12s;
|
|
189
|
+
}
|
|
190
|
+
/* Hover AND focus. Bound to hover alone, a keyboard user who tabs to the trash
|
|
191
|
+
gets it painted onto the name with nothing behind it. */
|
|
192
|
+
.es-tree-row:hover .es-tree-actions,
|
|
193
|
+
.es-tree-row:focus-within .es-tree-actions {
|
|
194
|
+
opacity: 1;
|
|
195
|
+
}
|
|
196
|
+
/* THE STRIP NEVER TAKES THE POINTER — only the buttons in it do, and each arms
|
|
197
|
+
its own as it shows (0.44.1). On a short row the fade covers most of the name,
|
|
198
|
+
and a row that selects from its NAME button (`onSelect`) must still get the
|
|
199
|
+
click: with the strip taking it, a hovered row could not be selected at all.
|
|
200
|
+
A row that selects through its own onClick is unaffected — the click lands on
|
|
201
|
+
the name and bubbles to the row as before. */
|
|
202
|
+
/* A hidden row keeps its eye showing, back in the flow, so it can always be
|
|
203
|
+
un-hidden without a scrim parked over its struck-through name. */
|
|
204
|
+
.es-tree-row.is-hidden .es-tree-actions {
|
|
205
|
+
position: static;
|
|
206
|
+
opacity: 1;
|
|
207
|
+
background: none;
|
|
208
|
+
padding-left: 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.es-tree-del,
|
|
212
|
+
.es-tree-eye {
|
|
213
|
+
width: 22px;
|
|
214
|
+
height: 22px;
|
|
215
|
+
border: none;
|
|
216
|
+
background: transparent;
|
|
217
|
+
border-radius: 5px;
|
|
218
|
+
cursor: pointer;
|
|
219
|
+
display: flex;
|
|
220
|
+
align-items: center;
|
|
221
|
+
justify-content: center;
|
|
222
|
+
padding: 0;
|
|
223
|
+
opacity: 0;
|
|
224
|
+
pointer-events: none;
|
|
225
|
+
flex: none;
|
|
226
|
+
}
|
|
227
|
+
.es-tree-del svg,
|
|
228
|
+
.es-tree-eye svg {
|
|
229
|
+
width: 14px;
|
|
230
|
+
height: 14px;
|
|
231
|
+
}
|
|
232
|
+
.es-tree-del {
|
|
233
|
+
color: var(--es-danger);
|
|
234
|
+
transition: opacity 0.12s, background 0.12s, color 0.12s;
|
|
235
|
+
}
|
|
236
|
+
.es-tree-eye {
|
|
237
|
+
color: var(--es-muted);
|
|
238
|
+
transition: opacity 0.12s, background 0.12s;
|
|
239
|
+
}
|
|
240
|
+
.es-tree-row:hover .es-tree-del,
|
|
241
|
+
.es-tree-row:focus-within .es-tree-del,
|
|
242
|
+
.es-tree-row:hover .es-tree-eye,
|
|
243
|
+
.es-tree-row:focus-within .es-tree-eye {
|
|
244
|
+
opacity: 0.7;
|
|
245
|
+
pointer-events: auto;
|
|
246
|
+
}
|
|
247
|
+
.es-tree-del:hover {
|
|
248
|
+
opacity: 1;
|
|
249
|
+
background: var(--es-danger-tint);
|
|
250
|
+
color: var(--es-danger-strong);
|
|
251
|
+
}
|
|
252
|
+
.es-tree-eye:hover {
|
|
253
|
+
opacity: 1;
|
|
254
|
+
background: var(--es-hover);
|
|
255
|
+
}
|
|
256
|
+
.es-tree-row.is-hidden .es-tree-eye {
|
|
257
|
+
opacity: 1;
|
|
258
|
+
pointer-events: auto;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/* The ONLY drag source and keyboard reorder route. It may be made invisible;
|
|
262
|
+
it may never be made unreachable — opacity only, never display or visibility. */
|
|
263
|
+
.es-tree-handle {
|
|
264
|
+
position: absolute;
|
|
265
|
+
left: 1px;
|
|
266
|
+
top: 50%;
|
|
267
|
+
transform: translateY(-50%);
|
|
268
|
+
color: var(--es-disabled);
|
|
269
|
+
font-family: inherit;
|
|
270
|
+
font-size: 11px;
|
|
271
|
+
line-height: 1;
|
|
272
|
+
letter-spacing: -2px;
|
|
273
|
+
width: 9px;
|
|
274
|
+
flex: none;
|
|
275
|
+
cursor: grab;
|
|
276
|
+
opacity: 0;
|
|
277
|
+
transition: opacity 0.12s;
|
|
278
|
+
padding: 0;
|
|
279
|
+
border: none;
|
|
280
|
+
background: transparent;
|
|
281
|
+
touch-action: none;
|
|
282
|
+
}
|
|
283
|
+
.es-tree-row:hover .es-tree-handle,
|
|
284
|
+
.es-tree-handle:focus-visible {
|
|
285
|
+
opacity: 1;
|
|
286
|
+
}
|
|
287
|
+
.es-tree-handle:active {
|
|
288
|
+
cursor: grabbing;
|
|
289
|
+
}
|
|
290
|
+
.es-tree-handle:focus-visible {
|
|
291
|
+
outline: 2px solid var(--es-accent);
|
|
292
|
+
outline-offset: 1px;
|
|
293
|
+
border-radius: 3px;
|
|
294
|
+
color: var(--es-text-secondary);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* The caret LEADS the row (One Ladder). A row that does not fold holds the
|
|
298
|
+
column open with the spacer, so every glyph below lines up. */
|
|
299
|
+
.es-tree-caret {
|
|
300
|
+
width: 14px;
|
|
301
|
+
height: 14px;
|
|
302
|
+
margin-left: -2px;
|
|
303
|
+
flex: none;
|
|
304
|
+
padding: 0;
|
|
305
|
+
border: none;
|
|
306
|
+
background: transparent;
|
|
307
|
+
border-radius: 4px;
|
|
308
|
+
color: var(--es-muted);
|
|
309
|
+
display: flex;
|
|
310
|
+
align-items: center;
|
|
311
|
+
justify-content: center;
|
|
312
|
+
cursor: pointer;
|
|
313
|
+
}
|
|
314
|
+
.es-tree-caret:hover {
|
|
315
|
+
background: var(--es-hover);
|
|
316
|
+
color: var(--es-text);
|
|
317
|
+
}
|
|
318
|
+
.es-tree-caret-spacer {
|
|
319
|
+
width: 14px;
|
|
320
|
+
margin-left: -2px;
|
|
321
|
+
flex: none;
|
|
322
|
+
}
|
|
323
|
+
.es-tree-chev {
|
|
324
|
+
transition: transform 0.14s;
|
|
325
|
+
}
|
|
326
|
+
.es-tree-chev.is-open {
|
|
327
|
+
transform: rotate(90deg);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ── 0.44.0 — the campaign editor's rows ─────────────────────────────────── */
|
|
331
|
+
/* The name as a button, for keyboard selection. It must not move the row by a
|
|
332
|
+
pixel against a row without one: no chrome, no padding, the same flex run. */
|
|
333
|
+
.es-tree-select {
|
|
334
|
+
all: unset;
|
|
335
|
+
box-sizing: border-box;
|
|
336
|
+
flex: 1;
|
|
337
|
+
min-width: 0;
|
|
338
|
+
display: flex;
|
|
339
|
+
align-items: center;
|
|
340
|
+
gap: 6px;
|
|
341
|
+
cursor: pointer;
|
|
342
|
+
border-radius: 4px;
|
|
343
|
+
}
|
|
344
|
+
.es-tree-select:focus-visible {
|
|
345
|
+
outline: 2px solid var(--es-accent);
|
|
346
|
+
outline-offset: 2px;
|
|
347
|
+
}
|
|
348
|
+
/* With a mark or a badge after it, the name hugs its words so the mark sits
|
|
349
|
+
beside them rather than at the far end. A plain row keeps `flex: 1`. */
|
|
350
|
+
.es-tree-select .es-tree-name,
|
|
351
|
+
.es-tree-name:has(~ .es-tree-mark),
|
|
352
|
+
.es-tree-name:has(~ .es-tree-badge) {
|
|
353
|
+
flex: 0 1 auto;
|
|
354
|
+
}
|
|
355
|
+
/* A named state after the name — quiet, never a control. */
|
|
356
|
+
.es-tree-mark {
|
|
357
|
+
flex: none;
|
|
358
|
+
display: inline-flex;
|
|
359
|
+
color: var(--es-muted);
|
|
360
|
+
}
|
|
361
|
+
.es-tree-mark svg,
|
|
362
|
+
.es-tree-trailing svg {
|
|
363
|
+
width: 13px;
|
|
364
|
+
height: 13px;
|
|
365
|
+
}
|
|
366
|
+
.es-tree-badge {
|
|
367
|
+
flex: none;
|
|
368
|
+
font-size: 10px;
|
|
369
|
+
font-weight: 500;
|
|
370
|
+
font-variant-numeric: tabular-nums;
|
|
371
|
+
color: var(--es-muted);
|
|
372
|
+
background: var(--es-chip-bg);
|
|
373
|
+
border-radius: 4px;
|
|
374
|
+
padding: 1px 4px;
|
|
375
|
+
}
|
|
376
|
+
.es-tree-trailing {
|
|
377
|
+
flex: none;
|
|
378
|
+
display: inline-flex;
|
|
379
|
+
color: var(--es-muted);
|
|
380
|
+
}
|
|
381
|
+
/* Any other row action, in the neutral colour — the eye's twin. */
|
|
382
|
+
.es-tree-act {
|
|
383
|
+
width: 22px;
|
|
384
|
+
height: 22px;
|
|
385
|
+
border: none;
|
|
386
|
+
background: transparent;
|
|
387
|
+
border-radius: 5px;
|
|
388
|
+
cursor: pointer;
|
|
389
|
+
color: var(--es-muted);
|
|
390
|
+
display: flex;
|
|
391
|
+
align-items: center;
|
|
392
|
+
justify-content: center;
|
|
393
|
+
padding: 0;
|
|
394
|
+
opacity: 0;
|
|
395
|
+
pointer-events: none;
|
|
396
|
+
flex: none;
|
|
397
|
+
transition: opacity 0.12s, background 0.12s;
|
|
398
|
+
}
|
|
399
|
+
.es-tree-act svg {
|
|
400
|
+
width: 14px;
|
|
401
|
+
height: 14px;
|
|
402
|
+
}
|
|
403
|
+
.es-tree-row:hover .es-tree-act,
|
|
404
|
+
.es-tree-row:focus-within .es-tree-act {
|
|
405
|
+
opacity: 0.7;
|
|
406
|
+
pointer-events: auto;
|
|
407
|
+
}
|
|
408
|
+
.es-tree-act:hover {
|
|
409
|
+
opacity: 1;
|
|
410
|
+
background: var(--es-hover);
|
|
411
|
+
}
|
|
412
|
+
.es-tree-act:disabled {
|
|
413
|
+
color: var(--es-disabled);
|
|
414
|
+
cursor: default;
|
|
415
|
+
}
|
|
416
|
+
/* A toggle that is ON stays visible at rest, like a hidden row's eye: the state
|
|
417
|
+
has to be readable without hovering. */
|
|
418
|
+
.es-tree-act[aria-pressed="true"] {
|
|
419
|
+
opacity: 1;
|
|
420
|
+
pointer-events: auto;
|
|
421
|
+
color: var(--es-accent);
|
|
422
|
+
}
|
|
423
|
+
/* …which means its strip must show too. Same answer as a hidden row's eye: the
|
|
424
|
+
strip goes back into the flow, with no scrim over the name, and the other
|
|
425
|
+
actions in it still wait for hover. */
|
|
426
|
+
.es-tree-actions:has(.es-tree-act[aria-pressed="true"]) {
|
|
427
|
+
position: static;
|
|
428
|
+
opacity: 1;
|
|
429
|
+
background: none;
|
|
430
|
+
padding-left: 0;
|
|
431
|
+
}
|
|
432
|
+
/* In the flow, the actions still waiting for hover must not hold their width
|
|
433
|
+
open at rest — that would cut the name down to make room for buttons nobody
|
|
434
|
+
can see. They come back when the row is hovered or focus enters it (the name
|
|
435
|
+
button is the row's first tab stop, so the keyboard reaches them). */
|
|
436
|
+
.es-tree-actions:has(.es-tree-act[aria-pressed="true"]) > :not([aria-pressed="true"]) {
|
|
437
|
+
display: none;
|
|
438
|
+
}
|
|
439
|
+
.es-tree-row:hover .es-tree-actions:has(.es-tree-act[aria-pressed="true"]) > :not([aria-pressed="true"]),
|
|
440
|
+
.es-tree-row:focus-within .es-tree-actions:has(.es-tree-act[aria-pressed="true"]) > :not([aria-pressed="true"]) {
|
|
441
|
+
display: flex;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/* A rename box stands in for the name. It must not move the row by a pixel:
|
|
445
|
+
same font and size, no border, no padding of its own. */
|
|
446
|
+
.es-tree-rename {
|
|
447
|
+
flex: 1 1 auto;
|
|
448
|
+
min-width: 0;
|
|
449
|
+
padding: 0;
|
|
450
|
+
border: 0;
|
|
451
|
+
background: transparent;
|
|
452
|
+
font: inherit;
|
|
453
|
+
font-size: 12px;
|
|
454
|
+
font-weight: 500;
|
|
455
|
+
color: inherit;
|
|
456
|
+
outline: none;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* ── Picking a row up (efficient-easel/drag, 0.74.0) ───────────────────────
|
|
460
|
+
The whole row is the handle. It says so four ways, and none of them is a
|
|
461
|
+
target of its own: the grab cursor, a faint ⋮ at its left on hover, a hint
|
|
462
|
+
after 0.7 s, and — while it moves — the row lifted with a shadow. */
|
|
463
|
+
.es-tree-row.is-draggable,
|
|
464
|
+
.es-tree-row.is-draggable .es-tree-select {
|
|
465
|
+
cursor: grab;
|
|
466
|
+
}
|
|
467
|
+
.es-tree-row.is-draggable:active,
|
|
468
|
+
.es-tree-row.is-draggable:active .es-tree-select {
|
|
469
|
+
cursor: grabbing;
|
|
470
|
+
}
|
|
471
|
+
.es-tree-grip {
|
|
472
|
+
position: absolute;
|
|
473
|
+
left: 2px;
|
|
474
|
+
top: 50%;
|
|
475
|
+
transform: translateY(-50%);
|
|
476
|
+
font-size: 12px;
|
|
477
|
+
line-height: 1;
|
|
478
|
+
color: var(--es-disabled);
|
|
479
|
+
opacity: 0;
|
|
480
|
+
transition: opacity 0.12s;
|
|
481
|
+
pointer-events: none;
|
|
482
|
+
}
|
|
483
|
+
.es-tree-row.is-draggable:hover .es-tree-grip {
|
|
484
|
+
opacity: 0.8;
|
|
485
|
+
}
|
|
486
|
+
/* The hint waits 0.7 s on the way in and none on the way out — a delay in the
|
|
487
|
+
transition, not a timer, so nothing re-renders while the pointer rests. */
|
|
488
|
+
.es-tree-hint {
|
|
489
|
+
position: absolute;
|
|
490
|
+
left: 24px;
|
|
491
|
+
top: calc(100% + 4px);
|
|
492
|
+
z-index: 5;
|
|
493
|
+
padding: 3px 7px;
|
|
494
|
+
border-radius: 6px;
|
|
495
|
+
background: var(--es-toast-bg);
|
|
496
|
+
color: var(--es-on-accent);
|
|
497
|
+
font-size: 11px;
|
|
498
|
+
line-height: 1.3;
|
|
499
|
+
white-space: nowrap;
|
|
500
|
+
pointer-events: none;
|
|
501
|
+
opacity: 0;
|
|
502
|
+
transition: opacity 0.1s;
|
|
503
|
+
}
|
|
504
|
+
.es-tree-row.is-draggable:hover .es-tree-hint {
|
|
505
|
+
opacity: 1;
|
|
506
|
+
transition-delay: 0.7s;
|
|
507
|
+
}
|
|
508
|
+
.es-tree-row.is-dragging .es-tree-hint,
|
|
509
|
+
.es-tree-row.is-lifting .es-tree-hint {
|
|
510
|
+
display: none;
|
|
511
|
+
}
|
|
512
|
+
/* On for the instant the browser takes the drag picture: the row that follows
|
|
513
|
+
the pointer is this one, raised. */
|
|
514
|
+
.es-tree-row.is-lifting {
|
|
515
|
+
background: var(--es-raised);
|
|
516
|
+
box-shadow: 0 8px 20px rgba(16, 24, 40, 0.16), 0 2px 6px rgba(16, 24, 40, 0.1);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
/* ── The seam — the gap between two rows, as a place (0.74.0) ───────────────
|
|
520
|
+
A drop between rows lands here, and a host may offer a "+" that adds here.
|
|
521
|
+
IT IS THE GAP: every rule below takes back the space a seam would otherwise
|
|
522
|
+
add, so a list reads exactly the same with seams in it or without. A list's
|
|
523
|
+
gaps are uniform — seams in every gap of it, or in none. */
|
|
524
|
+
.es-tree-seam {
|
|
525
|
+
position: relative;
|
|
526
|
+
z-index: 1;
|
|
527
|
+
flex: none;
|
|
528
|
+
height: var(--es-rhythm-between);
|
|
529
|
+
}
|
|
530
|
+
/* A little more than the gap to aim at, over the rows' own edges. */
|
|
531
|
+
.es-tree-seam::before {
|
|
532
|
+
content: "";
|
|
533
|
+
position: absolute;
|
|
534
|
+
left: 0;
|
|
535
|
+
right: 0;
|
|
536
|
+
top: -4px;
|
|
537
|
+
bottom: -4px;
|
|
538
|
+
}
|
|
539
|
+
.es-tree-seam::after {
|
|
540
|
+
content: "";
|
|
541
|
+
position: absolute;
|
|
542
|
+
left: 8px;
|
|
543
|
+
right: 8px;
|
|
544
|
+
top: calc(50% - 1px);
|
|
545
|
+
height: 2px;
|
|
546
|
+
background: var(--es-accent);
|
|
547
|
+
border-radius: 2px;
|
|
548
|
+
opacity: 0;
|
|
549
|
+
pointer-events: none;
|
|
550
|
+
transition: opacity 0.12s;
|
|
551
|
+
}
|
|
552
|
+
.es-tree-seam.is-drop::after,
|
|
553
|
+
.es-tree-seam.has-add:hover::after,
|
|
554
|
+
.es-tree-seam.has-add:focus-within::after {
|
|
555
|
+
opacity: 1;
|
|
556
|
+
}
|
|
557
|
+
.es-tree-seam-add {
|
|
558
|
+
position: absolute;
|
|
559
|
+
left: 50%;
|
|
560
|
+
top: 50%;
|
|
561
|
+
width: 18px;
|
|
562
|
+
height: 18px;
|
|
563
|
+
margin: -9px 0 0 -9px;
|
|
564
|
+
padding: 0;
|
|
565
|
+
border: none;
|
|
566
|
+
border-radius: 50%;
|
|
567
|
+
background: var(--es-accent);
|
|
568
|
+
color: var(--es-on-accent);
|
|
569
|
+
font: 600 13px/18px var(--es-font);
|
|
570
|
+
cursor: pointer;
|
|
571
|
+
opacity: 0;
|
|
572
|
+
transform: scale(0.7);
|
|
573
|
+
transition: opacity 0.12s, transform 0.12s;
|
|
574
|
+
}
|
|
575
|
+
.es-tree-seam.has-add:hover .es-tree-seam-add,
|
|
576
|
+
.es-tree-seam-add:focus-visible {
|
|
577
|
+
opacity: 1;
|
|
578
|
+
transform: scale(1);
|
|
579
|
+
}
|
|
580
|
+
.es-tree-seam-add:focus-visible {
|
|
581
|
+
outline: 2px solid var(--es-accent);
|
|
582
|
+
outline-offset: 2px;
|
|
583
|
+
}
|
|
584
|
+
/* While something is being dropped, the line alone. */
|
|
585
|
+
.es-tree-seam.is-drop .es-tree-seam-add {
|
|
586
|
+
opacity: 0;
|
|
587
|
+
}
|
|
588
|
+
/* The top level stacks as blocks, and margins there collapse: a seam after a
|
|
589
|
+
subtree, beside a group label, or at an end hands its height back. */
|
|
590
|
+
.es-tree > .es-subtree + .es-tree-seam,
|
|
591
|
+
.es-tree > .es-tree-group + .es-tree-seam,
|
|
592
|
+
.es-tree > .es-tree-seam:last-child {
|
|
593
|
+
margin-top: calc(-1 * var(--es-rhythm-between));
|
|
594
|
+
}
|
|
595
|
+
.es-tree > .es-tree-seam:has(+ .es-tree-group),
|
|
596
|
+
.es-tree > .es-tree-seam:first-child {
|
|
597
|
+
margin-bottom: calc(-1 * var(--es-rhythm-between));
|
|
598
|
+
}
|
|
599
|
+
/* …once: a seam both after a subtree and before a label has already handed its
|
|
600
|
+
height back above. */
|
|
601
|
+
.es-tree > .es-subtree + .es-tree-seam:has(+ .es-tree-group) {
|
|
602
|
+
margin-bottom: 0;
|
|
603
|
+
}
|
|
604
|
+
/* One level down is a flex column with a gap: a seamed list's seams ARE its
|
|
605
|
+
gaps, a nested list keeps the gap-and-margin it had, and the ends reach into
|
|
606
|
+
the list's own margins. */
|
|
607
|
+
.es-subtree:has(> .es-tree-seam) {
|
|
608
|
+
gap: 0;
|
|
609
|
+
}
|
|
610
|
+
.es-subtree:has(> .es-tree-seam) > .es-subtree {
|
|
611
|
+
margin-top: calc(2 * var(--es-rhythm-between));
|
|
612
|
+
}
|
|
613
|
+
.es-subtree > .es-tree-seam:first-child {
|
|
614
|
+
margin-top: calc(-1 * var(--es-rhythm-between));
|
|
615
|
+
}
|
|
616
|
+
.es-subtree > .es-tree-seam:last-child {
|
|
617
|
+
margin-bottom: calc(-1 * var(--es-rhythm-between));
|
|
618
|
+
}
|