dirvi-lib 0.8.1 → 0.8.2
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-api.d.ts +74 -0
- package/dist/app/app-api.d.ts.map +1 -0
- package/dist/app/app-api.js +11 -0
- package/dist/app/effect-to-action.d.ts +6 -0
- package/dist/app/effect-to-action.d.ts.map +1 -0
- package/dist/app/effect-to-action.js +74 -0
- package/dist/app/index.d.ts +6 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +5 -0
- package/dist/app/reducer-action.d.ts +22 -0
- package/dist/app/reducer-action.d.ts.map +1 -0
- package/dist/app/reducer.d.ts +5 -0
- package/dist/app/reducer.d.ts.map +1 -0
- package/dist/app/reducer.js +79 -0
- package/dist/app/view-api.d.ts +11 -0
- package/dist/app/view-api.d.ts.map +1 -0
- package/dist/index.d.ts +4 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- package/dist/input/application/index.d.ts.map +1 -0
- package/dist/input/application/intent-to-effect-no-state.test.d.ts.map +1 -0
- package/dist/input/application/intent-to-effect.d.ts +14 -0
- package/dist/input/application/intent-to-effect.d.ts.map +1 -0
- package/dist/{tree-surfer-ui → input}/application/intent-to-effect.js +36 -17
- package/dist/input/application/parse-command.d.ts +14 -0
- package/dist/input/application/parse-command.d.ts.map +1 -0
- package/dist/{tree-surfer-ui → input}/application/parse-command.js +13 -1
- package/dist/input/application/user-input-to-intent.d.ts.map +1 -0
- package/dist/input/application/user-input-to-intent.test.d.ts.map +1 -0
- package/dist/input/domain/effect.d.ts +55 -0
- package/dist/input/domain/effect.d.ts.map +1 -0
- package/dist/input/domain/index.d.ts.map +1 -0
- package/dist/input/domain/input-mode-state.d.ts.map +1 -0
- package/dist/input/domain/intent.d.ts.map +1 -0
- package/dist/input/domain/user-input.d.ts.map +1 -0
- package/dist/trees/cursor.d.ts.map +1 -0
- package/dist/trees/fold-node/deprecated/fold-node.impl.d.ts +10 -0
- package/dist/trees/fold-node/deprecated/fold-node.impl.d.ts.map +1 -0
- package/dist/trees/fold-node/deprecated/fold-node.impl.js +248 -0
- package/dist/trees/fold-node/deprecated/fold-node.test.d.ts +2 -0
- package/dist/trees/fold-node/deprecated/fold-node.test.d.ts.map +1 -0
- package/dist/trees/fold-node/deprecated/fold-node.test.js +130 -0
- package/dist/{tree-surfer/fold-node → trees/fold-node/deprecated}/fold-node.types.d.ts +15 -76
- package/dist/trees/fold-node/deprecated/fold-node.types.d.ts.map +1 -0
- package/dist/trees/fold-node/fold-node.impl.d.ts +16 -0
- package/dist/trees/fold-node/fold-node.impl.d.ts.map +1 -0
- package/dist/trees/fold-node/fold-node.impl.js +451 -0
- package/dist/trees/fold-node/fold-node.model.d.ts +120 -0
- package/dist/trees/fold-node/fold-node.model.d.ts.map +1 -0
- package/dist/trees/fold-node/fold-node.model.js +80 -0
- package/dist/trees/fold-node/fold-node.types.d.ts +206 -0
- package/dist/trees/fold-node/fold-node.types.d.ts.map +1 -0
- package/dist/trees/fold-node/index.d.ts +4 -0
- package/dist/trees/fold-node/index.d.ts.map +1 -0
- package/dist/trees/fold-node/index.js +3 -0
- package/dist/trees/index.d.ts +9 -0
- package/dist/trees/index.d.ts.map +1 -0
- package/dist/trees/index.js +8 -0
- package/dist/trees/nav-node/nav-node.impl.d.ts +29 -0
- package/dist/trees/nav-node/nav-node.impl.d.ts.map +1 -0
- package/dist/{tree-surfer → trees}/nav-node/nav-node.impl.js +89 -42
- package/dist/trees/nav-node/nav-node.types.d.ts +103 -0
- package/dist/trees/nav-node/nav-node.types.d.ts.map +1 -0
- package/dist/trees/state/state.impl.d.ts +8 -0
- package/dist/trees/state/state.impl.d.ts.map +1 -0
- package/dist/trees/state/state.impl.js +128 -0
- package/dist/trees/state/state.schemas.d.ts +25 -0
- package/dist/trees/state/state.schemas.d.ts.map +1 -0
- package/dist/trees/state/state.schemas.js +17 -0
- package/dist/trees/state/state.types.d.ts +36 -0
- package/dist/trees/state/state.types.d.ts.map +1 -0
- package/dist/trees/state/state.types.js +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.arb.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.arb.debug.test.d.ts.map +1 -0
- package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.debug.test.js +1 -1
- package/dist/trees/tree-node/deprecated/tree-node.impl.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.schemas.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.test.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.types.d.ts.map +1 -0
- package/dist/trees/tree-node/deprecated/tree-node.types.js +1 -0
- package/dist/trees/tree-node/index.d.ts +4 -0
- package/dist/trees/tree-node/index.d.ts.map +1 -0
- package/dist/trees/tree-node/index.js +3 -0
- package/dist/trees/tree-node/tree-node.arb.d.ts +104 -0
- package/dist/trees/tree-node/tree-node.arb.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.arb.js +191 -0
- package/dist/trees/tree-node/tree-node.impl.d.ts +15 -0
- package/dist/trees/tree-node/tree-node.impl.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.impl.js +286 -0
- package/dist/trees/tree-node/tree-node.model.d.ts +78 -0
- package/dist/trees/tree-node/tree-node.model.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.model.js +37 -0
- package/dist/trees/tree-node/tree-node.types.d.ts +419 -0
- package/dist/trees/tree-node/tree-node.types.d.ts.map +1 -0
- package/dist/trees/tree-node/tree-node.types.js +1 -0
- package/package.json +1 -1
- package/dist/tree-surfer/cursor.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.arb.d.ts +0 -2
- package/dist/tree-surfer/fold-node/fold-node.arb.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts +0 -4
- package/dist/tree-surfer/fold-node/fold-node.impl.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.impl.js +0 -149
- package/dist/tree-surfer/fold-node/fold-node.schema.d.ts +0 -5
- package/dist/tree-surfer/fold-node/fold-node.schema.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/fold-node.schema.js +0 -9
- package/dist/tree-surfer/fold-node/fold-node.types.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/tree-node.test.d.ts.map +0 -1
- package/dist/tree-surfer/fold-node/tree-node.test.js +0 -90
- package/dist/tree-surfer/index.d.ts +0 -13
- package/dist/tree-surfer/index.d.ts.map +0 -1
- package/dist/tree-surfer/index.js +0 -12
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts +0 -6
- package/dist/tree-surfer/nav-node/nav-node.impl.d.ts.map +0 -1
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts +0 -70
- package/dist/tree-surfer/nav-node/nav-node.types.d.ts.map +0 -1
- package/dist/tree-surfer/state/state.impl.d.ts +0 -7
- package/dist/tree-surfer/state/state.impl.d.ts.map +0 -1
- package/dist/tree-surfer/state/state.impl.js +0 -89
- package/dist/tree-surfer/state/state.schemas.d.ts +0 -9
- package/dist/tree-surfer/state/state.schemas.d.ts.map +0 -1
- package/dist/tree-surfer/state/state.schemas.js +0 -8
- package/dist/tree-surfer/state/state.types.d.ts +0 -21
- package/dist/tree-surfer/state/state.types.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.arb.debug.test.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.impl.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.schemas.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.test.d.ts +0 -2
- package/dist/tree-surfer/tree-node/tree-node.test.d.ts.map +0 -1
- package/dist/tree-surfer/tree-node/tree-node.types.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/index.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/intent-to-effect-no-state.test.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts +0 -10
- package/dist/tree-surfer-ui/application/intent-to-effect.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/parse-command.d.ts +0 -4
- package/dist/tree-surfer-ui/application/parse-command.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/user-input-to-intent.d.ts.map +0 -1
- package/dist/tree-surfer-ui/application/user-input-to-intent.test.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/effect.d.ts +0 -43
- package/dist/tree-surfer-ui/domain/effect.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/index.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/input-mode-state.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/intent.d.ts.map +0 -1
- package/dist/tree-surfer-ui/domain/user-input.d.ts.map +0 -1
- /package/dist/{tree-surfer-ui/domain/effect.js → app/reducer-action.js} +0 -0
- /package/dist/{tree-surfer-ui/domain/input-mode-state.js → app/view-api.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/application/index.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/index.js +0 -0
- /package/dist/{tree-surfer-ui → input}/application/intent-to-effect-no-state.test.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/intent-to-effect-no-state.test.js +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.js +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.test.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/application/user-input-to-intent.test.js +0 -0
- /package/dist/{tree-surfer-ui/domain/intent.js → input/domain/effect.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/index.d.ts +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/index.js +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/input-mode-state.d.ts +0 -0
- /package/dist/{tree-surfer-ui/domain/user-input.js → input/domain/input-mode-state.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/intent.d.ts +0 -0
- /package/dist/{tree-surfer/fold-node/fold-node.arb.js → input/domain/intent.js} +0 -0
- /package/dist/{tree-surfer-ui → input}/domain/user-input.d.ts +0 -0
- /package/dist/{tree-surfer/fold-node/fold-node.types.js → input/domain/user-input.js} +0 -0
- /package/dist/{tree-surfer → trees}/cursor.d.ts +0 -0
- /package/dist/{tree-surfer → trees}/cursor.js +0 -0
- /package/dist/{tree-surfer/nav-node/nav-node.types.js → trees/fold-node/deprecated/fold-node.types.js} +0 -0
- /package/dist/{tree-surfer/state/state.types.js → trees/fold-node/fold-node.types.js} +0 -0
- /package/dist/{tree-surfer/tree-node/tree-node.types.js → trees/nav-node/nav-node.types.js} +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.debug.test.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.arb.js +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.impl.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.impl.js +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.schemas.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.schemas.js +0 -0
- /package/dist/{tree-surfer/fold-node → trees/tree-node/deprecated}/tree-node.test.d.ts +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.test.js +0 -0
- /package/dist/{tree-surfer/tree-node → trees/tree-node/deprecated}/tree-node.types.d.ts +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import type { SerializableKey } from '../tree-node/index.js';
|
|
2
|
+
import type { FoldSlotModel, FoldsModel } from './fold-node.model.js';
|
|
3
|
+
declare const foldsBrand: unique symbol;
|
|
4
|
+
/**
|
|
5
|
+
* A slot index within Folds.
|
|
6
|
+
*
|
|
7
|
+
* Index 0 is always occupied by the required primary fold tree.
|
|
8
|
+
*
|
|
9
|
+
* Other valid indexes are non-negative safe integers. TypeScript cannot
|
|
10
|
+
* represent that restriction for number, so indexes must be validated at
|
|
11
|
+
* runtime at API boundaries.
|
|
12
|
+
*/
|
|
13
|
+
export type FoldIndex = number;
|
|
14
|
+
/**
|
|
15
|
+
* Public user-facing metadata for a fold tree.
|
|
16
|
+
*
|
|
17
|
+
* Every fold tree has a name. `description: null` means that no description
|
|
18
|
+
* has been supplied. An empty string is distinct: it is a supplied
|
|
19
|
+
* description with no text.
|
|
20
|
+
*/
|
|
21
|
+
export type FoldInfo = Readonly<{
|
|
22
|
+
/**
|
|
23
|
+
* Durable user-facing name of the fold tree.
|
|
24
|
+
*/
|
|
25
|
+
name: string;
|
|
26
|
+
/**
|
|
27
|
+
* User-facing description of the fold tree, or `null` when none exists.
|
|
28
|
+
*/
|
|
29
|
+
description: string | null;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Immutable collection of fold-data slots for one source node tree.
|
|
33
|
+
*
|
|
34
|
+
* Every contained fold tree uses the same ID paths as the source TreeNode
|
|
35
|
+
* tree. Slot zero always contains a fold tree.
|
|
36
|
+
*/
|
|
37
|
+
export type Folds<Id extends SerializableKey> = {
|
|
38
|
+
readonly [foldsBrand]: {
|
|
39
|
+
readonly id: Id;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
export type FoldsApi<Id extends SerializableKey> = Readonly<{
|
|
43
|
+
/**
|
|
44
|
+
* Creates Folds with its required primary fold tree in slot zero.
|
|
45
|
+
*
|
|
46
|
+
* The new fold tree initially contains no hidden entries and is active.
|
|
47
|
+
*/
|
|
48
|
+
create(rootId: Id, initialPrimaryInfo: FoldInfo): Folds<Id>;
|
|
49
|
+
/**
|
|
50
|
+
* Returns metadata for the fold tree at an occupied slot.
|
|
51
|
+
*
|
|
52
|
+
* Index zero always returns FoldInfo for a valid Folds value.
|
|
53
|
+
*/
|
|
54
|
+
getInfoAtIndex(folds: Folds<Id>, index: FoldIndex): FoldInfo | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Returns whether the fold tree at an occupied slot is active.
|
|
57
|
+
*
|
|
58
|
+
* Returns `undefined` when the slot is unoccupied.
|
|
59
|
+
*/
|
|
60
|
+
isActiveAtIndex(folds: Folds<Id>, index: FoldIndex): boolean | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Returns whether a slot is occupied.
|
|
63
|
+
*
|
|
64
|
+
* For valid Folds values, `hasAtIndex(folds, 0)` is always true.
|
|
65
|
+
*/
|
|
66
|
+
hasAtIndex(folds: Folds<Id>, index: FoldIndex): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Returns occupied slot indexes.
|
|
69
|
+
*
|
|
70
|
+
* The ordering is ascending slot order.
|
|
71
|
+
*/
|
|
72
|
+
indexes(folds: Folds<Id>): Iterable<FoldIndex>;
|
|
73
|
+
/**
|
|
74
|
+
* Stores a serialized occupied fold slot at an index.
|
|
75
|
+
*
|
|
76
|
+
* Replaces any existing slot at that index. The supplied `Folds` value is not
|
|
77
|
+
* mutated.
|
|
78
|
+
*
|
|
79
|
+
* `foldData` is converted into the internal opaque fold-tree representation.
|
|
80
|
+
* This operation returns `undefined` when `index` is not a non-negative safe
|
|
81
|
+
* integer or when the slot's fold-tree model cannot be restored.
|
|
82
|
+
*
|
|
83
|
+
* This is a low-level operation. Most callers should use
|
|
84
|
+
* `setAdditionalFoldAtIndex`, `updateInfoAtIndex`, or the fold-state
|
|
85
|
+
* operations instead.
|
|
86
|
+
*/
|
|
87
|
+
setAtIndex(folds: Folds<Id>, index: FoldIndex, foldData: FoldSlotModel<Id>): Folds<Id> | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Creates or replaces a non-primary fold tree at a slot.
|
|
90
|
+
*
|
|
91
|
+
* The new fold tree initially contains no hidden entries.
|
|
92
|
+
*
|
|
93
|
+
* This operation rejects index zero because the required primary fold tree
|
|
94
|
+
* must not be replaced accidentally.
|
|
95
|
+
*/
|
|
96
|
+
setAdditionalFoldAtIndex(folds: Folds<Id>, index: FoldIndex, rootId: Id, info: FoldInfo): Folds<Id> | undefined;
|
|
97
|
+
/**
|
|
98
|
+
* Removes a non-primary fold tree from a slot.
|
|
99
|
+
*
|
|
100
|
+
* Returns `undefined` when `index` is zero because the primary fold tree may
|
|
101
|
+
* not be removed.
|
|
102
|
+
*
|
|
103
|
+
* Returns the original `Folds` reference when the non-primary slot is already
|
|
104
|
+
* unoccupied.
|
|
105
|
+
*/
|
|
106
|
+
removeAdditionalFoldAtIndex(folds: Folds<Id>, index: FoldIndex): Folds<Id> | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Replaces supplied user-facing metadata while preserving the fold tree.
|
|
109
|
+
*
|
|
110
|
+
* Omitted properties are left unchanged.
|
|
111
|
+
*
|
|
112
|
+
* - `description: string` sets or replaces the description.
|
|
113
|
+
* - `description: null` clears the description.
|
|
114
|
+
*/
|
|
115
|
+
updateInfoAtIndex(folds: Folds<Id>, index: FoldIndex, update: Readonly<{
|
|
116
|
+
name?: string;
|
|
117
|
+
description?: string | null;
|
|
118
|
+
}>): Folds<Id> | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* Marks the fold tree at an occupied slot as active.
|
|
121
|
+
*
|
|
122
|
+
* An active fold tree contributes to hiding entries.
|
|
123
|
+
*
|
|
124
|
+
* Returns `undefined` when the slot is unoccupied. Returns the original
|
|
125
|
+
* Folds reference when the fold tree is already active.
|
|
126
|
+
*/
|
|
127
|
+
activateAtIndex(folds: Folds<Id>, index: FoldIndex): Folds<Id> | undefined;
|
|
128
|
+
/**
|
|
129
|
+
* Marks the fold tree at an occupied slot as inactive.
|
|
130
|
+
*
|
|
131
|
+
* An inactive fold tree retains its definition but does not contribute to
|
|
132
|
+
* hiding entries.
|
|
133
|
+
*
|
|
134
|
+
* Returns `undefined` when the slot is unoccupied. Returns the original
|
|
135
|
+
* Folds reference when the fold tree is already inactive.
|
|
136
|
+
*/
|
|
137
|
+
deactivateAtIndex(folds: Folds<Id>, index: FoldIndex): Folds<Id> | undefined;
|
|
138
|
+
/**
|
|
139
|
+
* Inverts whether the fold tree at an occupied slot is active.
|
|
140
|
+
*
|
|
141
|
+
* Returns `undefined` when the slot is unoccupied.
|
|
142
|
+
*/
|
|
143
|
+
toggleActiveAtIndex(folds: Folds<Id>, index: FoldIndex): Folds<Id> | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Returns whether an entry is hidden by one fold tree at an occupied slot.
|
|
146
|
+
*
|
|
147
|
+
* This checks the fold definition regardless of whether that fold tree is
|
|
148
|
+
* currently active.
|
|
149
|
+
*/
|
|
150
|
+
isEntryHiddenInFoldAtPath(folds: Folds<Id>, index: FoldIndex, path: readonly Id[], entryId: Id): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Returns whether an entry is hidden by at least one active fold tree.
|
|
153
|
+
*
|
|
154
|
+
* Inactive fold trees retain fold definitions but do not contribute to this
|
|
155
|
+
* result.
|
|
156
|
+
*/
|
|
157
|
+
isEntryHiddenAtPath(folds: Folds<Id>, path: readonly Id[], entryId: Id): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Returns IDs hidden directly at a branch path in one fold tree.
|
|
160
|
+
*/
|
|
161
|
+
hiddenEntryIdsAtPath(folds: Folds<Id>, index: FoldIndex, path: readonly Id[]): Iterable<Id> | undefined;
|
|
162
|
+
/**
|
|
163
|
+
* Marks an entry as hidden at a branch path in one fold tree.
|
|
164
|
+
*/
|
|
165
|
+
hideEntryAtPath(folds: Folds<Id>, index: FoldIndex, path: readonly Id[], entryId: Id): Folds<Id> | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Removes hidden state for an entry at a branch path in one fold tree.
|
|
168
|
+
*/
|
|
169
|
+
showEntryAtPath(folds: Folds<Id>, index: FoldIndex, path: readonly Id[], entryId: Id): Folds<Id> | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Shows every entry hidden directly at the branch addressed by `path`.
|
|
172
|
+
*
|
|
173
|
+
* This removes all hidden-entry IDs at that fold-tree node but retains
|
|
174
|
+
* descendant fold-tree nodes and their fold state.
|
|
175
|
+
*
|
|
176
|
+
* For example, given:
|
|
177
|
+
*
|
|
178
|
+
* root
|
|
179
|
+
* └── src
|
|
180
|
+
* hiddenEntryIds: ["lib", "main.ts"]
|
|
181
|
+
* └── lib
|
|
182
|
+
* hiddenEntryIds: ["parser.ts"]
|
|
183
|
+
*
|
|
184
|
+
* showAllHiddenEntriesAtPath(folds, index, ["src"]) produces:
|
|
185
|
+
*
|
|
186
|
+
* root
|
|
187
|
+
* └── src
|
|
188
|
+
* hiddenEntryIds: []
|
|
189
|
+
* └── lib
|
|
190
|
+
* hiddenEntryIds: ["parser.ts"]
|
|
191
|
+
*/
|
|
192
|
+
showAllHiddenEntriesAtPath(folds: Folds<Id>, index: FoldIndex, path: readonly Id[]): Folds<Id> | undefined;
|
|
193
|
+
/**
|
|
194
|
+
* Converts opaque runtime folds into a serializable fold-state model.
|
|
195
|
+
*/
|
|
196
|
+
toModel(folds: Folds<Id>): FoldsModel<Id>;
|
|
197
|
+
/**
|
|
198
|
+
* Restores opaque runtime folds from a validated serialized model.
|
|
199
|
+
*
|
|
200
|
+
* This validates fold-internal invariants, but does not validate that paths
|
|
201
|
+
* correspond to a specific source node tree.
|
|
202
|
+
*/
|
|
203
|
+
fromModel(model: FoldsModel<Id>): Folds<Id> | undefined;
|
|
204
|
+
}>;
|
|
205
|
+
export {};
|
|
206
|
+
//# sourceMappingURL=fold-node.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fold-node.types.d.ts","sourceRoot":"","sources":["../../../src/trees/fold-node/fold-node.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/trees/fold-node/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './fold-node/index.js';
|
|
2
|
+
export * from './nav-node/nav-node.impl.js';
|
|
3
|
+
export * from './nav-node/nav-node.types.js';
|
|
4
|
+
export * from './tree-node/index.js';
|
|
5
|
+
export * from './cursor.js';
|
|
6
|
+
export * from './state/state.impl.js';
|
|
7
|
+
export * from './state/state.schemas.js';
|
|
8
|
+
export * from './state/state.types.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/trees/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AAErC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAE7C,cAAc,sBAAsB,CAAC;AAErC,cAAc,aAAa,CAAC;AAE5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from './fold-node/index.js';
|
|
2
|
+
export * from './nav-node/nav-node.impl.js';
|
|
3
|
+
export * from './nav-node/nav-node.types.js';
|
|
4
|
+
export * from './tree-node/index.js';
|
|
5
|
+
export * from './cursor.js';
|
|
6
|
+
export * from './state/state.impl.js';
|
|
7
|
+
export * from './state/state.schemas.js';
|
|
8
|
+
export * from './state/state.types.js';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { SerializableKey, TreeNodeApi } from '../tree-node/index.js';
|
|
2
|
+
import type { FoldsApi } from '../fold-node/index.js';
|
|
3
|
+
import type { CursorApi } from '../cursor.js';
|
|
4
|
+
import type { NavNodeApi } from './nav-node.types.js';
|
|
5
|
+
export type NavEntryComparator<Id extends SerializableKey, Value> = (left: Readonly<{
|
|
6
|
+
id: Id;
|
|
7
|
+
value: Value;
|
|
8
|
+
}>, right: Readonly<{
|
|
9
|
+
id: Id;
|
|
10
|
+
value: Value;
|
|
11
|
+
}>) => number;
|
|
12
|
+
export type CreateNavNodeApiOptions<Id extends SerializableKey, Value> = Readonly<{
|
|
13
|
+
/**
|
|
14
|
+
* Defines display and cursor-navigation order among sibling entries.
|
|
15
|
+
*
|
|
16
|
+
* For deterministic navigation, this should define a total order for
|
|
17
|
+
* distinct sibling entries. If two entries compare equal, their order falls
|
|
18
|
+
* back to the source TreeNode child iteration order.
|
|
19
|
+
*/
|
|
20
|
+
compareEntries: NavEntryComparator<Id, Value>;
|
|
21
|
+
}>;
|
|
22
|
+
/**
|
|
23
|
+
* Creates operations for projecting an opaque tree into a navigation model.
|
|
24
|
+
*
|
|
25
|
+
* Navigation ordering is intentionally a UI concern. The underlying TreeNode
|
|
26
|
+
* API need not promise a particular child-storage representation or ordering.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createNavNodeApi<Id extends SerializableKey, Value>(treeNodeApi: TreeNodeApi<Id, Value>, foldsApi: FoldsApi<Id>, cursorApi: CursorApi<Id>, options: CreateNavNodeApiOptions<Id, Value>): NavNodeApi<Id, Value>;
|
|
29
|
+
//# sourceMappingURL=nav-node.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav-node.impl.d.ts","sourceRoot":"","sources":["../../../src/trees/nav-node/nav-node.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAY,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAS,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAIV,UAAU,EACX,MAAM,qBAAqB,CAAC;AAE7B,MAAM,MAAM,kBAAkB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,IAAI,CAClE,IAAI,EAAE,QAAQ,CAAC;IACb,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,KAAK,CAAC;CACd,CAAC,EACF,KAAK,EAAE,QAAQ,CAAC;IACd,EAAE,EAAE,EAAE,CAAC;IACP,KAAK,EAAE,KAAK,CAAC;CACd,CAAC,KACC,MAAM,CAAC;AAEZ,MAAM,MAAM,uBAAuB,CACjC,EAAE,SAAS,eAAe,EAC1B,KAAK,IACH,QAAQ,CAAC;IACX;;;;;;OAMG;IACH,cAAc,EAAE,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;CAC/C,CAAC,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAChE,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,EACnC,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,EACtB,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,EACxB,OAAO,EAAE,uBAAuB,CAAC,EAAE,EAAE,KAAK,CAAC,GAC1C,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,CA8UvB"}
|
|
@@ -1,17 +1,40 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Creates operations for projecting an opaque tree into a navigation model.
|
|
3
|
+
*
|
|
4
|
+
* Navigation ordering is intentionally a UI concern. The underlying TreeNode
|
|
5
|
+
* API need not promise a particular child-storage representation or ordering.
|
|
6
|
+
*/
|
|
7
|
+
export function createNavNodeApi(treeNodeApi, foldsApi, cursorApi, options) {
|
|
2
8
|
function entryIsBranch(entry) {
|
|
3
9
|
return 'children' in entry;
|
|
4
10
|
}
|
|
11
|
+
function compareTreeNodes(left, right) {
|
|
12
|
+
return options.compareEntries({
|
|
13
|
+
id: treeNodeApi.id(left),
|
|
14
|
+
value: treeNodeApi.value(left),
|
|
15
|
+
}, {
|
|
16
|
+
id: treeNodeApi.id(right),
|
|
17
|
+
value: treeNodeApi.value(right),
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Projects loaded children into navigation entries.
|
|
22
|
+
*
|
|
23
|
+
* Folded source entries are omitted from `entries` and represented in the
|
|
24
|
+
* synthetic `folded` row instead.
|
|
25
|
+
*/
|
|
5
26
|
function createNavNode(entries, foldRoot, parentPath) {
|
|
6
27
|
const visibleEntries = [];
|
|
7
28
|
const foldedEntries = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
29
|
+
/*
|
|
30
|
+
* Navigation owns presentation order, so materialize and sort the child
|
|
31
|
+
* iterable before projecting it.
|
|
32
|
+
*/
|
|
33
|
+
const orderedEntries = [...entries].sort(compareTreeNodes);
|
|
34
|
+
for (const entry of orderedEntries) {
|
|
35
|
+
const entryId = treeNodeApi.id(entry);
|
|
36
|
+
const entryPath = [...parentPath, entryId];
|
|
37
|
+
const isFolded = foldsApi.isEntryHiddenAtPath(foldRoot, parentPath, entryId);
|
|
15
38
|
const navigationEntry = createNavEntry(entry, foldRoot, entryPath);
|
|
16
39
|
if (isFolded) {
|
|
17
40
|
foldedEntries.push(navigationEntry);
|
|
@@ -22,7 +45,11 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
22
45
|
}
|
|
23
46
|
return {
|
|
24
47
|
entries: visibleEntries,
|
|
25
|
-
|
|
48
|
+
/*
|
|
49
|
+
* Fold state may contain entries that are not currently available in the
|
|
50
|
+
* loaded source tree. Do not render an empty synthetic row for them.
|
|
51
|
+
*/
|
|
52
|
+
folded: foldedEntries.length === 0
|
|
26
53
|
? null
|
|
27
54
|
: {
|
|
28
55
|
entries: foldedEntries,
|
|
@@ -30,23 +57,32 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
30
57
|
};
|
|
31
58
|
}
|
|
32
59
|
function createNavEntry(entry, foldRoot, entryPath) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
id
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
return treeNodeApi.match(entry, {
|
|
61
|
+
leaf: ({ id }) => ({
|
|
62
|
+
id,
|
|
63
|
+
}),
|
|
64
|
+
unloadedBranch: ({ id }) => ({
|
|
65
|
+
id,
|
|
66
|
+
children: null,
|
|
67
|
+
}),
|
|
68
|
+
loadedBranch: ({ id, children }) => ({
|
|
69
|
+
id,
|
|
70
|
+
children: createNavNode(children, foldRoot, entryPath),
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
39
73
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
74
|
+
function createRootNavBranch(root, foldRoot) {
|
|
75
|
+
return treeNodeApi.match(root, {
|
|
76
|
+
leaf: () => undefined,
|
|
77
|
+
unloadedBranch: ({ id }) => ({
|
|
78
|
+
id,
|
|
79
|
+
children: null,
|
|
80
|
+
}),
|
|
81
|
+
loadedBranch: ({ id, children }) => ({
|
|
82
|
+
id,
|
|
83
|
+
children: createNavNode(children, foldRoot, []),
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
50
86
|
}
|
|
51
87
|
function rootCursors(rootNode) {
|
|
52
88
|
if (rootNode.children === null) {
|
|
@@ -68,24 +104,24 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
68
104
|
}
|
|
69
105
|
const navNodeApi = {
|
|
70
106
|
entryIsBranch,
|
|
71
|
-
// Return a nav node from the TreeNode and FoldNode trees.
|
|
72
107
|
from(root, foldRoot) {
|
|
73
|
-
return
|
|
108
|
+
return createRootNavBranch(root, foldRoot);
|
|
74
109
|
},
|
|
75
110
|
getNodeAtPath(navigation, path) {
|
|
76
111
|
const [currentId, ...remainingPath] = path;
|
|
77
|
-
|
|
112
|
+
/*
|
|
113
|
+
* An empty path identifies the current navigation node.
|
|
114
|
+
*/
|
|
78
115
|
if (currentId === undefined) {
|
|
79
116
|
return navigation;
|
|
80
117
|
}
|
|
81
118
|
const entry = navigation.entries.find((candidate) => candidate.id === currentId);
|
|
82
|
-
if (entry === undefined) {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
if (!entryIsBranch(entry)) {
|
|
119
|
+
if (entry === undefined || !entryIsBranch(entry)) {
|
|
86
120
|
return undefined;
|
|
87
121
|
}
|
|
88
|
-
|
|
122
|
+
/*
|
|
123
|
+
* A null value represents a source branch whose children are not loaded.
|
|
124
|
+
*/
|
|
89
125
|
if (entry.children === null) {
|
|
90
126
|
return undefined;
|
|
91
127
|
}
|
|
@@ -93,6 +129,10 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
93
129
|
},
|
|
94
130
|
getEntryAtPath(navigation, path) {
|
|
95
131
|
const [currentId, ...remainingPath] = path;
|
|
132
|
+
/*
|
|
133
|
+
* A NavNode does not itself correspond to a NavEntry. Therefore [] does
|
|
134
|
+
* not resolve to an entry.
|
|
135
|
+
*/
|
|
96
136
|
if (currentId === undefined) {
|
|
97
137
|
return undefined;
|
|
98
138
|
}
|
|
@@ -125,6 +165,7 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
125
165
|
return cursors[currentIndex - 1];
|
|
126
166
|
},
|
|
127
167
|
cursorAfterFold(rootNode, cursor) {
|
|
168
|
+
// Folding root disallowed
|
|
128
169
|
if (cursor.length === 0) {
|
|
129
170
|
return undefined;
|
|
130
171
|
}
|
|
@@ -133,18 +174,22 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
133
174
|
if (currentIndex === -1) {
|
|
134
175
|
return undefined;
|
|
135
176
|
}
|
|
177
|
+
// If the last entry, then cursor should go to previous entry
|
|
178
|
+
// This works to go to the root when the last entry in the root is folded.
|
|
179
|
+
if (currentIndex + 1 === cursors.length) {
|
|
180
|
+
return cursors[currentIndex - 1];
|
|
181
|
+
}
|
|
136
182
|
for (let index = currentIndex + 1; index < cursors.length; index += 1) {
|
|
137
183
|
const candidate = cursors[index];
|
|
138
184
|
if (candidate === undefined) {
|
|
139
185
|
continue;
|
|
140
186
|
}
|
|
187
|
+
// Skip any entries that are children of the entry about to be folded
|
|
141
188
|
if (cursorApi.cursorBelongsToSubtree(candidate, cursor)) {
|
|
142
189
|
continue;
|
|
143
190
|
}
|
|
144
191
|
return candidate;
|
|
145
192
|
}
|
|
146
|
-
// The fold row will be created at the end of this directory.
|
|
147
|
-
return [...cursor];
|
|
148
193
|
},
|
|
149
194
|
parentCursor(_navigation, cursor) {
|
|
150
195
|
if (cursor.length === 0) {
|
|
@@ -159,15 +204,17 @@ export function createNavNodeApi(treeNodeApi, foldNodeService, cursorApi) {
|
|
|
159
204
|
const paths = [];
|
|
160
205
|
for (const entry of navigation.entries) {
|
|
161
206
|
const entryPath = [...parentPath, entry.id];
|
|
162
|
-
if (entryIsBranch(entry)) {
|
|
163
|
-
|
|
164
|
-
// loaded/opened, so there are no visible descendant files.
|
|
165
|
-
if (entry.children !== null) {
|
|
166
|
-
paths.push(...navNodeApi.visibleLeavesPaths(entry.children, entryPath));
|
|
167
|
-
}
|
|
207
|
+
if (!entryIsBranch(entry)) {
|
|
208
|
+
paths.push(entryPath);
|
|
168
209
|
continue;
|
|
169
210
|
}
|
|
170
|
-
|
|
211
|
+
/*
|
|
212
|
+
* A null value means the source branch is not loaded/opened. It has no
|
|
213
|
+
* currently visible descendants.
|
|
214
|
+
*/
|
|
215
|
+
if (entry.children !== null) {
|
|
216
|
+
paths.push(...navNodeApi.visibleLeavesPaths(entry.children, entryPath));
|
|
217
|
+
}
|
|
171
218
|
}
|
|
172
219
|
return paths;
|
|
173
220
|
},
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import type { SerializableKey, TreeNode } from '../tree-node/index.js';
|
|
2
|
+
import type { Cursor } from '../cursor.js';
|
|
3
|
+
import type { Folds } from '../fold-node/index.js';
|
|
4
|
+
export type NavNode<Id extends SerializableKey> = {
|
|
5
|
+
/**
|
|
6
|
+
* Synthetic UI entry representing folded children.
|
|
7
|
+
*
|
|
8
|
+
* It is absent when this directory has no folded children.
|
|
9
|
+
*/
|
|
10
|
+
folded: NavFoldEntry<Id> | null;
|
|
11
|
+
/**
|
|
12
|
+
* Loaded entries that are not folded at this directory, corresponding to
|
|
13
|
+
* navigable rows.
|
|
14
|
+
*
|
|
15
|
+
* Their order is the sibling iteration order supplied by the TreeNode API.
|
|
16
|
+
*/
|
|
17
|
+
entries: NavEntry<Id>[];
|
|
18
|
+
};
|
|
19
|
+
export type NavFoldEntry<Id extends SerializableKey> = {
|
|
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>;
|
|
28
|
+
export type NavLeaf<Id extends SerializableKey> = {
|
|
29
|
+
id: Id;
|
|
30
|
+
};
|
|
31
|
+
export type NavBranch<Id extends SerializableKey> = {
|
|
32
|
+
id: Id;
|
|
33
|
+
/**
|
|
34
|
+
* `null` means this branch's children have not been loaded or opened.
|
|
35
|
+
*/
|
|
36
|
+
children: NavNode<Id> | null;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Operations for creating and navigating a UI-oriented projection of a tree.
|
|
40
|
+
*
|
|
41
|
+
* @typeParam Id - The type identifying a node among its direct siblings.
|
|
42
|
+
* @typeParam Value - Application-owned data stored in each source TreeNode.
|
|
43
|
+
*/
|
|
44
|
+
export type NavNodeApi<Id extends SerializableKey, Value> = {
|
|
45
|
+
/**
|
|
46
|
+
* Tests whether a navigation entry represents a branch.
|
|
47
|
+
*
|
|
48
|
+
* A branch is an entry with a `children` property. Its `children` value is
|
|
49
|
+
* `null` when the corresponding source-tree branch has not been loaded or
|
|
50
|
+
* opened.
|
|
51
|
+
*/
|
|
52
|
+
entryIsBranch(entry: NavEntry<Id>): entry is NavBranch<Id>;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a navigation projection rooted at `root`.
|
|
55
|
+
*
|
|
56
|
+
* The source TreeNode is authoritative for:
|
|
57
|
+
*
|
|
58
|
+
* - entry identity;
|
|
59
|
+
* - whether an entry is a leaf, closed branch, or open branch;
|
|
60
|
+
* - the loaded direct child entries; and
|
|
61
|
+
* - sibling iteration order, where guaranteed by TreeNodeApi.
|
|
62
|
+
*
|
|
63
|
+
* `foldRoot` is authoritative for folding. It contains multiple independently
|
|
64
|
+
* active fold trees. An entry is folded in the projection when at least one
|
|
65
|
+
* active fold tree hides that entry at its parent path.
|
|
66
|
+
*
|
|
67
|
+
* A folded entry is omitted from its parent's navigable entries and is
|
|
68
|
+
* represented by that parent's synthetic `folded` entry instead.
|
|
69
|
+
*
|
|
70
|
+
* The root must be a branch node. Since TreeNode is opaque, callers cannot
|
|
71
|
+
* express that fact statically. This method returns `undefined` if `root`
|
|
72
|
+
* is a leaf.
|
|
73
|
+
*
|
|
74
|
+
* A closed root branch produces a NavBranch whose `children` is `null`.
|
|
75
|
+
*
|
|
76
|
+
* @param root - Source tree node from which to create navigation.
|
|
77
|
+
* @param folds - Fold definitions corresponding to `root`. All active fold
|
|
78
|
+
* trees contribute to whether a source entry is represented by its parent’s
|
|
79
|
+
* synthetic `folded` entry.
|
|
80
|
+
* @returns The projected root branch, or `undefined` when `root` is a leaf.
|
|
81
|
+
*/
|
|
82
|
+
from(root: TreeNode<Id, Value>, folds: Folds<Id>): NavBranch<Id> | undefined;
|
|
83
|
+
/**
|
|
84
|
+
* Finds the navigation node represented by a path relative to `navigation`.
|
|
85
|
+
*
|
|
86
|
+
* An empty path selects `navigation` itself. Paths cannot pass through leaf
|
|
87
|
+
* entries or branches whose children are currently `null`.
|
|
88
|
+
*/
|
|
89
|
+
getNodeAtPath(navigation: NavNode<Id>, path: readonly Id[]): NavNode<Id> | undefined;
|
|
90
|
+
/**
|
|
91
|
+
* Finds the navigation entry represented by a path relative to `navigation`.
|
|
92
|
+
*
|
|
93
|
+
* An empty path does not identify an entry and returns `undefined`.
|
|
94
|
+
*/
|
|
95
|
+
getEntryAtPath(navigation: NavNode<Id>, path: readonly Id[]): NavEntry<Id> | undefined;
|
|
96
|
+
nextCursor(rootNode: NavBranch<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
|
|
97
|
+
previousCursor(rootNode: NavBranch<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
|
|
98
|
+
cursorAfterFold(rootNode: NavBranch<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
|
|
99
|
+
parentCursor(navigation: NavNode<Id>, cursor: Cursor<Id>): Cursor<Id> | undefined;
|
|
100
|
+
cursors(navigation: NavNode<Id>, parentPath?: readonly Id[]): Cursor<Id>[];
|
|
101
|
+
visibleLeavesPaths(navigation: NavNode<Id>, parentPath?: readonly Id[]): Id[][];
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=nav-node.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nav-node.types.d.ts","sourceRoot":"","sources":["../../../src/trees/nav-node/nav-node.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { SerializableKey, TreeNodeApi } from '../tree-node/index.js';
|
|
2
|
+
import type { CursorApi } from '../cursor.js';
|
|
3
|
+
import type { StateApi } from './state.types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates operations for navigating and resynchronizing tree-surfer state.
|
|
6
|
+
*/
|
|
7
|
+
export declare function createStateApi<Id extends SerializableKey, Value>(treeNodeApi: TreeNodeApi<Id, Value>, cursorApi: CursorApi<Id>): StateApi<Id, Value>;
|
|
8
|
+
//# sourceMappingURL=state.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.impl.d.ts","sourceRoot":"","sources":["../../../src/trees/state/state.impl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAY,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEpF,OAAO,KAAK,EAAU,SAAS,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAS,MAAM,kBAAkB,CAAC;AAMxD;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAAE,SAAS,eAAe,EAAE,KAAK,EAC9D,WAAW,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,CAAC,EACnC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,GACvB,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC,CAuLrB"}
|