@tarhnama/core 0.1.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 +21 -0
- package/README.md +16 -0
- package/dist/code-tokens.d.ts +39 -0
- package/dist/code-tokens.d.ts.map +1 -0
- package/dist/code-tokens.js +189 -0
- package/dist/code-tokens.js.map +1 -0
- package/dist/context-menu.d.ts +59 -0
- package/dist/context-menu.d.ts.map +1 -0
- package/dist/context-menu.js +69 -0
- package/dist/context-menu.js.map +1 -0
- package/dist/features.d.ts +114 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/features.js +128 -0
- package/dist/features.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/nested.d.ts +66 -0
- package/dist/nested.d.ts.map +1 -0
- package/dist/nested.js +194 -0
- package/dist/nested.js.map +1 -0
- package/dist/ops.d.ts +120 -0
- package/dist/ops.d.ts.map +1 -0
- package/dist/ops.js +333 -0
- package/dist/ops.js.map +1 -0
- package/dist/shortcuts.d.ts +90 -0
- package/dist/shortcuts.d.ts.map +1 -0
- package/dist/shortcuts.js +179 -0
- package/dist/shortcuts.js.map +1 -0
- package/dist/spine.d.ts +92 -0
- package/dist/spine.d.ts.map +1 -0
- package/dist/spine.js +213 -0
- package/dist/spine.js.map +1 -0
- package/dist/styles.d.ts +63 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +169 -0
- package/dist/styles.js.map +1 -0
- package/dist/tree.d.ts +70 -0
- package/dist/tree.d.ts.map +1 -0
- package/dist/tree.js +190 -0
- package/dist/tree.js.map +1 -0
- package/dist/types.d.ts +239 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +47 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
- package/src/code-tokens.ts +236 -0
- package/src/context-menu.ts +139 -0
- package/src/features.ts +173 -0
- package/src/index.ts +58 -0
- package/src/nested.ts +271 -0
- package/src/ops.ts +341 -0
- package/src/shortcuts.ts +280 -0
- package/src/spine.ts +214 -0
- package/src/styles.ts +201 -0
- package/src/tree.ts +189 -0
- package/src/types.ts +275 -0
package/dist/spine.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { type Blocks, type OutlineLevel, type TreeIndex } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Operations behind the collapse spine.
|
|
4
|
+
*
|
|
5
|
+
* Collapse is the most-used interaction in the product and the mechanism the whole
|
|
6
|
+
* performance strategy rests on (a collapsed subtree is *unmounted*, never hidden), so its
|
|
7
|
+
* operations live together rather than scattered through `ops.ts`.
|
|
8
|
+
*
|
|
9
|
+
* All of them are pure and return the SAME list when nothing changed, like every other
|
|
10
|
+
* structural operation here — downstream memoization depends on it.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* How many blocks a heading would fold away.
|
|
14
|
+
*
|
|
15
|
+
* This is what the spine's scope line is a picture of, and what the count pill states. It
|
|
16
|
+
* excludes the heading itself: the question a reader is asking is "how much disappears if
|
|
17
|
+
* I click this", and the heading does not.
|
|
18
|
+
*/
|
|
19
|
+
export declare function subtreeSize(blocks: Blocks, blockId: string, index?: TreeIndex): number;
|
|
20
|
+
/**
|
|
21
|
+
* Collapse or expand every sibling at one heading's level, within its parent.
|
|
22
|
+
*
|
|
23
|
+
* Bound to ⌥click. "Siblings" means blocks with the same parent AND the same level — not
|
|
24
|
+
* every block at that level in the document, which would fold unrelated branches the user
|
|
25
|
+
* cannot see and did not ask about.
|
|
26
|
+
*
|
|
27
|
+
* The clicked heading decides the direction for all of them: if it is open, they all
|
|
28
|
+
* close. Deriving each one independently would produce a checkerboard.
|
|
29
|
+
*/
|
|
30
|
+
export declare function collapseSiblings<C>(blocks: Blocks<C>, blockId: string, collapsed?: boolean): Blocks<C>;
|
|
31
|
+
/**
|
|
32
|
+
* Open the tree down to `level`, closing everything deeper.
|
|
33
|
+
*
|
|
34
|
+
* Bound to ⌘⌥1…6 and to the ladder control. `level` 0 means "close everything" — every
|
|
35
|
+
* heading that governs a subtree folds; a level above the deepest heading means "open
|
|
36
|
+
* everything".
|
|
37
|
+
*
|
|
38
|
+
* Headings with no children are left alone: a collapsed flag on a leaf is invisible, and
|
|
39
|
+
* setting it would make the ladder's state depend on blocks the reader cannot see.
|
|
40
|
+
*/
|
|
41
|
+
export declare function openToLevel<C>(blocks: Blocks<C>, level: number): Blocks<C>;
|
|
42
|
+
/**
|
|
43
|
+
* Open a document as deep as a mounted-block budget allows.
|
|
44
|
+
*
|
|
45
|
+
* For a large import. A real 20,407-block book opened fully mounts every block — the cost the
|
|
46
|
+
* whole scale strategy exists to avoid (CLAUDE.md §2) — so it opens to the deepest level whose
|
|
47
|
+
* mounted window fits, and the ladder takes the reader further. Returns the SAME list when it
|
|
48
|
+
* already fits, stored collapse state included: an author's own folds are not overridden.
|
|
49
|
+
*
|
|
50
|
+
* Never shallower than level 1. Folding the top level away too would leave nothing on screen
|
|
51
|
+
* but the chapters' absence; one row per chapter is the floor, over budget or not.
|
|
52
|
+
*/
|
|
53
|
+
export declare function openToFit<C>(blocks: Blocks<C>, budget: number): Blocks<C>;
|
|
54
|
+
/**
|
|
55
|
+
* The deepest level in the document that governs a subtree.
|
|
56
|
+
*
|
|
57
|
+
* The ladder offers rungs only for levels that exist: a document of H1s and H2s should not
|
|
58
|
+
* show six of them, because four of the buttons would do nothing.
|
|
59
|
+
*/
|
|
60
|
+
export declare function deepestParentLevel(blocks: Blocks): OutlineLevel;
|
|
61
|
+
/**
|
|
62
|
+
* Which level the tree is currently open to, or null when the state is mixed.
|
|
63
|
+
*
|
|
64
|
+
* The ladder highlights a rung only when the document actually matches it. Reporting a
|
|
65
|
+
* best guess would leave the control lit while the tree says otherwise, and the user would
|
|
66
|
+
* stop trusting it.
|
|
67
|
+
*/
|
|
68
|
+
export declare function currentOpenLevel(blocks: Blocks): number | null;
|
|
69
|
+
/**
|
|
70
|
+
* Whether a block is inside a collapsed ancestor, and therefore not rendered.
|
|
71
|
+
*
|
|
72
|
+
* Needed by anything that wants to reveal a block: a scroll target that is currently
|
|
73
|
+
* unmounted has no geometry, so callers must open the way to it first.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isHidden(blocks: Blocks, blockId: string): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Close everything except the path to one subtree, and the subtree itself.
|
|
78
|
+
*
|
|
79
|
+
* Frame 3a's node menu calls this «فقط این زیردرخت باز بماند». It is the one command that
|
|
80
|
+
* makes a 50,000-block document usable for a single afternoon's work: every other branch
|
|
81
|
+
* unmounts, so what is left on screen is exactly the part being written.
|
|
82
|
+
*
|
|
83
|
+
* The heading's ANCESTORS have to stay open too, or the isolated subtree would itself be
|
|
84
|
+
* inside a fold and the command would blank the document — the most obvious way to write
|
|
85
|
+
* this, and wrong.
|
|
86
|
+
*
|
|
87
|
+
* Other branches fold at EVERY depth, not just at their topmost heading. Stopping at the
|
|
88
|
+
* first fold leaves the old open state buried inside it, so re-opening that branch later
|
|
89
|
+
* spills exactly what the user had just asked to put away.
|
|
90
|
+
*/
|
|
91
|
+
export declare function isolateSubtree<C>(blocks: Blocks<C>, blockId: string): Blocks<C>;
|
|
92
|
+
//# sourceMappingURL=spine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine.d.ts","sourceRoot":"","sources":["../src/spine.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,MAAM,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAElF;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAKtF;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,OAAO,GAClB,MAAM,CAAC,CAAC,CAAC,CA0BX;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAmB1E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CASzE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAQ/D;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiB9D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAKjE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAoB/E"}
|
package/dist/spine.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { ancestors, buildIndex, hasChildren, subtreeRange, visibleIndices } from './tree.js';
|
|
2
|
+
import { BODY } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Operations behind the collapse spine.
|
|
5
|
+
*
|
|
6
|
+
* Collapse is the most-used interaction in the product and the mechanism the whole
|
|
7
|
+
* performance strategy rests on (a collapsed subtree is *unmounted*, never hidden), so its
|
|
8
|
+
* operations live together rather than scattered through `ops.ts`.
|
|
9
|
+
*
|
|
10
|
+
* All of them are pure and return the SAME list when nothing changed, like every other
|
|
11
|
+
* structural operation here — downstream memoization depends on it.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* How many blocks a heading would fold away.
|
|
15
|
+
*
|
|
16
|
+
* This is what the spine's scope line is a picture of, and what the count pill states. It
|
|
17
|
+
* excludes the heading itself: the question a reader is asking is "how much disappears if
|
|
18
|
+
* I click this", and the heading does not.
|
|
19
|
+
*/
|
|
20
|
+
export function subtreeSize(blocks, blockId, index) {
|
|
21
|
+
const at = blocks.findIndex((block) => block.id === blockId);
|
|
22
|
+
if (at === -1)
|
|
23
|
+
return 0;
|
|
24
|
+
const [start, end] = subtreeRange(index ?? buildIndex(blocks), at);
|
|
25
|
+
return Math.max(0, end - start - 1);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Collapse or expand every sibling at one heading's level, within its parent.
|
|
29
|
+
*
|
|
30
|
+
* Bound to ⌥click. "Siblings" means blocks with the same parent AND the same level — not
|
|
31
|
+
* every block at that level in the document, which would fold unrelated branches the user
|
|
32
|
+
* cannot see and did not ask about.
|
|
33
|
+
*
|
|
34
|
+
* The clicked heading decides the direction for all of them: if it is open, they all
|
|
35
|
+
* close. Deriving each one independently would produce a checkerboard.
|
|
36
|
+
*/
|
|
37
|
+
export function collapseSiblings(blocks, blockId, collapsed) {
|
|
38
|
+
const index = buildIndex(blocks);
|
|
39
|
+
const at = blocks.findIndex((block) => block.id === blockId);
|
|
40
|
+
if (at === -1)
|
|
41
|
+
return blocks;
|
|
42
|
+
const level = blocks[at]?.level ?? BODY;
|
|
43
|
+
if (level === BODY)
|
|
44
|
+
return blocks;
|
|
45
|
+
const parent = index.parent[at] ?? -1;
|
|
46
|
+
const target = collapsed ?? !(blocks[at]?.collapsed ?? false);
|
|
47
|
+
const wanted = new Set();
|
|
48
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
49
|
+
if ((blocks[i]?.level ?? BODY) !== level)
|
|
50
|
+
continue;
|
|
51
|
+
if ((index.parent[i] ?? -1) !== parent)
|
|
52
|
+
continue;
|
|
53
|
+
// A heading with nothing under it has no collapsed state worth setting.
|
|
54
|
+
if (!hasChildren(index, i))
|
|
55
|
+
continue;
|
|
56
|
+
wanted.add(i);
|
|
57
|
+
}
|
|
58
|
+
let changed = false;
|
|
59
|
+
const next = blocks.map((block, i) => {
|
|
60
|
+
if (!wanted.has(i) || (block.collapsed ?? false) === target)
|
|
61
|
+
return block;
|
|
62
|
+
changed = true;
|
|
63
|
+
return { ...block, collapsed: target };
|
|
64
|
+
});
|
|
65
|
+
return changed ? next : blocks;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Open the tree down to `level`, closing everything deeper.
|
|
69
|
+
*
|
|
70
|
+
* Bound to ⌘⌥1…6 and to the ladder control. `level` 0 means "close everything" — every
|
|
71
|
+
* heading that governs a subtree folds; a level above the deepest heading means "open
|
|
72
|
+
* everything".
|
|
73
|
+
*
|
|
74
|
+
* Headings with no children are left alone: a collapsed flag on a leaf is invisible, and
|
|
75
|
+
* setting it would make the ladder's state depend on blocks the reader cannot see.
|
|
76
|
+
*/
|
|
77
|
+
export function openToLevel(blocks, level) {
|
|
78
|
+
const index = buildIndex(blocks);
|
|
79
|
+
let changed = false;
|
|
80
|
+
const next = blocks.map((block, i) => {
|
|
81
|
+
const blockLevel = block.level ?? BODY;
|
|
82
|
+
if (blockLevel === BODY || !hasChildren(index, i))
|
|
83
|
+
return block;
|
|
84
|
+
/*
|
|
85
|
+
* A heading AT the target level COLLAPSES: "open to level 2" means level-2 headings
|
|
86
|
+
* are the deepest thing visible, so their own children are folded away. The heading
|
|
87
|
+
* itself is still on screen — it is its subtree that closes.
|
|
88
|
+
*/
|
|
89
|
+
const shouldCollapse = blockLevel >= level;
|
|
90
|
+
if ((block.collapsed ?? false) === shouldCollapse)
|
|
91
|
+
return block;
|
|
92
|
+
changed = true;
|
|
93
|
+
return { ...block, collapsed: shouldCollapse };
|
|
94
|
+
});
|
|
95
|
+
return changed ? next : blocks;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Open a document as deep as a mounted-block budget allows.
|
|
99
|
+
*
|
|
100
|
+
* For a large import. A real 20,407-block book opened fully mounts every block — the cost the
|
|
101
|
+
* whole scale strategy exists to avoid (CLAUDE.md §2) — so it opens to the deepest level whose
|
|
102
|
+
* mounted window fits, and the ladder takes the reader further. Returns the SAME list when it
|
|
103
|
+
* already fits, stored collapse state included: an author's own folds are not overridden.
|
|
104
|
+
*
|
|
105
|
+
* Never shallower than level 1. Folding the top level away too would leave nothing on screen
|
|
106
|
+
* but the chapters' absence; one row per chapter is the floor, over budget or not.
|
|
107
|
+
*/
|
|
108
|
+
export function openToFit(blocks, budget) {
|
|
109
|
+
const mounted = (candidate) => visibleIndices(candidate, buildIndex(candidate)).length;
|
|
110
|
+
if (mounted(blocks) <= budget)
|
|
111
|
+
return blocks;
|
|
112
|
+
for (let level = deepestParentLevel(blocks); level > 1; level--) {
|
|
113
|
+
const candidate = openToLevel(blocks, level);
|
|
114
|
+
if (mounted(candidate) <= budget)
|
|
115
|
+
return candidate;
|
|
116
|
+
}
|
|
117
|
+
return openToLevel(blocks, 1);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The deepest level in the document that governs a subtree.
|
|
121
|
+
*
|
|
122
|
+
* The ladder offers rungs only for levels that exist: a document of H1s and H2s should not
|
|
123
|
+
* show six of them, because four of the buttons would do nothing.
|
|
124
|
+
*/
|
|
125
|
+
export function deepestParentLevel(blocks) {
|
|
126
|
+
const index = buildIndex(blocks);
|
|
127
|
+
let deepest = 0;
|
|
128
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
129
|
+
const level = blocks[i]?.level ?? BODY;
|
|
130
|
+
if (level !== BODY && hasChildren(index, i) && level > deepest)
|
|
131
|
+
deepest = level;
|
|
132
|
+
}
|
|
133
|
+
return deepest;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Which level the tree is currently open to, or null when the state is mixed.
|
|
137
|
+
*
|
|
138
|
+
* The ladder highlights a rung only when the document actually matches it. Reporting a
|
|
139
|
+
* best guess would leave the control lit while the tree says otherwise, and the user would
|
|
140
|
+
* stop trusting it.
|
|
141
|
+
*/
|
|
142
|
+
export function currentOpenLevel(blocks) {
|
|
143
|
+
const index = buildIndex(blocks);
|
|
144
|
+
let deepestOpen = 0;
|
|
145
|
+
let shallowestCollapsed = Number.POSITIVE_INFINITY;
|
|
146
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
147
|
+
const block = blocks[i];
|
|
148
|
+
const level = block?.level ?? BODY;
|
|
149
|
+
if (level === BODY || !hasChildren(index, i))
|
|
150
|
+
continue;
|
|
151
|
+
if (block?.collapsed)
|
|
152
|
+
shallowestCollapsed = Math.min(shallowestCollapsed, level);
|
|
153
|
+
else
|
|
154
|
+
deepestOpen = Math.max(deepestOpen, level);
|
|
155
|
+
}
|
|
156
|
+
if (shallowestCollapsed === Number.POSITIVE_INFINITY)
|
|
157
|
+
return deepestOpen + 1;
|
|
158
|
+
if (deepestOpen === 0)
|
|
159
|
+
return 0;
|
|
160
|
+
// Consistent only when every open heading is shallower than every collapsed one.
|
|
161
|
+
return deepestOpen < shallowestCollapsed ? shallowestCollapsed : null;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Whether a block is inside a collapsed ancestor, and therefore not rendered.
|
|
165
|
+
*
|
|
166
|
+
* Needed by anything that wants to reveal a block: a scroll target that is currently
|
|
167
|
+
* unmounted has no geometry, so callers must open the way to it first.
|
|
168
|
+
*/
|
|
169
|
+
export function isHidden(blocks, blockId) {
|
|
170
|
+
const at = blocks.findIndex((block) => block.id === blockId);
|
|
171
|
+
if (at === -1)
|
|
172
|
+
return false;
|
|
173
|
+
const index = buildIndex(blocks);
|
|
174
|
+
return ancestors(index, at).some((i) => blocks[i]?.collapsed === true);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Close everything except the path to one subtree, and the subtree itself.
|
|
178
|
+
*
|
|
179
|
+
* Frame 3a's node menu calls this «فقط این زیردرخت باز بماند». It is the one command that
|
|
180
|
+
* makes a 50,000-block document usable for a single afternoon's work: every other branch
|
|
181
|
+
* unmounts, so what is left on screen is exactly the part being written.
|
|
182
|
+
*
|
|
183
|
+
* The heading's ANCESTORS have to stay open too, or the isolated subtree would itself be
|
|
184
|
+
* inside a fold and the command would blank the document — the most obvious way to write
|
|
185
|
+
* this, and wrong.
|
|
186
|
+
*
|
|
187
|
+
* Other branches fold at EVERY depth, not just at their topmost heading. Stopping at the
|
|
188
|
+
* first fold leaves the old open state buried inside it, so re-opening that branch later
|
|
189
|
+
* spills exactly what the user had just asked to put away.
|
|
190
|
+
*/
|
|
191
|
+
export function isolateSubtree(blocks, blockId) {
|
|
192
|
+
const at = blocks.findIndex((block) => block.id === blockId);
|
|
193
|
+
if (at === -1)
|
|
194
|
+
return blocks;
|
|
195
|
+
const index = buildIndex(blocks);
|
|
196
|
+
const [, end] = subtreeRange(index, at);
|
|
197
|
+
const open = new Set(ancestors(index, at));
|
|
198
|
+
for (let i = at; i < end; i++)
|
|
199
|
+
open.add(i);
|
|
200
|
+
let changed = false;
|
|
201
|
+
const next = blocks.map((block, i) => {
|
|
202
|
+
// A leaf's collapsed flag is invisible, so leave it exactly as it was.
|
|
203
|
+
if (!hasChildren(index, i))
|
|
204
|
+
return block;
|
|
205
|
+
const collapsed = !open.has(i);
|
|
206
|
+
if ((block.collapsed === true) === collapsed)
|
|
207
|
+
return block;
|
|
208
|
+
changed = true;
|
|
209
|
+
return { ...block, collapsed };
|
|
210
|
+
});
|
|
211
|
+
return changed ? next : blocks;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=spine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spine.js","sourceRoot":"","sources":["../src/spine.ts"],"names":[],"mappings":"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"}
|
package/dist/styles.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Block, Blocks, BlockFormat, NamedStyle, OutlineLevel } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The chain from `styleId` to its root, nearest first.
|
|
4
|
+
*
|
|
5
|
+
* Cycles are broken rather than trusted not to exist: `w:basedOn` pointing back into its
|
|
6
|
+
* own ancestry is a documented corruption in files produced by older converters, and a
|
|
7
|
+
* naive walk hangs on it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function styleChain(styleId: string | undefined, styles: readonly NamedStyle[] | undefined): NamedStyle[];
|
|
10
|
+
/**
|
|
11
|
+
* A block's effective paragraph formatting: the style chain, then direct overrides.
|
|
12
|
+
*
|
|
13
|
+
* Merged field by field rather than by object spread of the whole chain, because a style
|
|
14
|
+
* that sets only `spaceAfterTwips` must not blank out an ancestor's `align`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function effectiveFormat(block: Block<unknown>, styles: readonly NamedStyle[] | undefined): BlockFormat;
|
|
17
|
+
/** Run-level defaults a style contributes, resolved down its chain. */
|
|
18
|
+
export declare function effectiveRunStyle(styleId: string | undefined, styles: readonly NamedStyle[] | undefined): {
|
|
19
|
+
font?: string;
|
|
20
|
+
sizeHalfPt?: number;
|
|
21
|
+
bold?: boolean;
|
|
22
|
+
italic?: boolean;
|
|
23
|
+
color?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The outline level a style implies, from the nearest ancestor that states one.
|
|
27
|
+
*
|
|
28
|
+
* Returns `undefined` rather than 0 when nothing in the chain says: 0 is body text, a
|
|
29
|
+
* real answer, and defaulting to it would silently demote every heading whose style table
|
|
30
|
+
* failed to load.
|
|
31
|
+
*/
|
|
32
|
+
export declare function styleOutlineLevel(styleId: string | undefined, styles: readonly NamedStyle[] | undefined): OutlineLevel | undefined;
|
|
33
|
+
export interface StyleUsage {
|
|
34
|
+
readonly style: NamedStyle;
|
|
35
|
+
/** Blocks referencing this style directly. */
|
|
36
|
+
readonly count: number;
|
|
37
|
+
/** Of those, how many also carry direct formatting that overrides it. */
|
|
38
|
+
readonly overridden: number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* How many blocks each style governs.
|
|
42
|
+
*
|
|
43
|
+
* The number is what makes "redefine this style across the document" a decision rather
|
|
44
|
+
* than a gamble — "this changes 412 paragraphs" and "this changes 2" are different
|
|
45
|
+
* actions, and the UI cannot tell them apart without counting.
|
|
46
|
+
*/
|
|
47
|
+
export declare function styleUsage(blocks: Blocks<unknown>, styles: readonly NamedStyle[] | undefined): StyleUsage[];
|
|
48
|
+
/**
|
|
49
|
+
* Redefine a style, and report what it touched.
|
|
50
|
+
*
|
|
51
|
+
* Returns the SAME document reference when nothing changed, as every structural op in
|
|
52
|
+
* this project does, so downstream memoization holds.
|
|
53
|
+
*/
|
|
54
|
+
export declare function redefineStyle(styles: readonly NamedStyle[] | undefined, styleId: string, patch: Partial<Omit<NamedStyle, 'id'>>): readonly NamedStyle[] | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Drop direct formatting from every block using a style, so the style governs again.
|
|
57
|
+
*
|
|
58
|
+
* This is what "reset to the style" means in Word, and it is the other half of redefining
|
|
59
|
+
* one: a redefinition has no visible effect on paragraphs whose direct formatting already
|
|
60
|
+
* overrides the field being changed.
|
|
61
|
+
*/
|
|
62
|
+
export declare function clearDirectFormat<C>(blocks: Blocks<C>, styleId: string): Blocks<C>;
|
|
63
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAevF;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACxC,UAAU,EAAE,CAad;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EACrB,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACxC,WAAW,CAQb;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACxC;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiB1F;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACxC,YAAY,GAAG,SAAS,CAK1B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,EACvB,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,GACxC,UAAU,EAAE,CAqBd;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,SAAS,EACzC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,GACrC,SAAS,UAAU,EAAE,GAAG,SAAS,CAanC;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CASlF"}
|
package/dist/styles.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Named-style resolution.
|
|
3
|
+
*
|
|
4
|
+
* Word's model, reproduced exactly: a paragraph's effective formatting is its style's
|
|
5
|
+
* formatting, merged with the style that style is based on, and so on to the root, with
|
|
6
|
+
* the paragraph's own direct formatting winning over all of it. Getting the precedence
|
|
7
|
+
* backwards is invisible on most documents and catastrophic on the one where an author
|
|
8
|
+
* overrode a heading's spacing.
|
|
9
|
+
*/
|
|
10
|
+
/** Depth limit for `basedOn` walking. Real Word documents contain cycles. */
|
|
11
|
+
const MAX_CHAIN = 32;
|
|
12
|
+
/**
|
|
13
|
+
* The chain from `styleId` to its root, nearest first.
|
|
14
|
+
*
|
|
15
|
+
* Cycles are broken rather than trusted not to exist: `w:basedOn` pointing back into its
|
|
16
|
+
* own ancestry is a documented corruption in files produced by older converters, and a
|
|
17
|
+
* naive walk hangs on it.
|
|
18
|
+
*/
|
|
19
|
+
export function styleChain(styleId, styles) {
|
|
20
|
+
if (!styleId || !styles || styles.length === 0)
|
|
21
|
+
return [];
|
|
22
|
+
const byId = new Map(styles.map((style) => [style.id, style]));
|
|
23
|
+
const chain = [];
|
|
24
|
+
const seen = new Set();
|
|
25
|
+
let current = byId.get(styleId);
|
|
26
|
+
while (current && !seen.has(current.id) && chain.length < MAX_CHAIN) {
|
|
27
|
+
seen.add(current.id);
|
|
28
|
+
chain.push(current);
|
|
29
|
+
current = current.basedOn ? byId.get(current.basedOn) : undefined;
|
|
30
|
+
}
|
|
31
|
+
return chain;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A block's effective paragraph formatting: the style chain, then direct overrides.
|
|
35
|
+
*
|
|
36
|
+
* Merged field by field rather than by object spread of the whole chain, because a style
|
|
37
|
+
* that sets only `spaceAfterTwips` must not blank out an ancestor's `align`.
|
|
38
|
+
*/
|
|
39
|
+
export function effectiveFormat(block, styles) {
|
|
40
|
+
const chain = styleChain(block.styleId, styles);
|
|
41
|
+
let out = {};
|
|
42
|
+
// Root first, so a nearer style overrides a more distant one.
|
|
43
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
44
|
+
out = { ...out, ...definedOnly(chain[i].format) };
|
|
45
|
+
}
|
|
46
|
+
return { ...out, ...definedOnly(block.format) };
|
|
47
|
+
}
|
|
48
|
+
/** Run-level defaults a style contributes, resolved down its chain. */
|
|
49
|
+
export function effectiveRunStyle(styleId, styles) {
|
|
50
|
+
const chain = styleChain(styleId, styles);
|
|
51
|
+
let out = {};
|
|
52
|
+
for (let i = chain.length - 1; i >= 0; i--) {
|
|
53
|
+
const style = chain[i];
|
|
54
|
+
out = {
|
|
55
|
+
...out,
|
|
56
|
+
...definedOnly({
|
|
57
|
+
font: style.font,
|
|
58
|
+
sizeHalfPt: style.sizeHalfPt,
|
|
59
|
+
bold: style.bold,
|
|
60
|
+
italic: style.italic,
|
|
61
|
+
color: style.color,
|
|
62
|
+
}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The outline level a style implies, from the nearest ancestor that states one.
|
|
69
|
+
*
|
|
70
|
+
* Returns `undefined` rather than 0 when nothing in the chain says: 0 is body text, a
|
|
71
|
+
* real answer, and defaulting to it would silently demote every heading whose style table
|
|
72
|
+
* failed to load.
|
|
73
|
+
*/
|
|
74
|
+
export function styleOutlineLevel(styleId, styles) {
|
|
75
|
+
for (const style of styleChain(styleId, styles)) {
|
|
76
|
+
if (style.outlineLevel !== undefined)
|
|
77
|
+
return style.outlineLevel;
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* How many blocks each style governs.
|
|
83
|
+
*
|
|
84
|
+
* The number is what makes "redefine this style across the document" a decision rather
|
|
85
|
+
* than a gamble — "this changes 412 paragraphs" and "this changes 2" are different
|
|
86
|
+
* actions, and the UI cannot tell them apart without counting.
|
|
87
|
+
*/
|
|
88
|
+
export function styleUsage(blocks, styles) {
|
|
89
|
+
if (!styles || styles.length === 0)
|
|
90
|
+
return [];
|
|
91
|
+
const counts = new Map();
|
|
92
|
+
for (const block of blocks) {
|
|
93
|
+
if (!block.styleId)
|
|
94
|
+
continue;
|
|
95
|
+
const entry = counts.get(block.styleId) ?? { count: 0, overridden: 0 };
|
|
96
|
+
entry.count += 1;
|
|
97
|
+
if (block.format && Object.keys(definedOnly(block.format)).length > 0)
|
|
98
|
+
entry.overridden += 1;
|
|
99
|
+
counts.set(block.styleId, entry);
|
|
100
|
+
}
|
|
101
|
+
return styles
|
|
102
|
+
.map((style) => ({
|
|
103
|
+
style,
|
|
104
|
+
count: counts.get(style.id)?.count ?? 0,
|
|
105
|
+
overridden: counts.get(style.id)?.overridden ?? 0,
|
|
106
|
+
}))
|
|
107
|
+
// Used styles first, then alphabetically — an unused style is still worth listing,
|
|
108
|
+
// because it is what an author reaches for next.
|
|
109
|
+
.sort((a, b) => b.count - a.count || a.style.name.localeCompare(b.style.name));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Redefine a style, and report what it touched.
|
|
113
|
+
*
|
|
114
|
+
* Returns the SAME document reference when nothing changed, as every structural op in
|
|
115
|
+
* this project does, so downstream memoization holds.
|
|
116
|
+
*/
|
|
117
|
+
export function redefineStyle(styles, styleId, patch) {
|
|
118
|
+
if (!styles)
|
|
119
|
+
return styles;
|
|
120
|
+
let changed = false;
|
|
121
|
+
const next = styles.map((style) => {
|
|
122
|
+
if (style.id !== styleId)
|
|
123
|
+
return style;
|
|
124
|
+
const merged = { ...style, ...definedOnly(patch), format: { ...style.format, ...definedOnly(patch.format) } };
|
|
125
|
+
if (shallowEqual(merged, style) && shallowEqual(merged.format ?? {}, style.format ?? {})) {
|
|
126
|
+
return style;
|
|
127
|
+
}
|
|
128
|
+
changed = true;
|
|
129
|
+
return merged;
|
|
130
|
+
});
|
|
131
|
+
return changed ? next : styles;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Drop direct formatting from every block using a style, so the style governs again.
|
|
135
|
+
*
|
|
136
|
+
* This is what "reset to the style" means in Word, and it is the other half of redefining
|
|
137
|
+
* one: a redefinition has no visible effect on paragraphs whose direct formatting already
|
|
138
|
+
* overrides the field being changed.
|
|
139
|
+
*/
|
|
140
|
+
export function clearDirectFormat(blocks, styleId) {
|
|
141
|
+
let changed = false;
|
|
142
|
+
const next = blocks.map((block) => {
|
|
143
|
+
if (block.styleId !== styleId || !block.format)
|
|
144
|
+
return block;
|
|
145
|
+
changed = true;
|
|
146
|
+
const { format: _dropped, ...rest } = block;
|
|
147
|
+
return rest;
|
|
148
|
+
});
|
|
149
|
+
return changed ? next : blocks;
|
|
150
|
+
}
|
|
151
|
+
/** Strip `undefined` values so a spread does not blank out an inherited field. */
|
|
152
|
+
function definedOnly(value) {
|
|
153
|
+
if (!value)
|
|
154
|
+
return {};
|
|
155
|
+
const out = {};
|
|
156
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
157
|
+
if (entry !== undefined)
|
|
158
|
+
out[key] = entry;
|
|
159
|
+
}
|
|
160
|
+
return out;
|
|
161
|
+
}
|
|
162
|
+
function shallowEqual(a, b) {
|
|
163
|
+
const keysA = Object.keys(a);
|
|
164
|
+
const keysB = Object.keys(b);
|
|
165
|
+
if (keysA.length !== keysB.length)
|
|
166
|
+
return false;
|
|
167
|
+
return keysA.every((key) => a[key] === b[key]);
|
|
168
|
+
}
|
|
169
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"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"}
|
package/dist/tree.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type Block, type Blocks, type TreeIndex } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the derived tree in a single O(n) pass.
|
|
4
|
+
*
|
|
5
|
+
* The rule that makes body text work: a level-0 block attaches to the nearest open
|
|
6
|
+
* heading but NEVER terminates a subtree. Only a heading whose level is <= an open
|
|
7
|
+
* heading's level closes it. This mirrors Word's outline semantics, where body text
|
|
8
|
+
* under "1.2" stays under "1.2" no matter how much of it there is.
|
|
9
|
+
*
|
|
10
|
+
* (The legacy `Document.getDirectChildren` had a bug here: it broke on `level <= own`
|
|
11
|
+
* without excluding body text, so a heading's direct children were truncated at the
|
|
12
|
+
* first paragraph of body text. That bug is not reproduced — see the regression test.)
|
|
13
|
+
*/
|
|
14
|
+
export declare function buildIndex(blocks: Blocks): TreeIndex;
|
|
15
|
+
/** `[start, end)` covering `i` and everything beneath it. */
|
|
16
|
+
export declare function subtreeRange(index: TreeIndex, i: number): readonly [number, number];
|
|
17
|
+
/** Every descendant index of `i`, at any depth, in document order. */
|
|
18
|
+
export declare function deepChildren(index: TreeIndex, i: number): number[];
|
|
19
|
+
/** Heading children of `i` — one level down in the DERIVED tree, not by `level`. */
|
|
20
|
+
export declare function childHeadings(blocks: Blocks, index: TreeIndex, i: number): number[];
|
|
21
|
+
/** Body-text blocks belonging directly to `i`. */
|
|
22
|
+
export declare function bodyChildren(blocks: Blocks, index: TreeIndex, i: number): number[];
|
|
23
|
+
/** Chain of ancestors from nearest parent to root. */
|
|
24
|
+
export declare function ancestors(index: TreeIndex, i: number): number[];
|
|
25
|
+
/**
|
|
26
|
+
* Whether two block lists have the same STRUCTURE: the same blocks, at the same levels,
|
|
27
|
+
* folded and locked the same way. Text is not structure.
|
|
28
|
+
*
|
|
29
|
+
* Everything a view derives from the outline — the tree, the counts, the folds, the locks,
|
|
30
|
+
* the spine — depends on exactly these fields, and typing never changes one. A memo keyed
|
|
31
|
+
* on the LIST recomputes per character, because every edit makes a new list; keyed on this
|
|
32
|
+
* it recomputes when the outline actually moves. The `a === b` check is the fast path:
|
|
33
|
+
* structural ops share unchanged blocks by reference, and so does the editor's conversion,
|
|
34
|
+
* so for typing this is a pointer comparison per block.
|
|
35
|
+
*/
|
|
36
|
+
export declare function sameStructure(a: Blocks, b: Blocks): boolean;
|
|
37
|
+
export declare function hasChildren(index: TreeIndex, i: number): boolean;
|
|
38
|
+
/** Index of the nearest preceding heading, or -1. Used by the indent rules. */
|
|
39
|
+
export declare function prevHeading(blocks: Blocks, i: number): number;
|
|
40
|
+
/**
|
|
41
|
+
* Indices that should actually be rendered, honouring `collapsed`.
|
|
42
|
+
*
|
|
43
|
+
* This is the project's primary scale lever. ProseMirror puts the entire document
|
|
44
|
+
* in the DOM and cannot be virtualized, so the working set has to be small by
|
|
45
|
+
* construction — and an outline collapsed to level 2 renders hundreds of blocks
|
|
46
|
+
* rather than tens of thousands. A collapsed subtree must render as NOTHING, not
|
|
47
|
+
* as hidden DOM, or the lever does no work.
|
|
48
|
+
*/
|
|
49
|
+
export declare function visibleIndices(blocks: Blocks, index: TreeIndex): number[];
|
|
50
|
+
/** Convenience for callers that want blocks rather than indices. */
|
|
51
|
+
export declare function visibleBlocks<C>(blocks: Blocks<C>, index: TreeIndex): Block<C>[];
|
|
52
|
+
/**
|
|
53
|
+
* Is `i` read-only — either locked itself, or inside a locked subtree?
|
|
54
|
+
*
|
|
55
|
+
* Walks ancestors rather than reading a stored flag, which is what keeps lock state
|
|
56
|
+
* correct for free when a block is moved, indented, or outdented: a block dragged out
|
|
57
|
+
* of a locked chapter stops being locked because its ancestry changed, with no
|
|
58
|
+
* bookkeeping pass to get wrong.
|
|
59
|
+
*/
|
|
60
|
+
export declare function isLocked(blocks: Blocks, index: TreeIndex, i: number): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The nearest ancestor (or self) that carries the lock, or -1.
|
|
63
|
+
*
|
|
64
|
+
* The UI needs this to say WHAT is locked — "this chapter is read-only" is actionable,
|
|
65
|
+
* "this paragraph is read-only" leaves the reader hunting for the padlock.
|
|
66
|
+
*/
|
|
67
|
+
export declare function lockOwner(blocks: Blocks, index: TreeIndex, i: number): number;
|
|
68
|
+
/** Indices of every read-only block, for bulk checks like a paste guard. */
|
|
69
|
+
export declare function lockedIndices(blocks: Blocks, index: TreeIndex): number[];
|
|
70
|
+
//# sourceMappingURL=tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../src/tree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,SAAS,EAAQ,MAAM,YAAY,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAoCpD;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAEnF;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAIlE;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAMnF;AAED,kDAAkD;AAClD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAMlF;AAED,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAI/D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAY3D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEhE;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAG7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAWzE;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAEhF;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAQ7E;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAM7E;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,EAAE,CAIxE"}
|