sinwan 0.1.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +66 -39
  2. package/dist/cjs/index.development.js +2373 -842
  3. package/dist/cjs/index.development.js.map +22 -18
  4. package/dist/cjs/index.production.min.js +2 -2
  5. package/dist/cjs/index.production.min.js.map +22 -18
  6. package/dist/cjs/jsx/jsx-dev-runtime.development.js +6 -16
  7. package/dist/cjs/jsx/jsx-dev-runtime.development.js.map +3 -3
  8. package/dist/cjs/jsx/jsx-dev-runtime.production.min.js +2 -2
  9. package/dist/cjs/jsx/jsx-dev-runtime.production.min.js.map +3 -3
  10. package/dist/cjs/jsx/jsx-runtime.development.js +6 -16
  11. package/dist/cjs/jsx/jsx-runtime.development.js.map +3 -3
  12. package/dist/cjs/jsx/jsx-runtime.production.min.js +2 -2
  13. package/dist/cjs/jsx/jsx-runtime.production.min.js.map +3 -3
  14. package/dist/cjs/renderer/index.development.js +1581 -0
  15. package/dist/cjs/renderer/index.development.js.map +25 -0
  16. package/dist/cjs/renderer/index.production.min.js +3 -0
  17. package/dist/cjs/renderer/index.production.min.js.map +25 -0
  18. package/dist/cjs/server/index.development.js +1210 -362
  19. package/dist/cjs/server/index.development.js.map +13 -10
  20. package/dist/cjs/server/index.production.min.js +2 -2
  21. package/dist/cjs/server/index.production.min.js.map +13 -10
  22. package/dist/component/control-flow.d.ts +71 -0
  23. package/dist/component/control-flow.d.ts.map +1 -0
  24. package/dist/component/index.d.ts +3 -1
  25. package/dist/component/index.d.ts.map +1 -1
  26. package/dist/component/instance.d.ts +7 -1
  27. package/dist/component/instance.d.ts.map +1 -1
  28. package/dist/component/lifecycle.d.ts +2 -1
  29. package/dist/component/lifecycle.d.ts.map +1 -1
  30. package/dist/component/provide-inject.d.ts +11 -5
  31. package/dist/component/provide-inject.d.ts.map +1 -1
  32. package/dist/esm/index.development.js +2253 -744
  33. package/dist/esm/index.development.js.map +22 -18
  34. package/dist/esm/index.production.min.js +2 -2
  35. package/dist/esm/index.production.min.js.map +22 -18
  36. package/dist/esm/jsx/jsx-dev-runtime.development.js +6 -16
  37. package/dist/esm/jsx/jsx-dev-runtime.development.js.map +3 -3
  38. package/dist/esm/jsx/jsx-dev-runtime.production.min.js +2 -2
  39. package/dist/esm/jsx/jsx-dev-runtime.production.min.js.map +3 -3
  40. package/dist/esm/jsx/jsx-runtime.development.js +6 -16
  41. package/dist/esm/jsx/jsx-runtime.development.js.map +3 -3
  42. package/dist/esm/jsx/jsx-runtime.production.min.js +2 -2
  43. package/dist/esm/jsx/jsx-runtime.production.min.js.map +3 -3
  44. package/dist/esm/renderer/index.development.js +1530 -0
  45. package/dist/esm/renderer/index.development.js.map +25 -0
  46. package/dist/esm/renderer/index.production.min.js +4 -0
  47. package/dist/esm/renderer/index.production.min.js.map +25 -0
  48. package/dist/esm/server/index.development.js +1210 -362
  49. package/dist/esm/server/index.development.js.map +13 -10
  50. package/dist/esm/server/index.production.min.js +2 -2
  51. package/dist/esm/server/index.production.min.js.map +13 -10
  52. package/dist/hydration/walk.d.ts.map +1 -1
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/jsx/jsx-runtime.d.ts +13 -0
  56. package/dist/jsx/jsx-runtime.d.ts.map +1 -1
  57. package/dist/jsx/jsx-types.d.ts +122 -57
  58. package/dist/jsx/jsx-types.d.ts.map +1 -1
  59. package/dist/renderer/attributes.d.ts +11 -0
  60. package/dist/renderer/attributes.d.ts.map +1 -1
  61. package/dist/renderer/dom-ops.d.ts +4 -1
  62. package/dist/renderer/dom-ops.d.ts.map +1 -1
  63. package/dist/renderer/index.d.ts +2 -2
  64. package/dist/renderer/index.d.ts.map +1 -1
  65. package/dist/renderer/mount.d.ts +2 -5
  66. package/dist/renderer/mount.d.ts.map +1 -1
  67. package/dist/renderer/render-children.d.ts +2 -2
  68. package/dist/renderer/render-children.d.ts.map +1 -1
  69. package/dist/renderer/render-control-flow.d.ts +13 -0
  70. package/dist/renderer/render-control-flow.d.ts.map +1 -0
  71. package/dist/renderer/render-element.d.ts +1 -1
  72. package/dist/renderer/render-element.d.ts.map +1 -1
  73. package/dist/renderer/types.d.ts +10 -1
  74. package/dist/renderer/types.d.ts.map +1 -1
  75. package/dist/renderer/unmount.d.ts +20 -0
  76. package/dist/renderer/unmount.d.ts.map +1 -0
  77. package/dist/renderer.d.ts +1 -0
  78. package/dist/renderer.js +7 -0
  79. package/dist/renderer.mjs +4 -0
  80. package/dist/server/attribute-utils.d.ts +2 -0
  81. package/dist/server/attribute-utils.d.ts.map +1 -0
  82. package/dist/server/hydration-markers.d.ts.map +1 -1
  83. package/dist/server/index.d.ts +1 -1
  84. package/dist/server/index.d.ts.map +1 -1
  85. package/dist/server/renderer.d.ts.map +1 -1
  86. package/dist/server/stream.d.ts +9 -1
  87. package/dist/server/stream.d.ts.map +1 -1
  88. package/dist/types.d.ts +8 -2
  89. package/dist/types.d.ts.map +1 -1
  90. package/package.json +19 -5
