svedit 0.11.1 → 0.13.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 +260 -82
- package/dist/Command.svelte.d.ts +54 -29
- package/dist/Command.svelte.d.ts.map +1 -1
- package/dist/Command.svelte.js +286 -283
- package/dist/CustomProperty.svelte +3 -5
- package/dist/CustomProperty.svelte.d.ts +3 -6
- package/dist/CustomProperty.svelte.d.ts.map +1 -1
- package/dist/KeyMapper.svelte.d.ts +19 -6
- package/dist/KeyMapper.svelte.d.ts.map +1 -1
- package/dist/KeyMapper.svelte.js +95 -112
- package/dist/Node.svelte +40 -9
- package/dist/Node.svelte.d.ts +3 -5
- package/dist/Node.svelte.d.ts.map +1 -1
- package/dist/NodeArrayProperty.svelte +142 -18
- package/dist/NodeArrayProperty.svelte.d.ts +3 -5
- package/dist/NodeArrayProperty.svelte.d.ts.map +1 -1
- package/dist/NodeCaret.svelte +1 -1
- package/dist/NodeCaret.svelte.d.ts +6 -14
- package/dist/NodeCaret.svelte.d.ts.map +1 -1
- package/dist/NodeGap.svelte +60 -12
- package/dist/NodeGap.svelte.d.ts +7 -14
- package/dist/NodeGap.svelte.d.ts.map +1 -1
- package/dist/NodeGapMarkers.svelte +19 -10
- package/dist/NodeGapMarkers.svelte.d.ts +6 -11
- package/dist/NodeGapMarkers.svelte.d.ts.map +1 -1
- package/dist/NodeSelectionMarkers.svelte +20 -6
- package/dist/NodeSelectionMarkers.svelte.d.ts +2 -5
- package/dist/NodeSelectionMarkers.svelte.d.ts.map +1 -1
- package/dist/Session.svelte.d.ts +85 -116
- package/dist/Session.svelte.d.ts.map +1 -1
- package/dist/Session.svelte.js +543 -571
- package/dist/Svedit.svelte +243 -216
- package/dist/Svedit.svelte.d.ts +30 -10
- package/dist/Svedit.svelte.d.ts.map +1 -1
- package/dist/{AnnotatedTextProperty.svelte → TextProperty.svelte} +71 -56
- package/dist/TextProperty.svelte.d.ts +5 -0
- package/dist/TextProperty.svelte.d.ts.map +1 -0
- package/dist/Transaction.svelte.d.ts +101 -126
- package/dist/Transaction.svelte.d.ts.map +1 -1
- package/dist/Transaction.svelte.js +843 -827
- package/dist/UnknownNode.svelte +4 -3
- package/dist/UnknownNode.svelte.d.ts +5 -9
- package/dist/UnknownNode.svelte.d.ts.map +1 -1
- package/dist/doc_utils.d.ts +109 -122
- package/dist/doc_utils.d.ts.map +1 -1
- package/dist/doc_utils.js +726 -698
- package/dist/index.d.ts +20 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -18
- package/dist/node_visibility.svelte.d.ts +132 -5
- package/dist/node_visibility.svelte.d.ts.map +1 -1
- package/dist/node_visibility.svelte.js +535 -642
- package/dist/paste_utils.d.ts +11 -43
- package/dist/paste_utils.d.ts.map +1 -1
- package/dist/paste_utils.js +111 -149
- package/dist/transforms.svelte.d.ts +9 -7
- package/dist/transforms.svelte.d.ts.map +1 -1
- package/dist/transforms.svelte.js +126 -152
- package/dist/types.d.ts +329 -291
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +79 -95
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +392 -305
- package/package.json +69 -67
- package/src/lib/{Command.svelte.js → Command.svelte.ts} +111 -41
- package/src/lib/CustomProperty.svelte +3 -5
- package/src/lib/{KeyMapper.svelte.js → KeyMapper.svelte.ts} +28 -11
- package/src/lib/Node.svelte +40 -9
- package/src/lib/NodeArrayProperty.svelte +142 -18
- package/src/lib/NodeCaret.svelte +1 -1
- package/src/lib/NodeGap.svelte +60 -12
- package/src/lib/NodeGapMarkers.svelte +19 -10
- package/src/lib/NodeSelectionMarkers.svelte +20 -6
- package/src/lib/Session.svelte.ts +656 -0
- package/src/lib/Svedit.svelte +243 -216
- package/src/lib/{AnnotatedTextProperty.svelte → TextProperty.svelte} +71 -56
- package/src/lib/Transaction.svelte.ts +1020 -0
- package/src/lib/UnknownNode.svelte +4 -3
- package/src/lib/doc_utils.ts +1120 -0
- package/src/lib/{index.js → index.ts} +48 -1
- package/src/lib/node_visibility.svelte.ts +658 -0
- package/src/lib/{paste_utils.js → paste_utils.ts} +51 -59
- package/src/lib/{transforms.svelte.js → transforms.svelte.ts} +44 -27
- package/src/lib/{types.d.ts → types.ts} +250 -103
- package/src/lib/utils.ts +660 -0
- package/dist/AnnotatedTextProperty.svelte.d.ts +0 -7
- package/dist/AnnotatedTextProperty.svelte.d.ts.map +0 -1
- package/src/lib/Session.svelte.js +0 -575
- package/src/lib/Transaction.svelte.js +0 -846
- package/src/lib/doc_utils.js +0 -807
- package/src/lib/node_visibility.svelte.js +0 -718
- package/src/lib/utils.js +0 -465
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeCaret.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeCaret.svelte.
|
|
1
|
+
{"version":3,"file":"NodeCaret.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeCaret.svelte.ts"],"names":[],"mappings":"AAmBA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,SAAS;;kBAA+E,CAAC;AAC7E,KAAK,SAAS,GAAG,YAAY,CAAC,OAAO,SAAS,CAAC,CAAC;AAClD,eAAe,SAAS,CAAC"}
|
package/dist/NodeGap.svelte
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
<script module>
|
|
2
|
-
function cycle_z_index(
|
|
3
|
-
const el =
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
function cycle_z_index(e: MouseEvent) {
|
|
3
|
+
const el = e.currentTarget as HTMLElement;
|
|
4
4
|
if (el.hasAttribute('data-sent-to-back')) {
|
|
5
5
|
document.querySelectorAll('.svedit-selectable[data-sent-to-back]').forEach((prev) => {
|
|
6
6
|
prev.removeAttribute('data-sent-to-back');
|
|
@@ -10,9 +10,11 @@
|
|
|
10
10
|
}
|
|
11
11
|
</script>
|
|
12
12
|
|
|
13
|
-
<script>
|
|
13
|
+
<script lang="ts">
|
|
14
14
|
import { serialize_path } from './utils.js';
|
|
15
15
|
import { getContext } from 'svelte';
|
|
16
|
+
import { should_position_gap } from './node_visibility.svelte.js';
|
|
17
|
+
import type { DocumentPath, SveditRenderContext } from './types.js';
|
|
16
18
|
|
|
17
19
|
/**
|
|
18
20
|
* ┌─────────────────────────────────────────────────────────────────┐
|
|
@@ -37,10 +39,13 @@
|
|
|
37
39
|
*
|
|
38
40
|
* Always present in the DOM when editable (stable structure for
|
|
39
41
|
* selection anchoring, scrollTo, etc.). Anchor positioning is
|
|
40
|
-
* activated lazily via the `.positioned` class,
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
42
|
+
* activated lazily via the `.positioned` class, derived reactively
|
|
43
|
+
* from the visibility registry's array_indices / edge_map. Svelte's
|
|
44
|
+
* reactive collections track reads at per-key granularity, so a
|
|
45
|
+
* registry write only
|
|
46
|
+
* re-evaluates the adjacent gaps. Applying the class declaratively
|
|
47
|
+
* (instead of imperative classList toggles) means it survives DOM
|
|
48
|
+
* recreation without a document change (e.g. dev-mode HMR).
|
|
44
49
|
*
|
|
45
50
|
* `position-visibility: anchors-visible` does NOT skip anchor
|
|
46
51
|
* resolution — the browser resolves all anchor() then hides the
|
|
@@ -54,14 +59,35 @@
|
|
|
54
59
|
* sure your custom component also handles read-only mode by rendering a
|
|
55
60
|
* plain `.node-gap` placeholder without editable internals.
|
|
56
61
|
*/
|
|
57
|
-
const svedit = getContext('svedit');
|
|
58
|
-
let {
|
|
62
|
+
const svedit = getContext<SveditRenderContext>('svedit');
|
|
63
|
+
let {
|
|
64
|
+
array_path,
|
|
65
|
+
offset,
|
|
66
|
+
count,
|
|
67
|
+
empty = false
|
|
68
|
+
}: { array_path: DocumentPath; offset: number; count: number; empty?: boolean } = $props();
|
|
59
69
|
let is_editable = $derived(svedit.editable);
|
|
60
70
|
|
|
61
71
|
let is_first = $derived(offset === 0);
|
|
62
72
|
let is_last = $derived(offset === count);
|
|
63
73
|
let type = $derived(is_first ? 'gap-before' : 'gap-after');
|
|
64
74
|
|
|
75
|
+
let path_str = $derived(serialize_path(array_path));
|
|
76
|
+
// Two-derived split is load-bearing: get_array_indices lazily
|
|
77
|
+
// creates the set, and Svelte doesn't track deps on state created
|
|
78
|
+
// inside the reading derived — so acquire here, read in `positioned`.
|
|
79
|
+
let near_indices = $derived(svedit.visibility_registry.get_array_indices(path_str));
|
|
80
|
+
let positioned = $derived(
|
|
81
|
+
is_editable &&
|
|
82
|
+
should_position_gap(
|
|
83
|
+
near_indices,
|
|
84
|
+
svedit.visibility_registry.edge_map.get(path_str),
|
|
85
|
+
offset,
|
|
86
|
+
is_last,
|
|
87
|
+
empty
|
|
88
|
+
)
|
|
89
|
+
);
|
|
90
|
+
|
|
65
91
|
let gap_style = $derived.by(() => {
|
|
66
92
|
if (!is_editable) return '';
|
|
67
93
|
const prev_idx = offset - 1;
|
|
@@ -87,8 +113,9 @@
|
|
|
87
113
|
class:gap-after={!is_first}
|
|
88
114
|
class:empty
|
|
89
115
|
class:last={is_last}
|
|
116
|
+
class:positioned
|
|
90
117
|
data-type={type}
|
|
91
|
-
data-gap-array-path={
|
|
118
|
+
data-gap-array-path={path_str}
|
|
92
119
|
data-gap-offset={offset}
|
|
93
120
|
style={gap_style}
|
|
94
121
|
>
|
|
@@ -111,9 +138,30 @@
|
|
|
111
138
|
}
|
|
112
139
|
|
|
113
140
|
/* ------------------------------------------------------------------ */
|
|
114
|
-
/* Un-positioned:
|
|
141
|
+
/* Un-positioned: no layout box at all */
|
|
115
142
|
/* ------------------------------------------------------------------ */
|
|
116
143
|
|
|
144
|
+
/*
|
|
145
|
+
* display: none is load-bearing for large documents. A zero-size
|
|
146
|
+
* absolutely-positioned selectable still belongs to the containing
|
|
147
|
+
* block's out-of-flow list, and the browser lays out EVERY such box
|
|
148
|
+
* on EVERY layout pass — measured ~430ms per pass at 2000 nodes
|
|
149
|
+
* (~3500 gaps) in Chrome vs ~23ms with the boxes removed. That cost
|
|
150
|
+
* hits every keystroke (the per-change reconcile reads a rect for
|
|
151
|
+
* every node, and selection rendering forces layout), every window
|
|
152
|
+
* resize frame, and every scroll-triggered layout.
|
|
153
|
+
*
|
|
154
|
+
* Off-screen gaps therefore contribute no layout box. DOM structure
|
|
155
|
+
* stays stable (the .node-gap wrapper and selectable elements remain),
|
|
156
|
+
* and DOM Ranges may still point into display:none elements, so
|
|
157
|
+
* programmatic node selections targeting off-screen gaps keep working.
|
|
158
|
+
* Empty-array gaps are excluded: they must stay clickable/visible even
|
|
159
|
+
* before reconcile positions them.
|
|
160
|
+
*/
|
|
161
|
+
:global(.node-gap:not(.positioned):not(.empty) .svedit-selectable) {
|
|
162
|
+
display: none;
|
|
163
|
+
}
|
|
164
|
+
|
|
117
165
|
:global(.node-gap:not(.positioned) .svedit-selectable) {
|
|
118
166
|
position: absolute;
|
|
119
167
|
pointer-events: none;
|
package/dist/NodeGap.svelte.d.ts
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
type NodeGap = {
|
|
3
|
-
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
-
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
-
};
|
|
6
|
-
declare const NodeGap: import("svelte").Component<{
|
|
7
|
-
array_path: any;
|
|
8
|
-
offset: any;
|
|
9
|
-
count: any;
|
|
10
|
-
empty?: boolean;
|
|
11
|
-
}, {}, "">;
|
|
1
|
+
import type { DocumentPath } from './types.js';
|
|
12
2
|
type $$ComponentProps = {
|
|
13
|
-
array_path:
|
|
14
|
-
offset:
|
|
15
|
-
count:
|
|
3
|
+
array_path: DocumentPath;
|
|
4
|
+
offset: number;
|
|
5
|
+
count: number;
|
|
16
6
|
empty?: boolean;
|
|
17
7
|
};
|
|
8
|
+
declare const NodeGap: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
9
|
+
type NodeGap = ReturnType<typeof NodeGap>;
|
|
10
|
+
export default NodeGap;
|
|
18
11
|
//# sourceMappingURL=NodeGap.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeGap.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGap.svelte.
|
|
1
|
+
{"version":3,"file":"NodeGap.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGap.svelte.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,YAAY,CAAC;AAEnE,KAAK,gBAAgB,GAAI;IAAE,UAAU,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAkHvG,QAAA,MAAM,OAAO,sDAAwC,CAAC;AACtD,KAAK,OAAO,GAAG,UAAU,CAAC,OAAO,OAAO,CAAC,CAAC;AAC1C,eAAe,OAAO,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import { getContext } from 'svelte';
|
|
3
3
|
import NodeCaret from './NodeCaret.svelte';
|
|
4
4
|
import { PATH_SEPARATOR, serialize_path } from './utils.js';
|
|
5
|
+
import type { DocumentPath, SveditRenderContext } from './types.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* ┌─────────────────────────────────────────────────────────────────┐
|
|
@@ -28,9 +29,9 @@
|
|
|
28
29
|
* re-evaluates when THIS array's visible-index set changes.
|
|
29
30
|
*/
|
|
30
31
|
|
|
31
|
-
let { path, count } = $props();
|
|
32
|
+
let { path, count }: { path: DocumentPath; count: number } = $props();
|
|
32
33
|
|
|
33
|
-
const svedit = getContext('svedit');
|
|
34
|
+
const svedit = getContext<SveditRenderContext>('svedit');
|
|
34
35
|
let path_str = $derived(serialize_path(path));
|
|
35
36
|
let visible = $derived(svedit.visibility_registry.get_array_indices(path_str));
|
|
36
37
|
|
|
@@ -51,8 +52,16 @@
|
|
|
51
52
|
? `;--_f:${anchor_prefix}${PATH_SEPARATOR}0;--_s:${anchor_prefix}${PATH_SEPARATOR}1`
|
|
52
53
|
: '';
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
type GapMarker = {
|
|
56
|
+
key: string;
|
|
57
|
+
offset: number;
|
|
58
|
+
type: string;
|
|
59
|
+
vars: string;
|
|
60
|
+
is_first: boolean;
|
|
61
|
+
is_last: boolean;
|
|
62
|
+
has_pair: boolean;
|
|
63
|
+
};
|
|
64
|
+
const result: GapMarker[] = [];
|
|
56
65
|
|
|
57
66
|
if (count === 0) {
|
|
58
67
|
if (visible.has(0)) {
|
|
@@ -73,15 +82,15 @@
|
|
|
73
82
|
// 1000 nodes with ~30 visible, this drops 1001 SvelteSet/SvelteMap
|
|
74
83
|
// reads per re-derivation to ~30. Filter stale indices >= count
|
|
75
84
|
// that may briefly remain after a node delete (until MO fires).
|
|
76
|
-
const sorted = [];
|
|
85
|
+
const sorted: number[] = [];
|
|
77
86
|
for (const i of visible) {
|
|
78
87
|
if (i >= 0 && i < count) sorted.push(i);
|
|
79
88
|
}
|
|
80
89
|
sorted.sort((a, b) => a - b);
|
|
81
90
|
if (sorted.length === 0) return result;
|
|
82
91
|
|
|
83
|
-
const offsets = [];
|
|
84
|
-
function add_offset(offset) {
|
|
92
|
+
const offsets: number[] = [];
|
|
93
|
+
function add_offset(offset: number) {
|
|
85
94
|
if (!offsets.includes(offset)) offsets.push(offset);
|
|
86
95
|
}
|
|
87
96
|
|
|
@@ -112,7 +121,7 @@
|
|
|
112
121
|
? `${g_prefix}${PATH_SEPARATOR}0-gap-before`
|
|
113
122
|
: `${g_prefix}${PATH_SEPARATOR}${offset - 1}-gap-after`;
|
|
114
123
|
|
|
115
|
-
let type, vars;
|
|
124
|
+
let type: string, vars: string;
|
|
116
125
|
if (is_first || is_last) {
|
|
117
126
|
type = 'gap-edge';
|
|
118
127
|
const adjacent = is_first
|
|
@@ -646,4 +655,4 @@
|
|
|
646
655
|
outline: 1px solid blue;
|
|
647
656
|
outline-offset: 0.5px;
|
|
648
657
|
} */
|
|
649
|
-
</style>
|
|
658
|
+
</style>
|
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
type NodeGapMarkers = {
|
|
3
|
-
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
-
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
-
};
|
|
6
|
-
declare const NodeGapMarkers: import("svelte").Component<{
|
|
7
|
-
path: any;
|
|
8
|
-
count: any;
|
|
9
|
-
}, {}, "">;
|
|
1
|
+
import type { DocumentPath } from './types.js';
|
|
10
2
|
type $$ComponentProps = {
|
|
11
|
-
path:
|
|
12
|
-
count:
|
|
3
|
+
path: DocumentPath;
|
|
4
|
+
count: number;
|
|
13
5
|
};
|
|
6
|
+
declare const NodeGapMarkers: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type NodeGapMarkers = ReturnType<typeof NodeGapMarkers>;
|
|
8
|
+
export default NodeGapMarkers;
|
|
14
9
|
//# sourceMappingURL=NodeGapMarkers.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeGapMarkers.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGapMarkers.svelte.
|
|
1
|
+
{"version":3,"file":"NodeGapMarkers.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeGapMarkers.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,YAAY,CAAC;AAEnE,KAAK,gBAAgB,GAAI;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAoKhE,QAAA,MAAM,cAAc,sDAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
<script>
|
|
1
|
+
<script lang="ts">
|
|
2
2
|
import { getContext } from 'svelte';
|
|
3
3
|
import { serialize_path } from './utils.js';
|
|
4
|
+
import type { DocumentPath, SveditContext } from './types.js';
|
|
4
5
|
|
|
5
|
-
const svedit = getContext('svedit');
|
|
6
|
+
const svedit = getContext<SveditContext>('svedit');
|
|
6
7
|
let selected_node_paths = $derived(get_selected_node_paths());
|
|
7
8
|
|
|
8
|
-
function get_selected_node_paths() {
|
|
9
|
-
const paths = [];
|
|
9
|
+
function get_selected_node_paths(): DocumentPath[] | undefined {
|
|
10
|
+
const paths: DocumentPath[] = [];
|
|
10
11
|
const selection = svedit.session.selection;
|
|
11
12
|
if (!selection) return;
|
|
12
13
|
if (selection.type !== 'node' || selection.anchor_offset === selection.focus_offset) return;
|
|
@@ -36,10 +37,23 @@
|
|
|
36
37
|
<style>
|
|
37
38
|
.selected-node-overlay,
|
|
38
39
|
.selected-property-overlay {
|
|
40
|
+
/* Selection frame: a single 1px outline, offset -0.5px so the
|
|
41
|
+
hairline centers on the node's edge and neighboring frames merge
|
|
42
|
+
into one shared line. Alternatives tried and rejected:
|
|
43
|
+
- Plain 1px border: adjacent selected nodes stack their borders
|
|
44
|
+
into a 2px seam between them, which looks ugly.
|
|
45
|
+
- Thick translucent frame (8px border) plus an inner hairline
|
|
46
|
+
outline: multiple nested lines take more cognitive effort to
|
|
47
|
+
parse than a single line.
|
|
48
|
+
- Inset box-shadow rings (1px stroke + 8px translucent): same
|
|
49
|
+
layered-frame look, same objection.
|
|
50
|
+
Performance note: outlines don't participate in layout, so
|
|
51
|
+
selection changes can't trigger reflows. */
|
|
39
52
|
position: absolute;
|
|
40
53
|
background: var(--svedit-editing-fill);
|
|
41
|
-
|
|
42
|
-
|
|
54
|
+
outline: 1px solid var(--svedit-editing-stroke);
|
|
55
|
+
outline-offset: -0.5px;
|
|
56
|
+
border-radius: 1px;
|
|
43
57
|
top: anchor(top);
|
|
44
58
|
left: anchor(left);
|
|
45
59
|
bottom: anchor(bottom);
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
export default NodeSelectionMarkers;
|
|
2
|
-
type NodeSelectionMarkers = {
|
|
3
|
-
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
-
$set?(props: Partial<Record<string, never>>): void;
|
|
5
|
-
};
|
|
6
1
|
declare const NodeSelectionMarkers: import("svelte").Component<Record<string, never>, {}, "">;
|
|
2
|
+
type NodeSelectionMarkers = ReturnType<typeof NodeSelectionMarkers>;
|
|
3
|
+
export default NodeSelectionMarkers;
|
|
7
4
|
//# sourceMappingURL=NodeSelectionMarkers.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeSelectionMarkers.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeSelectionMarkers.svelte.
|
|
1
|
+
{"version":3,"file":"NodeSelectionMarkers.svelte.d.ts","sourceRoot":"","sources":["../src/lib/NodeSelectionMarkers.svelte.ts"],"names":[],"mappings":"AA4CA,QAAA,MAAM,oBAAoB,2DAAwC,CAAC;AACnE,KAAK,oBAAoB,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AACpE,eAAe,oBAAoB,CAAC"}
|
package/dist/Session.svelte.d.ts
CHANGED
|
@@ -1,55 +1,58 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
selection?: Selection;
|
|
15
|
-
});
|
|
16
|
-
/** @type {DocumentSchema} */
|
|
17
|
-
schema: DocumentSchema;
|
|
18
|
-
/** @type {Document} */
|
|
1
|
+
import Transaction from './Transaction.svelte.js';
|
|
2
|
+
import type { SelectedAttachment } from './doc_utils.js';
|
|
3
|
+
import type { NodeId, DocumentPath, Selection, Attachment, NodeKind, DocumentSchema, DocumentNode, Document, AnyNode, Text, CommandRegistry, Inspection, SessionConfig, SveditContext } from './types.js';
|
|
4
|
+
import type { Keymap } from './KeyMapper.svelte.js';
|
|
5
|
+
type HistoryEntry = {
|
|
6
|
+
ops: Transaction['ops'];
|
|
7
|
+
inverse_ops: Transaction['inverse_ops'];
|
|
8
|
+
selection_before: Selection | null;
|
|
9
|
+
selection_after: Selection | null;
|
|
10
|
+
};
|
|
11
|
+
export default class Session<S extends DocumentSchema = DocumentSchema> {
|
|
12
|
+
#private;
|
|
13
|
+
schema: S;
|
|
19
14
|
doc: Document;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
history: any[];
|
|
15
|
+
config: SessionConfig;
|
|
16
|
+
history: HistoryEntry[];
|
|
23
17
|
history_index: number;
|
|
24
|
-
last_batch_started:
|
|
25
|
-
commands:
|
|
26
|
-
keymap:
|
|
18
|
+
last_batch_started: number | undefined;
|
|
19
|
+
commands: CommandRegistry;
|
|
20
|
+
keymap: Keymap;
|
|
27
21
|
can_undo: boolean;
|
|
28
22
|
can_redo: boolean;
|
|
29
|
-
selected_node:
|
|
30
|
-
|
|
23
|
+
selected_node: AnyNode<S> | null;
|
|
24
|
+
available_mark_types: string[];
|
|
25
|
+
available_annotation_types: string[];
|
|
26
|
+
selected_marks: SelectedAttachment[];
|
|
27
|
+
active_mark: SelectedAttachment | null;
|
|
28
|
+
selected_annotations: SelectedAttachment[];
|
|
29
|
+
active_annotation: SelectedAttachment | null;
|
|
30
|
+
/**
|
|
31
|
+
* @param schema - The document schema
|
|
32
|
+
* @param doc - The document
|
|
33
|
+
* @param config - configuration object
|
|
34
|
+
* @param options - Optional settings (e.g. initial selection state)
|
|
35
|
+
*/
|
|
36
|
+
constructor(schema: S, doc: Document, config: SessionConfig, options?: {
|
|
37
|
+
selection?: Selection | null;
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Gets the current selection
|
|
41
|
+
*/
|
|
42
|
+
get selection(): Selection | null;
|
|
31
43
|
/**
|
|
32
44
|
* Sets the selection with validation
|
|
33
|
-
* @param {Selection | null} value - The new selection
|
|
34
45
|
* @throws {Error} Throws if the selection is invalid
|
|
35
46
|
*/
|
|
36
47
|
set selection(value: Selection | null);
|
|
37
|
-
/**
|
|
38
|
-
* Gets the current selection
|
|
39
|
-
* @returns {Selection | null}
|
|
40
|
-
*/
|
|
41
|
-
get selection(): Selection | null;
|
|
42
48
|
/**
|
|
43
49
|
* Validates that a selection is within bounds and refers to valid paths.
|
|
44
50
|
*
|
|
45
|
-
* @param {Selection} selection - The selection to validate
|
|
46
51
|
* @throws {Error} Throws if the selection is invalid
|
|
47
|
-
* @private
|
|
48
52
|
*/
|
|
49
53
|
private _validate_selection;
|
|
50
54
|
/**
|
|
51
55
|
* Gets the document_id from the doc
|
|
52
|
-
* @returns {string}
|
|
53
56
|
*/
|
|
54
57
|
get document_id(): string;
|
|
55
58
|
/**
|
|
@@ -60,11 +63,10 @@ export default class Session {
|
|
|
60
63
|
* deleted nodes. That catches local node invariants and dangling references left
|
|
61
64
|
* behind by deletes without scanning every node on every apply.
|
|
62
65
|
*
|
|
63
|
-
* @param {Transaction} transaction - The transaction result to validate
|
|
64
66
|
* @throws {Error} Throws if the transaction result is invalid
|
|
65
67
|
*/
|
|
66
68
|
validate_transaction_result(transaction: Transaction): void;
|
|
67
|
-
generate_id():
|
|
69
|
+
generate_id(): string;
|
|
68
70
|
/**
|
|
69
71
|
* Initialize commands and keymap for this session.
|
|
70
72
|
* Called by Svedit component when it has the necessary context.
|
|
@@ -73,34 +75,34 @@ export default class Session {
|
|
|
73
75
|
* For multiple editors on the same document, this architecture would need
|
|
74
76
|
* to be refactored to support multiple sessions per document.
|
|
75
77
|
*
|
|
76
|
-
* @param
|
|
78
|
+
* @param context - The svedit context with session, editable, canvas, etc.
|
|
77
79
|
*/
|
|
78
|
-
initialize_commands(context:
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
initialize_commands(context: SveditContext<S>): void;
|
|
81
|
+
get_available_mark_types(): string[];
|
|
82
|
+
get_available_annotation_types(): string[];
|
|
83
|
+
get_selected_node(): AnyNode<S> | null;
|
|
81
84
|
/**
|
|
82
85
|
* Creates a new transaction for making atomic changes to the document.
|
|
83
|
-
*
|
|
84
|
-
* @returns {Transaction} A new transaction instance
|
|
85
86
|
*/
|
|
86
87
|
get tr(): Transaction;
|
|
87
88
|
/**
|
|
88
89
|
* Applies a transaction to the document.
|
|
89
|
-
* Auto-batches history entries with debounced behavior (max one entry per
|
|
90
|
+
* Auto-batches history entries with debounced behavior (max one entry per second) when batch is true.
|
|
90
91
|
*
|
|
91
|
-
* @param
|
|
92
|
-
* @param
|
|
93
|
-
* @param {boolean} [options.batch=false] - Whether to allow batching with previous transaction
|
|
92
|
+
* @param transaction - The transaction to apply
|
|
93
|
+
* @param options - Optional configuration (batch: whether to allow batching with previous transaction)
|
|
94
94
|
*/
|
|
95
95
|
apply(transaction: Transaction, { batch }?: {
|
|
96
96
|
batch?: boolean;
|
|
97
97
|
}): this;
|
|
98
|
-
undo(): this;
|
|
99
|
-
redo(): this;
|
|
98
|
+
undo(): this | undefined;
|
|
99
|
+
redo(): this | undefined;
|
|
100
100
|
/**
|
|
101
101
|
* Gets a node instance or property value at the specified path.
|
|
102
|
-
*
|
|
103
|
-
*
|
|
102
|
+
*
|
|
103
|
+
* The result type defaults to `any` because a path can address a node or
|
|
104
|
+
* any property value. Annotate the target to type the result.
|
|
105
|
+
*
|
|
104
106
|
* @example
|
|
105
107
|
* // Get a node by ID
|
|
106
108
|
* session.get('list_1') // => { type: 'list', id: 'list_1', ... }
|
|
@@ -114,10 +116,10 @@ export default class Session {
|
|
|
114
116
|
* session.get(['page_1', 'body', 3, 'list_items', 0]) // => { type: 'list_item', id: 'list_item_1', ... }
|
|
115
117
|
*
|
|
116
118
|
* @example
|
|
117
|
-
* // Get
|
|
118
|
-
* session.get(['page_1', 'cover', 'title']) // => {
|
|
119
|
+
* // Get a text property
|
|
120
|
+
* session.get(['page_1', 'cover', 'title']) // => {content: 'Hello world', marks: [], annotations: []}
|
|
119
121
|
*/
|
|
120
|
-
get(path: DocumentPath | string):
|
|
122
|
+
get<T = any>(path: DocumentPath | string): T;
|
|
121
123
|
/**
|
|
122
124
|
* While .get gives you the value of a path, inspect gives you
|
|
123
125
|
* the type info of that value.
|
|
@@ -140,50 +142,40 @@ export default class Session {
|
|
|
140
142
|
* type: 'paragraph',
|
|
141
143
|
* properties: {...}
|
|
142
144
|
* }
|
|
143
|
-
*
|
|
144
|
-
* @param {DocumentPath} path
|
|
145
|
-
* @returns {{kind: 'property'|'node', [key: string]: any}}
|
|
146
145
|
*/
|
|
147
|
-
inspect(path: DocumentPath):
|
|
148
|
-
kind: "property" | "node";
|
|
149
|
-
[key: string]: any;
|
|
150
|
-
};
|
|
146
|
+
inspect(path: DocumentPath): Inspection;
|
|
151
147
|
/**
|
|
152
|
-
* Determines the kind of a node ('
|
|
153
|
-
* text nodes
|
|
154
|
-
*
|
|
155
|
-
* @returns {NodeKind}
|
|
148
|
+
* Determines the kind of a node ('document' for root nodes, 'block' for
|
|
149
|
+
* structured blocks, 'text' for pure text nodes, 'mark' for mark nodes or
|
|
150
|
+
* 'annotation' for annotation nodes).
|
|
156
151
|
*/
|
|
157
|
-
kind(node:
|
|
152
|
+
kind(node: DocumentNode): NodeKind;
|
|
158
153
|
/**
|
|
159
154
|
* Determines whether a node type can be inserted at a given selection.
|
|
160
|
-
* @param {string} node_type - The type of node to insert.
|
|
161
|
-
* @param {Selection} [selection] - The selection at which to insert the node.
|
|
162
|
-
* @returns {boolean} True if the node type can be inserted, false otherwise.
|
|
163
|
-
*/
|
|
164
|
-
can_insert(node_type: string, selection?: Selection): boolean;
|
|
165
|
-
/**
|
|
166
|
-
* Compute next possible insert position from a given selection
|
|
167
155
|
*
|
|
168
|
-
* @param
|
|
169
|
-
* @
|
|
156
|
+
* @param node_type - The type of node to insert.
|
|
157
|
+
* @param selection - The selection at which to insert the node.
|
|
158
|
+
* @returns True if the node type can be inserted, false otherwise.
|
|
170
159
|
*/
|
|
171
|
-
|
|
160
|
+
can_insert(node_type: string, selection?: Selection | null): boolean;
|
|
172
161
|
/**
|
|
173
|
-
*
|
|
174
|
-
* NOTE: Annotations in Svedit are exclusive, so there can only be one active_annotation
|
|
162
|
+
* Compute next possible insert position from a given selection
|
|
175
163
|
*
|
|
176
|
-
* @param
|
|
177
|
-
* @returns
|
|
178
|
-
*/
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
164
|
+
* @param selection - Reference selection
|
|
165
|
+
* @returns The next node insert caret selection, or null if none is available
|
|
166
|
+
*/
|
|
167
|
+
get_next_node_insert_caret(selection?: Selection | null): Selection | null;
|
|
168
|
+
get_selected_text(): (Text & {
|
|
169
|
+
nodes: Record<string, DocumentNode>;
|
|
170
|
+
}) | null;
|
|
171
|
+
get_selected_annotated_nodes(): {
|
|
172
|
+
nodes: Record<string, DocumentNode>;
|
|
173
|
+
main_nodes: NodeId[];
|
|
174
|
+
marks: Attachment[];
|
|
175
|
+
annotations: Attachment[];
|
|
176
|
+
} | null;
|
|
177
|
+
get_selected_plain_text(): string | null;
|
|
178
|
+
get_selected_nodes(): NodeId[] | null;
|
|
187
179
|
select_parent(): void;
|
|
188
180
|
/**
|
|
189
181
|
* Traverses the document and returns a list of nodes in depth-first order.
|
|
@@ -193,9 +185,7 @@ export default class Session {
|
|
|
193
185
|
* 2. Branch nodes second
|
|
194
186
|
* 3. Root node (entry point) last
|
|
195
187
|
*
|
|
196
|
-
*
|
|
197
|
-
* @returns {Array<DocumentNode>} Array of nodes in depth-first order
|
|
198
|
-
* @note Nodes that are not reachable from the entry point node will not be included
|
|
188
|
+
* Nodes that are not reachable from the entry point node will not be included.
|
|
199
189
|
*/
|
|
200
190
|
traverse(node_id: string): Array<DocumentNode>;
|
|
201
191
|
/**
|
|
@@ -203,32 +193,11 @@ export default class Session {
|
|
|
203
193
|
*
|
|
204
194
|
* We make a traversal to ensure that orphaned nodes are not included,
|
|
205
195
|
* and that leaf nodes go first, followed by branches and the root node at last.
|
|
206
|
-
*
|
|
207
|
-
* @returns {Document} The document
|
|
208
196
|
*/
|
|
209
197
|
to_json(): Document;
|
|
210
|
-
property_type(type:
|
|
211
|
-
count_references(node_id:
|
|
212
|
-
/**
|
|
213
|
-
* @param {NodeId} node_id
|
|
214
|
-
* @returns {NodeId[]}
|
|
215
|
-
*/
|
|
198
|
+
property_type(type: string, property: string): string;
|
|
199
|
+
count_references(node_id: NodeId): number;
|
|
216
200
|
get_referenced_nodes(node_id: NodeId): NodeId[];
|
|
217
|
-
#private;
|
|
218
201
|
}
|
|
219
|
-
export
|
|
220
|
-
/**
|
|
221
|
-
* - Initial selection state
|
|
222
|
-
*/
|
|
223
|
-
selection?: Selection;
|
|
224
|
-
};
|
|
225
|
-
import type { DocumentSchema } from './types.d.ts';
|
|
226
|
-
import type { Document } from './types.d.ts';
|
|
227
|
-
import type { Selection } from './types.d.ts';
|
|
228
|
-
import Transaction from './Transaction.svelte.js';
|
|
229
|
-
import type { DocumentPath } from './types.d.ts';
|
|
230
|
-
import type { NodeKind } from './types.d.ts';
|
|
231
|
-
import type { Annotation } from './types.d.ts';
|
|
232
|
-
import type { DocumentNode } from './types.d.ts';
|
|
233
|
-
import type { NodeId } from './types.d.ts';
|
|
202
|
+
export {};
|
|
234
203
|
//# sourceMappingURL=Session.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Session.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Session.svelte.
|
|
1
|
+
{"version":3,"file":"Session.svelte.d.ts","sourceRoot":"","sources":["../src/lib/Session.svelte.ts"],"names":[],"mappings":"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"}
|