@textui/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 +67 -0
- package/dist/adapters/index.d.ts +12 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +11 -0
- package/dist/app/app.d.ts +200 -0
- package/dist/app/app.d.ts.map +1 -0
- package/dist/app/app.js +980 -0
- package/dist/core/animation.d.ts +34 -0
- package/dist/core/animation.d.ts.map +1 -0
- package/dist/core/animation.js +125 -0
- package/dist/core/clipboard.d.ts +29 -0
- package/dist/core/clipboard.d.ts.map +1 -0
- package/dist/core/clipboard.js +30 -0
- package/dist/core/commands.d.ts +42 -0
- package/dist/core/commands.d.ts.map +1 -0
- package/dist/core/commands.js +146 -0
- package/dist/core/components.d.ts +27 -0
- package/dist/core/components.d.ts.map +1 -0
- package/dist/core/components.js +78 -0
- package/dist/core/events.d.ts +23 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +77 -0
- package/dist/core/focus.d.ts +69 -0
- package/dist/core/focus.d.ts.map +1 -0
- package/dist/core/focus.js +336 -0
- package/dist/core/i18n.d.ts +27 -0
- package/dist/core/i18n.d.ts.map +1 -0
- package/dist/core/i18n.js +88 -0
- package/dist/core/keybindings.d.ts +53 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/keybindings.js +163 -0
- package/dist/core/layers.d.ts +28 -0
- package/dist/core/layers.d.ts.map +1 -0
- package/dist/core/layers.js +84 -0
- package/dist/core/manifest.d.ts +22 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +85 -0
- package/dist/core/navigation.d.ts +47 -0
- package/dist/core/navigation.d.ts.map +1 -0
- package/dist/core/navigation.js +110 -0
- package/dist/core/resources.d.ts +115 -0
- package/dist/core/resources.d.ts.map +1 -0
- package/dist/core/resources.js +321 -0
- package/dist/core/services.d.ts +21 -0
- package/dist/core/services.d.ts.map +1 -0
- package/dist/core/services.js +63 -0
- package/dist/core/store.d.ts +60 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +593 -0
- package/dist/core/surfaces.d.ts +81 -0
- package/dist/core/surfaces.d.ts.map +1 -0
- package/dist/core/surfaces.js +237 -0
- package/dist/core/syntax.d.ts +49 -0
- package/dist/core/syntax.d.ts.map +1 -0
- package/dist/core/syntax.js +172 -0
- package/dist/core/when.d.ts +15 -0
- package/dist/core/when.d.ts.map +1 -0
- package/dist/core/when.js +224 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/jsx/factory.d.ts +27 -0
- package/dist/jsx/factory.d.ts.map +1 -0
- package/dist/jsx/factory.js +102 -0
- package/dist/jsx/intrinsics.d.ts +96 -0
- package/dist/jsx/intrinsics.d.ts.map +1 -0
- package/dist/jsx/intrinsics.js +1 -0
- package/dist/jsx/jsx-dev-runtime.d.ts +13 -0
- package/dist/jsx/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-dev-runtime.js +12 -0
- package/dist/jsx/jsx-runtime.d.ts +42 -0
- package/dist/jsx/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx/jsx-runtime.js +16 -0
- package/dist/render/buffer.d.ts +77 -0
- package/dist/render/buffer.d.ts.map +1 -0
- package/dist/render/buffer.js +275 -0
- package/dist/render/color.d.ts +35 -0
- package/dist/render/color.d.ts.map +1 -0
- package/dist/render/color.js +160 -0
- package/dist/render/diff.d.ts +37 -0
- package/dist/render/diff.d.ts.map +1 -0
- package/dist/render/diff.js +66 -0
- package/dist/render/layout.d.ts +72 -0
- package/dist/render/layout.d.ts.map +1 -0
- package/dist/render/layout.js +633 -0
- package/dist/render/static.d.ts +63 -0
- package/dist/render/static.d.ts.map +1 -0
- package/dist/render/static.js +209 -0
- package/dist/runtime/bindings.d.ts +46 -0
- package/dist/runtime/bindings.d.ts.map +1 -0
- package/dist/runtime/bindings.js +116 -0
- package/dist/runtime/hooks.d.ts +284 -0
- package/dist/runtime/hooks.d.ts.map +1 -0
- package/dist/runtime/hooks.js +846 -0
- package/dist/runtime/instance.d.ts +106 -0
- package/dist/runtime/instance.d.ts.map +1 -0
- package/dist/runtime/instance.js +181 -0
- package/dist/runtime/paint.d.ts +27 -0
- package/dist/runtime/paint.d.ts.map +1 -0
- package/dist/runtime/paint.js +567 -0
- package/dist/runtime/reconcile.d.ts +23 -0
- package/dist/runtime/reconcile.d.ts.map +1 -0
- package/dist/runtime/reconcile.js +260 -0
- package/dist/runtime/runtime.d.ts +42 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +1 -0
- package/dist/runtime/style.d.ts +55 -0
- package/dist/runtime/style.d.ts.map +1 -0
- package/dist/runtime/style.js +143 -0
- package/dist/themes/borders.d.ts +10 -0
- package/dist/themes/borders.d.ts.map +1 -0
- package/dist/themes/borders.js +88 -0
- package/dist/themes/builtin.d.ts +31 -0
- package/dist/themes/builtin.d.ts.map +1 -0
- package/dist/themes/builtin.js +291 -0
- package/dist/themes/glyphs.d.ts +15 -0
- package/dist/themes/glyphs.d.ts.map +1 -0
- package/dist/themes/glyphs.js +97 -0
- package/dist/themes/index.d.ts +5 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +4 -0
- package/dist/themes/registry.d.ts +20 -0
- package/dist/themes/registry.d.ts.map +1 -0
- package/dist/themes/registry.js +204 -0
- package/dist/types/adapter.d.ts +38 -0
- package/dist/types/adapter.d.ts.map +1 -0
- package/dist/types/adapter.js +1 -0
- package/dist/types/animation.d.ts +31 -0
- package/dist/types/animation.d.ts.map +1 -0
- package/dist/types/animation.js +1 -0
- package/dist/types/app.d.ts +148 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +1 -0
- package/dist/types/async.d.ts +30 -0
- package/dist/types/async.d.ts.map +1 -0
- package/dist/types/async.js +1 -0
- package/dist/types/capabilities.d.ts +44 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +33 -0
- package/dist/types/cells.d.ts +72 -0
- package/dist/types/cells.d.ts.map +1 -0
- package/dist/types/cells.js +10 -0
- package/dist/types/command.d.ts +127 -0
- package/dist/types/command.d.ts.map +1 -0
- package/dist/types/command.js +1 -0
- package/dist/types/component-registry.d.ts +77 -0
- package/dist/types/component-registry.d.ts.map +1 -0
- package/dist/types/component-registry.js +1 -0
- package/dist/types/disposable.d.ts +8 -0
- package/dist/types/disposable.d.ts.map +1 -0
- package/dist/types/disposable.js +1 -0
- package/dist/types/focus.d.ts +72 -0
- package/dist/types/focus.d.ts.map +1 -0
- package/dist/types/focus.js +1 -0
- package/dist/types/geometry.d.ts +28 -0
- package/dist/types/geometry.d.ts.map +1 -0
- package/dist/types/geometry.js +14 -0
- package/dist/types/graph.d.ts +129 -0
- package/dist/types/graph.d.ts.map +1 -0
- package/dist/types/graph.js +31 -0
- package/dist/types/i18n.d.ts +23 -0
- package/dist/types/i18n.d.ts.map +1 -0
- package/dist/types/i18n.js +1 -0
- package/dist/types/index.d.ts +32 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +31 -0
- package/dist/types/input.d.ts +65 -0
- package/dist/types/input.d.ts.map +1 -0
- package/dist/types/input.js +1 -0
- package/dist/types/keybinding.d.ts +49 -0
- package/dist/types/keybinding.d.ts.map +1 -0
- package/dist/types/keybinding.js +1 -0
- package/dist/types/layer.d.ts +54 -0
- package/dist/types/layer.d.ts.map +1 -0
- package/dist/types/layer.js +1 -0
- package/dist/types/manifest.d.ts +114 -0
- package/dist/types/manifest.d.ts.map +1 -0
- package/dist/types/manifest.js +1 -0
- package/dist/types/markdown.d.ts +58 -0
- package/dist/types/markdown.d.ts.map +1 -0
- package/dist/types/markdown.js +1 -0
- package/dist/types/navigation.d.ts +40 -0
- package/dist/types/navigation.d.ts.map +1 -0
- package/dist/types/navigation.js +1 -0
- package/dist/types/render.d.ts +72 -0
- package/dist/types/render.d.ts.map +1 -0
- package/dist/types/render.js +1 -0
- package/dist/types/resource.d.ts +170 -0
- package/dist/types/resource.d.ts.map +1 -0
- package/dist/types/resource.js +1 -0
- package/dist/types/services.d.ts +24 -0
- package/dist/types/services.d.ts.map +1 -0
- package/dist/types/services.js +3 -0
- package/dist/types/shell.d.ts +32 -0
- package/dist/types/shell.d.ts.map +1 -0
- package/dist/types/shell.js +1 -0
- package/dist/types/store.d.ts +124 -0
- package/dist/types/store.d.ts.map +1 -0
- package/dist/types/store.js +1 -0
- package/dist/types/stream.d.ts +18 -0
- package/dist/types/stream.d.ts.map +1 -0
- package/dist/types/stream.js +1 -0
- package/dist/types/style.d.ts +166 -0
- package/dist/types/style.d.ts.map +1 -0
- package/dist/types/style.js +1 -0
- package/dist/types/surface.d.ts +97 -0
- package/dist/types/surface.d.ts.map +1 -0
- package/dist/types/surface.js +1 -0
- package/dist/types/syntax.d.ts +68 -0
- package/dist/types/syntax.d.ts.map +1 -0
- package/dist/types/syntax.js +5 -0
- package/dist/types/terminal.d.ts +52 -0
- package/dist/types/terminal.d.ts.map +1 -0
- package/dist/types/terminal.js +1 -0
- package/dist/types/theme.d.ts +117 -0
- package/dist/types/theme.d.ts.map +1 -0
- package/dist/types/theme.js +1 -0
- package/dist/types/when.d.ts +19 -0
- package/dist/types/when.d.ts.map +1 -0
- package/dist/types/when.js +1 -0
- package/dist/ui/primitives.d.ts +56 -0
- package/dist/ui/primitives.d.ts.map +1 -0
- package/dist/ui/primitives.js +108 -0
- package/dist/ui/screen.d.ts +23 -0
- package/dist/ui/screen.d.ts.map +1 -0
- package/dist/ui/screen.js +18 -0
- package/dist/util/disposable.d.ts +6 -0
- package/dist/util/disposable.d.ts.map +1 -0
- package/dist/util/disposable.js +49 -0
- package/dist/util/markdown.d.ts +24 -0
- package/dist/util/markdown.d.ts.map +1 -0
- package/dist/util/markdown.js +220 -0
- package/dist/util/paths.d.ts +47 -0
- package/dist/util/paths.d.ts.map +1 -0
- package/dist/util/paths.js +134 -0
- package/dist/util/stream.d.ts +32 -0
- package/dist/util/stream.d.ts.map +1 -0
- package/dist/util/stream.js +206 -0
- package/dist/util/text.d.ts +65 -0
- package/dist/util/text.d.ts.map +1 -0
- package/dist/util/text.js +419 -0
- package/package.json +70 -0
- package/src/adapters/index.ts +11 -0
- package/src/app/app.ts +1096 -0
- package/src/core/animation.ts +144 -0
- package/src/core/clipboard.ts +40 -0
- package/src/core/commands.ts +169 -0
- package/src/core/components.ts +91 -0
- package/src/core/events.ts +95 -0
- package/src/core/focus.ts +358 -0
- package/src/core/i18n.ts +107 -0
- package/src/core/keybindings.ts +184 -0
- package/src/core/layers.ts +94 -0
- package/src/core/manifest.ts +84 -0
- package/src/core/navigation.ts +135 -0
- package/src/core/resources.ts +362 -0
- package/src/core/services.ts +69 -0
- package/src/core/store.ts +640 -0
- package/src/core/surfaces.ts +292 -0
- package/src/core/syntax.ts +200 -0
- package/src/core/when.ts +238 -0
- package/src/index.ts +76 -0
- package/src/jsx/factory.ts +124 -0
- package/src/jsx/intrinsics.ts +99 -0
- package/src/jsx/jsx-dev-runtime.ts +23 -0
- package/src/jsx/jsx-runtime.ts +76 -0
- package/src/render/buffer.ts +318 -0
- package/src/render/color.ts +180 -0
- package/src/render/diff.ts +99 -0
- package/src/render/layout.ts +764 -0
- package/src/render/static.ts +290 -0
- package/src/runtime/bindings.ts +150 -0
- package/src/runtime/hooks.ts +1057 -0
- package/src/runtime/instance.ts +284 -0
- package/src/runtime/paint.ts +737 -0
- package/src/runtime/reconcile.ts +335 -0
- package/src/runtime/runtime.ts +47 -0
- package/src/runtime/style.ts +205 -0
- package/src/themes/borders.ts +95 -0
- package/src/themes/builtin.ts +301 -0
- package/src/themes/glyphs.ts +101 -0
- package/src/themes/index.ts +4 -0
- package/src/themes/registry.ts +224 -0
- package/src/types/adapter.ts +41 -0
- package/src/types/animation.ts +34 -0
- package/src/types/app.ts +149 -0
- package/src/types/async.ts +35 -0
- package/src/types/capabilities.ts +79 -0
- package/src/types/cells.ts +79 -0
- package/src/types/command.ts +139 -0
- package/src/types/component-registry.ts +82 -0
- package/src/types/disposable.ts +8 -0
- package/src/types/focus.ts +77 -0
- package/src/types/geometry.ts +50 -0
- package/src/types/graph.ts +174 -0
- package/src/types/i18n.ts +25 -0
- package/src/types/index.ts +31 -0
- package/src/types/input.ts +81 -0
- package/src/types/keybinding.ts +51 -0
- package/src/types/layer.ts +46 -0
- package/src/types/manifest.ts +101 -0
- package/src/types/markdown.ts +47 -0
- package/src/types/navigation.ts +42 -0
- package/src/types/render.ts +86 -0
- package/src/types/resource.ts +185 -0
- package/src/types/services.ts +28 -0
- package/src/types/shell.ts +30 -0
- package/src/types/store.ts +148 -0
- package/src/types/stream.ts +24 -0
- package/src/types/style.ts +205 -0
- package/src/types/surface.ts +119 -0
- package/src/types/syntax.ts +93 -0
- package/src/types/terminal.ts +58 -0
- package/src/types/theme.ts +121 -0
- package/src/types/when.ts +21 -0
- package/src/ui/primitives.ts +118 -0
- package/src/ui/screen.ts +41 -0
- package/src/util/disposable.ts +49 -0
- package/src/util/markdown.ts +225 -0
- package/src/util/paths.ts +138 -0
- package/src/util/stream.ts +213 -0
- package/src/util/text.ts +428 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
import { toDisposable } from '../util/disposable.js';
|
|
2
|
+
import { ancestorKeys, hasWildcard, isDescendantKey, matchKey, pathKey, PathError, } from '../util/paths.js';
|
|
3
|
+
/**
|
|
4
|
+
* The store is one tree, and it is the only place state lives. A component
|
|
5
|
+
* that keeps a copy in its own state has created a second answer to a question
|
|
6
|
+
* the store already answers.
|
|
7
|
+
*/
|
|
8
|
+
export class Store {
|
|
9
|
+
root = {};
|
|
10
|
+
subs = new Set();
|
|
11
|
+
computedByKey = new Map();
|
|
12
|
+
computedDeps = new Map();
|
|
13
|
+
providers = new Map();
|
|
14
|
+
schemas = new Map();
|
|
15
|
+
persistence = new Set();
|
|
16
|
+
persistTimers = new Map();
|
|
17
|
+
batchDepth = 0;
|
|
18
|
+
pending = new Map();
|
|
19
|
+
disposed = false;
|
|
20
|
+
/** Thrown-away errors from listeners would hide bugs; collect and report. */
|
|
21
|
+
onError = (err, context) => {
|
|
22
|
+
console.error(`[textui/store] ${context}`, err);
|
|
23
|
+
};
|
|
24
|
+
// ---------------------------------------------------------------- reading
|
|
25
|
+
get(path) {
|
|
26
|
+
const key = pathKey(path);
|
|
27
|
+
this.touchProvider(key);
|
|
28
|
+
return this.readKey(key);
|
|
29
|
+
}
|
|
30
|
+
read(path, fallback) {
|
|
31
|
+
const v = this.get(path);
|
|
32
|
+
return v === undefined ? fallback : v;
|
|
33
|
+
}
|
|
34
|
+
has(path) {
|
|
35
|
+
return this.readKey(pathKey(path)) !== undefined;
|
|
36
|
+
}
|
|
37
|
+
readKey(key) {
|
|
38
|
+
if (key === '')
|
|
39
|
+
return this.root;
|
|
40
|
+
const segs = key.split('/');
|
|
41
|
+
let node = this.root;
|
|
42
|
+
for (const seg of segs) {
|
|
43
|
+
if (node === null || node === undefined)
|
|
44
|
+
return undefined;
|
|
45
|
+
if (Array.isArray(node)) {
|
|
46
|
+
const i = Number(seg);
|
|
47
|
+
if (!Number.isInteger(i))
|
|
48
|
+
return undefined;
|
|
49
|
+
node = node[i];
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (typeof node !== 'object')
|
|
53
|
+
return undefined;
|
|
54
|
+
node = node[seg];
|
|
55
|
+
}
|
|
56
|
+
return node;
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------- writing
|
|
59
|
+
set(path, value) {
|
|
60
|
+
if (hasWildcard(path)) {
|
|
61
|
+
throw new PathError('wildcards are legal in subscriptions only', path);
|
|
62
|
+
}
|
|
63
|
+
const key = pathKey(path);
|
|
64
|
+
this.writeKey(key, value);
|
|
65
|
+
}
|
|
66
|
+
update(path, fn) {
|
|
67
|
+
this.set(path, fn(this.get(path)));
|
|
68
|
+
}
|
|
69
|
+
patch(path, partial) {
|
|
70
|
+
const current = this.get(path);
|
|
71
|
+
const base = current && typeof current === 'object' && !Array.isArray(current) ? current : {};
|
|
72
|
+
this.set(path, { ...base, ...partial });
|
|
73
|
+
}
|
|
74
|
+
patchMany(entries) {
|
|
75
|
+
this.batch(() => {
|
|
76
|
+
for (const [path, value] of Object.entries(entries)) {
|
|
77
|
+
this.set(path, value);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
delete(path) {
|
|
82
|
+
const key = pathKey(path);
|
|
83
|
+
const segs = key.split('/');
|
|
84
|
+
const last = segs.pop();
|
|
85
|
+
const parent = segs.length === 0 ? this.root : this.readKey(segs.join('/'));
|
|
86
|
+
if (parent === null || typeof parent !== 'object')
|
|
87
|
+
return;
|
|
88
|
+
const previous = parent[last];
|
|
89
|
+
if (previous === undefined && !(last in parent))
|
|
90
|
+
return;
|
|
91
|
+
if (Array.isArray(parent))
|
|
92
|
+
parent.splice(Number(last), 1);
|
|
93
|
+
else
|
|
94
|
+
delete parent[last];
|
|
95
|
+
this.enqueue({ path: `$/${key}`, value: undefined, previous });
|
|
96
|
+
this.flushIfIdle();
|
|
97
|
+
}
|
|
98
|
+
writeKey(key, value) {
|
|
99
|
+
if (this.disposed)
|
|
100
|
+
return;
|
|
101
|
+
if (key === '')
|
|
102
|
+
throw new PathError('cannot write the store root', '$/');
|
|
103
|
+
const schema = this.schemas.get(key);
|
|
104
|
+
if (schema) {
|
|
105
|
+
const problem = schema.validate(value);
|
|
106
|
+
if (problem)
|
|
107
|
+
throw new PathError(`schema rejected value (${problem})`, `$/${key}`);
|
|
108
|
+
}
|
|
109
|
+
const segs = key.split('/');
|
|
110
|
+
const last = segs.pop();
|
|
111
|
+
let node = this.root;
|
|
112
|
+
for (const seg of segs) {
|
|
113
|
+
let next = node[seg];
|
|
114
|
+
if (next === null || typeof next !== 'object') {
|
|
115
|
+
next = {};
|
|
116
|
+
node[seg] = next;
|
|
117
|
+
}
|
|
118
|
+
node = next;
|
|
119
|
+
}
|
|
120
|
+
const previous = node[last];
|
|
121
|
+
if (previous === value)
|
|
122
|
+
return;
|
|
123
|
+
node[last] = value;
|
|
124
|
+
this.enqueue({ path: `$/${key}`, value, previous });
|
|
125
|
+
this.flushIfIdle();
|
|
126
|
+
}
|
|
127
|
+
// --------------------------------------------------------------- batching
|
|
128
|
+
batch(fn) {
|
|
129
|
+
this.batchDepth++;
|
|
130
|
+
try {
|
|
131
|
+
return fn();
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
this.batchDepth--;
|
|
135
|
+
this.flushIfIdle();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
enqueue(change) {
|
|
139
|
+
const key = pathKey(change.path);
|
|
140
|
+
const existing = this.pending.get(key);
|
|
141
|
+
// Keep the oldest `previous` so a batch reports one net change.
|
|
142
|
+
this.pending.set(key, existing ? { ...change, previous: existing.previous } : change);
|
|
143
|
+
}
|
|
144
|
+
flushIfIdle() {
|
|
145
|
+
if (this.batchDepth > 0 || this.pending.size === 0)
|
|
146
|
+
return;
|
|
147
|
+
// Recomputing may enqueue more; drain until quiet, with a runaway guard.
|
|
148
|
+
let rounds = 0;
|
|
149
|
+
while (this.pending.size > 0) {
|
|
150
|
+
if (++rounds > 50) {
|
|
151
|
+
this.onError(new Error('computed paths did not settle after 50 rounds'), 'flush');
|
|
152
|
+
this.pending.clear();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
const changes = [...this.pending.values()];
|
|
156
|
+
this.pending.clear();
|
|
157
|
+
this.batchDepth++;
|
|
158
|
+
try {
|
|
159
|
+
for (const change of changes)
|
|
160
|
+
this.recomputeDependents(pathKey(change.path));
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
this.batchDepth--;
|
|
164
|
+
}
|
|
165
|
+
for (const change of changes)
|
|
166
|
+
this.notify(change);
|
|
167
|
+
for (const change of changes)
|
|
168
|
+
this.schedulePersist(pathKey(change.path));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
notify(change) {
|
|
172
|
+
const key = pathKey(change.path);
|
|
173
|
+
for (const sub of [...this.subs]) {
|
|
174
|
+
if (!this.subMatches(sub, key))
|
|
175
|
+
continue;
|
|
176
|
+
try {
|
|
177
|
+
sub.fn(this.readKey(sub.wildcard ? key : sub.key), change);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
this.onError(err, `subscriber of $/${sub.key}`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
subMatches(sub, changedKey) {
|
|
185
|
+
if (sub.wildcard)
|
|
186
|
+
return matchKey(changedKey, sub.key, sub.subtree);
|
|
187
|
+
if (sub.key === changedKey)
|
|
188
|
+
return true;
|
|
189
|
+
// A write below an exact subscription still changes that object's contents.
|
|
190
|
+
if (isDescendantKey(changedKey, sub.key))
|
|
191
|
+
return true;
|
|
192
|
+
// A write above it may have replaced the subtree the subscriber reads.
|
|
193
|
+
if (isDescendantKey(sub.key, changedKey))
|
|
194
|
+
return true;
|
|
195
|
+
return sub.subtree && ancestorKeys(changedKey).includes(sub.key);
|
|
196
|
+
}
|
|
197
|
+
// ---------------------------------------------------------- subscriptions
|
|
198
|
+
subscribe(path, fn, options = {}) {
|
|
199
|
+
const key = pathKey(path);
|
|
200
|
+
const sub = {
|
|
201
|
+
key,
|
|
202
|
+
subtree: options.subtree ?? false,
|
|
203
|
+
wildcard: hasWildcard(key),
|
|
204
|
+
fn,
|
|
205
|
+
};
|
|
206
|
+
this.subs.add(sub);
|
|
207
|
+
this.touchProvider(key);
|
|
208
|
+
if (options.immediate) {
|
|
209
|
+
try {
|
|
210
|
+
const value = this.readKey(key);
|
|
211
|
+
fn(value, { path, value, previous: undefined });
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
this.onError(err, `immediate subscriber of ${path}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return toDisposable(() => {
|
|
218
|
+
this.subs.delete(sub);
|
|
219
|
+
this.maybeUnloadProvider(key);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
subscriberCount(scope) {
|
|
223
|
+
let n = 0;
|
|
224
|
+
for (const sub of this.subs) {
|
|
225
|
+
if (sub.key === scope || sub.key.startsWith(scope + '/'))
|
|
226
|
+
n++;
|
|
227
|
+
}
|
|
228
|
+
return n;
|
|
229
|
+
}
|
|
230
|
+
clearScope(scope) {
|
|
231
|
+
const key = pathKey(scope.startsWith('$/') ? scope : `$/${scope}`);
|
|
232
|
+
const previous = this.readKey(key);
|
|
233
|
+
if (previous === undefined)
|
|
234
|
+
return;
|
|
235
|
+
const segs = key.split('/');
|
|
236
|
+
const last = segs.pop();
|
|
237
|
+
const parent = segs.length === 0 ? this.root : this.readKey(segs.join('/'));
|
|
238
|
+
if (parent && typeof parent === 'object') {
|
|
239
|
+
delete parent[last];
|
|
240
|
+
}
|
|
241
|
+
this.enqueue({ path: `$/${key}`, value: undefined, previous });
|
|
242
|
+
this.flushIfIdle();
|
|
243
|
+
}
|
|
244
|
+
// -------------------------------------------------------------- computed
|
|
245
|
+
computed(path, def) {
|
|
246
|
+
const key = pathKey(path);
|
|
247
|
+
const deps = def.from.map((p) => pathKey(p));
|
|
248
|
+
const select = typeof def.select === 'string'
|
|
249
|
+
? compileSelect(def.select, def.from)
|
|
250
|
+
: def.select;
|
|
251
|
+
const entry = {
|
|
252
|
+
key,
|
|
253
|
+
deps,
|
|
254
|
+
compute: () => {
|
|
255
|
+
const values = {};
|
|
256
|
+
for (let i = 0; i < def.from.length; i++) {
|
|
257
|
+
const p = def.from[i];
|
|
258
|
+
values[p] = this.readKey(deps[i]);
|
|
259
|
+
}
|
|
260
|
+
return select(values);
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
this.computedByKey.set(key, entry);
|
|
264
|
+
for (const dep of deps) {
|
|
265
|
+
let set = this.computedDeps.get(dep);
|
|
266
|
+
if (!set) {
|
|
267
|
+
set = new Set();
|
|
268
|
+
this.computedDeps.set(dep, set);
|
|
269
|
+
}
|
|
270
|
+
set.add(key);
|
|
271
|
+
}
|
|
272
|
+
this.recompute(entry);
|
|
273
|
+
return toDisposable(() => {
|
|
274
|
+
this.computedByKey.delete(key);
|
|
275
|
+
for (const dep of deps)
|
|
276
|
+
this.computedDeps.get(dep)?.delete(key);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
recompute(entry) {
|
|
280
|
+
try {
|
|
281
|
+
this.writeKey(entry.key, entry.compute());
|
|
282
|
+
}
|
|
283
|
+
catch (err) {
|
|
284
|
+
this.onError(err, `computed $/${entry.key}`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
recomputeDependents(changedKey) {
|
|
288
|
+
for (const [dep, keys] of this.computedDeps) {
|
|
289
|
+
const affected = dep === changedKey ||
|
|
290
|
+
isDescendantKey(changedKey, dep) ||
|
|
291
|
+
isDescendantKey(dep, changedKey);
|
|
292
|
+
if (!affected)
|
|
293
|
+
continue;
|
|
294
|
+
for (const key of keys) {
|
|
295
|
+
const entry = this.computedByKey.get(key);
|
|
296
|
+
if (entry)
|
|
297
|
+
this.recompute(entry);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// ------------------------------------------------------------ collections
|
|
302
|
+
collection(path) {
|
|
303
|
+
const read = () => {
|
|
304
|
+
const v = this.get(path);
|
|
305
|
+
return Array.isArray(v) ? v : [];
|
|
306
|
+
};
|
|
307
|
+
const write = (items) => this.set(path, items);
|
|
308
|
+
return {
|
|
309
|
+
all: () => read(),
|
|
310
|
+
at: (index) => read()[index],
|
|
311
|
+
find: (pred) => read().find(pred),
|
|
312
|
+
append: (...items) => write([...read(), ...items]),
|
|
313
|
+
prepend: (...items) => write([...items, ...read()]),
|
|
314
|
+
insertAt: (index, ...items) => {
|
|
315
|
+
const next = read();
|
|
316
|
+
next.splice(index, 0, ...items);
|
|
317
|
+
write(next);
|
|
318
|
+
},
|
|
319
|
+
removeAt: (index) => {
|
|
320
|
+
const next = read();
|
|
321
|
+
if (index < 0 || index >= next.length)
|
|
322
|
+
return;
|
|
323
|
+
next.splice(index, 1);
|
|
324
|
+
write(next);
|
|
325
|
+
},
|
|
326
|
+
remove: (pred) => {
|
|
327
|
+
const items = read();
|
|
328
|
+
const kept = items.filter((item, i) => !pred(item, i));
|
|
329
|
+
const removed = items.length - kept.length;
|
|
330
|
+
if (removed > 0)
|
|
331
|
+
write(kept);
|
|
332
|
+
return removed;
|
|
333
|
+
},
|
|
334
|
+
update: (pred, patch) => {
|
|
335
|
+
const items = read();
|
|
336
|
+
let changed = 0;
|
|
337
|
+
const next = items.map((item, i) => {
|
|
338
|
+
if (!pred(item, i))
|
|
339
|
+
return item;
|
|
340
|
+
changed++;
|
|
341
|
+
return typeof patch === 'function'
|
|
342
|
+
? patch(item)
|
|
343
|
+
: { ...item, ...patch };
|
|
344
|
+
});
|
|
345
|
+
if (changed > 0)
|
|
346
|
+
write(next);
|
|
347
|
+
return changed;
|
|
348
|
+
},
|
|
349
|
+
replace: (items) => write([...items]),
|
|
350
|
+
filter: (pred) => read().filter(pred),
|
|
351
|
+
clear: () => write([]),
|
|
352
|
+
cap: (n) => {
|
|
353
|
+
const items = read();
|
|
354
|
+
if (items.length > n)
|
|
355
|
+
write(items.slice(items.length - n));
|
|
356
|
+
},
|
|
357
|
+
get length() {
|
|
358
|
+
return read().length;
|
|
359
|
+
},
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
// -------------------------------------------------------------- providers
|
|
363
|
+
registerDataProvider(def) {
|
|
364
|
+
const key = pathKey(def.namespace.startsWith('$/') ? def.namespace : `$/${def.namespace}`);
|
|
365
|
+
const entry = { def, loaded: false, loading: null, unloadTimer: null };
|
|
366
|
+
this.providers.set(key, entry);
|
|
367
|
+
if (def.load === 'eager')
|
|
368
|
+
void this.loadProvider(key);
|
|
369
|
+
return toDisposable(() => {
|
|
370
|
+
if (entry.unloadTimer)
|
|
371
|
+
clearTimeout(entry.unloadTimer);
|
|
372
|
+
void def.provider.unload?.(this);
|
|
373
|
+
this.providers.delete(key);
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
listDataProviders() {
|
|
377
|
+
return [...this.providers.values()].map((e) => e.def);
|
|
378
|
+
}
|
|
379
|
+
/** A read or subscribe below a provider's namespace is what loads it. */
|
|
380
|
+
touchProvider(key) {
|
|
381
|
+
for (const [ns, entry] of this.providers) {
|
|
382
|
+
if (key !== ns && !isDescendantKey(key, ns))
|
|
383
|
+
continue;
|
|
384
|
+
if (entry.unloadTimer) {
|
|
385
|
+
clearTimeout(entry.unloadTimer);
|
|
386
|
+
entry.unloadTimer = null;
|
|
387
|
+
}
|
|
388
|
+
if (!entry.loaded && !entry.loading)
|
|
389
|
+
void this.loadProvider(ns);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
async loadProvider(ns) {
|
|
393
|
+
const entry = this.providers.get(ns);
|
|
394
|
+
if (!entry || entry.loaded || entry.loading)
|
|
395
|
+
return;
|
|
396
|
+
const run = (async () => {
|
|
397
|
+
try {
|
|
398
|
+
await entry.def.provider.load(this);
|
|
399
|
+
entry.loaded = true;
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
this.onError(err, `data provider ${entry.def.namespace}`);
|
|
403
|
+
}
|
|
404
|
+
finally {
|
|
405
|
+
entry.loading = null;
|
|
406
|
+
}
|
|
407
|
+
})();
|
|
408
|
+
entry.loading = run;
|
|
409
|
+
await run;
|
|
410
|
+
}
|
|
411
|
+
maybeUnloadProvider(key) {
|
|
412
|
+
for (const [ns, entry] of this.providers) {
|
|
413
|
+
if (key !== ns && !isDescendantKey(key, ns))
|
|
414
|
+
continue;
|
|
415
|
+
const { unloadAfter } = entry.def;
|
|
416
|
+
if (!unloadAfter || !entry.loaded)
|
|
417
|
+
continue;
|
|
418
|
+
if (this.subscriberCount(ns) > 0)
|
|
419
|
+
continue;
|
|
420
|
+
if (entry.unloadTimer)
|
|
421
|
+
clearTimeout(entry.unloadTimer);
|
|
422
|
+
entry.unloadTimer = setTimeout(() => {
|
|
423
|
+
entry.unloadTimer = null;
|
|
424
|
+
if (this.subscriberCount(ns) > 0)
|
|
425
|
+
return;
|
|
426
|
+
void entry.def.provider.unload?.(this);
|
|
427
|
+
entry.loaded = false;
|
|
428
|
+
}, unloadAfter);
|
|
429
|
+
entry.unloadTimer.unref?.();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// ---------------------------------------------------- schemas, persistence
|
|
433
|
+
registerSchema(schema) {
|
|
434
|
+
const key = pathKey(schema.path);
|
|
435
|
+
this.schemas.set(key, schema);
|
|
436
|
+
if (schema.initial !== undefined && this.readKey(key) === undefined) {
|
|
437
|
+
this.writeKey(key, schema.initial);
|
|
438
|
+
}
|
|
439
|
+
return toDisposable(() => this.schemas.delete(key));
|
|
440
|
+
}
|
|
441
|
+
registerPersistence(adapter) {
|
|
442
|
+
this.persistence.add(adapter);
|
|
443
|
+
return toDisposable(() => {
|
|
444
|
+
const timer = this.persistTimers.get(adapter.id);
|
|
445
|
+
if (timer)
|
|
446
|
+
clearTimeout(timer);
|
|
447
|
+
this.persistTimers.delete(adapter.id);
|
|
448
|
+
this.persistence.delete(adapter);
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
async hydrate() {
|
|
452
|
+
for (const adapter of this.persistence) {
|
|
453
|
+
try {
|
|
454
|
+
const entries = await adapter.read();
|
|
455
|
+
this.batch(() => {
|
|
456
|
+
for (const [path, value] of Object.entries(entries)) {
|
|
457
|
+
this.set((path.startsWith('$/') ? path : `$/${path}`), value);
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
catch (err) {
|
|
462
|
+
this.onError(err, `persistence adapter ${adapter.id}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
schedulePersist(changedKey) {
|
|
467
|
+
for (const adapter of this.persistence) {
|
|
468
|
+
const owns = adapter.paths.some((p) => {
|
|
469
|
+
const key = adapterKey(p);
|
|
470
|
+
return p.endsWith('/')
|
|
471
|
+
? changedKey === key || isDescendantKey(changedKey, key)
|
|
472
|
+
: changedKey === key;
|
|
473
|
+
});
|
|
474
|
+
if (!owns)
|
|
475
|
+
continue;
|
|
476
|
+
const existing = this.persistTimers.get(adapter.id);
|
|
477
|
+
if (existing)
|
|
478
|
+
clearTimeout(existing);
|
|
479
|
+
const timer = setTimeout(() => {
|
|
480
|
+
this.persistTimers.delete(adapter.id);
|
|
481
|
+
const entries = {};
|
|
482
|
+
for (const p of adapter.paths) {
|
|
483
|
+
const key = adapterKey(p);
|
|
484
|
+
entries[`$/${key}`] = this.readKey(key);
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
void adapter.write(entries);
|
|
488
|
+
}
|
|
489
|
+
catch (err) {
|
|
490
|
+
this.onError(err, `persistence adapter ${adapter.id}`);
|
|
491
|
+
}
|
|
492
|
+
}, adapter.debounceMs ?? 250);
|
|
493
|
+
timer.unref?.();
|
|
494
|
+
this.persistTimers.set(adapter.id, timer);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
// --------------------------------------------------------------- snapshot
|
|
498
|
+
snapshot(scope) {
|
|
499
|
+
if (!scope)
|
|
500
|
+
return structuredClone(this.root);
|
|
501
|
+
const key = pathKey(scope.startsWith('$/') ? scope : `$/${scope}`);
|
|
502
|
+
const value = this.readKey(key);
|
|
503
|
+
return value === undefined ? {} : structuredClone({ [key]: value });
|
|
504
|
+
}
|
|
505
|
+
restore(snapshot) {
|
|
506
|
+
this.batch(() => {
|
|
507
|
+
for (const [key, value] of Object.entries(snapshot)) {
|
|
508
|
+
this.set(`$/${pathKey(key.startsWith('$/') ? key : `$/${key}`)}`, value);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
dispose() {
|
|
513
|
+
if (this.disposed)
|
|
514
|
+
return;
|
|
515
|
+
this.disposed = true;
|
|
516
|
+
for (const timer of this.persistTimers.values())
|
|
517
|
+
clearTimeout(timer);
|
|
518
|
+
this.persistTimers.clear();
|
|
519
|
+
for (const entry of this.providers.values()) {
|
|
520
|
+
if (entry.unloadTimer)
|
|
521
|
+
clearTimeout(entry.unloadTimer);
|
|
522
|
+
try {
|
|
523
|
+
void entry.def.provider.unload?.(this);
|
|
524
|
+
}
|
|
525
|
+
catch {
|
|
526
|
+
/* teardown is best effort */
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
this.providers.clear();
|
|
530
|
+
this.subs.clear();
|
|
531
|
+
this.computedByKey.clear();
|
|
532
|
+
this.computedDeps.clear();
|
|
533
|
+
this.root = {};
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* A computed defined as data. Deliberately tiny: `sum`, `count`, `length`,
|
|
538
|
+
* `first`, `join`, or a path reference. Anything more is a function.
|
|
539
|
+
*/
|
|
540
|
+
function compileSelect(expr, from) {
|
|
541
|
+
const [op, arg] = expr.split(':');
|
|
542
|
+
const pick = (values) => values[arg ?? from[0]];
|
|
543
|
+
switch (op) {
|
|
544
|
+
case 'length':
|
|
545
|
+
case 'count':
|
|
546
|
+
return (v) => {
|
|
547
|
+
const x = pick(v);
|
|
548
|
+
return Array.isArray(x) ? x.length : x == null ? 0 : Object.keys(x).length;
|
|
549
|
+
};
|
|
550
|
+
case 'sum':
|
|
551
|
+
return (v) => {
|
|
552
|
+
const x = pick(v);
|
|
553
|
+
return Array.isArray(x) ? x.reduce((a, b) => a + Number(b || 0), 0) : 0;
|
|
554
|
+
};
|
|
555
|
+
case 'first':
|
|
556
|
+
return (v) => {
|
|
557
|
+
const x = pick(v);
|
|
558
|
+
return Array.isArray(x) ? x[0] : undefined;
|
|
559
|
+
};
|
|
560
|
+
case 'last':
|
|
561
|
+
return (v) => {
|
|
562
|
+
const x = pick(v);
|
|
563
|
+
return Array.isArray(x) ? x[x.length - 1] : undefined;
|
|
564
|
+
};
|
|
565
|
+
case 'not':
|
|
566
|
+
return (v) => !pick(v);
|
|
567
|
+
case 'join':
|
|
568
|
+
return (v) => {
|
|
569
|
+
const x = pick(v);
|
|
570
|
+
return Array.isArray(x) ? x.join(arg ?? ', ') : '';
|
|
571
|
+
};
|
|
572
|
+
case 'concat':
|
|
573
|
+
return (v) => from.map((p) => String(v[p] ?? '')).join('');
|
|
574
|
+
default:
|
|
575
|
+
// A bare path reference: `$/a/b`.
|
|
576
|
+
return (v) => v[expr];
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
export function createStore() {
|
|
580
|
+
return new Store();
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* The key an adapter's path stands for.
|
|
584
|
+
*
|
|
585
|
+
* A trailing slash means "and everything under it", so it has to come off
|
|
586
|
+
* before the path is turned into a key: `segments` keeps the empty piece it
|
|
587
|
+
* leaves behind, so `$/a/b/` became the key `a/b/` and matched neither `a/b`
|
|
588
|
+
* nor anything below it. Every subtree adapter ever registered was inert.
|
|
589
|
+
*/
|
|
590
|
+
function adapterKey(path) {
|
|
591
|
+
const bare = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
592
|
+
return pathKey(bare.startsWith('$/') ? bare : `$/${bare}`);
|
|
593
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { LayoutDefinition, LayoutRegistry, Mount, SurfaceName, SurfaceRegistry, SurfaceState } from '../types/surface.js';
|
|
2
|
+
import type { ShellDefinition, ShellRegistry } from '../types/shell.js';
|
|
3
|
+
import type { ReactiveStore } from '../types/store.js';
|
|
4
|
+
import type { WhenEngine } from '../types/when.js';
|
|
5
|
+
import type { ResourceRegistry } from '../types/resource.js';
|
|
6
|
+
import type { Disposable } from '../types/disposable.js';
|
|
7
|
+
/**
|
|
8
|
+
* The surfaces the shipped shells use.
|
|
9
|
+
*
|
|
10
|
+
* A convenience, not a constraint: it is what gets seeded at boot so the
|
|
11
|
+
* built-in shells have state to read. An application is free to mount onto a
|
|
12
|
+
* name that is not here, and nothing checks.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SURFACE_NAMES: SurfaceName[];
|
|
15
|
+
/**
|
|
16
|
+
* Surfaces, mounts and their state.
|
|
17
|
+
*
|
|
18
|
+
* A surface is whatever the application calls a region. The runtime keeps
|
|
19
|
+
* state per name and never validates one: mounting onto `lateral1` works
|
|
20
|
+
* exactly as well as mounting onto `sidebar`, and needs no registration. The
|
|
21
|
+
* shipped names are seeded at boot only so the shipped shells have something
|
|
22
|
+
* to read.
|
|
23
|
+
*
|
|
24
|
+
* Which layout a surface uses is store state rather than code, which is what
|
|
25
|
+
* makes it switchable at runtime and persistable per user.
|
|
26
|
+
*/
|
|
27
|
+
export declare class Surfaces implements SurfaceRegistry {
|
|
28
|
+
private deps;
|
|
29
|
+
private byKey;
|
|
30
|
+
/** Subscriptions to the paths a mount's `when` clause reads. */
|
|
31
|
+
private conditions;
|
|
32
|
+
constructor(deps: {
|
|
33
|
+
store: ReactiveStore;
|
|
34
|
+
when: WhenEngine;
|
|
35
|
+
resources(): ResourceRegistry;
|
|
36
|
+
onChange(): void;
|
|
37
|
+
});
|
|
38
|
+
private id;
|
|
39
|
+
private publish;
|
|
40
|
+
open(mount: Mount): Disposable;
|
|
41
|
+
close(surface: SurfaceName, key: string): void;
|
|
42
|
+
closeAll(surface: SurfaceName): void;
|
|
43
|
+
get(surface: SurfaceName, key: string): Mount | undefined;
|
|
44
|
+
private watchCondition;
|
|
45
|
+
private unwatchCondition;
|
|
46
|
+
/** Every mount on a surface, conditional or not. */
|
|
47
|
+
all(surface: SurfaceName): Mount[];
|
|
48
|
+
/** Mounts whose `when` clause passes, in order. */
|
|
49
|
+
mounts(surface: SurfaceName): Mount[];
|
|
50
|
+
activate(surface: SurfaceName, key: string): void;
|
|
51
|
+
state(surface: SurfaceName): SurfaceState;
|
|
52
|
+
setState(surface: SurfaceName, patch: Partial<SurfaceState>): void;
|
|
53
|
+
/**
|
|
54
|
+
* Resource-level open: ask the registry which viewer handles this kind, then
|
|
55
|
+
* mount it. The caller never names a component, which is what lets a new
|
|
56
|
+
* resource type arrive with its own viewer and work everywhere at once.
|
|
57
|
+
*/
|
|
58
|
+
openResource(uri: string, options?: {
|
|
59
|
+
surface?: SurfaceName;
|
|
60
|
+
viewerId?: string;
|
|
61
|
+
mode?: 'view' | 'edit';
|
|
62
|
+
}): Promise<Disposable | null>;
|
|
63
|
+
}
|
|
64
|
+
export declare class Layouts implements LayoutRegistry {
|
|
65
|
+
private defs;
|
|
66
|
+
register(def: LayoutDefinition): Disposable;
|
|
67
|
+
get(name: string): LayoutDefinition | undefined;
|
|
68
|
+
list(surface?: SurfaceName): LayoutDefinition[];
|
|
69
|
+
}
|
|
70
|
+
export declare class Shells implements ShellRegistry {
|
|
71
|
+
private defs;
|
|
72
|
+
register(def: ShellDefinition): Disposable;
|
|
73
|
+
get(id: string): ShellDefinition | undefined;
|
|
74
|
+
list(): ShellDefinition[];
|
|
75
|
+
/** Shells that fit, largest minimum first - the richest one that works. */
|
|
76
|
+
suitable(width: number, height: number): ShellDefinition[];
|
|
77
|
+
}
|
|
78
|
+
export declare function createSurfaces(deps: ConstructorParameters<typeof Surfaces>[0]): Surfaces;
|
|
79
|
+
export declare function createLayouts(): Layouts;
|
|
80
|
+
export declare function createShells(): Shells;
|
|
81
|
+
//# sourceMappingURL=surfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surfaces.d.ts","sourceRoot":"","sources":["../../src/core/surfaces.ts"],"names":[],"mappings":"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"}
|