@quillmark/svelte 0.26.2 → 0.28.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 +4 -4
- package/README.md +26 -8
- package/THEMING.md +40 -4
- package/dist/core/address.d.ts +35 -64
- package/dist/core/address.js +35 -55
- package/dist/core/bloom.d.ts +4 -10
- package/dist/core/bloom.js +14 -27
- package/dist/core/codec/blocks.d.ts +41 -43
- package/dist/core/codec/blocks.js +97 -130
- package/dist/core/codec/code.d.ts +7 -10
- package/dist/core/codec/code.js +37 -46
- package/dist/core/codec/decode.d.ts +19 -23
- package/dist/core/codec/decode.js +76 -111
- package/dist/core/codec/encode.d.ts +11 -15
- package/dist/core/codec/encode.js +60 -67
- package/dist/core/codec/field.d.ts +62 -95
- package/dist/core/codec/field.js +107 -179
- package/dist/core/codec/islands.d.ts +33 -41
- package/dist/core/codec/islands.js +76 -86
- package/dist/core/codec/lists.d.ts +17 -26
- package/dist/core/codec/lists.js +117 -157
- package/dist/core/codec/marks.d.ts +4 -3
- package/dist/core/codec/marks.js +8 -3
- package/dist/core/codec/prose.css +84 -46
- package/dist/core/codec/schema.d.ts +18 -23
- package/dist/core/codec/schema.js +84 -76
- package/dist/core/codec/slash.d.ts +42 -48
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-copy.d.ts +4 -3
- package/dist/core/codec/table-copy.js +25 -7
- package/dist/core/codec/table-view.d.ts +12 -12
- package/dist/core/codec/table-view.js +460 -383
- package/dist/core/codec/table.d.ts +94 -61
- package/dist/core/codec/table.js +331 -83
- package/dist/core/codec/tasks.d.ts +6 -0
- package/dist/core/codec/tasks.js +30 -3
- package/dist/core/errors.d.ts +15 -30
- package/dist/core/errors.js +2 -6
- package/dist/core/index.js +7 -12
- package/dist/core/lifecycle.d.ts +7 -16
- package/dist/core/lifecycle.js +10 -21
- package/dist/core/rebind.svelte.d.ts +10 -20
- package/dist/core/rebind.svelte.js +15 -27
- package/dist/core/rungs.d.ts +14 -11
- package/dist/core/rungs.js +17 -19
- package/dist/core/teardown.d.ts +4 -6
- package/dist/core/teardown.js +7 -10
- package/dist/core/theme.css +74 -54
- package/dist/index.js +3 -8
- package/dist/preset/app.css +71 -0
- package/dist/preset/index.css +8 -7
- package/dist/preset/recipes.css +19 -164
- package/dist/preset/scale.css +28 -18
- package/dist/preset/shell.css +157 -0
- package/dist/preview/Preview.svelte +8 -0
- package/dist/preview/bridge.d.ts +18 -22
- package/dist/preview/bridge.js +29 -58
- package/dist/preview/controller.d.ts +21 -29
- package/dist/preview/controller.js +14 -39
- package/dist/preview/geometry.d.ts +13 -34
- package/dist/preview/geometry.js +13 -34
- package/dist/preview/index.js +4 -16
- package/dist/preview/paint.d.ts +3 -3
- package/dist/preview/paint.js +28 -68
- package/dist/preview/strings.d.ts +1 -1
- package/dist/preview/strings.js +2 -14
- package/dist/preview/viewport.js +20 -15
- package/dist/preview/zoom.d.ts +21 -22
- package/dist/preview/zoom.js +53 -30
- package/dist/visual/ArrayField.svelte +77 -16
- package/dist/visual/BooleanField.svelte +28 -15
- package/dist/visual/Card.svelte +66 -51
- package/dist/visual/CardControls.svelte +5 -11
- package/dist/visual/DateField.svelte +20 -4
- package/dist/visual/EnumField.svelte +3 -0
- package/dist/visual/FieldHint.svelte +2 -1
- package/dist/visual/FormatPopover.svelte +82 -15
- package/dist/visual/FormatPopover.svelte.d.ts +4 -0
- package/dist/visual/MatrixAdd.svelte +30 -12
- package/dist/visual/MatrixField.svelte +24 -16
- package/dist/visual/NumberField.svelte +7 -0
- package/dist/visual/ObjectField.svelte +4 -4
- package/dist/visual/ProseField.svelte +0 -5
- package/dist/visual/TipsCard.svelte +11 -10
- package/dist/visual/VariantField.svelte +3 -1
- package/dist/visual/VisualEditorInner.svelte +19 -3
- package/dist/visual/controls.css +7 -2
- package/dist/visual/fonts.d.ts +18 -0
- package/dist/visual/fonts.js +59 -0
- package/dist/visual/icons/nodes.d.ts +0 -5
- package/dist/visual/icons/nodes.js +0 -4
- package/dist/visual/props.d.ts +14 -1
- package/dist/visual/strings.d.ts +7 -0
- package/dist/visual/strings.js +5 -2
- package/dist/visual/structure.d.ts +43 -87
- package/dist/visual/structure.js +42 -83
- package/package.json +2 -2
package/dist/visual/structure.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
// The schema × payload join,
|
|
2
|
-
//
|
|
3
|
-
// dispatch, group layout, titles, ghosts, and session-identity bookkeeping
|
|
4
|
-
// are unit-testable in isolation (tests/visual/structure.test.ts). The reactive
|
|
5
|
-
// orchestration (revision counter, live doc reads) lives in VisualEditor.svelte;
|
|
6
|
-
// this module is the projection math it feeds.
|
|
1
|
+
// The schema × payload join, as pure functions (VISUAL_EDITOR §Structure). The reactive
|
|
2
|
+
// orchestration lives in VisualEditor.svelte.
|
|
7
3
|
import { VARIANT_DISCRIMINANT_KEY } from '@quillmark/wasm';
|
|
8
4
|
import { core } from '../core/lifecycle.js';
|
|
9
5
|
/** The container controls: the ones a nested address walks into and a deep
|
|
@@ -11,25 +7,15 @@ import { core } from '../core/lifecycle.js';
|
|
|
11
7
|
export function isContainer(kind) {
|
|
12
8
|
return kind === 'array' || kind === 'object' || kind === 'variant' || kind === 'matrix';
|
|
13
9
|
}
|
|
14
|
-
/**
|
|
15
|
-
* A card's resolved rows keyed by field name: the provenance channel parallel to
|
|
16
|
-
* {@link CardModel.values}. `resolve` returns rows in declaration order; the
|
|
17
|
-
* editor keys them the same way `values` keys its payload walk, so a field's value
|
|
18
|
-
* and its provenance resolve under one name.
|
|
19
|
-
*/
|
|
10
|
+
/** A card's resolved rows keyed by field name, parallel to {@link CardModel.values}. */
|
|
20
11
|
export function provenanceMap(fields) {
|
|
21
12
|
return Object.fromEntries(fields.map((f) => [f.name, f]));
|
|
22
13
|
}
|
|
23
|
-
/**
|
|
24
|
-
* per-card miss allocates nothing. */
|
|
14
|
+
/** Shared so a per-card miss allocates nothing. */
|
|
25
15
|
export const NO_RESOLVED_ROWS = { fields: [], body: null };
|
|
26
16
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* once per derive, so the per-card provenance join is O(1). Both channels ride one
|
|
30
|
-
* entry: a card reads its fields and its body from a single lookup. Empty map when
|
|
31
|
-
* `resolved` is absent (a `resolve` failure degrades to no ghosts, never a blank
|
|
32
|
-
* form).
|
|
17
|
+
* Resolved rows keyed by `ResolvedCard.index`, not array position. Empty when `resolved` is absent:
|
|
18
|
+
* a `resolve` failure degrades to no ghosts, never a blank form.
|
|
33
19
|
*/
|
|
34
20
|
export function resolvedByCardIndex(resolved) {
|
|
35
21
|
return new Map((resolved?.cards ?? []).map((c) => [c.index, { fields: c.fields, body: c.body }]));
|
|
@@ -40,9 +26,10 @@ export function resolvedByCardIndex(resolved) {
|
|
|
40
26
|
export function ghostDefault(row) {
|
|
41
27
|
return row?.source === 'default' ? row.value : undefined;
|
|
42
28
|
}
|
|
43
|
-
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
29
|
+
/**
|
|
30
|
+
* A stored `boolean` cell as the render reads it (Quillmark's coercion, held to `reader.resolve()`
|
|
31
|
+
* by the suite); undefined where the render refuses it.
|
|
32
|
+
*/
|
|
46
33
|
export function renderedBoolean(value) {
|
|
47
34
|
if (typeof value === 'boolean')
|
|
48
35
|
return value;
|
|
@@ -52,10 +39,10 @@ export function renderedBoolean(value) {
|
|
|
52
39
|
return value.toLowerCase() === 'true';
|
|
53
40
|
return undefined;
|
|
54
41
|
}
|
|
55
|
-
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
|
|
42
|
+
/**
|
|
43
|
+
* A ghost value's string form, or undefined for null/object. A content field's default resolves as
|
|
44
|
+
* `Content` and is read by its text ({@link titleText}).
|
|
45
|
+
*/
|
|
59
46
|
export function stringifyGhost(ghost) {
|
|
60
47
|
return ghost != null && typeof ghost !== 'object' ? String(ghost) : undefined;
|
|
61
48
|
}
|
|
@@ -74,8 +61,10 @@ export function resolveBodyGhost(resolvedDefault, custom, builtIn) {
|
|
|
74
61
|
export function optionalCell(f) {
|
|
75
62
|
return f.type.endsWith('?');
|
|
76
63
|
}
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
64
|
+
/**
|
|
65
|
+
* The declared type with an optional cell's `?` stripped; the `?` moves the render floor and
|
|
66
|
+
* nothing else.
|
|
67
|
+
*/
|
|
79
68
|
export function baseType(f) {
|
|
80
69
|
return (optionalCell(f) ? f.type.slice(0, -1) : f.type);
|
|
81
70
|
}
|
|
@@ -84,7 +73,7 @@ export function baseType(f) {
|
|
|
84
73
|
export function oneLine(f) {
|
|
85
74
|
return f.multiline !== true;
|
|
86
75
|
}
|
|
87
|
-
/** Whether a content field's codec is the literal one
|
|
76
|
+
/** Whether a content field's codec is the literal one: `text`. */
|
|
88
77
|
export function literalText(f) {
|
|
89
78
|
return baseType(f) === 'text';
|
|
90
79
|
}
|
|
@@ -143,8 +132,7 @@ export function mountKey(name, f) {
|
|
|
143
132
|
items?.max ?? ''
|
|
144
133
|
].join('\u0000');
|
|
145
134
|
}
|
|
146
|
-
/**
|
|
147
|
-
* a type this build does not know takes the text input. */
|
|
135
|
+
/** An array's element control is this over `items`; an unknown type takes the text input. */
|
|
148
136
|
export function controlKind(f) {
|
|
149
137
|
switch (baseType(f)) {
|
|
150
138
|
case 'richtext':
|
|
@@ -260,7 +248,6 @@ export function memberWrite(columns, title) {
|
|
|
260
248
|
export function matrixId(id) {
|
|
261
249
|
return /^[a-z][a-z0-9_]*$/.test(id);
|
|
262
250
|
}
|
|
263
|
-
/** Whether `id` is on the roster. */
|
|
264
251
|
export function onRoster(matrix, id) {
|
|
265
252
|
return matrix.members != null && Object.hasOwn(matrix.members, id);
|
|
266
253
|
}
|
|
@@ -377,8 +364,9 @@ function stepInto(schema, step) {
|
|
|
377
364
|
}
|
|
378
365
|
}
|
|
379
366
|
// ── Row summaries and layouts ────────────────────────────────────────────────
|
|
380
|
-
/**
|
|
381
|
-
*
|
|
367
|
+
/**
|
|
368
|
+
* Whether a cell is one line tall by declaration: what a table column and a row summary can hold.
|
|
369
|
+
*/
|
|
382
370
|
export function shortCell(sub) {
|
|
383
371
|
const kind = controlKind(sub);
|
|
384
372
|
if (kind === 'prose')
|
|
@@ -386,11 +374,8 @@ export function shortCell(sub) {
|
|
|
386
374
|
return (kind === 'text' || kind === 'enum' || kind === 'number' || kind === 'boolean' || kind === 'date');
|
|
387
375
|
}
|
|
388
376
|
/**
|
|
389
|
-
* The
|
|
390
|
-
*
|
|
391
|
-
* there is no such cell or it is empty. The cell is picked by the schema alone, so an
|
|
392
|
-
* instance is named by one cell whatever the others hold. What names an instance from
|
|
393
|
-
* its own values: a collapsed row, and a card whose kind declares no `title`.
|
|
377
|
+
* The words of the first one-line `text` or `richtext` cell in declaration order, picked by schema
|
|
378
|
+
* alone so one cell names an instance whatever the others hold.
|
|
394
379
|
*/
|
|
395
380
|
function firstShortText(cells, values) {
|
|
396
381
|
const named = Object.entries(cells ?? {}).find(([, sub]) => {
|
|
@@ -401,8 +386,7 @@ function firstShortText(cells, values) {
|
|
|
401
386
|
return undefined;
|
|
402
387
|
return titleText(ownValue(values, named[0])).trim() || undefined;
|
|
403
388
|
}
|
|
404
|
-
/** A collapsed row's own words ({@link firstShortText})
|
|
405
|
-
* nothing to say for itself. */
|
|
389
|
+
/** A collapsed row's own words ({@link firstShortText}). */
|
|
406
390
|
export function rowSummary(items, row) {
|
|
407
391
|
return firstShortText(items?.properties, (row ?? {}));
|
|
408
392
|
}
|
|
@@ -451,7 +435,7 @@ export function commitDiscriminant(value, member) {
|
|
|
451
435
|
delete next[VARIANT_DISCRIMINANT];
|
|
452
436
|
return Object.keys(next).length ? next : undefined;
|
|
453
437
|
}
|
|
454
|
-
/** `foo_bar` → `Foo bar
|
|
438
|
+
/** `foo_bar` → `Foo bar`. */
|
|
455
439
|
export function humanize(name) {
|
|
456
440
|
const spaced = name.replace(/_/g, ' ').trim();
|
|
457
441
|
return spaced ? spaced[0].toUpperCase() + spaced.slice(1) : spaced;
|
|
@@ -483,10 +467,8 @@ export function fieldModels(cardSchema) {
|
|
|
483
467
|
});
|
|
484
468
|
}
|
|
485
469
|
/**
|
|
486
|
-
* Group-section order (VISUAL_EDITOR §"Structure mirrors the schema"): the
|
|
487
|
-
*
|
|
488
|
-
* boundary, so this reads it uncast: else the first-appearance order of each
|
|
489
|
-
* field's `ui.group`.
|
|
470
|
+
* Group-section order (VISUAL_EDITOR §"Structure mirrors the schema"): the `ui.groups` key order,
|
|
471
|
+
* else first appearance of each field's `ui.group`.
|
|
490
472
|
*/
|
|
491
473
|
export function groupOrder(cardSchema) {
|
|
492
474
|
const groups = cardSchema.ui?.groups;
|
|
@@ -500,20 +482,13 @@ export function groupOrder(cardSchema) {
|
|
|
500
482
|
}
|
|
501
483
|
return order;
|
|
502
484
|
}
|
|
503
|
-
/**
|
|
504
|
-
* A group's display label: the `ui.groups[g].title` override when the registry
|
|
505
|
-
* declares one, else the humanized id (`memo_for` → "Memo for"): the same
|
|
506
|
-
* id-derives-the-label rule a field's key follows.
|
|
507
|
-
*/
|
|
485
|
+
/** A group's `ui.groups[g].title`, else the humanized id. */
|
|
508
486
|
export function groupLabel(cardSchema, group) {
|
|
509
487
|
return cardSchema.ui?.groups?.[group]?.title ?? humanize(group);
|
|
510
488
|
}
|
|
511
489
|
/**
|
|
512
|
-
*
|
|
513
|
-
*
|
|
514
|
-
* groups (including the ungrouped bucket) in first-appearance order. `labelFor`
|
|
515
|
-
* resolves a group id to its display label: always {@link groupLabel} bound to
|
|
516
|
-
* the card schema, which falls back to {@link humanize} itself.
|
|
490
|
+
* Declared groups first (in `order`), then any remaining groups, including the ungrouped bucket, in
|
|
491
|
+
* first-appearance order.
|
|
517
492
|
*/
|
|
518
493
|
export function groupSections(fields, order, labelFor) {
|
|
519
494
|
const sections = [];
|
|
@@ -568,18 +543,9 @@ export function cardSections(cardSchema) {
|
|
|
568
543
|
return [...panels, ...groupSections(grouped, order, (g) => groupLabel(cardSchema, g))];
|
|
569
544
|
}
|
|
570
545
|
/**
|
|
571
|
-
* The group section a card's accordion opens on first mount
|
|
572
|
-
*
|
|
573
|
-
* the
|
|
574
|
-
*
|
|
575
|
-
* A card opens on fields. All-collapsed paints as a stack of chevrons that name
|
|
576
|
-
* their sections and disclose nothing of what is behind them, and a body leaf is
|
|
577
|
-
* no substitute: on a card carrying both, the fields are what the card is for.
|
|
578
|
-
* The first section is the one `ui.groups` already ranks highest, and it is the
|
|
579
|
-
* same section on every mount: a rule keyed on document state would move the
|
|
580
|
-
* opening under a user as they fill.
|
|
581
|
-
*
|
|
582
|
-
* State is ephemeral session state the Card owns; this only seeds it.
|
|
546
|
+
* The group section a card's accordion opens on first mount, or `null` when the card declares none.
|
|
547
|
+
* All-collapsed would disclose nothing of what is behind the chevrons, and a rule keyed on document
|
|
548
|
+
* state would move the opening under a user as they fill.
|
|
583
549
|
*/
|
|
584
550
|
export function initialExpandedGroup(sections) {
|
|
585
551
|
return sections.find((s) => s.group != null)?.group ?? null;
|
|
@@ -613,15 +579,9 @@ function packable(f) {
|
|
|
613
579
|
return f.control !== 'prose' || f.inline;
|
|
614
580
|
}
|
|
615
581
|
/**
|
|
616
|
-
*
|
|
617
|
-
* `
|
|
618
|
-
*
|
|
619
|
-
* A run of one is stranded — nothing packed beside it, and no row above to align to —
|
|
620
|
-
* so it is `full` like the shapes that declined: a lone narrow track reads as truncated
|
|
621
|
-
* against the width it leaves empty, and sharing was the whole of what asked for it.
|
|
622
|
-
* Everything else is `full`.
|
|
623
|
-
*
|
|
624
|
-
* Pure, and stays pure: no width, no measurement, nothing to re-derive on resize.
|
|
582
|
+
* Consecutive packable fields are `cell`s the grid auto-places; a trailing orphan keeps its column
|
|
583
|
+
* width. A run of one is `full`: a lone narrow track reads as truncated against the width it leaves
|
|
584
|
+
* empty. Everything else is `full`. No width is measured.
|
|
625
585
|
*/
|
|
626
586
|
export function placeFields(fields) {
|
|
627
587
|
const out = [];
|
|
@@ -693,7 +653,6 @@ export function cardTitle(cardSchema, kind, values, extTitle) {
|
|
|
693
653
|
return t;
|
|
694
654
|
return firstShortText(cardSchema?.fields, values) ?? humanize(kind);
|
|
695
655
|
}
|
|
696
|
-
/** Whether a card kind renders a body leaf: gated by `body.enabled !== false`. */
|
|
697
656
|
export function bodyEnabled(cardSchema) {
|
|
698
657
|
return cardSchema?.body?.enabled !== false;
|
|
699
658
|
}
|
|
@@ -702,10 +661,10 @@ export function bodyEnabled(cardSchema) {
|
|
|
702
661
|
// so a stable card-instance key cannot be the card object (a fresh object every
|
|
703
662
|
// derive): it is a session id held in a parallel array, reordered in lockstep
|
|
704
663
|
// with the structure ops and resolved to an index only at the mutation boundary.
|
|
705
|
-
/**
|
|
706
|
-
* session
|
|
707
|
-
*
|
|
708
|
-
|
|
664
|
+
/**
|
|
665
|
+
* A monotonic per-session id source of opaque strings. An id resolves to its index by
|
|
666
|
+
* `ids.indexOf(id)` at the mutation boundary, never cached.
|
|
667
|
+
*/
|
|
709
668
|
export class IdSeq {
|
|
710
669
|
#n = 0;
|
|
711
670
|
next() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quillmark/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.0",
|
|
4
4
|
"description": "Editor, live-preview and source surfaces over a Quillmark WASM session.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"check": "svelte-check --tsconfig ./tsconfig.json --fail-on-warnings"
|
|
70
70
|
},
|
|
71
71
|
"peerDependencies": {
|
|
72
|
-
"@quillmark/wasm": ">=0.
|
|
72
|
+
"@quillmark/wasm": ">=0.133.0-0",
|
|
73
73
|
"svelte": "^5.33.0"
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|