@quillmark/svelte 0.16.0 → 0.18.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 +4 -2
- package/dist/core/codec/index.d.ts +0 -3
- package/dist/core/rebind.svelte.js +5 -8
- package/dist/core/theme.css +12 -1
- package/dist/preset/index.d.ts +1 -0
- package/dist/preview/Preview.svelte +14 -19
- package/dist/preview/Preview.svelte.d.ts +3 -3
- package/dist/preview/index.d.ts +0 -1
- package/dist/visual/ArrayField.svelte +44 -41
- package/dist/visual/ArrayField.svelte.d.ts +0 -1
- package/dist/visual/BooleanField.svelte +16 -14
- package/dist/visual/BooleanField.svelte.d.ts +0 -1
- package/dist/visual/Card.svelte +65 -35
- package/dist/visual/CardControls.svelte.d.ts +0 -1
- package/dist/visual/DateField.svelte +14 -17
- package/dist/visual/DateField.svelte.d.ts +0 -1
- package/dist/visual/EnumField.svelte +9 -12
- package/dist/visual/EnumField.svelte.d.ts +0 -1
- package/dist/visual/Field.svelte +17 -10
- package/dist/visual/Field.svelte.d.ts +3 -0
- package/dist/visual/FieldHint.svelte.d.ts +0 -1
- package/dist/visual/FieldLabel.svelte +1 -2
- package/dist/visual/FormatPopover.svelte +22 -27
- package/dist/visual/FormatPopover.svelte.d.ts +0 -1
- package/dist/visual/MatrixAdd.svelte +210 -0
- package/dist/visual/MatrixAdd.svelte.d.ts +15 -0
- package/dist/visual/MatrixField.svelte +329 -84
- package/dist/visual/MatrixField.svelte.d.ts +8 -6
- package/dist/visual/NumberField.svelte +6 -10
- package/dist/visual/NumberField.svelte.d.ts +0 -1
- package/dist/visual/ObjectField.svelte +30 -17
- package/dist/visual/ObjectField.svelte.d.ts +3 -1
- package/dist/visual/ProseField.svelte +42 -41
- package/dist/visual/ProseField.svelte.d.ts +0 -1
- package/dist/visual/ProseValue.svelte +56 -56
- package/dist/visual/ProseValue.svelte.d.ts +0 -1
- package/dist/visual/SlashMenu.svelte +5 -15
- package/dist/visual/SlashMenu.svelte.d.ts +0 -1
- package/dist/visual/TextField.svelte +5 -9
- package/dist/visual/TextField.svelte.d.ts +0 -1
- package/dist/visual/TipsCard.svelte +10 -11
- package/dist/visual/TipsCard.svelte.d.ts +0 -1
- package/dist/visual/VisualEditorInner.svelte +21 -14
- package/dist/visual/VisualEditorInner.svelte.d.ts +0 -1
- package/dist/visual/checklists.d.ts +82 -0
- package/dist/visual/checklists.js +171 -0
- package/dist/visual/index.d.ts +0 -1
- package/dist/visual/strings.d.ts +15 -1
- package/dist/visual/strings.js +6 -0
- package/dist/visual/structure.d.ts +63 -31
- package/dist/visual/structure.js +122 -44
- package/package.json +20 -16
- package/dist/visual/synced.svelte.d.ts +0 -15
- package/dist/visual/synced.svelte.js +0 -34
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts">
|
|
21
21
|
import { onDestroy, tick } from 'svelte';
|
|
22
|
+
import { SvelteMap } from 'svelte/reactivity';
|
|
22
23
|
import { DropdownMenu } from 'bits-ui';
|
|
23
24
|
import { isQuillmarkError, MAIN_CARD_ADDR } from '@quillmark/wasm';
|
|
24
25
|
import {
|
|
@@ -81,6 +82,7 @@
|
|
|
81
82
|
import { createLeafRegistry, type FieldControl } from './leaves.js';
|
|
82
83
|
import { reorder, reorderArm, reorderTrips } from './motion.js';
|
|
83
84
|
import { tipsChannel } from './tips.js';
|
|
85
|
+
import { cardChecklists, setChecklists } from './checklists.js';
|
|
84
86
|
import { patchEditorExt } from './ext.js';
|
|
85
87
|
import Card from './Card.svelte';
|
|
86
88
|
import TipsCard from './TipsCard.svelte';
|
|
@@ -134,14 +136,7 @@
|
|
|
134
136
|
// Local commit-error diagnostics (VISUAL_EDITOR §Diagnostics, producer #2),
|
|
135
137
|
// id-keyed rather than positional so an error stays pinned to its field across a
|
|
136
138
|
// card reorder.
|
|
137
|
-
|
|
138
|
-
/** Edit the commit-error map copy-on-write: a `$state` Map is not deeply
|
|
139
|
-
* reactive, so a mutation in place re-derives nothing. */
|
|
140
|
-
function editCommitErrors(edit: (m: Map<string, RoutedDiagnostic>) => void): void {
|
|
141
|
-
const next = new Map(commitErrors);
|
|
142
|
-
edit(next);
|
|
143
|
-
commitErrors = next;
|
|
144
|
-
}
|
|
139
|
+
const commitErrors = new SvelteMap<string, RoutedDiagnostic>();
|
|
145
140
|
|
|
146
141
|
const kinds = $derived(Object.keys(quill.schema.card_kinds ?? {}));
|
|
147
142
|
|
|
@@ -349,14 +344,14 @@
|
|
|
349
344
|
w.card(i).set(name, value);
|
|
350
345
|
}
|
|
351
346
|
}
|
|
352
|
-
|
|
347
|
+
commitErrors.delete(keyStr);
|
|
353
348
|
bump('field', id, makeAddr(id, isMain, name));
|
|
354
349
|
} catch (e) {
|
|
355
350
|
const diagnostic: Diagnostic = (isQuillmarkError(e) ? e.diagnostics[0] : undefined) ?? {
|
|
356
351
|
severity: 'error',
|
|
357
352
|
message: errorMessage(e)
|
|
358
353
|
};
|
|
359
|
-
|
|
354
|
+
commitErrors.set(keyStr, { key, diagnostic });
|
|
360
355
|
// Both channels, deliberately: the diagnostic pins to the field on
|
|
361
356
|
// screen, the error reaches the app's sink (core/errors.ts).
|
|
362
357
|
reportError(onError, {
|
|
@@ -461,9 +456,7 @@
|
|
|
461
456
|
// because nothing else will ever clear it.
|
|
462
457
|
const prefix = `${id}:`;
|
|
463
458
|
const stale = [...commitErrors.keys()].filter((k) => k.startsWith(prefix));
|
|
464
|
-
|
|
465
|
-
// nothing to re-derive.
|
|
466
|
-
if (stale.length) editCommitErrors((m) => stale.forEach((k) => m.delete(k)));
|
|
459
|
+
for (const k of stale) commitErrors.delete(k);
|
|
467
460
|
// No addr: the removed card has none left and every survivor's shifted. The
|
|
468
461
|
// stack changed, not a leaf, and the id is the only handle the removal leaves.
|
|
469
462
|
bump('structure', id);
|
|
@@ -661,6 +654,20 @@
|
|
|
661
654
|
};
|
|
662
655
|
});
|
|
663
656
|
|
|
657
|
+
// The document's checklists, which an open matrix's add box searches whole
|
|
658
|
+
// (`checklists.ts`): off the model, so a list in a closed group or another card is
|
|
659
|
+
// reached without being mounted.
|
|
660
|
+
const lists = $derived(
|
|
661
|
+
cardChecklists(
|
|
662
|
+
[model.main, ...model.cards],
|
|
663
|
+
(c) => c.titleOverride || c.titlePlaceholder,
|
|
664
|
+
(c, field) => pathFor(makeAddr(c.id, c.isMain, field)),
|
|
665
|
+
(c, field) => fieldKeyToString({ card: c.isMain ? undefined : c.id, field }),
|
|
666
|
+
(c, field, next) => commitScalar(c.id, c.isMain, field, next)
|
|
667
|
+
)
|
|
668
|
+
);
|
|
669
|
+
setChecklists({ list: () => lists, land: (path) => void focusField(path) });
|
|
670
|
+
|
|
664
671
|
// ── Public entry points ─────────────────────────────────────────────────────
|
|
665
672
|
/**
|
|
666
673
|
* Resolve a preview {@link Landing} to a mounted leaf and land in it.
|
|
@@ -922,7 +929,7 @@
|
|
|
922
929
|
gaps between cards stay bare: the strip is the gap, and the pill each fills on
|
|
923
930
|
hover draws what a label would state, the space the new card takes. -->
|
|
924
931
|
{@const marked = atIndex === model.cards.length}
|
|
925
|
-
<div class=
|
|
932
|
+
<div class={['qm-add-card', { 'qm-add-card-marked': marked }]}>
|
|
926
933
|
<!-- Marked, the words are the accessible name and no `aria-label` doubles
|
|
927
934
|
them; bare, the same words land as the label, the strip having no
|
|
928
935
|
geometry to carry them. -->
|
|
@@ -2,7 +2,6 @@ import { type DocPath, type Landing } from '../core/address.js';
|
|
|
2
2
|
import type { VisualEditorProps } from './props.js';
|
|
3
3
|
import type { CardId } from './signals.js';
|
|
4
4
|
import type { FieldController } from '../core/codec/index.js';
|
|
5
|
-
import './controls.css';
|
|
6
5
|
declare const VisualEditorInner: import("svelte").Component<VisualEditorProps, {
|
|
7
6
|
setCaret: (at: Landing) => Promise<void>;
|
|
8
7
|
getActiveLeaf: () => FieldController | undefined;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import type { QuillFieldSchema } from '@quillmark/wasm';
|
|
2
|
+
import type { DocPath } from '../core/address.js';
|
|
3
|
+
import { type CardModel, type MatrixMember } from './structure.js';
|
|
4
|
+
/** One matrix of the document, as the add box reaches it. */
|
|
5
|
+
export interface Checklist {
|
|
6
|
+
/** The field's leaf key: how a mounted matrix tells itself from the rest. */
|
|
7
|
+
key: string;
|
|
8
|
+
/** The field's path, the prefix a member's landing address extends. */
|
|
9
|
+
path: DocPath;
|
|
10
|
+
/** What a result from this list reads under: the field's label, and the card's
|
|
11
|
+
* where the field is not the main card's. */
|
|
12
|
+
label: string;
|
|
13
|
+
schema: QuillFieldSchema;
|
|
14
|
+
/** The held set as it prints: the stored map, else the declared `default:`. */
|
|
15
|
+
value: Record<string, unknown> | undefined;
|
|
16
|
+
/** Commit the whole map, as the field's own control does. */
|
|
17
|
+
commit: (next: Record<string, unknown> | undefined) => void;
|
|
18
|
+
}
|
|
19
|
+
export interface ChecklistIndex {
|
|
20
|
+
list: () => readonly Checklist[];
|
|
21
|
+
/** Reveal and focus a member by its address. */
|
|
22
|
+
land: (path: DocPath) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare function setChecklists(index: ChecklistIndex): void;
|
|
25
|
+
/** The index under a mounted editor; `undefined` off-tree. */
|
|
26
|
+
export declare function checklists(): ChecklistIndex | undefined;
|
|
27
|
+
/** The value a matrix prints: the stored map, else a mapping `default:`. */
|
|
28
|
+
export declare function matrixPrinted(value: unknown, schema: QuillFieldSchema): Record<string, unknown> | undefined;
|
|
29
|
+
/** Every card-level matrix of the cards, in document order. */
|
|
30
|
+
export declare function cardChecklists(cards: readonly CardModel[], cardLabel: (card: CardModel) => string, path: (card: CardModel, field: string) => DocPath | undefined, leafKey: (card: CardModel, field: string) => string, commit: (card: CardModel, field: string, next: Record<string, unknown> | undefined) => void): Checklist[];
|
|
31
|
+
/** Every item a matrix can show: the roster in declaration order, then the items its
|
|
32
|
+
* map adds, in id order. */
|
|
33
|
+
export declare function checklistItems(schema: QuillFieldSchema, value: Record<string, unknown> | undefined): MatrixMember[];
|
|
34
|
+
/** One option of an add box. */
|
|
35
|
+
export interface AddOption {
|
|
36
|
+
/** Stable across one query's options: the option element's id suffix. */
|
|
37
|
+
key: string;
|
|
38
|
+
title: string;
|
|
39
|
+
/** Words after the title: the list a result stands in, its held state. */
|
|
40
|
+
note?: string;
|
|
41
|
+
/** The option that adds what was typed, rather than a result. */
|
|
42
|
+
add?: boolean;
|
|
43
|
+
/** A result the typed words name outright, which Enter takes unarrowed: an add box
|
|
44
|
+
* whose best result is weaker takes its add option instead. */
|
|
45
|
+
strong?: boolean;
|
|
46
|
+
/** What the owner reads back off a chosen option. */
|
|
47
|
+
payload?: unknown;
|
|
48
|
+
}
|
|
49
|
+
/** One search result: an item of some checklist, `list` naming which. */
|
|
50
|
+
export interface ChecklistHit<L> {
|
|
51
|
+
list: L;
|
|
52
|
+
id: string;
|
|
53
|
+
title: string;
|
|
54
|
+
held: boolean;
|
|
55
|
+
score: number;
|
|
56
|
+
/** Every query word claimed a title word whole or as its opening. */
|
|
57
|
+
strong: boolean;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* How well `query` names `title`, or `undefined` for not at all. Each query word claims
|
|
61
|
+
* a title word — whole, as its opening, or as an abbreviation of it (`flt cc` names
|
|
62
|
+
* `Flight CC`) — the stronger claims taken first, so `c cc` names `CC Candidate`; a
|
|
63
|
+
* word left over may claim a run of words whose openings it spells (`fcc`, `jqo`). The
|
|
64
|
+
* title the query spells outright ranks first, then one it opens.
|
|
65
|
+
*/
|
|
66
|
+
export declare function matchTitle(query: string, title: string): {
|
|
67
|
+
score: number;
|
|
68
|
+
strong: boolean;
|
|
69
|
+
} | undefined;
|
|
70
|
+
/** {@link matchTitle}'s score, `0` for no match. */
|
|
71
|
+
export declare function matchScore(query: string, title: string): number;
|
|
72
|
+
/** What a search reads of one list: its items and their ticks. */
|
|
73
|
+
export interface Searchable<L> {
|
|
74
|
+
list: L;
|
|
75
|
+
schema: QuillFieldSchema;
|
|
76
|
+
value: Record<string, unknown> | undefined;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The items across `lists` that `query` names, best first; a tie keeps the order of
|
|
80
|
+
* `lists`, then of each list's items.
|
|
81
|
+
*/
|
|
82
|
+
export declare function searchChecklists<L>(query: string, lists: readonly Searchable<L>[], limit?: number): ChecklistHit<L>[];
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The document's checklists, and the search an open matrix's add box runs over them
|
|
3
|
+
* (VISUAL_EDITOR §"The matrix"). The editor root publishes every card-level matrix off
|
|
4
|
+
* the model it derives, so a list in a collapsed group or another card is searched
|
|
5
|
+
* as surely as the one the author is typing in. A matrix mounted off-tree, or nested
|
|
6
|
+
* in a container, is not indexed and searches its own items alone.
|
|
7
|
+
*/
|
|
8
|
+
import { getContext, setContext } from 'svelte';
|
|
9
|
+
import { addedItems, matrixHeld, matrixMembers, memberValue } from './structure.js';
|
|
10
|
+
const KEY = Symbol('qm-checklists');
|
|
11
|
+
export function setChecklists(index) {
|
|
12
|
+
setContext(KEY, index);
|
|
13
|
+
}
|
|
14
|
+
/** The index under a mounted editor; `undefined` off-tree. */
|
|
15
|
+
export function checklists() {
|
|
16
|
+
return getContext(KEY);
|
|
17
|
+
}
|
|
18
|
+
/** The value a matrix prints: the stored map, else a mapping `default:`. */
|
|
19
|
+
export function matrixPrinted(value, schema) {
|
|
20
|
+
const map = (v) => typeof v === 'object' && v !== null && !Array.isArray(v)
|
|
21
|
+
? v
|
|
22
|
+
: undefined;
|
|
23
|
+
return value == null ? map(schema.default) : map(value);
|
|
24
|
+
}
|
|
25
|
+
/** Every card-level matrix of the cards, in document order. */
|
|
26
|
+
export function cardChecklists(cards, cardLabel, path, leafKey, commit) {
|
|
27
|
+
const out = [];
|
|
28
|
+
for (const card of cards) {
|
|
29
|
+
if (card.unschemable)
|
|
30
|
+
continue;
|
|
31
|
+
for (const section of card.sections)
|
|
32
|
+
for (const f of section.fields) {
|
|
33
|
+
if (f.control !== 'matrix')
|
|
34
|
+
continue;
|
|
35
|
+
const at = path(card, f.name);
|
|
36
|
+
if (at == null)
|
|
37
|
+
continue;
|
|
38
|
+
out.push({
|
|
39
|
+
key: leafKey(card, f.name),
|
|
40
|
+
path: at,
|
|
41
|
+
label: card.isMain ? f.label : `${f.label} · ${cardLabel(card)}`,
|
|
42
|
+
schema: f.schema,
|
|
43
|
+
value: matrixPrinted(card.values[f.name], f.schema),
|
|
44
|
+
commit: (next) => commit(card, f.name, next)
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/** Every item a matrix can show: the roster in declaration order, then the items its
|
|
51
|
+
* map adds, in id order. */
|
|
52
|
+
export function checklistItems(schema, value) {
|
|
53
|
+
return [...matrixMembers(schema.members), ...addedItems(schema, value)];
|
|
54
|
+
}
|
|
55
|
+
/** Lowercase, unaccented words, any script: `Exec / Aide / CAG` → `exec aide cag`. */
|
|
56
|
+
function words(s) {
|
|
57
|
+
return s
|
|
58
|
+
.normalize('NFKD')
|
|
59
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.split(/[^\p{L}\p{N}]+/u)
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
}
|
|
64
|
+
/** `flt` in `flight`: every letter in order, the first letters equal. */
|
|
65
|
+
function abbreviates(token, word) {
|
|
66
|
+
if (token[0] !== word[0])
|
|
67
|
+
return false;
|
|
68
|
+
let i = 0;
|
|
69
|
+
for (const c of word)
|
|
70
|
+
if (c === token[i])
|
|
71
|
+
i++;
|
|
72
|
+
return i === token.length;
|
|
73
|
+
}
|
|
74
|
+
/** How a query word claims one title word: whole (3), as its opening (2), as an
|
|
75
|
+
* abbreviation (1), or not (0). */
|
|
76
|
+
function claim(token, word) {
|
|
77
|
+
return word === token ? 3 : word.startsWith(token) ? 2 : abbreviates(token, word) ? 1 : 0;
|
|
78
|
+
}
|
|
79
|
+
/** The end of the run of free words from `i` whose openings spell `token` in order —
|
|
80
|
+
* `fcc` over `flight cc`, `jqo` over `joint qualified officer` — or `-1`. */
|
|
81
|
+
function runFrom(token, w, free, i) {
|
|
82
|
+
if (i >= w.length || !free[i])
|
|
83
|
+
return -1;
|
|
84
|
+
for (let k = Math.min(token.length, w[i].length); k > 0; k--) {
|
|
85
|
+
if (!w[i].startsWith(token.slice(0, k)))
|
|
86
|
+
continue;
|
|
87
|
+
if (k === token.length)
|
|
88
|
+
return i + 1;
|
|
89
|
+
const end = runFrom(token.slice(k), w, free, i + 1);
|
|
90
|
+
if (end >= 0)
|
|
91
|
+
return end;
|
|
92
|
+
}
|
|
93
|
+
return -1;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* How well `query` names `title`, or `undefined` for not at all. Each query word claims
|
|
97
|
+
* a title word — whole, as its opening, or as an abbreviation of it (`flt cc` names
|
|
98
|
+
* `Flight CC`) — the stronger claims taken first, so `c cc` names `CC Candidate`; a
|
|
99
|
+
* word left over may claim a run of words whose openings it spells (`fcc`, `jqo`). The
|
|
100
|
+
* title the query spells outright ranks first, then one it opens.
|
|
101
|
+
*/
|
|
102
|
+
export function matchTitle(query, title) {
|
|
103
|
+
const q = words(query);
|
|
104
|
+
const w = words(title);
|
|
105
|
+
if (!q.length || !w.length)
|
|
106
|
+
return undefined;
|
|
107
|
+
const free = w.map(() => true);
|
|
108
|
+
const left = q.map(() => true);
|
|
109
|
+
let score = 0;
|
|
110
|
+
let strong = true;
|
|
111
|
+
for (const level of [3, 2, 1])
|
|
112
|
+
q.forEach((token, t) => {
|
|
113
|
+
if (!left[t])
|
|
114
|
+
return;
|
|
115
|
+
const at = w.findIndex((word, i) => free[i] && claim(token, word) === level);
|
|
116
|
+
if (at < 0)
|
|
117
|
+
return;
|
|
118
|
+
free[at] = left[t] = false;
|
|
119
|
+
score += level;
|
|
120
|
+
if (level === 1)
|
|
121
|
+
strong = false;
|
|
122
|
+
});
|
|
123
|
+
for (let t = 0; t < q.length; t++) {
|
|
124
|
+
if (!left[t])
|
|
125
|
+
continue;
|
|
126
|
+
let found = false;
|
|
127
|
+
for (let i = 0; i < w.length && !found; i++) {
|
|
128
|
+
const end = runFrom(q[t], w, free, i);
|
|
129
|
+
if (end - i < 2)
|
|
130
|
+
continue;
|
|
131
|
+
for (let k = i; k < end; k++)
|
|
132
|
+
free[k] = false;
|
|
133
|
+
found = true;
|
|
134
|
+
}
|
|
135
|
+
if (!found)
|
|
136
|
+
return undefined;
|
|
137
|
+
score += 1;
|
|
138
|
+
strong = false;
|
|
139
|
+
}
|
|
140
|
+
const typed = q.join(' ');
|
|
141
|
+
const whole = w.join(' ');
|
|
142
|
+
return { score: score + (whole === typed ? 3 : whole.startsWith(typed) ? 1 : 0), strong };
|
|
143
|
+
}
|
|
144
|
+
/** {@link matchTitle}'s score, `0` for no match. */
|
|
145
|
+
export function matchScore(query, title) {
|
|
146
|
+
return matchTitle(query, title)?.score ?? 0;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The items across `lists` that `query` names, best first; a tie keeps the order of
|
|
150
|
+
* `lists`, then of each list's items.
|
|
151
|
+
*/
|
|
152
|
+
export function searchChecklists(query, lists, limit = 8) {
|
|
153
|
+
const hits = [];
|
|
154
|
+
for (const { list, schema, value } of lists)
|
|
155
|
+
for (const item of checklistItems(schema, value)) {
|
|
156
|
+
const match = matchTitle(query, item.title);
|
|
157
|
+
if (match)
|
|
158
|
+
hits.push({
|
|
159
|
+
list,
|
|
160
|
+
id: item.id,
|
|
161
|
+
title: item.title,
|
|
162
|
+
held: matrixHeld(memberValue(value, item.id)),
|
|
163
|
+
...match
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
return hits
|
|
167
|
+
.map((h, i) => [h, i])
|
|
168
|
+
.sort(([a, i], [b, j]) => b.score - a.score || i - j)
|
|
169
|
+
.slice(0, limit)
|
|
170
|
+
.map(([h]) => h);
|
|
171
|
+
}
|
package/dist/visual/index.d.ts
CHANGED
package/dist/visual/strings.d.ts
CHANGED
|
@@ -45,8 +45,22 @@ export interface VisualStrings extends TableChromeStrings, SlashStrings {
|
|
|
45
45
|
/** The tag on the unset sentinel's row, which is what tells it from the member it
|
|
46
46
|
* ghosts ({@link EnumField}). */
|
|
47
47
|
enumUnsetTag: string;
|
|
48
|
-
/** The count in the matrix's label row: how many of
|
|
48
|
+
/** The count in the matrix's label row: how many of its items are held. */
|
|
49
49
|
matrixHeld: (held: number, total: number) => string;
|
|
50
|
+
/** An open matrix's add box at rest, naming the list it adds to: `Add to Staff…`. The box
|
|
51
|
+
* draws its own `+`. `list` is empty for a matrix mounted with no label. */
|
|
52
|
+
matrixAdd: (list: string) => string;
|
|
53
|
+
/** The add box's last option, which adds what was typed as an item of this list. */
|
|
54
|
+
matrixAddNew: (title: string) => string;
|
|
55
|
+
/** Beside a result from another list: the list it would be ticked in. */
|
|
56
|
+
matrixIn: (list: string) => string;
|
|
57
|
+
/** Beside a result already held: picking it lands on it and ticks nothing. */
|
|
58
|
+
matrixHeldTag: string;
|
|
59
|
+
/** An added item's title input, named for the list it stands in and its 1-based
|
|
60
|
+
* place among the added items; also what an untitled item is called. */
|
|
61
|
+
matrixItemTitle: (list: string, index: number) => string;
|
|
62
|
+
/** An added item's remove control, named for the item. */
|
|
63
|
+
matrixRemove: (title: string) => string;
|
|
50
64
|
/** The date field's toggle, pressed while the field holds `today`: the render
|
|
51
65
|
* date rather than a written one. */
|
|
52
66
|
dateToday: string;
|
package/dist/visual/strings.js
CHANGED
|
@@ -37,6 +37,12 @@ export const DEFAULT_VISUAL_STRINGS = {
|
|
|
37
37
|
elementUntitled: (label, index) => `${label} ${index}`,
|
|
38
38
|
enumUnsetTag: 'default',
|
|
39
39
|
matrixHeld: (held, total) => `${held} of ${total} held`,
|
|
40
|
+
matrixAdd: (list) => (list ? `Add to ${list}…` : 'Add…'),
|
|
41
|
+
matrixAddNew: (title) => `Add “${title}”`,
|
|
42
|
+
matrixIn: (list) => `in ${list}`,
|
|
43
|
+
matrixHeldTag: 'held',
|
|
44
|
+
matrixItemTitle: (list, index) => `${list ? `${list} item` : 'Item'} ${index}`,
|
|
45
|
+
matrixRemove: (title) => `Remove ${title}`,
|
|
40
46
|
dateToday: 'Today',
|
|
41
47
|
fieldRequired: 'required',
|
|
42
48
|
optionalGhost: 'None',
|
|
@@ -35,7 +35,13 @@ export interface GroupSection {
|
|
|
35
35
|
group: string | undefined;
|
|
36
36
|
label: string;
|
|
37
37
|
fields: FieldModel[];
|
|
38
|
+
/** The field the section's header names in place of a label of its own: the one
|
|
39
|
+
* field of a group section, where that field is {@link flatObject}. */
|
|
40
|
+
head?: FieldModel;
|
|
38
41
|
}
|
|
42
|
+
/** `ui.layout: flat` on a typed dictionary: no frame of its own, its properties
|
|
43
|
+
* standing at the depth of the fields around it rather than a rung in. */
|
|
44
|
+
export declare function flatObject(schema: QuillFieldSchema): boolean;
|
|
39
45
|
/**
|
|
40
46
|
* One card instance projected for rendering: the schema × payload join result
|
|
41
47
|
* the VisualEditor's `$derived` produces and hands to `<Card>`. Positional
|
|
@@ -108,6 +114,10 @@ export declare function resolvedByCardIndex(resolved: Resolved | undefined): Map
|
|
|
108
114
|
* use (`source === 'default'`), else undefined: an `authored` field shows its value,
|
|
109
115
|
* a `blank` field has no default to show. */
|
|
110
116
|
export declare function ghostDefault(row: ResolvedField | undefined): unknown;
|
|
117
|
+
/** A stored `boolean` cell as the render reads it: a boolean, `true` or `false` in any
|
|
118
|
+
* case, or a number by whether it is non-zero; undefined where the render refuses the
|
|
119
|
+
* value. The engine's coercion, restated, so the suite holds it to `reader.resolve()`. */
|
|
120
|
+
export declare function renderedBoolean(value: unknown): boolean | undefined;
|
|
111
121
|
/** A ghost value's string form, or undefined for null/object (only text ghosts
|
|
112
122
|
* render a placeholder). A scalar's resolved default reads through it; a content
|
|
113
123
|
* field's resolves as `Content`, which a prose leaf reads by its text instead
|
|
@@ -177,11 +187,11 @@ export declare function controlKind(f: QuillFieldSchema): ControlKind;
|
|
|
177
187
|
* crosses inside untyped container data with no type to read it off, so a literal here
|
|
178
188
|
* would be a second spelling of a reserved key. No variant may declare it. */
|
|
179
189
|
export declare const VARIANT_DISCRIMINANT: "value";
|
|
180
|
-
/** The
|
|
181
|
-
* The boundary
|
|
182
|
-
*
|
|
183
|
-
export declare const
|
|
184
|
-
/** One
|
|
190
|
+
/** The label key of an open matrix's added item, the one cell a roster member never
|
|
191
|
+
* stores. The boundary exports no constant for it, so the package spells it once
|
|
192
|
+
* (canon `SCHEMAS.md` §Matrix). */
|
|
193
|
+
export declare const MATRIX_TITLE = "title";
|
|
194
|
+
/** One item of a matrix: its id and its title. */
|
|
185
195
|
export interface MatrixMember {
|
|
186
196
|
id: string;
|
|
187
197
|
title: string;
|
|
@@ -193,39 +203,60 @@ export declare function matrixMembers(roster: Record<string, string> | undefined
|
|
|
193
203
|
* spelled `constructor`. */
|
|
194
204
|
export declare function memberValue(map: Record<string, unknown> | undefined, id: string): unknown;
|
|
195
205
|
/**
|
|
196
|
-
* Whether a stored member is held
|
|
197
|
-
*
|
|
198
|
-
* `false`
|
|
199
|
-
*
|
|
200
|
-
* engine coerces to false — `false`, `0`, `"false"`, `null` — read false here; every other
|
|
201
|
-
* present scalar reads held, so a document the engine would refuse still draws the tick
|
|
202
|
-
* its spelling claims.
|
|
206
|
+
* Whether a stored member is held: by being present. A mapping is held whatever it
|
|
207
|
+
* carries, `{}` included, and a bare scalar is the tick itself, read as the engine's
|
|
208
|
+
* coercion reads it: `false`, `0`, `"false"` and `null` unheld, every other present
|
|
209
|
+
* scalar held, so a spelling the engine would refuse still draws the tick it claims.
|
|
203
210
|
*/
|
|
204
211
|
export declare function matrixHeld(stored: unknown): boolean;
|
|
205
|
-
/** A member's columns:
|
|
206
|
-
*
|
|
212
|
+
/** A member's columns: its mapping without the reserved keys, `{}` for a bare tick or an
|
|
213
|
+
* absent member. What the columns subform takes as its value, so an edit writes back
|
|
214
|
+
* no `held` a document stored (`validation::held_stored`). */
|
|
207
215
|
export declare function matrixColumns(stored: unknown): Record<string, unknown>;
|
|
216
|
+
/** What a matrix holding nothing commits: the unset field where unset prints nothing
|
|
217
|
+
* held, and the authored `{}` where it would print a `default:` or `none` instead. */
|
|
218
|
+
export declare function matrixEmpty(matrix: QuillFieldSchema): Record<string, unknown> | undefined;
|
|
208
219
|
/**
|
|
209
220
|
* The map after one member moves: `next` written under `id`, or the key dropped where
|
|
210
221
|
* `next` is `undefined`; a map left holding nothing is an unset field. Every other
|
|
211
|
-
* member rides through in the spelling the document had
|
|
212
|
-
* stays `true` while its neighbour is edited.
|
|
222
|
+
* member rides through in the spelling the document had.
|
|
213
223
|
*/
|
|
214
|
-
export declare function commitMember(map: Record<string, unknown> | undefined, id: string, next:
|
|
224
|
+
export declare function commitMember(map: Record<string, unknown> | undefined, id: string, next: unknown): Record<string, unknown> | undefined;
|
|
215
225
|
/**
|
|
216
|
-
* The member a tick or an edit writes
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
* Which columns are blank is the engine's rule and not restated here: a column control
|
|
220
|
-
* that clears drops its key (`ObjectField`), so a member emptied by hand arrives with no
|
|
221
|
-
* columns and only then leaves the map.
|
|
226
|
+
* The held member a tick or an edit writes: its columns, the bare tick `true` where
|
|
227
|
+
* it answers none, and an added item's `title` beside them. Unticking is removal
|
|
228
|
+
* ({@link commitMember} with `undefined`), never a write.
|
|
222
229
|
*/
|
|
223
|
-
export declare function memberWrite(
|
|
224
|
-
/**
|
|
225
|
-
*
|
|
226
|
-
export declare function
|
|
230
|
+
export declare function memberWrite(columns: Record<string, unknown>, title?: string): unknown;
|
|
231
|
+
/** Whether `id` is spelled as a matrix id: snake_case, the rule the roster's ids and
|
|
232
|
+
* an added item's key share. */
|
|
233
|
+
export declare function matrixId(id: string): boolean;
|
|
227
234
|
/** Whether `id` is on the roster. */
|
|
235
|
+
export declare function onRoster(matrix: QuillFieldSchema, id: string): boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Whether a step under the matrix names a member, judged on the schema alone as an
|
|
238
|
+
* index step is: a roster id, or on an open matrix any key spelled as an id, the added
|
|
239
|
+
* item it would be. So an unheld member's address resolves.
|
|
240
|
+
*/
|
|
228
241
|
export declare function matrixDeclares(matrix: QuillFieldSchema, id: string): boolean;
|
|
242
|
+
/**
|
|
243
|
+
* The added items a stored map holds, sorted by id as the plate orders them: on an
|
|
244
|
+
* open matrix, each key off the roster spelled as an id whose mapping carries a
|
|
245
|
+
* `title`. Any other key off the roster is the engine's refusal, drawn nowhere and
|
|
246
|
+
* ridden through.
|
|
247
|
+
*/
|
|
248
|
+
export declare function addedItems(matrix: QuillFieldSchema, map: Record<string, unknown> | undefined): MatrixMember[];
|
|
249
|
+
/**
|
|
250
|
+
* The id an item added under `title` takes: the title folded to snake_case, prefixed
|
|
251
|
+
* where it opens on no letter, and suffixed past every id `taken` names, the roster's
|
|
252
|
+
* and the document's alike. The id is the wire's and never drawn, so a later retitle
|
|
253
|
+
* leaves it where it is.
|
|
254
|
+
*/
|
|
255
|
+
export declare function addedId(title: string, taken: (id: string) => boolean): string;
|
|
256
|
+
/** The `object` a matrix member is, for the schema walk: the declared columns, and an
|
|
257
|
+
* added item's `title` beside them. Composed here because the boundary serializes the
|
|
258
|
+
* roster and the columns alone. */
|
|
259
|
+
export declare function matrixMemberSchema(matrix: QuillFieldSchema, id: string): QuillFieldSchema;
|
|
229
260
|
/**
|
|
230
261
|
* The schema at `steps` under `field`, or `undefined` where the schema declares no such
|
|
231
262
|
* place: an index under an `array`, a key under an `object`'s properties, a member id
|
|
@@ -248,7 +279,7 @@ export type ArrayLayout = 'list' | 'table';
|
|
|
248
279
|
* The layout an array takes: `'table'` where the array's own `ui.layout` asks for it
|
|
249
280
|
* and every cell of the row is short (a block prose cell declines it, at load width and
|
|
250
281
|
* every width after), else `'list'`. That every column is a leaf is the loader's
|
|
251
|
-
* contract (`quill::
|
|
282
|
+
* contract (`quill::table_column_not_leaf`); whether a leaf fits a cell is the surface's
|
|
252
283
|
* answer (canon `SCHEMAS.md`): a table composes by position, so a row that would stack
|
|
253
284
|
* inside a cell is not one.
|
|
254
285
|
*/
|
|
@@ -273,9 +304,10 @@ export declare function commitDiscriminant(value: Record<string, unknown> | unde
|
|
|
273
304
|
/**
|
|
274
305
|
* Whether the schema obliges a cell: `default:`'s absence, which is the whole of the
|
|
275
306
|
* obligation (DOCUMENT_MODEL). Exempt are the cells whose absence of one says nothing:
|
|
276
|
-
* a typed dictionary
|
|
277
|
-
*
|
|
278
|
-
* declare none, its unanswered render
|
|
307
|
+
* a typed dictionary, since a namespace declares no `default:` at all and `validate`
|
|
308
|
+
* anchors obligation on the leaves under it; a matrix, whose blank is nothing held, a
|
|
309
|
+
* whole answer; and an optional cell, which can declare none, its unanswered render
|
|
310
|
+
* being `none`.
|
|
279
311
|
*/
|
|
280
312
|
export declare function obliged(schema: QuillFieldSchema): boolean;
|
|
281
313
|
/** `foo_bar` → `Foo bar`: the label fallback when a field declares no `title`. */
|