@@ -87,22 +87,12 @@ function buildElement(type, props, children) {
87
87
  if (type === Fragment) {
88
88
  return { tag: "", props: {}, children };
89
89
  }
90
- if (typeof type === "function") {
91
- if (type._SinwanComponent || type._SinwanPage) {
92
- const result2 = type(props);
93
- if (result2 && typeof result2 === "object" && "tag" in result2) {
94
- return result2;
95
- }
96
- return { tag: "", props: {}, children: normalizeChildren(result2) };
97
- }
98
- const result = type(props);
99
- if (result && typeof result === "object" && "tag" in result) {
100
- return result;
90
+ if (typeof type === "function" || typeof type === "string") {
91
+ const finalProps = props ?? {};
92
+ if (children.length > 0 && finalProps.children === undefined) {
93
+ finalProps.children = children.length === 1 ? children[0] : children;
101
94
  }
102
- return { tag: "", props: {}, children: normalizeChildren(result) };
103
- }
104
- if (typeof type === "string") {
105
- return { tag: type, props: props || {}, children };
95
+ return { tag: type, props: finalProps, children };
106
96
  }
107
97
  return { tag: "", props: {}, children };
108
98
  }
@@ -122,270 +112,88 @@ function jsxDEV(type, props, key, isStaticChildren, source, self) {
122
112
  return element;
123
113
  }
124
114
 
125
- // src/server/index.ts
126
- var exports_server = {};
127
- __export(exports_server, {
128
- streamPage: () => streamPage,
129
- renderToString: () => renderToString,
130
- renderToHydratableString: () => renderToHydratableString,
131
- renderPage: () => renderPage,
132
- renderNodeToHydratableString: () => renderNodeToHydratableString,
133
- registerPage: () => registerPage,
134
- isSlots: () => isSlots,
135
- hasPage: () => hasPage,
136
- getPage: () => getPage
115
+ // src/renderer/index.ts
116
+ var exports_renderer = {};
117
+ __export(exports_renderer, {
118
+ unmountNode: () => unmountNode,
119
+ toEventName: () => toEventName,
120
+ setDOMOps: () => setDOMOps,
121
+ resetDOMOps: () => resetDOMOps,
122
+ renderNodeToDOM: () => renderNodeToDOM,
123
+ renderElementToDOM: () => renderElementToDOM,
124
+ renderChildrenToDOM: () => renderChildrenToDOM,
125
+ render: () => render,
126
+ mount: () => mount,
127
+ isEventProp: () => isEventProp,
128
+ domOps: () => domOps,
129
+ bindEvents: () => bindEvents,
130
+ bindEvent: () => bindEvent,
131
+ applyAttributes: () => applyAttributes
137
132
  });
138
- module.exports = __toCommonJS(exports_server);
139
-
140
- // src/escaper.ts
141
- var _bun = globalThis.Bun;
142
- var _nativeEscape = typeof _bun?.escapeHTML === "function" ? _bun.escapeHTML.bind(_bun) : undefined;
143
- var HTML_ESCAPE_RE = /[&<>"']/g;
144
- var HTML_ESCAPE_MAP = {
145
- "&": "&amp;",
146
- "<": "&lt;",
147
- ">": "&gt;",
148
- '"': "&quot;",
149
- "'": "&#39;"
150
- };
151
- function portableEscape(str) {
152
- HTML_ESCAPE_RE.lastIndex = 0;
153
- if (!HTML_ESCAPE_RE.test(str))
154
- return str;
155
- return str.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]);
156
- }
157
- function escapeHtml(value) {
158
- if (value == null || typeof value === "boolean")
159
- return "";
160
- if (typeof value === "number")
161
- return String(value);
162
- if (value instanceof HtmlEscapedString)
163
- return value.value;
164
- const s = String(value);
165
- return _nativeEscape ? _nativeEscape(s) : portableEscape(s);
166
- }
167
- function safeHtml(html) {
168
- return raw(html);
169
- }
170
- function isSafeHtml(value) {
171
- return value instanceof HtmlEscapedString;
172
- }
133
+ module.exports = __toCommonJS(exports_renderer);
173
134
 
174
- // src/server/renderer.ts
175
- var componentCache = new WeakMap;
176
- var pageRegistry = new Map;
177
- function registerPage(name, page) {
178
- pageRegistry.set(name, page);
179
- }
180
- function getPage(name) {
181
- return pageRegistry.get(name);
182
- }
183
- function hasPage(name) {
184
- return pageRegistry.has(name);
185
- }
186
- async function renderPage(name, data) {
187
- const page = getPage(name);
188
- if (!page) {
189
- throw new Error(`Page "${name}" not found in registry`);
190
- }
191
- const element = await page(data);
192
- return renderToString(element);
193
- }
194
- async function renderToString(node) {
195
- if (node == null || typeof node === "boolean") {
196
- return "";
197
- }
198
- if (typeof node === "string") {
199
- return escapeHtml(node);
200
- }
201
- if (typeof node === "number") {
202
- return String(node);
203
- }
204
- if (node instanceof HtmlEscapedString) {
205
- return node.value;
206
- }
207
- if (Array.isArray(node)) {
208
- const results = await Promise.all(node.map((child) => renderToString(child)));
209
- return results.join("");
210
- }
211
- if (node instanceof Promise) {
212
- return renderElement(await node);
213
- }
214
- return renderElement(node);
215
- }
216
- async function renderElement(element) {
217
- const { tag, props, children } = element;
218
- if (typeof tag === "function") {
219
- const result = await tag(props);
220
- return renderToString(result);
221
- }
222
- if (typeof tag === "string") {
223
- return renderIntrinsicElement(tag, props, children);
224
- }
225
- return renderToString(children);
226
- }
227
- var VOID_ELEMENTS2 = new Set([
228
- "area",
229
- "base",
230
- "br",
231
- "col",
232
- "embed",
233
- "hr",
234
- "img",
235
- "input",
236
- "link",
237
- "meta",
238
- "param",
239
- "source",
240
- "track",
241
- "wbr"
242
- ]);
243
- async function renderIntrinsicElement(tag, props, children) {
244
- const attrs = renderAttributes(props);
245
- if (VOID_ELEMENTS2.has(tag)) {
246
- return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
247
- }
248
- const childrenHtml = await renderChildren(children, props);
249
- return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
250
- }
251
- function renderAttributes(props) {
252
- let attrs = "";
253
- for (const [key, value] of Object.entries(props)) {
254
- if (key === "children")
255
- continue;
256
- if (value == null || value === false)
257
- continue;
258
- if (value === true) {
259
- attrs += ` ${key}`;
260
- continue;
261
- }
262
- if (key === "dangerouslySetInnerHTML") {
263
- continue;
264
- }
265
- const attrName = key === "className" ? "class" : key;
266
- const finalName = attrName === "htmlFor" ? "for" : attrName;
267
- const attrValue = escapeHtml(String(value));
268
- attrs += ` ${finalName}="${attrValue}"`;
269
- }
270
- return attrs;
271
- }
272
- async function renderChildren(children, props) {
273
- const dangerous = props.dangerouslySetInnerHTML;
274
- if (dangerous && typeof dangerous.__html === "string") {
275
- return dangerous.__html;
276
- }
277
- return renderToString(children);
278
- }
279
- function isSlots(children) {
280
- return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
281
- }
282
- // src/server/stream.ts
283
- var VOID_ELEMENTS3 = new Set([
284
- "area",
285
- "base",
286
- "br",
287
- "col",
288
- "embed",
289
- "hr",
290
- "img",
291
- "input",
292
- "link",
293
- "meta",
294
- "param",
295
- "source",
296
- "track",
297
- "wbr"
298
- ]);
299
- function streamPage(page, data) {
300
- const encoder = new TextEncoder;
301
- return new ReadableStream({
302
- async start(controller) {
303
- try {
304
- const element = await page(data);
305
- await streamNode(element, controller, encoder);
306
- controller.close();
307
- } catch (error) {
308
- controller.error(error);
309
- }
310
- }
311
- });
312
- }
313
- async function streamNode(node, controller, encoder) {
314
- if (node == null || typeof node === "boolean") {
315
- return;
316
- }
317
- if (typeof node === "string") {
318
- controller.enqueue(encoder.encode(escapeHtml(node)));
319
- return;
320
- }
321
- if (typeof node === "number") {
322
- controller.enqueue(encoder.encode(String(node)));
323
- return;
324
- }
325
- if (node instanceof HtmlEscapedString) {
326
- controller.enqueue(encoder.encode(node.value));
327
- return;
328
- }
329
- if (Array.isArray(node)) {
330
- for (const child of node) {
331
- await streamNode(child, controller, encoder);
135
+ // src/renderer/dom-ops.ts
136
+ function createDefaultDOMOps() {
137
+ return {
138
+ createElement(tag) {
139
+ return document.createElement(tag);
140
+ },
141
+ createElementNS(namespace, tag) {
142
+ return document.createElementNS(namespace, tag);
143
+ },
144
+ createTextNode(text) {
145
+ return document.createTextNode(text);
146
+ },
147
+ createComment(text) {
148
+ return document.createComment(text);
149
+ },
150
+ setAttribute(el, key, value) {
151
+ el.setAttribute(key, value);
152
+ },
153
+ removeAttribute(el, key) {
154
+ el.removeAttribute(key);
155
+ },
156
+ setProperty(el, key, value) {
157
+ el[key] = value;
158
+ },
159
+ insertBefore(parent, child, anchor) {
160
+ parent.insertBefore(child, anchor);
161
+ },
162
+ appendChild(parent, child) {
163
+ parent.appendChild(child);
164
+ },
165
+ remove(node) {
166
+ node.parentNode?.removeChild(node);
167
+ },
168
+ setTextContent(node, text) {
169
+ node.data = text;
170
+ },
171
+ addEventListener(el, event, handler) {
172
+ el.addEventListener(event, handler);
173
+ },
174
+ removeEventListener(el, event, handler) {
175
+ el.removeEventListener(event, handler);
176
+ },
177
+ parentNode(node) {
178
+ return node.parentNode;
179
+ },
180
+ nextSibling(node) {
181
+ return node.nextSibling;
332
182
  }
333
- return;
334
- }
335
- if (node instanceof Promise) {
336
- const resolved = await node;
337
- await streamElement(resolved, controller, encoder);
338
- return;
339
- }
340
- await streamElement(node, controller, encoder);
341
- }
342
- async function streamElement(element, controller, encoder) {
343
- const { tag, props, children } = element;
344
- if (typeof tag === "function") {
345
- const result = await tag(props);
346
- await streamNode(result, controller, encoder);
347
- return;
348
- }
349
- if (typeof tag === "string") {
350
- await streamIntrinsicElement(tag, props, children, controller, encoder);
351
- return;
352
- }
353
- await streamNode(children, controller, encoder);
183
+ };
354
184
  }
355
- async function streamIntrinsicElement(tag, props, children, controller, encoder) {
356
- const attrs = renderAttributes2(props);
357
- const dangerous = props.dangerouslySetInnerHTML;
358
- if (VOID_ELEMENTS3.has(tag)) {
359
- const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
360
- controller.enqueue(encoder.encode(html));
361
- return;
362
- }
363
- const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
364
- controller.enqueue(encoder.encode(openTag));
365
- if (dangerous && typeof dangerous.__html === "string") {
366
- controller.enqueue(encoder.encode(dangerous.__html));
367
- } else {
368
- await streamNode(children, controller, encoder);
369
- }
370
- controller.enqueue(encoder.encode(`</${tag}>`));
185
+ var defaultDOMOps = createDefaultDOMOps();
186
+ var domOps = { ...defaultDOMOps };
187
+ function setDOMOps(overrides) {
188
+ Object.assign(domOps, overrides);
371
189
  }
372
- function renderAttributes2(props) {
373
- let attrs = "";
374
- for (const [key, value] of Object.entries(props)) {
375
- if (key === "children" || key === "dangerouslySetInnerHTML")
376
- continue;
377
- if (value == null || value === false)
378
- continue;
379
- if (value === true) {
380
- attrs += ` ${key}`;
381
- continue;
382
- }
383
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
384
- const attrValue = escapeHtml(String(value));
385
- attrs += ` ${attrName}="${attrValue}"`;
190
+ function resetDOMOps() {
191
+ for (const key of Object.keys(domOps)) {
192
+ delete domOps[key];
386
193
  }
387
- return attrs;
194
+ Object.assign(domOps, defaultDOMOps);
388
195
  }
196
+
389
197
  // src/reactivity/scheduler.ts
390
198
  var pendingEffects = new Set;
391
199
  var flushScheduled = false;
@@ -628,79 +436,6 @@ function isComputed(value) {
628
436
  return value != null && typeof value === "object" && COMPUTED_BRAND in value;
629
437
  }
630
438
 
631
- // src/hydration/markers.ts
632
- var COMP_ID_ATTR = "data-sinwan-id";
633
- var COMP_ID_PREFIX = "c";
634
- var TEXT_MARKER_OPEN = "sinwan-t:";
635
- var TEXT_MARKER_CLOSE = "/sinwan-t";
636
- var EVENT_ATTR = "data-sinwan-ev";
637
- function compId(index) {
638
- return `${COMP_ID_PREFIX}${index}`;
639
- }
640
- function textMarkerOpen(index) {
641
- return `<!--${TEXT_MARKER_OPEN}${index}-->`;
642
- }
643
- function textMarkerCloseStr() {
644
- return `<!--${TEXT_MARKER_CLOSE}-->`;
645
- }
646
- function parseTextOpenMarker(node) {
647
- const data = node.data;
648
- if (data.startsWith(TEXT_MARKER_OPEN)) {
649
- const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
650
- return Number.isNaN(idx) ? -1 : idx;
651
- }
652
- return -1;
653
- }
654
- function isTextCloseMarker(node) {
655
- return node.data === TEXT_MARKER_CLOSE;
656
- }
657
-
658
- // src/renderer/dom-ops.ts
659
- var domOps = {
660
- createElement(tag) {
661
- return document.createElement(tag);
662
- },
663
- createTextNode(text) {
664
- return document.createTextNode(text);
665
- },
666
- createComment(text) {
667
- return document.createComment(text);
668
- },
669
- setAttribute(el, key, value) {
670
- el.setAttribute(key, value);
671
- },
672
- removeAttribute(el, key) {
673
- el.removeAttribute(key);
674
- },
675
- setProperty(el, key, value) {
676
- el[key] = value;
677
- },
678
- insertBefore(parent, child, anchor) {
679
- parent.insertBefore(child, anchor);
680
- },
681
- appendChild(parent, child) {
682
- parent.appendChild(child);
683
- },
684
- remove(node) {
685
- node.parentNode?.removeChild(node);
686
- },
687
- setTextContent(node, text) {
688
- node.data = text;
689
- },
690
- addEventListener(el, event, handler) {
691
- el.addEventListener(event, handler);
692
- },
693
- removeEventListener(el, event, handler) {
694
- el.removeEventListener(event, handler);
695
- },
696
- parentNode(node) {
697
- return node.parentNode;
698
- },
699
- nextSibling(node) {
700
- return node.nextSibling;
701
- }
702
- };
703
-
704
439
  // src/renderer/events.ts
705
440
  function isEventProp(key) {
706
441
  return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
@@ -757,7 +492,18 @@ function setCurrentInstance(instance) {
757
492
  currentInstance = instance;
758
493
  return prev;
759
494
  }
495
+ function withInstance(instance, fn) {
496
+ const prev = setCurrentInstance(instance);
497
+ try {
498
+ return fn();
499
+ } finally {
500
+ setCurrentInstance(prev);
501
+ }
502
+ }
760
503
  function fireMountedHooks(instance) {
504
+ if (instance.isUnmounted) {
505
+ return;
506
+ }
761
507
  for (const child of instance.children) {
762
508
  fireMountedHooks(child);
763
509
  }
@@ -784,6 +530,24 @@ function fireUnmountedHooks(instance) {
784
530
  instance.effects.length = 0;
785
531
  }
786
532
  }
533
+ function fireUpdatedHooks(instance) {
534
+ for (const hook of instance._updatedHooks) {
535
+ hook();
536
+ }
537
+ }
538
+ var queuedUpdatedHooks = new Set;
539
+ function queueUpdatedHooks(instance) {
540
+ if (!instance || !instance.isMounted || instance.isUnmounted || instance._updatedHooks.length === 0 || queuedUpdatedHooks.has(instance)) {
541
+ return;
542
+ }
543
+ queuedUpdatedHooks.add(instance);
544
+ nextTick(() => {
545
+ queuedUpdatedHooks.delete(instance);
546
+ if (instance.isMounted && !instance.isUnmounted) {
547
+ fireUpdatedHooks(instance);
548
+ }
549
+ });
550
+ }
787
551
  function handleComponentError(instance, err) {
788
552
  let current = instance;
789
553
  while (current) {
@@ -798,177 +562,125 @@ function handleComponentError(instance, err) {
798
562
  console.error("[Sinwan] Unhandled component error:", err);
799
563
  }
800
564
 
801
- // src/server/hydration-markers.ts
802
- function createHydrationContext() {
803
- return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
804
- }
805
- async function renderToHydratableString(component, props) {
806
- const ctx = createHydrationContext();
807
- const mergedProps = props ?? {};
808
- const instance = createComponentInstance(component, mergedProps, null);
809
- setCurrentInstance(instance);
810
- const result = await component(mergedProps);
811
- setCurrentInstance(null);
812
- if (result && typeof result === "object" && "tag" in result) {
813
- return renderElementH(result, ctx, true);
565
+ // src/renderer/attributes.ts
566
+ var SKIP_PROPS = new Set(["children", "key", "ref", "dangerouslySetInnerHTML"]);
567
+ var DOM_PROPERTIES = new Set(["value", "checked", "selected", "disabled", "readOnly", "multiple", "indeterminate"]);
568
+ var PROP_ALIASES = {
569
+ className: "class",
570
+ htmlFor: "for",
571
+ tabIndex: "tabindex",
572
+ crossOrigin: "crossorigin"
573
+ };
574
+ function applyAttributes(el, props) {
575
+ const disposers = [];
576
+ const owner = getCurrentInstance();
577
+ for (const [key, value] of Object.entries(props)) {
578
+ if (SKIP_PROPS.has(key) || isEventProp(key))
579
+ continue;
580
+ if (isSignal(value) || isComputed(value)) {
581
+ const state = { previousStyleProps: new Set };
582
+ let initialized = false;
583
+ const dispose = effect(() => {
584
+ setSingleAttribute(el, key, value.value, state);
585
+ if (initialized) {
586
+ queueUpdatedHooks(owner);
587
+ }
588
+ initialized = true;
589
+ });
590
+ disposers.push(dispose);
591
+ } else {
592
+ setSingleAttribute(el, key, value);
593
+ }
814
594
  }
815
- return renderNodeH(result, ctx);
816
- }
817
- async function renderNodeToHydratableString(node) {
818
- const ctx = createHydrationContext();
819
- return renderNodeH(node, ctx);
595
+ return disposers;
820
596
  }
821
- var VOID_ELEMENTS4 = new Set([
822
- "area",
823
- "base",
824
- "br",
825
- "col",
826
- "embed",
827
- "hr",
828
- "img",
829
- "input",
830
- "link",
831
- "meta",
832
- "param",
833
- "source",
834
- "track",
835
- "wbr"
836
- ]);
837
- function renderNodeH(node, ctx) {
838
- if (node == null || typeof node === "boolean")
839
- return "";
840
- if (typeof node === "string")
841
- return escapeHtml(node);
842
- if (typeof node === "number")
843
- return String(node);
844
- if (node instanceof HtmlEscapedString)
845
- return node.value;
846
- if (isSignal(node) || isComputed(node)) {
847
- const value = node.value;
848
- const idx = ctx.textIndex++;
849
- return `${textMarkerOpen(idx)}${escapeHtml(String(value))}${textMarkerCloseStr()}`;
850
- }
851
- if (Array.isArray(node)) {
852
- return node.map((child) => renderNodeH(child, ctx)).join("");
597
+ function setSingleAttribute(el, key, value, state) {
598
+ const attrName = resolveAttributeName(key);
599
+ if (attrName === "style" && typeof value === "object" && value !== null) {
600
+ applyStyle(el, value, state);
601
+ return;
853
602
  }
854
- if (node instanceof Promise) {
855
- return "";
603
+ if (attrName === "class" && typeof value === "object" && value !== null) {
604
+ applyClass(el, value);
605
+ return;
856
606
  }
857
- if (typeof node === "object" && "tag" in node) {
858
- return renderElementH(node, ctx, false);
607
+ if (value == null || value === false) {
608
+ domOps.removeAttribute(el, attrName);
609
+ if (attrName === "style" && state) {
610
+ state.previousStyleProps.clear();
611
+ }
612
+ if (DOM_PROPERTIES.has(attrName)) {
613
+ domOps.setProperty(el, attrName, attrName === "value" ? "" : false);
614
+ }
615
+ return;
859
616
  }
860
- return escapeHtml(String(node));
861
- }
862
- function renderElementH(element, ctx, isComponentRoot) {
863
- const { tag, props, children } = element;
864
- if (tag === "") {
865
- return children.map((child) => renderNodeH(child, ctx)).join("");
617
+ if (value === true) {
618
+ domOps.setAttribute(el, attrName, "");
619
+ if (attrName === "style" && state) {
620
+ state.previousStyleProps.clear();
621
+ }
622
+ if (DOM_PROPERTIES.has(attrName)) {
623
+ domOps.setProperty(el, attrName, true);
624
+ }
625
+ return;
866
626
  }
867
- if (typeof tag === "function") {
868
- return renderComponentH(tag, props, ctx);
627
+ if (DOM_PROPERTIES.has(attrName)) {
628
+ if (attrName === "style" && state) {
629
+ state.previousStyleProps.clear();
630
+ }
631
+ domOps.setProperty(el, attrName, value);
632
+ return;
869
633
  }
870
- if (typeof tag === "string") {
871
- return renderIntrinsicH(tag, props, children, ctx, isComponentRoot);
634
+ if (attrName === "style" && state) {
635
+ state.previousStyleProps.clear();
872
636
  }
873
- return children.map((child) => renderNodeH(child, ctx)).join("");
637
+ domOps.setAttribute(el, attrName, String(value));
874
638
  }
875
- function renderComponentH(component, props, ctx) {
876
- const parentInstance = globalThis.__SinwanCurrentInstance;
877
- const instance = createComponentInstance(component, props, null);
878
- const prev = setCurrentInstance(instance);
879
- const result = component(props);
880
- setCurrentInstance(prev);
881
- if (result && typeof result === "object" && "tag" in result) {
882
- return renderElementH(result, ctx, true);
883
- }
884
- return renderNodeH(result, ctx);
639
+ function resolveAttributeName(key) {
640
+ return PROP_ALIASES[key] ?? key;
885
641
  }
886
- function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
887
- let attrs = "";
888
- if (isComponentRoot) {
889
- attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
890
- }
891
- const eventParts = [];
892
- for (const [key, value] of Object.entries(props)) {
893
- if (key === "children" || key === "dangerouslySetInnerHTML")
894
- continue;
895
- if (isEventProp(key)) {
896
- const eventName = toEventName(key);
897
- eventParts.push(`${eventName}:${ctx.eventIndex++}`);
898
- continue;
899
- }
900
- if (value == null || value === false)
642
+ function applyStyle(el, styles, state) {
643
+ const nextProps = new Set;
644
+ for (const [prop, val] of Object.entries(styles)) {
645
+ nextProps.add(prop);
646
+ if (val == null) {
647
+ removeStyleProperty(el, prop);
901
648
  continue;
902
- let resolvedValue = value;
903
- if (isSignal(value) || isComputed(value)) {
904
- resolvedValue = value.value;
905
649
  }
906
- if (resolvedValue === true) {
907
- const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
908
- attrs += ` ${attrName2}`;
909
- continue;
650
+ if (prop.includes("-")) {
651
+ el.style.setProperty(prop, String(val));
652
+ } else {
653
+ el.style[prop] = val;
910
654
  }
911
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
912
- attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
913
655
  }
914
- if (eventParts.length > 0) {
915
- attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
656
+ if (!state) {
657
+ return;
916
658
  }
917
- if (VOID_ELEMENTS4.has(tag)) {
918
- return `<${tag}${attrs}>`;
659
+ for (const previousProp of state.previousStyleProps) {
660
+ if (!nextProps.has(previousProp)) {
661
+ removeStyleProperty(el, previousProp);
662
+ }
919
663
  }
920
- const dangerous = props.dangerouslySetInnerHTML;
921
- if (dangerous && typeof dangerous.__html === "string") {
922
- return `<${tag}${attrs}>${dangerous.__html}</${tag}>`;
664
+ state.previousStyleProps = nextProps;
665
+ }
666
+ function removeStyleProperty(el, prop) {
667
+ if (prop.includes("-")) {
668
+ el.style.removeProperty(prop);
669
+ } else {
670
+ el.style[prop] = "";
923
671
  }
924
- const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
925
- return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
926
672
  }
927
- // src/index.ts
928
- var exports_src = {};
929
- __export(exports_src, {
930
- unmountNode: () => unmountNode,
931
- streamPage: () => streamPage,
932
- signal: () => signal,
933
- safeHtml: () => safeHtml,
934
- renderToString: () => renderToString,
935
- renderToHydratableString: () => renderToHydratableString,
936
- renderPage: () => renderPage,
937
- renderNodeToHydratableString: () => renderNodeToHydratableString,
938
- renderNodeToDOM: () => renderNodeToDOM,
939
- renderElementToDOM: () => renderElementToDOM,
940
- render: () => render,
941
- registerPage: () => registerPage,
942
- raw: () => raw,
943
- provide: () => provide,
944
- onUpdated: () => onUpdated,
945
- onUnmounted: () => onUnmounted,
946
- onMounted: () => onMounted,
947
- onError: () => onError,
948
- nextTick: () => nextTick,
949
- mount: () => mount,
950
- jsxs: () => jsxs,
951
- jsxDEV: () => jsxDEV,
952
- jsx: () => jsx,
953
- isSignal: () => isSignal,
954
- isSafeHtml: () => isSafeHtml,
955
- isComputed: () => isComputed,
956
- inject: () => inject,
957
- hydrate: () => hydrate,
958
- hasPage: () => hasPage,
959
- getPage: () => getPage,
960
- getCurrentInstance: () => getCurrentInstance,
961
- escapeHtml: () => escapeHtml,
962
- effect: () => effect,
963
- createPage: () => createPage,
964
- createLayout: () => createLayout,
965
- createComponent: () => createComponent,
966
- computed: () => computed,
967
- batch: () => batch,
968
- HtmlEscapedString: () => HtmlEscapedString,
969
- Fragment: () => Fragment
970
- });
971
- module.exports = __toCommonJS(exports_src);
673
+ function applyClass(el, value) {
674
+ let classStr;
675
+ if (Array.isArray(value)) {
676
+ classStr = value.filter(Boolean).join(" ");
677
+ } else if (typeof value === "object" && value !== null) {
678
+ classStr = Object.entries(value).filter(([, v]) => Boolean(v)).map(([k]) => k).join(" ");
679
+ } else {
680
+ classStr = String(value);
681
+ }
682
+ domOps.setAttribute(el, "class", classStr);
683
+ }
972
684
  // src/reactivity/batch.ts
973
685
  var batchDepth = 0;
974
686
  function batch(fn) {
@@ -982,150 +694,1734 @@ function batch(fn) {
982
694
  }
983
695
  }
984
696
  }
985
- // src/component/lifecycle.ts
986
- function onMounted(fn) {
987
- const instance = getCurrentInstance();
988
- if (!instance) {
989
- throw new Error("onMounted() called outside of component setup.");
990
- }
991
- instance._mountedHooks.push(fn);
697
+ // src/component/control-flow.ts
698
+ var SHOW_TYPE = Symbol.for("Sinwan.Show");
699
+ var FOR_TYPE = Symbol.for("Sinwan.For");
700
+ var SWITCH_TYPE = Symbol.for("Sinwan.Switch");
701
+ var MATCH_TYPE = Symbol.for("Sinwan.Match");
702
+ var INDEX_TYPE = Symbol.for("Sinwan.Index");
703
+ var KEY_TYPE = Symbol.for("Sinwan.Key");
704
+ var DYNAMIC_TYPE = Symbol.for("Sinwan.Dynamic");
705
+ var PORTAL_TYPE = Symbol.for("Sinwan.Portal");
706
+ function Show(props) {
707
+ return {
708
+ tag: SHOW_TYPE,
709
+ props,
710
+ children: []
711
+ };
992
712
  }
993
- function onUnmounted(fn) {
994
- const instance = getCurrentInstance();
995
- if (!instance) {
996
- throw new Error("onUnmounted() called outside of component setup.");
713
+ function For(props) {
714
+ return {
715
+ tag: FOR_TYPE,
716
+ props,
717
+ children: []
718
+ };
719
+ }
720
+ function Switch(props) {
721
+ return {
722
+ tag: SWITCH_TYPE,
723
+ props,
724
+ children: []
725
+ };
726
+ }
727
+ function Match(props) {
728
+ return {
729
+ tag: MATCH_TYPE,
730
+ props,
731
+ children: []
732
+ };
733
+ }
734
+ function Index(props) {
735
+ return {
736
+ tag: INDEX_TYPE,
737
+ props,
738
+ children: []
739
+ };
740
+ }
741
+ function Key(props) {
742
+ return {
743
+ tag: KEY_TYPE,
744
+ props,
745
+ children: []
746
+ };
747
+ }
748
+ function Dynamic(props) {
749
+ return {
750
+ tag: DYNAMIC_TYPE,
751
+ props,
752
+ children: []
753
+ };
754
+ }
755
+ function Visible(props) {
756
+ const {
757
+ when,
758
+ as = "span",
759
+ style,
760
+ children,
761
+ ...rest
762
+ } = props;
763
+ const visibleStyle = computed(() => {
764
+ const base = readReactive(style);
765
+ const visible = Boolean(readReactive(when));
766
+ if (typeof base === "string") {
767
+ return visible ? base : appendHiddenDisplay(base);
768
+ }
769
+ const styleObject = base && typeof base === "object" ? { ...base } : {};
770
+ styleObject.display = visible ? styleObject.display : "none";
771
+ return styleObject;
772
+ });
773
+ return {
774
+ tag: as,
775
+ props: {
776
+ ...rest,
777
+ style: visibleStyle,
778
+ children
779
+ },
780
+ children: normalizeChildren2(children)
781
+ };
782
+ }
783
+ function Portal(props) {
784
+ return {
785
+ tag: PORTAL_TYPE,
786
+ props,
787
+ children: []
788
+ };
789
+ }
790
+ function isShowElement(element) {
791
+ return element.tag === SHOW_TYPE;
792
+ }
793
+ function isForElement(element) {
794
+ return element.tag === FOR_TYPE;
795
+ }
796
+ function isSwitchElement(element) {
797
+ return element.tag === SWITCH_TYPE;
798
+ }
799
+ function isMatchElement(element) {
800
+ return element.tag === MATCH_TYPE;
801
+ }
802
+ function isIndexElement(element) {
803
+ return element.tag === INDEX_TYPE;
804
+ }
805
+ function isKeyElement(element) {
806
+ return element.tag === KEY_TYPE;
807
+ }
808
+ function isDynamicElement(element) {
809
+ return element.tag === DYNAMIC_TYPE;
810
+ }
811
+ function isPortalElement(element) {
812
+ return element.tag === PORTAL_TYPE;
813
+ }
814
+ function normalizeChildren2(children) {
815
+ if (children == null || typeof children === "boolean") {
816
+ return [];
817
+ }
818
+ return Array.isArray(children) ? children : [children];
819
+ }
820
+ function readReactive(value) {
821
+ return isSignal(value) || isComputed(value) ? value.value : value;
822
+ }
823
+ function appendHiddenDisplay(style) {
824
+ const trimmed = style.trim();
825
+ const separator = trimmed.length > 0 && !trimmed.endsWith(";") ? ";" : "";
826
+ return `${trimmed}${separator}display:none`;
827
+ }
828
+
829
+ // src/renderer/unmount.ts
830
+ function getMountedDomNodes(node) {
831
+ switch (node.type) {
832
+ case "text":
833
+ case "reactive-text":
834
+ return [node.node];
835
+ case "element":
836
+ return [node.node];
837
+ case "fragment":
838
+ return [
839
+ node.anchor,
840
+ ...node.children.flatMap((child) => getMountedDomNodes(child))
841
+ ];
842
+ case "reactive-block":
843
+ return [
844
+ node.startAnchor,
845
+ ...node.children.flatMap((child) => getMountedDomNodes(child)),
846
+ node.endAnchor
847
+ ];
848
+ case "component":
849
+ return node.children.flatMap((child) => getMountedDomNodes(child));
850
+ case "portal":
851
+ return [node.anchor];
852
+ }
853
+ }
854
+ function unmountNode(node) {
855
+ switch (node.type) {
856
+ case "text":
857
+ break;
858
+ case "reactive-text":
859
+ node.dispose();
860
+ break;
861
+ case "element":
862
+ for (const dispose of node.attrDisposers) {
863
+ dispose();
864
+ }
865
+ for (const cleanup of node.eventCleanups) {
866
+ cleanup();
867
+ }
868
+ node.refCleanup?.();
869
+ for (const child of node.children) {
870
+ unmountNode(child);
871
+ }
872
+ break;
873
+ case "fragment":
874
+ for (const child of node.children) {
875
+ unmountNode(child);
876
+ }
877
+ break;
878
+ case "reactive-block":
879
+ node.dispose();
880
+ for (const child of node.children) {
881
+ unmountNode(child);
882
+ }
883
+ break;
884
+ case "component":
885
+ if (node.instance) {
886
+ fireUnmountedHooks(node.instance);
887
+ } else {
888
+ for (const dispose of node.disposers) {
889
+ dispose();
890
+ }
891
+ }
892
+ for (const child of node.children) {
893
+ unmountNode(child);
894
+ }
895
+ break;
896
+ case "portal":
897
+ node.dispose();
898
+ for (const child of node.children) {
899
+ removeMountedNode(child);
900
+ }
901
+ node.children = [];
902
+ break;
903
+ }
904
+ }
905
+ function removeMountedNode(node) {
906
+ const domNodes = getMountedDomNodes(node);
907
+ unmountNode(node);
908
+ for (const domNode of domNodes) {
909
+ if (domNode.parentNode) {
910
+ domOps.remove(domNode);
911
+ }
912
+ }
913
+ }
914
+
915
+ // src/renderer/render-control-flow.ts
916
+ function renderControlFlowToDOM(element, parent, anchor, namespace) {
917
+ if (isPortalElement(element)) {
918
+ return renderPortal(element, parent, anchor, namespace);
919
+ }
920
+ const startAnchor = domOps.createComment("Sinwan-b");
921
+ const endAnchor = domOps.createComment("/Sinwan-b");
922
+ insertNode(parent, startAnchor, anchor);
923
+ insertNode(parent, endAnchor, anchor);
924
+ const owner = getCurrentInstance();
925
+ let disposeEffect = () => {};
926
+ const block = {
927
+ type: "reactive-block",
928
+ dispose: () => disposeEffect(),
929
+ children: [],
930
+ startAnchor,
931
+ endAnchor
932
+ };
933
+ if (isShowElement(element)) {
934
+ disposeEffect = renderShowBlock(element, block, parent, namespace, owner);
935
+ } else if (isForElement(element)) {
936
+ disposeEffect = renderForBlock(element, block, parent, namespace, owner);
937
+ } else if (isSwitchElement(element)) {
938
+ disposeEffect = renderSwitchBlock(element, block, parent, namespace, owner);
939
+ } else if (isIndexElement(element)) {
940
+ disposeEffect = renderIndexBlock(element, block, parent, namespace, owner);
941
+ } else if (isKeyElement(element)) {
942
+ disposeEffect = renderKeyBlock(element, block, parent, namespace, owner);
943
+ } else if (isDynamicElement(element)) {
944
+ disposeEffect = renderDynamicBlock(element, block, parent, namespace, owner);
945
+ }
946
+ return block;
947
+ }
948
+ function renderShowBlock(element, block, parent, namespace, owner) {
949
+ let initialized = false;
950
+ return effect(() => {
951
+ clearChildren(block);
952
+ const when = readReactive2(element.props.when);
953
+ const content = withOptionalInstance(owner, () => when ? resolveShowChildren(element, when) : element.props.fallback);
954
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
955
+ if (initialized) {
956
+ fireMountedAndQueueUpdated(owner);
957
+ }
958
+ initialized = true;
959
+ });
960
+ }
961
+ function renderForBlock(element, block, parent, namespace, owner) {
962
+ let initialized = false;
963
+ let records = [];
964
+ return effect(() => {
965
+ const props = element.props;
966
+ const items = readReactive2(props.each);
967
+ const list = Array.isArray(items) ? items : [];
968
+ const renderChild = props.children;
969
+ if (typeof renderChild !== "function") {
970
+ clearChildren(block);
971
+ records = [];
972
+ if (initialized) {
973
+ queueUpdatedHooks(owner);
974
+ }
975
+ initialized = true;
976
+ return;
977
+ }
978
+ if (list.length === 0) {
979
+ clearChildren(block);
980
+ records = [];
981
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
982
+ if (initialized) {
983
+ fireMountedAndQueueUpdated(owner);
984
+ }
985
+ initialized = true;
986
+ return;
987
+ }
988
+ if (records.length === 0 && block.children.length > 0) {
989
+ clearChildren(block);
990
+ }
991
+ const oldByKey = new Map;
992
+ for (const record of records) {
993
+ oldByKey.set(record.key, record);
994
+ }
995
+ const nextRecords = [];
996
+ list.forEach((item, index) => {
997
+ const key = props.key ? props.key(item, index) : item;
998
+ const old = oldByKey.get(key);
999
+ if (old && old.item === item) {
1000
+ old.index = index;
1001
+ moveBeforeEnd(parent, old.mounted, block.endAnchor);
1002
+ nextRecords.push(old);
1003
+ oldByKey.delete(key);
1004
+ return;
1005
+ }
1006
+ if (old) {
1007
+ removeMountedNode(old.mounted);
1008
+ oldByKey.delete(key);
1009
+ }
1010
+ const record = {
1011
+ key,
1012
+ item,
1013
+ index,
1014
+ mounted: { type: "text", node: domOps.createTextNode("") }
1015
+ };
1016
+ record.mounted = withOptionalInstance(owner, () => renderNodeToDOM(renderChild(item, () => record.index), parent, block.endAnchor, namespace));
1017
+ nextRecords.push(record);
1018
+ });
1019
+ for (const record of oldByKey.values()) {
1020
+ removeMountedNode(record.mounted);
1021
+ }
1022
+ records = nextRecords;
1023
+ block.children = nextRecords.map((record) => record.mounted);
1024
+ if (initialized) {
1025
+ fireMountedAndQueueUpdated(owner);
1026
+ }
1027
+ initialized = true;
1028
+ });
1029
+ }
1030
+ function renderSwitchBlock(element, block, parent, namespace, owner) {
1031
+ let initialized = false;
1032
+ return effect(() => {
1033
+ clearChildren(block);
1034
+ const content = withOptionalInstance(owner, () => resolveSwitchContent(element));
1035
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1036
+ if (initialized) {
1037
+ fireMountedAndQueueUpdated(owner);
1038
+ }
1039
+ initialized = true;
1040
+ });
1041
+ }
1042
+ function renderIndexBlock(element, block, parent, namespace, owner) {
1043
+ let initialized = false;
1044
+ let records = [];
1045
+ return effect(() => {
1046
+ const props = element.props;
1047
+ const items = readReactive2(props.each);
1048
+ const list = Array.isArray(items) ? items : [];
1049
+ const renderChild = props.children;
1050
+ if (typeof renderChild !== "function") {
1051
+ clearChildren(block);
1052
+ records = [];
1053
+ if (initialized) {
1054
+ queueUpdatedHooks(owner);
1055
+ }
1056
+ initialized = true;
1057
+ return;
1058
+ }
1059
+ if (list.length === 0) {
1060
+ clearChildren(block);
1061
+ records = [];
1062
+ block.children = renderBlockContent(props.fallback, parent, block.endAnchor, namespace, owner);
1063
+ if (initialized) {
1064
+ fireMountedAndQueueUpdated(owner);
1065
+ }
1066
+ initialized = true;
1067
+ return;
1068
+ }
1069
+ if (records.length === 0 && block.children.length > 0) {
1070
+ clearChildren(block);
1071
+ }
1072
+ for (let index = 0;index < list.length; index++) {
1073
+ const existing = records[index];
1074
+ if (existing) {
1075
+ existing.item.value = list[index];
1076
+ continue;
1077
+ }
1078
+ const itemSignal = signal(list[index]);
1079
+ const record = {
1080
+ item: itemSignal,
1081
+ mounted: withOptionalInstance(owner, () => renderNodeToDOM(renderChild(() => itemSignal.value, index), parent, block.endAnchor, namespace))
1082
+ };
1083
+ records.push(record);
1084
+ }
1085
+ while (records.length > list.length) {
1086
+ const removed = records.pop();
1087
+ removeMountedNode(removed.mounted);
1088
+ }
1089
+ block.children = records.map((record) => record.mounted);
1090
+ if (initialized) {
1091
+ fireMountedAndQueueUpdated(owner);
1092
+ }
1093
+ initialized = true;
1094
+ });
1095
+ }
1096
+ function renderKeyBlock(element, block, parent, namespace, owner) {
1097
+ let initialized = false;
1098
+ let hasKey = false;
1099
+ let currentKey;
1100
+ return effect(() => {
1101
+ const key = readReactive2(element.props.when);
1102
+ if (hasKey && Object.is(currentKey, key)) {
1103
+ return;
1104
+ }
1105
+ currentKey = key;
1106
+ hasKey = true;
1107
+ clearChildren(block);
1108
+ const content = withOptionalInstance(owner, () => resolveKeyChildren(element, key));
1109
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1110
+ if (initialized) {
1111
+ fireMountedAndQueueUpdated(owner);
1112
+ }
1113
+ initialized = true;
1114
+ });
1115
+ }
1116
+ function renderDynamicBlock(element, block, parent, namespace, owner) {
1117
+ let initialized = false;
1118
+ let hasTag = false;
1119
+ let currentTag;
1120
+ return effect(() => {
1121
+ const tag = readReactive2(element.props.component);
1122
+ if (hasTag && Object.is(currentTag, tag)) {
1123
+ return;
1124
+ }
1125
+ currentTag = tag;
1126
+ hasTag = true;
1127
+ clearChildren(block);
1128
+ const content = tag ? createDynamicElement(element, tag) : null;
1129
+ block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
1130
+ if (initialized) {
1131
+ fireMountedAndQueueUpdated(owner);
1132
+ }
1133
+ initialized = true;
1134
+ });
1135
+ }
1136
+ function renderPortal(element, parent, anchor, namespace) {
1137
+ const placeholder = domOps.createComment("Sinwan-p");
1138
+ insertNode(parent, placeholder, anchor);
1139
+ const owner = getCurrentInstance();
1140
+ let disposeEffect = () => {};
1141
+ const portal = {
1142
+ type: "portal",
1143
+ anchor: placeholder,
1144
+ children: [],
1145
+ dispose: () => disposeEffect()
1146
+ };
1147
+ let initialized = false;
1148
+ disposeEffect = effect(() => {
1149
+ clearPortalChildren(portal);
1150
+ const target = resolvePortalTarget(element.props.mount);
1151
+ if (target) {
1152
+ portal.children = renderBlockContent(element.props.children ?? element.children, target, null, namespace, owner);
1153
+ }
1154
+ if (initialized) {
1155
+ fireMountedAndQueueUpdated(owner);
1156
+ }
1157
+ initialized = true;
1158
+ });
1159
+ return portal;
1160
+ }
1161
+ function resolveShowChildren(element, value) {
1162
+ const children = element.props.children ?? element.children;
1163
+ if (typeof children === "function") {
1164
+ return children(value);
1165
+ }
1166
+ return children;
1167
+ }
1168
+ function resolveSwitchContent(element) {
1169
+ const props = element.props;
1170
+ const children = normalizeContent(props.children ?? element.children);
1171
+ for (const child of children) {
1172
+ const match = getMatchElement(child);
1173
+ if (!match) {
1174
+ continue;
1175
+ }
1176
+ const when = readReactive2(match.props.when);
1177
+ if (when) {
1178
+ return resolveMatchChildren(match, when);
1179
+ }
1180
+ }
1181
+ return props.fallback;
1182
+ }
1183
+ function resolveMatchChildren(element, value) {
1184
+ const children = element.props.children ?? element.children;
1185
+ if (typeof children === "function") {
1186
+ return children(value);
1187
+ }
1188
+ return children;
1189
+ }
1190
+ function resolveKeyChildren(element, value) {
1191
+ const children = element.props.children ?? element.children;
1192
+ if (typeof children === "function") {
1193
+ return children(value);
1194
+ }
1195
+ return children;
1196
+ }
1197
+ function createDynamicElement(element, tag) {
1198
+ if (typeof tag !== "string" && typeof tag !== "function") {
1199
+ return null;
1200
+ }
1201
+ const { component, ...props } = element.props;
1202
+ const children = normalizeContent(props.children ?? element.children);
1203
+ return {
1204
+ tag,
1205
+ props,
1206
+ children
1207
+ };
1208
+ }
1209
+ function renderBlockContent(content, parent, anchor, namespace, owner) {
1210
+ if (content == null || typeof content === "boolean") {
1211
+ return [];
1212
+ }
1213
+ const nodes = Array.isArray(content) ? content : [content];
1214
+ return nodes.map((node) => withOptionalInstance(owner, () => renderNodeToDOM(node, parent, anchor, namespace)));
1215
+ }
1216
+ function clearChildren(block) {
1217
+ for (const child of block.children) {
1218
+ removeMountedNode(child);
1219
+ }
1220
+ block.children = [];
1221
+ }
1222
+ function clearPortalChildren(portal) {
1223
+ for (const child of portal.children) {
1224
+ removeMountedNode(child);
1225
+ }
1226
+ portal.children = [];
1227
+ }
1228
+ function moveBeforeEnd(parent, mounted, endAnchor) {
1229
+ for (const node of getMountedDomNodes(mounted)) {
1230
+ domOps.insertBefore(parent, node, endAnchor);
1231
+ }
1232
+ }
1233
+ function fireMountedAndQueueUpdated(owner) {
1234
+ if (owner) {
1235
+ fireMountedHooks(owner);
1236
+ }
1237
+ queueUpdatedHooks(owner);
1238
+ }
1239
+ function withOptionalInstance(owner, fn) {
1240
+ return owner ? withInstance(owner, fn) : fn();
1241
+ }
1242
+ function readReactive2(value) {
1243
+ return isSignal(value) || isComputed(value) ? value.value : value;
1244
+ }
1245
+ function normalizeContent(content) {
1246
+ if (content == null || typeof content === "boolean") {
1247
+ return [];
1248
+ }
1249
+ return Array.isArray(content) ? content : [content];
1250
+ }
1251
+ function isElementLike(value) {
1252
+ return value != null && typeof value === "object" && "tag" in value;
1253
+ }
1254
+ function getMatchElement(value) {
1255
+ if (!isElementLike(value)) {
1256
+ return null;
1257
+ }
1258
+ if (isMatchElement(value)) {
1259
+ return value;
1260
+ }
1261
+ return value.tag === Match ? Match(value.props) : null;
1262
+ }
1263
+ function resolvePortalTarget(value) {
1264
+ const target = readReactive2(value);
1265
+ if (target == null) {
1266
+ return typeof document === "undefined" ? null : document.body;
1267
+ }
1268
+ if (typeof target === "string") {
1269
+ return document.querySelector(target);
1270
+ }
1271
+ if (typeof target === "function") {
1272
+ return target();
1273
+ }
1274
+ if (typeof target === "object" && "nodeType" in target) {
1275
+ return target;
1276
+ }
1277
+ return null;
1278
+ }
1279
+ function insertNode(parent, child, anchor) {
1280
+ if (anchor) {
1281
+ domOps.insertBefore(parent, child, anchor);
1282
+ } else {
1283
+ domOps.appendChild(parent, child);
1284
+ }
1285
+ }
1286
+
1287
+ // src/renderer/render-element.ts
1288
+ var VOID_ELEMENTS2 = new Set([
1289
+ "area",
1290
+ "base",
1291
+ "br",
1292
+ "col",
1293
+ "embed",
1294
+ "hr",
1295
+ "img",
1296
+ "input",
1297
+ "link",
1298
+ "meta",
1299
+ "param",
1300
+ "source",
1301
+ "track",
1302
+ "wbr"
1303
+ ]);
1304
+ var SVG_NS = "http://www.w3.org/2000/svg";
1305
+ var MATH_NS = "http://www.w3.org/1998/Math/MathML";
1306
+ function renderElementToDOM(element, parent, anchor = null, namespace = null) {
1307
+ const { tag, props, children } = element;
1308
+ if (tag === "" || tag === Fragment) {
1309
+ return renderFragmentToDOM(children, parent, anchor, namespace);
1310
+ }
1311
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1312
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1313
+ }
1314
+ if (tag === Visible) {
1315
+ return renderElementToDOM(tag(props), parent, anchor, namespace);
1316
+ }
1317
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element) || isPortalElement(element)) {
1318
+ return renderControlFlowToDOM(element, parent, anchor, namespace);
1319
+ }
1320
+ if (typeof tag === "function") {
1321
+ return renderComponentToDOM(tag, props, parent, anchor, namespace);
1322
+ }
1323
+ if (typeof tag === "string") {
1324
+ return renderIntrinsicToDOM(tag, props, children, parent, anchor, namespace);
1325
+ }
1326
+ return renderFragmentToDOM(children, parent, anchor, namespace);
1327
+ }
1328
+ function renderIntrinsicToDOM(tag, props, children, parent, anchor, parentNamespace) {
1329
+ const namespace = getElementNamespace(tag, parentNamespace);
1330
+ const el = namespace ? domOps.createElementNS(namespace, tag) : domOps.createElement(tag);
1331
+ const attrDisposers = applyAttributes(el, props);
1332
+ const eventCleanups = bindEvents(el, props);
1333
+ let mountedChildren = [];
1334
+ if (!VOID_ELEMENTS2.has(tag)) {
1335
+ const dangerous = props.dangerouslySetInnerHTML;
1336
+ if (dangerous && typeof dangerous.__html === "string") {
1337
+ el.innerHTML = dangerous.__html;
1338
+ } else {
1339
+ mountedChildren = renderChildrenToDOM(children, el, getChildNamespace(tag, namespace));
1340
+ }
1341
+ }
1342
+ if (anchor) {
1343
+ domOps.insertBefore(parent, el, anchor);
1344
+ } else {
1345
+ domOps.appendChild(parent, el);
1346
+ }
1347
+ const refCleanup = applyRef(el, props.ref);
1348
+ return {
1349
+ type: "element",
1350
+ node: el,
1351
+ children: mountedChildren,
1352
+ eventCleanups,
1353
+ attrDisposers,
1354
+ refCleanup
1355
+ };
1356
+ }
1357
+ function renderComponentToDOM(component, props, parent, anchor, namespace) {
1358
+ const parentInstance = getCurrentInstance();
1359
+ const instance = createComponentInstance(component, props, parentInstance);
1360
+ if (parentInstance) {
1361
+ parentInstance.children.push(instance);
1362
+ }
1363
+ const prevInstance = setCurrentInstance(instance);
1364
+ let result;
1365
+ let child;
1366
+ try {
1367
+ result = component(props);
1368
+ if (result && typeof result === "object" && "tag" in result) {
1369
+ child = renderElementToDOM(result, parent, anchor, namespace);
1370
+ } else {
1371
+ child = renderNodeToDOM(result, parent, anchor, namespace);
1372
+ }
1373
+ } catch (err) {
1374
+ setCurrentInstance(prevInstance);
1375
+ handleComponentError(instance, err);
1376
+ const text = domOps.createTextNode("");
1377
+ if (anchor) {
1378
+ domOps.insertBefore(parent, text, anchor);
1379
+ } else {
1380
+ domOps.appendChild(parent, text);
1381
+ }
1382
+ return {
1383
+ type: "component",
1384
+ children: [{ type: "text", node: text }],
1385
+ disposers: [],
1386
+ instance
1387
+ };
1388
+ }
1389
+ setCurrentInstance(prevInstance);
1390
+ instance.element = child;
1391
+ return {
1392
+ type: "component",
1393
+ children: [child],
1394
+ disposers: instance.effects,
1395
+ instance
1396
+ };
1397
+ }
1398
+ function renderFragmentToDOM(children, parent, anchor, namespace) {
1399
+ const anchorComment = domOps.createComment("Sinwan-f");
1400
+ if (anchor) {
1401
+ domOps.insertBefore(parent, anchorComment, anchor);
1402
+ } else {
1403
+ domOps.appendChild(parent, anchorComment);
1404
+ }
1405
+ const mounted = [];
1406
+ for (const child of children) {
1407
+ mounted.push(renderNodeToDOM(child, parent, anchor, namespace));
1408
+ }
1409
+ return { type: "fragment", children: mounted, anchor: anchorComment };
1410
+ }
1411
+ function getElementNamespace(tag, parentNamespace) {
1412
+ if (tag === "svg")
1413
+ return SVG_NS;
1414
+ if (tag === "math")
1415
+ return MATH_NS;
1416
+ return parentNamespace;
1417
+ }
1418
+ function getChildNamespace(tag, namespace) {
1419
+ if (namespace === SVG_NS && tag === "foreignObject") {
1420
+ return null;
1421
+ }
1422
+ return namespace;
1423
+ }
1424
+ function applyRef(el, ref) {
1425
+ const value = ref;
1426
+ if (!value) {
1427
+ return null;
1428
+ }
1429
+ if (typeof value === "function") {
1430
+ value(el);
1431
+ return () => value(null);
1432
+ }
1433
+ if (typeof value === "object" && "current" in value) {
1434
+ value.current = el;
1435
+ return () => {
1436
+ value.current = null;
1437
+ };
1438
+ }
1439
+ return null;
1440
+ }
1441
+
1442
+ // src/renderer/render-children.ts
1443
+ function renderNodeToDOM(node, parent, anchor = null, namespace = null) {
1444
+ if (node == null || typeof node === "boolean") {
1445
+ const text2 = domOps.createTextNode("");
1446
+ insertNode2(parent, text2, anchor);
1447
+ return { type: "text", node: text2 };
1448
+ }
1449
+ if (typeof node === "string") {
1450
+ const text2 = domOps.createTextNode(node);
1451
+ insertNode2(parent, text2, anchor);
1452
+ return { type: "text", node: text2 };
1453
+ }
1454
+ if (typeof node === "number") {
1455
+ const text2 = domOps.createTextNode(String(node));
1456
+ insertNode2(parent, text2, anchor);
1457
+ return { type: "text", node: text2 };
1458
+ }
1459
+ if (node instanceof HtmlEscapedString) {
1460
+ const text2 = domOps.createTextNode(node.value);
1461
+ insertNode2(parent, text2, anchor);
1462
+ return { type: "text", node: text2 };
1463
+ }
1464
+ if (isSignal(node) || isComputed(node)) {
1465
+ const text2 = domOps.createTextNode(String(node.value));
1466
+ insertNode2(parent, text2, anchor);
1467
+ const owner = getCurrentInstance();
1468
+ let initialized = false;
1469
+ const dispose = effect(() => {
1470
+ domOps.setTextContent(text2, String(node.value));
1471
+ if (initialized) {
1472
+ queueUpdatedHooks(owner);
1473
+ }
1474
+ initialized = true;
1475
+ });
1476
+ return { type: "reactive-text", node: text2, dispose };
1477
+ }
1478
+ if (Array.isArray(node)) {
1479
+ return renderArrayToDOM(node, parent, anchor, namespace);
1480
+ }
1481
+ if (node instanceof Promise) {
1482
+ const placeholder = domOps.createTextNode("");
1483
+ insertNode2(parent, placeholder, anchor);
1484
+ node.then((resolved) => {
1485
+ const mounted = renderNodeToDOM(resolved, parent, placeholder, namespace);
1486
+ domOps.remove(placeholder);
1487
+ });
1488
+ return { type: "text", node: placeholder };
1489
+ }
1490
+ if (typeof node === "object" && "tag" in node) {
1491
+ return renderElementToDOM(node, parent, anchor, namespace);
1492
+ }
1493
+ const text = domOps.createTextNode(String(node));
1494
+ insertNode2(parent, text, anchor);
1495
+ return { type: "text", node: text };
1496
+ }
1497
+ function renderArrayToDOM(nodes, parent, anchor, namespace) {
1498
+ const anchorComment = domOps.createComment("Sinwan-f");
1499
+ insertNode2(parent, anchorComment, anchor);
1500
+ const children = [];
1501
+ for (const child of nodes) {
1502
+ children.push(renderNodeToDOM(child, parent, anchor, namespace));
1503
+ }
1504
+ return { type: "fragment", children, anchor: anchorComment };
1505
+ }
1506
+ function renderChildrenToDOM(children, parent, namespace = null) {
1507
+ const mounted = [];
1508
+ for (const child of children) {
1509
+ mounted.push(renderNodeToDOM(child, parent, null, namespace));
1510
+ }
1511
+ return mounted;
1512
+ }
1513
+ function insertNode2(parent, child, anchor) {
1514
+ if (anchor) {
1515
+ domOps.insertBefore(parent, child, anchor);
1516
+ } else {
1517
+ domOps.appendChild(parent, child);
1518
+ }
1519
+ }
1520
+
1521
+ // src/renderer/mount.ts
1522
+ function mount(component, container, props) {
1523
+ container.innerHTML = "";
1524
+ const mergedProps = props ?? {};
1525
+ const instance = createComponentInstance(component, mergedProps, null);
1526
+ let result;
1527
+ let root;
1528
+ setCurrentInstance(instance);
1529
+ try {
1530
+ result = component(mergedProps);
1531
+ if (result instanceof Promise) {
1532
+ const placeholder = document.createTextNode("");
1533
+ container.appendChild(placeholder);
1534
+ root = { type: "text", node: placeholder };
1535
+ result.then((resolved) => {
1536
+ container.innerHTML = "";
1537
+ setCurrentInstance(instance);
1538
+ root = renderElementToDOM(resolved, container);
1539
+ setCurrentInstance(null);
1540
+ instance.element = root;
1541
+ fireMountedHooks(instance);
1542
+ });
1543
+ } else if (result && typeof result === "object" && "tag" in result) {
1544
+ root = renderElementToDOM(result, container);
1545
+ } else {
1546
+ root = renderNodeToDOM(result, container);
1547
+ }
1548
+ } catch (err) {
1549
+ setCurrentInstance(null);
1550
+ handleComponentError(instance, err);
1551
+ return {
1552
+ root: { type: "text", node: document.createTextNode("") },
1553
+ unmount() {}
1554
+ };
1555
+ }
1556
+ setCurrentInstance(null);
1557
+ instance.element = root;
1558
+ fireMountedHooks(instance);
1559
+ return {
1560
+ root,
1561
+ unmount() {
1562
+ fireUnmountedHooks(instance);
1563
+ unmountNode(root);
1564
+ container.innerHTML = "";
1565
+ }
1566
+ };
1567
+ }
1568
+ function render(node, container) {
1569
+ container.innerHTML = "";
1570
+ const root = renderNodeToDOM(node, container);
1571
+ return {
1572
+ root,
1573
+ unmount() {
1574
+ unmountNode(root);
1575
+ container.innerHTML = "";
1576
+ }
1577
+ };
1578
+ }
1579
+ // src/server/index.ts
1580
+ var exports_server = {};
1581
+ __export(exports_server, {
1582
+ streamPage: () => streamPage,
1583
+ streamHydratablePage: () => streamHydratablePage,
1584
+ streamHydratableNode: () => streamHydratableNode,
1585
+ renderToString: () => renderToString,
1586
+ renderToHydratableString: () => renderToHydratableString,
1587
+ renderPage: () => renderPage,
1588
+ renderNodeToHydratableString: () => renderNodeToHydratableString,
1589
+ registerPage: () => registerPage,
1590
+ isSlots: () => isSlots,
1591
+ hasPage: () => hasPage,
1592
+ getPage: () => getPage
1593
+ });
1594
+ module.exports = __toCommonJS(exports_server);
1595
+
1596
+ // src/escaper.ts
1597
+ var _bun = globalThis.Bun;
1598
+ var _nativeEscape = typeof _bun?.escapeHTML === "function" ? _bun.escapeHTML.bind(_bun) : undefined;
1599
+ var HTML_ESCAPE_RE = /[&<>"']/g;
1600
+ var HTML_ESCAPE_MAP = {
1601
+ "&": "&amp;",
1602
+ "<": "&lt;",
1603
+ ">": "&gt;",
1604
+ '"': "&quot;",
1605
+ "'": "&#39;"
1606
+ };
1607
+ function portableEscape(str) {
1608
+ HTML_ESCAPE_RE.lastIndex = 0;
1609
+ if (!HTML_ESCAPE_RE.test(str))
1610
+ return str;
1611
+ return str.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]);
1612
+ }
1613
+ function escapeHtml(value) {
1614
+ if (value == null || typeof value === "boolean")
1615
+ return "";
1616
+ if (typeof value === "number")
1617
+ return String(value);
1618
+ if (value instanceof HtmlEscapedString)
1619
+ return value.value;
1620
+ const s = String(value);
1621
+ return _nativeEscape ? _nativeEscape(s) : portableEscape(s);
1622
+ }
1623
+ function safeHtml(html) {
1624
+ return raw(html);
1625
+ }
1626
+ function isSafeHtml(value) {
1627
+ return value instanceof HtmlEscapedString;
1628
+ }
1629
+
1630
+ // src/server/attribute-utils.ts
1631
+ var PROP_ALIASES2 = {
1632
+ className: "class",
1633
+ htmlFor: "for",
1634
+ tabIndex: "tabindex",
1635
+ crossOrigin: "crossorigin"
1636
+ };
1637
+ function renderServerAttribute(key, value) {
1638
+ const attrName = PROP_ALIASES2[key] ?? key;
1639
+ if (value == null || value === false) {
1640
+ return "";
1641
+ }
1642
+ if (value === true) {
1643
+ return ` ${attrName}`;
1644
+ }
1645
+ const attrValue = attrName === "class" && typeof value === "object" ? stringifyClass(value) : attrName === "style" && typeof value === "object" ? stringifyStyle(value) : String(value);
1646
+ return ` ${attrName}="${escapeHtml(attrValue)}"`;
1647
+ }
1648
+ function stringifyClass(value) {
1649
+ if (Array.isArray(value)) {
1650
+ return value.filter(Boolean).join(" ");
1651
+ }
1652
+ return Object.entries(value).filter(([, enabled]) => Boolean(enabled)).map(([name]) => name).join(" ");
1653
+ }
1654
+ function stringifyStyle(value) {
1655
+ return Object.entries(value).filter(([, val]) => val != null && val !== false).map(([prop, val]) => `${toKebabCase(prop)}:${String(val)}`).join(";");
1656
+ }
1657
+ function toKebabCase(value) {
1658
+ return value.includes("-") ? value : value.replace(/[A-Z]/g, (char) => `-${char.toLowerCase()}`);
1659
+ }
1660
+
1661
+ // src/server/renderer.ts
1662
+ var componentCache = new WeakMap;
1663
+ var pageRegistry = new Map;
1664
+ function registerPage(name, page) {
1665
+ pageRegistry.set(name, page);
1666
+ }
1667
+ function getPage(name) {
1668
+ return pageRegistry.get(name);
1669
+ }
1670
+ function hasPage(name) {
1671
+ return pageRegistry.has(name);
1672
+ }
1673
+ async function renderPage(name, data) {
1674
+ const page = getPage(name);
1675
+ if (!page) {
1676
+ throw new Error(`Page "${name}" not found in registry`);
1677
+ }
1678
+ const element = await page(data);
1679
+ return renderToString(element);
1680
+ }
1681
+ async function renderToString(node) {
1682
+ if (node == null || typeof node === "boolean") {
1683
+ return "";
1684
+ }
1685
+ if (typeof node === "string") {
1686
+ return escapeHtml(node);
1687
+ }
1688
+ if (typeof node === "number") {
1689
+ return String(node);
1690
+ }
1691
+ if (node instanceof HtmlEscapedString) {
1692
+ return node.value;
1693
+ }
1694
+ if (isSignal(node) || isComputed(node)) {
1695
+ return escapeHtml(String(node.value));
1696
+ }
1697
+ if (Array.isArray(node)) {
1698
+ const results = await Promise.all(node.map((child) => renderToString(child)));
1699
+ return results.join("");
1700
+ }
1701
+ if (node instanceof Promise) {
1702
+ return renderElement(await node);
1703
+ }
1704
+ return renderElement(node);
1705
+ }
1706
+ async function renderElement(element) {
1707
+ const { tag, props, children } = element;
1708
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
1709
+ return renderElement(tag(props));
1710
+ }
1711
+ if (tag === Visible) {
1712
+ return renderElement(tag(props));
1713
+ }
1714
+ if (isShowElement(element)) {
1715
+ const when = readReactive3(props.when);
1716
+ return renderToString(when ? resolveShowChildren2(element, when) : props.fallback);
1717
+ }
1718
+ if (isForElement(element)) {
1719
+ return renderForElement(element);
1720
+ }
1721
+ if (isSwitchElement(element)) {
1722
+ return renderToString(resolveSwitchContent2(element));
1723
+ }
1724
+ if (isMatchElement(element)) {
1725
+ const when = readReactive3(props.when);
1726
+ return renderToString(when ? resolveMatchChildren2(element, when) : null);
1727
+ }
1728
+ if (isIndexElement(element)) {
1729
+ return renderIndexElement(element);
1730
+ }
1731
+ if (isKeyElement(element)) {
1732
+ const key = readReactive3(props.when);
1733
+ return renderToString(resolveKeyChildren2(element, key));
1734
+ }
1735
+ if (isDynamicElement(element)) {
1736
+ const tag2 = readReactive3(props.component);
1737
+ const dynamic = createDynamicElement2(element, tag2);
1738
+ return dynamic ? renderElement(dynamic) : "";
1739
+ }
1740
+ if (isPortalElement(element)) {
1741
+ return "";
1742
+ }
1743
+ if (typeof tag === "function") {
1744
+ const result = await tag(props);
1745
+ return renderToString(result);
1746
+ }
1747
+ if (typeof tag === "string") {
1748
+ return renderIntrinsicElement(tag, props, children);
1749
+ }
1750
+ return renderToString(children);
1751
+ }
1752
+ var VOID_ELEMENTS3 = new Set([
1753
+ "area",
1754
+ "base",
1755
+ "br",
1756
+ "col",
1757
+ "embed",
1758
+ "hr",
1759
+ "img",
1760
+ "input",
1761
+ "link",
1762
+ "meta",
1763
+ "param",
1764
+ "source",
1765
+ "track",
1766
+ "wbr"
1767
+ ]);
1768
+ async function renderIntrinsicElement(tag, props, children) {
1769
+ const attrs = renderAttributes(props);
1770
+ if (VOID_ELEMENTS3.has(tag)) {
1771
+ return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
1772
+ }
1773
+ const childrenHtml = await renderChildren(children, props);
1774
+ return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
1775
+ }
1776
+ function renderAttributes(props) {
1777
+ let attrs = "";
1778
+ for (const [key, value] of Object.entries(props)) {
1779
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
1780
+ continue;
1781
+ }
1782
+ const resolvedValue = readReactive3(value);
1783
+ if (resolvedValue == null || resolvedValue === false)
1784
+ continue;
1785
+ attrs += renderServerAttribute(key, resolvedValue);
1786
+ }
1787
+ return attrs;
1788
+ }
1789
+ async function renderChildren(children, props) {
1790
+ const dangerous = props.dangerouslySetInnerHTML;
1791
+ if (dangerous && typeof dangerous.__html === "string") {
1792
+ return dangerous.__html;
1793
+ }
1794
+ return renderToString(children);
1795
+ }
1796
+ function isSlots(children) {
1797
+ return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
1798
+ }
1799
+ async function renderForElement(element) {
1800
+ const props = element.props;
1801
+ const each = readReactive3(props.each);
1802
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1803
+ return props.fallback ? renderToString(props.fallback) : "";
1804
+ }
1805
+ if (each.length === 0) {
1806
+ return props.fallback ? renderToString(props.fallback) : "";
1807
+ }
1808
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
1809
+ return rendered.join("");
1810
+ }
1811
+ async function renderIndexElement(element) {
1812
+ const props = element.props;
1813
+ const each = readReactive3(props.each);
1814
+ if (!Array.isArray(each) || typeof props.children !== "function") {
1815
+ return props.fallback ? renderToString(props.fallback) : "";
1816
+ }
1817
+ if (each.length === 0) {
1818
+ return props.fallback ? renderToString(props.fallback) : "";
1819
+ }
1820
+ const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(() => item, index))));
1821
+ return rendered.join("");
1822
+ }
1823
+ function resolveSwitchContent2(element) {
1824
+ const props = element.props;
1825
+ const children = normalizeContent2(props.children ?? element.children);
1826
+ for (const child of children) {
1827
+ const match = getMatchElement2(child);
1828
+ if (!match) {
1829
+ continue;
1830
+ }
1831
+ const when = readReactive3(match.props.when);
1832
+ if (when) {
1833
+ return resolveMatchChildren2(match, when);
1834
+ }
1835
+ }
1836
+ return props.fallback;
1837
+ }
1838
+ function resolveMatchChildren2(element, value) {
1839
+ const children = element.props.children ?? element.children;
1840
+ if (typeof children === "function") {
1841
+ return children(value);
1842
+ }
1843
+ return children;
1844
+ }
1845
+ function resolveKeyChildren2(element, value) {
1846
+ const children = element.props.children ?? element.children;
1847
+ if (typeof children === "function") {
1848
+ return children(value);
1849
+ }
1850
+ return children;
1851
+ }
1852
+ function createDynamicElement2(element, tag) {
1853
+ if (typeof tag !== "string" && typeof tag !== "function") {
1854
+ return null;
1855
+ }
1856
+ const { component, ...props } = element.props;
1857
+ const children = normalizeContent2(props.children ?? element.children);
1858
+ return {
1859
+ tag,
1860
+ props,
1861
+ children
1862
+ };
1863
+ }
1864
+ function resolveShowChildren2(element, value) {
1865
+ const children = element.props.children ?? element.children;
1866
+ if (typeof children === "function") {
1867
+ return children(value);
1868
+ }
1869
+ return children;
1870
+ }
1871
+ function readReactive3(value) {
1872
+ return isSignal(value) || isComputed(value) ? value.value : value;
1873
+ }
1874
+ function normalizeContent2(content) {
1875
+ if (content == null || typeof content === "boolean") {
1876
+ return [];
1877
+ }
1878
+ return Array.isArray(content) ? content : [content];
1879
+ }
1880
+ function isElementLike2(value) {
1881
+ return value != null && typeof value === "object" && "tag" in value;
1882
+ }
1883
+ function getMatchElement2(value) {
1884
+ if (!isElementLike2(value)) {
1885
+ return null;
1886
+ }
1887
+ if (isMatchElement(value)) {
1888
+ return value;
1889
+ }
1890
+ return value.tag === Match ? Match(value.props) : null;
1891
+ }
1892
+ // src/hydration/markers.ts
1893
+ var COMP_ID_ATTR = "data-sinwan-id";
1894
+ var COMP_ID_PREFIX = "c";
1895
+ var TEXT_MARKER_OPEN = "sinwan-t:";
1896
+ var TEXT_MARKER_CLOSE = "/sinwan-t";
1897
+ var EVENT_ATTR = "data-sinwan-ev";
1898
+ function compId(index) {
1899
+ return `${COMP_ID_PREFIX}${index}`;
1900
+ }
1901
+ function textMarkerOpen(index) {
1902
+ return `<!--${TEXT_MARKER_OPEN}${index}-->`;
1903
+ }
1904
+ function textMarkerCloseStr() {
1905
+ return `<!--${TEXT_MARKER_CLOSE}-->`;
1906
+ }
1907
+ function parseTextOpenMarker(node) {
1908
+ const data = node.data;
1909
+ if (data.startsWith(TEXT_MARKER_OPEN)) {
1910
+ const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
1911
+ return Number.isNaN(idx) ? -1 : idx;
1912
+ }
1913
+ return -1;
1914
+ }
1915
+ function isTextCloseMarker(node) {
1916
+ return node.data === TEXT_MARKER_CLOSE;
1917
+ }
1918
+
1919
+ // src/server/stream.ts
1920
+ function createHydratableStreamContext() {
1921
+ return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
1922
+ }
1923
+ var VOID_ELEMENTS4 = new Set([
1924
+ "area",
1925
+ "base",
1926
+ "br",
1927
+ "col",
1928
+ "embed",
1929
+ "hr",
1930
+ "img",
1931
+ "input",
1932
+ "link",
1933
+ "meta",
1934
+ "param",
1935
+ "source",
1936
+ "track",
1937
+ "wbr"
1938
+ ]);
1939
+ function streamPage(page, data) {
1940
+ const encoder = new TextEncoder;
1941
+ return new ReadableStream({
1942
+ async start(controller) {
1943
+ try {
1944
+ const element = await page(data);
1945
+ await streamNode(element, controller, encoder);
1946
+ controller.close();
1947
+ } catch (error) {
1948
+ controller.error(error);
1949
+ }
1950
+ }
1951
+ });
1952
+ }
1953
+ function streamHydratablePage(component, props) {
1954
+ const encoder = new TextEncoder;
1955
+ const ctx = createHydratableStreamContext();
1956
+ return new ReadableStream({
1957
+ async start(controller) {
1958
+ try {
1959
+ await streamHydratableComponent(component, props ?? {}, controller, encoder, ctx, true);
1960
+ controller.close();
1961
+ } catch (error) {
1962
+ controller.error(error);
1963
+ }
1964
+ }
1965
+ });
1966
+ }
1967
+ function streamHydratableNode(node) {
1968
+ const encoder = new TextEncoder;
1969
+ const ctx = createHydratableStreamContext();
1970
+ return new ReadableStream({
1971
+ async start(controller) {
1972
+ try {
1973
+ await streamHydratableNodeToController(node, controller, encoder, ctx);
1974
+ controller.close();
1975
+ } catch (error) {
1976
+ controller.error(error);
1977
+ }
1978
+ }
1979
+ });
1980
+ }
1981
+ async function streamNode(node, controller, encoder) {
1982
+ if (node == null || typeof node === "boolean") {
1983
+ return;
1984
+ }
1985
+ if (typeof node === "string") {
1986
+ controller.enqueue(encoder.encode(escapeHtml(node)));
1987
+ return;
1988
+ }
1989
+ if (typeof node === "number") {
1990
+ controller.enqueue(encoder.encode(String(node)));
1991
+ return;
1992
+ }
1993
+ if (node instanceof HtmlEscapedString) {
1994
+ controller.enqueue(encoder.encode(node.value));
1995
+ return;
1996
+ }
1997
+ if (isSignal(node) || isComputed(node)) {
1998
+ controller.enqueue(encoder.encode(escapeHtml(String(node.value))));
1999
+ return;
2000
+ }
2001
+ if (Array.isArray(node)) {
2002
+ for (const child of node) {
2003
+ await streamNode(child, controller, encoder);
2004
+ }
2005
+ return;
2006
+ }
2007
+ if (node instanceof Promise) {
2008
+ const resolved = await node;
2009
+ await streamElement(resolved, controller, encoder);
2010
+ return;
997
2011
  }
998
- instance._unmountedHooks.push(fn);
2012
+ await streamElement(node, controller, encoder);
999
2013
  }
1000
- function onUpdated(fn) {
1001
- const instance = getCurrentInstance();
1002
- if (!instance) {
1003
- throw new Error("onUpdated() called outside of component setup.");
2014
+ async function streamElement(element, controller, encoder) {
2015
+ const { tag, props, children } = element;
2016
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2017
+ await streamElement(tag(props), controller, encoder);
2018
+ return;
2019
+ }
2020
+ if (tag === Visible) {
2021
+ await streamElement(tag(props), controller, encoder);
2022
+ return;
2023
+ }
2024
+ if (isShowElement(element)) {
2025
+ const when = readReactive4(props.when);
2026
+ await streamNode(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder);
2027
+ return;
2028
+ }
2029
+ if (isForElement(element)) {
2030
+ await streamForElement(element, controller, encoder);
2031
+ return;
2032
+ }
2033
+ if (isSwitchElement(element)) {
2034
+ await streamNode(resolveSwitchContent3(element), controller, encoder);
2035
+ return;
2036
+ }
2037
+ if (isMatchElement(element)) {
2038
+ const when = readReactive4(props.when);
2039
+ await streamNode(when ? resolveMatchChildren3(element, when) : null, controller, encoder);
2040
+ return;
2041
+ }
2042
+ if (isIndexElement(element)) {
2043
+ await streamIndexElement(element, controller, encoder);
2044
+ return;
1004
2045
  }
1005
- instance._updatedHooks.push(fn);
2046
+ if (isKeyElement(element)) {
2047
+ const key = readReactive4(props.when);
2048
+ await streamNode(resolveKeyChildren3(element, key), controller, encoder);
2049
+ return;
2050
+ }
2051
+ if (isDynamicElement(element)) {
2052
+ const dynamicTag = readReactive4(props.component);
2053
+ const dynamic = createDynamicElement3(element, dynamicTag);
2054
+ if (dynamic) {
2055
+ await streamElement(dynamic, controller, encoder);
2056
+ }
2057
+ return;
2058
+ }
2059
+ if (isPortalElement(element)) {
2060
+ return;
2061
+ }
2062
+ if (typeof tag === "function") {
2063
+ const result = await tag(props);
2064
+ await streamNode(result, controller, encoder);
2065
+ return;
2066
+ }
2067
+ if (typeof tag === "string") {
2068
+ await streamIntrinsicElement(tag, props, children, controller, encoder);
2069
+ return;
2070
+ }
2071
+ await streamNode(children, controller, encoder);
1006
2072
  }
1007
- function onError(fn) {
1008
- const instance = getCurrentInstance();
1009
- if (!instance) {
1010
- throw new Error("onError() called outside of component setup.");
2073
+ async function streamIntrinsicElement(tag, props, children, controller, encoder) {
2074
+ const attrs = renderAttributes2(props);
2075
+ const dangerous = props.dangerouslySetInnerHTML;
2076
+ if (VOID_ELEMENTS4.has(tag)) {
2077
+ const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
2078
+ controller.enqueue(encoder.encode(html));
2079
+ return;
2080
+ }
2081
+ const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
2082
+ controller.enqueue(encoder.encode(openTag));
2083
+ if (dangerous && typeof dangerous.__html === "string") {
2084
+ controller.enqueue(encoder.encode(dangerous.__html));
2085
+ } else {
2086
+ await streamNode(children, controller, encoder);
1011
2087
  }
1012
- instance._errorHooks.push(fn);
2088
+ controller.enqueue(encoder.encode(`</${tag}>`));
1013
2089
  }
1014
- // src/component/create.ts
1015
- function createComponent(fn) {
1016
- const component = (props) => fn(props);
1017
- component._SinwanComponent = true;
1018
- component._displayName = fn.name || "AnonymousComponent";
1019
- return component;
2090
+ function renderAttributes2(props) {
2091
+ let attrs = "";
2092
+ for (const [key, value] of Object.entries(props)) {
2093
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
2094
+ continue;
2095
+ }
2096
+ const resolvedValue = readReactive4(value);
2097
+ if (resolvedValue == null || resolvedValue === false)
2098
+ continue;
2099
+ attrs += renderServerAttribute(key, resolvedValue);
2100
+ }
2101
+ return attrs;
1020
2102
  }
1021
- function createPage(fn) {
1022
- const page = (data) => fn(data);
1023
- page._SinwanPage = true;
1024
- page._displayName = fn.name || "AnonymousPage";
1025
- return page;
2103
+ async function streamHydratableNodeToController(node, controller, encoder, ctx, isComponentRoot = false) {
2104
+ if (node == null || typeof node === "boolean") {
2105
+ return;
2106
+ }
2107
+ if (typeof node === "string") {
2108
+ enqueue(controller, encoder, escapeHtml(node));
2109
+ return;
2110
+ }
2111
+ if (typeof node === "number") {
2112
+ enqueue(controller, encoder, String(node));
2113
+ return;
2114
+ }
2115
+ if (node instanceof HtmlEscapedString) {
2116
+ enqueue(controller, encoder, node.value);
2117
+ return;
2118
+ }
2119
+ if (isSignal(node) || isComputed(node)) {
2120
+ const idx = ctx.textIndex++;
2121
+ enqueue(controller, encoder, `${textMarkerOpen(idx)}${escapeHtml(String(node.value))}${textMarkerCloseStr()}`);
2122
+ return;
2123
+ }
2124
+ if (Array.isArray(node)) {
2125
+ for (const child of node) {
2126
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
2127
+ }
2128
+ return;
2129
+ }
2130
+ if (node instanceof Promise) {
2131
+ await streamHydratableElement(await node, controller, encoder, ctx, isComponentRoot);
2132
+ return;
2133
+ }
2134
+ await streamHydratableElement(node, controller, encoder, ctx, isComponentRoot);
1026
2135
  }
1027
- function createLayout(fn) {
1028
- return createComponent(fn);
2136
+ async function streamHydratableElement(element, controller, encoder, ctx, isComponentRoot) {
2137
+ const { tag, props, children } = element;
2138
+ if (tag === "") {
2139
+ for (const child of children) {
2140
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
2141
+ }
2142
+ return;
2143
+ }
2144
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2145
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2146
+ return;
2147
+ }
2148
+ if (tag === Visible) {
2149
+ await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
2150
+ return;
2151
+ }
2152
+ if (isShowElement(element)) {
2153
+ const when = readReactive4(props.when);
2154
+ await streamHydratableNodeToController(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
2155
+ return;
2156
+ }
2157
+ if (isForElement(element)) {
2158
+ await streamHydratableForElement(element, controller, encoder, ctx);
2159
+ return;
2160
+ }
2161
+ if (isSwitchElement(element)) {
2162
+ await streamHydratableNodeToController(resolveSwitchContent3(element), controller, encoder, ctx, isComponentRoot);
2163
+ return;
2164
+ }
2165
+ if (isMatchElement(element)) {
2166
+ const when = readReactive4(props.when);
2167
+ await streamHydratableNodeToController(when ? resolveMatchChildren3(element, when) : null, controller, encoder, ctx, isComponentRoot);
2168
+ return;
2169
+ }
2170
+ if (isIndexElement(element)) {
2171
+ await streamHydratableIndexElement(element, controller, encoder, ctx);
2172
+ return;
2173
+ }
2174
+ if (isKeyElement(element)) {
2175
+ const key = readReactive4(props.when);
2176
+ await streamHydratableNodeToController(resolveKeyChildren3(element, key), controller, encoder, ctx, isComponentRoot);
2177
+ return;
2178
+ }
2179
+ if (isDynamicElement(element)) {
2180
+ const dynamicTag = readReactive4(props.component);
2181
+ const dynamic = createDynamicElement3(element, dynamicTag);
2182
+ if (dynamic) {
2183
+ await streamHydratableElement(dynamic, controller, encoder, ctx, isComponentRoot);
2184
+ }
2185
+ return;
2186
+ }
2187
+ if (isPortalElement(element)) {
2188
+ return;
2189
+ }
2190
+ if (typeof tag === "function") {
2191
+ await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
2192
+ return;
2193
+ }
2194
+ if (typeof tag === "string") {
2195
+ await streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot);
2196
+ return;
2197
+ }
2198
+ await streamHydratableNodeToController(children, controller, encoder, ctx);
1029
2199
  }
1030
- // src/component/provide-inject.ts
1031
- function provide(key, value) {
1032
- const instance = getCurrentInstance();
1033
- if (!instance) {
1034
- throw new Error("provide() called outside of component setup.");
2200
+ async function streamHydratableComponent(component, props, controller, encoder, ctx, isComponentRoot) {
2201
+ const parentInstance = getCurrentInstance();
2202
+ const instance = createComponentInstance(component, props, parentInstance);
2203
+ if (parentInstance) {
2204
+ parentInstance.children.push(instance);
2205
+ }
2206
+ const prev = setCurrentInstance(instance);
2207
+ try {
2208
+ const result = await component(props);
2209
+ await streamHydratableNodeToController(result, controller, encoder, ctx, isComponentRoot);
2210
+ } finally {
2211
+ setCurrentInstance(prev);
1035
2212
  }
1036
- instance.provides[key] = value;
1037
2213
  }
1038
- function inject(key, defaultValue) {
1039
- const instance = getCurrentInstance();
1040
- if (!instance) {
1041
- throw new Error("inject() called outside of component setup.");
2214
+ async function streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot) {
2215
+ const attrs = renderHydratableAttributes(props, ctx, isComponentRoot);
2216
+ const dangerous = props.dangerouslySetInnerHTML;
2217
+ enqueue(controller, encoder, attrs ? `<${tag}${attrs}>` : `<${tag}>`);
2218
+ if (VOID_ELEMENTS4.has(tag)) {
2219
+ return;
1042
2220
  }
1043
- if (key in instance.provides) {
1044
- return instance.provides[key];
2221
+ if (dangerous && typeof dangerous.__html === "string") {
2222
+ enqueue(controller, encoder, dangerous.__html);
2223
+ } else {
2224
+ for (const child of children) {
2225
+ await streamHydratableNodeToController(child, controller, encoder, ctx);
2226
+ }
1045
2227
  }
1046
- if (arguments.length >= 2) {
1047
- return defaultValue;
2228
+ enqueue(controller, encoder, `</${tag}>`);
2229
+ }
2230
+ async function streamHydratableForElement(element, controller, encoder, ctx) {
2231
+ const props = element.props;
2232
+ const each = readReactive4(props.each);
2233
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2234
+ if (props.fallback) {
2235
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2236
+ }
2237
+ return;
2238
+ }
2239
+ if (each.length === 0) {
2240
+ if (props.fallback) {
2241
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2242
+ }
2243
+ return;
2244
+ }
2245
+ for (let index = 0;index < each.length; index++) {
2246
+ await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
1048
2247
  }
1049
- console.warn(`[Sinwan] inject() key "${String(key)}" not found and no default provided.`);
1050
- return;
1051
2248
  }
1052
- // src/renderer/attributes.ts
1053
- var SKIP_PROPS = new Set(["children", "key", "ref", "dangerouslySetInnerHTML"]);
1054
- var DOM_PROPERTIES = new Set(["value", "checked", "selected", "disabled", "readOnly", "multiple", "indeterminate"]);
1055
- var PROP_ALIASES = {
1056
- className: "class",
1057
- htmlFor: "for",
1058
- tabIndex: "tabindex",
1059
- crossOrigin: "crossorigin"
1060
- };
1061
- function applyAttributes(el, props) {
1062
- const disposers = [];
2249
+ async function streamHydratableIndexElement(element, controller, encoder, ctx) {
2250
+ const props = element.props;
2251
+ const each = readReactive4(props.each);
2252
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2253
+ if (props.fallback) {
2254
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2255
+ }
2256
+ return;
2257
+ }
2258
+ if (each.length === 0) {
2259
+ if (props.fallback) {
2260
+ await streamHydratableNodeToController(props.fallback, controller, encoder, ctx);
2261
+ }
2262
+ return;
2263
+ }
2264
+ for (let index = 0;index < each.length; index++) {
2265
+ await streamHydratableNodeToController(props.children(() => each[index], index), controller, encoder, ctx);
2266
+ }
2267
+ }
2268
+ function renderHydratableAttributes(props, ctx, isComponentRoot) {
2269
+ let attrs = "";
2270
+ if (isComponentRoot) {
2271
+ attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
2272
+ }
2273
+ const eventParts = [];
1063
2274
  for (const [key, value] of Object.entries(props)) {
1064
- if (SKIP_PROPS.has(key) || isEventProp(key))
2275
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
2276
+ continue;
2277
+ }
2278
+ if (isEventProp(key)) {
2279
+ eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
1065
2280
  continue;
1066
- if (isSignal(value) || isComputed(value)) {
1067
- const dispose = effect(() => {
1068
- setSingleAttribute(el, key, value.value);
1069
- });
1070
- disposers.push(dispose);
1071
- } else {
1072
- setSingleAttribute(el, key, value);
1073
2281
  }
2282
+ const resolvedValue = readReactive4(value);
2283
+ if (resolvedValue == null || resolvedValue === false)
2284
+ continue;
2285
+ attrs += renderServerAttribute(key, resolvedValue);
1074
2286
  }
1075
- return disposers;
2287
+ if (eventParts.length > 0) {
2288
+ attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
2289
+ }
2290
+ return attrs;
1076
2291
  }
1077
- function setSingleAttribute(el, key, value) {
1078
- const attrName = PROP_ALIASES[key] ?? key;
1079
- if (attrName === "style" && typeof value === "object" && value !== null) {
1080
- applyStyle(el, value);
2292
+ function enqueue(controller, encoder, html) {
2293
+ controller.enqueue(encoder.encode(html));
2294
+ }
2295
+ async function streamForElement(element, controller, encoder) {
2296
+ const props = element.props;
2297
+ const each = readReactive4(props.each);
2298
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2299
+ if (props.fallback) {
2300
+ await streamNode(props.fallback, controller, encoder);
2301
+ }
1081
2302
  return;
1082
2303
  }
1083
- if (attrName === "class" && typeof value === "object" && value !== null) {
1084
- applyClass(el, value);
2304
+ if (each.length === 0) {
2305
+ if (props.fallback) {
2306
+ await streamNode(props.fallback, controller, encoder);
2307
+ }
1085
2308
  return;
1086
2309
  }
1087
- if (value == null || value === false) {
1088
- domOps.removeAttribute(el, attrName);
1089
- if (DOM_PROPERTIES.has(attrName)) {
1090
- domOps.setProperty(el, attrName, attrName === "value" ? "" : false);
2310
+ for (let index = 0;index < each.length; index++) {
2311
+ await streamNode(props.children(each[index], () => index), controller, encoder);
2312
+ }
2313
+ }
2314
+ async function streamIndexElement(element, controller, encoder) {
2315
+ const props = element.props;
2316
+ const each = readReactive4(props.each);
2317
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2318
+ if (props.fallback) {
2319
+ await streamNode(props.fallback, controller, encoder);
1091
2320
  }
1092
2321
  return;
1093
2322
  }
1094
- if (value === true) {
1095
- domOps.setAttribute(el, attrName, "");
1096
- if (DOM_PROPERTIES.has(attrName)) {
1097
- domOps.setProperty(el, attrName, true);
2323
+ if (each.length === 0) {
2324
+ if (props.fallback) {
2325
+ await streamNode(props.fallback, controller, encoder);
1098
2326
  }
1099
2327
  return;
1100
2328
  }
1101
- if (DOM_PROPERTIES.has(attrName)) {
1102
- domOps.setProperty(el, attrName, value);
1103
- return;
2329
+ for (let index = 0;index < each.length; index++) {
2330
+ await streamNode(props.children(() => each[index], index), controller, encoder);
1104
2331
  }
1105
- domOps.setAttribute(el, attrName, String(value));
1106
2332
  }
1107
- function applyStyle(el, styles) {
1108
- for (const [prop, val] of Object.entries(styles)) {
1109
- if (prop.includes("-")) {
1110
- el.style.setProperty(prop, val);
1111
- } else {
1112
- el.style[prop] = val;
2333
+ function resolveShowChildren3(element, value) {
2334
+ const children = element.props.children ?? element.children;
2335
+ if (typeof children === "function") {
2336
+ return children(value);
2337
+ }
2338
+ return children;
2339
+ }
2340
+ function resolveSwitchContent3(element) {
2341
+ const props = element.props;
2342
+ const children = normalizeContent3(props.children ?? element.children);
2343
+ for (const child of children) {
2344
+ const match = getMatchElement3(child);
2345
+ if (!match) {
2346
+ continue;
2347
+ }
2348
+ const when = readReactive4(match.props.when);
2349
+ if (when) {
2350
+ return resolveMatchChildren3(match, when);
1113
2351
  }
1114
2352
  }
2353
+ return props.fallback;
1115
2354
  }
1116
- function applyClass(el, value) {
1117
- let classStr;
1118
- if (Array.isArray(value)) {
1119
- classStr = value.filter(Boolean).join(" ");
1120
- } else if (typeof value === "object" && value !== null) {
1121
- classStr = Object.entries(value).filter(([, v]) => Boolean(v)).map(([k]) => k).join(" ");
1122
- } else {
1123
- classStr = String(value);
2355
+ function resolveMatchChildren3(element, value) {
2356
+ const children = element.props.children ?? element.children;
2357
+ if (typeof children === "function") {
2358
+ return children(value);
1124
2359
  }
1125
- domOps.setAttribute(el, "class", classStr);
2360
+ return children;
2361
+ }
2362
+ function resolveKeyChildren3(element, value) {
2363
+ const children = element.props.children ?? element.children;
2364
+ if (typeof children === "function") {
2365
+ return children(value);
2366
+ }
2367
+ return children;
2368
+ }
2369
+ function createDynamicElement3(element, tag) {
2370
+ if (typeof tag !== "string" && typeof tag !== "function") {
2371
+ return null;
2372
+ }
2373
+ const { component, ...props } = element.props;
2374
+ const children = normalizeContent3(props.children ?? element.children);
2375
+ return {
2376
+ tag,
2377
+ props,
2378
+ children
2379
+ };
2380
+ }
2381
+ function readReactive4(value) {
2382
+ return isSignal(value) || isComputed(value) ? value.value : value;
2383
+ }
2384
+ function normalizeContent3(content) {
2385
+ if (content == null || typeof content === "boolean") {
2386
+ return [];
2387
+ }
2388
+ return Array.isArray(content) ? content : [content];
2389
+ }
2390
+ function isElementLike3(value) {
2391
+ return value != null && typeof value === "object" && "tag" in value;
2392
+ }
2393
+ function getMatchElement3(value) {
2394
+ if (!isElementLike3(value)) {
2395
+ return null;
2396
+ }
2397
+ if (isMatchElement(value)) {
2398
+ return value;
2399
+ }
2400
+ return value.tag === Match ? Match(value.props) : null;
2401
+ }
2402
+ // src/server/hydration-markers.ts
2403
+ function createHydrationContext() {
2404
+ return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
2405
+ }
2406
+ async function renderToHydratableString(component, props) {
2407
+ const ctx = createHydrationContext();
2408
+ const mergedProps = props ?? {};
2409
+ const instance = createComponentInstance(component, mergedProps, null);
2410
+ const prev = setCurrentInstance(instance);
2411
+ try {
2412
+ const result = await component(mergedProps);
2413
+ if (result && typeof result === "object" && "tag" in result) {
2414
+ return renderElementH(result, ctx, true);
2415
+ }
2416
+ return renderNodeH(result, ctx);
2417
+ } finally {
2418
+ setCurrentInstance(prev);
2419
+ }
2420
+ }
2421
+ async function renderNodeToHydratableString(node) {
2422
+ const ctx = createHydrationContext();
2423
+ return renderNodeH(node, ctx);
1126
2424
  }
1127
-
1128
- // src/renderer/render-element.ts
1129
2425
  var VOID_ELEMENTS5 = new Set([
1130
2426
  "area",
1131
2427
  "base",
@@ -1142,273 +2438,355 @@ var VOID_ELEMENTS5 = new Set([
1142
2438
  "track",
1143
2439
  "wbr"
1144
2440
  ]);
1145
- function renderElementToDOM(element, parent, anchor = null) {
1146
- const { tag, props, children } = element;
1147
- if (tag === "" || tag === Fragment) {
1148
- return renderFragmentToDOM(children, parent, anchor);
2441
+ function renderNodeH(node, ctx) {
2442
+ if (node == null || typeof node === "boolean")
2443
+ return "";
2444
+ if (typeof node === "string")
2445
+ return escapeHtml(node);
2446
+ if (typeof node === "number")
2447
+ return String(node);
2448
+ if (node instanceof HtmlEscapedString)
2449
+ return node.value;
2450
+ if (isSignal(node) || isComputed(node)) {
2451
+ const value = node.value;
2452
+ const idx = ctx.textIndex++;
2453
+ return `${textMarkerOpen(idx)}${escapeHtml(String(value))}${textMarkerCloseStr()}`;
1149
2454
  }
1150
- if (typeof tag === "function") {
1151
- return renderComponentToDOM(tag, props, parent, anchor);
2455
+ if (Array.isArray(node)) {
2456
+ return node.map((child) => renderNodeH(child, ctx)).join("");
1152
2457
  }
1153
- if (typeof tag === "string") {
1154
- return renderIntrinsicToDOM(tag, props, children, parent, anchor);
2458
+ if (node instanceof Promise) {
2459
+ return "";
2460
+ }
2461
+ if (typeof node === "object" && "tag" in node) {
2462
+ return renderElementH(node, ctx, false);
1155
2463
  }
1156
- return renderFragmentToDOM(children, parent, anchor);
2464
+ return escapeHtml(String(node));
1157
2465
  }
1158
- function renderIntrinsicToDOM(tag, props, children, parent, anchor) {
1159
- const el = domOps.createElement(tag);
1160
- const attrDisposers = applyAttributes(el, props);
1161
- const eventCleanups = bindEvents(el, props);
1162
- let mountedChildren = [];
1163
- if (!VOID_ELEMENTS5.has(tag)) {
1164
- const dangerous = props.dangerouslySetInnerHTML;
1165
- if (dangerous && typeof dangerous.__html === "string") {
1166
- el.innerHTML = dangerous.__html;
1167
- } else {
1168
- mountedChildren = renderChildrenToDOM(children, el);
1169
- }
2466
+ function renderElementH(element, ctx, isComponentRoot) {
2467
+ const { tag, props, children } = element;
2468
+ if (tag === "") {
2469
+ return children.map((child) => renderNodeH(child, ctx)).join("");
1170
2470
  }
1171
- if (anchor) {
1172
- domOps.insertBefore(parent, el, anchor);
1173
- } else {
1174
- domOps.appendChild(parent, el);
2471
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2472
+ return renderElementH(tag(props), ctx, isComponentRoot);
1175
2473
  }
1176
- return {
1177
- type: "element",
1178
- node: el,
1179
- children: mountedChildren,
1180
- eventCleanups,
1181
- attrDisposers
1182
- };
2474
+ if (tag === Visible) {
2475
+ return renderElementH(tag(props), ctx, isComponentRoot);
2476
+ }
2477
+ if (isShowElement(element)) {
2478
+ const when = readReactive5(props.when);
2479
+ const content = when ? resolveShowChildren4(element, when) : props.fallback;
2480
+ return renderNodeMaybeRoot(content, ctx, isComponentRoot);
2481
+ }
2482
+ if (isForElement(element)) {
2483
+ return renderForElementH(element, ctx);
2484
+ }
2485
+ if (isSwitchElement(element)) {
2486
+ return renderNodeMaybeRoot(resolveSwitchContent4(element), ctx, isComponentRoot);
2487
+ }
2488
+ if (isMatchElement(element)) {
2489
+ const when = readReactive5(props.when);
2490
+ return renderNodeMaybeRoot(when ? resolveMatchChildren4(element, when) : null, ctx, isComponentRoot);
2491
+ }
2492
+ if (isIndexElement(element)) {
2493
+ return renderIndexElementH(element, ctx);
2494
+ }
2495
+ if (isKeyElement(element)) {
2496
+ const key = readReactive5(props.when);
2497
+ return renderNodeMaybeRoot(resolveKeyChildren4(element, key), ctx, isComponentRoot);
2498
+ }
2499
+ if (isDynamicElement(element)) {
2500
+ const dynamicTag = readReactive5(props.component);
2501
+ const dynamic = createDynamicElement4(element, dynamicTag);
2502
+ return dynamic ? renderElementH(dynamic, ctx, isComponentRoot) : "";
2503
+ }
2504
+ if (isPortalElement(element)) {
2505
+ return "";
2506
+ }
2507
+ if (typeof tag === "function") {
2508
+ return renderComponentH(tag, props, ctx);
2509
+ }
2510
+ if (typeof tag === "string") {
2511
+ return renderIntrinsicH(tag, props, children, ctx, isComponentRoot);
2512
+ }
2513
+ return children.map((child) => renderNodeH(child, ctx)).join("");
1183
2514
  }
1184
- function renderComponentToDOM(component, props, parent, anchor) {
2515
+ function renderComponentH(component, props, ctx) {
1185
2516
  const parentInstance = getCurrentInstance();
1186
2517
  const instance = createComponentInstance(component, props, parentInstance);
1187
2518
  if (parentInstance) {
1188
2519
  parentInstance.children.push(instance);
1189
2520
  }
1190
- const prevInstance = setCurrentInstance(instance);
1191
- let result;
1192
- let child;
2521
+ const prev = setCurrentInstance(instance);
1193
2522
  try {
1194
- result = component(props);
2523
+ const result = component(props);
1195
2524
  if (result && typeof result === "object" && "tag" in result) {
1196
- child = renderElementToDOM(result, parent, anchor);
1197
- } else {
1198
- child = renderNodeToDOM(result, parent, anchor);
2525
+ return renderElementH(result, ctx, true);
1199
2526
  }
1200
- } catch (err) {
1201
- setCurrentInstance(prevInstance);
1202
- handleComponentError(instance, err);
1203
- const text = domOps.createTextNode("");
1204
- if (anchor) {
1205
- domOps.insertBefore(parent, text, anchor);
1206
- } else {
1207
- domOps.appendChild(parent, text);
2527
+ return renderNodeH(result, ctx);
2528
+ } finally {
2529
+ setCurrentInstance(prev);
2530
+ }
2531
+ }
2532
+ function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
2533
+ let attrs = "";
2534
+ if (isComponentRoot) {
2535
+ attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
2536
+ }
2537
+ const eventParts = [];
2538
+ for (const [key, value] of Object.entries(props)) {
2539
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
2540
+ continue;
1208
2541
  }
1209
- return {
1210
- type: "component",
1211
- children: [{ type: "text", node: text }],
1212
- disposers: [],
1213
- instance
1214
- };
2542
+ if (isEventProp(key)) {
2543
+ const eventName = toEventName(key);
2544
+ eventParts.push(`${eventName}:${ctx.eventIndex++}`);
2545
+ continue;
2546
+ }
2547
+ if (value == null || value === false)
2548
+ continue;
2549
+ let resolvedValue = value;
2550
+ if (isSignal(value) || isComputed(value)) {
2551
+ resolvedValue = value.value;
2552
+ }
2553
+ attrs += renderServerAttribute(key, resolvedValue);
1215
2554
  }
1216
- setCurrentInstance(prevInstance);
1217
- instance.element = child;
1218
- return {
1219
- type: "component",
1220
- children: [child],
1221
- disposers: instance.effects,
1222
- instance
1223
- };
2555
+ if (eventParts.length > 0) {
2556
+ attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
2557
+ }
2558
+ if (VOID_ELEMENTS5.has(tag)) {
2559
+ return `<${tag}${attrs}>`;
2560
+ }
2561
+ const dangerous = props.dangerouslySetInnerHTML;
2562
+ if (dangerous && typeof dangerous.__html === "string") {
2563
+ return `<${tag}${attrs}>${dangerous.__html}</${tag}>`;
2564
+ }
2565
+ const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
2566
+ return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
1224
2567
  }
1225
- function renderFragmentToDOM(children, parent, anchor) {
1226
- const anchorComment = domOps.createComment("Sinwan-f");
1227
- if (anchor) {
1228
- domOps.insertBefore(parent, anchorComment, anchor);
1229
- } else {
1230
- domOps.appendChild(parent, anchorComment);
2568
+ function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
2569
+ if (isComponentRoot && node && typeof node === "object" && !Array.isArray(node) && "tag" in node) {
2570
+ return renderElementH(node, ctx, true);
1231
2571
  }
1232
- const mounted = [];
1233
- for (const child of children) {
1234
- mounted.push(renderNodeToDOM(child, parent, anchor));
2572
+ return renderNodeH(node, ctx);
2573
+ }
2574
+ function renderForElementH(element, ctx) {
2575
+ const props = element.props;
2576
+ const each = readReactive5(props.each);
2577
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2578
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1235
2579
  }
1236
- return { type: "fragment", children: mounted, anchor: anchorComment };
2580
+ if (each.length === 0) {
2581
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
2582
+ }
2583
+ return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
1237
2584
  }
1238
-
1239
- // src/renderer/render-children.ts
1240
- function renderNodeToDOM(node, parent, anchor = null) {
1241
- if (node == null || typeof node === "boolean") {
1242
- const text2 = domOps.createTextNode("");
1243
- insertNode(parent, text2, anchor);
1244
- return { type: "text", node: text2 };
2585
+ function renderIndexElementH(element, ctx) {
2586
+ const props = element.props;
2587
+ const each = readReactive5(props.each);
2588
+ if (!Array.isArray(each) || typeof props.children !== "function") {
2589
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1245
2590
  }
1246
- if (typeof node === "string") {
1247
- const text2 = domOps.createTextNode(node);
1248
- insertNode(parent, text2, anchor);
1249
- return { type: "text", node: text2 };
2591
+ if (each.length === 0) {
2592
+ return props.fallback ? renderNodeH(props.fallback, ctx) : "";
1250
2593
  }
1251
- if (typeof node === "number") {
1252
- const text2 = domOps.createTextNode(String(node));
1253
- insertNode(parent, text2, anchor);
1254
- return { type: "text", node: text2 };
2594
+ return each.map((item, index) => renderNodeH(props.children(() => item, index), ctx)).join("");
2595
+ }
2596
+ function resolveShowChildren4(element, value) {
2597
+ const children = element.props.children ?? element.children;
2598
+ if (typeof children === "function") {
2599
+ return children(value);
1255
2600
  }
1256
- if (node instanceof HtmlEscapedString) {
1257
- const text2 = domOps.createTextNode(node.value);
1258
- insertNode(parent, text2, anchor);
1259
- return { type: "text", node: text2 };
2601
+ return children;
2602
+ }
2603
+ function resolveSwitchContent4(element) {
2604
+ const props = element.props;
2605
+ const children = normalizeContent4(props.children ?? element.children);
2606
+ for (const child of children) {
2607
+ const match = getMatchElement4(child);
2608
+ if (!match) {
2609
+ continue;
2610
+ }
2611
+ const when = readReactive5(match.props.when);
2612
+ if (when) {
2613
+ return resolveMatchChildren4(match, when);
2614
+ }
1260
2615
  }
1261
- if (isSignal(node) || isComputed(node)) {
1262
- const text2 = domOps.createTextNode(String(node.value));
1263
- insertNode(parent, text2, anchor);
1264
- const dispose = effect(() => {
1265
- domOps.setTextContent(text2, String(node.value));
1266
- });
1267
- return { type: "reactive-text", node: text2, dispose };
2616
+ return props.fallback;
2617
+ }
2618
+ function resolveMatchChildren4(element, value) {
2619
+ const children = element.props.children ?? element.children;
2620
+ if (typeof children === "function") {
2621
+ return children(value);
1268
2622
  }
1269
- if (Array.isArray(node)) {
1270
- return renderArrayToDOM(node, parent, anchor);
2623
+ return children;
2624
+ }
2625
+ function resolveKeyChildren4(element, value) {
2626
+ const children = element.props.children ?? element.children;
2627
+ if (typeof children === "function") {
2628
+ return children(value);
1271
2629
  }
1272
- if (node instanceof Promise) {
1273
- const placeholder = domOps.createTextNode("");
1274
- insertNode(parent, placeholder, anchor);
1275
- node.then((resolved) => {
1276
- const mounted = renderNodeToDOM(resolved, parent, placeholder);
1277
- domOps.remove(placeholder);
1278
- });
1279
- return { type: "text", node: placeholder };
2630
+ return children;
2631
+ }
2632
+ function createDynamicElement4(element, tag) {
2633
+ if (typeof tag !== "string" && typeof tag !== "function") {
2634
+ return null;
1280
2635
  }
1281
- if (typeof node === "object" && "tag" in node) {
1282
- return renderElementToDOM(node, parent, anchor);
2636
+ const { component, ...props } = element.props;
2637
+ const children = normalizeContent4(props.children ?? element.children);
2638
+ return {
2639
+ tag,
2640
+ props,
2641
+ children
2642
+ };
2643
+ }
2644
+ function readReactive5(value) {
2645
+ return isSignal(value) || isComputed(value) ? value.value : value;
2646
+ }
2647
+ function normalizeContent4(content) {
2648
+ if (content == null || typeof content === "boolean") {
2649
+ return [];
2650
+ }
2651
+ return Array.isArray(content) ? content : [content];
2652
+ }
2653
+ function isElementLike4(value) {
2654
+ return value != null && typeof value === "object" && "tag" in value;
2655
+ }
2656
+ function getMatchElement4(value) {
2657
+ if (!isElementLike4(value)) {
2658
+ return null;
2659
+ }
2660
+ if (isMatchElement(value)) {
2661
+ return value;
1283
2662
  }
1284
- const text = domOps.createTextNode(String(node));
1285
- insertNode(parent, text, anchor);
1286
- return { type: "text", node: text };
2663
+ return value.tag === Match ? Match(value.props) : null;
1287
2664
  }
1288
- function renderArrayToDOM(nodes, parent, anchor) {
1289
- const anchorComment = domOps.createComment("Sinwan-f");
1290
- insertNode(parent, anchorComment, anchor);
1291
- const children = [];
1292
- for (const child of nodes) {
1293
- children.push(renderNodeToDOM(child, parent, anchor));
2665
+ // src/index.ts
2666
+ var exports_src = {};
2667
+ __export(exports_src, {
2668
+ unmountNode: () => unmountNode,
2669
+ streamPage: () => streamPage,
2670
+ streamHydratablePage: () => streamHydratablePage,
2671
+ streamHydratableNode: () => streamHydratableNode,
2672
+ signal: () => signal,
2673
+ setDOMOps: () => setDOMOps,
2674
+ safeHtml: () => safeHtml,
2675
+ resetDOMOps: () => resetDOMOps,
2676
+ renderToString: () => renderToString,
2677
+ renderToHydratableString: () => renderToHydratableString,
2678
+ renderPage: () => renderPage,
2679
+ renderNodeToHydratableString: () => renderNodeToHydratableString,
2680
+ renderNodeToDOM: () => renderNodeToDOM,
2681
+ renderElementToDOM: () => renderElementToDOM,
2682
+ render: () => render,
2683
+ registerPage: () => registerPage,
2684
+ raw: () => raw,
2685
+ provide: () => provide,
2686
+ onUpdated: () => onUpdated,
2687
+ onUnmounted: () => onUnmounted,
2688
+ onMounted: () => onMounted,
2689
+ onError: () => onError,
2690
+ nextTick: () => nextTick,
2691
+ mount: () => mount,
2692
+ jsxs: () => jsxs,
2693
+ jsxDEV: () => jsxDEV,
2694
+ jsx: () => jsx,
2695
+ isSignal: () => isSignal,
2696
+ isSafeHtml: () => isSafeHtml,
2697
+ isComputed: () => isComputed,
2698
+ inject: () => inject,
2699
+ hydrate: () => hydrate,
2700
+ hasPage: () => hasPage,
2701
+ getPage: () => getPage,
2702
+ getCurrentInstance: () => getCurrentInstance,
2703
+ escapeHtml: () => escapeHtml,
2704
+ effect: () => effect,
2705
+ domOps: () => domOps,
2706
+ createPage: () => createPage,
2707
+ createLayout: () => createLayout,
2708
+ createComponent: () => createComponent,
2709
+ computed: () => computed,
2710
+ batch: () => batch,
2711
+ Visible: () => Visible,
2712
+ Switch: () => Switch,
2713
+ Show: () => Show,
2714
+ Portal: () => Portal,
2715
+ Match: () => Match,
2716
+ Key: () => Key,
2717
+ Index: () => Index,
2718
+ HtmlEscapedString: () => HtmlEscapedString,
2719
+ Fragment: () => Fragment,
2720
+ For: () => For,
2721
+ Dynamic: () => Dynamic
2722
+ });
2723
+ module.exports = __toCommonJS(exports_src);
2724
+ // src/component/lifecycle.ts
2725
+ function onMounted(fn) {
2726
+ const instance = getCurrentInstance();
2727
+ if (!instance) {
2728
+ throw new Error("onMounted() called outside of component setup.");
1294
2729
  }
1295
- return { type: "fragment", children, anchor: anchorComment };
2730
+ instance._mountedHooks.push(() => withInstance(instance, fn));
1296
2731
  }
1297
- function renderChildrenToDOM(children, parent) {
1298
- const mounted = [];
1299
- for (const child of children) {
1300
- mounted.push(renderNodeToDOM(child, parent));
2732
+ function onUnmounted(fn) {
2733
+ const instance = getCurrentInstance();
2734
+ if (!instance) {
2735
+ throw new Error("onUnmounted() called outside of component setup.");
1301
2736
  }
1302
- return mounted;
2737
+ instance._unmountedHooks.push(() => withInstance(instance, fn));
1303
2738
  }
1304
- function insertNode(parent, child, anchor) {
1305
- if (anchor) {
1306
- domOps.insertBefore(parent, child, anchor);
1307
- } else {
1308
- domOps.appendChild(parent, child);
2739
+ function onUpdated(fn) {
2740
+ const instance = getCurrentInstance();
2741
+ if (!instance) {
2742
+ throw new Error("onUpdated() called outside of component setup.");
1309
2743
  }
2744
+ instance._updatedHooks.push(() => withInstance(instance, fn));
1310
2745
  }
1311
-
1312
- // src/renderer/mount.ts
1313
- function mount(component, container, props) {
1314
- container.innerHTML = "";
1315
- const mergedProps = props ?? {};
1316
- const instance = createComponentInstance(component, mergedProps, null);
1317
- let result;
1318
- let root;
1319
- setCurrentInstance(instance);
1320
- try {
1321
- result = component(mergedProps);
1322
- if (result instanceof Promise) {
1323
- const placeholder = document.createTextNode("");
1324
- container.appendChild(placeholder);
1325
- root = { type: "text", node: placeholder };
1326
- result.then((resolved) => {
1327
- container.innerHTML = "";
1328
- setCurrentInstance(instance);
1329
- root = renderElementToDOM(resolved, container);
1330
- setCurrentInstance(null);
1331
- instance.element = root;
1332
- fireMountedHooks(instance);
1333
- });
1334
- } else if (result && typeof result === "object" && "tag" in result) {
1335
- root = renderElementToDOM(result, container);
1336
- } else {
1337
- root = renderNodeToDOM(result, container);
1338
- }
1339
- } catch (err) {
1340
- setCurrentInstance(null);
1341
- handleComponentError(instance, err);
1342
- return {
1343
- root: { type: "text", node: document.createTextNode("") },
1344
- unmount() {}
1345
- };
2746
+ function onError(fn) {
2747
+ const instance = getCurrentInstance();
2748
+ if (!instance) {
2749
+ throw new Error("onError() called outside of component setup.");
1346
2750
  }
1347
- setCurrentInstance(null);
1348
- instance.element = root;
1349
- fireMountedHooks(instance);
1350
- return {
1351
- root,
1352
- unmount() {
1353
- fireUnmountedHooks(instance);
1354
- unmountNode(root);
1355
- container.innerHTML = "";
1356
- }
1357
- };
2751
+ instance._errorHooks.push((err) => withInstance(instance, () => fn(err)));
1358
2752
  }
1359
- function render(node, container) {
1360
- container.innerHTML = "";
1361
- const root = renderNodeToDOM(node, container);
1362
- return {
1363
- root,
1364
- unmount() {
1365
- unmountNode(root);
1366
- container.innerHTML = "";
1367
- }
1368
- };
2753
+ // src/component/create.ts
2754
+ function createComponent(fn) {
2755
+ const component = (props) => fn(props);
2756
+ component._SinwanComponent = true;
2757
+ component._displayName = fn.name || "AnonymousComponent";
2758
+ return component;
1369
2759
  }
1370
- function unmountNode(node) {
1371
- switch (node.type) {
1372
- case "text":
1373
- break;
1374
- case "reactive-text":
1375
- node.dispose();
1376
- break;
1377
- case "element":
1378
- for (const dispose of node.attrDisposers) {
1379
- dispose();
1380
- }
1381
- for (const cleanup of node.eventCleanups) {
1382
- cleanup();
1383
- }
1384
- for (const child of node.children) {
1385
- unmountNode(child);
1386
- }
1387
- break;
1388
- case "fragment":
1389
- for (const child of node.children) {
1390
- unmountNode(child);
1391
- }
1392
- break;
1393
- case "reactive-block":
1394
- node.dispose();
1395
- for (const child of node.children) {
1396
- unmountNode(child);
1397
- }
1398
- break;
1399
- case "component":
1400
- if (node.instance) {
1401
- fireUnmountedHooks(node.instance);
1402
- } else {
1403
- for (const dispose of node.disposers) {
1404
- dispose();
1405
- }
1406
- }
1407
- for (const child of node.children) {
1408
- unmountNode(child);
1409
- }
1410
- break;
2760
+ function createPage(fn) {
2761
+ const page = (data) => fn(data);
2762
+ page._SinwanPage = true;
2763
+ page._displayName = fn.name || "AnonymousPage";
2764
+ return page;
2765
+ }
2766
+ function createLayout(fn) {
2767
+ return createComponent(fn);
2768
+ }
2769
+ // src/component/provide-inject.ts
2770
+ function provide(key, value) {
2771
+ const instance = getCurrentInstance();
2772
+ if (!instance) {
2773
+ throw new Error("provide() called outside of component setup.");
1411
2774
  }
2775
+ instance.provides[key] = value;
2776
+ }
2777
+ function inject(key, defaultValue) {
2778
+ const instance = getCurrentInstance();
2779
+ if (!instance) {
2780
+ throw new Error("inject() called outside of component setup.");
2781
+ }
2782
+ if (key in instance.provides) {
2783
+ return instance.provides[key];
2784
+ }
2785
+ if (arguments.length >= 2) {
2786
+ return defaultValue;
2787
+ }
2788
+ console.warn(`[Sinwan] inject() key "${String(key)}" not found and no default provided.`);
2789
+ return;
1412
2790
  }
1413
2791
  // src/hydration/walk.ts
1414
2792
  function advance(cursor) {
@@ -1449,6 +2827,7 @@ function hydrateNode(node, cursor) {
1449
2827
  }
1450
2828
  function hydrateReactiveText(reactive, cursor) {
1451
2829
  const openComment = cursor.current;
2830
+ const owner = getCurrentInstance();
1452
2831
  if (openComment && openComment.nodeType === 8 && parseTextOpenMarker(openComment) >= 0) {
1453
2832
  advance(cursor);
1454
2833
  const textNode2 = advance(cursor);
@@ -1456,21 +2835,36 @@ function hydrateReactiveText(reactive, cursor) {
1456
2835
  if (closeComment && closeComment.nodeType === 8 && isTextCloseMarker(closeComment)) {
1457
2836
  advance(cursor);
1458
2837
  }
2838
+ let initialized2 = false;
1459
2839
  const dispose2 = effect(() => {
1460
2840
  textNode2.data = String(reactive.value);
2841
+ if (initialized2) {
2842
+ queueUpdatedHooks(owner);
2843
+ }
2844
+ initialized2 = true;
1461
2845
  });
1462
2846
  return { type: "reactive-text", node: textNode2, dispose: dispose2 };
1463
2847
  }
1464
2848
  const textNode = advance(cursor);
1465
2849
  if (textNode) {
2850
+ let initialized2 = false;
1466
2851
  const dispose2 = effect(() => {
1467
2852
  textNode.data = String(reactive.value);
2853
+ if (initialized2) {
2854
+ queueUpdatedHooks(owner);
2855
+ }
2856
+ initialized2 = true;
1468
2857
  });
1469
2858
  return { type: "reactive-text", node: textNode, dispose: dispose2 };
1470
2859
  }
1471
2860
  const newText = document.createTextNode(String(reactive.value));
2861
+ let initialized = false;
1472
2862
  const dispose = effect(() => {
1473
2863
  newText.data = String(reactive.value);
2864
+ if (initialized) {
2865
+ queueUpdatedHooks(owner);
2866
+ }
2867
+ initialized = true;
1474
2868
  });
1475
2869
  return { type: "reactive-text", node: newText, dispose };
1476
2870
  }
@@ -1479,6 +2873,18 @@ function hydrateElement(element, cursor) {
1479
2873
  if (tag === "") {
1480
2874
  return hydrateArray(children, cursor);
1481
2875
  }
2876
+ if (tag === Show || tag === For || tag === Switch || tag === Index || tag === Key || tag === Dynamic || tag === Portal) {
2877
+ return hydrateElement(tag(props), cursor);
2878
+ }
2879
+ if (tag === Visible) {
2880
+ return hydrateElement(tag(props), cursor);
2881
+ }
2882
+ if (isPortalElement(element)) {
2883
+ return renderControlFlowToDOM(element, cursor.parent, cursor.current, null);
2884
+ }
2885
+ if (isShowElement(element) || isForElement(element) || isSwitchElement(element) || isIndexElement(element) || isKeyElement(element) || isDynamicElement(element)) {
2886
+ return hydrateControlFlow(element, cursor);
2887
+ }
1482
2888
  if (typeof tag === "function") {
1483
2889
  return hydrateComponent(tag, props, cursor);
1484
2890
  }
@@ -1497,6 +2903,7 @@ function hydrateIntrinsic(tag, props, children, cursor) {
1497
2903
  el.removeAttribute("data-sinwan-ev");
1498
2904
  const attrDisposers = hydrateAttributes(el, props);
1499
2905
  const eventCleanups = bindEvents(el, props);
2906
+ const refCleanup = applyRef2(el, props.ref);
1500
2907
  const childCursor = {
1501
2908
  parent: el,
1502
2909
  current: el.firstChild
@@ -1510,31 +2917,155 @@ function hydrateIntrinsic(tag, props, children, cursor) {
1510
2917
  node: el,
1511
2918
  children: mountedChildren,
1512
2919
  eventCleanups,
1513
- attrDisposers
2920
+ attrDisposers,
2921
+ refCleanup
1514
2922
  };
1515
2923
  }
1516
2924
  function hydrateAttributes(el, props) {
1517
2925
  const disposers = [];
2926
+ const owner = getCurrentInstance();
1518
2927
  for (const [key, value] of Object.entries(props)) {
1519
- if (key === "children" || key === "key" || key === "ref" || isEventProp(key))
2928
+ if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key))
1520
2929
  continue;
1521
2930
  if (isSignal(value) || isComputed(value)) {
2931
+ const state = { previousStyleProps: new Set };
2932
+ let initialized = false;
1522
2933
  const dispose = effect(() => {
1523
- const v = value.value;
1524
- const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
1525
- if (v == null || v === false) {
1526
- el.removeAttribute(attrName);
1527
- } else if (v === true) {
1528
- el.setAttribute(attrName, "");
1529
- } else {
1530
- el.setAttribute(attrName, String(v));
2934
+ setSingleAttribute(el, key, value.value, state);
2935
+ if (initialized) {
2936
+ queueUpdatedHooks(owner);
1531
2937
  }
2938
+ initialized = true;
1532
2939
  });
1533
2940
  disposers.push(dispose);
1534
2941
  }
1535
2942
  }
1536
2943
  return disposers;
1537
2944
  }
2945
+ function hydrateControlFlow(element, cursor) {
2946
+ if (isShowElement(element)) {
2947
+ const when = readReactive6(element.props.when);
2948
+ const content = when ? resolveShowChildren5(element, when) : element.props.fallback;
2949
+ return hydrateContent(content, cursor);
2950
+ }
2951
+ if (isForElement(element)) {
2952
+ const props = element.props;
2953
+ const items = readReactive6(props.each);
2954
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : props.fallback ? [props.fallback] : [];
2955
+ return hydrateArray(children, cursor);
2956
+ }
2957
+ if (isSwitchElement(element)) {
2958
+ return hydrateContent(resolveSwitchContent5(element), cursor);
2959
+ }
2960
+ if (isIndexElement(element)) {
2961
+ const props = element.props;
2962
+ const items = readReactive6(props.each);
2963
+ const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(() => item, index)) : props.fallback ? [props.fallback] : [];
2964
+ return hydrateArray(children, cursor);
2965
+ }
2966
+ if (isKeyElement(element)) {
2967
+ const key = readReactive6(element.props.when);
2968
+ return hydrateContent(resolveKeyChildren5(element, key), cursor);
2969
+ }
2970
+ if (isDynamicElement(element)) {
2971
+ const tag = readReactive6(element.props.component);
2972
+ const dynamic = createDynamicElement5(element, tag);
2973
+ return dynamic ? hydrateElement(dynamic, cursor) : hydrateArray([], cursor);
2974
+ }
2975
+ return hydrateArray(element.children, cursor);
2976
+ }
2977
+ function hydrateContent(content, cursor) {
2978
+ if (content == null || typeof content === "boolean") {
2979
+ return hydrateArray([], cursor);
2980
+ }
2981
+ return Array.isArray(content) ? hydrateArray(content, cursor) : hydrateNode(content, cursor);
2982
+ }
2983
+ function resolveShowChildren5(element, value) {
2984
+ const children = element.props.children ?? element.children;
2985
+ if (typeof children === "function") {
2986
+ return children(value);
2987
+ }
2988
+ return children;
2989
+ }
2990
+ function resolveSwitchContent5(element) {
2991
+ const props = element.props;
2992
+ const children = normalizeContent5(props.children ?? element.children);
2993
+ for (const child of children) {
2994
+ const match = getMatchElement5(child);
2995
+ if (!match) {
2996
+ continue;
2997
+ }
2998
+ const when = readReactive6(match.props.when);
2999
+ if (when) {
3000
+ return resolveMatchChildren5(match, when);
3001
+ }
3002
+ }
3003
+ return props.fallback;
3004
+ }
3005
+ function resolveMatchChildren5(element, value) {
3006
+ const children = element.props.children ?? element.children;
3007
+ if (typeof children === "function") {
3008
+ return children(value);
3009
+ }
3010
+ return children;
3011
+ }
3012
+ function resolveKeyChildren5(element, value) {
3013
+ const children = element.props.children ?? element.children;
3014
+ if (typeof children === "function") {
3015
+ return children(value);
3016
+ }
3017
+ return children;
3018
+ }
3019
+ function createDynamicElement5(element, tag) {
3020
+ if (typeof tag !== "string" && typeof tag !== "function") {
3021
+ return null;
3022
+ }
3023
+ const { component, ...props } = element.props;
3024
+ const children = normalizeContent5(props.children ?? element.children);
3025
+ return {
3026
+ tag,
3027
+ props,
3028
+ children
3029
+ };
3030
+ }
3031
+ function readReactive6(value) {
3032
+ return isSignal(value) || isComputed(value) ? value.value : value;
3033
+ }
3034
+ function normalizeContent5(content) {
3035
+ if (content == null || typeof content === "boolean") {
3036
+ return [];
3037
+ }
3038
+ return Array.isArray(content) ? content : [content];
3039
+ }
3040
+ function isElementLike5(value) {
3041
+ return value != null && typeof value === "object" && "tag" in value;
3042
+ }
3043
+ function getMatchElement5(value) {
3044
+ if (!isElementLike5(value)) {
3045
+ return null;
3046
+ }
3047
+ if (isMatchElement(value)) {
3048
+ return value;
3049
+ }
3050
+ return value.tag === Match ? Match(value.props) : null;
3051
+ }
3052
+ function applyRef2(el, ref) {
3053
+ const value = ref;
3054
+ if (!value) {
3055
+ return null;
3056
+ }
3057
+ if (typeof value === "function") {
3058
+ value(el);
3059
+ return () => value(null);
3060
+ }
3061
+ if (typeof value === "object" && "current" in value) {
3062
+ value.current = el;
3063
+ return () => {
3064
+ value.current = null;
3065
+ };
3066
+ }
3067
+ return null;
3068
+ }
1538
3069
  function hydrateComponent(component, props, cursor) {
1539
3070
  const parentInstance = getCurrentInstance();
1540
3071
  const instance = createComponentInstance(component, props, parentInstance);
@@ -1621,5 +3152,5 @@ function hydrate(component, container, props) {
1621
3152
  };
1622
3153
  }
1623
3154
 
1624
- //# debugId=F8718FCED5F52B5764756E2164756E21
3155
+ //# debugId=B2FFEB8D17EB811D64756E2164756E21
1625
3156
  //# sourceMappingURL=index.development.js.map