streetui 1.6.0 → 1.7.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/dist/bin.cjs +1 -1
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/bin.js.map +1 -1
- package/dist/{compile-CEom4hkp.d.cts → compile-Cte0nf06.d.cts} +80 -3
- package/dist/{compile-CEom4hkp.d.ts → compile-Cte0nf06.d.ts} +80 -3
- package/dist/create-bin.cjs +1 -1
- package/dist/create-bin.cjs.map +1 -1
- package/dist/create-bin.js +1 -1
- package/dist/create-bin.js.map +1 -1
- package/dist/{hydration-diagnostics-YrG-OJJe.d.ts → hydration-diagnostics-Ddgs3Puu.d.ts} +1 -1
- package/dist/{hydration-diagnostics-D286jpZZ.d.cts → hydration-diagnostics-zK-fihvd.d.cts} +1 -1
- package/dist/index.cjs +439 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -10
- package/dist/index.d.ts +93 -10
- package/dist/index.js +430 -5
- package/dist/index.js.map +1 -1
- package/dist/{server-C2xovHHb.d.cts → server-D4A8eunr.d.cts} +43 -1
- package/dist/{server-xU-BEwAj.d.ts → server-cgmCiPsz.d.ts} +43 -1
- package/dist/server.cjs +1126 -839
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1126 -839
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +375 -111
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -3
- package/dist/testing.d.ts +3 -3
- package/dist/testing.js +375 -111
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// ../renderer/src/render-context.ts
|
|
2
|
-
function createRenderContext(dom, graph, container, hydrationDiagnostics) {
|
|
2
|
+
function createRenderContext(dom, graph, container, hydrationDiagnostics, staticHTML) {
|
|
3
3
|
return {
|
|
4
4
|
dom,
|
|
5
5
|
graph,
|
|
6
6
|
instances: /* @__PURE__ */ new Map(),
|
|
7
7
|
container,
|
|
8
|
-
...hydrationDiagnostics !== void 0 ? { hydrationDiagnostics } : {}
|
|
8
|
+
...hydrationDiagnostics !== void 0 ? { hydrationDiagnostics } : {},
|
|
9
|
+
...staticHTML !== void 0 ? { staticHTML } : {}
|
|
9
10
|
};
|
|
10
11
|
}
|
|
11
12
|
|
|
@@ -153,948 +154,1130 @@ function wireEvents(dom, graph, node, element, instance) {
|
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
|
|
156
|
-
// ../
|
|
157
|
-
var
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
"list-item": "li",
|
|
169
|
-
image: "img",
|
|
170
|
-
link: "a",
|
|
171
|
-
component: "div",
|
|
172
|
-
slot: "div",
|
|
173
|
-
fragment: "div",
|
|
174
|
-
"reactive-list": "ul"
|
|
157
|
+
// ../dom/src/server-node.ts
|
|
158
|
+
var ServerStyle = class {
|
|
159
|
+
declarations = /* @__PURE__ */ new Map();
|
|
160
|
+
setProperty(name, value) {
|
|
161
|
+
this.declarations.set(name, value);
|
|
162
|
+
}
|
|
163
|
+
get isEmpty() {
|
|
164
|
+
return this.declarations.size === 0;
|
|
165
|
+
}
|
|
166
|
+
toCss() {
|
|
167
|
+
return [...this.declarations.entries()].map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
168
|
+
}
|
|
175
169
|
};
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const instance = ctx.instances.get(graphNode.id);
|
|
183
|
-
if (instance === void 0) return;
|
|
184
|
-
const domNode = instance.domNode;
|
|
185
|
-
if (!ctx.dom.isElement(domNode)) return;
|
|
186
|
-
const oldValue = graphNode.getProp(propKey);
|
|
187
|
-
switch (propKey) {
|
|
188
|
-
case "text":
|
|
189
|
-
if (!Object.is(oldValue, newValue)) {
|
|
190
|
-
ctx.dom.setTextContent(domNode, String(newValue ?? ""));
|
|
191
|
-
graphNode.setProp("text", String(newValue ?? ""));
|
|
192
|
-
}
|
|
193
|
-
break;
|
|
194
|
-
case "label":
|
|
195
|
-
if (!Object.is(oldValue, newValue)) {
|
|
196
|
-
ctx.dom.setTextContent(domNode, String(newValue ?? ""));
|
|
197
|
-
graphNode.setProp("label", String(newValue ?? ""));
|
|
198
|
-
}
|
|
199
|
-
break;
|
|
200
|
-
case "disabled":
|
|
201
|
-
if (newValue === true) {
|
|
202
|
-
ctx.dom.setAttribute(domNode, "disabled", "");
|
|
203
|
-
} else {
|
|
204
|
-
ctx.dom.removeAttribute(domNode, "disabled");
|
|
205
|
-
}
|
|
206
|
-
graphNode.setProp("disabled", Boolean(newValue));
|
|
207
|
-
break;
|
|
208
|
-
case "value":
|
|
209
|
-
if (!Object.is(oldValue, newValue)) {
|
|
210
|
-
ctx.dom.setProperty(domNode, "value", String(newValue ?? ""));
|
|
211
|
-
graphNode.setProp("value", String(newValue ?? ""));
|
|
212
|
-
}
|
|
213
|
-
break;
|
|
214
|
-
default:
|
|
215
|
-
patchProp(ctx.dom, domNode, propKey, oldValue, newValue);
|
|
216
|
-
graphNode.setProp(propKey, newValue);
|
|
217
|
-
break;
|
|
170
|
+
var ServerText = class {
|
|
171
|
+
kind = "text";
|
|
172
|
+
parent = null;
|
|
173
|
+
data;
|
|
174
|
+
constructor(data) {
|
|
175
|
+
this.data = data;
|
|
218
176
|
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
oldByKey.set(key, inst);
|
|
177
|
+
};
|
|
178
|
+
var ServerComment = class {
|
|
179
|
+
kind = "comment";
|
|
180
|
+
parent = null;
|
|
181
|
+
data;
|
|
182
|
+
constructor(data) {
|
|
183
|
+
this.data = data;
|
|
227
184
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
241
|
-
newInstances.push(existing);
|
|
242
|
-
} else {
|
|
243
|
-
const inst = mountFn(newNode, parentDom);
|
|
244
|
-
newInstances.push(inst);
|
|
245
|
-
}
|
|
185
|
+
};
|
|
186
|
+
var ServerFragment = class {
|
|
187
|
+
kind = "fragment";
|
|
188
|
+
parent = null;
|
|
189
|
+
children = [];
|
|
190
|
+
};
|
|
191
|
+
var ServerRawHTML = class {
|
|
192
|
+
kind = "raw";
|
|
193
|
+
parent = null;
|
|
194
|
+
html;
|
|
195
|
+
constructor(html) {
|
|
196
|
+
this.html = html;
|
|
246
197
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
198
|
+
};
|
|
199
|
+
var ServerElement = class {
|
|
200
|
+
kind = "element";
|
|
201
|
+
parent = null;
|
|
202
|
+
tagName;
|
|
203
|
+
attributes = /* @__PURE__ */ new Map();
|
|
204
|
+
children = [];
|
|
205
|
+
// Lazily-allocated stores. On the 10k-row SSR corpus ~0% of elements carry JS
|
|
206
|
+
// properties or inline styles (measured, §5: 1 of 80,029 elements uses
|
|
207
|
+
// `properties`, 0 use `style`), so eagerly allocating a `properties` Map plus
|
|
208
|
+
// a `ServerStyle` (which itself holds a Map) per element wasted ~240k
|
|
209
|
+
// allocations per /users render — all in the dominant mount phase. These are
|
|
210
|
+
// created on first WRITE via the `properties`/`style` getters; the serializer
|
|
211
|
+
// reads the raw `_properties`/`_style` fields so a READ never forces an
|
|
212
|
+
// allocation. Output is byte-identical: an unset store previously serialized
|
|
213
|
+
// to nothing (empty `properties.has(...)` / `style.isEmpty`), and a null store
|
|
214
|
+
// is skipped the same way.
|
|
215
|
+
_properties = null;
|
|
216
|
+
_style = null;
|
|
217
|
+
constructor(tagName) {
|
|
218
|
+
this.tagName = tagName.toLowerCase();
|
|
219
|
+
}
|
|
220
|
+
/** JS properties set via `setProperty` (e.g. input `value`, `checked`). Allocated on first access. */
|
|
221
|
+
get properties() {
|
|
222
|
+
return this._properties ??= /* @__PURE__ */ new Map();
|
|
223
|
+
}
|
|
224
|
+
/** Inline-style holder mirroring `element.style`. Allocated on first access. */
|
|
225
|
+
get style() {
|
|
226
|
+
return this._style ??= new ServerStyle();
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
var VOID_ELEMENTS = /* @__PURE__ */ new Set([
|
|
230
|
+
"area",
|
|
231
|
+
"base",
|
|
232
|
+
"br",
|
|
233
|
+
"col",
|
|
234
|
+
"embed",
|
|
235
|
+
"hr",
|
|
236
|
+
"img",
|
|
237
|
+
"input",
|
|
238
|
+
"link",
|
|
239
|
+
"meta",
|
|
240
|
+
"param",
|
|
241
|
+
"source",
|
|
242
|
+
"track",
|
|
243
|
+
"wbr"
|
|
244
|
+
]);
|
|
245
|
+
var SERIALIZED_PROPERTIES = {
|
|
246
|
+
value: "attr",
|
|
247
|
+
checked: "boolean",
|
|
248
|
+
selected: "boolean"
|
|
249
|
+
};
|
|
250
|
+
var SERIALIZED_PROPERTY_ENTRIES = Object.entries(SERIALIZED_PROPERTIES);
|
|
251
|
+
var TEXT_SPECIAL = /[&<>]/;
|
|
252
|
+
var ATTR_SPECIAL = /[&<>"]/;
|
|
253
|
+
function escapeHtmlText(value) {
|
|
254
|
+
if (!TEXT_SPECIAL.test(value)) return value;
|
|
255
|
+
let out = "";
|
|
256
|
+
let last = 0;
|
|
257
|
+
for (let i = 0; i < value.length; i++) {
|
|
258
|
+
let esc;
|
|
259
|
+
switch (value.charCodeAt(i)) {
|
|
260
|
+
case 38:
|
|
261
|
+
esc = "&";
|
|
262
|
+
break;
|
|
263
|
+
// &
|
|
264
|
+
case 60:
|
|
265
|
+
esc = "<";
|
|
266
|
+
break;
|
|
267
|
+
// <
|
|
268
|
+
case 62:
|
|
269
|
+
esc = ">";
|
|
270
|
+
break;
|
|
271
|
+
// >
|
|
272
|
+
default:
|
|
273
|
+
continue;
|
|
252
274
|
}
|
|
275
|
+
out += value.slice(last, i) + esc;
|
|
276
|
+
last = i + 1;
|
|
253
277
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
278
|
+
return out + value.slice(last);
|
|
279
|
+
}
|
|
280
|
+
function escapeHtmlAttr(value) {
|
|
281
|
+
if (!ATTR_SPECIAL.test(value)) return value;
|
|
282
|
+
let out = "";
|
|
283
|
+
let last = 0;
|
|
284
|
+
for (let i = 0; i < value.length; i++) {
|
|
285
|
+
let esc;
|
|
286
|
+
switch (value.charCodeAt(i)) {
|
|
287
|
+
case 38:
|
|
288
|
+
esc = "&";
|
|
289
|
+
break;
|
|
290
|
+
// &
|
|
291
|
+
case 60:
|
|
292
|
+
esc = "<";
|
|
293
|
+
break;
|
|
294
|
+
// <
|
|
295
|
+
case 62:
|
|
296
|
+
esc = ">";
|
|
297
|
+
break;
|
|
298
|
+
// >
|
|
299
|
+
case 34:
|
|
300
|
+
esc = """;
|
|
301
|
+
break;
|
|
302
|
+
// "
|
|
303
|
+
default:
|
|
304
|
+
continue;
|
|
258
305
|
}
|
|
259
|
-
|
|
306
|
+
out += value.slice(last, i) + esc;
|
|
307
|
+
last = i + 1;
|
|
260
308
|
}
|
|
261
|
-
|
|
262
|
-
return { instances: newInstances, removed };
|
|
309
|
+
return out + value.slice(last);
|
|
263
310
|
}
|
|
264
|
-
function
|
|
265
|
-
const
|
|
266
|
-
for (const
|
|
267
|
-
|
|
311
|
+
function serializeAttributes(el) {
|
|
312
|
+
const parts = [];
|
|
313
|
+
for (const [name, value] of el.attributes) {
|
|
314
|
+
if (value === "") {
|
|
315
|
+
parts.push(` ${name}`);
|
|
316
|
+
} else {
|
|
317
|
+
parts.push(` ${name}="${escapeHtmlAttr(value)}"`);
|
|
318
|
+
}
|
|
268
319
|
}
|
|
269
|
-
const
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (!Object.is(oldSig, newSig)) {
|
|
281
|
-
const freshNode = entry.build();
|
|
282
|
-
built.push(freshNode);
|
|
283
|
-
patchExistingInstance(ctx, existing, freshNode);
|
|
284
|
-
reconcileItemChildren(ctx, existing, freshNode, mountFn);
|
|
285
|
-
existing.graphNode.setProp("_sig", newSig);
|
|
320
|
+
const props = el._properties;
|
|
321
|
+
if (props !== null) {
|
|
322
|
+
for (const [name, kind] of SERIALIZED_PROPERTY_ENTRIES) {
|
|
323
|
+
if (!props.has(name)) continue;
|
|
324
|
+
if (el.attributes.has(name)) continue;
|
|
325
|
+
const raw = props.get(name);
|
|
326
|
+
if (kind === "boolean") {
|
|
327
|
+
if (raw === true) parts.push(` ${name}`);
|
|
328
|
+
} else {
|
|
329
|
+
if (raw !== void 0 && raw !== null) {
|
|
330
|
+
parts.push(` ${name}="${escapeHtmlAttr(String(raw))}"`);
|
|
286
331
|
}
|
|
287
|
-
existing.graphNode.setProp("_item", entry.item);
|
|
288
332
|
}
|
|
289
|
-
newInstances.push(existing);
|
|
290
|
-
} else {
|
|
291
|
-
const freshNode = entry.build();
|
|
292
|
-
built.push(freshNode);
|
|
293
|
-
const inst = mountFn(freshNode, parentDom);
|
|
294
|
-
newInstances.push(inst);
|
|
295
333
|
}
|
|
296
334
|
}
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (!usedKeys.has(key)) removed.push(inst);
|
|
301
|
-
}
|
|
302
|
-
for (const inst of removed) {
|
|
303
|
-
const parent = ctx.dom.parentNode(inst.domNode);
|
|
304
|
-
if (parent !== null) ctx.dom.removeChild(parent, inst.domNode);
|
|
305
|
-
inst.dispose();
|
|
335
|
+
const style = el._style;
|
|
336
|
+
if (style !== null && !style.isEmpty && !el.attributes.has("style")) {
|
|
337
|
+
parts.push(` style="${escapeHtmlAttr(style.toCss())}"`);
|
|
306
338
|
}
|
|
307
|
-
|
|
308
|
-
return { instances: newInstances, removed, built };
|
|
339
|
+
return parts.join("");
|
|
309
340
|
}
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
else lastSeen = oi;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
if (!moved) return;
|
|
330
|
-
const keep = longestIncreasingSubsequence(source);
|
|
331
|
-
let refNode = null;
|
|
332
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
333
|
-
const domNode = newInstances[i].domNode;
|
|
334
|
-
if (source[i] === -1 || !keep.has(i)) {
|
|
335
|
-
if (ctx.dom.nextSibling(domNode) !== refNode) {
|
|
336
|
-
ctx.dom.insertBefore(parentDom, domNode, refNode);
|
|
341
|
+
function serializeServerNode(node) {
|
|
342
|
+
switch (node.kind) {
|
|
343
|
+
case "text":
|
|
344
|
+
return escapeHtmlText(node.data);
|
|
345
|
+
case "comment":
|
|
346
|
+
return `<!--${node.data}-->`;
|
|
347
|
+
case "fragment":
|
|
348
|
+
return serializeChildren(node);
|
|
349
|
+
case "raw":
|
|
350
|
+
return node.html;
|
|
351
|
+
case "element": {
|
|
352
|
+
const el = node;
|
|
353
|
+
const tag = el.tagName;
|
|
354
|
+
const attrs = serializeAttributes(el);
|
|
355
|
+
if (VOID_ELEMENTS.has(tag)) {
|
|
356
|
+
return `<${tag}${attrs}>`;
|
|
337
357
|
}
|
|
358
|
+
return `<${tag}${attrs}>${serializeChildren(el)}</${tag}>`;
|
|
338
359
|
}
|
|
339
|
-
refNode = domNode;
|
|
340
360
|
}
|
|
341
361
|
}
|
|
342
|
-
function
|
|
343
|
-
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
362
|
+
function serializeChildren(node) {
|
|
363
|
+
let out = "";
|
|
364
|
+
for (const child of node.children) {
|
|
365
|
+
out += serializeServerNode(child);
|
|
366
|
+
}
|
|
367
|
+
return out;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ../dom/src/server-adapter.ts
|
|
371
|
+
function asServer(node) {
|
|
372
|
+
return node;
|
|
373
|
+
}
|
|
374
|
+
function asParent(node) {
|
|
375
|
+
return node;
|
|
376
|
+
}
|
|
377
|
+
var ServerDOMAdapter = class {
|
|
378
|
+
createElement(tag, _ns) {
|
|
379
|
+
return new ServerElement(tag);
|
|
380
|
+
}
|
|
381
|
+
createTextNode(data) {
|
|
382
|
+
return new ServerText(data);
|
|
383
|
+
}
|
|
384
|
+
createComment(data) {
|
|
385
|
+
return new ServerComment(data);
|
|
386
|
+
}
|
|
387
|
+
createFragment() {
|
|
388
|
+
return new ServerFragment();
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Create a verbatim pre-serialized HTML node (v1.7 static SSR plan, §6).
|
|
392
|
+
* Server-only: the browser adapter does not implement this, and the renderer
|
|
393
|
+
* fast path only invokes it when a static SSR plan is present (SSR). The
|
|
394
|
+
* stored HTML was produced by this same serializer, so it is emitted as-is.
|
|
395
|
+
*/
|
|
396
|
+
createRawHTML(html) {
|
|
397
|
+
return new ServerRawHTML(html);
|
|
398
|
+
}
|
|
399
|
+
appendChild(parent, child) {
|
|
400
|
+
const p = asParent(parent);
|
|
401
|
+
const c = asServer(child);
|
|
402
|
+
this._detach(c);
|
|
403
|
+
c.parent = p;
|
|
404
|
+
p.children.push(c);
|
|
405
|
+
}
|
|
406
|
+
insertBefore(parent, child, reference) {
|
|
407
|
+
const p = asParent(parent);
|
|
408
|
+
const c = asServer(child);
|
|
409
|
+
this._detach(c);
|
|
410
|
+
c.parent = p;
|
|
411
|
+
if (reference === null) {
|
|
412
|
+
p.children.push(c);
|
|
413
|
+
return;
|
|
356
414
|
}
|
|
357
|
-
|
|
358
|
-
|
|
415
|
+
const ref = asServer(reference);
|
|
416
|
+
const idx = p.children.indexOf(ref);
|
|
417
|
+
if (idx === -1) p.children.push(c);
|
|
418
|
+
else p.children.splice(idx, 0, c);
|
|
359
419
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
idx =
|
|
420
|
+
removeChild(parent, child) {
|
|
421
|
+
const p = asParent(parent);
|
|
422
|
+
const c = asServer(child);
|
|
423
|
+
const idx = p.children.indexOf(c);
|
|
424
|
+
if (idx !== -1) {
|
|
425
|
+
p.children.splice(idx, 1);
|
|
426
|
+
c.parent = null;
|
|
427
|
+
}
|
|
364
428
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if (
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
} else {
|
|
383
|
-
itemInstance.graphNode.appendChild(newChild);
|
|
384
|
-
const inst = mountFn(newChild, el);
|
|
385
|
-
nextChildren.push(inst);
|
|
429
|
+
replaceChild(parent, newChild, oldChild) {
|
|
430
|
+
const p = asParent(parent);
|
|
431
|
+
const nc = asServer(newChild);
|
|
432
|
+
const oc = asServer(oldChild);
|
|
433
|
+
const idx = p.children.indexOf(oc);
|
|
434
|
+
if (idx === -1) return;
|
|
435
|
+
this._detach(nc);
|
|
436
|
+
nc.parent = p;
|
|
437
|
+
p.children.splice(idx, 1, nc);
|
|
438
|
+
oc.parent = null;
|
|
439
|
+
}
|
|
440
|
+
_detach(node) {
|
|
441
|
+
if (node.parent !== null) {
|
|
442
|
+
const siblings = node.parent.children;
|
|
443
|
+
const idx = siblings.indexOf(node);
|
|
444
|
+
if (idx !== -1) siblings.splice(idx, 1);
|
|
445
|
+
node.parent = null;
|
|
386
446
|
}
|
|
387
447
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const parent = ctx.dom.parentNode(old.domNode);
|
|
391
|
-
if (parent !== null) ctx.dom.removeChild(parent, old.domNode);
|
|
392
|
-
old.dispose();
|
|
393
|
-
forgetInstanceTree(ctx, old);
|
|
394
|
-
ctx.graph.detachNode(old.graphNode);
|
|
448
|
+
setAttribute(element, name, value) {
|
|
449
|
+
element.attributes.set(name, value);
|
|
395
450
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
for (const c of nextChildren) itemInstance.children.push(c);
|
|
399
|
-
for (const c of [...itemInstance.graphNode.children]) {
|
|
400
|
-
itemInstance.graphNode.removeChild(c);
|
|
451
|
+
removeAttribute(element, name) {
|
|
452
|
+
element.attributes.delete(name);
|
|
401
453
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
function reorderDom(ctx, parentDom, instances) {
|
|
405
|
-
let referenceNode = null;
|
|
406
|
-
for (let i = instances.length - 1; i >= 0; i--) {
|
|
407
|
-
const inst = instances[i];
|
|
408
|
-
if (inst === void 0) continue;
|
|
409
|
-
const domNode = inst.domNode;
|
|
410
|
-
const currentNext = ctx.dom.nextSibling(domNode);
|
|
411
|
-
if (currentNext !== referenceNode) {
|
|
412
|
-
ctx.dom.insertBefore(parentDom, domNode, referenceNode);
|
|
413
|
-
}
|
|
414
|
-
referenceNode = domNode;
|
|
454
|
+
getAttribute(element, name) {
|
|
455
|
+
return element.attributes.get(name) ?? null;
|
|
415
456
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
ctx.instances.delete(instance.graphNode.id);
|
|
419
|
-
for (const child of instance.children) forgetInstanceTree(ctx, child);
|
|
420
|
-
}
|
|
421
|
-
function patchExistingInstance(ctx, instance, newNode) {
|
|
422
|
-
const oldNode = instance.graphNode;
|
|
423
|
-
for (const [key, newVal] of Object.entries(newNode.props)) {
|
|
424
|
-
const oldVal = oldNode.getProp(key);
|
|
425
|
-
if (!Object.is(oldVal, newVal)) {
|
|
426
|
-
patchNode(ctx, instance.graphNode, key, newVal);
|
|
427
|
-
}
|
|
457
|
+
setProperty(element, name, value) {
|
|
458
|
+
element.properties.set(name, value);
|
|
428
459
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
"href",
|
|
440
|
-
"external",
|
|
441
|
-
"value",
|
|
442
|
-
"placeholder",
|
|
443
|
-
"disabled",
|
|
444
|
-
"_renderKey",
|
|
445
|
-
"key",
|
|
446
|
-
"name"
|
|
447
|
-
]);
|
|
448
|
-
function mountGraph(ctx) {
|
|
449
|
-
return mountNode(ctx, ctx.graph.root, ctx.container);
|
|
450
|
-
}
|
|
451
|
-
function mountNode(ctx, graphNode, parentDom) {
|
|
452
|
-
const { dom, graph } = ctx;
|
|
453
|
-
if (graphNode.type === "application") {
|
|
454
|
-
const instance2 = new NodeInstance(graphNode, parentDom);
|
|
455
|
-
ctx.instances.set(graphNode.id, instance2);
|
|
456
|
-
for (const child of graphNode.children) {
|
|
457
|
-
const childInstance = mountNode(ctx, child, parentDom);
|
|
458
|
-
instance2.addChild(childInstance);
|
|
460
|
+
setTextContent(node, text) {
|
|
461
|
+
const n = asServer(node);
|
|
462
|
+
if (n.kind === "element" || n.kind === "fragment") {
|
|
463
|
+
const el = n;
|
|
464
|
+
el.children.length = 0;
|
|
465
|
+
const t = new ServerText(text);
|
|
466
|
+
t.parent = el;
|
|
467
|
+
el.children.push(t);
|
|
468
|
+
} else if (n.kind === "text") {
|
|
469
|
+
n.data = text;
|
|
459
470
|
}
|
|
460
|
-
return instance2;
|
|
461
471
|
}
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
if (graphNode.stateRefs.length !== 0) {
|
|
472
|
-
wireSignalBindings(ctx, graphNode, instance2, textUpdate(dom, el2, textNode));
|
|
472
|
+
getTextContent(node) {
|
|
473
|
+
const n = asServer(node);
|
|
474
|
+
if (n.kind === "text") return n.data;
|
|
475
|
+
if (n.kind === "element" || n.kind === "fragment") {
|
|
476
|
+
let out = "";
|
|
477
|
+
for (const c of n.children) {
|
|
478
|
+
out += this.getTextContent(c) ?? "";
|
|
479
|
+
}
|
|
480
|
+
return out;
|
|
473
481
|
}
|
|
474
|
-
|
|
475
|
-
return instance2;
|
|
482
|
+
return null;
|
|
476
483
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
const tag2 = `h${level}`;
|
|
480
|
-
const el2 = dom.createElement(tag2);
|
|
481
|
-
const text = String(graphNode.getProp("text") ?? "");
|
|
482
|
-
dom.setTextContent(el2, text);
|
|
483
|
-
applyNodeProps(ctx, graphNode, el2);
|
|
484
|
-
const instance2 = new NodeInstance(graphNode, el2);
|
|
485
|
-
ctx.instances.set(graphNode.id, instance2);
|
|
486
|
-
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
487
|
-
if (graphNode.stateRefs.length !== 0) {
|
|
488
|
-
wireSignalBindings(ctx, graphNode, instance2, headingUpdate(dom, el2));
|
|
489
|
-
}
|
|
490
|
-
dom.appendChild(parentDom, el2);
|
|
491
|
-
return instance2;
|
|
484
|
+
// Server nodes never dispatch events — listeners are a no-op on the server.
|
|
485
|
+
addEventListener() {
|
|
492
486
|
}
|
|
493
|
-
|
|
494
|
-
const el2 = dom.createElement("input");
|
|
495
|
-
const inputType = String(graphNode.getProp("inputType") ?? "text");
|
|
496
|
-
dom.setAttribute(el2, "type", inputType);
|
|
497
|
-
const placeholder = graphNode.getProp("placeholder");
|
|
498
|
-
if (placeholder !== void 0) dom.setAttribute(el2, "placeholder", String(placeholder));
|
|
499
|
-
const value = graphNode.getProp("value");
|
|
500
|
-
if (value !== void 0) dom.setProperty(el2, "value", String(value));
|
|
501
|
-
applyNodeProps(ctx, graphNode, el2);
|
|
502
|
-
const instance2 = new NodeInstance(graphNode, el2);
|
|
503
|
-
ctx.instances.set(graphNode.id, instance2);
|
|
504
|
-
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
505
|
-
if (graphNode.stateRefs.length !== 0) {
|
|
506
|
-
wireSignalBindings(ctx, graphNode, instance2, inputUpdate(dom, el2));
|
|
507
|
-
}
|
|
508
|
-
dom.appendChild(parentDom, el2);
|
|
509
|
-
return instance2;
|
|
487
|
+
removeEventListener() {
|
|
510
488
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const src = graphNode.getProp("src");
|
|
514
|
-
const alt = graphNode.getProp("alt");
|
|
515
|
-
if (src !== void 0) dom.setAttribute(el2, "src", String(src));
|
|
516
|
-
if (alt !== void 0) dom.setAttribute(el2, "alt", String(alt));
|
|
517
|
-
const width = graphNode.getProp("width");
|
|
518
|
-
const height = graphNode.getProp("height");
|
|
519
|
-
if (width !== void 0) dom.setAttribute(el2, "width", String(width));
|
|
520
|
-
if (height !== void 0) dom.setAttribute(el2, "height", String(height));
|
|
521
|
-
applyNodeProps(ctx, graphNode, el2);
|
|
522
|
-
const instance2 = new NodeInstance(graphNode, el2);
|
|
523
|
-
ctx.instances.set(graphNode.id, instance2);
|
|
524
|
-
dom.appendChild(parentDom, el2);
|
|
525
|
-
return instance2;
|
|
489
|
+
querySelector() {
|
|
490
|
+
return null;
|
|
526
491
|
}
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
const href = graphNode.getProp("href");
|
|
530
|
-
const label = graphNode.getProp("label");
|
|
531
|
-
const external = graphNode.getProp("external");
|
|
532
|
-
if (href !== void 0) dom.setAttribute(el2, "href", String(href));
|
|
533
|
-
if (label !== void 0) dom.setTextContent(el2, String(label));
|
|
534
|
-
if (external === true) {
|
|
535
|
-
dom.setAttribute(el2, "target", "_blank");
|
|
536
|
-
dom.setAttribute(el2, "rel", "noopener noreferrer");
|
|
537
|
-
}
|
|
538
|
-
applyNodeProps(ctx, graphNode, el2);
|
|
539
|
-
const instance2 = new NodeInstance(graphNode, el2);
|
|
540
|
-
ctx.instances.set(graphNode.id, instance2);
|
|
541
|
-
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
542
|
-
dom.appendChild(parentDom, el2);
|
|
543
|
-
return instance2;
|
|
492
|
+
querySelectorAll() {
|
|
493
|
+
return [];
|
|
544
494
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
const label = graphNode.getProp("label");
|
|
548
|
-
if (label !== void 0) dom.setTextContent(el2, String(label));
|
|
549
|
-
const disabled = graphNode.getProp("disabled");
|
|
550
|
-
if (disabled === true) dom.setAttribute(el2, "disabled", "");
|
|
551
|
-
applyNodeProps(ctx, graphNode, el2);
|
|
552
|
-
const instance2 = new NodeInstance(graphNode, el2);
|
|
553
|
-
ctx.instances.set(graphNode.id, instance2);
|
|
554
|
-
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
555
|
-
if (graphNode.stateRefs.length !== 0) {
|
|
556
|
-
wireSignalBindings(ctx, graphNode, instance2, buttonUpdate(dom, el2));
|
|
557
|
-
}
|
|
558
|
-
dom.appendChild(parentDom, el2);
|
|
559
|
-
return instance2;
|
|
495
|
+
getElementById() {
|
|
496
|
+
return null;
|
|
560
497
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
498
|
+
focus() {
|
|
499
|
+
}
|
|
500
|
+
body() {
|
|
501
|
+
return null;
|
|
502
|
+
}
|
|
503
|
+
activeElement() {
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
contains(_ancestor, _node) {
|
|
507
|
+
return false;
|
|
508
|
+
}
|
|
509
|
+
matches(_element, _selector) {
|
|
510
|
+
return false;
|
|
511
|
+
}
|
|
512
|
+
isElement(node) {
|
|
513
|
+
return asServer(node).kind === "element";
|
|
514
|
+
}
|
|
515
|
+
isTextNode(node) {
|
|
516
|
+
return asServer(node).kind === "text";
|
|
517
|
+
}
|
|
518
|
+
tagName(element) {
|
|
519
|
+
return element.tagName;
|
|
520
|
+
}
|
|
521
|
+
parentNode(node) {
|
|
522
|
+
return asServer(node).parent ?? null;
|
|
523
|
+
}
|
|
524
|
+
nextSibling(node) {
|
|
525
|
+
const n = asServer(node);
|
|
526
|
+
const parent = n.parent;
|
|
527
|
+
if (parent === null) return null;
|
|
528
|
+
const idx = parent.children.indexOf(n);
|
|
529
|
+
if (idx === -1 || idx + 1 >= parent.children.length) return null;
|
|
530
|
+
return parent.children[idx + 1];
|
|
531
|
+
}
|
|
532
|
+
firstChild(node) {
|
|
533
|
+
const n = asServer(node);
|
|
534
|
+
if (n.kind === "element" || n.kind === "fragment") {
|
|
535
|
+
const el = n;
|
|
536
|
+
return el.children[0] ?? null;
|
|
570
537
|
}
|
|
571
|
-
|
|
572
|
-
wireReactiveList(ctx, graphNode, instance2, el2);
|
|
573
|
-
return instance2;
|
|
538
|
+
return null;
|
|
574
539
|
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
const itemKey = graphNode.getProp("key");
|
|
580
|
-
if (itemKey !== void 0) {
|
|
581
|
-
dom.setAttribute(el, "data-streetui-key", String(itemKey));
|
|
540
|
+
childNodes(node) {
|
|
541
|
+
const n = asServer(node);
|
|
542
|
+
if (n.kind === "element" || n.kind === "fragment") {
|
|
543
|
+
return n.children;
|
|
582
544
|
}
|
|
545
|
+
return [];
|
|
583
546
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
547
|
+
// ── Server-only ────────────────────────────────────────────────────────────
|
|
548
|
+
/** Serialize a node's children ("inner HTML") to an HTML string. */
|
|
549
|
+
serializeInner(node) {
|
|
550
|
+
const n = asServer(node);
|
|
551
|
+
if (n.kind === "element" || n.kind === "fragment") {
|
|
552
|
+
return serializeChildren(n);
|
|
553
|
+
}
|
|
554
|
+
return "";
|
|
588
555
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
556
|
+
/** Serialize a node (including itself) to an HTML string. */
|
|
557
|
+
serializeOuter(node) {
|
|
558
|
+
return serializeServerNode(asServer(node));
|
|
592
559
|
}
|
|
593
|
-
|
|
594
|
-
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
// ../dom/src/focus.ts
|
|
563
|
+
var FOCUSABLE_SELECTOR = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
564
|
+
function focusById(dom, root, id) {
|
|
565
|
+
const el = dom.querySelector(root, `[id="${id}"]`);
|
|
566
|
+
if (el === null) return false;
|
|
567
|
+
dom.focus(el);
|
|
568
|
+
return true;
|
|
595
569
|
}
|
|
596
|
-
function
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
applyProp(dom, el, propKey, value);
|
|
602
|
-
}
|
|
603
|
-
};
|
|
570
|
+
function focusFirst(dom, container, selector = FOCUSABLE_SELECTOR) {
|
|
571
|
+
const el = dom.querySelector(container, selector);
|
|
572
|
+
if (el === null) return false;
|
|
573
|
+
dom.focus(el);
|
|
574
|
+
return true;
|
|
604
575
|
}
|
|
605
|
-
function
|
|
606
|
-
return (
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
} else {
|
|
610
|
-
applyProp(dom, el, propKey, value);
|
|
611
|
-
}
|
|
612
|
-
};
|
|
576
|
+
function getFocusable(dom, container, selector = FOCUSABLE_SELECTOR) {
|
|
577
|
+
return Array.from(dom.querySelectorAll(container, selector)).filter(
|
|
578
|
+
(el) => dom.matches(el, selector)
|
|
579
|
+
);
|
|
613
580
|
}
|
|
614
|
-
function
|
|
615
|
-
return (
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
581
|
+
function saveFocus(dom) {
|
|
582
|
+
return dom.activeElement();
|
|
583
|
+
}
|
|
584
|
+
function restoreFocus(dom, saved) {
|
|
585
|
+
if (saved !== null) dom.focus(saved);
|
|
586
|
+
}
|
|
587
|
+
function focusInitial(dom, container, initialFocusId) {
|
|
588
|
+
if (initialFocusId !== void 0 && focusById(dom, container, initialFocusId)) return;
|
|
589
|
+
focusFirst(dom, container);
|
|
590
|
+
}
|
|
591
|
+
function trapFocus(dom, container) {
|
|
592
|
+
const onKeydown = (event) => {
|
|
593
|
+
if (event.key !== "Tab") return;
|
|
594
|
+
const items = getFocusable(dom, container);
|
|
595
|
+
if (items.length === 0) {
|
|
596
|
+
event.preventDefault();
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const first = items[0];
|
|
600
|
+
const last = items[items.length - 1];
|
|
601
|
+
const active = dom.activeElement();
|
|
602
|
+
if (active === null || !dom.contains(container, active)) {
|
|
603
|
+
event.preventDefault();
|
|
604
|
+
dom.focus(first);
|
|
605
|
+
} else if (event.shiftKey && active === first) {
|
|
606
|
+
event.preventDefault();
|
|
607
|
+
dom.focus(last);
|
|
608
|
+
} else if (!event.shiftKey && active === last) {
|
|
609
|
+
event.preventDefault();
|
|
610
|
+
dom.focus(first);
|
|
620
611
|
}
|
|
621
612
|
};
|
|
613
|
+
dom.addEventListener(container, "keydown", onKeydown);
|
|
614
|
+
return () => dom.removeEventListener(container, "keydown", onKeydown);
|
|
622
615
|
}
|
|
623
|
-
function
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
dom.removeAttribute(el, "disabled");
|
|
632
|
-
}
|
|
633
|
-
} else {
|
|
634
|
-
applyProp(dom, el, propKey, value);
|
|
616
|
+
function containFocus(dom, container) {
|
|
617
|
+
const body = dom.body();
|
|
618
|
+
if (body === null) return () => {
|
|
619
|
+
};
|
|
620
|
+
const onFocusIn = (event) => {
|
|
621
|
+
const target = event.target;
|
|
622
|
+
if (target !== null && !dom.contains(container, target)) {
|
|
623
|
+
focusFirst(dom, container);
|
|
635
624
|
}
|
|
636
625
|
};
|
|
626
|
+
dom.addEventListener(body, "focusin", onFocusIn);
|
|
627
|
+
return () => dom.removeEventListener(body, "focusin", onFocusIn);
|
|
637
628
|
}
|
|
638
|
-
function
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
629
|
+
function onEscape(dom, target, handler) {
|
|
630
|
+
const onKeydown = (event) => {
|
|
631
|
+
if (event.key === "Escape") handler();
|
|
632
|
+
};
|
|
633
|
+
dom.addEventListener(target, "keydown", onKeydown);
|
|
634
|
+
return () => dom.removeEventListener(target, "keydown", onKeydown);
|
|
645
635
|
}
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
636
|
+
|
|
637
|
+
// ../renderer/src/tag-map.ts
|
|
638
|
+
var TAG_MAP = {
|
|
639
|
+
application: "div",
|
|
640
|
+
page: "div",
|
|
641
|
+
section: "section",
|
|
642
|
+
container: "div",
|
|
643
|
+
heading: "h1",
|
|
644
|
+
text: "span",
|
|
645
|
+
button: "button",
|
|
646
|
+
input: "input",
|
|
647
|
+
form: "form",
|
|
648
|
+
list: "ul",
|
|
649
|
+
"list-item": "li",
|
|
650
|
+
image: "img",
|
|
651
|
+
link: "a",
|
|
652
|
+
component: "div",
|
|
653
|
+
slot: "div",
|
|
654
|
+
fragment: "div",
|
|
655
|
+
"reactive-list": "ul",
|
|
656
|
+
// A portal renders as a neutral inline anchor <div> at its declaration site;
|
|
657
|
+
// its children are relocated to a document.body container on the browser
|
|
658
|
+
// (see the portal branch in mount.ts). On the server (no body) it renders
|
|
659
|
+
// inline, so the anchor tag is what SSR/hydration positionally match on.
|
|
660
|
+
portal: "div"
|
|
661
|
+
};
|
|
662
|
+
function resolveTag(type) {
|
|
663
|
+
return TAG_MAP[type] ?? "div";
|
|
657
664
|
}
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
665
|
+
|
|
666
|
+
// ../renderer/src/patch.ts
|
|
667
|
+
function patchNode(ctx, graphNode, propKey, newValue) {
|
|
668
|
+
const instance = ctx.instances.get(graphNode.id);
|
|
669
|
+
if (instance === void 0) return;
|
|
670
|
+
const domNode = instance.domNode;
|
|
671
|
+
if (!ctx.dom.isElement(domNode)) return;
|
|
672
|
+
const oldValue = graphNode.getProp(propKey);
|
|
673
|
+
switch (propKey) {
|
|
674
|
+
case "text":
|
|
675
|
+
if (!Object.is(oldValue, newValue)) {
|
|
676
|
+
ctx.dom.setTextContent(domNode, String(newValue ?? ""));
|
|
677
|
+
graphNode.setProp("text", String(newValue ?? ""));
|
|
678
|
+
}
|
|
679
|
+
break;
|
|
680
|
+
case "label":
|
|
681
|
+
if (!Object.is(oldValue, newValue)) {
|
|
682
|
+
ctx.dom.setTextContent(domNode, String(newValue ?? ""));
|
|
683
|
+
graphNode.setProp("label", String(newValue ?? ""));
|
|
684
|
+
}
|
|
685
|
+
break;
|
|
686
|
+
case "disabled":
|
|
687
|
+
if (newValue === true) {
|
|
688
|
+
ctx.dom.setAttribute(domNode, "disabled", "");
|
|
669
689
|
} else {
|
|
670
|
-
|
|
690
|
+
ctx.dom.removeAttribute(domNode, "disabled");
|
|
671
691
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
);
|
|
685
|
-
listInstance.children.length = 0;
|
|
686
|
-
for (const inst of result.instances) listInstance.children.push(inst);
|
|
687
|
-
for (const removed of result.removed) {
|
|
688
|
-
forgetInstance(ctx, removed);
|
|
689
|
-
ctx.graph.detachNode(removed.graphNode);
|
|
690
|
-
}
|
|
691
|
-
const adopted = new Set(result.instances.map((i) => i.graphNode));
|
|
692
|
-
for (const node of result.built ?? []) {
|
|
693
|
-
if (!adopted.has(node)) ctx.graph.detachNode(node);
|
|
694
|
-
}
|
|
695
|
-
for (const child of [...listNode.children]) listNode.removeChild(child);
|
|
696
|
-
for (const inst of result.instances) listNode.appendChild(inst.graphNode);
|
|
697
|
-
}
|
|
698
|
-
function reconcileReactiveList(ctx, listNode, listInstance, listEl, newNodes) {
|
|
699
|
-
const oldInstances = [...listInstance.children];
|
|
700
|
-
const result = reconcileChildren(
|
|
701
|
-
ctx,
|
|
702
|
-
listEl,
|
|
703
|
-
oldInstances,
|
|
704
|
-
newNodes,
|
|
705
|
-
(node, parent) => mountNode(ctx, node, parent)
|
|
706
|
-
);
|
|
707
|
-
listInstance.children.length = 0;
|
|
708
|
-
for (const inst of result.instances) listInstance.children.push(inst);
|
|
709
|
-
for (const removed of result.removed) {
|
|
710
|
-
forgetInstance(ctx, removed);
|
|
711
|
-
ctx.graph.detachNode(removed.graphNode);
|
|
712
|
-
}
|
|
713
|
-
const adopted = new Set(result.instances.map((i) => i.graphNode));
|
|
714
|
-
for (const built of newNodes) {
|
|
715
|
-
if (!adopted.has(built)) ctx.graph.detachNode(built);
|
|
716
|
-
}
|
|
717
|
-
for (const child of [...listNode.children]) listNode.removeChild(child);
|
|
718
|
-
for (const inst of result.instances) listNode.appendChild(inst.graphNode);
|
|
719
|
-
}
|
|
720
|
-
function forgetInstance(ctx, instance) {
|
|
721
|
-
ctx.instances.delete(instance.graphNode.id);
|
|
722
|
-
for (const child of instance.children) forgetInstance(ctx, child);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
// ../dom/src/server-node.ts
|
|
726
|
-
var ServerStyle = class {
|
|
727
|
-
declarations = /* @__PURE__ */ new Map();
|
|
728
|
-
setProperty(name, value) {
|
|
729
|
-
this.declarations.set(name, value);
|
|
730
|
-
}
|
|
731
|
-
get isEmpty() {
|
|
732
|
-
return this.declarations.size === 0;
|
|
733
|
-
}
|
|
734
|
-
toCss() {
|
|
735
|
-
return [...this.declarations.entries()].map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
736
|
-
}
|
|
737
|
-
};
|
|
738
|
-
var ServerText = class {
|
|
739
|
-
kind = "text";
|
|
740
|
-
parent = null;
|
|
741
|
-
data;
|
|
742
|
-
constructor(data) {
|
|
743
|
-
this.data = data;
|
|
744
|
-
}
|
|
745
|
-
};
|
|
746
|
-
var ServerComment = class {
|
|
747
|
-
kind = "comment";
|
|
748
|
-
parent = null;
|
|
749
|
-
data;
|
|
750
|
-
constructor(data) {
|
|
751
|
-
this.data = data;
|
|
752
|
-
}
|
|
753
|
-
};
|
|
754
|
-
var ServerFragment = class {
|
|
755
|
-
kind = "fragment";
|
|
756
|
-
parent = null;
|
|
757
|
-
children = [];
|
|
758
|
-
};
|
|
759
|
-
var ServerElement = class {
|
|
760
|
-
kind = "element";
|
|
761
|
-
parent = null;
|
|
762
|
-
tagName;
|
|
763
|
-
attributes = /* @__PURE__ */ new Map();
|
|
764
|
-
children = [];
|
|
765
|
-
// Lazily-allocated stores. On the 10k-row SSR corpus ~0% of elements carry JS
|
|
766
|
-
// properties or inline styles (measured, §5: 1 of 80,029 elements uses
|
|
767
|
-
// `properties`, 0 use `style`), so eagerly allocating a `properties` Map plus
|
|
768
|
-
// a `ServerStyle` (which itself holds a Map) per element wasted ~240k
|
|
769
|
-
// allocations per /users render — all in the dominant mount phase. These are
|
|
770
|
-
// created on first WRITE via the `properties`/`style` getters; the serializer
|
|
771
|
-
// reads the raw `_properties`/`_style` fields so a READ never forces an
|
|
772
|
-
// allocation. Output is byte-identical: an unset store previously serialized
|
|
773
|
-
// to nothing (empty `properties.has(...)` / `style.isEmpty`), and a null store
|
|
774
|
-
// is skipped the same way.
|
|
775
|
-
_properties = null;
|
|
776
|
-
_style = null;
|
|
777
|
-
constructor(tagName) {
|
|
778
|
-
this.tagName = tagName.toLowerCase();
|
|
692
|
+
graphNode.setProp("disabled", Boolean(newValue));
|
|
693
|
+
break;
|
|
694
|
+
case "value":
|
|
695
|
+
if (!Object.is(oldValue, newValue)) {
|
|
696
|
+
ctx.dom.setProperty(domNode, "value", String(newValue ?? ""));
|
|
697
|
+
graphNode.setProp("value", String(newValue ?? ""));
|
|
698
|
+
}
|
|
699
|
+
break;
|
|
700
|
+
default:
|
|
701
|
+
patchProp(ctx.dom, domNode, propKey, oldValue, newValue);
|
|
702
|
+
graphNode.setProp(propKey, newValue);
|
|
703
|
+
break;
|
|
779
704
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// ../renderer/src/reconciliation.ts
|
|
708
|
+
function reconcileChildren(ctx, parentDom, oldInstances, newNodes, mountFn) {
|
|
709
|
+
const oldByKey = /* @__PURE__ */ new Map();
|
|
710
|
+
for (const inst of oldInstances) {
|
|
711
|
+
const key = inst.graphNode.key ?? inst.graphNode.id;
|
|
712
|
+
oldByKey.set(key, inst);
|
|
783
713
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
714
|
+
const newInstances = [];
|
|
715
|
+
const usedKeys = /* @__PURE__ */ new Set();
|
|
716
|
+
for (const newNode of newNodes) {
|
|
717
|
+
const key = newNode.key ?? newNode.id;
|
|
718
|
+
const existing = oldByKey.get(key);
|
|
719
|
+
if (existing !== void 0) {
|
|
720
|
+
usedKeys.add(key);
|
|
721
|
+
const oldSig = existing.graphNode.getProp("_sig");
|
|
722
|
+
const newSig = newNode.getProp("_sig");
|
|
723
|
+
patchExistingInstance(ctx, existing, newNode);
|
|
724
|
+
if (!Object.is(oldSig, newSig)) {
|
|
725
|
+
reconcileItemChildren(ctx, existing, newNode, mountFn);
|
|
726
|
+
}
|
|
727
|
+
newInstances.push(existing);
|
|
728
|
+
} else {
|
|
729
|
+
const inst = mountFn(newNode, parentDom);
|
|
730
|
+
newInstances.push(inst);
|
|
731
|
+
}
|
|
787
732
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
"col",
|
|
794
|
-
"embed",
|
|
795
|
-
"hr",
|
|
796
|
-
"img",
|
|
797
|
-
"input",
|
|
798
|
-
"link",
|
|
799
|
-
"meta",
|
|
800
|
-
"param",
|
|
801
|
-
"source",
|
|
802
|
-
"track",
|
|
803
|
-
"wbr"
|
|
804
|
-
]);
|
|
805
|
-
var SERIALIZED_PROPERTIES = {
|
|
806
|
-
value: "attr",
|
|
807
|
-
checked: "boolean",
|
|
808
|
-
selected: "boolean"
|
|
809
|
-
};
|
|
810
|
-
var SERIALIZED_PROPERTY_ENTRIES = Object.entries(SERIALIZED_PROPERTIES);
|
|
811
|
-
var TEXT_SPECIAL = /[&<>]/;
|
|
812
|
-
var ATTR_SPECIAL = /[&<>"]/;
|
|
813
|
-
function escapeHtmlText(value) {
|
|
814
|
-
if (!TEXT_SPECIAL.test(value)) return value;
|
|
815
|
-
let out = "";
|
|
816
|
-
let last = 0;
|
|
817
|
-
for (let i = 0; i < value.length; i++) {
|
|
818
|
-
let esc;
|
|
819
|
-
switch (value.charCodeAt(i)) {
|
|
820
|
-
case 38:
|
|
821
|
-
esc = "&";
|
|
822
|
-
break;
|
|
823
|
-
// &
|
|
824
|
-
case 60:
|
|
825
|
-
esc = "<";
|
|
826
|
-
break;
|
|
827
|
-
// <
|
|
828
|
-
case 62:
|
|
829
|
-
esc = ">";
|
|
830
|
-
break;
|
|
831
|
-
// >
|
|
832
|
-
default:
|
|
833
|
-
continue;
|
|
733
|
+
const removed = [];
|
|
734
|
+
for (const inst of oldInstances) {
|
|
735
|
+
const key = inst.graphNode.key ?? inst.graphNode.id;
|
|
736
|
+
if (!usedKeys.has(key)) {
|
|
737
|
+
removed.push(inst);
|
|
834
738
|
}
|
|
835
|
-
out += value.slice(last, i) + esc;
|
|
836
|
-
last = i + 1;
|
|
837
739
|
}
|
|
838
|
-
|
|
740
|
+
for (const inst of removed) {
|
|
741
|
+
const parent = ctx.dom.parentNode(inst.domNode);
|
|
742
|
+
if (parent !== null) {
|
|
743
|
+
ctx.dom.removeChild(parent, inst.domNode);
|
|
744
|
+
}
|
|
745
|
+
inst.dispose();
|
|
746
|
+
}
|
|
747
|
+
reorderDom(ctx, parentDom, newInstances);
|
|
748
|
+
return { instances: newInstances, removed };
|
|
839
749
|
}
|
|
840
|
-
function
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
750
|
+
function reconcileChildrenByPlan(ctx, parentDom, oldInstances, plan, mountFn) {
|
|
751
|
+
const oldByKey = /* @__PURE__ */ new Map();
|
|
752
|
+
for (const inst of oldInstances) {
|
|
753
|
+
oldByKey.set(inst.graphNode.key ?? inst.graphNode.id, inst);
|
|
754
|
+
}
|
|
755
|
+
const newInstances = [];
|
|
756
|
+
const usedKeys = /* @__PURE__ */ new Set();
|
|
757
|
+
const built = [];
|
|
758
|
+
for (const entry of plan) {
|
|
759
|
+
const existing = oldByKey.get(entry.key);
|
|
760
|
+
if (existing !== void 0) {
|
|
761
|
+
usedKeys.add(entry.key);
|
|
762
|
+
const oldItem = existing.graphNode.getProp("_item");
|
|
763
|
+
if (!Object.is(oldItem, entry.item)) {
|
|
764
|
+
const newSig = entry.sig();
|
|
765
|
+
const oldSig = existing.graphNode.getProp("_sig");
|
|
766
|
+
if (!Object.is(oldSig, newSig)) {
|
|
767
|
+
const freshNode = entry.build();
|
|
768
|
+
built.push(freshNode);
|
|
769
|
+
patchExistingInstance(ctx, existing, freshNode);
|
|
770
|
+
reconcileItemChildren(ctx, existing, freshNode, mountFn);
|
|
771
|
+
existing.graphNode.setProp("_sig", newSig);
|
|
772
|
+
}
|
|
773
|
+
existing.graphNode.setProp("_item", entry.item);
|
|
774
|
+
}
|
|
775
|
+
newInstances.push(existing);
|
|
776
|
+
} else {
|
|
777
|
+
const freshNode = entry.build();
|
|
778
|
+
built.push(freshNode);
|
|
779
|
+
const inst = mountFn(freshNode, parentDom);
|
|
780
|
+
newInstances.push(inst);
|
|
865
781
|
}
|
|
866
|
-
out += value.slice(last, i) + esc;
|
|
867
|
-
last = i + 1;
|
|
868
782
|
}
|
|
869
|
-
|
|
783
|
+
const removed = [];
|
|
784
|
+
for (const inst of oldInstances) {
|
|
785
|
+
const key = inst.graphNode.key ?? inst.graphNode.id;
|
|
786
|
+
if (!usedKeys.has(key)) removed.push(inst);
|
|
787
|
+
}
|
|
788
|
+
for (const inst of removed) {
|
|
789
|
+
const parent = ctx.dom.parentNode(inst.domNode);
|
|
790
|
+
if (parent !== null) ctx.dom.removeChild(parent, inst.domNode);
|
|
791
|
+
inst.dispose();
|
|
792
|
+
}
|
|
793
|
+
reorderDomMinimal(ctx, parentDom, oldInstances, newInstances);
|
|
794
|
+
return { instances: newInstances, removed, built };
|
|
870
795
|
}
|
|
871
|
-
function
|
|
872
|
-
const
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
796
|
+
function reorderDomMinimal(ctx, parentDom, oldInstances, newInstances) {
|
|
797
|
+
const n = newInstances.length;
|
|
798
|
+
if (n === 0) return;
|
|
799
|
+
const oldIndexOf = /* @__PURE__ */ new Map();
|
|
800
|
+
for (let i = 0; i < oldInstances.length; i++) oldIndexOf.set(oldInstances[i], i);
|
|
801
|
+
const source = new Array(n);
|
|
802
|
+
let moved = false;
|
|
803
|
+
let lastSeen = -1;
|
|
804
|
+
for (let i = 0; i < n; i++) {
|
|
805
|
+
const oi = oldIndexOf.get(newInstances[i]);
|
|
806
|
+
if (oi === void 0) {
|
|
807
|
+
source[i] = -1;
|
|
808
|
+
moved = true;
|
|
876
809
|
} else {
|
|
877
|
-
|
|
810
|
+
source[i] = oi;
|
|
811
|
+
if (oi < lastSeen) moved = true;
|
|
812
|
+
else lastSeen = oi;
|
|
878
813
|
}
|
|
879
814
|
}
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
if (
|
|
887
|
-
|
|
888
|
-
} else {
|
|
889
|
-
if (raw !== void 0 && raw !== null) {
|
|
890
|
-
parts.push(` ${name}="${escapeHtmlAttr(String(raw))}"`);
|
|
891
|
-
}
|
|
815
|
+
if (!moved) return;
|
|
816
|
+
const keep = longestIncreasingSubsequence(source);
|
|
817
|
+
let refNode = null;
|
|
818
|
+
for (let i = n - 1; i >= 0; i--) {
|
|
819
|
+
const domNode = newInstances[i].domNode;
|
|
820
|
+
if (source[i] === -1 || !keep.has(i)) {
|
|
821
|
+
if (ctx.dom.nextSibling(domNode) !== refNode) {
|
|
822
|
+
ctx.dom.insertBefore(parentDom, domNode, refNode);
|
|
892
823
|
}
|
|
893
824
|
}
|
|
825
|
+
refNode = domNode;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
function longestIncreasingSubsequence(source) {
|
|
829
|
+
const keep = /* @__PURE__ */ new Set();
|
|
830
|
+
const n = source.length;
|
|
831
|
+
const tails = [];
|
|
832
|
+
const prev = new Array(n).fill(-1);
|
|
833
|
+
for (let i = 0; i < n; i++) {
|
|
834
|
+
const v = source[i];
|
|
835
|
+
if (v < 0) continue;
|
|
836
|
+
let lo = 0;
|
|
837
|
+
let hi = tails.length;
|
|
838
|
+
while (lo < hi) {
|
|
839
|
+
const mid = lo + hi >> 1;
|
|
840
|
+
if (source[tails[mid]] < v) lo = mid + 1;
|
|
841
|
+
else hi = mid;
|
|
842
|
+
}
|
|
843
|
+
if (lo > 0) prev[i] = tails[lo - 1];
|
|
844
|
+
tails[lo] = i;
|
|
845
|
+
}
|
|
846
|
+
let idx = tails.length > 0 ? tails[tails.length - 1] : -1;
|
|
847
|
+
while (idx >= 0) {
|
|
848
|
+
keep.add(idx);
|
|
849
|
+
idx = prev[idx];
|
|
850
|
+
}
|
|
851
|
+
return keep;
|
|
852
|
+
}
|
|
853
|
+
function reconcileItemChildren(ctx, itemInstance, newItemNode, mountFn) {
|
|
854
|
+
const el = itemInstance.domNode;
|
|
855
|
+
if (!ctx.dom.isElement(el)) return;
|
|
856
|
+
const oldChildren = [...itemInstance.children];
|
|
857
|
+
const newChildNodes = [...newItemNode.children];
|
|
858
|
+
const nextChildren = [];
|
|
859
|
+
const kept = /* @__PURE__ */ new Set();
|
|
860
|
+
for (let i = 0; i < newChildNodes.length; i++) {
|
|
861
|
+
const newChild = newChildNodes[i];
|
|
862
|
+
const oldChild = oldChildren[i];
|
|
863
|
+
if (oldChild !== void 0 && oldChild.graphNode.type === newChild.type) {
|
|
864
|
+
patchExistingInstance(ctx, oldChild, newChild);
|
|
865
|
+
reconcileItemChildren(ctx, oldChild, newChild, mountFn);
|
|
866
|
+
nextChildren.push(oldChild);
|
|
867
|
+
kept.add(oldChild);
|
|
868
|
+
} else {
|
|
869
|
+
itemInstance.graphNode.appendChild(newChild);
|
|
870
|
+
const inst = mountFn(newChild, el);
|
|
871
|
+
nextChildren.push(inst);
|
|
872
|
+
}
|
|
894
873
|
}
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
874
|
+
for (const old of oldChildren) {
|
|
875
|
+
if (kept.has(old)) continue;
|
|
876
|
+
const parent = ctx.dom.parentNode(old.domNode);
|
|
877
|
+
if (parent !== null) ctx.dom.removeChild(parent, old.domNode);
|
|
878
|
+
old.dispose();
|
|
879
|
+
forgetInstanceTree(ctx, old);
|
|
880
|
+
ctx.graph.detachNode(old.graphNode);
|
|
898
881
|
}
|
|
899
|
-
|
|
882
|
+
reorderDom(ctx, el, nextChildren);
|
|
883
|
+
itemInstance.children.length = 0;
|
|
884
|
+
for (const c of nextChildren) itemInstance.children.push(c);
|
|
885
|
+
for (const c of [...itemInstance.graphNode.children]) {
|
|
886
|
+
itemInstance.graphNode.removeChild(c);
|
|
887
|
+
}
|
|
888
|
+
for (const c of nextChildren) itemInstance.graphNode.appendChild(c.graphNode);
|
|
900
889
|
}
|
|
901
|
-
function
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
const el = node;
|
|
911
|
-
const tag = el.tagName;
|
|
912
|
-
const attrs = serializeAttributes(el);
|
|
913
|
-
if (VOID_ELEMENTS.has(tag)) {
|
|
914
|
-
return `<${tag}${attrs}>`;
|
|
915
|
-
}
|
|
916
|
-
return `<${tag}${attrs}>${serializeChildren(el)}</${tag}>`;
|
|
890
|
+
function reorderDom(ctx, parentDom, instances) {
|
|
891
|
+
let referenceNode = null;
|
|
892
|
+
for (let i = instances.length - 1; i >= 0; i--) {
|
|
893
|
+
const inst = instances[i];
|
|
894
|
+
if (inst === void 0) continue;
|
|
895
|
+
const domNode = inst.domNode;
|
|
896
|
+
const currentNext = ctx.dom.nextSibling(domNode);
|
|
897
|
+
if (currentNext !== referenceNode) {
|
|
898
|
+
ctx.dom.insertBefore(parentDom, domNode, referenceNode);
|
|
917
899
|
}
|
|
900
|
+
referenceNode = domNode;
|
|
918
901
|
}
|
|
919
902
|
}
|
|
920
|
-
function
|
|
921
|
-
|
|
922
|
-
for (const child of
|
|
923
|
-
|
|
903
|
+
function forgetInstanceTree(ctx, instance) {
|
|
904
|
+
ctx.instances.delete(instance.graphNode.id);
|
|
905
|
+
for (const child of instance.children) forgetInstanceTree(ctx, child);
|
|
906
|
+
}
|
|
907
|
+
function patchExistingInstance(ctx, instance, newNode) {
|
|
908
|
+
const oldNode = instance.graphNode;
|
|
909
|
+
for (const [key, newVal] of Object.entries(newNode.props)) {
|
|
910
|
+
const oldVal = oldNode.getProp(key);
|
|
911
|
+
if (!Object.is(oldVal, newVal)) {
|
|
912
|
+
patchNode(ctx, instance.graphNode, key, newVal);
|
|
913
|
+
}
|
|
924
914
|
}
|
|
925
|
-
return out;
|
|
926
915
|
}
|
|
927
916
|
|
|
928
|
-
// ../
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
917
|
+
// ../renderer/src/mount.ts
|
|
918
|
+
var SKIP_PROP_KEYS = /* @__PURE__ */ new Set([
|
|
919
|
+
"text",
|
|
920
|
+
"label",
|
|
921
|
+
"level",
|
|
922
|
+
"inputType",
|
|
923
|
+
"src",
|
|
924
|
+
"alt",
|
|
925
|
+
"href",
|
|
926
|
+
"external",
|
|
927
|
+
"value",
|
|
928
|
+
"placeholder",
|
|
929
|
+
"disabled",
|
|
930
|
+
"_renderKey",
|
|
931
|
+
"key",
|
|
932
|
+
"name"
|
|
933
|
+
]);
|
|
934
|
+
function mountGraph(ctx) {
|
|
935
|
+
return mountNode(ctx, ctx.graph.root, ctx.container);
|
|
934
936
|
}
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
return new ServerFragment();
|
|
947
|
-
}
|
|
948
|
-
appendChild(parent, child) {
|
|
949
|
-
const p = asParent(parent);
|
|
950
|
-
const c = asServer(child);
|
|
951
|
-
this._detach(c);
|
|
952
|
-
c.parent = p;
|
|
953
|
-
p.children.push(c);
|
|
954
|
-
}
|
|
955
|
-
insertBefore(parent, child, reference) {
|
|
956
|
-
const p = asParent(parent);
|
|
957
|
-
const c = asServer(child);
|
|
958
|
-
this._detach(c);
|
|
959
|
-
c.parent = p;
|
|
960
|
-
if (reference === null) {
|
|
961
|
-
p.children.push(c);
|
|
962
|
-
return;
|
|
937
|
+
function mountNode(ctx, graphNode, parentDom) {
|
|
938
|
+
const { dom, graph } = ctx;
|
|
939
|
+
const staticHTML = ctx.staticHTML;
|
|
940
|
+
if (staticHTML !== void 0 && dom.createRawHTML !== void 0) {
|
|
941
|
+
const precomputed = staticHTML.get(graphNode.id);
|
|
942
|
+
if (precomputed !== void 0) {
|
|
943
|
+
const raw = dom.createRawHTML(precomputed);
|
|
944
|
+
dom.appendChild(parentDom, raw);
|
|
945
|
+
const instance2 = new NodeInstance(graphNode, raw);
|
|
946
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
947
|
+
return instance2;
|
|
963
948
|
}
|
|
964
|
-
const ref = asServer(reference);
|
|
965
|
-
const idx = p.children.indexOf(ref);
|
|
966
|
-
if (idx === -1) p.children.push(c);
|
|
967
|
-
else p.children.splice(idx, 0, c);
|
|
968
949
|
}
|
|
969
|
-
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
const
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
c.parent = null;
|
|
950
|
+
if (graphNode.type === "application") {
|
|
951
|
+
const instance2 = new NodeInstance(graphNode, parentDom);
|
|
952
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
953
|
+
for (const child of graphNode.children) {
|
|
954
|
+
const childInstance = mountNode(ctx, child, parentDom);
|
|
955
|
+
instance2.addChild(childInstance);
|
|
976
956
|
}
|
|
957
|
+
return instance2;
|
|
977
958
|
}
|
|
978
|
-
|
|
979
|
-
const
|
|
980
|
-
const
|
|
981
|
-
const
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
_detach(node) {
|
|
990
|
-
if (node.parent !== null) {
|
|
991
|
-
const siblings = node.parent.children;
|
|
992
|
-
const idx = siblings.indexOf(node);
|
|
993
|
-
if (idx !== -1) siblings.splice(idx, 1);
|
|
994
|
-
node.parent = null;
|
|
959
|
+
if (graphNode.type === "text") {
|
|
960
|
+
const text = String(graphNode.getProp("text") ?? "");
|
|
961
|
+
const el2 = dom.createElement("span");
|
|
962
|
+
const textNode = dom.createTextNode(text);
|
|
963
|
+
dom.appendChild(el2, textNode);
|
|
964
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
965
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
966
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
967
|
+
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
968
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
969
|
+
wireSignalBindings(ctx, graphNode, instance2, textUpdate(dom, el2, textNode));
|
|
995
970
|
}
|
|
971
|
+
dom.appendChild(parentDom, el2);
|
|
972
|
+
return instance2;
|
|
996
973
|
}
|
|
997
|
-
|
|
998
|
-
|
|
974
|
+
if (graphNode.type === "heading") {
|
|
975
|
+
const level = graphNode.getProp("level") ?? 1;
|
|
976
|
+
const tag2 = `h${level}`;
|
|
977
|
+
const el2 = dom.createElement(tag2);
|
|
978
|
+
const text = String(graphNode.getProp("text") ?? "");
|
|
979
|
+
dom.setTextContent(el2, text);
|
|
980
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
981
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
982
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
983
|
+
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
984
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
985
|
+
wireSignalBindings(ctx, graphNode, instance2, headingUpdate(dom, el2));
|
|
986
|
+
}
|
|
987
|
+
dom.appendChild(parentDom, el2);
|
|
988
|
+
return instance2;
|
|
999
989
|
}
|
|
1000
|
-
|
|
1001
|
-
|
|
990
|
+
if (graphNode.type === "input") {
|
|
991
|
+
const el2 = dom.createElement("input");
|
|
992
|
+
const inputType = String(graphNode.getProp("inputType") ?? "text");
|
|
993
|
+
dom.setAttribute(el2, "type", inputType);
|
|
994
|
+
const placeholder = graphNode.getProp("placeholder");
|
|
995
|
+
if (placeholder !== void 0) dom.setAttribute(el2, "placeholder", String(placeholder));
|
|
996
|
+
const value = graphNode.getProp("value");
|
|
997
|
+
if (value !== void 0) dom.setProperty(el2, "value", String(value));
|
|
998
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
999
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
1000
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1001
|
+
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
1002
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
1003
|
+
wireSignalBindings(ctx, graphNode, instance2, inputUpdate(dom, el2));
|
|
1004
|
+
}
|
|
1005
|
+
dom.appendChild(parentDom, el2);
|
|
1006
|
+
return instance2;
|
|
1002
1007
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1008
|
+
if (graphNode.type === "image") {
|
|
1009
|
+
const el2 = dom.createElement("img");
|
|
1010
|
+
const src = graphNode.getProp("src");
|
|
1011
|
+
const alt = graphNode.getProp("alt");
|
|
1012
|
+
if (src !== void 0) dom.setAttribute(el2, "src", String(src));
|
|
1013
|
+
if (alt !== void 0) dom.setAttribute(el2, "alt", String(alt));
|
|
1014
|
+
const width = graphNode.getProp("width");
|
|
1015
|
+
const height = graphNode.getProp("height");
|
|
1016
|
+
if (width !== void 0) dom.setAttribute(el2, "width", String(width));
|
|
1017
|
+
if (height !== void 0) dom.setAttribute(el2, "height", String(height));
|
|
1018
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
1019
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
1020
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1021
|
+
dom.appendChild(parentDom, el2);
|
|
1022
|
+
return instance2;
|
|
1005
1023
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1024
|
+
if (graphNode.type === "link") {
|
|
1025
|
+
const el2 = dom.createElement("a");
|
|
1026
|
+
const href = graphNode.getProp("href");
|
|
1027
|
+
const label = graphNode.getProp("label");
|
|
1028
|
+
const external = graphNode.getProp("external");
|
|
1029
|
+
if (href !== void 0) dom.setAttribute(el2, "href", String(href));
|
|
1030
|
+
if (label !== void 0) dom.setTextContent(el2, String(label));
|
|
1031
|
+
if (external === true) {
|
|
1032
|
+
dom.setAttribute(el2, "target", "_blank");
|
|
1033
|
+
dom.setAttribute(el2, "rel", "noopener noreferrer");
|
|
1034
|
+
}
|
|
1035
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
1036
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
1037
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1038
|
+
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
1039
|
+
dom.appendChild(parentDom, el2);
|
|
1040
|
+
return instance2;
|
|
1008
1041
|
}
|
|
1009
|
-
|
|
1010
|
-
const
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1042
|
+
if (graphNode.type === "button") {
|
|
1043
|
+
const el2 = dom.createElement("button");
|
|
1044
|
+
const label = graphNode.getProp("label");
|
|
1045
|
+
if (label !== void 0) dom.setTextContent(el2, String(label));
|
|
1046
|
+
const disabled = graphNode.getProp("disabled");
|
|
1047
|
+
if (disabled === true) dom.setAttribute(el2, "disabled", "");
|
|
1048
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
1049
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
1050
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1051
|
+
wireEvents(dom, graph, graphNode, el2, instance2);
|
|
1052
|
+
if (graphNode.stateRefs.length !== 0) {
|
|
1053
|
+
wireSignalBindings(ctx, graphNode, instance2, buttonUpdate(dom, el2));
|
|
1019
1054
|
}
|
|
1055
|
+
dom.appendChild(parentDom, el2);
|
|
1056
|
+
return instance2;
|
|
1020
1057
|
}
|
|
1021
|
-
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1058
|
+
if (graphNode.type === "reactive-list" || graphNode.type === "conditional") {
|
|
1059
|
+
const tag2 = resolveTag(graphNode.type);
|
|
1060
|
+
const el2 = dom.createElement(tag2);
|
|
1061
|
+
applyNodeProps(ctx, graphNode, el2);
|
|
1062
|
+
const instance2 = new NodeInstance(graphNode, el2);
|
|
1063
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1064
|
+
for (const child of graphNode.children) {
|
|
1065
|
+
const childInstance = mountNode(ctx, child, el2);
|
|
1066
|
+
instance2.addChild(childInstance);
|
|
1030
1067
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
addEventListener() {
|
|
1035
|
-
}
|
|
1036
|
-
removeEventListener() {
|
|
1068
|
+
dom.appendChild(parentDom, el2);
|
|
1069
|
+
wireReactiveList(ctx, graphNode, instance2, el2);
|
|
1070
|
+
return instance2;
|
|
1037
1071
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1072
|
+
if (graphNode.type === "portal") {
|
|
1073
|
+
const anchor = dom.createElement(resolveTag("portal"));
|
|
1074
|
+
dom.setAttribute(anchor, "data-streetui-portal", "");
|
|
1075
|
+
applyNodeProps(ctx, graphNode, anchor);
|
|
1076
|
+
const instance2 = new NodeInstance(graphNode, anchor);
|
|
1077
|
+
ctx.instances.set(graphNode.id, instance2);
|
|
1078
|
+
const body = dom.body();
|
|
1079
|
+
let target = anchor;
|
|
1080
|
+
if (body !== null) {
|
|
1081
|
+
const portalContainer = dom.createElement("div");
|
|
1082
|
+
dom.setAttribute(portalContainer, "data-streetui-portal-container", "");
|
|
1083
|
+
dom.appendChild(body, portalContainer);
|
|
1084
|
+
instance2.trackCleanup(() => dom.removeChild(body, portalContainer));
|
|
1085
|
+
target = portalContainer;
|
|
1086
|
+
}
|
|
1087
|
+
for (const child of graphNode.children) {
|
|
1088
|
+
instance2.addChild(mountNode(ctx, child, target));
|
|
1089
|
+
}
|
|
1090
|
+
dom.appendChild(parentDom, anchor);
|
|
1091
|
+
wireOverlayBehavior(ctx, graphNode, instance2, target);
|
|
1092
|
+
return instance2;
|
|
1040
1093
|
}
|
|
1041
|
-
|
|
1042
|
-
|
|
1094
|
+
const tag = resolveTag(graphNode.type);
|
|
1095
|
+
const el = dom.createElement(tag);
|
|
1096
|
+
applyNodeProps(ctx, graphNode, el);
|
|
1097
|
+
if (graphNode.type === "list-item") {
|
|
1098
|
+
const itemKey = graphNode.getProp("key");
|
|
1099
|
+
if (itemKey !== void 0) {
|
|
1100
|
+
dom.setAttribute(el, "data-streetui-key", String(itemKey));
|
|
1101
|
+
}
|
|
1043
1102
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1103
|
+
const instance = new NodeInstance(graphNode, el);
|
|
1104
|
+
ctx.instances.set(graphNode.id, instance);
|
|
1105
|
+
if (graphNode.type === "form") {
|
|
1106
|
+
wireEvents(dom, graph, graphNode, el, instance);
|
|
1046
1107
|
}
|
|
1047
|
-
|
|
1108
|
+
for (const child of graphNode.children) {
|
|
1109
|
+
const childInstance = mountNode(ctx, child, el);
|
|
1110
|
+
instance.addChild(childInstance);
|
|
1048
1111
|
}
|
|
1049
|
-
|
|
1050
|
-
|
|
1112
|
+
dom.appendChild(parentDom, el);
|
|
1113
|
+
return instance;
|
|
1114
|
+
}
|
|
1115
|
+
function textUpdate(dom, el, textNode) {
|
|
1116
|
+
return (propKey, value) => {
|
|
1117
|
+
if (propKey === "text") {
|
|
1118
|
+
dom.setTextContent(textNode, String(value ?? ""));
|
|
1119
|
+
} else {
|
|
1120
|
+
applyProp(dom, el, propKey, value);
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
function headingUpdate(dom, el) {
|
|
1125
|
+
return (propKey, value) => {
|
|
1126
|
+
if (propKey === "text") {
|
|
1127
|
+
dom.setTextContent(el, String(value ?? ""));
|
|
1128
|
+
} else {
|
|
1129
|
+
applyProp(dom, el, propKey, value);
|
|
1130
|
+
}
|
|
1131
|
+
};
|
|
1132
|
+
}
|
|
1133
|
+
function inputUpdate(dom, el) {
|
|
1134
|
+
return (propKey, value) => {
|
|
1135
|
+
if (propKey === "value") {
|
|
1136
|
+
dom.setProperty(el, "value", String(value ?? ""));
|
|
1137
|
+
} else {
|
|
1138
|
+
applyProp(dom, el, propKey, value);
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
}
|
|
1142
|
+
function buttonUpdate(dom, el) {
|
|
1143
|
+
return (propKey, value) => {
|
|
1144
|
+
if (propKey === "label") {
|
|
1145
|
+
dom.setTextContent(el, String(value ?? ""));
|
|
1146
|
+
} else if (propKey === "disabled") {
|
|
1147
|
+
if (value === true) {
|
|
1148
|
+
dom.setAttribute(el, "disabled", "");
|
|
1149
|
+
} else {
|
|
1150
|
+
dom.removeAttribute(el, "disabled");
|
|
1151
|
+
}
|
|
1152
|
+
} else {
|
|
1153
|
+
applyProp(dom, el, propKey, value);
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
function applyNodeProps(ctx, graphNode, el) {
|
|
1158
|
+
const props = graphNode.props;
|
|
1159
|
+
for (const key in props) {
|
|
1160
|
+
if (!Object.hasOwn(props, key)) continue;
|
|
1161
|
+
if (SKIP_PROP_KEYS.has(key)) continue;
|
|
1162
|
+
applyProp(ctx.dom, el, key, props[key]);
|
|
1051
1163
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1164
|
+
}
|
|
1165
|
+
function wireSignalBindings(ctx, graphNode, instance, onUpdate) {
|
|
1166
|
+
if (graphNode.stateRefs.length === 0) return;
|
|
1167
|
+
for (const stateRef of graphNode.stateRefs) {
|
|
1168
|
+
const signalKey = `__signal__${stateRef.signalId}`;
|
|
1169
|
+
const maybeSig = ctx.graph.getHandler(signalKey);
|
|
1170
|
+
if (maybeSig === void 0 || typeof maybeSig.subscribe !== "function") continue;
|
|
1171
|
+
const unsub = maybeSig.subscribe((value) => {
|
|
1172
|
+
onUpdate(stateRef.propKey, value);
|
|
1173
|
+
});
|
|
1174
|
+
instance.trackCleanup(unsub);
|
|
1054
1175
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1176
|
+
}
|
|
1177
|
+
function wireReactiveList(ctx, graphNode, instance, el) {
|
|
1178
|
+
const plan = ctx.graph.getHandler(`__listplan__${graphNode.id}`);
|
|
1179
|
+
const build = ctx.graph.getHandler(`__listbuild__${graphNode.id}`);
|
|
1180
|
+
if (plan === void 0 && build === void 0) return;
|
|
1181
|
+
for (const stateRef of graphNode.stateRefs) {
|
|
1182
|
+
if (stateRef.propKey !== "items") continue;
|
|
1183
|
+
const sig = ctx.graph.getHandler(`__signal__${stateRef.signalId}`);
|
|
1184
|
+
if (sig === void 0 || typeof sig.subscribe !== "function") continue;
|
|
1185
|
+
const unsub = sig.subscribe((value) => {
|
|
1186
|
+
if (plan !== void 0) {
|
|
1187
|
+
reconcileReactiveListByPlan(ctx, graphNode, instance, el, plan(value));
|
|
1188
|
+
} else {
|
|
1189
|
+
reconcileReactiveList(ctx, graphNode, instance, el, build(value));
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
instance.trackCleanup(unsub);
|
|
1057
1193
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1194
|
+
}
|
|
1195
|
+
function reconcileReactiveListByPlan(ctx, listNode, listInstance, listEl, plan) {
|
|
1196
|
+
const oldInstances = [...listInstance.children];
|
|
1197
|
+
const result = reconcileChildrenByPlan(
|
|
1198
|
+
ctx,
|
|
1199
|
+
listEl,
|
|
1200
|
+
oldInstances,
|
|
1201
|
+
plan,
|
|
1202
|
+
(node, parent) => mountNode(ctx, node, parent)
|
|
1203
|
+
);
|
|
1204
|
+
listInstance.children.length = 0;
|
|
1205
|
+
for (const inst of result.instances) listInstance.children.push(inst);
|
|
1206
|
+
for (const removed of result.removed) {
|
|
1207
|
+
forgetInstance(ctx, removed);
|
|
1208
|
+
ctx.graph.detachNode(removed.graphNode);
|
|
1060
1209
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
if (parent === null) return null;
|
|
1065
|
-
const idx = parent.children.indexOf(n);
|
|
1066
|
-
if (idx === -1 || idx + 1 >= parent.children.length) return null;
|
|
1067
|
-
return parent.children[idx + 1];
|
|
1210
|
+
const adopted = new Set(result.instances.map((i) => i.graphNode));
|
|
1211
|
+
for (const node of result.built ?? []) {
|
|
1212
|
+
if (!adopted.has(node)) ctx.graph.detachNode(node);
|
|
1068
1213
|
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1214
|
+
for (const child of [...listNode.children]) listNode.removeChild(child);
|
|
1215
|
+
for (const inst of result.instances) listNode.appendChild(inst.graphNode);
|
|
1216
|
+
}
|
|
1217
|
+
function reconcileReactiveList(ctx, listNode, listInstance, listEl, newNodes) {
|
|
1218
|
+
const oldInstances = [...listInstance.children];
|
|
1219
|
+
const result = reconcileChildren(
|
|
1220
|
+
ctx,
|
|
1221
|
+
listEl,
|
|
1222
|
+
oldInstances,
|
|
1223
|
+
newNodes,
|
|
1224
|
+
(node, parent) => mountNode(ctx, node, parent)
|
|
1225
|
+
);
|
|
1226
|
+
listInstance.children.length = 0;
|
|
1227
|
+
for (const inst of result.instances) listInstance.children.push(inst);
|
|
1228
|
+
for (const removed of result.removed) {
|
|
1229
|
+
forgetInstance(ctx, removed);
|
|
1230
|
+
ctx.graph.detachNode(removed.graphNode);
|
|
1076
1231
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
if (
|
|
1080
|
-
return n.children;
|
|
1081
|
-
}
|
|
1082
|
-
return [];
|
|
1232
|
+
const adopted = new Set(result.instances.map((i) => i.graphNode));
|
|
1233
|
+
for (const built of newNodes) {
|
|
1234
|
+
if (!adopted.has(built)) ctx.graph.detachNode(built);
|
|
1083
1235
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1236
|
+
for (const child of [...listNode.children]) listNode.removeChild(child);
|
|
1237
|
+
for (const inst of result.instances) listNode.appendChild(inst.graphNode);
|
|
1238
|
+
}
|
|
1239
|
+
function forgetInstance(ctx, instance) {
|
|
1240
|
+
ctx.instances.delete(instance.graphNode.id);
|
|
1241
|
+
for (const child of instance.children) forgetInstance(ctx, child);
|
|
1242
|
+
}
|
|
1243
|
+
function wireOverlayBehavior(ctx, graphNode, instance, target) {
|
|
1244
|
+
const { dom, graph } = ctx;
|
|
1245
|
+
if (dom.body() === null) return;
|
|
1246
|
+
const descFn = graph.getHandler(`__overlay__${graphNode.id}`);
|
|
1247
|
+
if (descFn === void 0) return;
|
|
1248
|
+
const desc = descFn();
|
|
1249
|
+
const openSig = desc.open;
|
|
1250
|
+
if (openSig === void 0 || typeof openSig.subscribe !== "function") return;
|
|
1251
|
+
let active = [];
|
|
1252
|
+
let saved = null;
|
|
1253
|
+
const teardown = () => {
|
|
1254
|
+
for (const fn of active) fn();
|
|
1255
|
+
active = [];
|
|
1256
|
+
};
|
|
1257
|
+
const onOpenChange = (isOpen) => {
|
|
1258
|
+
if (isOpen) {
|
|
1259
|
+
if (desc.restoreFocus) saved = saveFocus(dom);
|
|
1260
|
+
if (desc.takesFocus) focusInitial(dom, target, desc.initialFocusId);
|
|
1261
|
+
if (desc.modal) {
|
|
1262
|
+
active.push(trapFocus(dom, target));
|
|
1263
|
+
active.push(containFocus(dom, target));
|
|
1264
|
+
}
|
|
1265
|
+
if (desc.closeOnEscape && desc.onClose !== void 0) {
|
|
1266
|
+
active.push(onEscape(dom, target, desc.onClose));
|
|
1267
|
+
}
|
|
1268
|
+
} else {
|
|
1269
|
+
teardown();
|
|
1270
|
+
if (desc.restoreFocus && saved !== null) {
|
|
1271
|
+
restoreFocus(dom, saved);
|
|
1272
|
+
saved = null;
|
|
1273
|
+
}
|
|
1090
1274
|
}
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
};
|
|
1275
|
+
};
|
|
1276
|
+
const unsub = openSig.subscribe(onOpenChange);
|
|
1277
|
+
instance.trackCleanup(unsub);
|
|
1278
|
+
instance.trackCleanup(teardown);
|
|
1279
|
+
if (openSig.peek() === true) onOpenChange(true);
|
|
1280
|
+
}
|
|
1098
1281
|
|
|
1099
1282
|
// ../renderer/src/dehydrate.ts
|
|
1100
1283
|
var STATE_MARKER_ATTR = "data-streetui-state";
|
|
@@ -1132,11 +1315,115 @@ function readState(dom, root) {
|
|
|
1132
1315
|
}
|
|
1133
1316
|
}
|
|
1134
1317
|
|
|
1318
|
+
// ../compiler/dist/diagnostics.js
|
|
1319
|
+
var TEXT_PROP_KEYS = /* @__PURE__ */ new Set(["text", "label", "value"]);
|
|
1320
|
+
function analyzeGraph(graph) {
|
|
1321
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
1322
|
+
const summary = {
|
|
1323
|
+
totalNodes: 0,
|
|
1324
|
+
staticNodes: 0,
|
|
1325
|
+
staticSubtrees: 0,
|
|
1326
|
+
dynamicTextNodes: 0,
|
|
1327
|
+
dynamicAttrNodes: 0,
|
|
1328
|
+
eventNodes: 0,
|
|
1329
|
+
lists: 0,
|
|
1330
|
+
conditionals: 0
|
|
1331
|
+
};
|
|
1332
|
+
const visit = (node) => {
|
|
1333
|
+
let allChildrenStatic = true;
|
|
1334
|
+
for (const child of node.children) {
|
|
1335
|
+
const childSubtreeStatic = visit(child);
|
|
1336
|
+
if (!childSubtreeStatic) allChildrenStatic = false;
|
|
1337
|
+
}
|
|
1338
|
+
let hasDynamicText = false;
|
|
1339
|
+
let hasDynamicAttr = false;
|
|
1340
|
+
for (const ref of node.stateRefs) {
|
|
1341
|
+
if (TEXT_PROP_KEYS.has(ref.propKey)) hasDynamicText = true;
|
|
1342
|
+
else hasDynamicAttr = true;
|
|
1343
|
+
}
|
|
1344
|
+
const hasEvents = node.events.length > 0;
|
|
1345
|
+
const isList = node.type === "reactive-list";
|
|
1346
|
+
const isConditional = node.type === "conditional";
|
|
1347
|
+
const isPortal = node.type === "portal";
|
|
1348
|
+
const isStatic = node.stateRefs.length === 0 && !hasEvents && !isList && !isConditional && !isPortal;
|
|
1349
|
+
const isStaticSubtree = isStatic && allChildrenStatic;
|
|
1350
|
+
nodes.set(node.id, {
|
|
1351
|
+
isStatic,
|
|
1352
|
+
isStaticSubtree,
|
|
1353
|
+
hasDynamicText,
|
|
1354
|
+
hasDynamicAttr,
|
|
1355
|
+
hasEvents,
|
|
1356
|
+
isList,
|
|
1357
|
+
isConditional
|
|
1358
|
+
});
|
|
1359
|
+
summary.totalNodes += 1;
|
|
1360
|
+
if (isStatic) summary.staticNodes += 1;
|
|
1361
|
+
if (isStaticSubtree) summary.staticSubtrees += 1;
|
|
1362
|
+
if (hasDynamicText) summary.dynamicTextNodes += 1;
|
|
1363
|
+
if (hasDynamicAttr) summary.dynamicAttrNodes += 1;
|
|
1364
|
+
if (hasEvents) summary.eventNodes += 1;
|
|
1365
|
+
if (isList) summary.lists += 1;
|
|
1366
|
+
if (isConditional) summary.conditionals += 1;
|
|
1367
|
+
return isStaticSubtree;
|
|
1368
|
+
};
|
|
1369
|
+
visit(graph.root);
|
|
1370
|
+
return { nodes, summary };
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
// ../renderer/src/static-ssr-plan.ts
|
|
1374
|
+
function collectMaximalStaticRoots(graph) {
|
|
1375
|
+
const analysis = analyzeGraph(graph);
|
|
1376
|
+
const roots = [];
|
|
1377
|
+
const walk = (node) => {
|
|
1378
|
+
if (node.type !== "application") {
|
|
1379
|
+
const a = analysis.nodes.get(node.id);
|
|
1380
|
+
if (a !== void 0 && a.isStaticSubtree) {
|
|
1381
|
+
roots.push(node);
|
|
1382
|
+
return;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
for (const child of node.children) walk(child);
|
|
1386
|
+
};
|
|
1387
|
+
walk(graph.root);
|
|
1388
|
+
return roots;
|
|
1389
|
+
}
|
|
1390
|
+
function serializeStaticSubtree(dom, graph, root) {
|
|
1391
|
+
const container = dom.createElement("div");
|
|
1392
|
+
const ctx = createRenderContext(dom, graph, container);
|
|
1393
|
+
const instance = mountNode(ctx, root, container);
|
|
1394
|
+
const html = dom.serializeInner(container);
|
|
1395
|
+
instance.dispose();
|
|
1396
|
+
ctx.instances.clear();
|
|
1397
|
+
return html;
|
|
1398
|
+
}
|
|
1399
|
+
function buildStaticSSRPlan(compiled) {
|
|
1400
|
+
const graph = compiled.graph;
|
|
1401
|
+
const roots = collectMaximalStaticRoots(graph);
|
|
1402
|
+
const plan = /* @__PURE__ */ new Map();
|
|
1403
|
+
if (roots.length === 0) return plan;
|
|
1404
|
+
const dom = new ServerDOMAdapter();
|
|
1405
|
+
for (const root of roots) {
|
|
1406
|
+
plan.set(root.id, serializeStaticSubtree(dom, graph, root));
|
|
1407
|
+
}
|
|
1408
|
+
return plan;
|
|
1409
|
+
}
|
|
1410
|
+
var PLAN_CACHE = /* @__PURE__ */ new WeakMap();
|
|
1411
|
+
function getStaticSSRPlan(compiled) {
|
|
1412
|
+
let plan = PLAN_CACHE.get(compiled);
|
|
1413
|
+
if (plan === void 0) {
|
|
1414
|
+
plan = buildStaticSSRPlan(compiled);
|
|
1415
|
+
PLAN_CACHE.set(compiled, plan);
|
|
1416
|
+
}
|
|
1417
|
+
return plan;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1135
1420
|
// ../renderer/src/ssr.ts
|
|
1136
1421
|
function renderToString(compiled, options = {}) {
|
|
1137
1422
|
const dom = options.domAdapter ?? new ServerDOMAdapter();
|
|
1423
|
+
const plan = options.staticPlan === null ? void 0 : options.staticPlan ?? getStaticSSRPlan(compiled);
|
|
1424
|
+
const staticHTML = plan !== void 0 && plan.size > 0 ? plan : void 0;
|
|
1138
1425
|
const container = dom.createElement("div");
|
|
1139
|
-
const ctx = createRenderContext(dom, compiled.graph, container);
|
|
1426
|
+
const ctx = createRenderContext(dom, compiled.graph, container, void 0, staticHTML);
|
|
1140
1427
|
const rootInstance = mountGraph(ctx);
|
|
1141
1428
|
const html = dom.serializeInner(container);
|
|
1142
1429
|
rootInstance.dispose();
|
|
@@ -1145,7 +1432,7 @@ function renderToString(compiled, options = {}) {
|
|
|
1145
1432
|
}
|
|
1146
1433
|
|
|
1147
1434
|
// src/version.ts
|
|
1148
|
-
var VERSION = "1.
|
|
1435
|
+
var VERSION = "1.7.0";
|
|
1149
1436
|
export {
|
|
1150
1437
|
STATE_MARKER_ATTR,
|
|
1151
1438
|
ServerDOMAdapter,
|