dirvi-lib 0.10.0 → 0.11.0-beta.12
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/dist/app/app-methods.d.ts +53 -0
- package/dist/app/app-methods.d.ts.map +1 -0
- package/dist/app/index.d.ts +1 -1
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +1 -1
- package/dist/app/reducer/effect-to-action.d.ts +2 -2
- package/dist/app/reducer/effect-to-action.d.ts.map +1 -1
- package/dist/app/reducer/effect-to-action.js +87 -32
- package/dist/app/reducer/reducer-action.d.ts +12 -6
- package/dist/app/reducer/reducer-action.d.ts.map +1 -1
- package/dist/app/reducer/reducer.d.ts +4 -2
- package/dist/app/reducer/reducer.d.ts.map +1 -1
- package/dist/app/reducer/reducer.js +106 -72
- package/dist/feedback/feedback.impl.d.ts.map +1 -1
- package/dist/feedback/feedback.types.d.ts +1 -1
- package/dist/feedback/feedback.types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/input/application/intent-to-effect.d.ts +2 -2
- package/dist/input/application/intent-to-effect.d.ts.map +1 -1
- package/dist/input/application/intent-to-effect.js +10 -11
- package/dist/input/application/parse-ex-command.d.ts +17 -0
- package/dist/input/application/parse-ex-command.d.ts.map +1 -0
- package/dist/input/application/{parse-command.js → parse-ex-command.js} +84 -54
- package/dist/input/application/parse-normal-command.d.ts +1 -1
- package/dist/input/application/parse-normal-command.d.ts.map +1 -1
- package/dist/input/domain/effect.d.ts +20 -9
- package/dist/input/domain/effect.d.ts.map +1 -1
- package/dist/state-and-nav/cursor.d.ts +89 -0
- package/dist/state-and-nav/cursor.d.ts.map +1 -0
- package/dist/state-and-nav/cursor.js +84 -0
- package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.impl.d.ts +1 -1
- package/dist/state-and-nav/fold-node/deprecated/fold-node.impl.d.ts.map +1 -0
- package/dist/state-and-nav/fold-node/deprecated/fold-node.test.d.ts.map +1 -0
- package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.test.js +2 -2
- package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.types.d.ts +2 -2
- package/dist/state-and-nav/fold-node/deprecated/fold-node.types.d.ts.map +1 -0
- package/dist/{trees → state-and-nav}/fold-node/fold-node.impl.d.ts +3 -3
- package/dist/state-and-nav/fold-node/fold-node.impl.d.ts.map +1 -0
- package/dist/{trees → state-and-nav}/fold-node/fold-node.impl.js +2 -2
- package/dist/{trees → state-and-nav}/fold-node/fold-node.model.d.ts +1 -1
- package/dist/state-and-nav/fold-node/fold-node.model.d.ts.map +1 -0
- package/dist/{trees → state-and-nav}/fold-node/fold-node.types.d.ts +2 -2
- package/dist/state-and-nav/fold-node/fold-node.types.d.ts.map +1 -0
- package/dist/state-and-nav/fold-node/index.d.ts.map +1 -0
- package/dist/state-and-nav/index.d.ts +16 -0
- package/dist/state-and-nav/index.d.ts.map +1 -0
- package/dist/state-and-nav/index.js +6 -0
- package/dist/state-and-nav/nav/nav.ordered.impl.d.ts +12 -0
- package/dist/state-and-nav/nav/nav.ordered.impl.d.ts.map +1 -0
- package/dist/state-and-nav/nav/nav.ordered.impl.js +77 -0
- package/dist/state-and-nav/nav/nav.traversal.d.ts +11 -0
- package/dist/state-and-nav/nav/nav.traversal.d.ts.map +1 -0
- package/dist/state-and-nav/nav/nav.traversal.js +204 -0
- package/dist/{trees/nav-node/nav-node.types.d.ts → state-and-nav/nav/nav.types.d.ts} +37 -23
- package/dist/state-and-nav/nav/nav.types.d.ts.map +1 -0
- package/dist/state-and-nav/nav/nav.unordered.impl.d.ts +13 -0
- package/dist/state-and-nav/nav/nav.unordered.impl.d.ts.map +1 -0
- package/dist/state-and-nav/nav/nav.unordered.impl.js +77 -0
- package/dist/state-and-nav/state/state.impl.d.ts +9 -0
- package/dist/state-and-nav/state/state.impl.d.ts.map +1 -0
- package/dist/{trees → state-and-nav}/state/state.impl.js +62 -9
- package/dist/state-and-nav/state/state.schemas.d.ts +2 -0
- package/dist/state-and-nav/state/state.schemas.d.ts.map +1 -0
- package/dist/state-and-nav/state/state.schemas.js +39 -0
- package/dist/state-and-nav/state/state.types.d.ts +72 -0
- package/dist/state-and-nav/state/state.types.d.ts.map +1 -0
- package/dist/state-and-nav/tree/deprecated/tree-node.arb.d.ts.map +1 -0
- package/dist/state-and-nav/tree/deprecated/tree-node.arb.debug.test.d.ts.map +1 -0
- package/dist/state-and-nav/tree/deprecated/tree-node.impl.d.ts.map +1 -0
- package/dist/state-and-nav/tree/deprecated/tree-node.schemas.d.ts.map +1 -0
- package/dist/state-and-nav/tree/deprecated/tree-node.test.d.ts.map +1 -0
- package/dist/state-and-nav/tree/deprecated/tree-node.types.d.ts.map +1 -0
- package/dist/state-and-nav/tree/index.d.ts +7 -0
- package/dist/state-and-nav/tree/index.d.ts.map +1 -0
- package/dist/state-and-nav/tree/index.js +1 -0
- package/dist/state-and-nav/tree/tree-node.arb.d.ts +94 -0
- package/dist/state-and-nav/tree/tree-node.arb.d.ts.map +1 -0
- package/dist/state-and-nav/tree/tree-node.arb.debug.test.d.ts +2 -0
- package/dist/state-and-nav/tree/tree-node.arb.debug.test.d.ts.map +1 -0
- package/dist/state-and-nav/tree/tree-node.arb.debug.test.js +54 -0
- package/dist/state-and-nav/tree/tree-node.arb.js +188 -0
- package/dist/state-and-nav/tree/tree-node.model.d.ts +194 -0
- package/dist/state-and-nav/tree/tree-node.model.d.ts.map +1 -0
- package/dist/state-and-nav/tree/tree-node.model.js +110 -0
- package/dist/state-and-nav/tree/tree-node.test.d.ts +2 -0
- package/dist/state-and-nav/tree/tree-node.test.d.ts.map +1 -0
- package/dist/state-and-nav/tree/tree-node.test.js +234 -0
- package/dist/{trees/tree-node/tree-node.impl.d.ts → state-and-nav/tree/tree.impl.d.ts} +3 -3
- package/dist/state-and-nav/tree/tree.impl.d.ts.map +1 -0
- package/dist/{trees/tree-node/tree-node.impl.js → state-and-nav/tree/tree.impl.js} +20 -17
- package/dist/{trees/tree-node/tree-node.types.d.ts → state-and-nav/tree/tree.types.d.ts} +67 -47
- package/dist/state-and-nav/tree/tree.types.d.ts.map +1 -0
- package/dist/state-and-nav/tree/tree.types.js +1 -0
- package/package.json +4 -3
- package/dist/app/app-api.d.ts +0 -74
- package/dist/app/app-api.d.ts.map +0 -1
- package/dist/app/app-api.js +0 -11
- package/dist/input/application/parse-command.d.ts +0 -14
- package/dist/input/application/parse-command.d.ts.map +0 -1
- package/dist/trees/cursor.d.ts +0 -59
- package/dist/trees/cursor.d.ts.map +0 -1
- package/dist/trees/cursor.js +0 -55
- package/dist/trees/fold-node/deprecated/fold-node.impl.d.ts.map +0 -1
- package/dist/trees/fold-node/deprecated/fold-node.test.d.ts.map +0 -1
- package/dist/trees/fold-node/deprecated/fold-node.types.d.ts.map +0 -1
- package/dist/trees/fold-node/fold-node.impl.d.ts.map +0 -1
- package/dist/trees/fold-node/fold-node.model.d.ts.map +0 -1
- package/dist/trees/fold-node/fold-node.types.d.ts.map +0 -1
- package/dist/trees/fold-node/index.d.ts.map +0 -1
- package/dist/trees/index.d.ts +0 -9
- package/dist/trees/index.d.ts.map +0 -1
- package/dist/trees/index.js +0 -8
- package/dist/trees/nav-node/nav-node.impl.d.ts +0 -29
- package/dist/trees/nav-node/nav-node.impl.d.ts.map +0 -1
- package/dist/trees/nav-node/nav-node.impl.js +0 -223
- package/dist/trees/nav-node/nav-node.types.d.ts.map +0 -1
- package/dist/trees/state/state.impl.d.ts +0 -8
- package/dist/trees/state/state.impl.d.ts.map +0 -1
- package/dist/trees/state/state.schemas.d.ts +0 -25
- package/dist/trees/state/state.schemas.d.ts.map +0 -1
- package/dist/trees/state/state.schemas.js +0 -17
- package/dist/trees/state/state.types.d.ts +0 -36
- package/dist/trees/state/state.types.d.ts.map +0 -1
- package/dist/trees/tree-node/deprecated/tree-node.arb.d.ts.map +0 -1
- package/dist/trees/tree-node/deprecated/tree-node.arb.debug.test.d.ts.map +0 -1
- package/dist/trees/tree-node/deprecated/tree-node.impl.d.ts.map +0 -1
- package/dist/trees/tree-node/deprecated/tree-node.schemas.d.ts.map +0 -1
- package/dist/trees/tree-node/deprecated/tree-node.test.d.ts.map +0 -1
- package/dist/trees/tree-node/deprecated/tree-node.types.d.ts.map +0 -1
- package/dist/trees/tree-node/index.d.ts +0 -5
- package/dist/trees/tree-node/index.d.ts.map +0 -1
- package/dist/trees/tree-node/index.js +0 -2
- package/dist/trees/tree-node/tree-node.arb.d.ts +0 -104
- package/dist/trees/tree-node/tree-node.arb.d.ts.map +0 -1
- package/dist/trees/tree-node/tree-node.arb.js +0 -188
- package/dist/trees/tree-node/tree-node.impl.d.ts.map +0 -1
- package/dist/trees/tree-node/tree-node.model.d.ts +0 -78
- package/dist/trees/tree-node/tree-node.model.d.ts.map +0 -1
- package/dist/trees/tree-node/tree-node.model.js +0 -37
- package/dist/trees/tree-node/tree-node.types.d.ts.map +0 -1
- /package/dist/{trees/fold-node/deprecated/fold-node.types.js → app/app-methods.js} +0 -0
- /package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.impl.js +0 -0
- /package/dist/{trees → state-and-nav}/fold-node/deprecated/fold-node.test.d.ts +0 -0
- /package/dist/{trees/fold-node → state-and-nav/fold-node/deprecated}/fold-node.types.js +0 -0
- /package/dist/{trees → state-and-nav}/fold-node/fold-node.model.js +0 -0
- /package/dist/{trees/nav-node/nav-node.types.js → state-and-nav/fold-node/fold-node.types.js} +0 -0
- /package/dist/{trees → state-and-nav}/fold-node/index.d.ts +0 -0
- /package/dist/{trees → state-and-nav}/fold-node/index.js +0 -0
- /package/dist/{trees/state/state.types.js → state-and-nav/nav/nav.types.js} +0 -0
- /package/dist/{trees/tree-node/deprecated/tree-node.types.js → state-and-nav/state/state.types.js} +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.d.ts +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.debug.test.d.ts +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.debug.test.js +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.arb.js +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.impl.d.ts +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.impl.js +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.schemas.d.ts +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.schemas.js +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.test.d.ts +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.test.js +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree}/deprecated/tree-node.types.d.ts +0 -0
- /package/dist/{trees/tree-node → state-and-nav/tree/deprecated}/tree-node.types.js +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared navigation operations over both projection styles.
|
|
3
|
+
*
|
|
4
|
+
* Fold summaries exist in either projection, but only ordered navigation
|
|
5
|
+
* exposes them as cursor destinations.
|
|
6
|
+
*/
|
|
7
|
+
export function createNavTraversalMethods(cursorMethods, navigateFolds) {
|
|
8
|
+
function entryIsBranch(entry) {
|
|
9
|
+
return 'children' in entry;
|
|
10
|
+
}
|
|
11
|
+
function entryIsFold(entry) {
|
|
12
|
+
return 'folded' in entry;
|
|
13
|
+
}
|
|
14
|
+
function foldCursor(entry, parentPath) {
|
|
15
|
+
const firstEntry = entry.folded[0];
|
|
16
|
+
/*
|
|
17
|
+
* Projected folds are nonempty and contain direct source entries.
|
|
18
|
+
* Keep the guard because NavFold also permits richer future contents.
|
|
19
|
+
*/
|
|
20
|
+
if (firstEntry === undefined || entryIsFold(firstEntry)) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
parentPath: [...parentPath],
|
|
25
|
+
firstId: firstEntry.id,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function getNodeAtPath(navigation, path) {
|
|
29
|
+
let node = navigation;
|
|
30
|
+
for (const id of path) {
|
|
31
|
+
const entry = node.entries.find((candidate) => !entryIsFold(candidate) && candidate.id === id);
|
|
32
|
+
/*
|
|
33
|
+
* Paths cannot pass through leaves, folds, or unloaded branches.
|
|
34
|
+
* Hidden entries inside fold summaries are deliberately not searched.
|
|
35
|
+
*/
|
|
36
|
+
if (entry === undefined ||
|
|
37
|
+
!entryIsBranch(entry) ||
|
|
38
|
+
entry.children === null) {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
node = entry.children;
|
|
42
|
+
}
|
|
43
|
+
// An empty path identifies the current navigation node.
|
|
44
|
+
return node;
|
|
45
|
+
}
|
|
46
|
+
function getEntryAtPath(navigation, path) {
|
|
47
|
+
/*
|
|
48
|
+
* A NavNode does not itself correspond to a NavEntry. Therefore [] does
|
|
49
|
+
* not resolve to an entry.
|
|
50
|
+
*/
|
|
51
|
+
if (path.length === 0) {
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const parent = getNodeAtPath(navigation, path.slice(0, -1));
|
|
55
|
+
const id = path[path.length - 1];
|
|
56
|
+
return parent?.entries.find((candidate) => !entryIsFold(candidate) && candidate.id === id);
|
|
57
|
+
}
|
|
58
|
+
function cursors(navigation, parentPath = []) {
|
|
59
|
+
const positions = [];
|
|
60
|
+
for (const entry of navigation.entries) {
|
|
61
|
+
if (entryIsFold(entry)) {
|
|
62
|
+
if (navigateFolds) {
|
|
63
|
+
const cursor = foldCursor(entry, parentPath);
|
|
64
|
+
if (cursor !== undefined) {
|
|
65
|
+
positions.push(cursor);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Hidden descendants are never separately navigable.
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const entryPath = [...parentPath, entry.id];
|
|
72
|
+
positions.push({ path: entryPath });
|
|
73
|
+
if (entryIsBranch(entry) && entry.children !== null) {
|
|
74
|
+
positions.push(...cursors(entry.children, entryPath));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return positions;
|
|
78
|
+
}
|
|
79
|
+
function rootCursors(rootNode) {
|
|
80
|
+
return [
|
|
81
|
+
{ path: [] },
|
|
82
|
+
...(rootNode.children === null ? [] : cursors(rootNode.children)),
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
function nextCursor(rootNode, cursor) {
|
|
86
|
+
const positions = rootCursors(rootNode);
|
|
87
|
+
const currentIndex = positions.findIndex((candidate) => cursorMethods.equal(candidate, cursor));
|
|
88
|
+
if (currentIndex === -1) {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
return positions[currentIndex + 1];
|
|
92
|
+
}
|
|
93
|
+
function previousCursor(rootNode, cursor) {
|
|
94
|
+
const positions = rootCursors(rootNode);
|
|
95
|
+
const currentIndex = positions.findIndex((candidate) => cursorMethods.equal(candidate, cursor));
|
|
96
|
+
if (currentIndex <= 0) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
return positions[currentIndex - 1];
|
|
100
|
+
}
|
|
101
|
+
function cursorAfterFold(rootNode, cursor) {
|
|
102
|
+
if (!cursorMethods.isNodeCursor(cursor) ||
|
|
103
|
+
cursor.path.length === 0 ||
|
|
104
|
+
rootNode.children === null) {
|
|
105
|
+
// Folding root is disallowed. Fold markers are already folded.
|
|
106
|
+
return undefined;
|
|
107
|
+
}
|
|
108
|
+
if (navigateFolds) {
|
|
109
|
+
const parentPath = cursor.path.slice(0, -1);
|
|
110
|
+
const parent = getNodeAtPath(rootNode.children, parentPath);
|
|
111
|
+
const id = cursor.path[cursor.path.length - 1];
|
|
112
|
+
if (parent === undefined) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
const currentIndex = parent.entries.findIndex((entry) => !entryIsFold(entry) && entry.id === id);
|
|
116
|
+
if (currentIndex === -1) {
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
const entry = parent.entries[currentIndex];
|
|
120
|
+
if (entry === undefined || entryIsFold(entry)) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const previousEntry = parent.entries[currentIndex - 1];
|
|
124
|
+
/*
|
|
125
|
+
* Folding next to an existing preceding run merges into that run.
|
|
126
|
+
* A following run also merges, but does not determine the first ID.
|
|
127
|
+
*/
|
|
128
|
+
if (previousEntry !== undefined && entryIsFold(previousEntry)) {
|
|
129
|
+
const previousFoldCursor = foldCursor(previousEntry, parentPath);
|
|
130
|
+
if (previousFoldCursor !== undefined) {
|
|
131
|
+
return previousFoldCursor;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
parentPath,
|
|
136
|
+
firstId: entry.id,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
const positions = rootCursors(rootNode);
|
|
140
|
+
const currentIndex = positions.findIndex((candidate) => cursorMethods.equal(candidate, cursor));
|
|
141
|
+
if (currentIndex === -1) {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
for (let index = currentIndex + 1; index < positions.length; index += 1) {
|
|
145
|
+
const candidate = positions[index];
|
|
146
|
+
if (candidate === undefined) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
// Skip entries that are children of the entry about to be folded.
|
|
150
|
+
if (cursorMethods.cursorBelongsToSubtree(candidate, cursor.path)) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
return candidate;
|
|
154
|
+
}
|
|
155
|
+
/*
|
|
156
|
+
* No following position survives the fold. Move before the subtree,
|
|
157
|
+
* rather than into one of its soon-to-be-hidden descendants.
|
|
158
|
+
*/
|
|
159
|
+
return positions[currentIndex - 1];
|
|
160
|
+
}
|
|
161
|
+
function parentCursor(_navigation, cursor) {
|
|
162
|
+
if (cursorMethods.isFoldCursor(cursor)) {
|
|
163
|
+
return {
|
|
164
|
+
path: [...cursor.parentPath],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (cursor.path.length === 0) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
path: cursor.path.slice(0, -1),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function visiblePaths(navigation, parentPath = []) {
|
|
175
|
+
const paths = [];
|
|
176
|
+
for (const entry of navigation.entries) {
|
|
177
|
+
if (entryIsFold(entry)) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const entryPath = [...parentPath, entry.id];
|
|
181
|
+
paths.push(entryPath);
|
|
182
|
+
/*
|
|
183
|
+
* A null value means the source branch is not loaded/opened. It has no
|
|
184
|
+
* currently visible descendants.
|
|
185
|
+
*/
|
|
186
|
+
if (entryIsBranch(entry) && entry.children !== null) {
|
|
187
|
+
paths.push(...visiblePaths(entry.children, entryPath));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return paths;
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
entryIsBranch,
|
|
194
|
+
entryIsFold,
|
|
195
|
+
getNodeAtPath,
|
|
196
|
+
getEntryAtPath,
|
|
197
|
+
nextCursor,
|
|
198
|
+
previousCursor,
|
|
199
|
+
cursorAfterFold,
|
|
200
|
+
parentCursor,
|
|
201
|
+
cursors,
|
|
202
|
+
visiblePaths,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import type { SerializableKey, TreeNode } from '../tree
|
|
1
|
+
import type { SerializableKey, TreeNode } from '../tree/index.js';
|
|
2
2
|
import type { Cursor } from '../cursor.js';
|
|
3
3
|
import type { Folds } from '../fold-node/index.js';
|
|
4
4
|
export type NavNode<Id extends SerializableKey> = {
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Projected direct children, including fold summaries.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Loaded entries that are not folded at this directory, corresponding to
|
|
13
|
-
* navigable rows.
|
|
8
|
+
* Ordered navigation preserves source sibling order and inserts inline folds.
|
|
9
|
+
* Unordered navigation uses presentation order and places its optional fold
|
|
10
|
+
* summary first.
|
|
14
11
|
*
|
|
15
|
-
*
|
|
12
|
+
* Not every entry is therefore necessarily a cursor destination: in ordered
|
|
13
|
+
* trees, the fold summary is not navigable and the NavMethod implementation
|
|
14
|
+
* should skip it.
|
|
16
15
|
*/
|
|
17
16
|
entries: NavEntry<Id>[];
|
|
18
17
|
};
|
|
19
|
-
export type
|
|
20
|
-
/**
|
|
21
|
-
* Folded entries that are present in the loaded TreeNode.
|
|
22
|
-
*
|
|
23
|
-
* This is information for rendering the folded row.
|
|
24
|
-
*/
|
|
25
|
-
entries: NavEntry<Id>[];
|
|
26
|
-
};
|
|
27
|
-
export type NavEntry<Id extends SerializableKey> = NavLeaf<Id> | NavBranch<Id>;
|
|
18
|
+
export type NavEntry<Id extends SerializableKey> = NavLeaf<Id> | NavBranch<Id> | NavFold<Id>;
|
|
28
19
|
export type NavLeaf<Id extends SerializableKey> = {
|
|
29
20
|
id: Id;
|
|
30
21
|
};
|
|
31
22
|
export type NavBranch<Id extends SerializableKey> = {
|
|
32
23
|
id: Id;
|
|
33
24
|
/**
|
|
34
|
-
* `null` means this branch's children have not been loaded
|
|
25
|
+
* `null` means this branch's children have not been loaded.
|
|
35
26
|
*/
|
|
36
27
|
children: NavNode<Id> | null;
|
|
37
28
|
};
|
|
29
|
+
export type NavFold<Id extends SerializableKey> = {
|
|
30
|
+
/**
|
|
31
|
+
* Folded entries that are present in the loaded TreeNode.
|
|
32
|
+
*
|
|
33
|
+
* For unordered trees, there is at most one folded entry, and it is the first
|
|
34
|
+
* in nav node's `entries`.
|
|
35
|
+
*/
|
|
36
|
+
folded: NavEntry<Id>[];
|
|
37
|
+
};
|
|
38
38
|
/**
|
|
39
39
|
* Operations for creating and navigating a UI-oriented projection of a tree.
|
|
40
40
|
*
|
|
41
41
|
* @typeParam Id - The type identifying a node among its direct siblings.
|
|
42
42
|
* @typeParam Value - Application-owned data stored in each source TreeNode.
|
|
43
43
|
*/
|
|
44
|
-
export type
|
|
44
|
+
export type NavMethods<Id extends SerializableKey, Value> = {
|
|
45
45
|
/**
|
|
46
46
|
* Tests whether a navigation entry represents a branch.
|
|
47
47
|
*
|
|
@@ -50,6 +50,10 @@ export type NavNodeApi<Id extends SerializableKey, Value> = {
|
|
|
50
50
|
* opened.
|
|
51
51
|
*/
|
|
52
52
|
entryIsBranch(entry: NavEntry<Id>): entry is NavBranch<Id>;
|
|
53
|
+
/**
|
|
54
|
+
* Tests whether a navigation entry represents a branch.
|
|
55
|
+
*/
|
|
56
|
+
entryIsFold(entry: NavEntry<Id>): entry is NavFold<Id>;
|
|
53
57
|
/**
|
|
54
58
|
* Creates a navigation projection rooted at `root`.
|
|
55
59
|
*
|
|
@@ -71,7 +75,7 @@ export type NavNodeApi<Id extends SerializableKey, Value> = {
|
|
|
71
75
|
* express that fact statically. This method returns `undefined` if `root`
|
|
72
76
|
* is a leaf.
|
|
73
77
|
*
|
|
74
|
-
*
|
|
78
|
+
* An unloaded branch produces a NavBranch whose `children` is `null`.
|
|
75
79
|
*
|
|
76
80
|
* @param root - Source tree node from which to create navigation.
|
|
77
81
|
* @param folds - Fold definitions corresponding to `root`. All active fold
|
|
@@ -102,7 +106,17 @@ export type NavNodeApi<Id extends SerializableKey, Value> = {
|
|
|
102
106
|
* @param cursor
|
|
103
107
|
*/
|
|
104
108
|
parentCursor(navigation: NavNode<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Enumerates navigable positions in depth-first display order.
|
|
111
|
+
*
|
|
112
|
+
* Unordered navigation skips fold summaries.
|
|
113
|
+
* Ordered navigation includes inline folds as fold cursors.
|
|
114
|
+
*/
|
|
105
115
|
cursors(navigation: NavNode<Id>, parentPath?: readonly Id[]): Cursor<Id>[];
|
|
106
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Returns visible node paths in depth-first display order, excluding the
|
|
118
|
+
* root and folded entries. Includes both leaves and branches.
|
|
119
|
+
*/
|
|
120
|
+
visiblePaths(navigation: NavNode<Id>, parentPath?: readonly Id[]): Id[][];
|
|
107
121
|
};
|
|
108
|
-
//# sourceMappingURL=nav
|
|
122
|
+
//# sourceMappingURL=nav.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.types.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/nav/nav.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { SerializableKey, TreeMethods } from '../tree/index.js';
|
|
2
|
+
import type { FoldMethods } from '../fold-node/index.js';
|
|
3
|
+
import type { CursorMethods } from '../cursor.js';
|
|
4
|
+
import type { NavMethods } from './nav.types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Creates operations for projecting an opaque tree into a navigation model.
|
|
7
|
+
*
|
|
8
|
+
* Sibling order has no semantic meaning in this navigation system.
|
|
9
|
+
* This projection preserves source sibling order among visible entries and
|
|
10
|
+
* collects hidden entries into one leading, non-navigable fold summary.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createUnorderedNavMethods<Id extends SerializableKey, Value>(treeMethods: TreeMethods<Id, Value>, foldMethods: FoldMethods<Id>, cursorMethods: CursorMethods<Id>): NavMethods<Id, Value>;
|
|
13
|
+
//# sourceMappingURL=nav.unordered.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav.unordered.impl.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/nav/nav.unordered.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAY,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAKV,UAAU,EACX,MAAM,gBAAgB,CAAC;AAGxB;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EACzE,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,EACnC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,EAC5B,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC,GAC/B,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CA+FvB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { createNavTraversalMethods } from './nav.traversal.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates operations for projecting an opaque tree into a navigation model.
|
|
4
|
+
*
|
|
5
|
+
* Sibling order has no semantic meaning in this navigation system.
|
|
6
|
+
* This projection preserves source sibling order among visible entries and
|
|
7
|
+
* collects hidden entries into one leading, non-navigable fold summary.
|
|
8
|
+
*/
|
|
9
|
+
export function createUnorderedNavMethods(treeMethods, foldMethods, cursorMethods) {
|
|
10
|
+
/**
|
|
11
|
+
* Projects loaded children into navigation entries.
|
|
12
|
+
*
|
|
13
|
+
* Folded source entries are collected into one leading, non-navigable
|
|
14
|
+
* fold summary. Their complete projections are retained inside it.
|
|
15
|
+
*/
|
|
16
|
+
function createNavNode(entries, foldRoot, parentPath) {
|
|
17
|
+
const visibleEntries = [];
|
|
18
|
+
const foldedEntries = [];
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
const entryId = treeMethods.id(entry);
|
|
21
|
+
const entryPath = [...parentPath, entryId];
|
|
22
|
+
const isFolded = foldMethods.isEntryHiddenAtPath(foldRoot, parentPath, entryId);
|
|
23
|
+
const navigationEntry = createNavEntry(entry, foldRoot, entryPath);
|
|
24
|
+
if (isFolded) {
|
|
25
|
+
/*
|
|
26
|
+
* Retain the complete projection for later fold inspection.
|
|
27
|
+
* Ordinary traversal never descends into this hidden projection.
|
|
28
|
+
*/
|
|
29
|
+
foldedEntries.push(navigationEntry);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
visibleEntries.push(navigationEntry);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
/*
|
|
37
|
+
* Fold state may contain entries that are not currently available in the
|
|
38
|
+
* loaded source tree. Do not render an empty synthetic row for them.
|
|
39
|
+
*/
|
|
40
|
+
entries: foldedEntries.length === 0
|
|
41
|
+
? visibleEntries
|
|
42
|
+
: [{ folded: foldedEntries }, ...visibleEntries],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createNavEntry(entry, foldRoot, entryPath) {
|
|
46
|
+
return treeMethods.matchByKind(entry, {
|
|
47
|
+
leaf: ({ id }) => ({
|
|
48
|
+
id,
|
|
49
|
+
}),
|
|
50
|
+
unloadedBranch: ({ id }) => ({
|
|
51
|
+
id,
|
|
52
|
+
children: null,
|
|
53
|
+
}),
|
|
54
|
+
loadedBranch: ({ id, children }) => ({
|
|
55
|
+
id,
|
|
56
|
+
children: createNavNode(children, foldRoot, entryPath),
|
|
57
|
+
}),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function createRootNavBranch(root, foldRoot) {
|
|
61
|
+
return treeMethods.matchByKind(root, {
|
|
62
|
+
leaf: () => undefined,
|
|
63
|
+
unloadedBranch: ({ id }) => ({
|
|
64
|
+
id,
|
|
65
|
+
children: null,
|
|
66
|
+
}),
|
|
67
|
+
loadedBranch: ({ id, children }) => ({
|
|
68
|
+
id,
|
|
69
|
+
children: createNavNode(children, foldRoot, []),
|
|
70
|
+
}),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
...createNavTraversalMethods(cursorMethods, false),
|
|
75
|
+
from: createRootNavBranch,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SerializableKey, TreeMethods } from '../tree/index.js';
|
|
2
|
+
import type { FoldMethods } from '../fold-node/index.js';
|
|
3
|
+
import type { CursorMethods } from '../cursor.js';
|
|
4
|
+
import type { StateMethods } from './state.types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Creates operations for navigating and resynchronizing tree-surfer state.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createStateApi<Id extends SerializableKey, Value>(treeNodeApi: TreeMethods<Id, Value>, foldsApi: FoldMethods<Id>, cursorApi: CursorMethods<Id>): StateMethods<Id, Value>;
|
|
9
|
+
//# sourceMappingURL=state.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.impl.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/state/state.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAS,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAU,aAAa,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAS,MAAM,kBAAkB,CAAC;AA4C5D;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAC9D,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,EACnC,QAAQ,EAAE,WAAW,CAAC,EAAE,CAAC,EACzB,SAAS,EAAE,aAAa,CAAC,EAAE,CAAC,GAC3B,YAAY,CAAC,EAAE,EAAE,KAAK,CAAC,CA2PzB"}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
function getStateData(state) {
|
|
2
|
+
return state;
|
|
3
|
+
}
|
|
4
|
+
function createState(data) {
|
|
5
|
+
return data;
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* Creates operations for navigating and resynchronizing tree-surfer state.
|
|
3
9
|
*/
|
|
4
|
-
export function createStateApi(treeNodeApi, cursorApi) {
|
|
10
|
+
export function createStateApi(treeNodeApi, foldsApi, cursorApi) {
|
|
5
11
|
/**
|
|
6
12
|
* Reloads one node's direct children and recursively reloads descendant
|
|
7
13
|
* branches that were open in the old state.
|
|
@@ -102,27 +108,74 @@ export function createStateApi(treeNodeApi, cursorApi) {
|
|
|
102
108
|
* 5. If no entry cursor exists, use the root cursor.
|
|
103
109
|
*/
|
|
104
110
|
function resyncCursor(_oldState, _newRoot, _newFolds) {
|
|
105
|
-
return [];
|
|
111
|
+
return { path: [] };
|
|
106
112
|
}
|
|
107
113
|
return {
|
|
114
|
+
treeMethods: treeNodeApi,
|
|
115
|
+
foldMethods: foldsApi,
|
|
116
|
+
cursorMethods: cursorApi,
|
|
117
|
+
create(root, folds, cursor) {
|
|
118
|
+
return treeNodeApi.kind(root) === 'loaded-branch'
|
|
119
|
+
? createState({ root, folds, cursor })
|
|
120
|
+
: undefined;
|
|
121
|
+
},
|
|
122
|
+
getRoot(state) {
|
|
123
|
+
return getStateData(state).root;
|
|
124
|
+
},
|
|
125
|
+
getFolds(state) {
|
|
126
|
+
return getStateData(state).folds;
|
|
127
|
+
},
|
|
128
|
+
getCursor(state) {
|
|
129
|
+
return getStateData(state).cursor;
|
|
130
|
+
},
|
|
131
|
+
update(state, changes) {
|
|
132
|
+
const data = getStateData(state);
|
|
133
|
+
const root = changes.root ?? data.root;
|
|
134
|
+
const folds = changes.folds ?? data.folds;
|
|
135
|
+
const cursor = changes.cursor ?? data.cursor;
|
|
136
|
+
if (treeNodeApi.kind(root) !== 'loaded-branch') {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
if (root === data.root &&
|
|
140
|
+
folds === data.folds &&
|
|
141
|
+
cursor === data.cursor) {
|
|
142
|
+
return state;
|
|
143
|
+
}
|
|
144
|
+
return createState({ root, folds, cursor });
|
|
145
|
+
},
|
|
108
146
|
getNodeAtCursor(state) {
|
|
109
|
-
const
|
|
110
|
-
|
|
147
|
+
const { root, cursor } = getStateData(state);
|
|
148
|
+
/*
|
|
149
|
+
* A fold cursor identifies a display item, not a single source node.
|
|
150
|
+
* Its representative path must not silently select its first child.
|
|
151
|
+
*/
|
|
152
|
+
if (!cursorApi.isNodeCursor(cursor)) {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
return treeNodeApi.selectAtPath(root, cursor.path, (node) => node);
|
|
156
|
+
},
|
|
157
|
+
isCursorRoot(state) {
|
|
158
|
+
const { cursor } = getStateData(state);
|
|
159
|
+
return cursorApi.isNodeCursor(cursor) && cursor.path.length === 0;
|
|
160
|
+
},
|
|
161
|
+
cursorPath(state) {
|
|
162
|
+
const { cursor } = getStateData(state);
|
|
163
|
+
return cursorApi.getPath(cursor);
|
|
111
164
|
},
|
|
112
165
|
async resync(oldState, loadBranches) {
|
|
113
|
-
const
|
|
166
|
+
const oldStateData = getStateData(oldState);
|
|
167
|
+
const reloaded = await reload(oldStateData.root, [], loadBranches);
|
|
114
168
|
/*
|
|
115
169
|
* Fold-state resynchronization is not implemented yet. Keep the existing
|
|
116
170
|
* fold definitions while the source tree is reloaded.
|
|
117
171
|
*/
|
|
118
|
-
const folds =
|
|
172
|
+
const folds = oldStateData.folds;
|
|
119
173
|
const root = reloaded.root;
|
|
120
|
-
return {
|
|
121
|
-
...oldState,
|
|
174
|
+
return createState({
|
|
122
175
|
root,
|
|
123
176
|
folds,
|
|
124
177
|
cursor: resyncCursor(oldState, root, folds),
|
|
125
|
-
};
|
|
178
|
+
});
|
|
126
179
|
},
|
|
127
180
|
};
|
|
128
181
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.schemas.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/state/state.schemas.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export {};
|
|
2
|
+
// import { z } from 'zod';
|
|
3
|
+
// import type { Cursor } from './unordered-nav/cursor.js';
|
|
4
|
+
// import type { FoldsModel } from './fold-node/index.js';
|
|
5
|
+
// import type { SerializableKey, TreeNodeModel } from './tree/index.js';
|
|
6
|
+
//
|
|
7
|
+
// /**
|
|
8
|
+
// * Serializable persistence/interchange model for tree-surfer state.
|
|
9
|
+
// *
|
|
10
|
+
// * This is intentionally distinct from runtime `State`: its root and folds use
|
|
11
|
+
// * public structural models, while runtime state holds opaque TreeNode and
|
|
12
|
+
// * Folds values.
|
|
13
|
+
// */
|
|
14
|
+
// export type StateModel<Id extends SerializableKey, Value> = Readonly<{
|
|
15
|
+
// root: TreeNodeModel<Id, Value>;
|
|
16
|
+
// folds: FoldsModel<Id>;
|
|
17
|
+
// cursor: Cursor<Id>;
|
|
18
|
+
// }>;
|
|
19
|
+
//
|
|
20
|
+
// /**
|
|
21
|
+
// * Creates a schema for the serializable StateModel DTO.
|
|
22
|
+
// *
|
|
23
|
+
// * This validates only the persistence representation. Applications must decode
|
|
24
|
+
// * the validated root and folds models through their specialized TreeNodeApi and
|
|
25
|
+
// * FoldsApi before constructing opaque runtime State.
|
|
26
|
+
// */
|
|
27
|
+
// export function createStateModelSchema<Id extends SerializableKey, Value>(
|
|
28
|
+
// rootSchema: z.ZodType<TreeNodeModel<Id, Value>>,
|
|
29
|
+
// foldsSchema: z.ZodType<FoldsModel<Id>>,
|
|
30
|
+
// cursorSchema: z.ZodType<Cursor<Id>>,
|
|
31
|
+
// ): z.ZodType<StateModel<Id, Value>> {
|
|
32
|
+
// return z
|
|
33
|
+
// .object({
|
|
34
|
+
// root: rootSchema,
|
|
35
|
+
// folds: foldsSchema,
|
|
36
|
+
// cursor: cursorSchema,
|
|
37
|
+
// })
|
|
38
|
+
// .strict();
|
|
39
|
+
// }
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { SerializableKey, TreeNode, TreeMethods } from '../tree/index.js';
|
|
2
|
+
import type { FoldMethods, Folds } from '../fold-node/index.js';
|
|
3
|
+
import type { Cursor, CursorMethods } from '../cursor.js';
|
|
4
|
+
declare const stateBrand: unique symbol;
|
|
5
|
+
/**
|
|
6
|
+
* Opaque type for state of the tree, folds, and cursor.
|
|
7
|
+
*
|
|
8
|
+
* Used by consumers as React State.
|
|
9
|
+
*/
|
|
10
|
+
export type State<Id extends SerializableKey, Value> = Readonly<{
|
|
11
|
+
[stateBrand]: Readonly<{
|
|
12
|
+
id: Id;
|
|
13
|
+
value: Value;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
export type StateMethods<Id extends SerializableKey, Value> = Readonly<{
|
|
17
|
+
treeMethods: TreeMethods<Id, Value>;
|
|
18
|
+
foldMethods: FoldMethods<Id>;
|
|
19
|
+
cursorMethods: CursorMethods<Id>;
|
|
20
|
+
/**
|
|
21
|
+
* Creates state whose root is a loaded branch.
|
|
22
|
+
*
|
|
23
|
+
* Returns undefined when root is a leaf or an unloaded branch.
|
|
24
|
+
*/
|
|
25
|
+
create(root: TreeNode<Id, Value>, folds: Folds<Id>, cursor: Cursor<Id>): State<Id, Value> | undefined;
|
|
26
|
+
getRoot(state: State<Id, Value>): TreeNode<Id, Value>;
|
|
27
|
+
getFolds(state: State<Id, Value>): Folds<Id>;
|
|
28
|
+
getCursor(state: State<Id, Value>): Cursor<Id>;
|
|
29
|
+
/**
|
|
30
|
+
* Immutably replaces supplied state components.
|
|
31
|
+
*
|
|
32
|
+
* Returns undefined when the replacement root is not a loaded branch.
|
|
33
|
+
* Returns the original state when all components retain their references.
|
|
34
|
+
*/
|
|
35
|
+
update(state: State<Id, Value>, changes: Readonly<{
|
|
36
|
+
root?: TreeNode<Id, Value>;
|
|
37
|
+
folds?: Folds<Id>;
|
|
38
|
+
cursor?: Cursor<Id>;
|
|
39
|
+
}>): State<Id, Value> | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Returns a mutable root-relative path.
|
|
42
|
+
*
|
|
43
|
+
* For a fold cursor, returns the path of its first hidden child.
|
|
44
|
+
* This representative path does not identify the fold marker itself.
|
|
45
|
+
*/
|
|
46
|
+
cursorPath(state: State<Id, Value>): Id[];
|
|
47
|
+
/**
|
|
48
|
+
* Tests whether the cursor is the root node cursor: { path: [] }.
|
|
49
|
+
*/
|
|
50
|
+
isCursorRoot(state: State<Id, Value>): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Resolves a node cursor against the source tree.
|
|
53
|
+
*
|
|
54
|
+
* Returns undefined for fold cursors or paths absent from the loaded tree.
|
|
55
|
+
* This does not check visibility in a navigation projection.
|
|
56
|
+
*/
|
|
57
|
+
getNodeAtCursor(state: State<Id, Value>): TreeNode<Id, Value> | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Reloads the root's children and all descendant branches that were loaded
|
|
60
|
+
* in the previous state.
|
|
61
|
+
*
|
|
62
|
+
* `loadBranches([])` loads the root's direct children.
|
|
63
|
+
* `loadBranches(['src'])` loads the children of `src`, where `src` is the
|
|
64
|
+
* ID of a root child.
|
|
65
|
+
*
|
|
66
|
+
* Returned nodes must be valid TreeNode values created or decoded through
|
|
67
|
+
* the specialized TreeNodeApi for `Id` and `Value`.
|
|
68
|
+
*/
|
|
69
|
+
resync(oldState: State<Id, Value>, loadBranches: (path: readonly Id[]) => Promise<readonly TreeNode<Id, Value>[]>): Promise<State<Id, Value>>;
|
|
70
|
+
}>;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=state.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.types.d.ts","sourceRoot":"","sources":["../../../src/state-and-nav/state/state.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAAI,QAAQ,CAAC;IAC9D,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC;QACrB,EAAE,EAAE,EAAE,CAAC;QACP,KAAK,EAAE,KAAK,CAAC;KACd,CAAC,CAAC;CACJ,CAAC,CAAC;AAEH,MAAM,MAAM,YAAY,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAAI,QAAQ,CAAC;IACrE,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACpC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,CAAC;IAC7B,aAAa,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;IAEjC;;;;OAIG;IACH,MAAM,CACJ,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,EACzB,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,EAChB,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GACjB,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;IAEhC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IACtD,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7C,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;IAE/C;;;;;OAKG;IACH,MAAM,CACJ,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EACvB,OAAO,EAAE,QAAQ,CAAC;QAChB,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QAC3B,KAAK,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;KACrB,CAAC,GACD,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;IAEhC;;;;;OAKG;IACH,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;IAC1C;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC;IAC/C;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,GAAG,SAAS,CAAC;IAE1E;;;;;;;;;;OAUG;IACH,MAAM,CACJ,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,EAC1B,YAAY,EAAE,CACZ,IAAI,EAAE,SAAS,EAAE,EAAE,KAChB,OAAO,CAAC,SAAS,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,GAC3C,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;CAC9B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-node.arb.d.ts","sourceRoot":"","sources":["../../../../src/state-and-nav/tree/deprecated/tree-node.arb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD;;;;GAIG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC;AAOzB;;;GAGG;AACH,eAAO,MAAM,SAAS,sBAIpB,CAAC;AAEH;;GAEG;AAEH,MAAM,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAC1D,KAAK,IAAI,GAAG,UAAU,EAAE,CAAC;AAEzB,KAAK,UAAU,GAAG;IAChB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,UAAU,CAAC;CAClB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,EAAE,UAAU,EAAE,CAAC;CAC9B,CAAC;AAuEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,sCAEhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,sCAExC,CAAC;AAaF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,EAAE,EAAE,CAAC,SAAS,CAAC,sBAAsB,CA0C5D,CAAC;AAEP;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,wCAIjC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;EAK3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;;;;EAQnC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;EAYpC,CAAC;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,cAAc,qBAE1B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,4BAA8C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-node.arb.debug.test.d.ts","sourceRoot":"","sources":["../../../../src/state-and-nav/tree/deprecated/tree-node.arb.debug.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-node.impl.d.ts","sourceRoot":"","sources":["../../../../src/state-and-nav/tree/deprecated/tree-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,eAAe,EACf,QAAQ,EACR,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,SAAS,eAAe,EAC1B,IAAI,SAAS,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC,KAC5B,WAAW,CAAC,EAAE,EAAE,IAAI,CAAC,CAqGzB"}
|