@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,284 @@
|
|
|
1
|
+
import type { BindingPath, ComponentNode } from '../types/graph.js';
|
|
2
|
+
import type { ComponentDefinition } from '../types/component-registry.js';
|
|
3
|
+
import type { Disposable } from '../types/disposable.js';
|
|
4
|
+
import type { FunctionComponent, HostComponent, RenderOutput } from '../types/render.js';
|
|
5
|
+
import type { LayoutBox } from '../render/layout.js';
|
|
6
|
+
import type { Rect, Size } from '../types/geometry.js';
|
|
7
|
+
import type { Runtime } from './runtime.js';
|
|
8
|
+
import { isComponentNode } from '../types/graph.js';
|
|
9
|
+
import { ZERO_EDGES } from '../types/geometry.js';
|
|
10
|
+
import { isTemplateChildren, resolveProps, type ResolveContext } from './bindings.js';
|
|
11
|
+
import { nodeFunction } from '../jsx/factory.js';
|
|
12
|
+
import { joinPath } from '../util/paths.js';
|
|
13
|
+
|
|
14
|
+
export type HookSlot = {
|
|
15
|
+
kind: string;
|
|
16
|
+
value: unknown;
|
|
17
|
+
deps?: unknown[];
|
|
18
|
+
cleanup?: (() => void) | void;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type InstanceKind = 'function' | 'host' | 'template' | 'missing';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* One mounted node.
|
|
25
|
+
*
|
|
26
|
+
* The tree is retained between frames, which is the whole reason hooks can
|
|
27
|
+
* hold state and the renderer can diff rather than redraw: an instance whose
|
|
28
|
+
* node and props are unchanged is not re-rendered at all.
|
|
29
|
+
*/
|
|
30
|
+
export interface Instance {
|
|
31
|
+
id: string;
|
|
32
|
+
component: string;
|
|
33
|
+
kind: InstanceKind;
|
|
34
|
+
key: string | number | undefined;
|
|
35
|
+
|
|
36
|
+
node: ComponentNode;
|
|
37
|
+
props: Record<string, unknown>;
|
|
38
|
+
|
|
39
|
+
fn?: FunctionComponent;
|
|
40
|
+
host?: HostComponent;
|
|
41
|
+
definition?: ComponentDefinition;
|
|
42
|
+
|
|
43
|
+
parent: Instance | null;
|
|
44
|
+
children: Instance[];
|
|
45
|
+
|
|
46
|
+
hooks: HookSlot[];
|
|
47
|
+
hookIndex: number;
|
|
48
|
+
|
|
49
|
+
/** Store paths this instance's props read. Re-render when one changes. */
|
|
50
|
+
reads: Set<string>;
|
|
51
|
+
subscriptions: Disposable[];
|
|
52
|
+
|
|
53
|
+
dataContext?: BindingPath;
|
|
54
|
+
/** Context values provided by this instance, by context id. */
|
|
55
|
+
contexts?: Map<string, unknown>;
|
|
56
|
+
|
|
57
|
+
dirty: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* A descendant is dirty. Without this the render pass stops at the first
|
|
60
|
+
* clean ancestor and never reaches the component that actually changed -
|
|
61
|
+
* which is exactly what happens when a text field deep inside a mounted
|
|
62
|
+
* surface updates its own state.
|
|
63
|
+
*/
|
|
64
|
+
childDirty: boolean;
|
|
65
|
+
mounted: boolean;
|
|
66
|
+
/** Set when this subtree threw; a boundary renders its fallback instead. */
|
|
67
|
+
error?: unknown;
|
|
68
|
+
/** Why the last render ran. Diagnostics only. */
|
|
69
|
+
renderReason?: string;
|
|
70
|
+
|
|
71
|
+
/** Filled by the layout pass for host instances. */
|
|
72
|
+
box?: LayoutBox;
|
|
73
|
+
/** Last content rect observed by `useMeasure`, if this instance asked. */
|
|
74
|
+
measured?: Rect;
|
|
75
|
+
/** Content extent when it overflows that rect, for `useScrollExtent`. */
|
|
76
|
+
scrollExtent?: Size;
|
|
77
|
+
/** The child nodes produced by the last render, for a children-only pass. */
|
|
78
|
+
lastChildren: { node: ComponentNode; dataContext?: BindingPath }[];
|
|
79
|
+
/** Effects queued during this render, flushed after the frame commits. */
|
|
80
|
+
pendingEffects: (() => void)[];
|
|
81
|
+
|
|
82
|
+
runtime: Runtime;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let nextId = 1;
|
|
86
|
+
|
|
87
|
+
export function createInstance(
|
|
88
|
+
runtime: Runtime,
|
|
89
|
+
node: ComponentNode,
|
|
90
|
+
parent: Instance | null,
|
|
91
|
+
): Instance {
|
|
92
|
+
return {
|
|
93
|
+
id: node.id ?? `n${nextId++}`,
|
|
94
|
+
component: node.component,
|
|
95
|
+
kind: 'missing',
|
|
96
|
+
key: node.key,
|
|
97
|
+
node,
|
|
98
|
+
props: {},
|
|
99
|
+
parent,
|
|
100
|
+
children: [],
|
|
101
|
+
hooks: [],
|
|
102
|
+
hookIndex: 0,
|
|
103
|
+
reads: new Set(),
|
|
104
|
+
subscriptions: [],
|
|
105
|
+
dataContext: parent?.dataContext,
|
|
106
|
+
lastChildren: [],
|
|
107
|
+
dirty: true,
|
|
108
|
+
childDirty: false,
|
|
109
|
+
mounted: false,
|
|
110
|
+
pendingEffects: [],
|
|
111
|
+
runtime,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Flatten render output into nodes. Strings and numbers become text nodes. */
|
|
116
|
+
export function normalizeChildren(output: unknown): ComponentNode[] {
|
|
117
|
+
const out: ComponentNode[] = [];
|
|
118
|
+
|
|
119
|
+
const walk = (value: unknown): void => {
|
|
120
|
+
if (value === null || value === undefined || value === false || value === true) return;
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
for (const item of value) walk(item);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
126
|
+
const content = String(value);
|
|
127
|
+
if (content !== '') out.push({ component: 'text', content });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (isComponentNode(value)) {
|
|
131
|
+
out.push(value);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Anything else is a programmer error worth seeing rather than swallowing.
|
|
135
|
+
out.push({ component: 'text', content: String(value) });
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
walk(output as RenderOutput);
|
|
139
|
+
return out;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Expand `{ template, path }` into one node per item, each with its own data
|
|
144
|
+
* context - which is what lets one templated node render a hundred rows.
|
|
145
|
+
*/
|
|
146
|
+
export function expandTemplate(
|
|
147
|
+
runtime: Runtime,
|
|
148
|
+
spec: { template: ComponentNode; path: BindingPath },
|
|
149
|
+
dataContext: BindingPath | undefined,
|
|
150
|
+
): { nodes: ComponentNode[]; contexts: BindingPath[]; read: string } {
|
|
151
|
+
const base = spec.path.startsWith('$/')
|
|
152
|
+
? spec.path
|
|
153
|
+
: (joinPath(dataContext ?? '$/', spec.path) as BindingPath);
|
|
154
|
+
|
|
155
|
+
const items = runtime.store.get<unknown[]>(base);
|
|
156
|
+
const list = Array.isArray(items) ? items : [];
|
|
157
|
+
|
|
158
|
+
const nodes: ComponentNode[] = [];
|
|
159
|
+
const contexts: BindingPath[] = [];
|
|
160
|
+
for (let i = 0; i < list.length; i++) {
|
|
161
|
+
const item = list[i] as Record<string, unknown> | undefined;
|
|
162
|
+
const key =
|
|
163
|
+
item && typeof item === 'object' && 'id' in item ? String(item.id) : String(i);
|
|
164
|
+
nodes.push({ ...spec.template, key });
|
|
165
|
+
contexts.push(joinPath(base, String(i)) as BindingPath);
|
|
166
|
+
}
|
|
167
|
+
return { nodes, contexts, read: base };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function resolveContextFor(instance: Instance): ResolveContext {
|
|
171
|
+
return {
|
|
172
|
+
store: instance.runtime.store,
|
|
173
|
+
dataContext: instance.dataContext,
|
|
174
|
+
execute: (id, args) => instance.runtime.execute(id, args),
|
|
175
|
+
emit: (path, payload) => instance.runtime.emit(path, payload),
|
|
176
|
+
reads: new Set<string>(),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Look up a context value by walking the parent chain. */
|
|
181
|
+
export function readContext(instance: Instance, contextId: string): unknown {
|
|
182
|
+
let cursor: Instance | null = instance;
|
|
183
|
+
while (cursor) {
|
|
184
|
+
const value = cursor.contexts?.get(contextId);
|
|
185
|
+
if (value !== undefined) return value;
|
|
186
|
+
cursor = cursor.parent;
|
|
187
|
+
}
|
|
188
|
+
return undefined;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function emptyBox(): LayoutBox {
|
|
192
|
+
return {
|
|
193
|
+
style: {},
|
|
194
|
+
borderEdges: ZERO_EDGES,
|
|
195
|
+
children: [],
|
|
196
|
+
rect: { x: 0, y: 0, width: 0, height: 0 },
|
|
197
|
+
content: { x: 0, y: 0, width: 0, height: 0 },
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/** Depth-first walk, parents before children. */
|
|
202
|
+
export function walkInstances(root: Instance, visit: (i: Instance) => void): void {
|
|
203
|
+
visit(root);
|
|
204
|
+
for (const child of root.children) walkInstances(child, visit);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function unmountInstance(instance: Instance): void {
|
|
208
|
+
for (const child of instance.children) unmountInstance(child);
|
|
209
|
+
instance.children = [];
|
|
210
|
+
|
|
211
|
+
for (const hook of instance.hooks) {
|
|
212
|
+
if (typeof hook.cleanup === 'function') {
|
|
213
|
+
try {
|
|
214
|
+
hook.cleanup();
|
|
215
|
+
} catch (err) {
|
|
216
|
+
instance.runtime.onError(err, `cleanup in <${instance.component}>`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
instance.hooks = [];
|
|
221
|
+
|
|
222
|
+
for (const sub of instance.subscriptions) sub.dispose();
|
|
223
|
+
instance.subscriptions = [];
|
|
224
|
+
instance.mounted = false;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Re-resolve props and note which store paths this instance now depends on. */
|
|
228
|
+
export function updateProps(instance: Instance, node: ComponentNode): void {
|
|
229
|
+
const ctx = resolveContextFor(instance);
|
|
230
|
+
const nextContext = node.dataContext;
|
|
231
|
+
if (typeof nextContext === 'string') {
|
|
232
|
+
instance.dataContext = nextContext as BindingPath;
|
|
233
|
+
ctx.dataContext = instance.dataContext;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
instance.node = node;
|
|
237
|
+
instance.props = resolveProps(ctx, node);
|
|
238
|
+
|
|
239
|
+
// Children that are a templated list read their source path too.
|
|
240
|
+
const children = instance.props.children;
|
|
241
|
+
if (isTemplateChildren(children)) {
|
|
242
|
+
const expanded = expandTemplate(instance.runtime, children, instance.dataContext);
|
|
243
|
+
ctx.reads.add(expanded.read);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
instance.reads = ctx.reads;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function findFunction(
|
|
250
|
+
runtime: Runtime,
|
|
251
|
+
node: ComponentNode,
|
|
252
|
+
): { kind: InstanceKind; fn?: FunctionComponent; host?: HostComponent; definition?: ComponentDefinition } {
|
|
253
|
+
const inline = nodeFunction(node);
|
|
254
|
+
if (inline) return { kind: 'function', fn: inline };
|
|
255
|
+
|
|
256
|
+
const def = runtime.components.get(node.component);
|
|
257
|
+
if (!def) return { kind: 'missing' };
|
|
258
|
+
|
|
259
|
+
switch (def.renderer.kind) {
|
|
260
|
+
case 'function':
|
|
261
|
+
return { kind: 'function', fn: def.renderer.render, definition: def };
|
|
262
|
+
case 'host':
|
|
263
|
+
return { kind: 'host', host: def.renderer.host, definition: def };
|
|
264
|
+
case 'template':
|
|
265
|
+
return { kind: 'template', definition: def };
|
|
266
|
+
case 'lazy':
|
|
267
|
+
// Not resolved yet; the registry resolves it and asks for another frame.
|
|
268
|
+
return { kind: 'missing', definition: def };
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Mark an instance for re-render, and tell its ancestors a descendant changed
|
|
274
|
+
* so the render pass will walk down to it.
|
|
275
|
+
*/
|
|
276
|
+
export function markDirty(instance: Instance, reason: string): void {
|
|
277
|
+
instance.dirty = true;
|
|
278
|
+
instance.renderReason = reason;
|
|
279
|
+
let cursor = instance.parent;
|
|
280
|
+
while (cursor && !cursor.childDirty) {
|
|
281
|
+
cursor.childDirty = true;
|
|
282
|
+
cursor = cursor.parent;
|
|
283
|
+
}
|
|
284
|
+
}
|