@quillmark/svelte 0.0.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/LICENSE +201 -0
- package/NOTICE +58 -0
- package/README.md +241 -0
- package/THEMING.md +153 -0
- package/dist/core/address.d.ts +56 -0
- package/dist/core/address.js +95 -0
- package/dist/core/bloom.d.ts +37 -0
- package/dist/core/bloom.js +116 -0
- package/dist/core/codec/anchor.d.ts +19 -0
- package/dist/core/codec/anchor.js +36 -0
- package/dist/core/codec/code.d.ts +12 -0
- package/dist/core/codec/code.js +118 -0
- package/dist/core/codec/decode.d.ts +24 -0
- package/dist/core/codec/decode.js +270 -0
- package/dist/core/codec/encode.d.ts +71 -0
- package/dist/core/codec/encode.js +480 -0
- package/dist/core/codec/field.d.ts +171 -0
- package/dist/core/codec/field.js +493 -0
- package/dist/core/codec/index.d.ts +22 -0
- package/dist/core/codec/index.js +43 -0
- package/dist/core/codec/inputrules.d.ts +7 -0
- package/dist/core/codec/inputrules.js +168 -0
- package/dist/core/codec/islands.d.ts +36 -0
- package/dist/core/codec/islands.js +82 -0
- package/dist/core/codec/keymap.d.ts +13 -0
- package/dist/core/codec/keymap.js +29 -0
- package/dist/core/codec/lists.d.ts +22 -0
- package/dist/core/codec/lists.js +104 -0
- package/dist/core/codec/marks.d.ts +37 -0
- package/dist/core/codec/marks.js +74 -0
- package/dist/core/codec/positions.d.ts +17 -0
- package/dist/core/codec/positions.js +108 -0
- package/dist/core/codec/prose.css +458 -0
- package/dist/core/codec/reconcile.d.ts +26 -0
- package/dist/core/codec/reconcile.js +64 -0
- package/dist/core/codec/schema.d.ts +13 -0
- package/dist/core/codec/schema.js +155 -0
- package/dist/core/codec/slash.d.ts +79 -0
- package/dist/core/codec/slash.js +0 -0
- package/dist/core/codec/table-view.d.ts +50 -0
- package/dist/core/codec/table-view.js +928 -0
- package/dist/core/codec/table.d.ts +85 -0
- package/dist/core/codec/table.js +224 -0
- package/dist/core/errors.d.ts +73 -0
- package/dist/core/errors.js +24 -0
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +19 -0
- package/dist/core/lifecycle.d.ts +7 -0
- package/dist/core/lifecycle.js +21 -0
- package/dist/core/rebind.svelte.d.ts +18 -0
- package/dist/core/rebind.svelte.js +44 -0
- package/dist/core/teardown.d.ts +20 -0
- package/dist/core/teardown.js +37 -0
- package/dist/core/theme.css +276 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +9 -0
- package/dist/preset/index.css +10 -0
- package/dist/preset/recipes.css +188 -0
- package/dist/preset/scale.css +97 -0
- package/dist/preview/Preview.svelte +118 -0
- package/dist/preview/Preview.svelte.d.ts +39 -0
- package/dist/preview/bridge.d.ts +13 -0
- package/dist/preview/bridge.js +88 -0
- package/dist/preview/controller.d.ts +40 -0
- package/dist/preview/controller.js +141 -0
- package/dist/preview/geometry.d.ts +37 -0
- package/dist/preview/geometry.js +45 -0
- package/dist/preview/index.d.ts +5 -0
- package/dist/preview/index.js +14 -0
- package/dist/preview/overlay.d.ts +10 -0
- package/dist/preview/overlay.js +82 -0
- package/dist/preview/paint.d.ts +17 -0
- package/dist/preview/paint.js +262 -0
- package/dist/preview/strings.d.ts +14 -0
- package/dist/preview/strings.js +22 -0
- package/dist/visual/ArrayField.svelte +362 -0
- package/dist/visual/ArrayField.svelte.d.ts +24 -0
- package/dist/visual/BooleanField.svelte +88 -0
- package/dist/visual/BooleanField.svelte.d.ts +20 -0
- package/dist/visual/Card.svelte +849 -0
- package/dist/visual/Card.svelte.d.ts +43 -0
- package/dist/visual/CardControls.svelte +92 -0
- package/dist/visual/CardControls.svelte.d.ts +11 -0
- package/dist/visual/DateField.svelte +203 -0
- package/dist/visual/DateField.svelte.d.ts +28 -0
- package/dist/visual/DiagnosticList.svelte +50 -0
- package/dist/visual/DiagnosticList.svelte.d.ts +7 -0
- package/dist/visual/EnumField.svelte +169 -0
- package/dist/visual/EnumField.svelte.d.ts +25 -0
- package/dist/visual/Field.svelte +270 -0
- package/dist/visual/Field.svelte.d.ts +37 -0
- package/dist/visual/FieldHint.svelte +185 -0
- package/dist/visual/FieldHint.svelte.d.ts +13 -0
- package/dist/visual/FieldLabel.svelte +141 -0
- package/dist/visual/FieldLabel.svelte.d.ts +19 -0
- package/dist/visual/FormatPopover.svelte +396 -0
- package/dist/visual/FormatPopover.svelte.d.ts +9 -0
- package/dist/visual/NumberField.svelte +72 -0
- package/dist/visual/NumberField.svelte.d.ts +19 -0
- package/dist/visual/ObjectField.svelte +131 -0
- package/dist/visual/ObjectField.svelte.d.ts +17 -0
- package/dist/visual/ProseArrayElement.svelte +98 -0
- package/dist/visual/ProseArrayElement.svelte.d.ts +19 -0
- package/dist/visual/ProseField.svelte +213 -0
- package/dist/visual/ProseField.svelte.d.ts +50 -0
- package/dist/visual/SlashMenu.svelte +126 -0
- package/dist/visual/SlashMenu.svelte.d.ts +14 -0
- package/dist/visual/TextField.svelte +63 -0
- package/dist/visual/TextField.svelte.d.ts +23 -0
- package/dist/visual/TipsCard.svelte +191 -0
- package/dist/visual/TipsCard.svelte.d.ts +13 -0
- package/dist/visual/VisualEditor.svelte +96 -0
- package/dist/visual/VisualEditor.svelte.d.ts +14 -0
- package/dist/visual/VisualEditorInner.svelte +1032 -0
- package/dist/visual/VisualEditorInner.svelte.d.ts +17 -0
- package/dist/visual/controls.css +272 -0
- package/dist/visual/diagnostics.d.ts +52 -0
- package/dist/visual/diagnostics.js +83 -0
- package/dist/visual/domid.d.ts +21 -0
- package/dist/visual/domid.js +36 -0
- package/dist/visual/ext.d.ts +19 -0
- package/dist/visual/ext.js +29 -0
- package/dist/visual/icons/Icon.svelte +39 -0
- package/dist/visual/icons/Icon.svelte.d.ts +12 -0
- package/dist/visual/icons/nodes.d.ts +103 -0
- package/dist/visual/icons/nodes.js +55 -0
- package/dist/visual/index.d.ts +9 -0
- package/dist/visual/index.js +24 -0
- package/dist/visual/motion.d.ts +18 -0
- package/dist/visual/motion.js +53 -0
- package/dist/visual/props.d.ts +77 -0
- package/dist/visual/props.js +1 -0
- package/dist/visual/signals.d.ts +59 -0
- package/dist/visual/signals.js +1 -0
- package/dist/visual/strings.d.ts +123 -0
- package/dist/visual/strings.js +80 -0
- package/dist/visual/structure.d.ts +224 -0
- package/dist/visual/structure.js +270 -0
- package/dist/visual/synced.svelte.d.ts +15 -0
- package/dist/visual/synced.svelte.js +34 -0
- package/dist/visual/tips.d.ts +24 -0
- package/dist/visual/tips.js +50 -0
- package/package.json +102 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The ephemeral tips card. Renders the
|
|
3
|
+
`$ext.editor.tips` channel one tip at a time: dots reach any tip in the set, and the
|
|
4
|
+
foot's one button advances until the last, where it becomes the dismiss. Dismissal
|
|
5
|
+
CLEARS the channel in the Document, so the card is gone and does not reappear.
|
|
6
|
+
|
|
7
|
+
The cursor is LOCAL state, not the channel. Advancing writes nothing: a per-tip
|
|
8
|
+
write would round-trip the boundary, re-derive the card tree, and dirty the
|
|
9
|
+
document (firing a consumer's autosave) on what is a read gesture. Exactly one
|
|
10
|
+
write happens, at dismissal, and this component unmounts with it, so the cursor
|
|
11
|
+
needs no reset.
|
|
12
|
+
-->
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import { wording } from './strings.js';
|
|
15
|
+
|
|
16
|
+
// The surface's words, ambient from the editor root; the package's English
|
|
17
|
+
// off-tree, so this component renders standalone too.
|
|
18
|
+
const t = wording();
|
|
19
|
+
import Icon from './icons/Icon.svelte';
|
|
20
|
+
import { renderTip } from './tips.js';
|
|
21
|
+
import type { EditorErrorHandler } from '../core/errors.js';
|
|
22
|
+
import './controls.css';
|
|
23
|
+
|
|
24
|
+
interface Props {
|
|
25
|
+
/** The narrowed channel (`tipsChannel`); never empty; the parent gates on length. */
|
|
26
|
+
tips: string[];
|
|
27
|
+
/** Clear `$ext.editor.tips`: the patch-write that preserves the `title` sibling. */
|
|
28
|
+
onDismiss: () => void;
|
|
29
|
+
/** A tip whose markdown did not render; it shows literally either way. */
|
|
30
|
+
onError?: EditorErrorHandler;
|
|
31
|
+
}
|
|
32
|
+
let { tips, onDismiss, onError }: Props = $props();
|
|
33
|
+
|
|
34
|
+
/** Control-glyph size: the shared rule, as CardControls. */
|
|
35
|
+
const GLYPH = 14;
|
|
36
|
+
|
|
37
|
+
let cursor = $state(0);
|
|
38
|
+
// Clamped: the channel is consumer-authored and can be re-seeded shorter while
|
|
39
|
+
// the card is open, which would otherwise index past the end.
|
|
40
|
+
const index = $derived(Math.min(cursor, tips.length - 1));
|
|
41
|
+
const isLast = $derived(index >= tips.length - 1);
|
|
42
|
+
|
|
43
|
+
// The tip STRING is derived before the effect reads it, and that is load-bearing.
|
|
44
|
+
// Reading `tips[index]` inside the effect makes the parent's `model` derive the
|
|
45
|
+
// dependency (a fresh object every `revision` bump) so the effect would re-run
|
|
46
|
+
// on every unrelated commit, re-crossing the WASM boundary and rebuilding this
|
|
47
|
+
// `aria-live` region per keystroke. A derived string short-circuits on `===`.
|
|
48
|
+
const tip = $derived(tips[index] ?? '');
|
|
49
|
+
|
|
50
|
+
// The tip is DOM, not text: `renderTip` returns a fragment the codec's own
|
|
51
|
+
// `toDOM` built, so it is written in rather than interpolated.
|
|
52
|
+
let bodyEl: HTMLDivElement | undefined = $state();
|
|
53
|
+
$effect(() => {
|
|
54
|
+
const el = bodyEl;
|
|
55
|
+
if (el) el.replaceChildren(renderTip(tip, onError));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
function advance(): void {
|
|
59
|
+
if (isLast) onDismiss();
|
|
60
|
+
else cursor = index + 1;
|
|
61
|
+
}
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<aside class="qm-tips" aria-label={t.strings.tipsLabel}>
|
|
65
|
+
<!-- Advancing swaps the text under a button that keeps focus, so the region
|
|
66
|
+
announces rather than the change passing silently. -->
|
|
67
|
+
<div class="qm-tips-body" aria-live="polite" bind:this={bodyEl}></div>
|
|
68
|
+
<div class="qm-tips-foot">
|
|
69
|
+
<!-- One tip is its own whole set, so a lone dot reports nothing the card does
|
|
70
|
+
not already show. -->
|
|
71
|
+
{#if tips.length > 1}
|
|
72
|
+
<div class="qm-tips-dots">
|
|
73
|
+
{#each tips as _, i (i)}
|
|
74
|
+
<button
|
|
75
|
+
type="button"
|
|
76
|
+
class="qm-tips-dot"
|
|
77
|
+
aria-label={t.strings.tipsDot(i + 1, tips.length)}
|
|
78
|
+
aria-current={i === index}
|
|
79
|
+
onclick={() => (cursor = i)}
|
|
80
|
+
></button>
|
|
81
|
+
{/each}
|
|
82
|
+
</div>
|
|
83
|
+
{/if}
|
|
84
|
+
<!-- ONE button, and its action is where the cursor stands: the set is walked,
|
|
85
|
+
and its end is the exit. -->
|
|
86
|
+
<button type="button" class="qm-icon-btn qm-tips-action" onclick={advance}>
|
|
87
|
+
{#if isLast}
|
|
88
|
+
{t.strings.tipsDismiss} <Icon name="x" size={GLYPH} />
|
|
89
|
+
{:else}
|
|
90
|
+
{t.strings.tipsNext} <Icon name="chevron-right" size={GLYPH} />
|
|
91
|
+
{/if}
|
|
92
|
+
</button>
|
|
93
|
+
</div>
|
|
94
|
+
</aside>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
/* ATTACHED to `main`, not a block beside it: a square top pulled up by the radius,
|
|
98
|
+
so its background fills the notches `main`'s rounded bottom corners cut and `main`
|
|
99
|
+
paints over the rest. The seam is `main`'s own bottom hairline, and the two read as
|
|
100
|
+
one block, which is what document-level guidance is: the main card's, not a card of
|
|
101
|
+
its own. Still in-flow, one hairline, no lift, no fill beyond the card recipe. It
|
|
102
|
+
reads as guidance rather than as a field by TONE and TYPE: the label rung in the
|
|
103
|
+
muted label colour; not by a badge or an accent. It mints no token of its own;
|
|
104
|
+
every value here is an existing dial.
|
|
105
|
+
|
|
106
|
+
The top inset takes the tuck back, so the space above the tip is the space below
|
|
107
|
+
the foot.
|
|
108
|
+
|
|
109
|
+
Leading is the reading rung, not the tight one the label SIZE would suggest: a
|
|
110
|
+
tip is a passage that wraps, and the two axes are independent. */
|
|
111
|
+
.qm-tips {
|
|
112
|
+
margin-top: calc(var(--_qm-radius) * -1);
|
|
113
|
+
border: var(--_qm-border-width) solid var(--_qm-border);
|
|
114
|
+
border-radius: 0 0 var(--_qm-radius) var(--_qm-radius);
|
|
115
|
+
padding: calc(var(--_qm-space-3) + var(--_qm-radius)) var(--_qm-space-3) var(--_qm-space-3);
|
|
116
|
+
background: var(--_qm-surface-raised);
|
|
117
|
+
display: flex;
|
|
118
|
+
flex-direction: column;
|
|
119
|
+
gap: var(--_qm-space-2);
|
|
120
|
+
font-size: var(--_qm-text-label);
|
|
121
|
+
line-height: var(--_qm-leading-body);
|
|
122
|
+
color: var(--_qm-ink-label);
|
|
123
|
+
}
|
|
124
|
+
/* The rendered tip is injected DOM (the codec's `toDOM` output), so its element
|
|
125
|
+
styles are `:global`: the compiler never sees these tags in the markup. Three
|
|
126
|
+
rules restated from `core/codec/prose.css`, which is where they are argued and
|
|
127
|
+
which cannot reach here: its selectors are scoped to `.ProseMirror` and a tip is
|
|
128
|
+
not a view. The one deliberate divergence is the link, which takes no underline:
|
|
129
|
+
a tip is not editable, so a hidden `href` costs its reader nothing. */
|
|
130
|
+
.qm-tips-body :global(p) {
|
|
131
|
+
margin: 0;
|
|
132
|
+
}
|
|
133
|
+
.qm-tips-body :global(code) {
|
|
134
|
+
font-family: var(--_qm-font-mono);
|
|
135
|
+
}
|
|
136
|
+
.qm-tips-body :global(a) {
|
|
137
|
+
color: inherit;
|
|
138
|
+
}
|
|
139
|
+
.qm-tips-foot {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: flex-end;
|
|
143
|
+
gap: var(--_qm-space-2);
|
|
144
|
+
}
|
|
145
|
+
.qm-tips-dots {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
margin-right: auto;
|
|
149
|
+
}
|
|
150
|
+
/* Random access to the set, and the PITCH is the tap floor: 2.5.8's spacing
|
|
151
|
+
exception measures centre distance, which is the number the floor already fixes,
|
|
152
|
+
so a tighter row of dots buys nothing it does not immediately owe back. Target and
|
|
153
|
+
mark are therefore not one rectangle (the floor is the button, the dot is drawn
|
|
154
|
+
inside it), which is also why the hover reads on the mark rather than filling the
|
|
155
|
+
box a `.qm-icon-btn` would. */
|
|
156
|
+
.qm-tips-dot {
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
box-sizing: border-box;
|
|
161
|
+
min-width: var(--_qm-tap-min);
|
|
162
|
+
min-height: var(--_qm-tap-min);
|
|
163
|
+
border: none;
|
|
164
|
+
background: transparent;
|
|
165
|
+
cursor: pointer;
|
|
166
|
+
}
|
|
167
|
+
/* Three steps of ONE ink on the recede ladder (rest, hover, current), never a
|
|
168
|
+
second hue and never a size: a dot that grew would move the row it sits in. */
|
|
169
|
+
.qm-tips-dot::before {
|
|
170
|
+
content: '';
|
|
171
|
+
width: 5px;
|
|
172
|
+
height: 5px;
|
|
173
|
+
border-radius: var(--_qm-radius-pill);
|
|
174
|
+
background: currentColor;
|
|
175
|
+
opacity: var(--_qm-opacity-idle);
|
|
176
|
+
transition: opacity var(--_qm-duration-fast) var(--_qm-ease-reverse);
|
|
177
|
+
}
|
|
178
|
+
.qm-tips-dot:hover::before {
|
|
179
|
+
opacity: var(--_qm-opacity-muted);
|
|
180
|
+
}
|
|
181
|
+
.qm-tips-dot[aria-current='true']::before {
|
|
182
|
+
opacity: 1;
|
|
183
|
+
}
|
|
184
|
+
/* Box and disabled state come from `.qm-icon-btn` (controls.css); the foot's
|
|
185
|
+
button carries a label and so widens its inset and takes the meta type rung. */
|
|
186
|
+
.qm-tips-action {
|
|
187
|
+
padding: var(--_qm-space-half) var(--_qm-space-2);
|
|
188
|
+
font-size: var(--_qm-text-meta);
|
|
189
|
+
color: var(--_qm-ink-label);
|
|
190
|
+
}
|
|
191
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { EditorErrorHandler } from '../core/errors.js';
|
|
2
|
+
import './controls.css';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** The narrowed channel (`tipsChannel`); never empty; the parent gates on length. */
|
|
5
|
+
tips: string[];
|
|
6
|
+
/** Clear `$ext.editor.tips`: the patch-write that preserves the `title` sibling. */
|
|
7
|
+
onDismiss: () => void;
|
|
8
|
+
/** A tip whose markdown did not render; it shows literally either way. */
|
|
9
|
+
onError?: EditorErrorHandler;
|
|
10
|
+
}
|
|
11
|
+
declare const TipsCard: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type TipsCard = ReturnType<typeof TipsCard>;
|
|
13
|
+
export default TipsCard;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The editor's door, and the whole of what it adds is the re-key: swapping the
|
|
3
|
+
`doc` prop remounts the editor under it, so a consumer holding one mount across
|
|
4
|
+
two documents gets a surface that names the live handle.
|
|
5
|
+
|
|
6
|
+
IT IS A `{#key}`, NOT A RESEED. The state a swap invalidates is not one field:
|
|
7
|
+
composable cards key on session id, the main card is keyed on nothing, and each
|
|
8
|
+
prose leaf mounts once per stable leaf key with `createField` closing over the
|
|
9
|
+
`doc` it mounted against — so after an in-place swap the main card's leaves
|
|
10
|
+
commit to the PREVIOUS handle. Reseeding by hand means threading a generation
|
|
11
|
+
token through every leaf key and resetting the id state, the commit-error map,
|
|
12
|
+
the active address, the leaf registry, the card refs and any pending scroll,
|
|
13
|
+
which is a remount spelled out one field at a time. This spells it as one.
|
|
14
|
+
|
|
15
|
+
Teardown order is the one `core/teardown.ts` states: the outgoing mount
|
|
16
|
+
unregisters, cancels its pending ticks, and only then releases, so a continuation
|
|
17
|
+
awaiting a flush across the swap runs against nothing.
|
|
18
|
+
|
|
19
|
+
`quill` is NOT part of the key: the schema is re-read on every derive, so a quill
|
|
20
|
+
swap re-projects correctly on its own, and keying on it would throw away a card
|
|
21
|
+
tree that did not need rebuilding. What it cannot do is re-mount the leaves, so a
|
|
22
|
+
quill swapped WITHOUT a doc swap reports `rebind-ignored` rather than passing
|
|
23
|
+
silently.
|
|
24
|
+
-->
|
|
25
|
+
<script lang="ts">
|
|
26
|
+
import { untrack } from 'svelte';
|
|
27
|
+
import { reportError } from '../core/errors.js';
|
|
28
|
+
import type { ContentHit } from '@quillmark/wasm';
|
|
29
|
+
import type { DocPath } from '../core/address.js';
|
|
30
|
+
import type { CardId } from './signals.js';
|
|
31
|
+
import type { VisualEditorProps } from './props.js';
|
|
32
|
+
import VisualEditorInner from './VisualEditorInner.svelte';
|
|
33
|
+
|
|
34
|
+
let props: VisualEditorProps = $props();
|
|
35
|
+
|
|
36
|
+
let inner = $state<VisualEditorInner | undefined>();
|
|
37
|
+
|
|
38
|
+
// The pair the CURRENT mount bound to. Re-read on each re-key rather than held
|
|
39
|
+
// from the first mount: after a doc swap the incoming mount binds whatever quill
|
|
40
|
+
// came with it, and comparing against the original would report a pairing that
|
|
41
|
+
// is correct.
|
|
42
|
+
let boundDoc: unknown = undefined;
|
|
43
|
+
let boundQuill: unknown = undefined;
|
|
44
|
+
let reported = false;
|
|
45
|
+
$effect(() => {
|
|
46
|
+
const { doc, quill } = props;
|
|
47
|
+
untrack(() => {
|
|
48
|
+
// A doc swap re-keys, and the new mount binds this quill: nothing is stale.
|
|
49
|
+
if (doc !== boundDoc) {
|
|
50
|
+
boundDoc = doc;
|
|
51
|
+
boundQuill = quill;
|
|
52
|
+
reported = false;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (quill === boundQuill || reported) return;
|
|
56
|
+
reported = true;
|
|
57
|
+
reportError(props.onError, {
|
|
58
|
+
code: 'rebind-ignored',
|
|
59
|
+
severity: 'dev',
|
|
60
|
+
message:
|
|
61
|
+
'quill swapped in place; the mounted leaves still commit against the quill this doc mounted with. Swap the doc with it, or remount the editor, to rebind.'
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// The instance surface, every member a pass-through to the live mount: a call
|
|
67
|
+
// landing between a swap and the incoming mount is a no-op rather than a throw,
|
|
68
|
+
// which is what lets a host hold ONE `bind:this` across two documents.
|
|
69
|
+
|
|
70
|
+
/** Place the caret at a preview hit. */
|
|
71
|
+
export async function setCaret(hit: ContentHit): Promise<void> {
|
|
72
|
+
await inner?.setCaret(hit);
|
|
73
|
+
}
|
|
74
|
+
/** Reveal and focus the leaf at `field`, without placing a caret inside it. */
|
|
75
|
+
export async function focusField(field: DocPath): Promise<void> {
|
|
76
|
+
await inner?.focusField(field);
|
|
77
|
+
}
|
|
78
|
+
/** Seed a card of `kind` at `at` (default: the end); the new card's session key. */
|
|
79
|
+
export function insertCard(kind: string, at?: number): CardId | undefined {
|
|
80
|
+
return inner?.insertCard(kind, at);
|
|
81
|
+
}
|
|
82
|
+
export function removeCard(cardId: CardId): void {
|
|
83
|
+
inner?.removeCard(cardId);
|
|
84
|
+
}
|
|
85
|
+
/** Move a card one slot; at either edge it is a no-op. */
|
|
86
|
+
export function moveCard(cardId: CardId, dir: -1 | 1): void {
|
|
87
|
+
inner?.moveCard(cardId, dir);
|
|
88
|
+
}
|
|
89
|
+
export function setKind(cardId: CardId, kind: string): void {
|
|
90
|
+
inner?.setKind(cardId, kind);
|
|
91
|
+
}
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
{#key props.doc}
|
|
95
|
+
<VisualEditorInner bind:this={inner} {...props} />
|
|
96
|
+
{/key}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ContentHit } from '@quillmark/wasm';
|
|
2
|
+
import type { DocPath } from '../core/address.js';
|
|
3
|
+
import type { CardId } from './signals.js';
|
|
4
|
+
import type { VisualEditorProps } from './props.js';
|
|
5
|
+
declare const VisualEditor: import("svelte").Component<VisualEditorProps, {
|
|
6
|
+
setCaret: (hit: ContentHit) => Promise<void>;
|
|
7
|
+
focusField: (field: DocPath) => Promise<void>;
|
|
8
|
+
insertCard: (kind: string, at?: number) => CardId | undefined;
|
|
9
|
+
removeCard: (cardId: CardId) => void;
|
|
10
|
+
moveCard: (cardId: CardId, dir: -1 | 1) => void;
|
|
11
|
+
setKind: (cardId: CardId, kind: string) => void;
|
|
12
|
+
}, "">;
|
|
13
|
+
type VisualEditor = ReturnType<typeof VisualEditor>;
|
|
14
|
+
export default VisualEditor;
|