streetui 1.0.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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +127 -0
  3. package/dist/bin.cjs +894 -0
  4. package/dist/bin.cjs.map +1 -0
  5. package/dist/bin.d.cts +1 -0
  6. package/dist/bin.d.ts +1 -0
  7. package/dist/bin.js +892 -0
  8. package/dist/bin.js.map +1 -0
  9. package/dist/compile-B0q07Hzq.d.cts +656 -0
  10. package/dist/compile-B0q07Hzq.d.ts +656 -0
  11. package/dist/create-bin.cjs +896 -0
  12. package/dist/create-bin.cjs.map +1 -0
  13. package/dist/create-bin.d.cts +1 -0
  14. package/dist/create-bin.d.ts +1 -0
  15. package/dist/create-bin.js +894 -0
  16. package/dist/create-bin.js.map +1 -0
  17. package/dist/hydration-diagnostics-BE6xVWD1.d.cts +89 -0
  18. package/dist/hydration-diagnostics-Bck5dMbz.d.ts +89 -0
  19. package/dist/index.cjs +4284 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.cts +1759 -0
  22. package/dist/index.d.ts +1759 -0
  23. package/dist/index.js +4114 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/server-84Rz4g8W.d.cts +165 -0
  26. package/dist/server-D9GPmB49.d.ts +165 -0
  27. package/dist/server.cjs +972 -0
  28. package/dist/server.cjs.map +1 -0
  29. package/dist/server.d.cts +2 -0
  30. package/dist/server.d.ts +2 -0
  31. package/dist/server.js +940 -0
  32. package/dist/server.js.map +1 -0
  33. package/dist/testing.cjs +1754 -0
  34. package/dist/testing.cjs.map +1 -0
  35. package/dist/testing.d.cts +113 -0
  36. package/dist/testing.d.ts +113 -0
  37. package/dist/testing.js +1719 -0
  38. package/dist/testing.js.map +1 -0
  39. package/package.json +113 -0
  40. package/templates/basic/README.md +39 -0
  41. package/templates/basic/_gitignore +15 -0
  42. package/templates/basic/_package.json +21 -0
  43. package/templates/basic/public/styles.css +40 -0
  44. package/templates/basic/src/app.ts +62 -0
  45. package/templates/basic/src/main.ts +39 -0
  46. package/templates/basic/src/server.ts +40 -0
  47. package/templates/basic/streetui.config.ts +6 -0
  48. package/templates/basic/tsconfig.json +16 -0
  49. package/templates/ssr/README.md +46 -0
  50. package/templates/ssr/_gitignore +15 -0
  51. package/templates/ssr/_package.json +21 -0
  52. package/templates/ssr/public/favicon.svg +4 -0
  53. package/templates/ssr/public/styles.css +61 -0
  54. package/templates/ssr/src/app.ts +135 -0
  55. package/templates/ssr/src/main.ts +53 -0
  56. package/templates/ssr/src/server.ts +47 -0
  57. package/templates/ssr/streetui.config.ts +14 -0
  58. package/templates/ssr/tsconfig.json +16 -0
