@quillmark/svelte 0.1.1 → 0.3.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/README.md +16 -12
- package/THEMING.md +48 -25
- package/dist/core/address.d.ts +42 -7
- package/dist/core/address.js +49 -21
- package/dist/core/bloom.d.ts +5 -5
- package/dist/core/bloom.js +8 -8
- package/dist/core/codec/anchor.d.ts +1 -1
- package/dist/core/codec/anchor.js +1 -1
- package/dist/core/codec/atoms.d.ts +10 -0
- package/dist/core/codec/atoms.js +78 -0
- package/dist/core/codec/clipboard.d.ts +59 -0
- package/dist/core/codec/clipboard.js +202 -0
- package/dist/core/codec/code.d.ts +1 -1
- package/dist/core/codec/code.js +4 -4
- package/dist/core/codec/decode.d.ts +1 -1
- package/dist/core/codec/decode.js +8 -8
- package/dist/core/codec/encode.d.ts +4 -4
- package/dist/core/codec/encode.js +14 -11
- package/dist/core/codec/field.d.ts +22 -27
- package/dist/core/codec/field.js +33 -32
- package/dist/core/codec/index.js +5 -8
- package/dist/core/codec/inputrules.js +56 -18
- package/dist/core/codec/islands.d.ts +11 -7
- package/dist/core/codec/islands.js +16 -10
- package/dist/core/codec/keymap.d.ts +5 -6
- package/dist/core/codec/keymap.js +8 -7
- package/dist/core/codec/lists.d.ts +3 -3
- package/dist/core/codec/lists.js +32 -13
- package/dist/core/codec/marks.d.ts +1 -1
- package/dist/core/codec/marks.js +1 -1
- package/dist/core/codec/positions.js +1 -1
- package/dist/core/codec/prose.css +266 -228
- package/dist/core/codec/schema.js +4 -4
- package/dist/core/codec/slash.d.ts +39 -41
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-view.d.ts +12 -16
- package/dist/core/codec/table-view.js +488 -292
- package/dist/core/codec/table.d.ts +42 -15
- package/dist/core/codec/table.js +73 -27
- package/dist/core/errors.d.ts +17 -7
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +6 -5
- package/dist/core/lifecycle.d.ts +21 -5
- package/dist/core/lifecycle.js +34 -8
- package/dist/core/rebind.svelte.d.ts +18 -4
- package/dist/core/rebind.svelte.js +30 -12
- package/dist/core/teardown.d.ts +1 -1
- package/dist/core/teardown.js +1 -1
- package/dist/core/theme.css +173 -58
- package/dist/preset/index.css +1 -1
- package/dist/preset/recipes.css +79 -30
- package/dist/preset/scale.css +40 -28
- package/dist/preview/Preview.svelte +22 -19
- package/dist/preview/Preview.svelte.d.ts +8 -8
- package/dist/preview/bridge.d.ts +6 -4
- package/dist/preview/bridge.js +19 -9
- package/dist/preview/controller.d.ts +13 -6
- package/dist/preview/controller.js +8 -5
- package/dist/preview/geometry.d.ts +17 -2
- package/dist/preview/geometry.js +21 -1
- package/dist/preview/index.d.ts +1 -0
- package/dist/preview/index.js +9 -2
- package/dist/preview/overlay.d.ts +2 -1
- package/dist/preview/overlay.js +26 -11
- package/dist/preview/paint.js +19 -17
- package/dist/visual/ArrayField.svelte +103 -83
- package/dist/visual/ArrayField.svelte.d.ts +5 -4
- package/dist/visual/BooleanField.svelte +8 -6
- package/dist/visual/BooleanField.svelte.d.ts +2 -2
- package/dist/visual/Card.svelte +161 -333
- package/dist/visual/Card.svelte.d.ts +5 -4
- package/dist/visual/CardControls.svelte +1 -1
- package/dist/visual/DateField.svelte +19 -19
- package/dist/visual/DateField.svelte.d.ts +3 -3
- package/dist/visual/DiagnosticList.svelte +2 -2
- package/dist/visual/EnumField.svelte +48 -28
- package/dist/visual/EnumField.svelte.d.ts +5 -4
- package/dist/visual/Field.svelte +207 -132
- package/dist/visual/Field.svelte.d.ts +11 -7
- package/dist/visual/FieldHint.svelte +79 -48
- package/dist/visual/FieldHint.svelte.d.ts +1 -1
- package/dist/visual/FieldLabel.svelte +8 -8
- package/dist/visual/FormatPopover.svelte +82 -35
- package/dist/visual/NumberField.svelte +5 -5
- package/dist/visual/NumberField.svelte.d.ts +1 -1
- package/dist/visual/ObjectField.svelte +28 -9
- package/dist/visual/ObjectField.svelte.d.ts +4 -2
- package/dist/visual/ProseArrayElement.svelte +12 -19
- package/dist/visual/ProseArrayElement.svelte.d.ts +1 -2
- package/dist/visual/ProseField.svelte +62 -85
- package/dist/visual/ProseField.svelte.d.ts +14 -17
- package/dist/visual/SlashMenu.svelte +42 -16
- package/dist/visual/TextField.svelte +5 -5
- package/dist/visual/TextField.svelte.d.ts +1 -1
- package/dist/visual/TipsCard.svelte +43 -28
- package/dist/visual/VisualEditor.svelte +18 -19
- package/dist/visual/VisualEditor.svelte.d.ts +2 -3
- package/dist/visual/VisualEditorInner.svelte +251 -184
- package/dist/visual/VisualEditorInner.svelte.d.ts +2 -3
- package/dist/visual/controls.css +85 -38
- package/dist/visual/diagnostics.d.ts +13 -21
- package/dist/visual/diagnostics.js +7 -19
- package/dist/visual/domid.js +3 -3
- package/dist/visual/ext.d.ts +1 -1
- package/dist/visual/ext.js +1 -1
- package/dist/visual/icons/nodes.d.ts +3 -0
- package/dist/visual/icons/nodes.js +2 -1
- package/dist/visual/index.d.ts +1 -0
- package/dist/visual/index.js +10 -3
- package/dist/visual/leaves.d.ts +47 -0
- package/dist/visual/leaves.js +31 -0
- package/dist/visual/links.d.ts +24 -0
- package/dist/visual/links.js +67 -0
- package/dist/visual/props.d.ts +33 -12
- package/dist/visual/signals.d.ts +6 -6
- package/dist/visual/strings.d.ts +14 -19
- package/dist/visual/strings.js +5 -7
- package/dist/visual/structure.d.ts +24 -17
- package/dist/visual/structure.js +8 -8
- package/dist/visual/synced.svelte.d.ts +1 -1
- package/dist/visual/synced.svelte.js +4 -4
- package/dist/visual/tips.d.ts +4 -2
- package/dist/visual/tips.js +7 -4
- package/package.json +2 -2
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { type DocPath } from '../core/address.js';
|
|
2
|
-
import type { ContentHit } from '@quillmark/wasm';
|
|
1
|
+
import { type DocPath, type Landing } from '../core/address.js';
|
|
3
2
|
import type { VisualEditorProps } from './props.js';
|
|
4
3
|
import type { CardId } from './signals.js';
|
|
5
4
|
import type { FieldController } from '../core/codec/index.js';
|
|
6
5
|
import './controls.css';
|
|
7
6
|
declare const VisualEditorInner: import("svelte").Component<VisualEditorProps, {
|
|
8
|
-
setCaret: (
|
|
7
|
+
setCaret: (at: Landing) => Promise<void>;
|
|
9
8
|
getActiveLeaf: () => FieldController | undefined;
|
|
10
9
|
focusField: (field: DocPath) => Promise<void>;
|
|
11
10
|
insertCard: (kind: string, at?: number) => CardId | undefined;
|
package/dist/visual/controls.css
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
markup: a component that carries a shared class without also carrying its rule
|
|
5
5
|
ships unstyled, and nothing raises it.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Not in `core/theme.css`: that file is the derivation (public dials in, the
|
|
8
8
|
private `--_qm-*` scale out) and it mints values. This file mints none; every
|
|
9
9
|
declaration reads a rung, exactly as a component's own block must; `check:style`
|
|
10
10
|
holds that over `.css` too.
|
|
@@ -17,41 +17,42 @@
|
|
|
17
17
|
|
|
18
18
|
@layer qm.chrome {
|
|
19
19
|
/* The themed focus ring in place of the raw UA outline, as a
|
|
20
|
-
|
|
21
|
-
fixes the
|
|
20
|
+
rule rather than a pair of rungs each control assembles. `--_qm-ring`
|
|
21
|
+
fixes the value; which properties draw a ring, and on what state, is the other
|
|
22
22
|
half of the decision, and `check:style` sees a minted literal but never a
|
|
23
23
|
divergent rule. A control opts in by carrying the marker class.
|
|
24
24
|
|
|
25
25
|
Two selectors, because focus lands in two places. Usually on the control
|
|
26
|
-
itself; but the date field's focus lives on a
|
|
26
|
+
itself; but the date field's focus lives on a segment, so it rings the field
|
|
27
27
|
around it: a per-segment ring flickers across the field as the caret walks
|
|
28
28
|
it. That is the only distinction, and this pair is the whole of it. */
|
|
29
29
|
.qm-focus-ring:focus-visible,
|
|
30
30
|
.qm-focus-ring-within:focus-within {
|
|
31
|
-
outline: var(--_qm-ring
|
|
31
|
+
outline: var(--_qm-ring);
|
|
32
32
|
outline-offset: var(--_qm-ring-offset);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
/*
|
|
35
|
+
/* The type half, for both recipe families at once. A UA control inherits neither
|
|
36
36
|
family nor size, so a control or a button that declares none renders in the UA
|
|
37
37
|
face at the UA size: `--qm-font`, a documented dial, stopping short of the
|
|
38
38
|
package's own surfaces with nothing raised, since an absence mints no literal
|
|
39
|
-
for `check:style`. `font: inherit` first, then the
|
|
39
|
+
for `check:style`. `font: inherit` first, then the body rung off the ramp:
|
|
40
40
|
inheriting the size lands the surface on the host page's body size, a rung the
|
|
41
41
|
scale never minted and one a consumer moves by restyling their page rather than
|
|
42
42
|
by turning `--qm-font-size`.
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
One rule over both families rather than the same two declarations in each,
|
|
45
45
|
because the drift a copy invites here is a box and the button beside it reading
|
|
46
|
-
|
|
46
|
+
different rungs, which no gate can see: `check:style`'s type axis holds that
|
|
47
47
|
each side reads a rung, never that both read the same one.
|
|
48
48
|
|
|
49
|
-
The list is wider than either recipe's chrome:
|
|
49
|
+
The list is wider than either recipe's chrome: a prose leaf withholds the box
|
|
50
50
|
and still reads the ramp, so `.qm-prose` is
|
|
51
|
-
here and not below.
|
|
51
|
+
here and not below. The body leaf steps off this rung onto `--_qm-text-paper`
|
|
52
|
+
from its own block (`ProseField`).
|
|
52
53
|
|
|
53
54
|
`font` is a shorthand carrying `line-height`, so each family's leading is
|
|
54
|
-
declared in the rules
|
|
55
|
+
declared in the rules below and would be dropped in silence above them. */
|
|
55
56
|
.qm-control-box,
|
|
56
57
|
.qm-input,
|
|
57
58
|
.qm-prose,
|
|
@@ -63,22 +64,24 @@
|
|
|
63
64
|
|
|
64
65
|
/* A typed value's box (every scalar control and every prose leaf): the text and
|
|
65
66
|
numeric inputs, the array's JSON textarea, the enum trigger, the date field, and
|
|
66
|
-
the inline richtext leaves.
|
|
67
|
+
the inline richtext leaves. One rule, because a
|
|
67
68
|
leaf that agrees with the input beside it "by construction" has to draw the same
|
|
68
69
|
declarations, not a copy of them: five hand-kept copies agree until one is
|
|
69
70
|
edited, and nothing raises it (no literal is minted, so `check:style` stays
|
|
70
71
|
green while a control renders subtly the wrong height).
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
height is
|
|
74
|
-
input beside it agree on height exactly as long as they agree on leading
|
|
75
|
-
is the whole of what "by construction" buys.
|
|
73
|
+
Leading sits on the wide list rather than on the box's own, because a box's
|
|
74
|
+
height is an inset rung plus a line box and nothing else: a leaf and the
|
|
75
|
+
input beside it agree on height exactly as long as they agree on leading and on
|
|
76
|
+
size, which is the whole of what "by construction" buys. The body leaf keeps the
|
|
77
|
+
leading and steps off the size, which costs it nothing: it draws no box and
|
|
78
|
+
stands in no row.
|
|
76
79
|
|
|
77
|
-
|
|
80
|
+
Colour is the trap one property over: `font` does not carry it either, so an
|
|
78
81
|
input or trigger left off this line falls to the UA's own text colour: a second
|
|
79
82
|
black sitting beside the card's ink rather than the rung it renders on.
|
|
80
83
|
`caret-color` is pinned to `currentColor` rather than left at its `auto`
|
|
81
|
-
initial, which resolves the same way: the prose leaf's caret
|
|
84
|
+
initial, which resolves the same way: the prose leaf's caret is its focus
|
|
82
85
|
indicator, the outline dropped in its favour (`ProseField`), so it tracks
|
|
83
86
|
this rule's own ink deliberately. */
|
|
84
87
|
.qm-control-box,
|
|
@@ -88,12 +91,15 @@
|
|
|
88
91
|
color: var(--_qm-ink);
|
|
89
92
|
caret-color: currentColor;
|
|
90
93
|
}
|
|
94
|
+
/* The box is A fill and not an edge (ARCHITECTURE §Styling), and the fill is the
|
|
95
|
+
well rung: a field is a hole cut into the card rather than a plane of its own,
|
|
96
|
+
and with no edge to carry it the step is the whole of what says so. */
|
|
91
97
|
.qm-control-box,
|
|
92
98
|
.qm-input {
|
|
93
|
-
padding: var(--_qm-
|
|
94
|
-
border:
|
|
99
|
+
padding: var(--_qm-inset-control);
|
|
100
|
+
border: none;
|
|
95
101
|
border-radius: var(--_qm-radius-inner);
|
|
96
|
-
background: var(--_qm-surface);
|
|
102
|
+
background: var(--_qm-surface-well);
|
|
97
103
|
}
|
|
98
104
|
/* What a form control adds over the box: it does not fill its row on its own. */
|
|
99
105
|
.qm-input {
|
|
@@ -118,26 +124,26 @@
|
|
|
118
124
|
|
|
119
125
|
`--_qm-tap-min` is WCAG 2.5.8's floor, read rather than re-expressed per
|
|
120
126
|
control: `min-*` is outside every `check:style` axis, so a second expression of
|
|
121
|
-
the same threshold has nothing watching it. `box-sizing` is what makes it a
|
|
127
|
+
the same threshold has nothing watching it. `box-sizing` is what makes it a box
|
|
122
128
|
floor: a `<button>` takes border-box from the UA sheet and a plain element does
|
|
123
129
|
not, so a control on this recipe that is not a button clears the threshold on its
|
|
124
|
-
|
|
130
|
+
content box and stands a padding taller than the button beside it. Declared here,
|
|
125
131
|
the floor means the same height whatever element carries it; and a caller that
|
|
126
132
|
stretches one of these to its row gets a width the padding sits inside.
|
|
127
133
|
|
|
128
134
|
Both button families are named here rather than opting in through a marker: a
|
|
129
|
-
glyph button and an add affordance are not
|
|
135
|
+
glyph button and an add affordance are not sometimes flat, so a class they could
|
|
130
136
|
be built without is a class one of them will eventually miss.
|
|
131
137
|
|
|
132
138
|
The type half is the shared rule above, which both families are named in; what
|
|
133
|
-
diverges is the
|
|
139
|
+
diverges is the leading. Where the box's height is a line box, a button's is
|
|
134
140
|
`--_qm-tap-min`: a label is one line and a glyph is not text at all, so the line
|
|
135
141
|
box collapses onto its content (`1`) and the floor decides, rather than two
|
|
136
142
|
height sources competing. That is the same structural `1` a glyph row takes,
|
|
137
143
|
which is why it is here and not on one family, and it is what keeps a button off
|
|
138
144
|
the host page's leading the way the size rung keeps it off the host page's body
|
|
139
|
-
size. A caller whose button carries a
|
|
140
|
-
own block: the tips foot takes the
|
|
145
|
+
size. A caller whose button carries a label restates the rung it wants from its
|
|
146
|
+
own block: the tips foot takes the label rung, which is that surface's decision,
|
|
141
147
|
not the family's. */
|
|
142
148
|
.qm-icon-btn,
|
|
143
149
|
.qm-add-affordance {
|
|
@@ -172,7 +178,7 @@
|
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
/* An add affordance: the between-card trigger and the array foot's. A pill rather
|
|
175
|
-
than the inner radius, because it
|
|
181
|
+
than the inner radius, because it fills on hover instead of tinting ink: both rest
|
|
176
182
|
unfilled on `--_qm-opacity-idle`, so a hover shifting ink alone would have little
|
|
177
183
|
to shift. The recede ladder itself stays with each caller: it is driven by their
|
|
178
184
|
own hover/focus state. */
|
|
@@ -187,36 +193,77 @@
|
|
|
187
193
|
color: var(--_qm-ink);
|
|
188
194
|
}
|
|
189
195
|
|
|
196
|
+
/* The press floor, for a trigger standing in a line of text or a band of gutter
|
|
197
|
+
rather than in a row of its own, whose drawn box is therefore smaller than the target
|
|
198
|
+
it owes. A target is a region of the screen and a box is paint; separating them is
|
|
199
|
+
what lets both be right at once. The target is the box or the floor, whichever is
|
|
200
|
+
larger, which is what `width: 100%` under a `min-width` says. Unpainted, so it
|
|
201
|
+
enlarges the press and not the mark, and out of the accessibility tree by
|
|
202
|
+
construction: a pseudo-element has no node.
|
|
203
|
+
|
|
204
|
+
The family's floor comes off in the same rule, carrying this class being what giving
|
|
205
|
+
it up means. It sits after both families for that: same specificity, so source order
|
|
206
|
+
decides. */
|
|
207
|
+
.qm-tap-floor {
|
|
208
|
+
position: relative;
|
|
209
|
+
min-width: 0;
|
|
210
|
+
min-height: 0;
|
|
211
|
+
}
|
|
212
|
+
.qm-tap-floor::after {
|
|
213
|
+
content: '';
|
|
214
|
+
position: absolute;
|
|
215
|
+
top: 50%;
|
|
216
|
+
left: 50%;
|
|
217
|
+
width: 100%;
|
|
218
|
+
min-width: var(--_qm-tap-min);
|
|
219
|
+
height: var(--_qm-tap-min);
|
|
220
|
+
transform: translate(-50%, -50%);
|
|
221
|
+
}
|
|
222
|
+
|
|
190
223
|
/* A floating list of choices: the enum's listbox and the card stack's kind menu.
|
|
191
|
-
Both portal into the nearest `[data-qm-root]`, and both are
|
|
224
|
+
Both portal into the nearest `[data-qm-root]`, and both are picked from, so the
|
|
192
225
|
surface (its edge, its inset, its ink) and the item (its pad, its radius, the
|
|
193
226
|
rung a highlight fills with) are one recipe rather than two that agree until one
|
|
194
227
|
is edited. What a caller adds over it is its own: the enum sizes itself off its
|
|
195
228
|
trigger and weights the stored value.
|
|
196
229
|
|
|
197
|
-
`[data-highlighted]` is bits-ui's mark and it is the
|
|
230
|
+
`[data-highlighted]` is bits-ui's mark and it is the only hover lane: an item
|
|
198
231
|
under the pointer and an item under the keyboard cursor are one state to a menu,
|
|
199
232
|
so the primitive marks both and a `:hover` rule beside it would paint a second
|
|
200
|
-
highlight the keyboard cannot reach.
|
|
233
|
+
highlight the keyboard cannot reach. It fills with the accent held rather than
|
|
234
|
+
the hover rung: the mark is a cursor a keyboard drives, so it has to read at a
|
|
235
|
+
glance from across the list, where a hover only has to confirm the pointer
|
|
236
|
+
already under it.
|
|
237
|
+
|
|
238
|
+
The resting fill is the recipe's too: an item drawn on a `<button>` carries a UA
|
|
239
|
+
fill to take back, and a component's scoped block is unlayered, so a caller taking
|
|
240
|
+
it back outranks this layer and erases the highlight with it. Transparent here
|
|
241
|
+
leaves the caller nothing to declare.
|
|
242
|
+
|
|
243
|
+
A floating surface is the one place a hairline is still load-bearing: it hangs
|
|
244
|
+
over content the surface did not choose, so there is no plane under it for a
|
|
245
|
+
tone to step off (ARCHITECTURE §Styling). It takes the raised rung as well, which
|
|
246
|
+
is a real step in dark and nothing in light, where the edge is the whole of it. */
|
|
201
247
|
.qm-menu-surface {
|
|
202
248
|
padding: var(--_qm-space-half);
|
|
203
249
|
border: var(--_qm-border-width) solid var(--_qm-border);
|
|
204
250
|
border-radius: var(--_qm-radius);
|
|
205
|
-
background: var(--_qm-surface);
|
|
251
|
+
background: var(--_qm-surface-raised);
|
|
206
252
|
font-size: var(--_qm-text-body);
|
|
207
253
|
color: var(--_qm-ink);
|
|
208
254
|
}
|
|
209
255
|
.qm-menu-item {
|
|
210
256
|
padding: var(--_qm-space) var(--_qm-space-2);
|
|
211
257
|
border-radius: var(--_qm-radius-inner);
|
|
258
|
+
background: transparent;
|
|
212
259
|
cursor: pointer;
|
|
213
260
|
user-select: none;
|
|
214
261
|
}
|
|
215
262
|
.qm-menu-item[data-highlighted] {
|
|
216
|
-
background: var(--_qm-
|
|
263
|
+
background: var(--_qm-accent-tint);
|
|
217
264
|
}
|
|
218
265
|
|
|
219
|
-
/* A floating surface that is
|
|
266
|
+
/* A floating surface that is read rather than picked from: the selection popover
|
|
220
267
|
and the field label's guidance. The theme surface mixed toward transparent
|
|
221
268
|
behind a backdrop blur, so the page reads faintly through it and the surface
|
|
222
269
|
rung stays the mix base, which is what keeps `--qm-bg` tinting it. The lists
|
|
@@ -224,7 +271,7 @@
|
|
|
224
271
|
row of glyphs does.
|
|
225
272
|
|
|
226
273
|
The raise and the dismissal are the recipe's too, one existence↔absence trip
|
|
227
|
-
taken twice, which is why the class goes on the
|
|
274
|
+
taken twice, which is why the class goes on the presence
|
|
228
275
|
node (bits-ui's own content element, reached through its `child` snippet)
|
|
229
276
|
rather than on a pill inside it: the node's animations are what the primitive
|
|
230
277
|
waits on before unmounting, and an animation one level in is a fade it never
|
|
@@ -244,10 +291,10 @@
|
|
|
244
291
|
-webkit-backdrop-filter: blur(var(--_qm-blur));
|
|
245
292
|
border: var(--_qm-border-width) solid var(--_qm-border);
|
|
246
293
|
border-radius: var(--_qm-radius);
|
|
247
|
-
animation: qm-pop-in var(--_qm-duration-fast) var(--_qm-ease-
|
|
294
|
+
animation: qm-pop-in var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
248
295
|
}
|
|
249
296
|
.qm-popover-surface[data-ending-style] {
|
|
250
|
-
animation: qm-pop-out var(--_qm-duration-fast) var(--_qm-ease-
|
|
297
|
+
animation: qm-pop-out var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
251
298
|
}
|
|
252
299
|
@keyframes qm-pop-in {
|
|
253
300
|
from {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Diagnostic } from '@quillmark/wasm';
|
|
2
|
-
/** A field's routing address
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
2
|
+
/** A field's routing address, and `/core`'s `Addr` structurally: an `Addr` is a
|
|
3
|
+
* positional `FieldKey`, so `addrForFieldPath` is the path→key walk and routing
|
|
4
|
+
* carries no second copy of the grammar. `card` is `undefined` for the main card; a
|
|
5
|
+
* composable card slot is a stable session id (the editor's own bookkeeping) once
|
|
6
|
+
* resolved, or an absolute document-array index straight off a parsed `DocPath`
|
|
7
|
+
* (resolve via {@link resolveCardKey} before merging with id-keyed sources). `field`
|
|
8
|
+
* `undefined` addresses the body (the field-less leaf). */
|
|
7
9
|
export interface FieldKey {
|
|
8
10
|
card?: string | number;
|
|
9
11
|
field?: string;
|
|
@@ -11,18 +13,8 @@ export interface FieldKey {
|
|
|
11
13
|
/** Canonical string key for a `FieldKey`: the routing `Map`'s key space. */
|
|
12
14
|
export declare function fieldKeyToString(k: FieldKey): string;
|
|
13
15
|
/**
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
16
|
-
* document-array index. `/core`'s `addrForFieldPath` IS this walk — an `Addr` is a
|
|
17
|
-
* positional `FieldKey` — so routing reads the one public inverse rather than a
|
|
18
|
-
* second copy of the grammar that drifts from it. `undefined` for a path naming no
|
|
19
|
-
* single commit address (a nested / array-element path, a field-rooted one, a
|
|
20
|
-
* malformed one).
|
|
21
|
-
*/
|
|
22
|
-
export declare function parsePath(path: string): FieldKey | undefined;
|
|
23
|
-
/**
|
|
24
|
-
* Resolve a positional `FieldKey` (an ABSOLUTE document-array index, straight off
|
|
25
|
-
* {@link parsePath}) to the editor's stable-id keying using the LIVE `cardIds`
|
|
16
|
+
* Resolve a positional `FieldKey` (an absolute document-array index, straight off
|
|
17
|
+
* `addrForFieldPath`) to the editor's stable-id keying using the live `cardIds`
|
|
26
18
|
* array: re-resolved fresh on every call (never cached), the same "resolve only
|
|
27
19
|
* at the point of use" discipline `cardIndexOf` applies to writes (VISUAL_EDITOR
|
|
28
20
|
* §"The address is the spine"). A key already id-keyed (`card` a string) or main
|
|
@@ -37,10 +29,10 @@ export interface RoutedDiagnostic {
|
|
|
37
29
|
}
|
|
38
30
|
/**
|
|
39
31
|
* Route a path-keyed producer's raw `Diagnostic[]` (validate / external) to the
|
|
40
|
-
* editor's stable-id keying: the
|
|
41
|
-
* `resolveCardKey` in a single pass. An entry drops rather than mis-routes when
|
|
42
|
-
* carries no `path`, when
|
|
43
|
-
*
|
|
32
|
+
* editor's stable-id keying: the one door producers #1/#3 take, `addrForFieldPath`
|
|
33
|
+
* and `resolveCardKey` in a single pass. An entry drops rather than mis-routes when
|
|
34
|
+
* it carries no `path`, when the path names no single commit address (a nested /
|
|
35
|
+
* array-element one), or when its absolute card index is out of the live `cardIds`.
|
|
44
36
|
*/
|
|
45
37
|
export declare function routeAndResolve(diagnostics: Diagnostic[] | undefined, cardIds: readonly string[]): RoutedDiagnostic[];
|
|
46
38
|
/**
|
|
@@ -4,20 +4,8 @@ export function fieldKeyToString(k) {
|
|
|
4
4
|
return `${k.card ?? 'main'}:${k.field ?? '$body'}`;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
* `
|
|
9
|
-
* document-array index. `/core`'s `addrForFieldPath` IS this walk — an `Addr` is a
|
|
10
|
-
* positional `FieldKey` — so routing reads the one public inverse rather than a
|
|
11
|
-
* second copy of the grammar that drifts from it. `undefined` for a path naming no
|
|
12
|
-
* single commit address (a nested / array-element path, a field-rooted one, a
|
|
13
|
-
* malformed one).
|
|
14
|
-
*/
|
|
15
|
-
export function parsePath(path) {
|
|
16
|
-
return addrForFieldPath(path);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Resolve a positional `FieldKey` (an ABSOLUTE document-array index, straight off
|
|
20
|
-
* {@link parsePath}) to the editor's stable-id keying using the LIVE `cardIds`
|
|
7
|
+
* Resolve a positional `FieldKey` (an absolute document-array index, straight off
|
|
8
|
+
* `addrForFieldPath`) to the editor's stable-id keying using the live `cardIds`
|
|
21
9
|
* array: re-resolved fresh on every call (never cached), the same "resolve only
|
|
22
10
|
* at the point of use" discipline `cardIndexOf` applies to writes (VISUAL_EDITOR
|
|
23
11
|
* §"The address is the spine"). A key already id-keyed (`card` a string) or main
|
|
@@ -32,17 +20,17 @@ export function resolveCardKey(key, cardIds) {
|
|
|
32
20
|
}
|
|
33
21
|
/**
|
|
34
22
|
* Route a path-keyed producer's raw `Diagnostic[]` (validate / external) to the
|
|
35
|
-
* editor's stable-id keying: the
|
|
36
|
-
* `resolveCardKey` in a single pass. An entry drops rather than mis-routes when
|
|
37
|
-
* carries no `path`, when
|
|
38
|
-
*
|
|
23
|
+
* editor's stable-id keying: the one door producers #1/#3 take, `addrForFieldPath`
|
|
24
|
+
* and `resolveCardKey` in a single pass. An entry drops rather than mis-routes when
|
|
25
|
+
* it carries no `path`, when the path names no single commit address (a nested /
|
|
26
|
+
* array-element one), or when its absolute card index is out of the live `cardIds`.
|
|
39
27
|
*/
|
|
40
28
|
export function routeAndResolve(diagnostics, cardIds) {
|
|
41
29
|
const out = [];
|
|
42
30
|
for (const d of diagnostics ?? []) {
|
|
43
31
|
if (!d.path)
|
|
44
32
|
continue;
|
|
45
|
-
const key =
|
|
33
|
+
const key = addrForFieldPath(d.path);
|
|
46
34
|
const resolved = key && resolveCardKey(key, cardIds);
|
|
47
35
|
if (resolved)
|
|
48
36
|
out.push({ key: resolved, diagnostic: d });
|
package/dist/visual/domid.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// A field's DOM ids. The DOM needs three names per field (the control a `<label
|
|
2
2
|
// for>` points at, the label an `aria-labelledby` control points back to, and the
|
|
3
3
|
// parked description an `aria-describedby` reads) and they are derived from the
|
|
4
|
-
// leaf key so the DOM shares the
|
|
4
|
+
// leaf key so the DOM shares the one per-field identity space the registry and
|
|
5
5
|
// diagnostics already collapse to (`fieldKeyToString`), rather than minting a
|
|
6
6
|
// second.
|
|
7
7
|
//
|
|
8
8
|
// `uid` is the editor instance's own (`$props.id()`, stable across SSR and
|
|
9
|
-
// hydration). The leaf-key space is unique per
|
|
9
|
+
// hydration). The leaf-key space is unique per editor, not per document: two
|
|
10
10
|
// `VisualEditor`s on a page both hold `main:subject`, and a duplicate `id` makes
|
|
11
11
|
// `for` resolve to whichever mounted first.
|
|
12
12
|
/**
|
|
13
13
|
* `id` syntax admits far less than a leaf key spends (`main:subject`, `$body`).
|
|
14
|
-
* The escape is
|
|
14
|
+
* The escape is injective (`-` introduces it, so `-` escapes itself), which a
|
|
15
15
|
* plain replace-with-dash is not: `a:b` and `a-b` would collapse onto one id.
|
|
16
16
|
*/
|
|
17
17
|
function escapeId(key) {
|
package/dist/visual/ext.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Document, CardAddr } from '@quillmark/wasm';
|
|
2
2
|
/**
|
|
3
3
|
* Merge `patch` into `$ext.editor` on the card `addr` targets (absent `card` =
|
|
4
|
-
* main). A key whose patch value is `undefined` is
|
|
4
|
+
* main). A key whose patch value is `undefined` is dropped; every other key in the
|
|
5
5
|
* namespace is carried through untouched.
|
|
6
6
|
*
|
|
7
7
|
* **The namespace is the write unit.** `storeExtNamespace` replaces the namespace
|
package/dist/visual/ext.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Merge `patch` into `$ext.editor` on the card `addr` targets (absent `card` =
|
|
3
|
-
* main). A key whose patch value is `undefined` is
|
|
3
|
+
* main). A key whose patch value is `undefined` is dropped; every other key in the
|
|
4
4
|
* namespace is carried through untouched.
|
|
5
5
|
*
|
|
6
6
|
* **The namespace is the write unit.** `storeExtNamespace` replaces the namespace
|
|
@@ -97,6 +97,9 @@ export declare const ICONS: {
|
|
|
97
97
|
}], readonly ["path", {
|
|
98
98
|
readonly d: "m6 6 12 12";
|
|
99
99
|
}]];
|
|
100
|
+
readonly minus: readonly [readonly ["path", {
|
|
101
|
+
readonly d: "M5 12h14";
|
|
102
|
+
}]];
|
|
100
103
|
};
|
|
101
104
|
/** The closed set. A name that is not here is a compile error at the call site,
|
|
102
105
|
* which is what a string key buys over thirteen imported components. */
|
package/dist/visual/index.d.ts
CHANGED
package/dist/visual/index.js
CHANGED
|
@@ -3,19 +3,26 @@
|
|
|
3
3
|
// The federated VisualEditor: a thin Svelte composition over many small editors.
|
|
4
4
|
// Each content leaf is the codec's `createField` prose leaf; scalar fields are
|
|
5
5
|
// form controls; structure/cards are the editor's own. Depends on `/core` and the
|
|
6
|
-
// codec.
|
|
6
|
+
// codec. Relative imports (not `$lib`): svelte-package ships this as-is.
|
|
7
7
|
//
|
|
8
8
|
// The barrel carries what a consumer story wants, and nothing else: a symbol
|
|
9
9
|
// earns its line when a caller outside the package needs it, and grows one when
|
|
10
10
|
// that caller arrives, not before.
|
|
11
|
+
// The theme derivation, which every control on this surface reads through `var()`.
|
|
12
|
+
// Imported at the barrel because a subpath is what a consumer gets: this surface
|
|
13
|
+
// reaches modules inside `core/` and never its entry, so a sheet hanging off that
|
|
14
|
+
// entry arrives only for a consumer importing `/core` for some other reason. The
|
|
15
|
+
// sheet rather than the entry, because the barrel needs the derivation and not
|
|
16
|
+
// `init`. `check:deps` (rule 4) walks this file's own graph and holds the reach.
|
|
17
|
+
import '../core/theme.css';
|
|
11
18
|
export { default as VisualEditor } from './VisualEditor.svelte';
|
|
12
19
|
// The prose leaf: the vanilla mount API a non-Svelte consumer (or a custom
|
|
13
20
|
// surface) builds on.
|
|
14
21
|
export { createField } from '../core/codec/index.js';
|
|
15
|
-
// What the surface
|
|
22
|
+
// What the surface says, and how it words a diagnostic. `strings` is keyed and
|
|
16
23
|
// partial (unset keys take the package's English) and `DEFAULT_VISUAL_STRINGS` is
|
|
17
24
|
// that English, exported so a consumer can compose against it rather than restate
|
|
18
|
-
// it. The empty body's per-
|
|
25
|
+
// it. The empty body's per-card hook is the `bodyPlaceholder` key inside it.
|
|
19
26
|
export { DEFAULT_VISUAL_STRINGS } from './strings.js';
|
|
20
27
|
// The `$ext.editor` write unit. A consumer seeding editor-side chrome
|
|
21
28
|
// state (a card title, the tips channel) goes through this rather than
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { FieldController } from '../core/codec/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* A mounted field's landing handle: focus it, and the element the arrival wash blooms
|
|
4
|
+
* inside ({@link import('../core/bloom.js').bloomInside}).
|
|
5
|
+
*
|
|
6
|
+
* A `FieldController` is one, which is what lets the two lanes share a lookup; `Field`
|
|
7
|
+
* builds the same shape over a form control off the handoff a label click already
|
|
8
|
+
* takes, so `focusField` and a label cannot land in different places.
|
|
9
|
+
*/
|
|
10
|
+
export interface FieldControl {
|
|
11
|
+
focus(): void;
|
|
12
|
+
/**
|
|
13
|
+
* Focus element `index` of a control that has elements, resolving the index to the
|
|
14
|
+
* element's session id at the call; {@link focus}'s own answer for an index past
|
|
15
|
+
* the live list. Absent on every control without elements.
|
|
16
|
+
*
|
|
17
|
+
* The granularity rides the call because the registry stays parent-keyed: a
|
|
18
|
+
* per-element key is positional, in a registry whose doctrine is dodging
|
|
19
|
+
* positional churn.
|
|
20
|
+
*/
|
|
21
|
+
focusElement?(index: number): void;
|
|
22
|
+
readonly el: HTMLElement;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The registry the editor holds and the mounted tree writes into.
|
|
26
|
+
*
|
|
27
|
+
* A lane is dropped by its own owner, which is what the symmetric pairs are for: a
|
|
28
|
+
* card retyped to a kind that declares the same field name at another type swaps the
|
|
29
|
+
* control under one leaf key without remounting `Field`, so the leaving control and
|
|
30
|
+
* the arriving prose leaf both touch that key with no order between them to rely on.
|
|
31
|
+
*/
|
|
32
|
+
export interface LeafRegistry {
|
|
33
|
+
/** A prose leaf, by its controller: the landing handle and the codec seam at once. */
|
|
34
|
+
registerProse(key: string, controller: FieldController): void;
|
|
35
|
+
unregisterProse(key: string): void;
|
|
36
|
+
/** A form control: the landing lane only, having no codec half to offer. */
|
|
37
|
+
registerControl(key: string, control: FieldControl): void;
|
|
38
|
+
unregisterControl(key: string): void;
|
|
39
|
+
/** The landing handle at `key`, whichever lane holds it. */
|
|
40
|
+
control(key: string): FieldControl | undefined;
|
|
41
|
+
/** The codec seam at `key`, `undefined` for a form control. */
|
|
42
|
+
prose(key: string): FieldController | undefined;
|
|
43
|
+
/** Drop everything: the surface going away as a whole, where a leaf's cleanup
|
|
44
|
+
* order relative to the parent's is Svelte's business. */
|
|
45
|
+
clear(): void;
|
|
46
|
+
}
|
|
47
|
+
export declare function createLeafRegistry(): LeafRegistry;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function createLeafRegistry() {
|
|
2
|
+
const controls = new Map();
|
|
3
|
+
const proses = new Map();
|
|
4
|
+
return {
|
|
5
|
+
registerProse(key, controller) {
|
|
6
|
+
proses.set(key, controller);
|
|
7
|
+
},
|
|
8
|
+
unregisterProse(key) {
|
|
9
|
+
proses.delete(key);
|
|
10
|
+
},
|
|
11
|
+
registerControl(key, control) {
|
|
12
|
+
controls.set(key, control);
|
|
13
|
+
},
|
|
14
|
+
unregisterControl(key) {
|
|
15
|
+
controls.delete(key);
|
|
16
|
+
},
|
|
17
|
+
// The prose map is read second: a controller is a control, so a leaf answers a
|
|
18
|
+
// landing without a second entry, and a key the two lanes overlap on during a
|
|
19
|
+
// retype resolves to the form control the tree is currently rendering.
|
|
20
|
+
control(key) {
|
|
21
|
+
return controls.get(key) ?? proses.get(key);
|
|
22
|
+
},
|
|
23
|
+
prose(key) {
|
|
24
|
+
return proses.get(key);
|
|
25
|
+
},
|
|
26
|
+
clear() {
|
|
27
|
+
controls.clear();
|
|
28
|
+
proses.clear();
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Command, EditorState } from 'prosemirror-state';
|
|
2
|
+
/**
|
|
3
|
+
* The href a typed value stands for. A value with no scheme names a host, and
|
|
4
|
+
* stored verbatim it is a relative href resolving against whatever page the editor
|
|
5
|
+
* is embedded in, so it takes `https://`. A bare address takes `mailto:` instead,
|
|
6
|
+
* the host prefix reading `jane@example.com` as `example.com` with `jane` for
|
|
7
|
+
* userinfo — a wrong destination this normalization would itself have minted.
|
|
8
|
+
*
|
|
9
|
+
* A rooted value is left alone, being the spelling that asks for the embedding
|
|
10
|
+
* page, and so is anything already carrying a scheme. `''` for a blank value, which
|
|
11
|
+
* is nothing to apply.
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeHref(raw: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* The href under the selection: the first link mark it touches, `''` where it
|
|
16
|
+
* touches none. A selection may span several links; the prompt holds one value, so
|
|
17
|
+
* the first is both what it seeds with and what an apply writes over the whole
|
|
18
|
+
* range.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hrefInSelection(state: EditorState): string;
|
|
21
|
+
/** Write `href` over the selection, replacing whatever link it already carries. */
|
|
22
|
+
export declare function setLink(href: string): Command;
|
|
23
|
+
/** Drop every link the selection carries. */
|
|
24
|
+
export declare const clearLink: Command;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** A scheme: a letter, then letters, digits, `+`, `-` or `.`, then `:` (RFC 3986). */
|
|
2
|
+
const SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
3
|
+
/** Rooted at the page rather than at a host: an absolute path, a query, a fragment,
|
|
4
|
+
* or a protocol-relative host. Every one of them means relative on purpose. */
|
|
5
|
+
const ROOTED = /^[/#?]/;
|
|
6
|
+
/** A bare mail address: one `@`, no scheme and no path. */
|
|
7
|
+
const ADDRESS = /^[^\s/@]+@[^\s/@]+$/;
|
|
8
|
+
/**
|
|
9
|
+
* The href a typed value stands for. A value with no scheme names a host, and
|
|
10
|
+
* stored verbatim it is a relative href resolving against whatever page the editor
|
|
11
|
+
* is embedded in, so it takes `https://`. A bare address takes `mailto:` instead,
|
|
12
|
+
* the host prefix reading `jane@example.com` as `example.com` with `jane` for
|
|
13
|
+
* userinfo — a wrong destination this normalization would itself have minted.
|
|
14
|
+
*
|
|
15
|
+
* A rooted value is left alone, being the spelling that asks for the embedding
|
|
16
|
+
* page, and so is anything already carrying a scheme. `''` for a blank value, which
|
|
17
|
+
* is nothing to apply.
|
|
18
|
+
*/
|
|
19
|
+
export function normalizeHref(raw) {
|
|
20
|
+
const value = raw.trim();
|
|
21
|
+
if (!value || SCHEME.test(value) || ROOTED.test(value))
|
|
22
|
+
return value;
|
|
23
|
+
return ADDRESS.test(value) ? `mailto:${value}` : `https://${value}`;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The href under the selection: the first link mark it touches, `''` where it
|
|
27
|
+
* touches none. A selection may span several links; the prompt holds one value, so
|
|
28
|
+
* the first is both what it seeds with and what an apply writes over the whole
|
|
29
|
+
* range.
|
|
30
|
+
*/
|
|
31
|
+
export function hrefInSelection(state) {
|
|
32
|
+
const type = state.schema.marks.link;
|
|
33
|
+
if (!type)
|
|
34
|
+
return '';
|
|
35
|
+
const { from, to } = state.selection;
|
|
36
|
+
let href = '';
|
|
37
|
+
state.doc.nodesBetween(from, to, (node) => {
|
|
38
|
+
if (href)
|
|
39
|
+
return false;
|
|
40
|
+
const mark = type.isInSet(node.marks);
|
|
41
|
+
if (mark)
|
|
42
|
+
href = String(mark.attrs.href ?? '');
|
|
43
|
+
});
|
|
44
|
+
return href;
|
|
45
|
+
}
|
|
46
|
+
/** Write `href` over the selection, replacing whatever link it already carries. */
|
|
47
|
+
export function setLink(href) {
|
|
48
|
+
return (state, dispatch) => {
|
|
49
|
+
const type = state.schema.marks.link;
|
|
50
|
+
const { from, to, empty } = state.selection;
|
|
51
|
+
if (!type || empty || !href)
|
|
52
|
+
return false;
|
|
53
|
+
if (dispatch)
|
|
54
|
+
dispatch(state.tr.removeMark(from, to, type).addMark(from, to, type.create({ href })));
|
|
55
|
+
return true;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Drop every link the selection carries. */
|
|
59
|
+
export const clearLink = (state, dispatch) => {
|
|
60
|
+
const type = state.schema.marks.link;
|
|
61
|
+
const { from, to, empty } = state.selection;
|
|
62
|
+
if (!type || empty || !state.doc.rangeHasMark(from, to, type))
|
|
63
|
+
return false;
|
|
64
|
+
if (dispatch)
|
|
65
|
+
dispatch(state.tr.removeMark(from, to, type));
|
|
66
|
+
return true;
|
|
67
|
+
};
|