@craft-ts/component 0.7.0-beta.13
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/package.json +36 -0
- package/src/index.d.ts +40 -0
- package/src/index.d.ts.map +1 -0
- package/src/index.js +38 -0
- package/src/index.js.map +1 -0
- package/src/lib/a11y-control.d.ts +58 -0
- package/src/lib/a11y-control.d.ts.map +1 -0
- package/src/lib/a11y-control.js +74 -0
- package/src/lib/a11y-control.js.map +1 -0
- package/src/lib/a11y.d.ts +87 -0
- package/src/lib/a11y.d.ts.map +1 -0
- package/src/lib/a11y.js +96 -0
- package/src/lib/a11y.js.map +1 -0
- package/src/lib/ai/ai-context-menu.d.ts +140 -0
- package/src/lib/ai/ai-context-menu.d.ts.map +1 -0
- package/src/lib/ai/ai-context-menu.js +66 -0
- package/src/lib/ai/ai-context-menu.js.map +1 -0
- package/src/lib/ai/ai-send-dialog.d.ts +1263 -0
- package/src/lib/ai/ai-send-dialog.d.ts.map +1 -0
- package/src/lib/ai/ai-send-dialog.js +288 -0
- package/src/lib/ai/ai-send-dialog.js.map +1 -0
- package/src/lib/ai/send-context-to-ai.d.ts +29 -0
- package/src/lib/ai/send-context-to-ai.d.ts.map +1 -0
- package/src/lib/ai/send-context-to-ai.js +127 -0
- package/src/lib/ai/send-context-to-ai.js.map +1 -0
- package/src/lib/assert-defined-input.d.ts +26 -0
- package/src/lib/assert-defined-input.d.ts.map +1 -0
- package/src/lib/assert-defined-input.js +47 -0
- package/src/lib/assert-defined-input.js.map +1 -0
- package/src/lib/block.d.ts +36 -0
- package/src/lib/block.d.ts.map +1 -0
- package/src/lib/block.js +55 -0
- package/src/lib/block.js.map +1 -0
- package/src/lib/bootstrap.d.ts +32 -0
- package/src/lib/bootstrap.d.ts.map +1 -0
- package/src/lib/bootstrap.js +60 -0
- package/src/lib/bootstrap.js.map +1 -0
- package/src/lib/bridge.d.ts +56 -0
- package/src/lib/bridge.d.ts.map +1 -0
- package/src/lib/bridge.js +81 -0
- package/src/lib/bridge.js.map +1 -0
- package/src/lib/component.d.ts +46 -0
- package/src/lib/component.d.ts.map +1 -0
- package/src/lib/component.js +118 -0
- package/src/lib/component.js.map +1 -0
- package/src/lib/composition.d.ts +17 -0
- package/src/lib/composition.d.ts.map +1 -0
- package/src/lib/composition.js +28 -0
- package/src/lib/composition.js.map +1 -0
- package/src/lib/craft-defaults.d.ts +2 -0
- package/src/lib/craft-defaults.d.ts.map +1 -0
- package/src/lib/craft-defaults.js +41 -0
- package/src/lib/craft-defaults.js.map +1 -0
- package/src/lib/craft-host-tokens.d.ts +6 -0
- package/src/lib/craft-host-tokens.d.ts.map +1 -0
- package/src/lib/craft-host-tokens.js +7 -0
- package/src/lib/craft-host-tokens.js.map +1 -0
- package/src/lib/craft-router-outlet.d.ts +15 -0
- package/src/lib/craft-router-outlet.d.ts.map +1 -0
- package/src/lib/craft-router-outlet.js +10 -0
- package/src/lib/craft-router-outlet.js.map +1 -0
- package/src/lib/css-vars.d.ts +31 -0
- package/src/lib/css-vars.d.ts.map +1 -0
- package/src/lib/css-vars.js +43 -0
- package/src/lib/css-vars.js.map +1 -0
- package/src/lib/css-vars.type.d.ts +151 -0
- package/src/lib/css-vars.type.d.ts.map +1 -0
- package/src/lib/css-vars.type.js +1 -0
- package/src/lib/css-vars.type.js.map +1 -0
- package/src/lib/defer.d.ts +31 -0
- package/src/lib/defer.d.ts.map +1 -0
- package/src/lib/defer.js +19 -0
- package/src/lib/defer.js.map +1 -0
- package/src/lib/directive.d.ts +9 -0
- package/src/lib/directive.d.ts.map +1 -0
- package/src/lib/directive.js +31 -0
- package/src/lib/directive.js.map +1 -0
- package/src/lib/each-scheduling.d.ts +59 -0
- package/src/lib/each-scheduling.d.ts.map +1 -0
- package/src/lib/each-scheduling.js +120 -0
- package/src/lib/each-scheduling.js.map +1 -0
- package/src/lib/each.d.ts +29 -0
- package/src/lib/each.d.ts.map +1 -0
- package/src/lib/each.js +23 -0
- package/src/lib/each.js.map +1 -0
- package/src/lib/factory-runtime.d.ts +5 -0
- package/src/lib/factory-runtime.d.ts.map +1 -0
- package/src/lib/factory-runtime.js +26 -0
- package/src/lib/factory-runtime.js.map +1 -0
- package/src/lib/field-exception-block.d.ts +96 -0
- package/src/lib/field-exception-block.d.ts.map +1 -0
- package/src/lib/field-exception-block.js +44 -0
- package/src/lib/field-exception-block.js.map +1 -0
- package/src/lib/host-runtime.d.ts +60 -0
- package/src/lib/host-runtime.d.ts.map +1 -0
- package/src/lib/host-runtime.js +16 -0
- package/src/lib/host-runtime.js.map +1 -0
- package/src/lib/hydrate.d.ts +15 -0
- package/src/lib/hydrate.d.ts.map +1 -0
- package/src/lib/hydrate.js +79 -0
- package/src/lib/hydrate.js.map +1 -0
- package/src/lib/hyperscript.d.ts +148 -0
- package/src/lib/hyperscript.d.ts.map +1 -0
- package/src/lib/hyperscript.js +96 -0
- package/src/lib/hyperscript.js.map +1 -0
- package/src/lib/if-block.d.ts +8 -0
- package/src/lib/if-block.d.ts.map +1 -0
- package/src/lib/if-block.js +16 -0
- package/src/lib/if-block.js.map +1 -0
- package/src/lib/locator.d.ts +170 -0
- package/src/lib/locator.d.ts.map +1 -0
- package/src/lib/locator.js +151 -0
- package/src/lib/locator.js.map +1 -0
- package/src/lib/match-block.d.ts +38 -0
- package/src/lib/match-block.d.ts.map +1 -0
- package/src/lib/match-block.js +29 -0
- package/src/lib/match-block.js.map +1 -0
- package/src/lib/pending-block.d.ts +125 -0
- package/src/lib/pending-block.d.ts.map +1 -0
- package/src/lib/pending-block.js +48 -0
- package/src/lib/pending-block.js.map +1 -0
- package/src/lib/project.d.ts +19 -0
- package/src/lib/project.d.ts.map +1 -0
- package/src/lib/project.js +56 -0
- package/src/lib/project.js.map +1 -0
- package/src/lib/render/hydration-metadata.d.ts +3 -0
- package/src/lib/render/hydration-metadata.d.ts.map +1 -0
- package/src/lib/render/hydration-metadata.js +8 -0
- package/src/lib/render/hydration-metadata.js.map +1 -0
- package/src/lib/render/hydration.d.ts +24 -0
- package/src/lib/render/hydration.d.ts.map +1 -0
- package/src/lib/render/hydration.js +181 -0
- package/src/lib/render/hydration.js.map +1 -0
- package/src/lib/render/interpreter.d.ts +32 -0
- package/src/lib/render/interpreter.d.ts.map +1 -0
- package/src/lib/render/interpreter.js +3588 -0
- package/src/lib/render/interpreter.js.map +1 -0
- package/src/lib/render/server-style-collector.d.ts +6 -0
- package/src/lib/render/server-style-collector.d.ts.map +1 -0
- package/src/lib/render/server-style-collector.js +23 -0
- package/src/lib/render/server-style-collector.js.map +1 -0
- package/src/lib/render/ssr-coordinator.d.ts +20 -0
- package/src/lib/render/ssr-coordinator.d.ts.map +1 -0
- package/src/lib/render/ssr-coordinator.js +99 -0
- package/src/lib/render/ssr-coordinator.js.map +1 -0
- package/src/lib/render/string-dom.d.ts +9 -0
- package/src/lib/render/string-dom.d.ts.map +1 -0
- package/src/lib/render/string-dom.js +377 -0
- package/src/lib/render/string-dom.js.map +1 -0
- package/src/lib/render/style-registry.d.ts +14 -0
- package/src/lib/render/style-registry.d.ts.map +1 -0
- package/src/lib/render/style-registry.js +79 -0
- package/src/lib/render/style-registry.js.map +1 -0
- package/src/lib/render/style-scope.d.ts +30 -0
- package/src/lib/render/style-scope.d.ts.map +1 -0
- package/src/lib/render/style-scope.js +261 -0
- package/src/lib/render/style-scope.js.map +1 -0
- package/src/lib/render/vnode.d.ts +330 -0
- package/src/lib/render/vnode.d.ts.map +1 -0
- package/src/lib/render/vnode.js +293 -0
- package/src/lib/render/vnode.js.map +1 -0
- package/src/lib/server-render.d.ts +34 -0
- package/src/lib/server-render.d.ts.map +1 -0
- package/src/lib/server-render.js +84 -0
- package/src/lib/server-render.js.map +1 -0
- package/src/lib/start.d.ts +13 -0
- package/src/lib/start.d.ts.map +1 -0
- package/src/lib/start.js +20 -0
- package/src/lib/start.js.map +1 -0
- package/src/lib/template-contract.d.ts +347 -0
- package/src/lib/template-contract.d.ts.map +1 -0
- package/src/lib/template-contract.js +1 -0
- package/src/lib/template-contract.js.map +1 -0
- package/src/lib/template.d.ts +11 -0
- package/src/lib/template.d.ts.map +1 -0
- package/src/lib/template.js +21 -0
- package/src/lib/template.js.map +1 -0
- package/src/lib/testing.d.ts +157 -0
- package/src/lib/testing.d.ts.map +1 -0
- package/src/lib/testing.js +416 -0
- package/src/lib/testing.js.map +1 -0
- package/src/lib/types.d.ts +442 -0
- package/src/lib/types.d.ts.map +1 -0
- package/src/lib/types.js +22 -0
- package/src/lib/types.js.map +1 -0
- package/testing/public-api.d.ts +3 -0
- package/testing/public-api.d.ts.map +1 -0
- package/testing/public-api.js +3 -0
- package/testing/public-api.js.map +1 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { CRAFT_NODE_DIRECTIVE, isCraftNodeDirective } from '@craft-ts/core';
|
|
2
|
+
import { isCraftDirective } from '../types';
|
|
3
|
+
import { CATCH_BLOCK_DIRECTIVE, } from '../block';
|
|
4
|
+
import { PENDING_BLOCK_DIRECTIVE, } from '../pending-block';
|
|
5
|
+
import { FIELD_EXCEPTION_BLOCK_DIRECTIVE, } from '../field-exception-block';
|
|
6
|
+
import { SCHEDULE_EACH_DIRECTIVE, isScheduleEachDirective, } from '../each-scheduling';
|
|
7
|
+
export const CRAFT_NODE_CSS_VARS = Symbol('craft-node-css-vars');
|
|
8
|
+
export const CRAFT_NODE_DIRECTIVES = Symbol('craft-node-directives');
|
|
9
|
+
let activeCraftRenderContext;
|
|
10
|
+
/** Internal bridge used by factories that create nodes while a template runs. */
|
|
11
|
+
export function withCraftRenderContext(context, work) {
|
|
12
|
+
const previous = activeCraftRenderContext;
|
|
13
|
+
activeCraftRenderContext = context;
|
|
14
|
+
try {
|
|
15
|
+
return work();
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
activeCraftRenderContext = previous;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function currentCraftRenderContext() {
|
|
22
|
+
return activeCraftRenderContext;
|
|
23
|
+
}
|
|
24
|
+
export function isCraftNode(value) {
|
|
25
|
+
if (typeof value !== 'object' || value === null || !('kind' in value)) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return (value.kind === 'element' ||
|
|
29
|
+
value.kind === 'text' ||
|
|
30
|
+
value.kind === 'component' ||
|
|
31
|
+
value.kind === 'angular' ||
|
|
32
|
+
value.kind === 'directive' ||
|
|
33
|
+
value.kind === 'each' ||
|
|
34
|
+
value.kind === 'if' ||
|
|
35
|
+
value.kind === 'heading' ||
|
|
36
|
+
value.kind === 'heading-section' ||
|
|
37
|
+
value.kind === 'defer' ||
|
|
38
|
+
value.kind === 'catch-block' ||
|
|
39
|
+
value.kind === 'pending-block' ||
|
|
40
|
+
value.kind === 'field-exception-block' ||
|
|
41
|
+
value.kind === 'match-block' ||
|
|
42
|
+
value.kind === 'projection' ||
|
|
43
|
+
value.kind === 'template');
|
|
44
|
+
}
|
|
45
|
+
function withPipe(node) {
|
|
46
|
+
return {
|
|
47
|
+
...node,
|
|
48
|
+
pipe: ((directive) => pipeCraftNode(node, directive)),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function pipeCraftNode(node, directive) {
|
|
52
|
+
if (isScheduleEachDirective(directive)) {
|
|
53
|
+
if (node.kind !== 'each') {
|
|
54
|
+
throw new TypeError('scheduleEach(...) can only be piped onto an each(...) block.');
|
|
55
|
+
}
|
|
56
|
+
return withPipe({
|
|
57
|
+
...node,
|
|
58
|
+
schedule: directive[SCHEDULE_EACH_DIRECTIVE],
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (isCraftNodeDirective(directive)) {
|
|
62
|
+
node = applyCraftNodeDirective(node, directive);
|
|
63
|
+
if (!isCraftDirective(directive)) {
|
|
64
|
+
return node;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!isCraftDirective(directive)) {
|
|
68
|
+
if (node.kind === 'directive') {
|
|
69
|
+
return withPipe({
|
|
70
|
+
...node,
|
|
71
|
+
node: pipeCraftNode(node.node, directive),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// Only Craft directives are applicable; anything else is a no-op now that
|
|
75
|
+
// Angular directive definitions (`ɵdir`) are gone.
|
|
76
|
+
return node;
|
|
77
|
+
}
|
|
78
|
+
const catchBlockDefinition = directive[CATCH_BLOCK_DIRECTIVE];
|
|
79
|
+
if (catchBlockDefinition) {
|
|
80
|
+
const definition = catchBlockDefinition;
|
|
81
|
+
return {
|
|
82
|
+
kind: 'catch-block',
|
|
83
|
+
source: node,
|
|
84
|
+
handlers: definition.handlers,
|
|
85
|
+
position: definition.position,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const pendingBlockDefinition = directive[PENDING_BLOCK_DIRECTIVE];
|
|
89
|
+
if (pendingBlockDefinition) {
|
|
90
|
+
const definition = pendingBlockDefinition;
|
|
91
|
+
return withPipe({
|
|
92
|
+
kind: 'pending-block',
|
|
93
|
+
source: node,
|
|
94
|
+
handlers: definition.handlers,
|
|
95
|
+
fallback: definition.fallback,
|
|
96
|
+
reloading: definition.reloading,
|
|
97
|
+
position: definition.position,
|
|
98
|
+
ssr: definition.ssr,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const fieldExceptionBlockDefinition = directive[FIELD_EXCEPTION_BLOCK_DIRECTIVE];
|
|
102
|
+
if (fieldExceptionBlockDefinition) {
|
|
103
|
+
const definition = fieldExceptionBlockDefinition;
|
|
104
|
+
return withPipe({
|
|
105
|
+
kind: 'field-exception-block',
|
|
106
|
+
source: node,
|
|
107
|
+
handlers: definition.handlers,
|
|
108
|
+
options: definition.options,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
if (node.kind === 'directive') {
|
|
112
|
+
return withPipe({
|
|
113
|
+
...node,
|
|
114
|
+
directives: [...node.directives, directive],
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return withPipe({
|
|
118
|
+
kind: 'directive',
|
|
119
|
+
node,
|
|
120
|
+
directives: [directive],
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function applyCraftNodeDirective(node, directive) {
|
|
124
|
+
if (node.kind === 'directive') {
|
|
125
|
+
return withPipe({
|
|
126
|
+
...node,
|
|
127
|
+
node: applyCraftNodeDirective(node.node, directive),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
if (node.kind !== 'element')
|
|
131
|
+
return node;
|
|
132
|
+
const definition = directive[CRAFT_NODE_DIRECTIVE];
|
|
133
|
+
const props = { ...node.props };
|
|
134
|
+
const inputs = Object.fromEntries(definition.inputs
|
|
135
|
+
.filter((name) => name in props)
|
|
136
|
+
.map((name) => [name, props[name]]));
|
|
137
|
+
definition.inputs.forEach((name) => delete props[name]);
|
|
138
|
+
return withPipe({
|
|
139
|
+
...node,
|
|
140
|
+
props,
|
|
141
|
+
[CRAFT_NODE_DIRECTIVES]: [
|
|
142
|
+
...(node[CRAFT_NODE_DIRECTIVES] ?? []),
|
|
143
|
+
{ directive, inputs },
|
|
144
|
+
],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function resolveHostValue(value) {
|
|
148
|
+
return typeof value === 'function' ? value() : value;
|
|
149
|
+
}
|
|
150
|
+
function hasHostBinding(value, seen = new Set()) {
|
|
151
|
+
if (typeof value === 'function')
|
|
152
|
+
return true;
|
|
153
|
+
if (typeof value !== 'object' || value === null || seen.has(value)) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
seen.add(value);
|
|
157
|
+
return Object.values(value).some((child) => hasHostBinding(child, seen));
|
|
158
|
+
}
|
|
159
|
+
function classTokens(value) {
|
|
160
|
+
const resolved = resolveHostValue(value);
|
|
161
|
+
if (Array.isArray(resolved)) {
|
|
162
|
+
return resolved.flatMap((item) => classTokens(item));
|
|
163
|
+
}
|
|
164
|
+
if (typeof resolved === 'object' && resolved !== null) {
|
|
165
|
+
return Object.entries(resolved)
|
|
166
|
+
.filter(([, enabled]) => enabled)
|
|
167
|
+
.map(([name]) => name);
|
|
168
|
+
}
|
|
169
|
+
return resolved == null || resolved === false
|
|
170
|
+
? []
|
|
171
|
+
: String(resolved).split(/\s+/).filter(Boolean);
|
|
172
|
+
}
|
|
173
|
+
function mergeResolvedClasses(left, right) {
|
|
174
|
+
const classes = [...classTokens(left), ...classTokens(right)];
|
|
175
|
+
return classes.length ? [...new Set(classes)].join(' ') : undefined;
|
|
176
|
+
}
|
|
177
|
+
function mergeClasses(left, right) {
|
|
178
|
+
return hasHostBinding(left) || hasHostBinding(right)
|
|
179
|
+
? () => mergeResolvedClasses(left, right)
|
|
180
|
+
: mergeResolvedClasses(left, right);
|
|
181
|
+
}
|
|
182
|
+
function mergeResolvedStyles(left, right) {
|
|
183
|
+
const resolvedLeft = resolveHostValue(left);
|
|
184
|
+
const resolvedRight = resolveHostValue(right);
|
|
185
|
+
if (typeof resolvedLeft === 'object' &&
|
|
186
|
+
resolvedLeft !== null &&
|
|
187
|
+
typeof resolvedRight === 'object' &&
|
|
188
|
+
resolvedRight !== null) {
|
|
189
|
+
return { ...resolvedLeft, ...resolvedRight };
|
|
190
|
+
}
|
|
191
|
+
if (resolvedRight === undefined || resolvedRight === null) {
|
|
192
|
+
return resolvedLeft;
|
|
193
|
+
}
|
|
194
|
+
if (typeof resolvedLeft === 'string' && typeof resolvedRight === 'string') {
|
|
195
|
+
return `${resolvedLeft.replace(/;?\s*$/, ';')}${resolvedRight}`;
|
|
196
|
+
}
|
|
197
|
+
return resolvedRight;
|
|
198
|
+
}
|
|
199
|
+
function mergeStyles(left, right) {
|
|
200
|
+
return hasHostBinding(left) || hasHostBinding(right)
|
|
201
|
+
? () => mergeResolvedStyles(left, right)
|
|
202
|
+
: mergeResolvedStyles(left, right);
|
|
203
|
+
}
|
|
204
|
+
export function mergeHostProps(base, added) {
|
|
205
|
+
const merged = { ...base, ...added };
|
|
206
|
+
const classes = mergeClasses(base['class'], added['class']);
|
|
207
|
+
if (classes === undefined) {
|
|
208
|
+
delete merged['class'];
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
merged['class'] = classes;
|
|
212
|
+
}
|
|
213
|
+
if ('style' in base || 'style' in added) {
|
|
214
|
+
merged['style'] = mergeStyles(base['style'], added['style']);
|
|
215
|
+
}
|
|
216
|
+
return merged;
|
|
217
|
+
}
|
|
218
|
+
function addHostPropsToNode(node, props, applied) {
|
|
219
|
+
if (applied.value) {
|
|
220
|
+
return node;
|
|
221
|
+
}
|
|
222
|
+
if (node.kind === 'element') {
|
|
223
|
+
applied.value = true;
|
|
224
|
+
return withPipe({
|
|
225
|
+
...node,
|
|
226
|
+
props: mergeHostProps(node.props, props),
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
if (node.kind === 'component') {
|
|
230
|
+
applied.value = true;
|
|
231
|
+
return {
|
|
232
|
+
...node,
|
|
233
|
+
props: mergeHostProps(node.props, props),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (node.kind === 'directive') {
|
|
237
|
+
return withPipe({
|
|
238
|
+
...node,
|
|
239
|
+
node: addHostPropsToNode(node.node, props, applied),
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return node;
|
|
243
|
+
}
|
|
244
|
+
/** Adds host properties to the first host node produced by a template. */
|
|
245
|
+
export function applyHostPropsToChildren(children, props) {
|
|
246
|
+
if (!props || Object.keys(props).length === 0) {
|
|
247
|
+
return children;
|
|
248
|
+
}
|
|
249
|
+
const applied = { value: false };
|
|
250
|
+
const visit = (child) => {
|
|
251
|
+
if (Array.isArray(child)) {
|
|
252
|
+
return child.map(visit);
|
|
253
|
+
}
|
|
254
|
+
return isCraftNode(child)
|
|
255
|
+
? addHostPropsToNode(child, props, applied)
|
|
256
|
+
: child;
|
|
257
|
+
};
|
|
258
|
+
return visit(children);
|
|
259
|
+
}
|
|
260
|
+
export function normalizeChildren(children) {
|
|
261
|
+
const result = [];
|
|
262
|
+
const visit = (child) => {
|
|
263
|
+
if (Array.isArray(child)) {
|
|
264
|
+
child.forEach(visit);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
if (child === null || child === undefined || child === false) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
if (isCraftNode(child)) {
|
|
271
|
+
result.push(child);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (typeof child === 'function') {
|
|
275
|
+
result.push({
|
|
276
|
+
kind: 'reactive-text',
|
|
277
|
+
binding: child,
|
|
278
|
+
});
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const resolved = child;
|
|
282
|
+
if (resolved === null || resolved === undefined) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
result.push({
|
|
286
|
+
kind: 'text',
|
|
287
|
+
value: String(resolved),
|
|
288
|
+
});
|
|
289
|
+
};
|
|
290
|
+
visit(children);
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=vnode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vnode.js","sourceRoot":"","sources":["../../../../../../libs/component/src/lib/render/vnode.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AnyCraftException,\n CraftNodeDirective,\n CraftLazyLoadHelpers,\n CatchTagExhaustiveCodesCheck,\n CraftSettledCodesOf,\n CraftSettledSourcesOf,\n ExtractCraftGenExceptions,\n ExtractCraftPendingSources,\n FieldValidationCasesOf,\n SsrMode,\n} from '@craft-ts/core';\nimport { CRAFT_NODE_DIRECTIVE, isCraftNodeDirective } from '@craft-ts/core';\nimport type {\n CraftComponent,\n CraftDirectiveTemplateDependencies,\n ComponentInitializationExceptionsOf,\n ComponentFieldExceptionsOf,\n CraftTemplate,\n ContentStylePolicy,\n InputValue,\n} from '../types';\nimport { isCraftDirective, type CraftDirective } from '../types';\nimport type { CssVarContract, EmptyCssVarContract } from '../css-vars.type';\nimport {\n CATCH_BLOCK_DIRECTIVE,\n type CatchBlockDirective,\n type CatchBlockHandlerChildren,\n type CatchBlockHandlers,\n type CatchBlockPosition,\n} from '../block';\nimport {\n PENDING_BLOCK_DIRECTIVE,\n type PendingBlockDirective,\n type PendingBlockHandlers,\n type PendingBlockPosition,\n type PendingFallback,\n type PendingBlockExhaustiveCheck,\n type PendingBlockResidualSources,\n} from '../pending-block';\nimport {\n FIELD_EXCEPTION_BLOCK_DIRECTIVE,\n type FieldExceptionBlockDirective,\n type FieldExceptionBlockExhaustiveCheck,\n type FieldExceptionBlockPartialCheck,\n type FieldExceptionBlockOptions,\n type FieldExceptionHandlerFieldExceptions,\n type FieldExceptionHandlerChildren,\n type FieldExceptionHandlers,\n type FieldValidationHandledIdentities,\n type FieldValidationHandledIdentitiesCarrier,\n type ResidualFieldValidationCases,\n type UnhandledFieldValidationCases,\n} from '../field-exception-block';\nimport type {\n EachSchedulePolicy,\n ScheduleEachDirective,\n} from '../each-scheduling';\nimport {\n SCHEDULE_EACH_DIRECTIVE,\n isScheduleEachDirective,\n} from '../each-scheduling';\n\nexport type CraftHostInjector = unknown;\ntype HostInjector = CraftHostInjector & any;\ntype CraftHostType<T> = Function & {\n new (...args: any[]): T;\n};\n\nexport declare const CRAFT_NODE_DEPS: unique symbol;\nexport const CRAFT_NODE_CSS_VARS: unique symbol = Symbol('craft-node-css-vars');\nexport const CRAFT_NODE_DIRECTIVES = Symbol('craft-node-directives');\ndeclare const CRAFT_NODE_EXCEPTIONS: unique symbol;\ndeclare const CRAFT_NODE_HANDLED_EXCEPTIONS: unique symbol;\ndeclare const CRAFT_NODE_PENDING: unique symbol;\ndeclare const CRAFT_NODE_SETTLED_EXCEPTIONS: unique symbol;\ndeclare const CRAFT_NODE_HEADING_NEED: unique symbol;\nexport declare const CRAFT_NODE_FIELD_EXCEPTIONS: unique symbol;\n\nlet activeCraftRenderContext: unknown;\n\n/** Internal bridge used by factories that create nodes while a template runs. */\nexport function withCraftRenderContext<T>(context: unknown, work: () => T): T {\n const previous = activeCraftRenderContext;\n activeCraftRenderContext = context;\n try {\n return work();\n } finally {\n activeCraftRenderContext = previous;\n }\n}\n\nexport function currentCraftRenderContext(): unknown {\n return activeCraftRenderContext;\n}\n\nexport type CraftNodeDepsCarrier<Dependencies extends object = {}> = {\n readonly [CRAFT_NODE_DEPS]?: Dependencies;\n};\n\n/** Type-only contract propagated from descendant component calls. */\nexport type CraftNodeCssVarsCarrier<\n Contract extends CssVarContract = EmptyCssVarContract,\n> = {\n readonly __craftNodeCssVars__?: Contract;\n};\n\ntype IsAny<Value> = 0 extends 1 & Value ? true : false;\n\nexport type CraftNodeExceptionsCarrier<Exceptions extends string = string> = {\n readonly [CRAFT_NODE_EXCEPTIONS]?: Exceptions;\n};\n\nexport type CraftNodeHandledExceptionsCarrier<Codes extends string = string> = {\n readonly [CRAFT_NODE_HANDLED_EXCEPTIONS]?: Codes;\n};\n\nexport type CraftNodeFieldExceptionsCarrier<Cases = never> = {\n readonly [CRAFT_NODE_FIELD_EXCEPTIONS]?: Cases;\n};\n\n/**\n * Type-only carrier for the async sources a subtree reads through a\n * `settledValue` (directly, or through a `craftComputed` that consumed one with\n * `yield* settled(...)`).\n *\n * It is the pending twin of {@link CraftNodeExceptionsCarrier}: sources bubble up\n * from children to parents until a `pendingBlock` boundary clears them, and any\n * source still uncovered when the template reaches `craftComponent(...)` is a\n * compile error.\n */\nexport type CraftNodePendingCarrier<Sources extends string = string> = {\n readonly [CRAFT_NODE_PENDING]?: Sources;\n};\n\n/**\n * Type-only carrier for the exception codes a subtree can reach **through a\n * settled read** — codes that only become reachable because the template renders\n * the value, not because a component declared them.\n *\n * They travel apart from {@link CraftNodeExceptionsCarrier} on purpose:\n * `RequireCaughtComponentExceptions` fires on the children of the tag helper\n * that receives them, and a text binding has no place to host a boundary\n * (`span(userName)` would demand a `catchBlock` inside `span`'s own children).\n * These bubble silently instead, are cleared by any ancestor `catchBlock`, and\n * are checked once at `craftComponent(...)`.\n */\nexport type CraftNodeSettledExceptionsCarrier<Codes extends string = string> = {\n readonly [CRAFT_NODE_SETTLED_EXCEPTIONS]?: Codes;\n};\n\n/**\n * Type-only carrier for a relative heading outline. `heading()` marks a\n * subtree as needing a parent `headingSection` (or the route-level outline).\n * `headingSection` absorbs that need for its children.\n *\n * `'heading'` is a local `heading()` in this template (allowed on the\n * component that declares it). `'heading-from-child'` is a nested component\n * that still exposes an uncovered heading — the parent must wrap that call in\n * `headingSection`.\n */\nexport type CraftNodeHeadingNeedCarrier<Need extends string = never> = {\n readonly [CRAFT_NODE_HEADING_NEED]?: Need;\n};\n\nexport type ChildHeadingNeed = 'heading-from-child';\n\nexport type RemapToChildHeadingNeed<Need> = [Need] extends [never]\n ? never\n : string extends Need\n ? never\n : ChildHeadingNeed;\n\ntype UnionToIntersection<Union> = (\n Union extends any ? (value: Union) => void : never\n) extends (value: infer Intersection) => void\n ? Intersection\n : never;\n\ntype CraftNodeChildrenDependenciesOf<Value> =\n IsAny<Value> extends true\n ? {}\n : string extends Value\n ? {}\n : Value extends readonly (infer Child)[]\n ? CraftNodeChildrenDependenciesOf<Child>\n : Value extends object\n ? typeof CRAFT_NODE_DEPS extends keyof Value\n ? Value extends CraftNodeDepsCarrier<\n infer Dependencies extends object\n >\n ? IsAny<Dependencies> extends true\n ? {}\n : Dependencies\n : {}\n : {}\n : {};\n\nexport type CraftNodeChildrenDependencies<Value> = {\n [Key in keyof UnionToIntersection<\n CraftNodeChildrenDependenciesOf<Value>\n >]: UnionToIntersection<CraftNodeChildrenDependenciesOf<Value>>[Key];\n} & {};\n\ntype CraftNodeChildrenCssVarsOf<\n Value,\n Depth extends unknown[] = [],\n> = Depth['length'] extends 8\n ? never\n : IsAny<Value> extends true\n ? never\n : Value extends readonly (infer Child)[]\n ? CraftNodeChildrenCssVarsOf<Child, [...Depth, unknown]>\n : Value extends CraftNodeCssVarsCarrier<infer Contract>\n ? Contract\n : never;\n\ntype CssVarField<\n Contracts,\n Key extends keyof CssVarContract,\n> = Contracts extends CssVarContract ? Contracts[Key] : never;\n\nexport type CraftNodeChildrenCssVars<Value> = [CraftNodeChildren] extends [\n Value,\n]\n ? EmptyCssVarContract\n : IsAny<Value> extends true\n ? CssVarContract\n : [CraftNodeChildrenCssVarsOf<Value>] extends [never]\n ? EmptyCssVarContract\n : {\n readonly required: CssVarField<\n CraftNodeChildrenCssVarsOf<Value>,\n 'required'\n >;\n readonly optional: CssVarField<\n CraftNodeChildrenCssVarsOf<Value>,\n 'optional'\n >;\n readonly declared: CssVarField<\n CraftNodeChildrenCssVarsOf<Value>,\n 'declared'\n >;\n readonly inherited: CssVarField<\n CraftNodeChildrenCssVarsOf<Value>,\n 'inherited'\n >;\n readonly nonInherited: CssVarField<\n CraftNodeChildrenCssVarsOf<Value>,\n 'nonInherited'\n >;\n readonly unknownCss: true extends CssVarField<\n CraftNodeChildrenCssVarsOf<Value>,\n 'unknownCss'\n >\n ? true\n : false;\n };\n\nexport type CraftTextValue = string | number | bigint | boolean;\n\n/**\n * A text binding. Two shapes, both already supported by the renderer:\n *\n * - a plain read — `() => user.name()`;\n * - a generator — the projected form of a `craftComputed` bound by reference\n * (`span(fullName)`), whose yields carry its exception and pending markers.\n */\nexport type CraftTextBinding =\n | (() => CraftTextValue | null | undefined)\n | (() => Generator<any, CraftTextValue | null | undefined, any>);\n\ntype ElementNodeExceptions<\n Children extends CraftNodeChildren,\n Exceptions extends string,\n> =\n string extends CraftNodeChildrenExceptions<Children>\n ? Exceptions\n : CraftNodeChildrenExceptions<Children>;\n\n/**\n * The async sources an element still needs a `pendingBlock` for: the ones read\n * by its children, the ones bound to its own props, plus any inherited from a\n * node it was piped from.\n */\ntype ElementNodePendingSources<\n Props extends object,\n Children extends CraftNodeChildren,\n PendingSources extends string,\n> =\n | PendingSources\n | CraftNodeChildrenPendingSources<Children>\n | CraftNodeChildrenPendingSources<Props[keyof Props]>;\n\ntype ElementNodeSettledExceptions<\n Props extends object,\n Children extends CraftNodeChildren,\n SettledExceptions extends string,\n> =\n | SettledExceptions\n | CraftNodeChildrenSettledExceptions<Children>\n | CraftNodeChildrenSettledExceptions<Props[keyof Props]>;\n\nexport interface ElementNodeBase<\n Dependencies extends object = {},\n Tag extends string = string,\n Props extends object = Readonly<Record<string, unknown>>,\n Children extends CraftNodeChildren = CraftNodeChildren,\n LocalName extends string | undefined = string | undefined,\n Exceptions extends string = string,\n HandledExceptions extends string = string,\n FieldExceptions = unknown,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeExceptionsCarrier<ElementNodeExceptions<Children, Exceptions>>,\n CraftNodeHandledExceptionsCarrier<HandledExceptions>,\n CraftNodePendingCarrier<\n ElementNodePendingSources<Props, Children, PendingSources>\n >,\n CraftNodeSettledExceptionsCarrier<\n ElementNodeSettledExceptions<Props, Children, SettledExceptions>\n >,\n CraftNodeHeadingNeedCarrier<CraftNodeChildrenHeadingNeed<Children>>,\n CraftNodeFieldExceptionsCarrier<\n FieldExceptions | CraftNodeChildrenRawFieldExceptions<Children>\n > {\n readonly kind: 'element';\n readonly tag: Tag;\n readonly localName?: LocalName;\n readonly props: Props;\n readonly children: Children;\n readonly [CRAFT_NODE_DIRECTIVES]?: readonly AppliedCraftNodeDirective[];\n}\n\nexport interface ElementNode<\n Dependencies extends object = {},\n Tag extends string = string,\n Props extends object = Readonly<Record<string, unknown>>,\n Children extends CraftNodeChildren = CraftNodeChildren,\n LocalName extends string | undefined = string | undefined,\n Exceptions extends string = string,\n HandledExceptions extends string = string,\n FieldExceptions = never,\n CssVars extends CssVarContract = EmptyCssVarContract,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends ElementNodeBase<\n Dependencies,\n Tag,\n Props,\n Children,\n LocalName,\n Exceptions,\n HandledExceptions,\n FieldExceptions,\n PendingSources,\n SettledExceptions\n >,\n CraftNodeCssVarsCarrier<CssVars> {\n readonly [CRAFT_NODE_EXCEPTIONS]: ElementNodeExceptions<Children, Exceptions>;\n readonly [CRAFT_NODE_FIELD_EXCEPTIONS]:\n | FieldExceptions\n | CraftNodeChildrenRawFieldExceptions<Children>;\n readonly pipe: CraftNodePipe<\n Dependencies,\n ElementNodeExceptions<Children, Exceptions>,\n FieldExceptions | CraftNodeChildrenRawFieldExceptions<Children>,\n ElementNodePendingSources<Props, Children, PendingSources>,\n ElementNodeSettledExceptions<Props, Children, SettledExceptions>\n >;\n}\n\ntype PipedNode<\n Dependencies extends object,\n Exceptions extends string,\n FieldExceptions,\n Directive extends CraftDirective,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> =\n Directive extends PendingBlockDirective<\n infer Handlers extends PendingBlockHandlers | undefined,\n infer FallbackChildren extends CraftNodeChildren\n >\n ? PendingBlockNode<\n Dependencies | CraftNodeChildrenDependencies<FallbackChildren>,\n Exceptions | CraftNodeChildrenExceptions<FallbackChildren>,\n FieldExceptions | CraftNodeChildrenRawFieldExceptions<FallbackChildren>,\n | PendingBlockResidualSources<PendingSources, Handlers>\n // A fallback that suspends in turn needs a boundary of its own.\n | CraftNodeChildrenPendingSources<FallbackChildren>,\n // A pending boundary is not an exception boundary: settled exceptions\n // pass straight through it.\n SettledExceptions | CraftNodeChildrenSettledExceptions<FallbackChildren>\n >\n : PipedNodeWithoutPending<\n Dependencies,\n Exceptions,\n FieldExceptions,\n Directive,\n PendingSources,\n SettledExceptions\n >;\n\ntype PipedNodeWithoutPending<\n Dependencies extends object,\n Exceptions extends string,\n FieldExceptions,\n Directive extends CraftDirective,\n PendingSources extends string,\n SettledExceptions extends string,\n> =\n Directive extends FieldExceptionBlockDirective<\n infer FieldHandlers extends FieldExceptionHandlers,\n boolean\n >\n ? FieldExceptionBlockNode<\n Dependencies | CraftDirectiveTemplateDependencies<Directive>,\n | Exceptions\n | CraftNodeChildrenExceptions<\n FieldExceptionHandlerChildren<FieldHandlers[keyof FieldHandlers]>\n >,\n | ResidualFieldValidationCases<\n UnhandledFieldValidationCases<FieldExceptions>,\n FieldHandlers\n >\n | FieldExceptionHandlerFieldExceptions<FieldHandlers>\n | Extract<FieldExceptions, FieldValidationHandledIdentitiesCarrier<any>>\n | FieldValidationHandledIdentitiesCarrier<\n FieldValidationHandledIdentities<FieldExceptions, FieldHandlers>\n >,\n FieldHandlers,\n | PendingSources\n | CraftNodeChildrenPendingSources<\n FieldExceptionHandlerChildren<FieldHandlers[keyof FieldHandlers]>\n >,\n | SettledExceptions\n | CraftNodeChildrenSettledExceptions<\n FieldExceptionHandlerChildren<FieldHandlers[keyof FieldHandlers]>\n >\n >\n : Directive extends CatchBlockDirective<\n infer Handlers extends CatchBlockHandlers\n >\n ? CatchBlockNode<\n Dependencies | CraftDirectiveTemplateDependencies<Directive>,\n | Exclude<Exceptions, Extract<keyof Handlers, string>>\n | CraftNodeChildrenExceptions<\n CatchBlockHandlerChildren<Handlers[keyof Handlers]>\n >,\n Handlers,\n Directive[typeof CATCH_BLOCK_DIRECTIVE]['position'],\n FieldExceptions,\n | PendingSources\n | CraftNodeChildrenPendingSources<\n CatchBlockHandlerChildren<Handlers[keyof Handlers]>\n >,\n // The boundary clears the settled codes it handles, and inherits any\n // its own handlers reach.\n | Exclude<SettledExceptions, Extract<keyof Handlers, string>>\n | CraftNodeChildrenSettledExceptions<\n CatchBlockHandlerChildren<Handlers[keyof Handlers]>\n >\n >\n : CraftDirectiveNode<\n Dependencies | CraftDirectiveTemplateDependencies<Directive>,\n Exceptions,\n FieldExceptions,\n PendingSources,\n SettledExceptions\n >;\n\ntype PipedCraftNodeDirective<\n Dependencies extends object,\n Exceptions extends string,\n FieldExceptions,\n Directive extends CraftNodeDirective<any>,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> = ElementNode<\n Dependencies,\n string,\n Readonly<Record<string, unknown>>,\n CraftNodeChildren,\n string | undefined,\n Exceptions,\n string,\n FieldExceptions | FieldValidationCasesOf<Directive>,\n EmptyCssVarContract,\n PendingSources,\n SettledExceptions\n>;\n\nexport type CraftNodePipe<\n Dependencies extends object = {},\n Exceptions extends string = string,\n FieldExceptions = never,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> = {\n <Directive extends CraftDirective>(\n directive: (Directive extends ScheduleEachDirective ? never : Directive) &\n (Directive extends PendingBlockDirective<\n infer PendingHandlers extends PendingBlockHandlers | undefined,\n CraftNodeChildren\n >\n ? PendingHandlers extends PendingBlockHandlers\n ? PendingBlockExhaustiveCheck<PendingSources, PendingHandlers>\n : unknown\n : Directive extends CatchBlockDirective<\n infer Handlers extends CatchBlockHandlers\n >\n ? CatchTagExhaustiveCodesCheck<\n Exceptions | SettledExceptions,\n Record<Extract<keyof Handlers, string>, unknown>\n >\n : Directive extends FieldExceptionBlockDirective<\n infer FieldHandlers extends FieldExceptionHandlers,\n infer Exhaustive extends boolean\n >\n ? Exhaustive extends true\n ? [UnhandledFieldValidationCases<FieldExceptions>] extends [never]\n ? unknown\n : FieldExceptionBlockExhaustiveCheck<\n UnhandledFieldValidationCases<FieldExceptions>,\n FieldHandlers\n >\n : [UnhandledFieldValidationCases<FieldExceptions>] extends [never]\n ? unknown\n : FieldExceptionBlockPartialCheck<\n UnhandledFieldValidationCases<FieldExceptions>,\n FieldHandlers\n >\n : unknown),\n ): PipedNode<\n Dependencies,\n Exceptions,\n FieldExceptions,\n Directive,\n PendingSources,\n SettledExceptions\n >;\n <Directive extends CraftNodeDirective<any>>(\n directive: Directive,\n ): PipedCraftNodeDirective<\n Dependencies,\n Exceptions,\n FieldExceptions,\n Directive,\n PendingSources,\n SettledExceptions\n >;\n (directive: CraftHostType<unknown>): CraftNode;\n};\n\nexport type EachNodePipe<\n Dependencies extends object = {},\n Exceptions extends string = string,\n FieldExceptions = never,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n Item = unknown,\n Key = unknown,\n SourceName extends string | undefined = string | undefined,\n ItemChildren extends CraftNodeChildren = CraftNodeChildren,\n EmptyChildren extends CraftNodeChildren = CraftNodeChildren,\n Schedule extends EachSchedulePolicy | undefined =\n | EachSchedulePolicy\n | undefined,\n> = CraftNodePipe<\n Dependencies,\n Exceptions,\n FieldExceptions,\n PendingSources,\n SettledExceptions\n> & {\n <Policy extends EachSchedulePolicy>(\n directive: ScheduleEachDirective<Policy>,\n ): EachNode<\n Item,\n Key,\n Dependencies,\n SourceName,\n ItemChildren,\n EmptyChildren,\n Policy\n >;\n};\n\nexport interface AppliedCraftNodeDirective {\n readonly directive: CraftNodeDirective<any>;\n readonly inputs: Readonly<Record<string, unknown>>;\n}\n\nexport interface CraftDirectiveNode<\n Dependencies extends object = {},\n Exceptions extends string = string,\n FieldExceptions = unknown,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeExceptionsCarrier<Exceptions>,\n CraftNodePendingCarrier<PendingSources>,\n CraftNodeSettledExceptionsCarrier<SettledExceptions>,\n CraftNodeFieldExceptionsCarrier<FieldExceptions> {\n readonly [CRAFT_NODE_EXCEPTIONS]: Exceptions;\n readonly [CRAFT_NODE_FIELD_EXCEPTIONS]: FieldExceptions;\n readonly kind: 'directive';\n readonly node: CraftNode;\n readonly directives: readonly CraftDirective[];\n readonly pipe: CraftNodePipe<\n Dependencies,\n Exceptions,\n FieldExceptions,\n PendingSources,\n SettledExceptions\n >;\n}\n\nexport interface TextNode {\n readonly kind: 'text';\n readonly value: string;\n}\n\n/**\n * Internal VNode used to retain a text binding until it is mounted. Keeping\n * the callback intact lets the renderer give every binding its own reactive\n * effect instead of collecting its dependencies in the component render.\n */\nexport interface ReactiveTextNode {\n readonly kind: 'reactive-text';\n readonly binding: CraftTextBinding;\n}\n\nexport interface ComponentNode<\n Props extends object = object,\n ComponentDeps extends object = {},\n Component extends CraftComponent<\n any,\n ComponentDeps,\n any,\n any,\n any,\n any,\n any,\n any,\n any\n > = CraftComponent<any, ComponentDeps, any, any, any, any, any, any, any>,\n ContentDependencies extends object = ContentDependenciesFromProps<Props>,\n InputExceptions extends string = never,\n CssVars extends CssVarContract = EmptyCssVarContract,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends CraftNodeDepsCarrier<ComponentDeps & ContentDependencies>,\n CraftNodeCssVarsCarrier<CssVars>,\n CraftNodeExceptionsCarrier<\n ComponentInitializationExceptionsOf<Component> | InputExceptions\n >,\n CraftNodePendingCarrier<\n PendingSources | ContentPendingSourcesFromProps<Props>\n >,\n CraftNodeSettledExceptionsCarrier<\n SettledExceptions | ContentSettledExceptionsFromProps<Props>\n >,\n CraftNodeHeadingNeedCarrier<\n RemapToChildHeadingNeed<\n ComponentHeadingNeedOf<Component> | ContentHeadingNeedFromProps<Props>\n >\n >,\n CraftNodeFieldExceptionsCarrier<\n | ComponentFieldExceptionsOf<Component>\n | ContentFieldExceptionsFromProps<Props>\n > {\n readonly kind: 'component';\n readonly component: Component;\n readonly props: Props;\n /** Optional route/feature injector used as this component's DI parent. */\n readonly injector?: HostInjector;\n readonly declarationContext?: unknown;\n readonly [CRAFT_NODE_EXCEPTIONS]:\n | ComponentInitializationExceptionsOf<Component>\n | InputExceptions;\n readonly [CRAFT_NODE_FIELD_EXCEPTIONS]:\n | ComponentFieldExceptionsOf<Component>\n | ContentFieldExceptionsFromProps<Props>;\n readonly pipe: CraftNodePipe<\n ComponentDeps & ContentDependencies,\n ComponentInitializationExceptionsOf<Component> | InputExceptions,\n | ComponentFieldExceptionsOf<Component>\n | ContentFieldExceptionsFromProps<Props>,\n PendingSources | ContentPendingSourcesFromProps<Props>,\n SettledExceptions | ContentSettledExceptionsFromProps<Props>\n >;\n}\n\nexport interface CatchBlockNode<\n Dependencies extends object = {},\n Exceptions extends string = string,\n Handlers extends CatchBlockHandlers = CatchBlockHandlers,\n Position extends CatchBlockPosition = CatchBlockPosition,\n FieldExceptions = unknown,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeExceptionsCarrier<Exceptions>,\n CraftNodeHandledExceptionsCarrier<Extract<keyof Handlers, string>>,\n CraftNodePendingCarrier<PendingSources>,\n CraftNodeSettledExceptionsCarrier<SettledExceptions>,\n CraftNodeFieldExceptionsCarrier<FieldExceptions> {\n readonly kind: 'catch-block';\n readonly source: CraftNode;\n readonly handlers: Handlers;\n readonly position: Position;\n}\n\nexport interface FieldExceptionBlockNode<\n Dependencies extends object = {},\n Exceptions extends string = string,\n FieldExceptions = never,\n Handlers extends FieldExceptionHandlers = FieldExceptionHandlers,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeExceptionsCarrier<Exceptions>,\n CraftNodePendingCarrier<PendingSources>,\n CraftNodeSettledExceptionsCarrier<SettledExceptions>,\n CraftNodeFieldExceptionsCarrier<FieldExceptions> {\n readonly kind: 'field-exception-block';\n readonly [CRAFT_NODE_FIELD_EXCEPTIONS]: FieldExceptions;\n readonly source: CraftNodeChildren;\n readonly handlers: Handlers;\n readonly options: Required<\n Pick<FieldExceptionBlockOptions, 'mode' | 'position'>\n > &\n Pick<FieldExceptionBlockOptions, 'visibility'>;\n readonly pipe: CraftNodePipe<\n Dependencies,\n Exceptions,\n FieldExceptions,\n PendingSources,\n SettledExceptions\n >;\n}\n\nexport interface MatchBlockNode<\n Dependencies extends object = {},\n Source extends ((...args: any[]) => unknown) | object = () =>\n | object\n | undefined,\n Children extends CraftNodeChildren = CraftNodeChildren,\n HandledExceptions extends string = string,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeHandledExceptionsCarrier<HandledExceptions>,\n CraftNodePendingCarrier<CraftNodeChildrenPendingSources<Children>>,\n CraftNodeSettledExceptionsCarrier<\n CraftNodeChildrenSettledExceptions<Children>\n > {\n readonly kind: 'match-block';\n readonly source: Source;\n readonly key: PropertyKey;\n readonly handlers: Record<string, (exception: AnyCraftException) => Children>;\n}\n\nexport interface EachNode<\n Item = unknown,\n Key = unknown,\n Dependencies extends object = {},\n SourceName extends string | undefined = string | undefined,\n ItemChildren extends CraftNodeChildren = CraftNodeChildren,\n EmptyChildren extends CraftNodeChildren = CraftNodeChildren,\n Schedule extends EachSchedulePolicy | undefined =\n | EachSchedulePolicy\n | undefined,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeCssVarsCarrier<\n CraftNodeChildrenCssVars<ItemChildren | EmptyChildren>\n >,\n CraftNodePendingCarrier<\n | CraftNodeChildrenPendingSources<ItemChildren>\n | CraftNodeChildrenPendingSources<EmptyChildren>\n >,\n CraftNodeSettledExceptionsCarrier<\n | CraftNodeChildrenSettledExceptions<ItemChildren>\n | CraftNodeChildrenSettledExceptions<EmptyChildren>\n >,\n CraftNodeHeadingNeedCarrier<\n | CraftNodeChildrenHeadingNeed<ItemChildren>\n | CraftNodeChildrenHeadingNeed<EmptyChildren>\n >,\n CraftNodeFieldExceptionsCarrier<\n | CraftNodeChildrenRawFieldExceptions<ItemChildren>\n | CraftNodeChildrenRawFieldExceptions<EmptyChildren>\n > {\n readonly kind: 'each';\n readonly source:\n | readonly Item[]\n | null\n | undefined\n | (() => readonly Item[] | null | undefined)\n | (() => Generator<unknown, readonly Item[] | null | undefined, unknown>);\n readonly sourceName?: SourceName;\n readonly track: (item: Item, index: number) => Key;\n readonly empty?: () => EmptyChildren;\n readonly schedule?: Schedule;\n readonly itemTemplate: (\n item: InputValue<Item>,\n index: number,\n ) => ItemChildren;\n readonly pipe: EachNodePipe<\n Dependencies,\n CraftNodeChildrenExceptions<ItemChildren | EmptyChildren>,\n CraftNodeChildrenRawFieldExceptions<ItemChildren | EmptyChildren>,\n | CraftNodeChildrenPendingSources<ItemChildren>\n | CraftNodeChildrenPendingSources<EmptyChildren>,\n CraftNodeChildrenSettledExceptions<ItemChildren | EmptyChildren>,\n Item,\n Key,\n SourceName,\n ItemChildren,\n EmptyChildren,\n Schedule\n >;\n}\n\nexport interface IfBlockNode<\n ConditionName extends string = string,\n Dependencies extends object = {},\n TrueChildren extends CraftNodeChildren = CraftNodeChildren,\n FalseChildren extends CraftNodeChildren = CraftNodeChildren,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeCssVarsCarrier<\n CraftNodeChildrenCssVars<TrueChildren | FalseChildren>\n >,\n CraftNodePendingCarrier<\n | CraftNodeChildrenPendingSources<TrueChildren>\n | CraftNodeChildrenPendingSources<FalseChildren>\n >,\n CraftNodeSettledExceptionsCarrier<\n | CraftNodeChildrenSettledExceptions<TrueChildren>\n | CraftNodeChildrenSettledExceptions<FalseChildren>\n >,\n CraftNodeHeadingNeedCarrier<\n | CraftNodeChildrenHeadingNeed<TrueChildren>\n | CraftNodeChildrenHeadingNeed<FalseChildren>\n >,\n CraftNodeFieldExceptionsCarrier<\n | CraftNodeChildrenRawFieldExceptions<TrueChildren>\n | CraftNodeChildrenRawFieldExceptions<FalseChildren>\n > {\n readonly kind: 'if';\n readonly condition: () => boolean;\n readonly conditionName: ConditionName;\n readonly whenTrue: () => TrueChildren;\n readonly whenFalse?: () => FalseChildren;\n}\n\n/**\n * Relative heading. The runtime picks `h1`–`h6` from the current outline\n * level. The node brands the subtree as needing a parent outline.\n */\nexport interface HeadingNode<\n Dependencies extends object = {},\n Children extends CraftNodeChildren = CraftNodeChildren,\n Props extends object = Readonly<Record<string, unknown>>,\n Need extends string = never,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeCssVarsCarrier<CraftNodeChildrenCssVars<Children>>,\n CraftNodePendingCarrier<CraftNodeChildrenPendingSources<Children>>,\n CraftNodeSettledExceptionsCarrier<\n CraftNodeChildrenSettledExceptions<Children>\n >,\n CraftNodeHeadingNeedCarrier<Need>,\n CraftNodeFieldExceptionsCarrier<\n CraftNodeChildrenRawFieldExceptions<Children>\n > {\n readonly kind: 'heading';\n readonly props: Props;\n readonly children: Children;\n readonly pipe: CraftNodePipe<\n Dependencies,\n CraftNodeChildrenExceptions<Children>,\n CraftNodeChildrenRawFieldExceptions<Children>,\n CraftNodeChildrenPendingSources<Children>,\n CraftNodeChildrenSettledExceptions<Children>\n >;\n}\n\n/**\n * Increments the heading outline for its subtree without a DOM wrapper.\n * Absorbs children's heading need — the parent established the outline.\n * `reset: true` (`headingRoot`) starts the outline at level 1 instead of\n * incrementing — used by route pages and skip-link shells.\n */\nexport interface HeadingSectionNode<\n Dependencies extends object = {},\n Children extends CraftNodeChildren = CraftNodeChildren,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeCssVarsCarrier<CraftNodeChildrenCssVars<Children>>,\n CraftNodePendingCarrier<CraftNodeChildrenPendingSources<Children>>,\n CraftNodeSettledExceptionsCarrier<\n CraftNodeChildrenSettledExceptions<Children>\n >,\n CraftNodeHeadingNeedCarrier<never>,\n CraftNodeFieldExceptionsCarrier<\n CraftNodeChildrenRawFieldExceptions<Children>\n > {\n readonly kind: 'heading-section';\n readonly reset?: boolean;\n readonly children: Children;\n}\n\nexport type DeferTrigger = 'immediate' | 'idle' | 'viewport' | 'interaction';\n\nexport interface DeferNode<\n Loaded = unknown,\n Dependencies extends object = {},\n Children extends CraftNodeChildren = CraftNodeChildren,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeCssVarsCarrier<CraftNodeChildrenCssVars<Children>>,\n CraftNodePendingCarrier<CraftNodeChildrenPendingSources<Children>>,\n CraftNodeSettledExceptionsCarrier<\n CraftNodeChildrenSettledExceptions<Children>\n >,\n CraftNodeHeadingNeedCarrier<CraftNodeChildrenHeadingNeed<Children>>,\n CraftNodeFieldExceptionsCarrier<\n CraftNodeChildrenRawFieldExceptions<Children>\n > {\n readonly kind: 'defer';\n readonly loader: (helpers: CraftLazyLoadHelpers) => Promise<Loaded>;\n readonly resolve: (loaded: Loaded) => CraftNodeChildren;\n readonly trigger: DeferTrigger;\n readonly placeholder?: () => CraftNodeChildren;\n readonly loading?: () => CraftNodeChildren;\n readonly error?: (error: unknown) => CraftNodeChildren;\n}\n\n/**\n * A suspension boundary. Its source subtree stays mounted while it is pending —\n * hidden, not destroyed — and the fallback is inserted next to it.\n */\nexport interface PendingBlockNode<\n Dependencies extends object = {},\n Exceptions extends string = string,\n FieldExceptions = unknown,\n PendingSources extends string = never,\n SettledExceptions extends string = never,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeExceptionsCarrier<Exceptions>,\n CraftNodePendingCarrier<PendingSources>,\n CraftNodeSettledExceptionsCarrier<SettledExceptions>,\n CraftNodeFieldExceptionsCarrier<FieldExceptions> {\n readonly [CRAFT_NODE_EXCEPTIONS]: Exceptions;\n readonly kind: 'pending-block';\n readonly source: CraftNode;\n readonly handlers: PendingBlockHandlers | undefined;\n readonly fallback: PendingFallback | undefined;\n readonly reloading: PendingFallback | undefined;\n readonly position: PendingBlockPosition;\n readonly ssr: SsrMode | undefined;\n readonly pipe: CraftNodePipe<\n Dependencies,\n Exceptions,\n FieldExceptions,\n PendingSources,\n SettledExceptions\n >;\n}\n\nexport type CraftNode =\n | ElementNodeBase<any>\n | TextNode\n | ReactiveTextNode\n | ComponentNode<any, any, any, any, any, any>\n | CraftDirectiveNode<any>\n | EachNode<any, any, any, any, any, any>\n | IfBlockNode<any, any, any, any>\n | HeadingNode<any, any, any>\n | HeadingSectionNode<any, any>\n | DeferNode<any, any, any>\n | CatchBlockNode<any, any>\n | PendingBlockNode<any, any, any, any>\n | FieldExceptionBlockNode<any, any, any>\n | MatchBlockNode<any, any>\n | ProjectionNode<any, any>\n | TemplateNode<any, any, any>;\n\nexport type CraftNodeChild =\n | CraftNode\n // Keep generic node specialisations assignable even when their type-only\n // carriers contain narrower contracts than the broad CraftNode union.\n | { readonly kind: CraftNode['kind'] }\n | CraftTextValue\n | CraftTextBinding\n | null\n | undefined\n | readonly CraftNodeChild[];\n\nexport type CraftNodeChildren = CraftNodeChild | readonly CraftNodeChild[];\n\ntype ContentChildrenFromProps<Props extends object> =\n Props[keyof Props] extends infer Value\n ? Value extends (...args: any[]) => infer Output\n ? Output\n : Value extends readonly (infer Item)[]\n ? Item\n : Value extends CraftNode\n ? Value\n : never\n : never;\n\nexport type ContentDependenciesFromProps<Props extends object> =\n CraftNodeChildrenDependencies<ContentChildrenFromProps<Props>>;\n\nexport type ContentFieldExceptionsFromProps<Props extends object> =\n CraftNodeChildrenRawFieldExceptions<ContentChildrenFromProps<Props>>;\n\n/**\n * Async sources read by content a caller projects into a component. They are the\n * caller's responsibility: the nodes are declared in the caller's template, so\n * the boundary belongs there too.\n */\nexport type ContentPendingSourcesFromProps<Props extends object> =\n CraftNodeChildrenPendingSources<ContentChildrenFromProps<Props>>;\n\n/** Settled exceptions reachable through content a caller projects in. */\nexport type ContentSettledExceptionsFromProps<Props extends object> =\n CraftNodeChildrenSettledExceptions<ContentChildrenFromProps<Props>>;\n\nexport type ContentHeadingNeedFromProps<Props extends object> =\n CraftNodeChildrenHeadingNeed<ContentChildrenFromProps<Props>>;\n\nexport type ComponentHeadingNeedOf<Component> =\n Component extends CraftComponent<any, any, any, any, any, any, infer Template>\n ? Template extends (...args: any[]) => infer Output\n ? CraftNodeChildrenHeadingNeed<Output>\n : never\n : never;\n\nexport interface ProjectionNode<\n Dependencies extends object = {},\n Output extends CraftNodeChildren = CraftNodeChildren,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodeCssVarsCarrier<CraftNodeChildrenCssVars<Output>>,\n CraftNodePendingCarrier<CraftNodeChildrenPendingSources<Output>>,\n CraftNodeSettledExceptionsCarrier<\n CraftNodeChildrenSettledExceptions<Output>\n >,\n CraftNodeFieldExceptionsCarrier<\n CraftNodeChildrenRawFieldExceptions<Output>\n > {\n readonly kind: 'projection';\n readonly render: () => Output;\n readonly slotName?: string;\n readonly stylePolicy: ContentStylePolicy;\n readonly declarationContext?: unknown;\n}\n\nexport interface TemplateNode<\n Context = unknown,\n Output extends CraftNodeChildren = CraftNodeChildren,\n Dependencies extends object = CraftNodeChildrenDependencies<Output>,\n> extends CraftNodeDepsCarrier<Dependencies>,\n CraftNodePendingCarrier<CraftNodeChildrenPendingSources<Output>>,\n CraftNodeSettledExceptionsCarrier<\n CraftNodeChildrenSettledExceptions<Output>\n > {\n readonly __craftNodeCssVars__?: CraftNodeChildrenCssVars<Output>;\n readonly [CRAFT_NODE_FIELD_EXCEPTIONS]?: CraftNodeChildrenRawFieldExceptions<Output>;\n readonly kind: 'template';\n readonly template: CraftTemplate<Context, Output>;\n readonly context: Context;\n readonly declarationContext?: unknown;\n}\n\n/** The yields of a child written as (or projected to) a generator callback. */\ntype ChildBindingYielded<Value> = Value extends (\n ...args: any[]\n) => Generator<infer Yielded, any, any>\n ? Yielded\n : never;\n\n// NOTE — the exceptions a settled read may raise are deliberately NOT folded in\n// here. `RequireCaughtComponentExceptions` fires on the children of the tag\n// helper that receives them, and a text binding has no place to put a boundary:\n// `span(userName)` would demand a `catchBlock` inside `span`'s own children.\n// They are routed at runtime instead (to the nearest `catchBlock`, else\n// `CraftUnhandledExceptionError`); a deferred compile-time channel for them,\n// checked at `craftComponent` like the pending one, is the next iteration.\ntype CraftNodeDirectExceptions<Value> =\n IsAny<Value> extends true\n ? never\n : Value extends CraftNodeExceptionsCarrier<infer Exceptions>\n ? string extends Exceptions\n ? never\n : Exceptions\n : never;\n\nexport type CraftNodeChildrenExceptions<Value> = Value extends unknown\n ? Value extends readonly (infer Child)[]\n ? CraftNodeDirectExceptions<Child>\n : CraftNodeDirectExceptions<Value>\n : never;\n\ntype CraftNodeDirectPendingSources<Value> =\n IsAny<Value> extends true\n ? never\n : // Either a bound `settledValue` / async `craftComputed` (branded signal),\n // or a child node that still carries uncovered sources of its own.\n | CraftSettledSourcesOf<Value>\n | ExtractCraftPendingSources<ChildBindingYielded<Value>>\n | (Value extends CraftNodePendingCarrier<infer Sources>\n ? string extends Sources\n ? never\n : Sources\n : never);\n\nexport type CraftNodeChildrenPendingSources<Value> = Value extends unknown\n ? Value extends readonly (infer Child)[]\n ? CraftNodeDirectPendingSources<Child>\n : CraftNodeDirectPendingSources<Value>\n : never;\n\ntype CraftNodeDirectSettledExceptions<Value> =\n IsAny<Value> extends true\n ? never\n : // A bound `settledValue` carries its source's exceptions; through the\n // template context an async `craftComputed` is projected to a generator\n // callback, so the same markers arrive on its yields instead.\n | CraftSettledCodesOf<Value>\n | Extract<\n ExtractCraftGenExceptions<ChildBindingYielded<Value>>,\n { readonly _tag: string }\n >['_tag']\n | (Value extends CraftNodeSettledExceptionsCarrier<infer Codes>\n ? string extends Codes\n ? never\n : Codes\n : never);\n\nexport type CraftNodeChildrenSettledExceptions<Value> = Value extends unknown\n ? Value extends readonly (infer Child)[]\n ? CraftNodeDirectSettledExceptions<Child>\n : CraftNodeDirectSettledExceptions<Value>\n : never;\n\ntype CraftNodeDirectHeadingNeed<Value> =\n IsAny<Value> extends true\n ? never\n : Value extends CraftNodeHeadingNeedCarrier<infer Need>\n ? string extends Need\n ? never\n : Need\n : never;\n\nexport type CraftNodeChildrenHeadingNeed<Value> = Value extends unknown\n ? Value extends readonly (infer Child)[]\n ? CraftNodeDirectHeadingNeed<Child>\n : CraftNodeDirectHeadingNeed<Value>\n : never;\n\ntype CraftNodeDirectFieldExceptions<Value> =\n IsAny<Value> extends true\n ? never\n : Value extends CraftNodeFieldExceptionsCarrier<infer Cases>\n ? IsAny<Cases> extends true\n ? never\n : unknown extends Cases\n ? never\n : Exclude<Cases, undefined>\n : never;\n\nexport type CraftNodeChildrenRawFieldExceptions<Value> = Value extends unknown\n ? Value extends readonly (infer Child)[]\n ? CraftNodeDirectFieldExceptions<Child>\n : CraftNodeDirectFieldExceptions<Value>\n : never;\n\nexport type CraftNodeChildrenFieldExceptions<Value> =\n UnhandledFieldValidationCases<CraftNodeChildrenRawFieldExceptions<Value>>;\n\ntype CraftNodeDirectHandledExceptionCodes<Value> =\n IsAny<Value> extends true\n ? never\n : Value extends CraftNodeHandledExceptionsCarrier<\n infer Codes extends string\n >\n ? string extends Codes\n ? never\n : Codes\n : never;\n\nexport type CraftNodeChildrenHandledExceptionCodes<Value> =\n Value extends unknown\n ? Value extends readonly (infer Child)[]\n ? CraftNodeDirectHandledExceptionCodes<Child>\n : CraftNodeDirectHandledExceptionCodes<Value>\n : never;\n\n/** A template child is renderable only after its component exceptions are handled. */\ntype RequireCaughtInitializationExceptions<Children extends CraftNodeChildren> =\n IsAny<CraftNodeChildrenExceptions<Children>> extends true\n ? unknown\n : [CraftNodeChildrenExceptions<Children>] extends [never]\n ? unknown\n : {\n 'catchTag.exhaustive or catchBlock.exhaustive is required before rendering component exceptions': CraftNodeChildrenExceptions<Children>;\n };\n\ntype DirectComponentFieldExceptions<Value> =\n IsAny<Value> extends true\n ? never\n : Value extends ComponentNode<any, any, infer Component>\n ? ComponentFieldExceptionsOf<Component> extends infer Cases\n ? IsAny<Cases> extends true\n ? never\n : Cases\n : never\n : never;\n\ntype ComponentFieldExceptionsInChildren<Value> =\n Value extends readonly (infer Child)[]\n ? DirectComponentFieldExceptions<Child>\n : DirectComponentFieldExceptions<Value>;\n\ntype RequireHandledComponentFieldExceptions<\n Children extends CraftNodeChildren,\n> =\n unknown extends ComponentFieldExceptionsInChildren<Children>\n ? unknown\n : [ComponentFieldExceptionsInChildren<Children>] extends [never]\n ? unknown\n : {\n 'fieldExceptionBlock.exhaustive is required before rendering component field exceptions': ComponentFieldExceptionsInChildren<Children>;\n };\n\nexport type RequireCaughtComponentExceptions<\n Children extends CraftNodeChildren,\n> = RequireCaughtInitializationExceptions<Children> &\n RequireHandledComponentFieldExceptions<Children>;\n\nexport function isCraftNode(value: unknown): value is CraftNode {\n if (typeof value !== 'object' || value === null || !('kind' in value)) {\n return false;\n }\n\n return (\n value.kind === 'element' ||\n value.kind === 'text' ||\n value.kind === 'component' ||\n value.kind === 'angular' ||\n value.kind === 'directive' ||\n value.kind === 'each' ||\n value.kind === 'if' ||\n value.kind === 'heading' ||\n value.kind === 'heading-section' ||\n value.kind === 'defer' ||\n value.kind === 'catch-block' ||\n value.kind === 'pending-block' ||\n value.kind === 'field-exception-block' ||\n value.kind === 'match-block' ||\n value.kind === 'projection' ||\n value.kind === 'template'\n );\n}\n\nfunction withPipe(node: any): any {\n return {\n ...node,\n pipe: ((\n directive:\n | CraftDirective\n | CraftNodeDirective<any>\n | ScheduleEachDirective\n | CraftHostType<unknown>,\n ) => pipeCraftNode(node as CraftNode, directive)) as CraftNodePipe,\n };\n}\n\nexport function pipeCraftNode(\n node: CraftNode,\n directive:\n | CraftDirective\n | CraftNodeDirective<any>\n | ScheduleEachDirective\n | CraftHostType<unknown>,\n): CraftNode {\n if (isScheduleEachDirective(directive)) {\n if (node.kind !== 'each') {\n throw new TypeError(\n 'scheduleEach(...) can only be piped onto an each(...) block.',\n );\n }\n return withPipe({\n ...node,\n schedule: directive[SCHEDULE_EACH_DIRECTIVE],\n });\n }\n\n if (isCraftNodeDirective(directive)) {\n node = applyCraftNodeDirective(node, directive);\n if (!isCraftDirective(directive)) {\n return node;\n }\n }\n\n if (!isCraftDirective(directive)) {\n if (node.kind === 'directive') {\n return withPipe({\n ...node,\n node: pipeCraftNode(node.node, directive),\n });\n }\n\n // Only Craft directives are applicable; anything else is a no-op now that\n // Angular directive definitions (`ɵdir`) are gone.\n return node;\n }\n\n const catchBlockDefinition = (\n directive as Partial<Record<typeof CATCH_BLOCK_DIRECTIVE, unknown>>\n )[CATCH_BLOCK_DIRECTIVE];\n if (catchBlockDefinition) {\n const definition = catchBlockDefinition as {\n readonly handlers: CatchBlockHandlers;\n readonly position: CatchBlockPosition;\n };\n return {\n kind: 'catch-block',\n source: node,\n handlers: definition.handlers,\n position: definition.position,\n } as CatchBlockNode;\n }\n\n const pendingBlockDefinition = (\n directive as Partial<Record<typeof PENDING_BLOCK_DIRECTIVE, unknown>>\n )[PENDING_BLOCK_DIRECTIVE];\n if (pendingBlockDefinition) {\n const definition = pendingBlockDefinition as {\n readonly handlers: PendingBlockHandlers | undefined;\n readonly fallback: PendingFallback | undefined;\n readonly reloading: PendingFallback | undefined;\n readonly position: PendingBlockPosition;\n readonly ssr: SsrMode | undefined;\n };\n return withPipe({\n kind: 'pending-block',\n source: node,\n handlers: definition.handlers,\n fallback: definition.fallback,\n reloading: definition.reloading,\n position: definition.position,\n ssr: definition.ssr,\n } as PendingBlockNode);\n }\n\n const fieldExceptionBlockDefinition = (\n directive as Partial<\n Record<typeof FIELD_EXCEPTION_BLOCK_DIRECTIVE, unknown>\n >\n )[FIELD_EXCEPTION_BLOCK_DIRECTIVE];\n if (fieldExceptionBlockDefinition) {\n const definition = fieldExceptionBlockDefinition as {\n readonly handlers: FieldExceptionHandlers;\n readonly options: FieldExceptionBlockNode['options'];\n };\n return withPipe({\n kind: 'field-exception-block',\n source: node,\n handlers: definition.handlers,\n options: definition.options,\n } as FieldExceptionBlockNode);\n }\n\n if (node.kind === 'directive') {\n return withPipe({\n ...node,\n directives: [...node.directives, directive],\n });\n }\n\n return withPipe({\n kind: 'directive',\n node,\n directives: [directive],\n });\n}\n\nfunction applyCraftNodeDirective(\n node: CraftNode,\n directive: CraftNodeDirective<any>,\n): CraftNode {\n if (node.kind === 'directive') {\n return withPipe({\n ...node,\n node: applyCraftNodeDirective(node.node, directive),\n });\n }\n\n if (node.kind !== 'element') return node;\n\n const definition = directive[CRAFT_NODE_DIRECTIVE];\n const props = { ...node.props } as Record<string, unknown>;\n const inputs = Object.fromEntries(\n definition.inputs\n .filter((name) => name in props)\n .map((name) => [name, props[name]]),\n );\n definition.inputs.forEach((name) => delete props[name]);\n\n return withPipe({\n ...node,\n props,\n [CRAFT_NODE_DIRECTIVES]: [\n ...(node[CRAFT_NODE_DIRECTIVES] ?? []),\n { directive, inputs },\n ],\n });\n}\n\nfunction resolveHostValue(value: unknown): unknown {\n return typeof value === 'function' ? value() : value;\n}\n\nfunction hasHostBinding(value: unknown, seen = new Set<object>()): boolean {\n if (typeof value === 'function') return true;\n if (typeof value !== 'object' || value === null || seen.has(value)) {\n return false;\n }\n seen.add(value);\n return Object.values(value).some((child) => hasHostBinding(child, seen));\n}\n\nfunction classTokens(value: unknown): string[] {\n const resolved = resolveHostValue(value);\n if (Array.isArray(resolved)) {\n return resolved.flatMap((item) => classTokens(item));\n }\n if (typeof resolved === 'object' && resolved !== null) {\n return Object.entries(resolved)\n .filter(([, enabled]) => enabled)\n .map(([name]) => name);\n }\n return resolved == null || resolved === false\n ? []\n : String(resolved).split(/\\s+/).filter(Boolean);\n}\n\nfunction mergeResolvedClasses(\n left: unknown,\n right: unknown,\n): string | undefined {\n const classes = [...classTokens(left), ...classTokens(right)];\n return classes.length ? [...new Set(classes)].join(' ') : undefined;\n}\n\nfunction mergeClasses(left: unknown, right: unknown): unknown {\n return hasHostBinding(left) || hasHostBinding(right)\n ? () => mergeResolvedClasses(left, right)\n : mergeResolvedClasses(left, right);\n}\n\nfunction mergeResolvedStyles(left: unknown, right: unknown): unknown {\n const resolvedLeft = resolveHostValue(left);\n const resolvedRight = resolveHostValue(right);\n if (\n typeof resolvedLeft === 'object' &&\n resolvedLeft !== null &&\n typeof resolvedRight === 'object' &&\n resolvedRight !== null\n ) {\n return { ...resolvedLeft, ...resolvedRight };\n }\n if (resolvedRight === undefined || resolvedRight === null) {\n return resolvedLeft;\n }\n if (typeof resolvedLeft === 'string' && typeof resolvedRight === 'string') {\n return `${resolvedLeft.replace(/;?\\s*$/, ';')}${resolvedRight}`;\n }\n return resolvedRight;\n}\n\nfunction mergeStyles(left: unknown, right: unknown): unknown {\n return hasHostBinding(left) || hasHostBinding(right)\n ? () => mergeResolvedStyles(left, right)\n : mergeResolvedStyles(left, right);\n}\n\nexport function mergeHostProps(\n base: Readonly<Record<string, unknown>>,\n added: Readonly<Record<string, unknown>>,\n): Readonly<Record<string, unknown>> {\n const merged = { ...base, ...added };\n const classes = mergeClasses(base['class'], added['class']);\n if (classes === undefined) {\n delete merged['class'];\n } else {\n merged['class'] = classes;\n }\n if ('style' in base || 'style' in added) {\n merged['style'] = mergeStyles(base['style'], added['style']);\n }\n return merged;\n}\n\nfunction addHostPropsToNode(\n node: CraftNode,\n props: Readonly<Record<string, unknown>>,\n applied: { value: boolean },\n): CraftNode {\n if (applied.value) {\n return node;\n }\n\n if (node.kind === 'element') {\n applied.value = true;\n return withPipe({\n ...node,\n props: mergeHostProps(node.props, props),\n });\n }\n\n if (node.kind === 'component') {\n applied.value = true;\n return {\n ...node,\n props: mergeHostProps(node.props, props),\n } as ComponentNode;\n }\n\n if (node.kind === 'directive') {\n return withPipe({\n ...node,\n node: addHostPropsToNode(node.node, props, applied),\n });\n }\n\n return node;\n}\n\n/** Adds host properties to the first host node produced by a template. */\nexport function applyHostPropsToChildren(\n children: CraftNodeChildren,\n props: Readonly<Record<string, unknown>> | undefined,\n): CraftNodeChildren {\n if (!props || Object.keys(props).length === 0) {\n return children;\n }\n\n const applied = { value: false };\n const visit = (child: CraftNodeChild): CraftNodeChild => {\n if (Array.isArray(child)) {\n return child.map(visit);\n }\n return isCraftNode(child)\n ? addHostPropsToNode(child, props, applied)\n : child;\n };\n return visit(children);\n}\n\nexport function normalizeChildren(children: CraftNodeChildren): CraftNode[] {\n const result: CraftNode[] = [];\n\n const visit = (child: CraftNodeChild): void => {\n if (Array.isArray(child)) {\n child.forEach(visit);\n return;\n }\n\n if (child === null || child === undefined || child === false) {\n return;\n }\n\n if (isCraftNode(child)) {\n result.push(child);\n return;\n }\n\n if (typeof child === 'function') {\n result.push({\n kind: 'reactive-text',\n binding: child,\n });\n return;\n }\n\n const resolved = child;\n if (resolved === null || resolved === undefined) {\n return;\n }\n\n result.push({\n kind: 'text',\n value: String(resolved),\n });\n };\n\n visit(children);\n return result;\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type CraftInjector, type CraftTransferSnapshot } from '@craft-ts/core';
|
|
2
|
+
import { type CraftComponent, type PropsOf } from './types';
|
|
3
|
+
export declare const CRAFT_TRANSFER_SCRIPT_ID = "__CRAFT_TRANSFER__";
|
|
4
|
+
export type RenderCraftOptions = Readonly<{
|
|
5
|
+
config: {
|
|
6
|
+
readonly providers: readonly unknown[];
|
|
7
|
+
};
|
|
8
|
+
url?: string;
|
|
9
|
+
props?: object;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
includeStyles?: boolean;
|
|
13
|
+
includeSnapshotScript?: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
export type RenderCraftResult = Readonly<{
|
|
16
|
+
html: string;
|
|
17
|
+
rootHtml: string;
|
|
18
|
+
styles: string;
|
|
19
|
+
snapshot: CraftTransferSnapshot;
|
|
20
|
+
}>;
|
|
21
|
+
/** Renders one fully isolated Craft application request to deterministic HTML. */
|
|
22
|
+
export declare function renderCraft(options: RenderCraftOptions): Promise<RenderCraftResult>;
|
|
23
|
+
export type RenderToStringOptions<Component extends CraftComponent<any>> = Readonly<{
|
|
24
|
+
props?: PropsOf<Component>;
|
|
25
|
+
providers?: readonly unknown[];
|
|
26
|
+
url?: string;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
signal?: AbortSignal;
|
|
29
|
+
}>;
|
|
30
|
+
/** Low-level component convenience API built on the same per-request runtime. */
|
|
31
|
+
export declare function renderToString<Component extends CraftComponent<any>>(component: Component, options?: RenderToStringOptions<Component>): Promise<string>;
|
|
32
|
+
/** Kept type-visible for adapters that need to share the request injector. */
|
|
33
|
+
export type CraftServerInjector = CraftInjector;
|
|
34
|
+
//# sourceMappingURL=server-render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-render.d.ts","sourceRoot":"","sources":["../../../../../libs/component/src/lib/server-render.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,gBAAgB,CAAC;AAcxB,OAAO,EAAmB,KAAK,cAAc,EAAE,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAE7E,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,MAAM,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,SAAS,OAAO,EAAE,CAAA;KAAE,CAAC;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,QAAQ,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,qBAAqB,CAAC;CACjC,CAAC,CAAC;AAEH,kFAAkF;AAClF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,iBAAiB,CAAC,CAoE5B;AAED,MAAM,MAAM,qBAAqB,CAAC,SAAS,SAAS,cAAc,CAAC,GAAG,CAAC,IACrE,QAAQ,CAAC;IACP,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3B,SAAS,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC,CAAC;AAEL,iFAAiF;AACjF,wBAAsB,cAAc,CAAC,SAAS,SAAS,cAAc,CAAC,GAAG,CAAC,EACxE,SAAS,EAAE,SAAS,EACpB,OAAO,GAAE,qBAAqB,CAAC,SAAS,CAAM,GAC7C,OAAO,CAAC,MAAM,CAAC,CAcjB;AAMD,8EAA8E;AAC9E,MAAM,MAAM,mBAAmB,GAAG,aAAa,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { CRAFT_PLATFORM, CRAFT_PRIMITIVE_REGISTRY, CRAFT_SSR_RUNTIME, captureCraftTransferSnapshot, createCraftRenderIdentity, createServerPlatform, serializeCraftTransferSnapshot, } from '@craft-ts/core';
|
|
2
|
+
import { ɵcreateCraftApplicationInjector, ɵrunCraftAppInitializers, } from './bootstrap';
|
|
3
|
+
import { CRAFT_ROOT_COMPONENT } from './craft-host-tokens';
|
|
4
|
+
import { provideCraftRootComponent } from './bridge';
|
|
5
|
+
import { mountInterpretedComponentWithOptions, } from './render/interpreter';
|
|
6
|
+
import { createServerStyleCollector } from './render/server-style-collector';
|
|
7
|
+
import { CraftSsrCoordinator } from './render/ssr-coordinator';
|
|
8
|
+
import { createStringDomAdapter } from './render/string-dom';
|
|
9
|
+
import { CRAFT_COMPONENT } from './types';
|
|
10
|
+
export const CRAFT_TRANSFER_SCRIPT_ID = '__CRAFT_TRANSFER__';
|
|
11
|
+
/** Renders one fully isolated Craft application request to deterministic HTML. */
|
|
12
|
+
export async function renderCraft(options) {
|
|
13
|
+
const dom = createStringDomAdapter();
|
|
14
|
+
const platform = createServerPlatform({
|
|
15
|
+
url: options.url,
|
|
16
|
+
document: dom.document,
|
|
17
|
+
signal: options.signal,
|
|
18
|
+
});
|
|
19
|
+
const coordinator = new CraftSsrCoordinator((source, mode) => platform.serverResources?.decide(source, mode));
|
|
20
|
+
const injector = ɵcreateCraftApplicationInjector(options.config, [
|
|
21
|
+
{ provide: CRAFT_PLATFORM, useValue: platform },
|
|
22
|
+
{ provide: CRAFT_SSR_RUNTIME, useValue: coordinator },
|
|
23
|
+
]);
|
|
24
|
+
let mounted;
|
|
25
|
+
try {
|
|
26
|
+
await Promise.all(ɵrunCraftAppInitializers(injector));
|
|
27
|
+
const root = injector.get(CRAFT_ROOT_COMPONENT);
|
|
28
|
+
if (!root) {
|
|
29
|
+
throw new Error('renderCraft found no root component. Add provideCraftRootComponent(App) to your app config.');
|
|
30
|
+
}
|
|
31
|
+
const identity = createCraftRenderIdentity([root[CRAFT_COMPONENT].name, 0]);
|
|
32
|
+
const host = dom.createHost();
|
|
33
|
+
dom.adapter.setAttribute(host, 'data-craft-hk', identity.hydrationKey);
|
|
34
|
+
const serverStyles = createServerStyleCollector();
|
|
35
|
+
mounted = mountInterpretedComponentWithOptions(root, host, injector, (options.props ?? {}), {
|
|
36
|
+
renderer: dom.adapter,
|
|
37
|
+
identity,
|
|
38
|
+
emitHydrationKeys: true,
|
|
39
|
+
ssr: coordinator,
|
|
40
|
+
serverStyles,
|
|
41
|
+
});
|
|
42
|
+
await coordinator.untilSettled(options.timeoutMs ?? 5_000, options.signal);
|
|
43
|
+
const styles = serverStyles.cssText();
|
|
44
|
+
const snapshot = captureCraftTransferSnapshot(injector.get(CRAFT_PRIMITIVE_REGISTRY));
|
|
45
|
+
const rootHtml = dom.serialize(host);
|
|
46
|
+
const styleHtml = options.includeStyles === false || !styles
|
|
47
|
+
? ''
|
|
48
|
+
: `<style data-craft-ssr>${escapeStyleText(styles)}</style>`;
|
|
49
|
+
const snapshotHtml = options.includeSnapshotScript === false
|
|
50
|
+
? ''
|
|
51
|
+
: `<script id="${CRAFT_TRANSFER_SCRIPT_ID}" type="application/json">${serializeCraftTransferSnapshot(snapshot)}</script>`;
|
|
52
|
+
return {
|
|
53
|
+
html: `${styleHtml}${rootHtml}${snapshotHtml}`,
|
|
54
|
+
rootHtml,
|
|
55
|
+
styles,
|
|
56
|
+
snapshot,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
mounted?.destroy();
|
|
61
|
+
platform.history.dispose();
|
|
62
|
+
injector.destroy?.();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Low-level component convenience API built on the same per-request runtime. */
|
|
66
|
+
export async function renderToString(component, options = {}) {
|
|
67
|
+
const result = await renderCraft({
|
|
68
|
+
config: {
|
|
69
|
+
providers: [
|
|
70
|
+
provideCraftRootComponent(component),
|
|
71
|
+
...(options.providers ?? []),
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
props: options.props,
|
|
75
|
+
url: options.url,
|
|
76
|
+
timeoutMs: options.timeoutMs,
|
|
77
|
+
signal: options.signal,
|
|
78
|
+
});
|
|
79
|
+
return result.html;
|
|
80
|
+
}
|
|
81
|
+
function escapeStyleText(value) {
|
|
82
|
+
return value.replace(/<\/style/gi, '<\\/style');
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=server-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-render.js","sourceRoot":"","sources":["../../../../../libs/component/src/lib/server-render.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n CRAFT_PLATFORM,\n CRAFT_PRIMITIVE_REGISTRY,\n CRAFT_SSR_RUNTIME,\n captureCraftTransferSnapshot,\n createCraftRenderIdentity,\n createServerPlatform,\n serializeCraftTransferSnapshot,\n type CraftInjector,\n type CraftTransferSnapshot,\n} from '@craft-ts/core';\nimport {\n ɵcreateCraftApplicationInjector,\n ɵrunCraftAppInitializers,\n} from './bootstrap';\nimport { CRAFT_ROOT_COMPONENT } from './craft-host-tokens';\nimport { provideCraftRootComponent } from './bridge';\nimport {\n mountInterpretedComponentWithOptions,\n type MountedCraftComponent,\n} from './render/interpreter';\nimport { createServerStyleCollector } from './render/server-style-collector';\nimport { CraftSsrCoordinator } from './render/ssr-coordinator';\nimport { createStringDomAdapter } from './render/string-dom';\nimport { CRAFT_COMPONENT, type CraftComponent, type PropsOf } from './types';\n\nexport const CRAFT_TRANSFER_SCRIPT_ID = '__CRAFT_TRANSFER__';\n\nexport type RenderCraftOptions = Readonly<{\n config: { readonly providers: readonly unknown[] };\n url?: string;\n props?: object;\n timeoutMs?: number;\n signal?: AbortSignal;\n includeStyles?: boolean;\n includeSnapshotScript?: boolean;\n}>;\n\nexport type RenderCraftResult = Readonly<{\n html: string;\n rootHtml: string;\n styles: string;\n snapshot: CraftTransferSnapshot;\n}>;\n\n/** Renders one fully isolated Craft application request to deterministic HTML. */\nexport async function renderCraft(\n options: RenderCraftOptions,\n): Promise<RenderCraftResult> {\n const dom = createStringDomAdapter();\n const platform = createServerPlatform({\n url: options.url,\n document: dom.document,\n signal: options.signal,\n });\n const coordinator = new CraftSsrCoordinator((source, mode) =>\n platform.serverResources?.decide(source, mode),\n );\n const injector = ɵcreateCraftApplicationInjector(options.config, [\n { provide: CRAFT_PLATFORM, useValue: platform },\n { provide: CRAFT_SSR_RUNTIME, useValue: coordinator },\n ]);\n let mounted: MountedCraftComponent<object> | undefined;\n try {\n await Promise.all(ɵrunCraftAppInitializers(injector));\n const root = injector.get(CRAFT_ROOT_COMPONENT) as CraftComponent<object>;\n if (!root) {\n throw new Error(\n 'renderCraft found no root component. Add provideCraftRootComponent(App) to your app config.',\n );\n }\n\n const identity = createCraftRenderIdentity([root[CRAFT_COMPONENT].name, 0]);\n const host = dom.createHost();\n dom.adapter.setAttribute(host, 'data-craft-hk', identity.hydrationKey);\n const serverStyles = createServerStyleCollector();\n mounted = mountInterpretedComponentWithOptions(\n root,\n host,\n injector,\n (options.props ?? {}) as object,\n {\n renderer: dom.adapter,\n identity,\n emitHydrationKeys: true,\n ssr: coordinator,\n serverStyles,\n },\n );\n\n await coordinator.untilSettled(options.timeoutMs ?? 5_000, options.signal);\n\n const styles = serverStyles.cssText();\n const snapshot = captureCraftTransferSnapshot(\n injector.get(CRAFT_PRIMITIVE_REGISTRY),\n );\n const rootHtml = dom.serialize(host);\n const styleHtml =\n options.includeStyles === false || !styles\n ? ''\n : `<style data-craft-ssr>${escapeStyleText(styles)}</style>`;\n const snapshotHtml =\n options.includeSnapshotScript === false\n ? ''\n : `<script id=\"${CRAFT_TRANSFER_SCRIPT_ID}\" type=\"application/json\">${serializeCraftTransferSnapshot(snapshot)}</script>`;\n return {\n html: `${styleHtml}${rootHtml}${snapshotHtml}`,\n rootHtml,\n styles,\n snapshot,\n };\n } finally {\n mounted?.destroy();\n platform.history.dispose();\n (injector as { destroy?(): void }).destroy?.();\n }\n}\n\nexport type RenderToStringOptions<Component extends CraftComponent<any>> =\n Readonly<{\n props?: PropsOf<Component>;\n providers?: readonly unknown[];\n url?: string;\n timeoutMs?: number;\n signal?: AbortSignal;\n }>;\n\n/** Low-level component convenience API built on the same per-request runtime. */\nexport async function renderToString<Component extends CraftComponent<any>>(\n component: Component,\n options: RenderToStringOptions<Component> = {},\n): Promise<string> {\n const result = await renderCraft({\n config: {\n providers: [\n provideCraftRootComponent(component),\n ...(options.providers ?? []),\n ],\n },\n props: options.props as object | undefined,\n url: options.url,\n timeoutMs: options.timeoutMs,\n signal: options.signal,\n });\n return result.html;\n}\n\nfunction escapeStyleText(value: string): string {\n return value.replace(/<\\/style/gi, '<\\\\/style');\n}\n\n/** Kept type-visible for adapters that need to share the request injector. */\nexport type CraftServerInjector = CraftInjector;\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type CraftAppRef } from './bootstrap';
|
|
2
|
+
import { type HydrateCraftOptions, type HydratedCraftAppRef } from './hydrate';
|
|
3
|
+
/** Options shared by a normal browser start and an SSR hydration. */
|
|
4
|
+
export type StartCraftOptions = HydrateCraftOptions;
|
|
5
|
+
export type StartedCraftAppRef = CraftAppRef | HydratedCraftAppRef;
|
|
6
|
+
/**
|
|
7
|
+
* Starts a Craft application in the browser.
|
|
8
|
+
*
|
|
9
|
+
* If the host contains Craft's SSR hydration marker, the existing DOM is
|
|
10
|
+
* hydrated; otherwise a fresh client render is mounted.
|
|
11
|
+
*/
|
|
12
|
+
export declare function startCraft(options: StartCraftOptions): StartedCraftAppRef;
|
|
13
|
+
//# sourceMappingURL=start.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../../../libs/component/src/lib/start.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACzB,MAAM,WAAW,CAAC;AAEnB,qEAAqE;AACrE,MAAM,MAAM,iBAAiB,GAAG,mBAAmB,CAAC;AAEpD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,mBAAmB,CAAC;AAEnE;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,kBAAkB,CAazE"}
|
package/src/lib/start.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { bootstrapCraft, } from './bootstrap';
|
|
2
|
+
import { hydrateCraft, } from './hydrate';
|
|
3
|
+
/**
|
|
4
|
+
* Starts a Craft application in the browser.
|
|
5
|
+
*
|
|
6
|
+
* If the host contains Craft's SSR hydration marker, the existing DOM is
|
|
7
|
+
* hydrated; otherwise a fresh client render is mounted.
|
|
8
|
+
*/
|
|
9
|
+
export function startCraft(options) {
|
|
10
|
+
const host = options.host ?? document.querySelector('craft-root') ?? document.body;
|
|
11
|
+
if (host.hasAttribute('data-craft-hk')) {
|
|
12
|
+
return hydrateCraft({ ...options, host });
|
|
13
|
+
}
|
|
14
|
+
const bootstrapOptions = {
|
|
15
|
+
config: options.config,
|
|
16
|
+
host,
|
|
17
|
+
};
|
|
18
|
+
return bootstrapCraft(bootstrapOptions);
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../../../../libs/component/src/lib/start.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,YAAY,GAGb,MAAM,WAAW,CAAC;AAOnB;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,MAAM,IAAI,GACR,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC;IAExE,IAAI,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,EAAE,CAAC;QACvC,OAAO,YAAY,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,gBAAgB,GAA0B;QAC9C,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI;KACL,CAAC;IACF,OAAO,cAAc,CAAC,gBAAgB,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import {\n bootstrapCraft,\n type BootstrapCraftOptions,\n type CraftAppRef,\n} from './bootstrap';\nimport {\n hydrateCraft,\n type HydrateCraftOptions,\n type HydratedCraftAppRef,\n} from './hydrate';\n\n/** Options shared by a normal browser start and an SSR hydration. */\nexport type StartCraftOptions = HydrateCraftOptions;\n\nexport type StartedCraftAppRef = CraftAppRef | HydratedCraftAppRef;\n\n/**\n * Starts a Craft application in the browser.\n *\n * If the host contains Craft's SSR hydration marker, the existing DOM is\n * hydrated; otherwise a fresh client render is mounted.\n */\nexport function startCraft(options: StartCraftOptions): StartedCraftAppRef {\n const host =\n options.host ?? document.querySelector('craft-root') ?? document.body;\n\n if (host.hasAttribute('data-craft-hk')) {\n return hydrateCraft({ ...options, host });\n }\n\n const bootstrapOptions: BootstrapCraftOptions = {\n config: options.config,\n host,\n };\n return bootstrapCraft(bootstrapOptions);\n}\n"]}
|