package/dist/server.js ADDED
@@ -0,0 +1,940 @@
1
+ // ../renderer/src/render-context.ts
2
+ function createRenderContext(dom, graph, container, hydrationDiagnostics) {
3
+ return {
4
+ dom,
5
+ graph,
6
+ instances: /* @__PURE__ */ new Map(),
7
+ container,
8
+ ...hydrationDiagnostics !== void 0 ? { hydrationDiagnostics } : {}
9
+ };
10
+ }
11
+
12
+ // ../core/src/lifecycle.ts
13
+ var CleanupRegistry = class {
14
+ _fns = [];
15
+ add(fn) {
16
+ this._fns.push(fn);
17
+ }
18
+ run() {
19
+ for (const fn of this._fns) {
20
+ try {
21
+ fn();
22
+ } catch {
23
+ }
24
+ }
25
+ this._fns.length = 0;
26
+ }
27
+ };
28
+
29
+ // ../renderer/src/node-instance.ts
30
+ var NodeInstance = class {
31
+ graphNode;
32
+ /** The primary DOM node for this instance (element or text node). */
33
+ domNode;
34
+ children = [];
35
+ cleanup = new CleanupRegistry();
36
+ constructor(graphNode, domNode) {
37
+ this.graphNode = graphNode;
38
+ this.domNode = domNode;
39
+ }
40
+ addChild(child) {
41
+ this.children.push(child);
42
+ }
43
+ /** Subscribe to a signal; auto-cleanup on unmount. */
44
+ trackSignal(sig, handler) {
45
+ const unsub = sig.subscribe(handler);
46
+ this.cleanup.add(unsub);
47
+ }
48
+ /** Register a raw cleanup fn (DOM event removal, etc.). */
49
+ trackCleanup(fn) {
50
+ this.cleanup.add(fn);
51
+ }
52
+ dispose() {
53
+ for (const child of this.children) {
54
+ child.dispose();
55
+ }
56
+ this.cleanup.run();
57
+ }
58
+ };
59
+
60
+ // ../renderer/src/attributes.ts
61
+ var DOM_PROPERTIES = /* @__PURE__ */ new Set([
62
+ "value",
63
+ "checked",
64
+ "selected",
65
+ "indeterminate",
66
+ "innerHTML",
67
+ "textContent",
68
+ "innerText",
69
+ "scrollTop",
70
+ "scrollLeft"
71
+ ]);
72
+ var BOOLEAN_ATTRS = /* @__PURE__ */ new Set([
73
+ "disabled",
74
+ "readonly",
75
+ "required",
76
+ "checked",
77
+ "selected",
78
+ "multiple",
79
+ "autofocus",
80
+ "autoplay",
81
+ "controls",
82
+ "default",
83
+ "defer",
84
+ "formnovalidate",
85
+ "hidden",
86
+ "ismap",
87
+ "loop",
88
+ "novalidate",
89
+ "open",
90
+ "reversed",
91
+ "scoped",
92
+ "seamless"
93
+ ]);
94
+ function applyProp(dom, element, name, value) {
95
+ if (name.startsWith("_")) return;
96
+ if (name.startsWith("on")) return;
97
+ if (DOM_PROPERTIES.has(name)) {
98
+ dom.setProperty(element, name, value);
99
+ return;
100
+ }
101
+ if (BOOLEAN_ATTRS.has(name)) {
102
+ if (value === true || value === "" || value === name) {
103
+ dom.setAttribute(element, name, "");
104
+ } else {
105
+ dom.removeAttribute(element, name);
106
+ }
107
+ return;
108
+ }
109
+ if (name === "class" || name === "className") {
110
+ dom.setAttribute(element, "class", String(value ?? ""));
111
+ return;
112
+ }
113
+ if (name === "style" && typeof value === "object" && value !== null) {
114
+ const el = element;
115
+ const styles = value;
116
+ for (const [k, v] of Object.entries(styles)) {
117
+ el.style.setProperty(k, v);
118
+ }
119
+ return;
120
+ }
121
+ if (value === null || value === void 0 || value === false) {
122
+ dom.removeAttribute(element, name);
123
+ return;
124
+ }
125
+ dom.setAttribute(element, name, String(value));
126
+ }
127
+ function patchProp(dom, element, name, oldValue, newValue) {
128
+ if (Object.is(oldValue, newValue)) return;
129
+ applyProp(dom, element, name, newValue);
130
+ }
131
+
132
+ // ../renderer/src/events.ts
133
+ function wireEvents(dom, graph, node, element, instance) {
134
+ for (const eventDesc of node.events) {
135
+ const handler = graph.getHandler(eventDesc.handlerKey);
136
+ if (handler === void 0) continue;
137
+ const domListener = (domEvent) => {
138
+ if (eventDesc.type === "input" || eventDesc.type === "change") {
139
+ const input = domEvent.target;
140
+ handler(input.value);
141
+ } else if (eventDesc.type === "submit") {
142
+ domEvent.preventDefault();
143
+ handler(domEvent);
144
+ } else {
145
+ handler();
146
+ }
147
+ };
148
+ dom.addEventListener(element, eventDesc.type, domListener);
149
+ instance.trackCleanup(() => {
150
+ dom.removeEventListener(element, eventDesc.type, domListener);
151
+ });
152
+ }
153
+ }
154
+
155
+ // ../renderer/src/tag-map.ts
156
+ var TAG_MAP = {
157
+ application: "div",
158
+ page: "div",
159
+ section: "section",
160
+ container: "div",
161
+ heading: "h1",
162
+ text: "span",
163
+ button: "button",
164
+ input: "input",
165
+ form: "form",
166
+ list: "ul",
167
+ "list-item": "li",
168
+ image: "img",
169
+ link: "a",
170
+ component: "div",
171
+ slot: "div",
172
+ fragment: "div",
173
+ "reactive-list": "ul"
174
+ };
175
+ function resolveTag(type) {
176
+ return TAG_MAP[type] ?? "div";
177
+ }
178
+
179
+ // ../renderer/src/patch.ts
180
+ function patchNode(ctx, graphNode, propKey, newValue) {
181
+ const instance = ctx.instances.get(graphNode.id);
182
+ if (instance === void 0) return;
183
+ const domNode = instance.domNode;
184
+ if (!ctx.dom.isElement(domNode)) return;
185
+ const oldValue = graphNode.getProp(propKey);
186
+ switch (propKey) {
187
+ case "text":
188
+ if (!Object.is(oldValue, newValue)) {
189
+ ctx.dom.setTextContent(domNode, String(newValue ?? ""));
190
+ graphNode.setProp("text", String(newValue ?? ""));
191
+ }
192
+ break;
193
+ case "label":
194
+ if (!Object.is(oldValue, newValue)) {
195
+ ctx.dom.setTextContent(domNode, String(newValue ?? ""));
196
+ graphNode.setProp("label", String(newValue ?? ""));
197
+ }
198
+ break;
199
+ case "disabled":
200
+ if (newValue === true) {
201
+ ctx.dom.setAttribute(domNode, "disabled", "");
202
+ } else {
203
+ ctx.dom.removeAttribute(domNode, "disabled");
204
+ }
205
+ graphNode.setProp("disabled", Boolean(newValue));
206
+ break;
207
+ case "value":
208
+ if (!Object.is(oldValue, newValue)) {
209
+ ctx.dom.setProperty(domNode, "value", String(newValue ?? ""));
210
+ graphNode.setProp("value", String(newValue ?? ""));
211
+ }
212
+ break;
213
+ default:
214
+ patchProp(ctx.dom, domNode, propKey, oldValue, newValue);
215
+ graphNode.setProp(propKey, newValue);
216
+ break;
217
+ }
218
+ }
219
+
220
+ // ../renderer/src/reconciliation.ts
221
+ function reconcileChildren(ctx, parentDom, oldInstances, newNodes, mountFn) {
222
+ const oldByKey = /* @__PURE__ */ new Map();
223
+ for (const inst of oldInstances) {
224
+ const key = inst.graphNode.key ?? inst.graphNode.id;
225
+ oldByKey.set(key, inst);
226
+ }
227
+ const newInstances = [];
228
+ const usedKeys = /* @__PURE__ */ new Set();
229
+ for (const newNode of newNodes) {
230
+ const key = newNode.key ?? newNode.id;
231
+ const existing = oldByKey.get(key);
232
+ if (existing !== void 0) {
233
+ usedKeys.add(key);
234
+ const oldSig = existing.graphNode.getProp("_sig");
235
+ const newSig = newNode.getProp("_sig");
236
+ patchExistingInstance(ctx, existing, newNode);
237
+ if (!Object.is(oldSig, newSig)) {
238
+ reconcileItemChildren(ctx, existing, newNode, mountFn);
239
+ }
240
+ newInstances.push(existing);
241
+ } else {
242
+ const inst = mountFn(newNode, parentDom);
243
+ newInstances.push(inst);
244
+ }
245
+ }
246
+ const removed = [];
247
+ for (const inst of oldInstances) {
248
+ const key = inst.graphNode.key ?? inst.graphNode.id;
249
+ if (!usedKeys.has(key)) {
250
+ removed.push(inst);
251
+ }
252
+ }
253
+ for (const inst of removed) {
254
+ const parent = ctx.dom.parentNode(inst.domNode);
255
+ if (parent !== null) {
256
+ ctx.dom.removeChild(parent, inst.domNode);
257
+ }
258
+ inst.dispose();
259
+ }
260
+ reorderDom(ctx, parentDom, newInstances);
261
+ return { instances: newInstances, removed };
262
+ }
263
+ function reconcileItemChildren(ctx, itemInstance, newItemNode, mountFn) {
264
+ const el = itemInstance.domNode;
265
+ if (!ctx.dom.isElement(el)) return;
266
+ const oldChildren = [...itemInstance.children];
267
+ const newChildNodes = [...newItemNode.children];
268
+ const nextChildren = [];
269
+ const kept = /* @__PURE__ */ new Set();
270
+ for (let i = 0; i < newChildNodes.length; i++) {
271
+ const newChild = newChildNodes[i];
272
+ const oldChild = oldChildren[i];
273
+ if (oldChild !== void 0 && oldChild.graphNode.type === newChild.type) {
274
+ patchExistingInstance(ctx, oldChild, newChild);
275
+ reconcileItemChildren(ctx, oldChild, newChild, mountFn);
276
+ nextChildren.push(oldChild);
277
+ kept.add(oldChild);
278
+ } else {
279
+ itemInstance.graphNode.appendChild(newChild);
280
+ const inst = mountFn(newChild, el);
281
+ nextChildren.push(inst);
282
+ }
283
+ }
284
+ for (const old of oldChildren) {
285
+ if (kept.has(old)) continue;
286
+ const parent = ctx.dom.parentNode(old.domNode);
287
+ if (parent !== null) ctx.dom.removeChild(parent, old.domNode);
288
+ old.dispose();
289
+ forgetInstanceTree(ctx, old);
290
+ ctx.graph.detachNode(old.graphNode);
291
+ }
292
+ reorderDom(ctx, el, nextChildren);
293
+ itemInstance.children.length = 0;
294
+ for (const c of nextChildren) itemInstance.children.push(c);
295
+ for (const c of [...itemInstance.graphNode.children]) {
296
+ itemInstance.graphNode.removeChild(c);
297
+ }
298
+ for (const c of nextChildren) itemInstance.graphNode.appendChild(c.graphNode);
299
+ }
300
+ function reorderDom(ctx, parentDom, instances) {
301
+ let referenceNode = null;
302
+ for (let i = instances.length - 1; i >= 0; i--) {
303
+ const inst = instances[i];
304
+ if (inst === void 0) continue;
305
+ const domNode = inst.domNode;
306
+ const currentNext = ctx.dom.nextSibling(domNode);
307
+ if (currentNext !== referenceNode) {
308
+ ctx.dom.insertBefore(parentDom, domNode, referenceNode);
309
+ }
310
+ referenceNode = domNode;
311
+ }
312
+ }
313
+ function forgetInstanceTree(ctx, instance) {
314
+ ctx.instances.delete(instance.graphNode.id);
315
+ for (const child of instance.children) forgetInstanceTree(ctx, child);
316
+ }
317
+ function patchExistingInstance(ctx, instance, newNode) {
318
+ const oldNode = instance.graphNode;
319
+ for (const [key, newVal] of Object.entries(newNode.props)) {
320
+ const oldVal = oldNode.getProp(key);
321
+ if (!Object.is(oldVal, newVal)) {
322
+ patchNode(ctx, instance.graphNode, key, newVal);
323
+ }
324
+ }
325
+ }
326
+
327
+ // ../renderer/src/mount.ts
328
+ var SKIP_PROP_KEYS = /* @__PURE__ */ new Set([
329
+ "text",
330
+ "label",
331
+ "level",
332
+ "inputType",
333
+ "src",
334
+ "alt",
335
+ "href",
336
+ "external",
337
+ "value",
338
+ "placeholder",
339
+ "disabled",
340
+ "_renderKey",
341
+ "key",
342
+ "name"
343
+ ]);
344
+ function mountGraph(ctx) {
345
+ return mountNode(ctx, ctx.graph.root, ctx.container);
346
+ }
347
+ function mountNode(ctx, graphNode, parentDom) {
348
+ const { dom, graph } = ctx;
349
+ if (graphNode.type === "application") {
350
+ const instance2 = new NodeInstance(graphNode, parentDom);
351
+ ctx.instances.set(graphNode.id, instance2);
352
+ for (const child of graphNode.children) {
353
+ const childInstance = mountNode(ctx, child, parentDom);
354
+ instance2.addChild(childInstance);
355
+ }
356
+ return instance2;
357
+ }
358
+ if (graphNode.type === "text") {
359
+ const text = String(graphNode.getProp("text") ?? "");
360
+ const el2 = dom.createElement("span");
361
+ const textNode = dom.createTextNode(text);
362
+ dom.appendChild(el2, textNode);
363
+ applyNodeProps(ctx, graphNode, el2);
364
+ wireEvents(dom, graph, graphNode, el2, new NodeInstance(graphNode, el2));
365
+ const instance2 = new NodeInstance(graphNode, el2);
366
+ ctx.instances.set(graphNode.id, instance2);
367
+ wireSignalBindings(ctx, graphNode, instance2, textUpdate(dom, el2, textNode));
368
+ dom.appendChild(parentDom, el2);
369
+ return instance2;
370
+ }
371
+ if (graphNode.type === "heading") {
372
+ const level = graphNode.getProp("level") ?? 1;
373
+ const tag2 = `h${level}`;
374
+ const el2 = dom.createElement(tag2);
375
+ const text = String(graphNode.getProp("text") ?? "");
376
+ dom.setTextContent(el2, text);
377
+ applyNodeProps(ctx, graphNode, el2);
378
+ const instance2 = new NodeInstance(graphNode, el2);
379
+ ctx.instances.set(graphNode.id, instance2);
380
+ wireEvents(dom, graph, graphNode, el2, instance2);
381
+ wireSignalBindings(ctx, graphNode, instance2, headingUpdate(dom, el2));
382
+ dom.appendChild(parentDom, el2);
383
+ return instance2;
384
+ }
385
+ if (graphNode.type === "input") {
386
+ const el2 = dom.createElement("input");
387
+ const inputType = String(graphNode.getProp("inputType") ?? "text");
388
+ dom.setAttribute(el2, "type", inputType);
389
+ const placeholder = graphNode.getProp("placeholder");
390
+ if (placeholder !== void 0) dom.setAttribute(el2, "placeholder", String(placeholder));
391
+ const value = graphNode.getProp("value");
392
+ if (value !== void 0) dom.setProperty(el2, "value", String(value));
393
+ applyNodeProps(ctx, graphNode, el2);
394
+ const instance2 = new NodeInstance(graphNode, el2);
395
+ ctx.instances.set(graphNode.id, instance2);
396
+ wireEvents(dom, graph, graphNode, el2, instance2);
397
+ wireSignalBindings(ctx, graphNode, instance2, inputUpdate(dom, el2));
398
+ dom.appendChild(parentDom, el2);
399
+ return instance2;
400
+ }
401
+ if (graphNode.type === "image") {
402
+ const el2 = dom.createElement("img");
403
+ const src = graphNode.getProp("src");
404
+ const alt = graphNode.getProp("alt");
405
+ if (src !== void 0) dom.setAttribute(el2, "src", String(src));
406
+ if (alt !== void 0) dom.setAttribute(el2, "alt", String(alt));
407
+ const width = graphNode.getProp("width");
408
+ const height = graphNode.getProp("height");
409
+ if (width !== void 0) dom.setAttribute(el2, "width", String(width));
410
+ if (height !== void 0) dom.setAttribute(el2, "height", String(height));
411
+ applyNodeProps(ctx, graphNode, el2);
412
+ const instance2 = new NodeInstance(graphNode, el2);
413
+ ctx.instances.set(graphNode.id, instance2);
414
+ dom.appendChild(parentDom, el2);
415
+ return instance2;
416
+ }
417
+ if (graphNode.type === "link") {
418
+ const el2 = dom.createElement("a");
419
+ const href = graphNode.getProp("href");
420
+ const label = graphNode.getProp("label");
421
+ const external = graphNode.getProp("external");
422
+ if (href !== void 0) dom.setAttribute(el2, "href", String(href));
423
+ if (label !== void 0) dom.setTextContent(el2, String(label));
424
+ if (external === true) {
425
+ dom.setAttribute(el2, "target", "_blank");
426
+ dom.setAttribute(el2, "rel", "noopener noreferrer");
427
+ }
428
+ applyNodeProps(ctx, graphNode, el2);
429
+ const instance2 = new NodeInstance(graphNode, el2);
430
+ ctx.instances.set(graphNode.id, instance2);
431
+ wireEvents(dom, graph, graphNode, el2, instance2);
432
+ dom.appendChild(parentDom, el2);
433
+ return instance2;
434
+ }
435
+ if (graphNode.type === "button") {
436
+ const el2 = dom.createElement("button");
437
+ const label = graphNode.getProp("label");
438
+ if (label !== void 0) dom.setTextContent(el2, String(label));
439
+ const disabled = graphNode.getProp("disabled");
440
+ if (disabled === true) dom.setAttribute(el2, "disabled", "");
441
+ applyNodeProps(ctx, graphNode, el2);
442
+ const instance2 = new NodeInstance(graphNode, el2);
443
+ ctx.instances.set(graphNode.id, instance2);
444
+ wireEvents(dom, graph, graphNode, el2, instance2);
445
+ wireSignalBindings(ctx, graphNode, instance2, buttonUpdate(dom, el2));
446
+ dom.appendChild(parentDom, el2);
447
+ return instance2;
448
+ }
449
+ if (graphNode.type === "reactive-list" || graphNode.type === "conditional") {
450
+ const tag2 = resolveTag(graphNode.type);
451
+ const el2 = dom.createElement(tag2);
452
+ applyNodeProps(ctx, graphNode, el2);
453
+ const instance2 = new NodeInstance(graphNode, el2);
454
+ ctx.instances.set(graphNode.id, instance2);
455
+ for (const child of graphNode.children) {
456
+ const childInstance = mountNode(ctx, child, el2);
457
+ instance2.addChild(childInstance);
458
+ }
459
+ dom.appendChild(parentDom, el2);
460
+ wireReactiveList(ctx, graphNode, instance2, el2);
461
+ return instance2;
462
+ }
463
+ const tag = resolveTag(graphNode.type);
464
+ const el = dom.createElement(tag);
465
+ applyNodeProps(ctx, graphNode, el);
466
+ if (graphNode.type === "list-item") {
467
+ const itemKey = graphNode.getProp("key");
468
+ if (itemKey !== void 0) {
469
+ dom.setAttribute(el, "data-streetui-key", String(itemKey));
470
+ }
471
+ }
472
+ if (graphNode.type === "form") {
473
+ wireEvents(dom, graph, graphNode, el, new NodeInstance(graphNode, el));
474
+ }
475
+ const instance = new NodeInstance(graphNode, el);
476
+ ctx.instances.set(graphNode.id, instance);
477
+ for (const child of graphNode.children) {
478
+ const childInstance = mountNode(ctx, child, el);
479
+ instance.addChild(childInstance);
480
+ }
481
+ dom.appendChild(parentDom, el);
482
+ return instance;
483
+ }
484
+ function textUpdate(dom, el, textNode) {
485
+ return (propKey, value) => {
486
+ if (propKey === "text") {
487
+ dom.setTextContent(textNode, String(value ?? ""));
488
+ } else {
489
+ applyProp(dom, el, propKey, value);
490
+ }
491
+ };
492
+ }
493
+ function headingUpdate(dom, el) {
494
+ return (propKey, value) => {
495
+ if (propKey === "text") {
496
+ dom.setTextContent(el, String(value ?? ""));
497
+ } else {
498
+ applyProp(dom, el, propKey, value);
499
+ }
500
+ };
501
+ }
502
+ function inputUpdate(dom, el) {
503
+ return (propKey, value) => {
504
+ if (propKey === "value") {
505
+ dom.setProperty(el, "value", String(value ?? ""));
506
+ } else {
507
+ applyProp(dom, el, propKey, value);
508
+ }
509
+ };
510
+ }
511
+ function buttonUpdate(dom, el) {
512
+ return (propKey, value) => {
513
+ if (propKey === "label") {
514
+ dom.setTextContent(el, String(value ?? ""));
515
+ } else if (propKey === "disabled") {
516
+ if (value === true) {
517
+ dom.setAttribute(el, "disabled", "");
518
+ } else {
519
+ dom.removeAttribute(el, "disabled");
520
+ }
521
+ } else {
522
+ applyProp(dom, el, propKey, value);
523
+ }
524
+ };
525
+ }
526
+ function applyNodeProps(ctx, graphNode, el) {
527
+ for (const [key, value] of Object.entries(graphNode.props)) {
528
+ if (SKIP_PROP_KEYS.has(key)) continue;
529
+ applyProp(ctx.dom, el, key, value);
530
+ }
531
+ }
532
+ function wireSignalBindings(ctx, graphNode, instance, onUpdate) {
533
+ for (const stateRef of graphNode.stateRefs) {
534
+ const signalKey = `__signal__${stateRef.signalId}`;
535
+ const maybeSig = ctx.graph.getHandler(signalKey);
536
+ if (maybeSig === void 0 || typeof maybeSig.subscribe !== "function") continue;
537
+ const unsub = maybeSig.subscribe((value) => {
538
+ onUpdate(stateRef.propKey, value);
539
+ });
540
+ instance.trackCleanup(unsub);
541
+ }
542
+ }
543
+ function wireReactiveList(ctx, graphNode, instance, el) {
544
+ const build = ctx.graph.getHandler(`__listbuild__${graphNode.id}`);
545
+ if (build === void 0) return;
546
+ for (const stateRef of graphNode.stateRefs) {
547
+ if (stateRef.propKey !== "items") continue;
548
+ const sig = ctx.graph.getHandler(`__signal__${stateRef.signalId}`);
549
+ if (sig === void 0 || typeof sig.subscribe !== "function") continue;
550
+ const unsub = sig.subscribe((value) => {
551
+ reconcileReactiveList(ctx, graphNode, instance, el, build(value));
552
+ });
553
+ instance.trackCleanup(unsub);
554
+ }
555
+ }
556
+ function reconcileReactiveList(ctx, listNode, listInstance, listEl, newNodes) {
557
+ const oldInstances = [...listInstance.children];
558
+ const result = reconcileChildren(
559
+ ctx,
560
+ listEl,
561
+ oldInstances,
562
+ newNodes,
563
+ (node, parent) => mountNode(ctx, node, parent)
564
+ );
565
+ listInstance.children.length = 0;
566
+ for (const inst of result.instances) listInstance.children.push(inst);
567
+ for (const removed of result.removed) {
568
+ forgetInstance(ctx, removed);
569
+ ctx.graph.detachNode(removed.graphNode);
570
+ }
571
+ const adopted = new Set(result.instances.map((i) => i.graphNode));
572
+ for (const built of newNodes) {
573
+ if (!adopted.has(built)) ctx.graph.detachNode(built);
574
+ }
575
+ for (const child of [...listNode.children]) listNode.removeChild(child);
576
+ for (const inst of result.instances) listNode.appendChild(inst.graphNode);
577
+ }
578
+ function forgetInstance(ctx, instance) {
579
+ ctx.instances.delete(instance.graphNode.id);
580
+ for (const child of instance.children) forgetInstance(ctx, child);
581
+ }
582
+
583
+ // ../dom/src/server-node.ts
584
+ var ServerStyle = class {
585
+ declarations = /* @__PURE__ */ new Map();
586
+ setProperty(name, value) {
587
+ this.declarations.set(name, value);
588
+ }
589
+ get isEmpty() {
590
+ return this.declarations.size === 0;
591
+ }
592
+ toCss() {
593
+ return [...this.declarations.entries()].map(([k, v]) => `${k}: ${v}`).join("; ");
594
+ }
595
+ };
596
+ var ServerText = class {
597
+ kind = "text";
598
+ parent = null;
599
+ data;
600
+ constructor(data) {
601
+ this.data = data;
602
+ }
603
+ };
604
+ var ServerComment = class {
605
+ kind = "comment";
606
+ parent = null;
607
+ data;
608
+ constructor(data) {
609
+ this.data = data;
610
+ }
611
+ };
612
+ var ServerFragment = class {
613
+ kind = "fragment";
614
+ parent = null;
615
+ children = [];
616
+ };
617
+ var ServerElement = class {
618
+ kind = "element";
619
+ parent = null;
620
+ tagName;
621
+ attributes = /* @__PURE__ */ new Map();
622
+ /** JS properties set via `setProperty` (e.g. input `value`, `checked`). */
623
+ properties = /* @__PURE__ */ new Map();
624
+ children = [];
625
+ style = new ServerStyle();
626
+ constructor(tagName) {
627
+ this.tagName = tagName.toLowerCase();
628
+ }
629
+ };
630
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
631
+ "area",
632
+ "base",
633
+ "br",
634
+ "col",
635
+ "embed",
636
+ "hr",
637
+ "img",
638
+ "input",
639
+ "link",
640
+ "meta",
641
+ "param",
642
+ "source",
643
+ "track",
644
+ "wbr"
645
+ ]);
646
+ var SERIALIZED_PROPERTIES = {
647
+ value: "attr",
648
+ checked: "boolean",
649
+ selected: "boolean"
650
+ };
651
+ function escapeHtmlText(value) {
652
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
653
+ }
654
+ function escapeHtmlAttr(value) {
655
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
656
+ }
657
+ function serializeAttributes(el) {
658
+ const parts = [];
659
+ for (const [name, value] of el.attributes) {
660
+ if (value === "") {
661
+ parts.push(` ${name}`);
662
+ } else {
663
+ parts.push(` ${name}="${escapeHtmlAttr(value)}"`);
664
+ }
665
+ }
666
+ for (const [name, kind] of Object.entries(SERIALIZED_PROPERTIES)) {
667
+ if (!el.properties.has(name)) continue;
668
+ if (el.attributes.has(name)) continue;
669
+ const raw = el.properties.get(name);
670
+ if (kind === "boolean") {
671
+ if (raw === true) parts.push(` ${name}`);
672
+ } else {
673
+ if (raw !== void 0 && raw !== null) {
674
+ parts.push(` ${name}="${escapeHtmlAttr(String(raw))}"`);
675
+ }
676
+ }
677
+ }
678
+ if (!el.style.isEmpty && !el.attributes.has("style")) {
679
+ parts.push(` style="${escapeHtmlAttr(el.style.toCss())}"`);
680
+ }
681
+ return parts.join("");
682
+ }
683
+ function serializeServerNode(node) {
684
+ switch (node.kind) {
685
+ case "text":
686
+ return escapeHtmlText(node.data);
687
+ case "comment":
688
+ return `<!--${node.data}-->`;
689
+ case "fragment":
690
+ return serializeChildren(node);
691
+ case "element": {
692
+ const el = node;
693
+ const tag = el.tagName;
694
+ const attrs = serializeAttributes(el);
695
+ if (VOID_ELEMENTS.has(tag)) {
696
+ return `<${tag}${attrs}>`;
697
+ }
698
+ return `<${tag}${attrs}>${serializeChildren(el)}</${tag}>`;
699
+ }
700
+ }
701
+ }
702
+ function serializeChildren(node) {
703
+ let out = "";
704
+ for (const child of node.children) {
705
+ out += serializeServerNode(child);
706
+ }
707
+ return out;
708
+ }
709
+
710
+ // ../dom/src/server-adapter.ts
711
+ function asServer(node) {
712
+ return node;
713
+ }
714
+ function asParent(node) {
715
+ return node;
716
+ }
717
+ var ServerDOMAdapter = class {
718
+ createElement(tag, _ns) {
719
+ return new ServerElement(tag);
720
+ }
721
+ createTextNode(data) {
722
+ return new ServerText(data);
723
+ }
724
+ createComment(data) {
725
+ return new ServerComment(data);
726
+ }
727
+ createFragment() {
728
+ return new ServerFragment();
729
+ }
730
+ appendChild(parent, child) {
731
+ const p = asParent(parent);
732
+ const c = asServer(child);
733
+ this._detach(c);
734
+ c.parent = p;
735
+ p.children.push(c);
736
+ }
737
+ insertBefore(parent, child, reference) {
738
+ const p = asParent(parent);
739
+ const c = asServer(child);
740
+ this._detach(c);
741
+ c.parent = p;
742
+ if (reference === null) {
743
+ p.children.push(c);
744
+ return;
745
+ }
746
+ const ref = asServer(reference);
747
+ const idx = p.children.indexOf(ref);
748
+ if (idx === -1) p.children.push(c);
749
+ else p.children.splice(idx, 0, c);
750
+ }
751
+ removeChild(parent, child) {
752
+ const p = asParent(parent);
753
+ const c = asServer(child);
754
+ const idx = p.children.indexOf(c);
755
+ if (idx !== -1) {
756
+ p.children.splice(idx, 1);
757
+ c.parent = null;
758
+ }
759
+ }
760
+ replaceChild(parent, newChild, oldChild) {
761
+ const p = asParent(parent);
762
+ const nc = asServer(newChild);
763
+ const oc = asServer(oldChild);
764
+ const idx = p.children.indexOf(oc);
765
+ if (idx === -1) return;
766
+ this._detach(nc);
767
+ nc.parent = p;
768
+ p.children.splice(idx, 1, nc);
769
+ oc.parent = null;
770
+ }
771
+ _detach(node) {
772
+ if (node.parent !== null) {
773
+ const siblings = node.parent.children;
774
+ const idx = siblings.indexOf(node);
775
+ if (idx !== -1) siblings.splice(idx, 1);
776
+ node.parent = null;
777
+ }
778
+ }
779
+ setAttribute(element, name, value) {
780
+ element.attributes.set(name, value);
781
+ }
782
+ removeAttribute(element, name) {
783
+ element.attributes.delete(name);
784
+ }
785
+ getAttribute(element, name) {
786
+ return element.attributes.get(name) ?? null;
787
+ }
788
+ setProperty(element, name, value) {
789
+ element.properties.set(name, value);
790
+ }
791
+ setTextContent(node, text) {
792
+ const n = asServer(node);
793
+ if (n.kind === "element" || n.kind === "fragment") {
794
+ const el = n;
795
+ el.children.length = 0;
796
+ const t = new ServerText(text);
797
+ t.parent = el;
798
+ el.children.push(t);
799
+ } else if (n.kind === "text") {
800
+ n.data = text;
801
+ }
802
+ }
803
+ getTextContent(node) {
804
+ const n = asServer(node);
805
+ if (n.kind === "text") return n.data;
806
+ if (n.kind === "element" || n.kind === "fragment") {
807
+ let out = "";
808
+ for (const c of n.children) {
809
+ out += this.getTextContent(c) ?? "";
810
+ }
811
+ return out;
812
+ }
813
+ return null;
814
+ }
815
+ // Server nodes never dispatch events — listeners are a no-op on the server.
816
+ addEventListener() {
817
+ }
818
+ removeEventListener() {
819
+ }
820
+ querySelector() {
821
+ return null;
822
+ }
823
+ querySelectorAll() {
824
+ return [];
825
+ }
826
+ getElementById() {
827
+ return null;
828
+ }
829
+ focus() {
830
+ }
831
+ isElement(node) {
832
+ return asServer(node).kind === "element";
833
+ }
834
+ isTextNode(node) {
835
+ return asServer(node).kind === "text";
836
+ }
837
+ tagName(element) {
838
+ return element.tagName;
839
+ }
840
+ parentNode(node) {
841
+ return asServer(node).parent ?? null;
842
+ }
843
+ nextSibling(node) {
844
+ const n = asServer(node);
845
+ const parent = n.parent;
846
+ if (parent === null) return null;
847
+ const idx = parent.children.indexOf(n);
848
+ if (idx === -1 || idx + 1 >= parent.children.length) return null;
849
+ return parent.children[idx + 1];
850
+ }
851
+ firstChild(node) {
852
+ const n = asServer(node);
853
+ if (n.kind === "element" || n.kind === "fragment") {
854
+ const el = n;
855
+ return el.children[0] ?? null;
856
+ }
857
+ return null;
858
+ }
859
+ childNodes(node) {
860
+ const n = asServer(node);
861
+ if (n.kind === "element" || n.kind === "fragment") {
862
+ return n.children;
863
+ }
864
+ return [];
865
+ }
866
+ // ── Server-only ────────────────────────────────────────────────────────────
867
+ /** Serialize a node's children ("inner HTML") to an HTML string. */
868
+ serializeInner(node) {
869
+ const n = asServer(node);
870
+ if (n.kind === "element" || n.kind === "fragment") {
871
+ return serializeChildren(n);
872
+ }
873
+ return "";
874
+ }
875
+ /** Serialize a node (including itself) to an HTML string. */
876
+ serializeOuter(node) {
877
+ return serializeServerNode(asServer(node));
878
+ }
879
+ };
880
+ var serverDOMAdapter = new ServerDOMAdapter();
881
+
882
+ // ../renderer/src/dehydrate.ts
883
+ var STATE_MARKER_ATTR = "data-streetui-state";
884
+ function escapeForScript(json) {
885
+ let out = "";
886
+ for (const ch of json) {
887
+ const code = ch.charCodeAt(0);
888
+ if (ch === "<") out += "\\u003c";
889
+ else if (ch === ">") out += "\\u003e";
890
+ else if (ch === "&") out += "\\u0026";
891
+ else if (code === 8232) out += "\\u2028";
892
+ else if (code === 8233) out += "\\u2029";
893
+ else out += ch;
894
+ }
895
+ return out;
896
+ }
897
+ function serializeState(state) {
898
+ if (Object.keys(state).length === 0) return "";
899
+ const json = escapeForScript(JSON.stringify(state));
900
+ return `<script type="application/json" ${STATE_MARKER_ATTR}>${json}</script>`;
901
+ }
902
+ function readState(dom, root) {
903
+ const el = dom.querySelector(root, `script[${STATE_MARKER_ATTR}]`);
904
+ if (el === null) return {};
905
+ const text = dom.getTextContent(el);
906
+ if (text === null || text.length === 0) return {};
907
+ try {
908
+ const parsed = JSON.parse(text);
909
+ if (parsed !== null && typeof parsed === "object") {
910
+ return parsed;
911
+ }
912
+ return {};
913
+ } catch {
914
+ return {};
915
+ }
916
+ }
917
+
918
+ // ../renderer/src/ssr.ts
919
+ function renderToString(compiled, options = {}) {
920
+ const dom = options.domAdapter ?? new ServerDOMAdapter();
921
+ const container = dom.createElement("div");
922
+ const ctx = createRenderContext(dom, compiled.graph, container);
923
+ const rootInstance = mountGraph(ctx);
924
+ const html = dom.serializeInner(container);
925
+ rootInstance.dispose();
926
+ ctx.instances.clear();
927
+ return html;
928
+ }
929
+
930
+ // src/version.ts
931
+ var VERSION = "1.0.0";
932
+ export {
933
+ STATE_MARKER_ATTR,
934
+ ServerDOMAdapter,
935
+ VERSION,
936
+ readState,
937
+ renderToString,
938
+ serializeState
939
+ };
940
+ //# sourceMappingURL=server.js.map