@quario/editor 0.1.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/CHANGELOG.md +39 -0
- package/LICENSE +219 -0
- package/README.md +89 -0
- package/lib/chrome.js +431 -0
- package/lib/document.js +674 -0
- package/lib/history.js +57 -0
- package/lib/index.d.ts +119 -0
- package/lib/index.js +820 -0
- package/lib/rail.js +506 -0
- package/lib/register.d.ts +9 -0
- package/lib/register.js +10 -0
- package/lib/stage.js +654 -0
- package/lib/style.js +85 -0
- package/package.json +77 -0
package/lib/chrome.js
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The editor's chrome: bar, stage and the one right rail, under stable `qe-*`
|
|
3
|
+
* class names, plus the default palette — the `:host` block below is the one
|
|
4
|
+
* place a `--qe-*` fallback is written, and everything else paints from the
|
|
5
|
+
* `--_*` alias it declares (the viewer's discipline, editor.test.js pins it).
|
|
6
|
+
* The fallbacks are `light-dark()`, so the host's `color-scheme` pin paints
|
|
7
|
+
* chrome without a class (ADR 0018): a color scheme reaches chrome only,
|
|
8
|
+
* never the sheet, the report, or the drag furniture.
|
|
9
|
+
*
|
|
10
|
+
* Drag furniture — grips, carets, drop indicators, placeholders — is chrome
|
|
11
|
+
* by ownership but **sheet-relative in colour**: tuned once for legibility
|
|
12
|
+
* against the white sheet and never inverted, or a dark scheme would turn the
|
|
13
|
+
* carets light and vanish them against the paper. Those rules use literal
|
|
14
|
+
* colours on purpose.
|
|
15
|
+
*
|
|
16
|
+
* One token owns the gutter: `--_gutter` sizes both the stage padding left of
|
|
17
|
+
* the sheet and the sheet's own left padding, so a grip can overlap the item
|
|
18
|
+
* by a couple of pixels and the two numbers cannot drift.
|
|
19
|
+
*/
|
|
20
|
+
import { css } from "lit";
|
|
21
|
+
|
|
22
|
+
export let CHROME = css`
|
|
23
|
+
:host {
|
|
24
|
+
display: block;
|
|
25
|
+
color-scheme: light;
|
|
26
|
+
|
|
27
|
+
--_backdrop: var(--qe-backdrop, light-dark(#e9e9eb, #1c1c1e));
|
|
28
|
+
--_text: var(--qe-text, light-dark(#454548, #c7c7cc));
|
|
29
|
+
--_bar: var(--qe-bar, light-dark(#f8f8f9, #2c2c2e));
|
|
30
|
+
--_rail: var(--qe-rail, light-dark(#f8f8f9, #2c2c2e));
|
|
31
|
+
--_border: var(--qe-border, light-dark(#dededf, #3a3a3c));
|
|
32
|
+
--_icon: var(--qe-icon, light-dark(#58585c, #8e8e93));
|
|
33
|
+
--_hover: var(--qe-hover, light-dark(#ebebec, #3a3a3c));
|
|
34
|
+
--_focus: var(--qe-focus, #4a90d9);
|
|
35
|
+
--_field: var(--qe-field, light-dark(#ffffff, #1c1c1e));
|
|
36
|
+
--_error: var(--qe-error, light-dark(#fdeded, #3b1c1c));
|
|
37
|
+
--_error-text: var(--qe-error-text, light-dark(#5f2120, #f5c6c6));
|
|
38
|
+
--_error-border: var(--qe-error-border, light-dark(#f1c5c5, #6b3434));
|
|
39
|
+
--_sheet-shadow: var(
|
|
40
|
+
--qe-sheet-shadow,
|
|
41
|
+
0 1px 2px light-dark(rgba(0, 0, 0, 0.16), rgba(0, 0, 0, 0.5)),
|
|
42
|
+
0 6px 24px light-dark(rgba(0, 0, 0, 0.09), rgba(0, 0, 0, 0.45))
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
/* The gutter's one number: stage chrome left of the sheet, and the
|
|
46
|
+
sheet's own matching padding. */
|
|
47
|
+
--_gutter: 28px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.qe-editor {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
width: 100%;
|
|
54
|
+
height: 100%;
|
|
55
|
+
background: var(--_backdrop);
|
|
56
|
+
color: var(--_text);
|
|
57
|
+
font: 13px/1.4 system-ui, sans-serif;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.qe-bar {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
gap: 6px;
|
|
64
|
+
flex: none;
|
|
65
|
+
padding: 5px 10px;
|
|
66
|
+
background: var(--_bar);
|
|
67
|
+
border-bottom: 1px solid var(--_border);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.qe-button {
|
|
71
|
+
appearance: none;
|
|
72
|
+
border: 0;
|
|
73
|
+
border-radius: 5px;
|
|
74
|
+
background: none;
|
|
75
|
+
color: var(--_icon);
|
|
76
|
+
font: inherit;
|
|
77
|
+
padding: 4px 8px;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.qe-button:hover:not(:disabled) {
|
|
82
|
+
background: var(--_hover);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.qe-button:disabled {
|
|
86
|
+
opacity: 0.4;
|
|
87
|
+
cursor: default;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.qe-button:focus-visible {
|
|
91
|
+
outline: 2px solid var(--_focus);
|
|
92
|
+
outline-offset: 1px;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.qe-button[aria-pressed="true"] {
|
|
96
|
+
background: var(--_hover);
|
|
97
|
+
color: var(--_text);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.qe-crumbs {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 2px;
|
|
104
|
+
min-width: 0;
|
|
105
|
+
overflow: hidden;
|
|
106
|
+
white-space: nowrap;
|
|
107
|
+
margin-right: auto;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.qe-crumb {
|
|
111
|
+
font-family: ui-monospace, monospace;
|
|
112
|
+
font-size: 12px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.qe-crumbs .qe-here {
|
|
116
|
+
color: var(--_text);
|
|
117
|
+
font-weight: 600;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* The body: the stage, then the fixed rail. One breakpoint moves the rail
|
|
121
|
+
below the stage on a narrow host; no docking, no resizing. */
|
|
122
|
+
.qe-body {
|
|
123
|
+
position: relative;
|
|
124
|
+
display: flex;
|
|
125
|
+
flex: 1;
|
|
126
|
+
min-height: 0;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.qe-rail {
|
|
130
|
+
flex: none;
|
|
131
|
+
width: 280px;
|
|
132
|
+
overflow-y: auto;
|
|
133
|
+
background: var(--_rail);
|
|
134
|
+
border-left: 1px solid var(--_border);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@media (max-width: 640px) {
|
|
138
|
+
.qe-body {
|
|
139
|
+
flex-direction: column;
|
|
140
|
+
}
|
|
141
|
+
.qe-rail {
|
|
142
|
+
width: auto;
|
|
143
|
+
max-height: 45%;
|
|
144
|
+
border-left: 0;
|
|
145
|
+
border-top: 1px solid var(--_border);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.qe-section {
|
|
150
|
+
padding: 10px 12px;
|
|
151
|
+
border-bottom: 1px solid var(--_border);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.qe-section h3 {
|
|
155
|
+
margin: 0 0 6px;
|
|
156
|
+
font-size: 11px;
|
|
157
|
+
font-weight: 600;
|
|
158
|
+
letter-spacing: 0.04em;
|
|
159
|
+
text-transform: uppercase;
|
|
160
|
+
color: var(--_icon);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.qe-field {
|
|
164
|
+
display: block;
|
|
165
|
+
margin: 6px 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.qe-field > span {
|
|
169
|
+
display: block;
|
|
170
|
+
font-size: 11px;
|
|
171
|
+
color: var(--_icon);
|
|
172
|
+
margin-bottom: 2px;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.qe-field input[type="text"],
|
|
176
|
+
.qe-field input[type="number"],
|
|
177
|
+
.qe-field select,
|
|
178
|
+
.qe-field textarea {
|
|
179
|
+
width: 100%;
|
|
180
|
+
box-sizing: border-box;
|
|
181
|
+
font: 12px/1.4 ui-monospace, monospace;
|
|
182
|
+
color: var(--_text);
|
|
183
|
+
background: var(--_field);
|
|
184
|
+
border: 1px solid var(--_border);
|
|
185
|
+
border-radius: 4px;
|
|
186
|
+
padding: 3px 6px;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.qe-row {
|
|
190
|
+
display: flex;
|
|
191
|
+
gap: 4px;
|
|
192
|
+
align-items: center;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.qe-inline-error {
|
|
196
|
+
margin: 2px 0 0;
|
|
197
|
+
font-size: 11px;
|
|
198
|
+
color: var(--_error-text);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.qe-inline-error u {
|
|
202
|
+
text-decoration: underline wavy;
|
|
203
|
+
text-underline-offset: 2px;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.qe-problem {
|
|
207
|
+
display: block;
|
|
208
|
+
width: 100%;
|
|
209
|
+
text-align: left;
|
|
210
|
+
font-size: 12px;
|
|
211
|
+
padding: 3px 4px;
|
|
212
|
+
border-radius: 4px;
|
|
213
|
+
border: 0;
|
|
214
|
+
background: none;
|
|
215
|
+
color: var(--_error-text);
|
|
216
|
+
cursor: pointer;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.qe-problem:hover {
|
|
220
|
+
background: var(--_hover);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.qe-group-row {
|
|
224
|
+
display: flex;
|
|
225
|
+
align-items: center;
|
|
226
|
+
gap: 4px;
|
|
227
|
+
padding: 2px 0;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.qe-group-row .qe-name {
|
|
231
|
+
flex: 1;
|
|
232
|
+
font-family: ui-monospace, monospace;
|
|
233
|
+
font-size: 12px;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.qe-panel {
|
|
237
|
+
position: absolute;
|
|
238
|
+
inset: 0 0 auto 0;
|
|
239
|
+
z-index: 3;
|
|
240
|
+
display: flex;
|
|
241
|
+
align-items: baseline;
|
|
242
|
+
gap: 8px;
|
|
243
|
+
padding: 8px 12px;
|
|
244
|
+
background: var(--_error);
|
|
245
|
+
color: var(--_error-text);
|
|
246
|
+
border-bottom: 1px solid var(--_error-border);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.qe-panel code {
|
|
250
|
+
font: 12px ui-monospace, monospace;
|
|
251
|
+
overflow-wrap: anywhere;
|
|
252
|
+
}
|
|
253
|
+
`;
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* The stage and the drag furniture. The stage owns the scroll and the gutter;
|
|
257
|
+
* the sheet stays paper — white by identity, whatever the chrome's scheme.
|
|
258
|
+
* Furniture colours are literal (sheet-relative), never scheme tokens.
|
|
259
|
+
*/
|
|
260
|
+
export let SURFACE = css`
|
|
261
|
+
.qe-stage {
|
|
262
|
+
position: relative;
|
|
263
|
+
flex: 1;
|
|
264
|
+
min-width: 0;
|
|
265
|
+
overflow: auto;
|
|
266
|
+
padding: 24px;
|
|
267
|
+
padding-left: var(--_gutter);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.qe-sheet {
|
|
271
|
+
position: relative;
|
|
272
|
+
box-sizing: border-box;
|
|
273
|
+
margin: 0 auto;
|
|
274
|
+
background: #fff;
|
|
275
|
+
color: #000;
|
|
276
|
+
box-shadow: var(--_sheet-shadow);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* Selection and hover: every instance of the definition lights softly, the
|
|
280
|
+
clicked one strongly, and hover previews what a click would select. On
|
|
281
|
+
the sheet, so the colours are sheet-relative. */
|
|
282
|
+
.qe-peek {
|
|
283
|
+
outline: 1px dashed #74a5d8;
|
|
284
|
+
outline-offset: 1px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.qe-hit {
|
|
288
|
+
outline: 1.5px solid #a5c8ec;
|
|
289
|
+
outline-offset: 1px;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.qe-hit-first {
|
|
293
|
+
outline: 2px solid #2f76c4;
|
|
294
|
+
outline-offset: 1px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/* The overlay above the sheet: grips, carets, placeholders. It spans the
|
|
298
|
+
stage's scrollable content and never takes pointer events itself — each
|
|
299
|
+
piece of furniture opts back in. */
|
|
300
|
+
.qe-overlay {
|
|
301
|
+
position: absolute;
|
|
302
|
+
inset: 0;
|
|
303
|
+
pointer-events: none;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.qe-grip {
|
|
307
|
+
position: absolute;
|
|
308
|
+
box-sizing: border-box;
|
|
309
|
+
display: flex;
|
|
310
|
+
align-items: flex-start;
|
|
311
|
+
justify-content: center;
|
|
312
|
+
padding-top: 1px;
|
|
313
|
+
width: 18px;
|
|
314
|
+
color: #9a9aa0;
|
|
315
|
+
background: none;
|
|
316
|
+
border: 0;
|
|
317
|
+
border-radius: 3px;
|
|
318
|
+
font-size: 12px;
|
|
319
|
+
line-height: 1.2;
|
|
320
|
+
cursor: grab;
|
|
321
|
+
pointer-events: auto;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.qe-grip:hover {
|
|
325
|
+
color: #2f76c4;
|
|
326
|
+
background: rgba(47, 118, 196, 0.08);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.qe-plus {
|
|
330
|
+
position: absolute;
|
|
331
|
+
box-sizing: border-box;
|
|
332
|
+
width: 18px;
|
|
333
|
+
height: 16px;
|
|
334
|
+
padding: 0;
|
|
335
|
+
color: #9a9aa0;
|
|
336
|
+
background: none;
|
|
337
|
+
border: 0;
|
|
338
|
+
border-radius: 3px;
|
|
339
|
+
font-size: 12px;
|
|
340
|
+
line-height: 1;
|
|
341
|
+
cursor: pointer;
|
|
342
|
+
pointer-events: auto;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.qe-plus:hover {
|
|
346
|
+
color: #2f76c4;
|
|
347
|
+
background: rgba(47, 118, 196, 0.08);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.qe-caret {
|
|
351
|
+
position: absolute;
|
|
352
|
+
height: 0;
|
|
353
|
+
border-top: 2px solid #2f76c4;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.qe-caret::before {
|
|
357
|
+
content: "";
|
|
358
|
+
position: absolute;
|
|
359
|
+
left: -3px;
|
|
360
|
+
top: -4px;
|
|
361
|
+
width: 6px;
|
|
362
|
+
height: 6px;
|
|
363
|
+
border-radius: 50%;
|
|
364
|
+
background: #2f76c4;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
.qe-vcaret {
|
|
368
|
+
position: absolute;
|
|
369
|
+
width: 0;
|
|
370
|
+
border-left: 2px solid #2f76c4;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.qe-lifted {
|
|
374
|
+
opacity: 0.45;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.qe-menu {
|
|
378
|
+
position: absolute;
|
|
379
|
+
z-index: 4;
|
|
380
|
+
display: flex;
|
|
381
|
+
flex-direction: column;
|
|
382
|
+
min-width: 110px;
|
|
383
|
+
padding: 3px;
|
|
384
|
+
background: #fff;
|
|
385
|
+
color: #333;
|
|
386
|
+
border: 1px solid #d5d5d8;
|
|
387
|
+
border-radius: 6px;
|
|
388
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.14);
|
|
389
|
+
pointer-events: auto;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.qe-menu button {
|
|
393
|
+
appearance: none;
|
|
394
|
+
border: 0;
|
|
395
|
+
background: none;
|
|
396
|
+
font: 12px system-ui, sans-serif;
|
|
397
|
+
color: inherit;
|
|
398
|
+
text-align: left;
|
|
399
|
+
padding: 4px 8px;
|
|
400
|
+
border-radius: 4px;
|
|
401
|
+
cursor: pointer;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.qe-menu button:hover {
|
|
405
|
+
background: #eef4fb;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/* Placeholders: what the render leaves out, drawn where it would sit. An
|
|
409
|
+
empty band's is an insertion point; a hidden item's shows its template
|
|
410
|
+
source dimmed, so several hidden items are distinguishable. */
|
|
411
|
+
.qe-ghost {
|
|
412
|
+
position: absolute;
|
|
413
|
+
box-sizing: border-box;
|
|
414
|
+
display: flex;
|
|
415
|
+
align-items: center;
|
|
416
|
+
gap: 6px;
|
|
417
|
+
padding: 0 8px;
|
|
418
|
+
font: italic 11px system-ui, sans-serif;
|
|
419
|
+
color: #8a8a90;
|
|
420
|
+
background: rgba(120, 120, 128, 0.06);
|
|
421
|
+
border: 1px dashed #c0c0c6;
|
|
422
|
+
border-radius: 4px;
|
|
423
|
+
pointer-events: auto;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.qe-ghost.qe-hidden-item {
|
|
427
|
+
font-style: normal;
|
|
428
|
+
font-family: ui-monospace, monospace;
|
|
429
|
+
cursor: pointer;
|
|
430
|
+
}
|
|
431
|
+
`;
|