@quillmark/svelte 0.21.0 → 0.22.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/NOTICE +6 -7
- package/README.md +1 -1
- package/dist/core/address.d.ts +6 -1
- package/dist/core/address.js +12 -3
- package/dist/core/bloom.d.ts +9 -4
- package/dist/core/bloom.js +18 -49
- package/dist/core/codec/atoms.d.ts +1 -1
- package/dist/core/codec/atoms.js +1 -1
- package/dist/core/codec/blocks.js +4 -2
- package/dist/core/codec/code.d.ts +1 -1
- package/dist/core/codec/code.js +1 -1
- package/dist/core/codec/decode.d.ts +5 -5
- package/dist/core/codec/decode.js +18 -12
- package/dist/core/codec/encode.js +6 -1
- package/dist/core/codec/field.d.ts +15 -10
- package/dist/core/codec/field.js +46 -17
- package/dist/core/codec/index.d.ts +1 -1
- package/dist/core/codec/index.js +2 -2
- package/dist/core/codec/inputrules.js +1 -1
- package/dist/core/codec/lists.d.ts +3 -2
- package/dist/core/codec/lists.js +21 -5
- package/dist/core/codec/nesting.d.ts +20 -0
- package/dist/core/codec/nesting.js +62 -0
- package/dist/core/codec/prose.css +74 -20
- package/dist/core/codec/schema.d.ts +2 -2
- package/dist/core/codec/schema.js +16 -7
- package/dist/core/codec/table-copy.d.ts +17 -0
- package/dist/core/codec/table-copy.js +84 -0
- package/dist/core/codec/table-view.d.ts +1 -7
- package/dist/core/codec/table-view.js +70 -119
- package/dist/core/codec/table.d.ts +2 -9
- package/dist/core/codec/table.js +10 -19
- package/dist/core/codec/tasks.d.ts +19 -0
- package/dist/core/codec/tasks.js +140 -0
- package/dist/core/errors.d.ts +2 -2
- package/dist/visual/ArrayField.svelte +101 -63
- package/dist/visual/ArrayField.svelte.d.ts +0 -2
- package/dist/visual/Card.svelte +9 -3
- package/dist/visual/Card.svelte.d.ts +2 -2
- package/dist/visual/Field.svelte +20 -16
- package/dist/visual/Field.svelte.d.ts +4 -2
- package/dist/visual/FieldLabel.svelte +5 -33
- package/dist/visual/FieldLabel.svelte.d.ts +0 -2
- package/dist/visual/FormatPopover.svelte +54 -73
- package/dist/visual/MatrixField.svelte +18 -12
- package/dist/visual/NumberField.svelte +32 -3
- package/dist/visual/ObjectField.svelte +38 -20
- package/dist/visual/ObjectField.svelte.d.ts +6 -0
- package/dist/visual/ProseField.svelte +10 -13
- package/dist/visual/ProseField.svelte.d.ts +5 -2
- package/dist/visual/ProseValue.svelte +25 -19
- package/dist/visual/ProseValue.svelte.d.ts +4 -4
- package/dist/visual/TextField.svelte +3 -2
- package/dist/visual/TipsCard.svelte +5 -2
- package/dist/visual/VariantField.svelte +1 -1
- package/dist/visual/VariantField.svelte.d.ts +1 -1
- package/dist/visual/VisualEditorInner.svelte +13 -13
- package/dist/visual/controls.css +19 -1
- package/dist/visual/icons/nodes.d.ts +0 -21
- package/dist/visual/icons/nodes.js +1 -7
- package/dist/visual/leaves.d.ts +12 -9
- package/dist/visual/leaves.js +19 -0
- package/dist/visual/strings.d.ts +10 -5
- package/dist/visual/strings.js +16 -9
- package/dist/visual/structure.d.ts +21 -31
- package/dist/visual/structure.js +54 -51
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
A prose leaf the parent commits by value: an element of a `richtext` (fixture
|
|
3
|
-
`keywords`) or `
|
|
3
|
+
`keywords`) or `text` (`authors`, `errata`) array, and a content cell of a subform — an
|
|
4
4
|
`object`'s property, a variant's cell ({@link ObjectField}). None of them is
|
|
5
5
|
`applyChange`-addressable: `Addr.field` is a flat name, so `keywords[0]` and
|
|
6
6
|
`contact.note` have no op address. So this is not a `createField` leaf: it mounts a
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
The content is read, not passed: `reader.getContentAt(addr, path)` decodes through
|
|
21
21
|
the codec the leaf's own declared type names, so what it rests as — the content
|
|
22
|
-
object, a `
|
|
22
|
+
object, a `text` literal, the authored string a transport door left — stops
|
|
23
23
|
being the row's or the cell's business. It is read at mount and again wherever the
|
|
24
24
|
parent's re-derive hands down a `value` that moved, and a read differing from the
|
|
25
25
|
content the leaf last committed or took replaces the view, the gate `createField`
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
it, so the echo replaces nothing and the caret and the history stay.
|
|
29
29
|
|
|
30
30
|
The schema is the declared type's where the parent has room for it: a subform cell
|
|
31
|
-
declaring
|
|
32
|
-
block schema and a `
|
|
31
|
+
declaring `multiline: true` takes the full row ({@link ObjectField}), a `richtext` one
|
|
32
|
+
on the block schema and a `text` one on the plain schema, paragraphs and hard breaks.
|
|
33
33
|
An array element is one textblock whatever it declares, since Enter there is the
|
|
34
34
|
repeater's. There is no slash menu at either width, and no island view.
|
|
35
35
|
|
|
@@ -80,8 +80,8 @@
|
|
|
80
80
|
/** The default an unset leaf holds, where it prints: drawn at the default rung,
|
|
81
81
|
* and handed up whole with the first edit in it, as `createField` takes one. */
|
|
82
82
|
fallback?: Content;
|
|
83
|
-
/** The mark-free schema (a `
|
|
84
|
-
*
|
|
83
|
+
/** The mark-free schema (a `text` leaf): literal text, no formatting, exactly
|
|
84
|
+
* as the field of that type mounts. */
|
|
85
85
|
plaintext?: boolean;
|
|
86
86
|
/** A multi-block schema, for a cell the parent draws at full width: the block
|
|
87
87
|
* schema, or the plain one with `plaintext`. Absent, the leaf is one textblock. */
|
|
@@ -96,8 +96,8 @@
|
|
|
96
96
|
labelledBy?: string;
|
|
97
97
|
/** The parked `description` (FieldLabel) → `aria-describedby`. */
|
|
98
98
|
describedBy?: string;
|
|
99
|
-
/** The empty leaf's ghost, a subform cell's
|
|
100
|
-
*
|
|
99
|
+
/** The empty leaf's ghost, a subform cell's: the `none` an optional cell prints
|
|
100
|
+
* unset. Read per decoration pass. */
|
|
101
101
|
placeholder?: string;
|
|
102
102
|
onChange: (rt: Content) => void;
|
|
103
103
|
/** Raw keydown, for a container whose own keys run through this leaf: the
|
|
@@ -130,9 +130,8 @@
|
|
|
130
130
|
/** Take the caret: what a parent placing focus on this leaf calls. The view's
|
|
131
131
|
* focus, not the element's: a PM view restores its selection, where a bare DOM
|
|
132
132
|
* focus on a contenteditable leaves the caret unplaced. And the reveal beside it,
|
|
133
|
-
* since PM's focus prevents the scroll a
|
|
134
|
-
*
|
|
135
|
-
* landing off screen. */
|
|
133
|
+
* since PM's focus prevents the scroll a form control takes by default — an array
|
|
134
|
+
* whose two item types revealed differently is one row of it landing off screen. */
|
|
136
135
|
export function focus(): void {
|
|
137
136
|
if (!view) return;
|
|
138
137
|
view.focus();
|
|
@@ -157,11 +156,18 @@
|
|
|
157
156
|
view.dispatch(view.state.tr.setSelection(sel).scrollIntoView());
|
|
158
157
|
}
|
|
159
158
|
|
|
159
|
+
$effect(() => {
|
|
160
|
+
void [label, labelledBy, describedBy, placeholder];
|
|
161
|
+
view?.setProps({});
|
|
162
|
+
});
|
|
163
|
+
|
|
160
164
|
function mountView(mount: HTMLDivElement): () => void {
|
|
161
165
|
return untrack(() => {
|
|
162
166
|
const inline = !block;
|
|
163
167
|
const leaf = { inline, plaintext, islands: false };
|
|
164
|
-
|
|
168
|
+
// Read per attribute pass, not captured: an element's name carries its index,
|
|
169
|
+
// which a remove above it moves.
|
|
170
|
+
const names = () => ({ label, labelledBy, describedBy });
|
|
165
171
|
const shown = (stored: Content | undefined): Content => stored ?? fallback ?? emptyContent();
|
|
166
172
|
const stored = content();
|
|
167
173
|
let seen = value;
|
|
@@ -171,8 +177,8 @@
|
|
|
171
177
|
// Which of `aria-label` / `aria-labelledby` wins is the codec's one answer
|
|
172
178
|
// (`proseAttributes`), so a cell carrying a label element and a row carrying
|
|
173
179
|
// none cannot name their regions by different rules.
|
|
174
|
-
const plainNamed = proseAttributes(names) ?? {};
|
|
175
|
-
const heldNamed = heldAttributes(names, heldId);
|
|
180
|
+
const plainNamed = () => proseAttributes(names()) ?? {};
|
|
181
|
+
const heldNamed = () => heldAttributes(names(), heldId);
|
|
176
182
|
const build = (rt: Content): EditorState => {
|
|
177
183
|
// The same keymap and plugin stack a `createField` leaf mounts (shared
|
|
178
184
|
// `proseLeafPlugins`), minus the anchor-position plugin: anchors are dropped on
|
|
@@ -184,8 +190,7 @@
|
|
|
184
190
|
? []
|
|
185
191
|
: proseLeafPlugins(schema, {
|
|
186
192
|
inline,
|
|
187
|
-
placeholder: () => placeholder
|
|
188
|
-
placeholderUntilEdit: true
|
|
193
|
+
placeholder: () => placeholder
|
|
189
194
|
})
|
|
190
195
|
});
|
|
191
196
|
};
|
|
@@ -195,11 +200,12 @@
|
|
|
195
200
|
state: build(reconciler.last),
|
|
196
201
|
editable: () => !held,
|
|
197
202
|
attributes: () => {
|
|
198
|
-
const named = held ? heldNamed : plainNamed;
|
|
203
|
+
const named = held ? heldNamed() : plainNamed();
|
|
199
204
|
return defaulted ? { ...named, 'data-default': '' } : named;
|
|
200
205
|
},
|
|
201
206
|
dispatchTransaction(tr) {
|
|
202
207
|
const next = mounted.state.apply(tr);
|
|
208
|
+
if (next === mounted.state) return;
|
|
203
209
|
const edit = tr.docChanged && !held;
|
|
204
210
|
if (edit) defaulted = false;
|
|
205
211
|
mounted.updateState(next);
|
|
@@ -265,8 +271,8 @@
|
|
|
265
271
|
</script>
|
|
266
272
|
|
|
267
273
|
<!-- `.qm-control-box` (controls.css) is the whole box, so an array of `richtext` and
|
|
268
|
-
an array of `
|
|
269
|
-
like the
|
|
274
|
+
an array of `text` render rows of equal height, and a subform's prose cell measures
|
|
275
|
+
like the form control beside it. No floor: the reset in `core/codec/prose.css` makes one
|
|
270
276
|
line of prose measure one line. Width is the row's or the cell's to give: the leaf
|
|
271
277
|
fills the track it is placed in. -->
|
|
272
278
|
<div class="qm-prose-value qm-control-box qm-focus-ring-within">
|
|
@@ -12,8 +12,8 @@ interface Props {
|
|
|
12
12
|
/** The default an unset leaf holds, where it prints: drawn at the default rung,
|
|
13
13
|
* and handed up whole with the first edit in it, as `createField` takes one. */
|
|
14
14
|
fallback?: Content;
|
|
15
|
-
/** The mark-free schema (a `
|
|
16
|
-
*
|
|
15
|
+
/** The mark-free schema (a `text` leaf): literal text, no formatting, exactly
|
|
16
|
+
* as the field of that type mounts. */
|
|
17
17
|
plaintext?: boolean;
|
|
18
18
|
/** A multi-block schema, for a cell the parent draws at full width: the block
|
|
19
19
|
* schema, or the plain one with `plaintext`. Absent, the leaf is one textblock. */
|
|
@@ -28,8 +28,8 @@ interface Props {
|
|
|
28
28
|
labelledBy?: string;
|
|
29
29
|
/** The parked `description` (FieldLabel) → `aria-describedby`. */
|
|
30
30
|
describedBy?: string;
|
|
31
|
-
/** The empty leaf's ghost, a subform cell's
|
|
32
|
-
*
|
|
31
|
+
/** The empty leaf's ghost, a subform cell's: the `none` an optional cell prints
|
|
32
|
+
* unset. Read per decoration pass. */
|
|
33
33
|
placeholder?: string;
|
|
34
34
|
onChange: (rt: Content) => void;
|
|
35
35
|
/** Raw keydown, for a container whose own keys run through this leaf: the
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
A
|
|
3
|
-
typed `writer.set`, so the
|
|
2
|
+
A text input: the control a field of a type this build does not know falls to.
|
|
3
|
+
Commits every edit live (on input) via the parent's typed `writer.set`, so the
|
|
4
|
+
preview tracks typing.
|
|
4
5
|
|
|
5
6
|
An unset field whose `default:` prints holds that default as its text, at the
|
|
6
7
|
default rung (theme.css): the value it prints, drawn as one and a step off a written
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
{#each tips as _, i (i)}
|
|
70
70
|
<button
|
|
71
71
|
type="button"
|
|
72
|
-
class="qm-tips-dot"
|
|
72
|
+
class="qm-tips-dot qm-focus-ring"
|
|
73
73
|
aria-label={t.strings.tipsDot(i + 1, tips.length)}
|
|
74
74
|
aria-current={i === index}
|
|
75
75
|
onclick={() => (cursor = i)}
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
{/each}
|
|
78
78
|
</div>
|
|
79
79
|
{/if}
|
|
80
|
-
<button type="button" class="qm-icon-btn qm-tips-action" onclick={advance}>
|
|
80
|
+
<button type="button" class="qm-icon-btn qm-tips-action qm-focus-ring" onclick={advance}>
|
|
81
81
|
{#if isLast}
|
|
82
82
|
{t.strings.tipsDismiss} <Icon name="trash-2" />
|
|
83
83
|
{:else}
|
|
@@ -193,6 +193,9 @@
|
|
|
193
193
|
.qm-tips-dot:hover {
|
|
194
194
|
opacity: var(--_qm-opacity-muted);
|
|
195
195
|
}
|
|
196
|
+
.qm-tips-dot:focus-visible {
|
|
197
|
+
opacity: 1;
|
|
198
|
+
}
|
|
196
199
|
.qm-tips-dot[aria-current='true'] {
|
|
197
200
|
opacity: 1;
|
|
198
201
|
}
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
describedBy?: string;
|
|
43
43
|
/** The boundary's nested content read for this field, which the cells take
|
|
44
44
|
* unprefixed: a variant's cell is one key in from the container it rests as, so
|
|
45
|
-
* a `
|
|
45
|
+
* a `text` cell's path is its own name ({@link ObjectField}). */
|
|
46
46
|
contentAt: (path: PathStep[]) => Content | undefined;
|
|
47
47
|
onCommit: (v: Record<string, unknown> | undefined) => void;
|
|
48
48
|
optionAllowed?: (value: string) => boolean;
|
|
@@ -16,7 +16,7 @@ interface Props {
|
|
|
16
16
|
describedBy?: string;
|
|
17
17
|
/** The boundary's nested content read for this field, which the cells take
|
|
18
18
|
* unprefixed: a variant's cell is one key in from the container it rests as, so
|
|
19
|
-
* a `
|
|
19
|
+
* a `text` cell's path is its own name ({@link ObjectField}). */
|
|
20
20
|
contentAt: (path: PathStep[]) => Content | undefined;
|
|
21
21
|
onCommit: (v: Record<string, unknown> | undefined) => void;
|
|
22
22
|
optionAllowed?: (value: string) => boolean;
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
type Landing
|
|
32
32
|
} from '../core/address.js';
|
|
33
33
|
import { errorMessage, reportError } from '../core/errors.js';
|
|
34
|
-
import {
|
|
34
|
+
import { bloom } from '../core/bloom.js';
|
|
35
35
|
import { createLifespan } from '../core/teardown.js';
|
|
36
36
|
import { spacePx } from '../core/rungs.js';
|
|
37
37
|
import type {
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
const card = addr.card;
|
|
221
221
|
return card != null ? { card, field: addr.field } : { field: addr.field };
|
|
222
222
|
}
|
|
223
|
-
function handleFocus(addr: Addr): void {
|
|
223
|
+
function handleFocus(addr: Addr, steps: readonly PathStep[] = []): void {
|
|
224
224
|
const plain = normalize(addr);
|
|
225
225
|
activeAddr = plain;
|
|
226
226
|
activeCardId = cardIdOf(plain);
|
|
@@ -228,7 +228,7 @@
|
|
|
228
228
|
// to at the offset it still names has to report again.
|
|
229
229
|
lastCaretField = undefined;
|
|
230
230
|
lastCaretPos = undefined;
|
|
231
|
-
const field = pathFor(plain);
|
|
231
|
+
const field = pathFor(plain, steps);
|
|
232
232
|
// Both halves or neither: a stale addr names no path and no live card.
|
|
233
233
|
if (field != null && activeCardId != null)
|
|
234
234
|
onActiveLeafChange?.({ field, cardId: activeCardId });
|
|
@@ -245,11 +245,11 @@
|
|
|
245
245
|
return model.cards.map((c) => c.kind);
|
|
246
246
|
}
|
|
247
247
|
/**
|
|
248
|
-
* A leaf's canonical `DocPath
|
|
249
|
-
* array (a stale addr: drop rather than mis-target).
|
|
248
|
+
* A leaf's canonical `DocPath`, `steps` down from the field. `undefined` for an
|
|
249
|
+
* address outside the live card array (a stale addr: drop rather than mis-target).
|
|
250
250
|
*/
|
|
251
|
-
function pathFor(addr: Addr): DocPath | undefined {
|
|
252
|
-
return fieldPathForAddr(addr, addr.card == null ? NO_KINDS : liveKinds());
|
|
251
|
+
function pathFor(addr: Addr, steps: readonly PathStep[] = []): DocPath | undefined {
|
|
252
|
+
return fieldPathForAddr(addr, addr.card == null ? NO_KINDS : liveKinds(), steps);
|
|
253
253
|
}
|
|
254
254
|
// The last place reported, so a caret that did not move is not news. A leaf fires
|
|
255
255
|
// one caret signal per transaction, and a transaction need not have moved the
|
|
@@ -736,10 +736,10 @@
|
|
|
736
736
|
// (where landing a caret changes nothing on screen) or one off-screen, where the
|
|
737
737
|
// browser's focus-scroll moves the page and leaves the caret to be hunted for.
|
|
738
738
|
const box = await land(found, at.granularity === 'segment' ? undefined : at.pos);
|
|
739
|
-
if (span.alive)
|
|
739
|
+
if (span.alive) bloom(box);
|
|
740
740
|
}
|
|
741
741
|
/** The active prose leaf: the formatting popover's observation seam. The active
|
|
742
|
-
* field's
|
|
742
|
+
* field's own leaf where it registered one, else the by-value leaf focused last
|
|
743
743
|
* under it (`leaves.ts`); `undefined` for a form control, which holds no marks to
|
|
744
744
|
* toggle. */
|
|
745
745
|
export function getActiveLeaf(): ActiveProse | undefined {
|
|
@@ -747,7 +747,7 @@
|
|
|
747
747
|
const card = activeAddr.card != null ? activeCardId : undefined;
|
|
748
748
|
const key = fieldKeyToString({ card, field: activeAddr.field });
|
|
749
749
|
const controller = leaves.prose(key);
|
|
750
|
-
if (controller) return { views: controller as FieldController & LeafViews
|
|
750
|
+
if (controller) return { views: controller as FieldController & LeafViews };
|
|
751
751
|
const views = leaves.value(key);
|
|
752
752
|
return views && { views };
|
|
753
753
|
}
|
|
@@ -826,7 +826,7 @@
|
|
|
826
826
|
const found = await revealLeaf(field);
|
|
827
827
|
if (!found) return missed(`no mounted field at ${field}`, field);
|
|
828
828
|
const box = await land(found, undefined);
|
|
829
|
-
if (span.alive)
|
|
829
|
+
if (span.alive) bloom(box);
|
|
830
830
|
}
|
|
831
831
|
/** Seed a card of `kind` and insert it at `at` (default: the end). Returns the new
|
|
832
832
|
* card's session key, or `undefined` when the quill seeds no card of that kind. */
|
|
@@ -995,7 +995,7 @@
|
|
|
995
995
|
{#if kinds.length === 1}
|
|
996
996
|
<button
|
|
997
997
|
type="button"
|
|
998
|
-
class="qm-add-btn qm-add-affordance qm-tap-floor"
|
|
998
|
+
class="qm-add-btn qm-add-affordance qm-tap-floor qm-focus-ring"
|
|
999
999
|
aria-label={marked ? undefined : merged.addCard}
|
|
1000
1000
|
onclick={() => addCard(atIndex, kinds[0], true)}
|
|
1001
1001
|
>{#if marked}{merged.addCard}{:else}<Icon name="plus" class="qm-add-glyph" />{/if}</button
|
|
@@ -1008,7 +1008,7 @@
|
|
|
1008
1008
|
rules below reach it through `:global`. -->
|
|
1009
1009
|
<DropdownMenu.Root>
|
|
1010
1010
|
<DropdownMenu.Trigger
|
|
1011
|
-
class="qm-add-btn qm-add-affordance qm-tap-floor"
|
|
1011
|
+
class="qm-add-btn qm-add-affordance qm-tap-floor qm-focus-ring"
|
|
1012
1012
|
aria-label={marked ? undefined : merged.addCard}
|
|
1013
1013
|
>{#if marked}{merged.addCard}{:else}<Icon
|
|
1014
1014
|
name="plus"
|
package/dist/visual/controls.css
CHANGED
|
@@ -267,6 +267,22 @@
|
|
|
267
267
|
transform: translate(-50%, -50%);
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
+
/* The arrival wash: a plane over the host's box at rest, which a landing plays
|
|
271
|
+
(`core/bloom.ts`). On the host from mount, because WebKit resizes a laid-out subgrid's
|
|
272
|
+
tracks when an out-of-flow box is added to it. */
|
|
273
|
+
:where(.qm-wash) {
|
|
274
|
+
position: relative;
|
|
275
|
+
}
|
|
276
|
+
:where(.qm-wash)::after {
|
|
277
|
+
content: '';
|
|
278
|
+
position: absolute;
|
|
279
|
+
inset: 0;
|
|
280
|
+
border-radius: inherit;
|
|
281
|
+
background: var(--_qm-accent-wash);
|
|
282
|
+
opacity: 0;
|
|
283
|
+
pointer-events: none;
|
|
284
|
+
}
|
|
285
|
+
|
|
270
286
|
/* The capacity ladder: how many tracks a grid of fields steps to, off the width of
|
|
271
287
|
the query container it stands in. One recipe, because three grids read it — a section's
|
|
272
288
|
fields (`Card.svelte`), a subform's properties (`ObjectField`), each over its own
|
|
@@ -311,7 +327,8 @@
|
|
|
311
327
|
highlight the keyboard cannot reach. It fills with the accent held rather than
|
|
312
328
|
the hover rung: the mark is a cursor a keyboard drives, so it has to read at a
|
|
313
329
|
glance from across the list, where a hover only has to confirm the pointer
|
|
314
|
-
already under it.
|
|
330
|
+
already under it. So the mark is the item's whole focus indicator, and the
|
|
331
|
+
outline a focused item would draw beside it is taken off.
|
|
315
332
|
|
|
316
333
|
The resting fill is the recipe's too: an item drawn on a `<button>` carries a UA
|
|
317
334
|
fill to take back, and a scoped block outranks this file, so a caller taking it
|
|
@@ -338,6 +355,7 @@
|
|
|
338
355
|
background: transparent;
|
|
339
356
|
cursor: pointer;
|
|
340
357
|
user-select: none;
|
|
358
|
+
outline: none;
|
|
341
359
|
}
|
|
342
360
|
:where(.qm-menu-item[data-highlighted]) {
|
|
343
361
|
background: var(--_qm-accent-tint);
|
|
@@ -87,27 +87,6 @@ export declare const ICONS: {
|
|
|
87
87
|
}], readonly ["path", {
|
|
88
88
|
readonly d: "M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71";
|
|
89
89
|
}]];
|
|
90
|
-
readonly hash: readonly [readonly ["line", {
|
|
91
|
-
readonly x1: "4";
|
|
92
|
-
readonly x2: "20";
|
|
93
|
-
readonly y1: "9";
|
|
94
|
-
readonly y2: "9";
|
|
95
|
-
}], readonly ["line", {
|
|
96
|
-
readonly x1: "4";
|
|
97
|
-
readonly x2: "20";
|
|
98
|
-
readonly y1: "15";
|
|
99
|
-
readonly y2: "15";
|
|
100
|
-
}], readonly ["line", {
|
|
101
|
-
readonly x1: "10";
|
|
102
|
-
readonly x2: "8";
|
|
103
|
-
readonly y1: "3";
|
|
104
|
-
readonly y2: "21";
|
|
105
|
-
}], readonly ["line", {
|
|
106
|
-
readonly x1: "16";
|
|
107
|
-
readonly x2: "14";
|
|
108
|
-
readonly y1: "3";
|
|
109
|
-
readonly y2: "21";
|
|
110
|
-
}]];
|
|
111
90
|
readonly info: readonly [readonly ["circle", {
|
|
112
91
|
readonly cx: "12";
|
|
113
92
|
readonly cy: "12";
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
//
|
|
6
6
|
// Verbatim from lucide 1.28.0 — the version is stated because a glyph that drifts
|
|
7
7
|
// from upstream is otherwise invisible, and because the notices in `NOTICE` are the
|
|
8
|
-
// ones that release carries (ISC, and MIT for the Feather-derived
|
|
8
|
+
// ones that release carries (ISC, and MIT for the Feather-derived glyphs).
|
|
9
9
|
export const ICONS = {
|
|
10
10
|
'chevron-right': [['path', { d: 'm9 18 6-6-6-6' }]],
|
|
11
11
|
'arrow-right': [
|
|
@@ -45,12 +45,6 @@ export const ICONS = {
|
|
|
45
45
|
['path', { d: 'M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71' }],
|
|
46
46
|
['path', { d: 'M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71' }]
|
|
47
47
|
],
|
|
48
|
-
hash: [
|
|
49
|
-
['line', { x1: '4', x2: '20', y1: '9', y2: '9' }],
|
|
50
|
-
['line', { x1: '4', x2: '20', y1: '15', y2: '15' }],
|
|
51
|
-
['line', { x1: '10', x2: '8', y1: '3', y2: '21' }],
|
|
52
|
-
['line', { x1: '16', x2: '14', y1: '3', y2: '21' }]
|
|
53
|
-
],
|
|
54
48
|
info: [
|
|
55
49
|
['circle', { cx: '12', cy: '12', r: '10' }],
|
|
56
50
|
['path', { d: 'M12 16v-4' }],
|
package/dist/visual/leaves.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ import type { FieldController, LeafViews } from '../core/codec/index.js';
|
|
|
8
8
|
*/
|
|
9
9
|
export type LandingBox = HTMLElement | undefined | Promise<HTMLElement | undefined>;
|
|
10
10
|
/**
|
|
11
|
-
* A mounted field's landing handle: focus it, and the
|
|
12
|
-
*
|
|
11
|
+
* A mounted field's landing handle: focus it, and the `.qm-wash` box the arrival wash
|
|
12
|
+
* plays over ({@link import('../core/bloom.js').bloom}).
|
|
13
13
|
*
|
|
14
14
|
* A `FieldController` is one, which is what lets the two lanes share a lookup; `Field`
|
|
15
15
|
* builds the same shape over a form control off the handoff a label click already
|
|
@@ -71,16 +71,19 @@ export interface LeafRegistry {
|
|
|
71
71
|
clear(): void;
|
|
72
72
|
}
|
|
73
73
|
export declare function createLeafRegistry(): LeafRegistry;
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
* read from and a mark toggled at, and the controller where the leaf is a field's. A
|
|
77
|
-
* by-value leaf has none, its anchors being dropped on the parent's value write, so the
|
|
78
|
-
* anchor verbs the controller carries have nothing to act on there.
|
|
79
|
-
*/
|
|
74
|
+
/** The active prose leaf as the formatting popover reaches it: the views a selection is
|
|
75
|
+
* read from and a mark toggled at. */
|
|
80
76
|
export interface ActiveProse {
|
|
81
77
|
views: LeafViews;
|
|
82
|
-
controller?: FieldController;
|
|
83
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The steps from a field's control box `root` down to the cell holding `target`, the
|
|
81
|
+
* reverse of {@link FieldControl.focusPath}: read off the marker each container rung
|
|
82
|
+
* stamps on the cell it draws, `data-qm-index` on an array's row and `data-qm-prop` on a
|
|
83
|
+
* key step (an object's property, a variant's cell, a matrix's member and an added
|
|
84
|
+
* item's title). `[]` for a target on the field's own control.
|
|
85
|
+
*/
|
|
86
|
+
export declare function stepsTo(target: EventTarget | null, root: Element): PathStep[];
|
|
84
87
|
/** The by-value lane with a field's key bound: what a leaf under that field announces
|
|
85
88
|
* itself through, knowing no key of its own. */
|
|
86
89
|
export interface ValueLeafSeat {
|
package/dist/visual/leaves.js
CHANGED
|
@@ -66,6 +66,25 @@ export function createLeafRegistry() {
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* The steps from a field's control box `root` down to the cell holding `target`, the
|
|
71
|
+
* reverse of {@link FieldControl.focusPath}: read off the marker each container rung
|
|
72
|
+
* stamps on the cell it draws, `data-qm-index` on an array's row and `data-qm-prop` on a
|
|
73
|
+
* key step (an object's property, a variant's cell, a matrix's member and an added
|
|
74
|
+
* item's title). `[]` for a target on the field's own control.
|
|
75
|
+
*/
|
|
76
|
+
export function stepsTo(target, root) {
|
|
77
|
+
const steps = [];
|
|
78
|
+
for (let el = target instanceof Element ? target : null; el && el !== root; el = el.parentElement) {
|
|
79
|
+
const index = el.getAttribute('data-qm-index');
|
|
80
|
+
const key = el.getAttribute('data-qm-prop');
|
|
81
|
+
if (index != null)
|
|
82
|
+
steps.push(Number(index));
|
|
83
|
+
else if (key != null)
|
|
84
|
+
steps.push(key);
|
|
85
|
+
}
|
|
86
|
+
return steps.reverse();
|
|
87
|
+
}
|
|
69
88
|
const SEAT = Symbol('qm-value-leaf');
|
|
70
89
|
/** Seat every by-value leaf under the calling field, at any depth of its containers. */
|
|
71
90
|
export function seatValueLeaves(seat) {
|
package/dist/visual/strings.d.ts
CHANGED
|
@@ -15,13 +15,13 @@ export interface VisualStrings extends TableChromeStrings, SlashStrings {
|
|
|
15
15
|
/** The card-title input's accessible name. */
|
|
16
16
|
cardTitle: string;
|
|
17
17
|
/** The trailing strip's visible words, which are also every strip's accessible
|
|
18
|
-
* name
|
|
18
|
+
* name. One string over
|
|
19
19
|
* one kind and many: the trigger seeds a card, and which kind is the menu's word
|
|
20
20
|
* to say or the schema's to have already settled. */
|
|
21
21
|
addCard: string;
|
|
22
22
|
arrayAdd: string;
|
|
23
23
|
arrayRemove: string;
|
|
24
|
-
/** The drag handle on an `object` row: its tooltip
|
|
24
|
+
/** The drag handle on an `object` row: its tooltip. */
|
|
25
25
|
arrayDrag: string;
|
|
26
26
|
/**
|
|
27
27
|
* A row control's accessible name, the action and the row it acts on: `Remove
|
|
@@ -59,8 +59,6 @@ export interface VisualStrings extends TableChromeStrings, SlashStrings {
|
|
|
59
59
|
/** The date field's toggle, pressed while the field holds `today`: the render
|
|
60
60
|
* date rather than a written one. */
|
|
61
61
|
dateToday: string;
|
|
62
|
-
/** The required marker's accessible name; the glyph itself is a `*`. */
|
|
63
|
-
fieldRequired: string;
|
|
64
62
|
/** What an unset optional cell (`t?`) ghosts at rest: the `none` it prints
|
|
65
63
|
* unanswered, in the product's words. */
|
|
66
64
|
optionalGhost: string;
|
|
@@ -75,7 +73,8 @@ export interface VisualStrings extends TableChromeStrings, SlashStrings {
|
|
|
75
73
|
formatStrikethrough: string;
|
|
76
74
|
formatCode: string;
|
|
77
75
|
formatLink: string;
|
|
78
|
-
/** The anchor button's accessible name.
|
|
76
|
+
/** The anchor button's accessible name. The popover withholds the button, so
|
|
77
|
+
* nothing draws this or the title below. */
|
|
79
78
|
formatAnchor: string;
|
|
80
79
|
/** Its hover title, which says what an anchor is; the name above only says what. */
|
|
81
80
|
formatAnchorTitle: string;
|
|
@@ -138,6 +137,12 @@ export interface VisualStrings extends TableChromeStrings, SlashStrings {
|
|
|
138
137
|
* diagnostic.
|
|
139
138
|
*/
|
|
140
139
|
export type FormatDiagnostic = (d: Diagnostic) => string | undefined;
|
|
140
|
+
/**
|
|
141
|
+
* A `Mod` chord as the writer's platform prints it: `⌘B` on Apple's, `Ctrl+B`
|
|
142
|
+
* elsewhere. The platform test is the one `prosemirror-keymap` resolves `Mod` by, so a
|
|
143
|
+
* tooltip names the chord the keymap binds.
|
|
144
|
+
*/
|
|
145
|
+
export declare function chord(key: string, platform?: string): string;
|
|
141
146
|
/** The package's English. Every key, so the merge below is total. */
|
|
142
147
|
export declare const DEFAULT_VISUAL_STRINGS: VisualStrings;
|
|
143
148
|
/** A consumer's wording: any subset, the rest the package's. */
|
package/dist/visual/strings.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// makes wording an override rather than a fork.
|
|
5
5
|
//
|
|
6
6
|
// Several of these are accessible names rather than decoration — the card
|
|
7
|
-
// controls, the add trigger
|
|
7
|
+
// controls, the add trigger — so an untranslated surface is
|
|
8
8
|
// not merely inconsistent, it reads the wrong language to a screen reader. That is
|
|
9
9
|
// why this exists as a seam and not as a list of literals to grep for.
|
|
10
10
|
//
|
|
@@ -14,11 +14,19 @@
|
|
|
14
14
|
//
|
|
15
15
|
// The strings reach the tree through context, not props. They are ambient,
|
|
16
16
|
// read-only, and wanted eight components deep (a card's controls, a field's
|
|
17
|
-
//
|
|
17
|
+
// optional ghost, the formatting popover, the tips card); threading them by hand
|
|
18
18
|
// would put a `strings` prop on every component between the root and each leaf,
|
|
19
19
|
// which is a prop that means nothing to any of them.
|
|
20
20
|
import { getContext, setContext } from 'svelte';
|
|
21
21
|
import { DEFAULT_SLASH_STRINGS, DEFAULT_TABLE_STRINGS } from '../core/codec/index.js';
|
|
22
|
+
/**
|
|
23
|
+
* A `Mod` chord as the writer's platform prints it: `⌘B` on Apple's, `Ctrl+B`
|
|
24
|
+
* elsewhere. The platform test is the one `prosemirror-keymap` resolves `Mod` by, so a
|
|
25
|
+
* tooltip names the chord the keymap binds.
|
|
26
|
+
*/
|
|
27
|
+
export function chord(key, platform = typeof navigator === 'undefined' ? '' : navigator.platform) {
|
|
28
|
+
return /Mac|iP(hone|[oa]d)/.test(platform) ? `⌘${key}` : `Ctrl+${key}`;
|
|
29
|
+
}
|
|
22
30
|
/** The package's English. Every key, so the merge below is total. */
|
|
23
31
|
export const DEFAULT_VISUAL_STRINGS = {
|
|
24
32
|
...DEFAULT_TABLE_STRINGS,
|
|
@@ -27,7 +35,7 @@ export const DEFAULT_VISUAL_STRINGS = {
|
|
|
27
35
|
cardMoveDown: 'Move down',
|
|
28
36
|
cardDelete: 'Delete card',
|
|
29
37
|
cardTitle: 'Card title',
|
|
30
|
-
addCard: '
|
|
38
|
+
addCard: 'Add card',
|
|
31
39
|
arrayAdd: '+ Add',
|
|
32
40
|
arrayRemove: 'Remove',
|
|
33
41
|
arrayDrag: 'Drag to move',
|
|
@@ -41,16 +49,15 @@ export const DEFAULT_VISUAL_STRINGS = {
|
|
|
41
49
|
matrixItemTitle: (list, index) => `${list ? `${list} item` : 'Item'} ${index}`,
|
|
42
50
|
matrixRemove: (title) => `Remove ${title}`,
|
|
43
51
|
dateToday: 'Today',
|
|
44
|
-
fieldRequired: 'required',
|
|
45
52
|
optionalGhost: 'None',
|
|
46
53
|
proseHeld: 'Holds more than this field can edit here.',
|
|
47
54
|
formatGroup: 'Formatting',
|
|
48
|
-
formatBold:
|
|
49
|
-
formatEmphasis:
|
|
50
|
-
formatUnderline:
|
|
55
|
+
formatBold: `Bold (${chord('B')})`,
|
|
56
|
+
formatEmphasis: `Italic (${chord('I')})`,
|
|
57
|
+
formatUnderline: `Underline (${chord('U')})`,
|
|
51
58
|
formatStrikethrough: 'Strikethrough',
|
|
52
59
|
formatCode: 'Code',
|
|
53
|
-
formatLink:
|
|
60
|
+
formatLink: `Link (${chord('K')})`,
|
|
54
61
|
formatAnchor: 'Anchor',
|
|
55
62
|
formatAnchorTitle: 'Anchor — an identity handle over the selection',
|
|
56
63
|
linkPlaceholder: 'https://…',
|
|
@@ -61,7 +68,7 @@ export const DEFAULT_VISUAL_STRINGS = {
|
|
|
61
68
|
tipsDismiss: 'Dismiss',
|
|
62
69
|
tipsNext: 'Next',
|
|
63
70
|
tipsDot: (index, count) => `Tip ${index} of ${count}`,
|
|
64
|
-
unknownKind: (kind) => `
|
|
71
|
+
unknownKind: (kind) => `Unknown card type ${kind}. Its content is kept.`,
|
|
65
72
|
retypeLabel: 'Change to',
|
|
66
73
|
retypePlaceholder: 'Choose a type…',
|
|
67
74
|
noCardKinds: 'This document declares no card types — delete this card to remove it.',
|