sinwan 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -39
- package/dist/cjs/index.development.js +1624 -961
- package/dist/cjs/index.development.js.map +21 -18
- package/dist/cjs/index.production.min.js +2 -2
- package/dist/cjs/index.production.min.js.map +21 -18
- package/dist/cjs/jsx/jsx-dev-runtime.development.js +6 -16
- package/dist/cjs/jsx/jsx-dev-runtime.development.js.map +3 -3
- package/dist/cjs/jsx/jsx-dev-runtime.production.min.js +2 -2
- package/dist/cjs/jsx/jsx-dev-runtime.production.min.js.map +3 -3
- package/dist/cjs/jsx/jsx-runtime.development.js +6 -16
- package/dist/cjs/jsx/jsx-runtime.development.js.map +3 -3
- package/dist/cjs/jsx/jsx-runtime.production.min.js +2 -2
- package/dist/cjs/jsx/jsx-runtime.production.min.js.map +3 -3
- package/dist/cjs/renderer/index.development.js +1175 -0
- package/dist/cjs/renderer/index.development.js.map +24 -0
- package/dist/cjs/renderer/index.production.min.js +3 -0
- package/dist/cjs/renderer/index.production.min.js.map +24 -0
- package/dist/cjs/server/index.development.js +665 -329
- package/dist/cjs/server/index.development.js.map +11 -10
- package/dist/cjs/server/index.production.min.js +2 -2
- package/dist/cjs/server/index.production.min.js.map +11 -10
- package/dist/component/control-flow.d.ts +18 -0
- package/dist/component/control-flow.d.ts.map +1 -0
- package/dist/component/index.d.ts +3 -1
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/instance.d.ts +7 -1
- package/dist/component/instance.d.ts.map +1 -1
- package/dist/component/lifecycle.d.ts +2 -1
- package/dist/component/lifecycle.d.ts.map +1 -1
- package/dist/component/provide-inject.d.ts +11 -5
- package/dist/component/provide-inject.d.ts.map +1 -1
- package/dist/esm/index.development.js +1301 -660
- package/dist/esm/index.development.js.map +21 -18
- package/dist/esm/index.production.min.js +2 -2
- package/dist/esm/index.production.min.js.map +21 -18
- package/dist/esm/jsx/jsx-dev-runtime.development.js +6 -16
- package/dist/esm/jsx/jsx-dev-runtime.development.js.map +3 -3
- package/dist/esm/jsx/jsx-dev-runtime.production.min.js +2 -2
- package/dist/esm/jsx/jsx-dev-runtime.production.min.js.map +3 -3
- package/dist/esm/jsx/jsx-runtime.development.js +6 -16
- package/dist/esm/jsx/jsx-runtime.development.js.map +3 -3
- package/dist/esm/jsx/jsx-runtime.production.min.js +2 -2
- package/dist/esm/jsx/jsx-runtime.production.min.js.map +3 -3
- package/dist/esm/renderer/index.development.js +1124 -0
- package/dist/esm/renderer/index.development.js.map +24 -0
- package/dist/esm/renderer/index.production.min.js +4 -0
- package/dist/esm/renderer/index.production.min.js.map +24 -0
- package/dist/esm/server/index.development.js +665 -329
- package/dist/esm/server/index.development.js.map +11 -10
- package/dist/esm/server/index.production.min.js +2 -2
- package/dist/esm/server/index.production.min.js.map +11 -10
- package/dist/hydration/walk.d.ts.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/jsx/jsx-runtime.d.ts +13 -0
- package/dist/jsx/jsx-runtime.d.ts.map +1 -1
- package/dist/jsx/jsx-types.d.ts +122 -57
- package/dist/jsx/jsx-types.d.ts.map +1 -1
- package/dist/renderer/attributes.d.ts.map +1 -1
- package/dist/renderer/dom-ops.d.ts +4 -1
- package/dist/renderer/dom-ops.d.ts.map +1 -1
- package/dist/renderer/index.d.ts +1 -1
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/mount.d.ts +2 -5
- package/dist/renderer/mount.d.ts.map +1 -1
- package/dist/renderer/render-children.d.ts +2 -2
- package/dist/renderer/render-children.d.ts.map +1 -1
- package/dist/renderer/render-control-flow.d.ts +13 -0
- package/dist/renderer/render-control-flow.d.ts.map +1 -0
- package/dist/renderer/render-element.d.ts +1 -1
- package/dist/renderer/render-element.d.ts.map +1 -1
- package/dist/renderer/types.d.ts +2 -0
- package/dist/renderer/types.d.ts.map +1 -1
- package/dist/renderer/unmount.d.ts +20 -0
- package/dist/renderer/unmount.d.ts.map +1 -0
- package/dist/renderer.d.ts +1 -0
- package/dist/renderer.js +7 -0
- package/dist/renderer.mjs +4 -0
- package/dist/server/hydration-markers.d.ts.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/renderer.d.ts.map +1 -1
- package/dist/server/stream.d.ts +9 -1
- package/dist/server/stream.d.ts.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -1
|
@@ -40,22 +40,12 @@ function buildElement(type, props, children) {
|
|
|
40
40
|
if (type === Fragment) {
|
|
41
41
|
return { tag: "", props: {}, children };
|
|
42
42
|
}
|
|
43
|
-
if (typeof type === "function") {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return result2;
|
|
48
|
-
}
|
|
49
|
-
return { tag: "", props: {}, children: normalizeChildren(result2) };
|
|
50
|
-
}
|
|
51
|
-
const result = type(props);
|
|
52
|
-
if (result && typeof result === "object" && "tag" in result) {
|
|
53
|
-
return result;
|
|
43
|
+
if (typeof type === "function" || typeof type === "string") {
|
|
44
|
+
const finalProps = props ?? {};
|
|
45
|
+
if (children.length > 0 && finalProps.children === undefined) {
|
|
46
|
+
finalProps.children = children.length === 1 ? children[0] : children;
|
|
54
47
|
}
|
|
55
|
-
return { tag:
|
|
56
|
-
}
|
|
57
|
-
if (typeof type === "string") {
|
|
58
|
-
return { tag: type, props: props || {}, children };
|
|
48
|
+
return { tag: type, props: finalProps, children };
|
|
59
49
|
}
|
|
60
50
|
return { tag: "", props: {}, children };
|
|
61
51
|
}
|
|
@@ -75,255 +65,68 @@ function jsxDEV(type, props, key, isStaticChildren, source, self) {
|
|
|
75
65
|
return element;
|
|
76
66
|
}
|
|
77
67
|
|
|
78
|
-
// src/
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const page = getPage(name);
|
|
126
|
-
if (!page) {
|
|
127
|
-
throw new Error(`Page "${name}" not found in registry`);
|
|
128
|
-
}
|
|
129
|
-
const element = await page(data);
|
|
130
|
-
return renderToString(element);
|
|
131
|
-
}
|
|
132
|
-
async function renderToString(node) {
|
|
133
|
-
if (node == null || typeof node === "boolean") {
|
|
134
|
-
return "";
|
|
135
|
-
}
|
|
136
|
-
if (typeof node === "string") {
|
|
137
|
-
return escapeHtml(node);
|
|
138
|
-
}
|
|
139
|
-
if (typeof node === "number") {
|
|
140
|
-
return String(node);
|
|
141
|
-
}
|
|
142
|
-
if (node instanceof HtmlEscapedString) {
|
|
143
|
-
return node.value;
|
|
144
|
-
}
|
|
145
|
-
if (Array.isArray(node)) {
|
|
146
|
-
const results = await Promise.all(node.map((child) => renderToString(child)));
|
|
147
|
-
return results.join("");
|
|
148
|
-
}
|
|
149
|
-
if (node instanceof Promise) {
|
|
150
|
-
return renderElement(await node);
|
|
151
|
-
}
|
|
152
|
-
return renderElement(node);
|
|
153
|
-
}
|
|
154
|
-
async function renderElement(element) {
|
|
155
|
-
const { tag, props, children } = element;
|
|
156
|
-
if (typeof tag === "function") {
|
|
157
|
-
const result = await tag(props);
|
|
158
|
-
return renderToString(result);
|
|
159
|
-
}
|
|
160
|
-
if (typeof tag === "string") {
|
|
161
|
-
return renderIntrinsicElement(tag, props, children);
|
|
162
|
-
}
|
|
163
|
-
return renderToString(children);
|
|
164
|
-
}
|
|
165
|
-
var VOID_ELEMENTS2 = new Set([
|
|
166
|
-
"area",
|
|
167
|
-
"base",
|
|
168
|
-
"br",
|
|
169
|
-
"col",
|
|
170
|
-
"embed",
|
|
171
|
-
"hr",
|
|
172
|
-
"img",
|
|
173
|
-
"input",
|
|
174
|
-
"link",
|
|
175
|
-
"meta",
|
|
176
|
-
"param",
|
|
177
|
-
"source",
|
|
178
|
-
"track",
|
|
179
|
-
"wbr"
|
|
180
|
-
]);
|
|
181
|
-
async function renderIntrinsicElement(tag, props, children) {
|
|
182
|
-
const attrs = renderAttributes(props);
|
|
183
|
-
if (VOID_ELEMENTS2.has(tag)) {
|
|
184
|
-
return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
|
|
185
|
-
}
|
|
186
|
-
const childrenHtml = await renderChildren(children, props);
|
|
187
|
-
return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
|
|
188
|
-
}
|
|
189
|
-
function renderAttributes(props) {
|
|
190
|
-
let attrs = "";
|
|
191
|
-
for (const [key, value] of Object.entries(props)) {
|
|
192
|
-
if (key === "children")
|
|
193
|
-
continue;
|
|
194
|
-
if (value == null || value === false)
|
|
195
|
-
continue;
|
|
196
|
-
if (value === true) {
|
|
197
|
-
attrs += ` ${key}`;
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (key === "dangerouslySetInnerHTML") {
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
const attrName = key === "className" ? "class" : key;
|
|
204
|
-
const finalName = attrName === "htmlFor" ? "for" : attrName;
|
|
205
|
-
const attrValue = escapeHtml(String(value));
|
|
206
|
-
attrs += ` ${finalName}="${attrValue}"`;
|
|
207
|
-
}
|
|
208
|
-
return attrs;
|
|
209
|
-
}
|
|
210
|
-
async function renderChildren(children, props) {
|
|
211
|
-
const dangerous = props.dangerouslySetInnerHTML;
|
|
212
|
-
if (dangerous && typeof dangerous.__html === "string") {
|
|
213
|
-
return dangerous.__html;
|
|
214
|
-
}
|
|
215
|
-
return renderToString(children);
|
|
216
|
-
}
|
|
217
|
-
function isSlots(children) {
|
|
218
|
-
return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
|
|
219
|
-
}
|
|
220
|
-
// src/server/stream.ts
|
|
221
|
-
var VOID_ELEMENTS3 = new Set([
|
|
222
|
-
"area",
|
|
223
|
-
"base",
|
|
224
|
-
"br",
|
|
225
|
-
"col",
|
|
226
|
-
"embed",
|
|
227
|
-
"hr",
|
|
228
|
-
"img",
|
|
229
|
-
"input",
|
|
230
|
-
"link",
|
|
231
|
-
"meta",
|
|
232
|
-
"param",
|
|
233
|
-
"source",
|
|
234
|
-
"track",
|
|
235
|
-
"wbr"
|
|
236
|
-
]);
|
|
237
|
-
function streamPage(page, data) {
|
|
238
|
-
const encoder = new TextEncoder;
|
|
239
|
-
return new ReadableStream({
|
|
240
|
-
async start(controller) {
|
|
241
|
-
try {
|
|
242
|
-
const element = await page(data);
|
|
243
|
-
await streamNode(element, controller, encoder);
|
|
244
|
-
controller.close();
|
|
245
|
-
} catch (error) {
|
|
246
|
-
controller.error(error);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
async function streamNode(node, controller, encoder) {
|
|
252
|
-
if (node == null || typeof node === "boolean") {
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
if (typeof node === "string") {
|
|
256
|
-
controller.enqueue(encoder.encode(escapeHtml(node)));
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
if (typeof node === "number") {
|
|
260
|
-
controller.enqueue(encoder.encode(String(node)));
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
if (node instanceof HtmlEscapedString) {
|
|
264
|
-
controller.enqueue(encoder.encode(node.value));
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
if (Array.isArray(node)) {
|
|
268
|
-
for (const child of node) {
|
|
269
|
-
await streamNode(child, controller, encoder);
|
|
68
|
+
// src/renderer/dom-ops.ts
|
|
69
|
+
function createDefaultDOMOps() {
|
|
70
|
+
return {
|
|
71
|
+
createElement(tag) {
|
|
72
|
+
return document.createElement(tag);
|
|
73
|
+
},
|
|
74
|
+
createElementNS(namespace, tag) {
|
|
75
|
+
return document.createElementNS(namespace, tag);
|
|
76
|
+
},
|
|
77
|
+
createTextNode(text) {
|
|
78
|
+
return document.createTextNode(text);
|
|
79
|
+
},
|
|
80
|
+
createComment(text) {
|
|
81
|
+
return document.createComment(text);
|
|
82
|
+
},
|
|
83
|
+
setAttribute(el, key, value) {
|
|
84
|
+
el.setAttribute(key, value);
|
|
85
|
+
},
|
|
86
|
+
removeAttribute(el, key) {
|
|
87
|
+
el.removeAttribute(key);
|
|
88
|
+
},
|
|
89
|
+
setProperty(el, key, value) {
|
|
90
|
+
el[key] = value;
|
|
91
|
+
},
|
|
92
|
+
insertBefore(parent, child, anchor) {
|
|
93
|
+
parent.insertBefore(child, anchor);
|
|
94
|
+
},
|
|
95
|
+
appendChild(parent, child) {
|
|
96
|
+
parent.appendChild(child);
|
|
97
|
+
},
|
|
98
|
+
remove(node) {
|
|
99
|
+
node.parentNode?.removeChild(node);
|
|
100
|
+
},
|
|
101
|
+
setTextContent(node, text) {
|
|
102
|
+
node.data = text;
|
|
103
|
+
},
|
|
104
|
+
addEventListener(el, event, handler) {
|
|
105
|
+
el.addEventListener(event, handler);
|
|
106
|
+
},
|
|
107
|
+
removeEventListener(el, event, handler) {
|
|
108
|
+
el.removeEventListener(event, handler);
|
|
109
|
+
},
|
|
110
|
+
parentNode(node) {
|
|
111
|
+
return node.parentNode;
|
|
112
|
+
},
|
|
113
|
+
nextSibling(node) {
|
|
114
|
+
return node.nextSibling;
|
|
270
115
|
}
|
|
271
|
-
|
|
272
|
-
}
|
|
273
|
-
if (node instanceof Promise) {
|
|
274
|
-
const resolved = await node;
|
|
275
|
-
await streamElement(resolved, controller, encoder);
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
await streamElement(node, controller, encoder);
|
|
279
|
-
}
|
|
280
|
-
async function streamElement(element, controller, encoder) {
|
|
281
|
-
const { tag, props, children } = element;
|
|
282
|
-
if (typeof tag === "function") {
|
|
283
|
-
const result = await tag(props);
|
|
284
|
-
await streamNode(result, controller, encoder);
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
if (typeof tag === "string") {
|
|
288
|
-
await streamIntrinsicElement(tag, props, children, controller, encoder);
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
await streamNode(children, controller, encoder);
|
|
116
|
+
};
|
|
292
117
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
|
|
298
|
-
controller.enqueue(encoder.encode(html));
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
|
|
302
|
-
controller.enqueue(encoder.encode(openTag));
|
|
303
|
-
if (dangerous && typeof dangerous.__html === "string") {
|
|
304
|
-
controller.enqueue(encoder.encode(dangerous.__html));
|
|
305
|
-
} else {
|
|
306
|
-
await streamNode(children, controller, encoder);
|
|
307
|
-
}
|
|
308
|
-
controller.enqueue(encoder.encode(`</${tag}>`));
|
|
118
|
+
var defaultDOMOps = createDefaultDOMOps();
|
|
119
|
+
var domOps = { ...defaultDOMOps };
|
|
120
|
+
function setDOMOps(overrides) {
|
|
121
|
+
Object.assign(domOps, overrides);
|
|
309
122
|
}
|
|
310
|
-
function
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
if (key === "children" || key === "dangerouslySetInnerHTML")
|
|
314
|
-
continue;
|
|
315
|
-
if (value == null || value === false)
|
|
316
|
-
continue;
|
|
317
|
-
if (value === true) {
|
|
318
|
-
attrs += ` ${key}`;
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
322
|
-
const attrValue = escapeHtml(String(value));
|
|
323
|
-
attrs += ` ${attrName}="${attrValue}"`;
|
|
123
|
+
function resetDOMOps() {
|
|
124
|
+
for (const key of Object.keys(domOps)) {
|
|
125
|
+
delete domOps[key];
|
|
324
126
|
}
|
|
325
|
-
|
|
127
|
+
Object.assign(domOps, defaultDOMOps);
|
|
326
128
|
}
|
|
129
|
+
|
|
327
130
|
// src/reactivity/scheduler.ts
|
|
328
131
|
var pendingEffects = new Set;
|
|
329
132
|
var flushScheduled = false;
|
|
@@ -566,82 +369,9 @@ function isComputed(value) {
|
|
|
566
369
|
return value != null && typeof value === "object" && COMPUTED_BRAND in value;
|
|
567
370
|
}
|
|
568
371
|
|
|
569
|
-
// src/
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
var TEXT_MARKER_OPEN = "sinwan-t:";
|
|
573
|
-
var TEXT_MARKER_CLOSE = "/sinwan-t";
|
|
574
|
-
var EVENT_ATTR = "data-sinwan-ev";
|
|
575
|
-
function compId(index) {
|
|
576
|
-
return `${COMP_ID_PREFIX}${index}`;
|
|
577
|
-
}
|
|
578
|
-
function textMarkerOpen(index) {
|
|
579
|
-
return `<!--${TEXT_MARKER_OPEN}${index}-->`;
|
|
580
|
-
}
|
|
581
|
-
function textMarkerCloseStr() {
|
|
582
|
-
return `<!--${TEXT_MARKER_CLOSE}-->`;
|
|
583
|
-
}
|
|
584
|
-
function parseTextOpenMarker(node) {
|
|
585
|
-
const data = node.data;
|
|
586
|
-
if (data.startsWith(TEXT_MARKER_OPEN)) {
|
|
587
|
-
const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
|
|
588
|
-
return Number.isNaN(idx) ? -1 : idx;
|
|
589
|
-
}
|
|
590
|
-
return -1;
|
|
591
|
-
}
|
|
592
|
-
function isTextCloseMarker(node) {
|
|
593
|
-
return node.data === TEXT_MARKER_CLOSE;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// src/renderer/dom-ops.ts
|
|
597
|
-
var domOps = {
|
|
598
|
-
createElement(tag) {
|
|
599
|
-
return document.createElement(tag);
|
|
600
|
-
},
|
|
601
|
-
createTextNode(text) {
|
|
602
|
-
return document.createTextNode(text);
|
|
603
|
-
},
|
|
604
|
-
createComment(text) {
|
|
605
|
-
return document.createComment(text);
|
|
606
|
-
},
|
|
607
|
-
setAttribute(el, key, value) {
|
|
608
|
-
el.setAttribute(key, value);
|
|
609
|
-
},
|
|
610
|
-
removeAttribute(el, key) {
|
|
611
|
-
el.removeAttribute(key);
|
|
612
|
-
},
|
|
613
|
-
setProperty(el, key, value) {
|
|
614
|
-
el[key] = value;
|
|
615
|
-
},
|
|
616
|
-
insertBefore(parent, child, anchor) {
|
|
617
|
-
parent.insertBefore(child, anchor);
|
|
618
|
-
},
|
|
619
|
-
appendChild(parent, child) {
|
|
620
|
-
parent.appendChild(child);
|
|
621
|
-
},
|
|
622
|
-
remove(node) {
|
|
623
|
-
node.parentNode?.removeChild(node);
|
|
624
|
-
},
|
|
625
|
-
setTextContent(node, text) {
|
|
626
|
-
node.data = text;
|
|
627
|
-
},
|
|
628
|
-
addEventListener(el, event, handler) {
|
|
629
|
-
el.addEventListener(event, handler);
|
|
630
|
-
},
|
|
631
|
-
removeEventListener(el, event, handler) {
|
|
632
|
-
el.removeEventListener(event, handler);
|
|
633
|
-
},
|
|
634
|
-
parentNode(node) {
|
|
635
|
-
return node.parentNode;
|
|
636
|
-
},
|
|
637
|
-
nextSibling(node) {
|
|
638
|
-
return node.nextSibling;
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
|
|
642
|
-
// src/renderer/events.ts
|
|
643
|
-
function isEventProp(key) {
|
|
644
|
-
return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
|
|
372
|
+
// src/renderer/events.ts
|
|
373
|
+
function isEventProp(key) {
|
|
374
|
+
return key.length > 2 && key[0] === "o" && key[1] === "n" && key[2] >= "A" && key[2] <= "Z";
|
|
645
375
|
}
|
|
646
376
|
function toEventName(key) {
|
|
647
377
|
return key.slice(2).toLowerCase();
|
|
@@ -695,7 +425,18 @@ function setCurrentInstance(instance) {
|
|
|
695
425
|
currentInstance = instance;
|
|
696
426
|
return prev;
|
|
697
427
|
}
|
|
428
|
+
function withInstance(instance, fn) {
|
|
429
|
+
const prev = setCurrentInstance(instance);
|
|
430
|
+
try {
|
|
431
|
+
return fn();
|
|
432
|
+
} finally {
|
|
433
|
+
setCurrentInstance(prev);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
698
436
|
function fireMountedHooks(instance) {
|
|
437
|
+
if (instance.isUnmounted) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
699
440
|
for (const child of instance.children) {
|
|
700
441
|
fireMountedHooks(child);
|
|
701
442
|
}
|
|
@@ -722,6 +463,24 @@ function fireUnmountedHooks(instance) {
|
|
|
722
463
|
instance.effects.length = 0;
|
|
723
464
|
}
|
|
724
465
|
}
|
|
466
|
+
function fireUpdatedHooks(instance) {
|
|
467
|
+
for (const hook of instance._updatedHooks) {
|
|
468
|
+
hook();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
var queuedUpdatedHooks = new Set;
|
|
472
|
+
function queueUpdatedHooks(instance) {
|
|
473
|
+
if (!instance || !instance.isMounted || instance.isUnmounted || instance._updatedHooks.length === 0 || queuedUpdatedHooks.has(instance)) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
queuedUpdatedHooks.add(instance);
|
|
477
|
+
nextTick(() => {
|
|
478
|
+
queuedUpdatedHooks.delete(instance);
|
|
479
|
+
if (instance.isMounted && !instance.isUnmounted) {
|
|
480
|
+
fireUpdatedHooks(instance);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
725
484
|
function handleComponentError(instance, err) {
|
|
726
485
|
let current = instance;
|
|
727
486
|
while (current) {
|
|
@@ -736,212 +495,6 @@ function handleComponentError(instance, err) {
|
|
|
736
495
|
console.error("[Sinwan] Unhandled component error:", err);
|
|
737
496
|
}
|
|
738
497
|
|
|
739
|
-
// src/server/hydration-markers.ts
|
|
740
|
-
function createHydrationContext() {
|
|
741
|
-
return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
|
|
742
|
-
}
|
|
743
|
-
async function renderToHydratableString(component, props) {
|
|
744
|
-
const ctx = createHydrationContext();
|
|
745
|
-
const mergedProps = props ?? {};
|
|
746
|
-
const instance = createComponentInstance(component, mergedProps, null);
|
|
747
|
-
setCurrentInstance(instance);
|
|
748
|
-
const result = await component(mergedProps);
|
|
749
|
-
setCurrentInstance(null);
|
|
750
|
-
if (result && typeof result === "object" && "tag" in result) {
|
|
751
|
-
return renderElementH(result, ctx, true);
|
|
752
|
-
}
|
|
753
|
-
return renderNodeH(result, ctx);
|
|
754
|
-
}
|
|
755
|
-
async function renderNodeToHydratableString(node) {
|
|
756
|
-
const ctx = createHydrationContext();
|
|
757
|
-
return renderNodeH(node, ctx);
|
|
758
|
-
}
|
|
759
|
-
var VOID_ELEMENTS4 = new Set([
|
|
760
|
-
"area",
|
|
761
|
-
"base",
|
|
762
|
-
"br",
|
|
763
|
-
"col",
|
|
764
|
-
"embed",
|
|
765
|
-
"hr",
|
|
766
|
-
"img",
|
|
767
|
-
"input",
|
|
768
|
-
"link",
|
|
769
|
-
"meta",
|
|
770
|
-
"param",
|
|
771
|
-
"source",
|
|
772
|
-
"track",
|
|
773
|
-
"wbr"
|
|
774
|
-
]);
|
|
775
|
-
function renderNodeH(node, ctx) {
|
|
776
|
-
if (node == null || typeof node === "boolean")
|
|
777
|
-
return "";
|
|
778
|
-
if (typeof node === "string")
|
|
779
|
-
return escapeHtml(node);
|
|
780
|
-
if (typeof node === "number")
|
|
781
|
-
return String(node);
|
|
782
|
-
if (node instanceof HtmlEscapedString)
|
|
783
|
-
return node.value;
|
|
784
|
-
if (isSignal(node) || isComputed(node)) {
|
|
785
|
-
const value = node.value;
|
|
786
|
-
const idx = ctx.textIndex++;
|
|
787
|
-
return `${textMarkerOpen(idx)}${escapeHtml(String(value))}${textMarkerCloseStr()}`;
|
|
788
|
-
}
|
|
789
|
-
if (Array.isArray(node)) {
|
|
790
|
-
return node.map((child) => renderNodeH(child, ctx)).join("");
|
|
791
|
-
}
|
|
792
|
-
if (node instanceof Promise) {
|
|
793
|
-
return "";
|
|
794
|
-
}
|
|
795
|
-
if (typeof node === "object" && "tag" in node) {
|
|
796
|
-
return renderElementH(node, ctx, false);
|
|
797
|
-
}
|
|
798
|
-
return escapeHtml(String(node));
|
|
799
|
-
}
|
|
800
|
-
function renderElementH(element, ctx, isComponentRoot) {
|
|
801
|
-
const { tag, props, children } = element;
|
|
802
|
-
if (tag === "") {
|
|
803
|
-
return children.map((child) => renderNodeH(child, ctx)).join("");
|
|
804
|
-
}
|
|
805
|
-
if (typeof tag === "function") {
|
|
806
|
-
return renderComponentH(tag, props, ctx);
|
|
807
|
-
}
|
|
808
|
-
if (typeof tag === "string") {
|
|
809
|
-
return renderIntrinsicH(tag, props, children, ctx, isComponentRoot);
|
|
810
|
-
}
|
|
811
|
-
return children.map((child) => renderNodeH(child, ctx)).join("");
|
|
812
|
-
}
|
|
813
|
-
function renderComponentH(component, props, ctx) {
|
|
814
|
-
const parentInstance = globalThis.__SinwanCurrentInstance;
|
|
815
|
-
const instance = createComponentInstance(component, props, null);
|
|
816
|
-
const prev = setCurrentInstance(instance);
|
|
817
|
-
const result = component(props);
|
|
818
|
-
setCurrentInstance(prev);
|
|
819
|
-
if (result && typeof result === "object" && "tag" in result) {
|
|
820
|
-
return renderElementH(result, ctx, true);
|
|
821
|
-
}
|
|
822
|
-
return renderNodeH(result, ctx);
|
|
823
|
-
}
|
|
824
|
-
function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
|
|
825
|
-
let attrs = "";
|
|
826
|
-
if (isComponentRoot) {
|
|
827
|
-
attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
|
|
828
|
-
}
|
|
829
|
-
const eventParts = [];
|
|
830
|
-
for (const [key, value] of Object.entries(props)) {
|
|
831
|
-
if (key === "children" || key === "dangerouslySetInnerHTML")
|
|
832
|
-
continue;
|
|
833
|
-
if (isEventProp(key)) {
|
|
834
|
-
const eventName = toEventName(key);
|
|
835
|
-
eventParts.push(`${eventName}:${ctx.eventIndex++}`);
|
|
836
|
-
continue;
|
|
837
|
-
}
|
|
838
|
-
if (value == null || value === false)
|
|
839
|
-
continue;
|
|
840
|
-
let resolvedValue = value;
|
|
841
|
-
if (isSignal(value) || isComputed(value)) {
|
|
842
|
-
resolvedValue = value.value;
|
|
843
|
-
}
|
|
844
|
-
if (resolvedValue === true) {
|
|
845
|
-
const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
846
|
-
attrs += ` ${attrName2}`;
|
|
847
|
-
continue;
|
|
848
|
-
}
|
|
849
|
-
const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
850
|
-
attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
|
|
851
|
-
}
|
|
852
|
-
if (eventParts.length > 0) {
|
|
853
|
-
attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
|
|
854
|
-
}
|
|
855
|
-
if (VOID_ELEMENTS4.has(tag)) {
|
|
856
|
-
return `<${tag}${attrs}>`;
|
|
857
|
-
}
|
|
858
|
-
const dangerous = props.dangerouslySetInnerHTML;
|
|
859
|
-
if (dangerous && typeof dangerous.__html === "string") {
|
|
860
|
-
return `<${tag}${attrs}>${dangerous.__html}</${tag}>`;
|
|
861
|
-
}
|
|
862
|
-
const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
|
|
863
|
-
return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
|
|
864
|
-
}
|
|
865
|
-
// src/reactivity/batch.ts
|
|
866
|
-
var batchDepth = 0;
|
|
867
|
-
function batch(fn) {
|
|
868
|
-
batchDepth++;
|
|
869
|
-
try {
|
|
870
|
-
fn();
|
|
871
|
-
} finally {
|
|
872
|
-
batchDepth--;
|
|
873
|
-
if (batchDepth === 0) {
|
|
874
|
-
flushSync();
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
// src/component/lifecycle.ts
|
|
879
|
-
function onMounted(fn) {
|
|
880
|
-
const instance = getCurrentInstance();
|
|
881
|
-
if (!instance) {
|
|
882
|
-
throw new Error("onMounted() called outside of component setup.");
|
|
883
|
-
}
|
|
884
|
-
instance._mountedHooks.push(fn);
|
|
885
|
-
}
|
|
886
|
-
function onUnmounted(fn) {
|
|
887
|
-
const instance = getCurrentInstance();
|
|
888
|
-
if (!instance) {
|
|
889
|
-
throw new Error("onUnmounted() called outside of component setup.");
|
|
890
|
-
}
|
|
891
|
-
instance._unmountedHooks.push(fn);
|
|
892
|
-
}
|
|
893
|
-
function onUpdated(fn) {
|
|
894
|
-
const instance = getCurrentInstance();
|
|
895
|
-
if (!instance) {
|
|
896
|
-
throw new Error("onUpdated() called outside of component setup.");
|
|
897
|
-
}
|
|
898
|
-
instance._updatedHooks.push(fn);
|
|
899
|
-
}
|
|
900
|
-
function onError(fn) {
|
|
901
|
-
const instance = getCurrentInstance();
|
|
902
|
-
if (!instance) {
|
|
903
|
-
throw new Error("onError() called outside of component setup.");
|
|
904
|
-
}
|
|
905
|
-
instance._errorHooks.push(fn);
|
|
906
|
-
}
|
|
907
|
-
// src/component/create.ts
|
|
908
|
-
function createComponent(fn) {
|
|
909
|
-
const component = (props) => fn(props);
|
|
910
|
-
component._SinwanComponent = true;
|
|
911
|
-
component._displayName = fn.name || "AnonymousComponent";
|
|
912
|
-
return component;
|
|
913
|
-
}
|
|
914
|
-
function createPage(fn) {
|
|
915
|
-
const page = (data) => fn(data);
|
|
916
|
-
page._SinwanPage = true;
|
|
917
|
-
page._displayName = fn.name || "AnonymousPage";
|
|
918
|
-
return page;
|
|
919
|
-
}
|
|
920
|
-
function createLayout(fn) {
|
|
921
|
-
return createComponent(fn);
|
|
922
|
-
}
|
|
923
|
-
// src/component/provide-inject.ts
|
|
924
|
-
function provide(key, value) {
|
|
925
|
-
const instance = getCurrentInstance();
|
|
926
|
-
if (!instance) {
|
|
927
|
-
throw new Error("provide() called outside of component setup.");
|
|
928
|
-
}
|
|
929
|
-
instance.provides[key] = value;
|
|
930
|
-
}
|
|
931
|
-
function inject(key, defaultValue) {
|
|
932
|
-
const instance = getCurrentInstance();
|
|
933
|
-
if (!instance) {
|
|
934
|
-
throw new Error("inject() called outside of component setup.");
|
|
935
|
-
}
|
|
936
|
-
if (key in instance.provides) {
|
|
937
|
-
return instance.provides[key];
|
|
938
|
-
}
|
|
939
|
-
if (arguments.length >= 2) {
|
|
940
|
-
return defaultValue;
|
|
941
|
-
}
|
|
942
|
-
console.warn(`[Sinwan] inject() key "${String(key)}" not found and no default provided.`);
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
498
|
// src/renderer/attributes.ts
|
|
946
499
|
var SKIP_PROPS = new Set(["children", "key", "ref", "dangerouslySetInnerHTML"]);
|
|
947
500
|
var DOM_PROPERTIES = new Set(["value", "checked", "selected", "disabled", "readOnly", "multiple", "indeterminate"]);
|
|
@@ -953,12 +506,18 @@ var PROP_ALIASES = {
|
|
|
953
506
|
};
|
|
954
507
|
function applyAttributes(el, props) {
|
|
955
508
|
const disposers = [];
|
|
509
|
+
const owner = getCurrentInstance();
|
|
956
510
|
for (const [key, value] of Object.entries(props)) {
|
|
957
511
|
if (SKIP_PROPS.has(key) || isEventProp(key))
|
|
958
512
|
continue;
|
|
959
513
|
if (isSignal(value) || isComputed(value)) {
|
|
514
|
+
let initialized = false;
|
|
960
515
|
const dispose = effect(() => {
|
|
961
516
|
setSingleAttribute(el, key, value.value);
|
|
517
|
+
if (initialized) {
|
|
518
|
+
queueUpdatedHooks(owner);
|
|
519
|
+
}
|
|
520
|
+
initialized = true;
|
|
962
521
|
});
|
|
963
522
|
disposers.push(dispose);
|
|
964
523
|
} else {
|
|
@@ -1018,47 +577,293 @@ function applyClass(el, value) {
|
|
|
1018
577
|
domOps.setAttribute(el, "class", classStr);
|
|
1019
578
|
}
|
|
1020
579
|
|
|
1021
|
-
// src/
|
|
1022
|
-
var
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
"input",
|
|
1031
|
-
"link",
|
|
1032
|
-
"meta",
|
|
1033
|
-
"param",
|
|
1034
|
-
"source",
|
|
1035
|
-
"track",
|
|
1036
|
-
"wbr"
|
|
1037
|
-
]);
|
|
1038
|
-
function renderElementToDOM(element, parent, anchor = null) {
|
|
1039
|
-
const { tag, props, children } = element;
|
|
1040
|
-
if (tag === "" || tag === Fragment) {
|
|
1041
|
-
return renderFragmentToDOM(children, parent, anchor);
|
|
1042
|
-
}
|
|
1043
|
-
if (typeof tag === "function") {
|
|
1044
|
-
return renderComponentToDOM(tag, props, parent, anchor);
|
|
1045
|
-
}
|
|
1046
|
-
if (typeof tag === "string") {
|
|
1047
|
-
return renderIntrinsicToDOM(tag, props, children, parent, anchor);
|
|
1048
|
-
}
|
|
1049
|
-
return renderFragmentToDOM(children, parent, anchor);
|
|
580
|
+
// src/component/control-flow.ts
|
|
581
|
+
var SHOW_TYPE = Symbol.for("Sinwan.Show");
|
|
582
|
+
var FOR_TYPE = Symbol.for("Sinwan.For");
|
|
583
|
+
function Show(props) {
|
|
584
|
+
return {
|
|
585
|
+
tag: SHOW_TYPE,
|
|
586
|
+
props,
|
|
587
|
+
children: []
|
|
588
|
+
};
|
|
1050
589
|
}
|
|
1051
|
-
function
|
|
1052
|
-
|
|
1053
|
-
|
|
590
|
+
function For(props) {
|
|
591
|
+
return {
|
|
592
|
+
tag: FOR_TYPE,
|
|
593
|
+
props,
|
|
594
|
+
children: []
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function isShowElement(element) {
|
|
598
|
+
return element.tag === SHOW_TYPE;
|
|
599
|
+
}
|
|
600
|
+
function isForElement(element) {
|
|
601
|
+
return element.tag === FOR_TYPE;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/renderer/unmount.ts
|
|
605
|
+
function getMountedDomNodes(node) {
|
|
606
|
+
switch (node.type) {
|
|
607
|
+
case "text":
|
|
608
|
+
case "reactive-text":
|
|
609
|
+
return [node.node];
|
|
610
|
+
case "element":
|
|
611
|
+
return [node.node];
|
|
612
|
+
case "fragment":
|
|
613
|
+
return [
|
|
614
|
+
node.anchor,
|
|
615
|
+
...node.children.flatMap((child) => getMountedDomNodes(child))
|
|
616
|
+
];
|
|
617
|
+
case "reactive-block":
|
|
618
|
+
return [
|
|
619
|
+
node.startAnchor,
|
|
620
|
+
...node.children.flatMap((child) => getMountedDomNodes(child)),
|
|
621
|
+
node.endAnchor
|
|
622
|
+
];
|
|
623
|
+
case "component":
|
|
624
|
+
return node.children.flatMap((child) => getMountedDomNodes(child));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function unmountNode(node) {
|
|
628
|
+
switch (node.type) {
|
|
629
|
+
case "text":
|
|
630
|
+
break;
|
|
631
|
+
case "reactive-text":
|
|
632
|
+
node.dispose();
|
|
633
|
+
break;
|
|
634
|
+
case "element":
|
|
635
|
+
for (const dispose of node.attrDisposers) {
|
|
636
|
+
dispose();
|
|
637
|
+
}
|
|
638
|
+
for (const cleanup of node.eventCleanups) {
|
|
639
|
+
cleanup();
|
|
640
|
+
}
|
|
641
|
+
node.refCleanup?.();
|
|
642
|
+
for (const child of node.children) {
|
|
643
|
+
unmountNode(child);
|
|
644
|
+
}
|
|
645
|
+
break;
|
|
646
|
+
case "fragment":
|
|
647
|
+
for (const child of node.children) {
|
|
648
|
+
unmountNode(child);
|
|
649
|
+
}
|
|
650
|
+
break;
|
|
651
|
+
case "reactive-block":
|
|
652
|
+
node.dispose();
|
|
653
|
+
for (const child of node.children) {
|
|
654
|
+
unmountNode(child);
|
|
655
|
+
}
|
|
656
|
+
break;
|
|
657
|
+
case "component":
|
|
658
|
+
if (node.instance) {
|
|
659
|
+
fireUnmountedHooks(node.instance);
|
|
660
|
+
} else {
|
|
661
|
+
for (const dispose of node.disposers) {
|
|
662
|
+
dispose();
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
for (const child of node.children) {
|
|
666
|
+
unmountNode(child);
|
|
667
|
+
}
|
|
668
|
+
break;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
function removeMountedNode(node) {
|
|
672
|
+
const domNodes = getMountedDomNodes(node);
|
|
673
|
+
unmountNode(node);
|
|
674
|
+
for (const domNode of domNodes) {
|
|
675
|
+
if (domNode.parentNode) {
|
|
676
|
+
domOps.remove(domNode);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// src/renderer/render-control-flow.ts
|
|
682
|
+
function renderControlFlowToDOM(element, parent, anchor, namespace) {
|
|
683
|
+
const startAnchor = domOps.createComment("Sinwan-b");
|
|
684
|
+
const endAnchor = domOps.createComment("/Sinwan-b");
|
|
685
|
+
insertNode(parent, startAnchor, anchor);
|
|
686
|
+
insertNode(parent, endAnchor, anchor);
|
|
687
|
+
const owner = getCurrentInstance();
|
|
688
|
+
let disposeEffect = () => {};
|
|
689
|
+
const block = {
|
|
690
|
+
type: "reactive-block",
|
|
691
|
+
dispose: () => disposeEffect(),
|
|
692
|
+
children: [],
|
|
693
|
+
startAnchor,
|
|
694
|
+
endAnchor
|
|
695
|
+
};
|
|
696
|
+
if (isShowElement(element)) {
|
|
697
|
+
disposeEffect = renderShowBlock(element, block, parent, namespace, owner);
|
|
698
|
+
} else if (isForElement(element)) {
|
|
699
|
+
disposeEffect = renderForBlock(element, block, parent, namespace, owner);
|
|
700
|
+
}
|
|
701
|
+
return block;
|
|
702
|
+
}
|
|
703
|
+
function renderShowBlock(element, block, parent, namespace, owner) {
|
|
704
|
+
let initialized = false;
|
|
705
|
+
return effect(() => {
|
|
706
|
+
clearChildren(block);
|
|
707
|
+
const when = readReactive(element.props.when);
|
|
708
|
+
const content = withOptionalInstance(owner, () => when ? resolveShowChildren(element, when) : element.props.fallback);
|
|
709
|
+
block.children = renderBlockContent(content, parent, block.endAnchor, namespace, owner);
|
|
710
|
+
if (initialized) {
|
|
711
|
+
fireMountedAndQueueUpdated(owner);
|
|
712
|
+
}
|
|
713
|
+
initialized = true;
|
|
714
|
+
});
|
|
715
|
+
}
|
|
716
|
+
function renderForBlock(element, block, parent, namespace, owner) {
|
|
717
|
+
let initialized = false;
|
|
718
|
+
let records = [];
|
|
719
|
+
return effect(() => {
|
|
720
|
+
const props = element.props;
|
|
721
|
+
const items = readReactive(props.each);
|
|
722
|
+
const list = Array.isArray(items) ? items : [];
|
|
723
|
+
const renderChild = props.children;
|
|
724
|
+
if (typeof renderChild !== "function") {
|
|
725
|
+
clearChildren(block);
|
|
726
|
+
records = [];
|
|
727
|
+
if (initialized) {
|
|
728
|
+
queueUpdatedHooks(owner);
|
|
729
|
+
}
|
|
730
|
+
initialized = true;
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const oldByKey = new Map;
|
|
734
|
+
for (const record of records) {
|
|
735
|
+
oldByKey.set(record.key, record);
|
|
736
|
+
}
|
|
737
|
+
const nextRecords = [];
|
|
738
|
+
list.forEach((item, index) => {
|
|
739
|
+
const key = props.key ? props.key(item, index) : item;
|
|
740
|
+
const old = oldByKey.get(key);
|
|
741
|
+
if (old && old.item === item) {
|
|
742
|
+
old.index = index;
|
|
743
|
+
moveBeforeEnd(parent, old.mounted, block.endAnchor);
|
|
744
|
+
nextRecords.push(old);
|
|
745
|
+
oldByKey.delete(key);
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
if (old) {
|
|
749
|
+
removeMountedNode(old.mounted);
|
|
750
|
+
oldByKey.delete(key);
|
|
751
|
+
}
|
|
752
|
+
const record = {
|
|
753
|
+
key,
|
|
754
|
+
item,
|
|
755
|
+
index,
|
|
756
|
+
mounted: { type: "text", node: domOps.createTextNode("") }
|
|
757
|
+
};
|
|
758
|
+
record.mounted = withOptionalInstance(owner, () => renderNodeToDOM(renderChild(item, () => record.index), parent, block.endAnchor, namespace));
|
|
759
|
+
nextRecords.push(record);
|
|
760
|
+
});
|
|
761
|
+
for (const record of oldByKey.values()) {
|
|
762
|
+
removeMountedNode(record.mounted);
|
|
763
|
+
}
|
|
764
|
+
records = nextRecords;
|
|
765
|
+
block.children = nextRecords.map((record) => record.mounted);
|
|
766
|
+
if (initialized) {
|
|
767
|
+
fireMountedAndQueueUpdated(owner);
|
|
768
|
+
}
|
|
769
|
+
initialized = true;
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
function resolveShowChildren(element, value) {
|
|
773
|
+
const children = element.props.children ?? element.children;
|
|
774
|
+
if (typeof children === "function") {
|
|
775
|
+
return children(value);
|
|
776
|
+
}
|
|
777
|
+
return children;
|
|
778
|
+
}
|
|
779
|
+
function renderBlockContent(content, parent, anchor, namespace, owner) {
|
|
780
|
+
if (content == null || typeof content === "boolean") {
|
|
781
|
+
return [];
|
|
782
|
+
}
|
|
783
|
+
const nodes = Array.isArray(content) ? content : [content];
|
|
784
|
+
return nodes.map((node) => withOptionalInstance(owner, () => renderNodeToDOM(node, parent, anchor, namespace)));
|
|
785
|
+
}
|
|
786
|
+
function clearChildren(block) {
|
|
787
|
+
for (const child of block.children) {
|
|
788
|
+
removeMountedNode(child);
|
|
789
|
+
}
|
|
790
|
+
block.children = [];
|
|
791
|
+
}
|
|
792
|
+
function moveBeforeEnd(parent, mounted, endAnchor) {
|
|
793
|
+
for (const node of getMountedDomNodes(mounted)) {
|
|
794
|
+
domOps.insertBefore(parent, node, endAnchor);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
function fireMountedAndQueueUpdated(owner) {
|
|
798
|
+
if (owner) {
|
|
799
|
+
fireMountedHooks(owner);
|
|
800
|
+
}
|
|
801
|
+
queueUpdatedHooks(owner);
|
|
802
|
+
}
|
|
803
|
+
function withOptionalInstance(owner, fn) {
|
|
804
|
+
return owner ? withInstance(owner, fn) : fn();
|
|
805
|
+
}
|
|
806
|
+
function readReactive(value) {
|
|
807
|
+
return isSignal(value) || isComputed(value) ? value.value : value;
|
|
808
|
+
}
|
|
809
|
+
function insertNode(parent, child, anchor) {
|
|
810
|
+
if (anchor) {
|
|
811
|
+
domOps.insertBefore(parent, child, anchor);
|
|
812
|
+
} else {
|
|
813
|
+
domOps.appendChild(parent, child);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// src/renderer/render-element.ts
|
|
818
|
+
var VOID_ELEMENTS2 = new Set([
|
|
819
|
+
"area",
|
|
820
|
+
"base",
|
|
821
|
+
"br",
|
|
822
|
+
"col",
|
|
823
|
+
"embed",
|
|
824
|
+
"hr",
|
|
825
|
+
"img",
|
|
826
|
+
"input",
|
|
827
|
+
"link",
|
|
828
|
+
"meta",
|
|
829
|
+
"param",
|
|
830
|
+
"source",
|
|
831
|
+
"track",
|
|
832
|
+
"wbr"
|
|
833
|
+
]);
|
|
834
|
+
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
835
|
+
var MATH_NS = "http://www.w3.org/1998/Math/MathML";
|
|
836
|
+
function renderElementToDOM(element, parent, anchor = null, namespace = null) {
|
|
837
|
+
const { tag, props, children } = element;
|
|
838
|
+
if (tag === "" || tag === Fragment) {
|
|
839
|
+
return renderFragmentToDOM(children, parent, anchor, namespace);
|
|
840
|
+
}
|
|
841
|
+
if (tag === Show || tag === For) {
|
|
842
|
+
return renderElementToDOM(tag(props), parent, anchor, namespace);
|
|
843
|
+
}
|
|
844
|
+
if (isShowElement(element) || isForElement(element)) {
|
|
845
|
+
return renderControlFlowToDOM(element, parent, anchor, namespace);
|
|
846
|
+
}
|
|
847
|
+
if (typeof tag === "function") {
|
|
848
|
+
return renderComponentToDOM(tag, props, parent, anchor, namespace);
|
|
849
|
+
}
|
|
850
|
+
if (typeof tag === "string") {
|
|
851
|
+
return renderIntrinsicToDOM(tag, props, children, parent, anchor, namespace);
|
|
852
|
+
}
|
|
853
|
+
return renderFragmentToDOM(children, parent, anchor, namespace);
|
|
854
|
+
}
|
|
855
|
+
function renderIntrinsicToDOM(tag, props, children, parent, anchor, parentNamespace) {
|
|
856
|
+
const namespace = getElementNamespace(tag, parentNamespace);
|
|
857
|
+
const el = namespace ? domOps.createElementNS(namespace, tag) : domOps.createElement(tag);
|
|
858
|
+
const attrDisposers = applyAttributes(el, props);
|
|
1054
859
|
const eventCleanups = bindEvents(el, props);
|
|
1055
860
|
let mountedChildren = [];
|
|
1056
|
-
if (!
|
|
861
|
+
if (!VOID_ELEMENTS2.has(tag)) {
|
|
1057
862
|
const dangerous = props.dangerouslySetInnerHTML;
|
|
1058
863
|
if (dangerous && typeof dangerous.__html === "string") {
|
|
1059
864
|
el.innerHTML = dangerous.__html;
|
|
1060
865
|
} else {
|
|
1061
|
-
mountedChildren = renderChildrenToDOM(children, el);
|
|
866
|
+
mountedChildren = renderChildrenToDOM(children, el, getChildNamespace(tag, namespace));
|
|
1062
867
|
}
|
|
1063
868
|
}
|
|
1064
869
|
if (anchor) {
|
|
@@ -1066,15 +871,17 @@ function renderIntrinsicToDOM(tag, props, children, parent, anchor) {
|
|
|
1066
871
|
} else {
|
|
1067
872
|
domOps.appendChild(parent, el);
|
|
1068
873
|
}
|
|
874
|
+
const refCleanup = applyRef(el, props.ref);
|
|
1069
875
|
return {
|
|
1070
876
|
type: "element",
|
|
1071
877
|
node: el,
|
|
1072
878
|
children: mountedChildren,
|
|
1073
879
|
eventCleanups,
|
|
1074
|
-
attrDisposers
|
|
880
|
+
attrDisposers,
|
|
881
|
+
refCleanup
|
|
1075
882
|
};
|
|
1076
883
|
}
|
|
1077
|
-
function renderComponentToDOM(component, props, parent, anchor) {
|
|
884
|
+
function renderComponentToDOM(component, props, parent, anchor, namespace) {
|
|
1078
885
|
const parentInstance = getCurrentInstance();
|
|
1079
886
|
const instance = createComponentInstance(component, props, parentInstance);
|
|
1080
887
|
if (parentInstance) {
|
|
@@ -1086,9 +893,9 @@ function renderComponentToDOM(component, props, parent, anchor) {
|
|
|
1086
893
|
try {
|
|
1087
894
|
result = component(props);
|
|
1088
895
|
if (result && typeof result === "object" && "tag" in result) {
|
|
1089
|
-
child = renderElementToDOM(result, parent, anchor);
|
|
896
|
+
child = renderElementToDOM(result, parent, anchor, namespace);
|
|
1090
897
|
} else {
|
|
1091
|
-
child = renderNodeToDOM(result, parent, anchor);
|
|
898
|
+
child = renderNodeToDOM(result, parent, anchor, namespace);
|
|
1092
899
|
}
|
|
1093
900
|
} catch (err) {
|
|
1094
901
|
setCurrentInstance(prevInstance);
|
|
@@ -1115,7 +922,7 @@ function renderComponentToDOM(component, props, parent, anchor) {
|
|
|
1115
922
|
instance
|
|
1116
923
|
};
|
|
1117
924
|
}
|
|
1118
|
-
function renderFragmentToDOM(children, parent, anchor) {
|
|
925
|
+
function renderFragmentToDOM(children, parent, anchor, namespace) {
|
|
1119
926
|
const anchorComment = domOps.createComment("Sinwan-f");
|
|
1120
927
|
if (anchor) {
|
|
1121
928
|
domOps.insertBefore(parent, anchorComment, anchor);
|
|
@@ -1124,77 +931,113 @@ function renderFragmentToDOM(children, parent, anchor) {
|
|
|
1124
931
|
}
|
|
1125
932
|
const mounted = [];
|
|
1126
933
|
for (const child of children) {
|
|
1127
|
-
mounted.push(renderNodeToDOM(child, parent, anchor));
|
|
934
|
+
mounted.push(renderNodeToDOM(child, parent, anchor, namespace));
|
|
1128
935
|
}
|
|
1129
936
|
return { type: "fragment", children: mounted, anchor: anchorComment };
|
|
1130
937
|
}
|
|
938
|
+
function getElementNamespace(tag, parentNamespace) {
|
|
939
|
+
if (tag === "svg")
|
|
940
|
+
return SVG_NS;
|
|
941
|
+
if (tag === "math")
|
|
942
|
+
return MATH_NS;
|
|
943
|
+
return parentNamespace;
|
|
944
|
+
}
|
|
945
|
+
function getChildNamespace(tag, namespace) {
|
|
946
|
+
if (namespace === SVG_NS && tag === "foreignObject") {
|
|
947
|
+
return null;
|
|
948
|
+
}
|
|
949
|
+
return namespace;
|
|
950
|
+
}
|
|
951
|
+
function applyRef(el, ref) {
|
|
952
|
+
const value = ref;
|
|
953
|
+
if (!value) {
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
if (typeof value === "function") {
|
|
957
|
+
value(el);
|
|
958
|
+
return () => value(null);
|
|
959
|
+
}
|
|
960
|
+
if (typeof value === "object" && "current" in value) {
|
|
961
|
+
value.current = el;
|
|
962
|
+
return () => {
|
|
963
|
+
value.current = null;
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
return null;
|
|
967
|
+
}
|
|
1131
968
|
|
|
1132
969
|
// src/renderer/render-children.ts
|
|
1133
|
-
function renderNodeToDOM(node, parent, anchor = null) {
|
|
970
|
+
function renderNodeToDOM(node, parent, anchor = null, namespace = null) {
|
|
1134
971
|
if (node == null || typeof node === "boolean") {
|
|
1135
972
|
const text2 = domOps.createTextNode("");
|
|
1136
|
-
|
|
973
|
+
insertNode2(parent, text2, anchor);
|
|
1137
974
|
return { type: "text", node: text2 };
|
|
1138
975
|
}
|
|
1139
976
|
if (typeof node === "string") {
|
|
1140
977
|
const text2 = domOps.createTextNode(node);
|
|
1141
|
-
|
|
978
|
+
insertNode2(parent, text2, anchor);
|
|
1142
979
|
return { type: "text", node: text2 };
|
|
1143
980
|
}
|
|
1144
981
|
if (typeof node === "number") {
|
|
1145
982
|
const text2 = domOps.createTextNode(String(node));
|
|
1146
|
-
|
|
983
|
+
insertNode2(parent, text2, anchor);
|
|
1147
984
|
return { type: "text", node: text2 };
|
|
1148
985
|
}
|
|
1149
986
|
if (node instanceof HtmlEscapedString) {
|
|
1150
987
|
const text2 = domOps.createTextNode(node.value);
|
|
1151
|
-
|
|
988
|
+
insertNode2(parent, text2, anchor);
|
|
1152
989
|
return { type: "text", node: text2 };
|
|
1153
990
|
}
|
|
1154
991
|
if (isSignal(node) || isComputed(node)) {
|
|
1155
992
|
const text2 = domOps.createTextNode(String(node.value));
|
|
1156
|
-
|
|
993
|
+
insertNode2(parent, text2, anchor);
|
|
994
|
+
const owner = getCurrentInstance();
|
|
995
|
+
let initialized = false;
|
|
1157
996
|
const dispose = effect(() => {
|
|
1158
997
|
domOps.setTextContent(text2, String(node.value));
|
|
998
|
+
if (initialized) {
|
|
999
|
+
queueUpdatedHooks(owner);
|
|
1000
|
+
}
|
|
1001
|
+
initialized = true;
|
|
1159
1002
|
});
|
|
1160
1003
|
return { type: "reactive-text", node: text2, dispose };
|
|
1161
1004
|
}
|
|
1162
1005
|
if (Array.isArray(node)) {
|
|
1163
|
-
return renderArrayToDOM(node, parent, anchor);
|
|
1006
|
+
return renderArrayToDOM(node, parent, anchor, namespace);
|
|
1164
1007
|
}
|
|
1165
1008
|
if (node instanceof Promise) {
|
|
1166
1009
|
const placeholder = domOps.createTextNode("");
|
|
1167
|
-
|
|
1010
|
+
insertNode2(parent, placeholder, anchor);
|
|
1168
1011
|
node.then((resolved) => {
|
|
1169
|
-
const mounted = renderNodeToDOM(resolved, parent, placeholder);
|
|
1012
|
+
const mounted = renderNodeToDOM(resolved, parent, placeholder, namespace);
|
|
1170
1013
|
domOps.remove(placeholder);
|
|
1171
1014
|
});
|
|
1172
1015
|
return { type: "text", node: placeholder };
|
|
1173
1016
|
}
|
|
1174
1017
|
if (typeof node === "object" && "tag" in node) {
|
|
1175
|
-
return renderElementToDOM(node, parent, anchor);
|
|
1018
|
+
return renderElementToDOM(node, parent, anchor, namespace);
|
|
1176
1019
|
}
|
|
1177
1020
|
const text = domOps.createTextNode(String(node));
|
|
1178
|
-
|
|
1021
|
+
insertNode2(parent, text, anchor);
|
|
1179
1022
|
return { type: "text", node: text };
|
|
1180
1023
|
}
|
|
1181
|
-
function renderArrayToDOM(nodes, parent, anchor) {
|
|
1024
|
+
function renderArrayToDOM(nodes, parent, anchor, namespace) {
|
|
1182
1025
|
const anchorComment = domOps.createComment("Sinwan-f");
|
|
1183
|
-
|
|
1026
|
+
insertNode2(parent, anchorComment, anchor);
|
|
1184
1027
|
const children = [];
|
|
1185
1028
|
for (const child of nodes) {
|
|
1186
|
-
children.push(renderNodeToDOM(child, parent, anchor));
|
|
1029
|
+
children.push(renderNodeToDOM(child, parent, anchor, namespace));
|
|
1187
1030
|
}
|
|
1188
1031
|
return { type: "fragment", children, anchor: anchorComment };
|
|
1189
1032
|
}
|
|
1190
|
-
function renderChildrenToDOM(children, parent) {
|
|
1033
|
+
function renderChildrenToDOM(children, parent, namespace = null) {
|
|
1191
1034
|
const mounted = [];
|
|
1192
1035
|
for (const child of children) {
|
|
1193
|
-
mounted.push(renderNodeToDOM(child, parent));
|
|
1036
|
+
mounted.push(renderNodeToDOM(child, parent, null, namespace));
|
|
1194
1037
|
}
|
|
1195
1038
|
return mounted;
|
|
1196
1039
|
}
|
|
1197
|
-
function
|
|
1040
|
+
function insertNode2(parent, child, anchor) {
|
|
1198
1041
|
if (anchor) {
|
|
1199
1042
|
domOps.insertBefore(parent, child, anchor);
|
|
1200
1043
|
} else {
|
|
@@ -1260,79 +1103,793 @@ function render(node, container) {
|
|
|
1260
1103
|
}
|
|
1261
1104
|
};
|
|
1262
1105
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
}
|
|
1280
|
-
break;
|
|
1281
|
-
case "fragment":
|
|
1282
|
-
for (const child of node.children) {
|
|
1283
|
-
unmountNode(child);
|
|
1284
|
-
}
|
|
1285
|
-
break;
|
|
1286
|
-
case "reactive-block":
|
|
1287
|
-
node.dispose();
|
|
1288
|
-
for (const child of node.children) {
|
|
1289
|
-
unmountNode(child);
|
|
1290
|
-
}
|
|
1291
|
-
break;
|
|
1292
|
-
case "component":
|
|
1293
|
-
if (node.instance) {
|
|
1294
|
-
fireUnmountedHooks(node.instance);
|
|
1295
|
-
} else {
|
|
1296
|
-
for (const dispose of node.disposers) {
|
|
1297
|
-
dispose();
|
|
1298
|
-
}
|
|
1299
|
-
}
|
|
1300
|
-
for (const child of node.children) {
|
|
1301
|
-
unmountNode(child);
|
|
1302
|
-
}
|
|
1303
|
-
break;
|
|
1304
|
-
}
|
|
1106
|
+
// src/escaper.ts
|
|
1107
|
+
var _bun = globalThis.Bun;
|
|
1108
|
+
var _nativeEscape = typeof _bun?.escapeHTML === "function" ? _bun.escapeHTML.bind(_bun) : undefined;
|
|
1109
|
+
var HTML_ESCAPE_RE = /[&<>"']/g;
|
|
1110
|
+
var HTML_ESCAPE_MAP = {
|
|
1111
|
+
"&": "&",
|
|
1112
|
+
"<": "<",
|
|
1113
|
+
">": ">",
|
|
1114
|
+
'"': """,
|
|
1115
|
+
"'": "'"
|
|
1116
|
+
};
|
|
1117
|
+
function portableEscape(str) {
|
|
1118
|
+
HTML_ESCAPE_RE.lastIndex = 0;
|
|
1119
|
+
if (!HTML_ESCAPE_RE.test(str))
|
|
1120
|
+
return str;
|
|
1121
|
+
return str.replace(HTML_ESCAPE_RE, (c) => HTML_ESCAPE_MAP[c]);
|
|
1305
1122
|
}
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
if (
|
|
1310
|
-
|
|
1123
|
+
function escapeHtml(value) {
|
|
1124
|
+
if (value == null || typeof value === "boolean")
|
|
1125
|
+
return "";
|
|
1126
|
+
if (typeof value === "number")
|
|
1127
|
+
return String(value);
|
|
1128
|
+
if (value instanceof HtmlEscapedString)
|
|
1129
|
+
return value.value;
|
|
1130
|
+
const s = String(value);
|
|
1131
|
+
return _nativeEscape ? _nativeEscape(s) : portableEscape(s);
|
|
1132
|
+
}
|
|
1133
|
+
function safeHtml(html) {
|
|
1134
|
+
return raw(html);
|
|
1135
|
+
}
|
|
1136
|
+
function isSafeHtml(value) {
|
|
1137
|
+
return value instanceof HtmlEscapedString;
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// src/server/renderer.ts
|
|
1141
|
+
var componentCache = new WeakMap;
|
|
1142
|
+
var pageRegistry = new Map;
|
|
1143
|
+
function registerPage(name, page) {
|
|
1144
|
+
pageRegistry.set(name, page);
|
|
1145
|
+
}
|
|
1146
|
+
function getPage(name) {
|
|
1147
|
+
return pageRegistry.get(name);
|
|
1148
|
+
}
|
|
1149
|
+
function hasPage(name) {
|
|
1150
|
+
return pageRegistry.has(name);
|
|
1151
|
+
}
|
|
1152
|
+
async function renderPage(name, data) {
|
|
1153
|
+
const page = getPage(name);
|
|
1154
|
+
if (!page) {
|
|
1155
|
+
throw new Error(`Page "${name}" not found in registry`);
|
|
1311
1156
|
}
|
|
1312
|
-
|
|
1157
|
+
const element = await page(data);
|
|
1158
|
+
return renderToString(element);
|
|
1313
1159
|
}
|
|
1314
|
-
function
|
|
1160
|
+
async function renderToString(node) {
|
|
1315
1161
|
if (node == null || typeof node === "boolean") {
|
|
1316
|
-
|
|
1317
|
-
return { type: "text", node: textNode2 ?? document.createTextNode("") };
|
|
1162
|
+
return "";
|
|
1318
1163
|
}
|
|
1319
1164
|
if (typeof node === "string") {
|
|
1320
|
-
|
|
1321
|
-
return { type: "text", node: textNode2 };
|
|
1165
|
+
return escapeHtml(node);
|
|
1322
1166
|
}
|
|
1323
1167
|
if (typeof node === "number") {
|
|
1324
|
-
|
|
1325
|
-
return { type: "text", node: textNode2 };
|
|
1168
|
+
return String(node);
|
|
1326
1169
|
}
|
|
1327
1170
|
if (node instanceof HtmlEscapedString) {
|
|
1328
|
-
|
|
1329
|
-
return { type: "text", node: textNode2 };
|
|
1171
|
+
return node.value;
|
|
1330
1172
|
}
|
|
1331
1173
|
if (isSignal(node) || isComputed(node)) {
|
|
1332
|
-
return
|
|
1174
|
+
return escapeHtml(String(node.value));
|
|
1333
1175
|
}
|
|
1334
1176
|
if (Array.isArray(node)) {
|
|
1335
|
-
|
|
1177
|
+
const results = await Promise.all(node.map((child) => renderToString(child)));
|
|
1178
|
+
return results.join("");
|
|
1179
|
+
}
|
|
1180
|
+
if (node instanceof Promise) {
|
|
1181
|
+
return renderElement(await node);
|
|
1182
|
+
}
|
|
1183
|
+
return renderElement(node);
|
|
1184
|
+
}
|
|
1185
|
+
async function renderElement(element) {
|
|
1186
|
+
const { tag, props, children } = element;
|
|
1187
|
+
if (isShowElement(element)) {
|
|
1188
|
+
const when = readReactive2(props.when);
|
|
1189
|
+
return renderToString(when ? resolveShowChildren2(element, when) : props.fallback);
|
|
1190
|
+
}
|
|
1191
|
+
if (isForElement(element)) {
|
|
1192
|
+
return renderForElement(element);
|
|
1193
|
+
}
|
|
1194
|
+
if (typeof tag === "function") {
|
|
1195
|
+
const result = await tag(props);
|
|
1196
|
+
return renderToString(result);
|
|
1197
|
+
}
|
|
1198
|
+
if (typeof tag === "string") {
|
|
1199
|
+
return renderIntrinsicElement(tag, props, children);
|
|
1200
|
+
}
|
|
1201
|
+
return renderToString(children);
|
|
1202
|
+
}
|
|
1203
|
+
var VOID_ELEMENTS3 = new Set([
|
|
1204
|
+
"area",
|
|
1205
|
+
"base",
|
|
1206
|
+
"br",
|
|
1207
|
+
"col",
|
|
1208
|
+
"embed",
|
|
1209
|
+
"hr",
|
|
1210
|
+
"img",
|
|
1211
|
+
"input",
|
|
1212
|
+
"link",
|
|
1213
|
+
"meta",
|
|
1214
|
+
"param",
|
|
1215
|
+
"source",
|
|
1216
|
+
"track",
|
|
1217
|
+
"wbr"
|
|
1218
|
+
]);
|
|
1219
|
+
async function renderIntrinsicElement(tag, props, children) {
|
|
1220
|
+
const attrs = renderAttributes(props);
|
|
1221
|
+
if (VOID_ELEMENTS3.has(tag)) {
|
|
1222
|
+
return attrs ? `<${tag}${attrs}>` : `<${tag}>`;
|
|
1223
|
+
}
|
|
1224
|
+
const childrenHtml = await renderChildren(children, props);
|
|
1225
|
+
return attrs ? `<${tag}${attrs}>${childrenHtml}</${tag}>` : `<${tag}>${childrenHtml}</${tag}>`;
|
|
1226
|
+
}
|
|
1227
|
+
function renderAttributes(props) {
|
|
1228
|
+
let attrs = "";
|
|
1229
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1230
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
const resolvedValue = readReactive2(value);
|
|
1234
|
+
if (resolvedValue == null || resolvedValue === false)
|
|
1235
|
+
continue;
|
|
1236
|
+
const attrName = key === "className" ? "class" : key;
|
|
1237
|
+
const finalName = attrName === "htmlFor" ? "for" : attrName;
|
|
1238
|
+
if (resolvedValue === true) {
|
|
1239
|
+
attrs += ` ${finalName}`;
|
|
1240
|
+
continue;
|
|
1241
|
+
}
|
|
1242
|
+
const attrValue = escapeHtml(String(resolvedValue));
|
|
1243
|
+
attrs += ` ${finalName}="${attrValue}"`;
|
|
1244
|
+
}
|
|
1245
|
+
return attrs;
|
|
1246
|
+
}
|
|
1247
|
+
async function renderChildren(children, props) {
|
|
1248
|
+
const dangerous = props.dangerouslySetInnerHTML;
|
|
1249
|
+
if (dangerous && typeof dangerous.__html === "string") {
|
|
1250
|
+
return dangerous.__html;
|
|
1251
|
+
}
|
|
1252
|
+
return renderToString(children);
|
|
1253
|
+
}
|
|
1254
|
+
function isSlots(children) {
|
|
1255
|
+
return children != null && typeof children === "object" && !Array.isArray(children) && !(children instanceof HtmlEscapedString);
|
|
1256
|
+
}
|
|
1257
|
+
async function renderForElement(element) {
|
|
1258
|
+
const props = element.props;
|
|
1259
|
+
const each = readReactive2(props.each);
|
|
1260
|
+
if (!Array.isArray(each) || typeof props.children !== "function") {
|
|
1261
|
+
return "";
|
|
1262
|
+
}
|
|
1263
|
+
const rendered = await Promise.all(each.map((item, index) => renderToString(props.children(item, () => index))));
|
|
1264
|
+
return rendered.join("");
|
|
1265
|
+
}
|
|
1266
|
+
function resolveShowChildren2(element, value) {
|
|
1267
|
+
const children = element.props.children ?? element.children;
|
|
1268
|
+
if (typeof children === "function") {
|
|
1269
|
+
return children(value);
|
|
1270
|
+
}
|
|
1271
|
+
return children;
|
|
1272
|
+
}
|
|
1273
|
+
function readReactive2(value) {
|
|
1274
|
+
return isSignal(value) || isComputed(value) ? value.value : value;
|
|
1275
|
+
}
|
|
1276
|
+
// src/hydration/markers.ts
|
|
1277
|
+
var COMP_ID_ATTR = "data-sinwan-id";
|
|
1278
|
+
var COMP_ID_PREFIX = "c";
|
|
1279
|
+
var TEXT_MARKER_OPEN = "sinwan-t:";
|
|
1280
|
+
var TEXT_MARKER_CLOSE = "/sinwan-t";
|
|
1281
|
+
var EVENT_ATTR = "data-sinwan-ev";
|
|
1282
|
+
function compId(index) {
|
|
1283
|
+
return `${COMP_ID_PREFIX}${index}`;
|
|
1284
|
+
}
|
|
1285
|
+
function textMarkerOpen(index) {
|
|
1286
|
+
return `<!--${TEXT_MARKER_OPEN}${index}-->`;
|
|
1287
|
+
}
|
|
1288
|
+
function textMarkerCloseStr() {
|
|
1289
|
+
return `<!--${TEXT_MARKER_CLOSE}-->`;
|
|
1290
|
+
}
|
|
1291
|
+
function parseTextOpenMarker(node) {
|
|
1292
|
+
const data = node.data;
|
|
1293
|
+
if (data.startsWith(TEXT_MARKER_OPEN)) {
|
|
1294
|
+
const idx = parseInt(data.slice(TEXT_MARKER_OPEN.length), 10);
|
|
1295
|
+
return Number.isNaN(idx) ? -1 : idx;
|
|
1296
|
+
}
|
|
1297
|
+
return -1;
|
|
1298
|
+
}
|
|
1299
|
+
function isTextCloseMarker(node) {
|
|
1300
|
+
return node.data === TEXT_MARKER_CLOSE;
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// src/server/stream.ts
|
|
1304
|
+
function createHydratableStreamContext() {
|
|
1305
|
+
return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
|
|
1306
|
+
}
|
|
1307
|
+
var VOID_ELEMENTS4 = new Set([
|
|
1308
|
+
"area",
|
|
1309
|
+
"base",
|
|
1310
|
+
"br",
|
|
1311
|
+
"col",
|
|
1312
|
+
"embed",
|
|
1313
|
+
"hr",
|
|
1314
|
+
"img",
|
|
1315
|
+
"input",
|
|
1316
|
+
"link",
|
|
1317
|
+
"meta",
|
|
1318
|
+
"param",
|
|
1319
|
+
"source",
|
|
1320
|
+
"track",
|
|
1321
|
+
"wbr"
|
|
1322
|
+
]);
|
|
1323
|
+
function streamPage(page, data) {
|
|
1324
|
+
const encoder = new TextEncoder;
|
|
1325
|
+
return new ReadableStream({
|
|
1326
|
+
async start(controller) {
|
|
1327
|
+
try {
|
|
1328
|
+
const element = await page(data);
|
|
1329
|
+
await streamNode(element, controller, encoder);
|
|
1330
|
+
controller.close();
|
|
1331
|
+
} catch (error) {
|
|
1332
|
+
controller.error(error);
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
function streamHydratablePage(component, props) {
|
|
1338
|
+
const encoder = new TextEncoder;
|
|
1339
|
+
const ctx = createHydratableStreamContext();
|
|
1340
|
+
return new ReadableStream({
|
|
1341
|
+
async start(controller) {
|
|
1342
|
+
try {
|
|
1343
|
+
await streamHydratableComponent(component, props ?? {}, controller, encoder, ctx, true);
|
|
1344
|
+
controller.close();
|
|
1345
|
+
} catch (error) {
|
|
1346
|
+
controller.error(error);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
1351
|
+
function streamHydratableNode(node) {
|
|
1352
|
+
const encoder = new TextEncoder;
|
|
1353
|
+
const ctx = createHydratableStreamContext();
|
|
1354
|
+
return new ReadableStream({
|
|
1355
|
+
async start(controller) {
|
|
1356
|
+
try {
|
|
1357
|
+
await streamHydratableNodeToController(node, controller, encoder, ctx);
|
|
1358
|
+
controller.close();
|
|
1359
|
+
} catch (error) {
|
|
1360
|
+
controller.error(error);
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
async function streamNode(node, controller, encoder) {
|
|
1366
|
+
if (node == null || typeof node === "boolean") {
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
if (typeof node === "string") {
|
|
1370
|
+
controller.enqueue(encoder.encode(escapeHtml(node)));
|
|
1371
|
+
return;
|
|
1372
|
+
}
|
|
1373
|
+
if (typeof node === "number") {
|
|
1374
|
+
controller.enqueue(encoder.encode(String(node)));
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
if (node instanceof HtmlEscapedString) {
|
|
1378
|
+
controller.enqueue(encoder.encode(node.value));
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
if (isSignal(node) || isComputed(node)) {
|
|
1382
|
+
controller.enqueue(encoder.encode(escapeHtml(String(node.value))));
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
if (Array.isArray(node)) {
|
|
1386
|
+
for (const child of node) {
|
|
1387
|
+
await streamNode(child, controller, encoder);
|
|
1388
|
+
}
|
|
1389
|
+
return;
|
|
1390
|
+
}
|
|
1391
|
+
if (node instanceof Promise) {
|
|
1392
|
+
const resolved = await node;
|
|
1393
|
+
await streamElement(resolved, controller, encoder);
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
await streamElement(node, controller, encoder);
|
|
1397
|
+
}
|
|
1398
|
+
async function streamElement(element, controller, encoder) {
|
|
1399
|
+
const { tag, props, children } = element;
|
|
1400
|
+
if (isShowElement(element)) {
|
|
1401
|
+
const when = readReactive3(props.when);
|
|
1402
|
+
await streamNode(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
if (isForElement(element)) {
|
|
1406
|
+
await streamForElement(element, controller, encoder);
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
if (typeof tag === "function") {
|
|
1410
|
+
const result = await tag(props);
|
|
1411
|
+
await streamNode(result, controller, encoder);
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
if (typeof tag === "string") {
|
|
1415
|
+
await streamIntrinsicElement(tag, props, children, controller, encoder);
|
|
1416
|
+
return;
|
|
1417
|
+
}
|
|
1418
|
+
await streamNode(children, controller, encoder);
|
|
1419
|
+
}
|
|
1420
|
+
async function streamIntrinsicElement(tag, props, children, controller, encoder) {
|
|
1421
|
+
const attrs = renderAttributes2(props);
|
|
1422
|
+
const dangerous = props.dangerouslySetInnerHTML;
|
|
1423
|
+
if (VOID_ELEMENTS4.has(tag)) {
|
|
1424
|
+
const html = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
|
|
1425
|
+
controller.enqueue(encoder.encode(html));
|
|
1426
|
+
return;
|
|
1427
|
+
}
|
|
1428
|
+
const openTag = attrs ? `<${tag}${attrs}>` : `<${tag}>`;
|
|
1429
|
+
controller.enqueue(encoder.encode(openTag));
|
|
1430
|
+
if (dangerous && typeof dangerous.__html === "string") {
|
|
1431
|
+
controller.enqueue(encoder.encode(dangerous.__html));
|
|
1432
|
+
} else {
|
|
1433
|
+
await streamNode(children, controller, encoder);
|
|
1434
|
+
}
|
|
1435
|
+
controller.enqueue(encoder.encode(`</${tag}>`));
|
|
1436
|
+
}
|
|
1437
|
+
function renderAttributes2(props) {
|
|
1438
|
+
let attrs = "";
|
|
1439
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1440
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML" || isEventProp(key)) {
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
const resolvedValue = readReactive3(value);
|
|
1444
|
+
if (resolvedValue == null || resolvedValue === false)
|
|
1445
|
+
continue;
|
|
1446
|
+
const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
1447
|
+
if (resolvedValue === true) {
|
|
1448
|
+
attrs += ` ${attrName}`;
|
|
1449
|
+
continue;
|
|
1450
|
+
}
|
|
1451
|
+
const attrValue = escapeHtml(String(resolvedValue));
|
|
1452
|
+
attrs += ` ${attrName}="${attrValue}"`;
|
|
1453
|
+
}
|
|
1454
|
+
return attrs;
|
|
1455
|
+
}
|
|
1456
|
+
async function streamHydratableNodeToController(node, controller, encoder, ctx, isComponentRoot = false) {
|
|
1457
|
+
if (node == null || typeof node === "boolean") {
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
if (typeof node === "string") {
|
|
1461
|
+
enqueue(controller, encoder, escapeHtml(node));
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
if (typeof node === "number") {
|
|
1465
|
+
enqueue(controller, encoder, String(node));
|
|
1466
|
+
return;
|
|
1467
|
+
}
|
|
1468
|
+
if (node instanceof HtmlEscapedString) {
|
|
1469
|
+
enqueue(controller, encoder, node.value);
|
|
1470
|
+
return;
|
|
1471
|
+
}
|
|
1472
|
+
if (isSignal(node) || isComputed(node)) {
|
|
1473
|
+
const idx = ctx.textIndex++;
|
|
1474
|
+
enqueue(controller, encoder, `${textMarkerOpen(idx)}${escapeHtml(String(node.value))}${textMarkerCloseStr()}`);
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
if (Array.isArray(node)) {
|
|
1478
|
+
for (const child of node) {
|
|
1479
|
+
await streamHydratableNodeToController(child, controller, encoder, ctx);
|
|
1480
|
+
}
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
if (node instanceof Promise) {
|
|
1484
|
+
await streamHydratableElement(await node, controller, encoder, ctx, isComponentRoot);
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
await streamHydratableElement(node, controller, encoder, ctx, isComponentRoot);
|
|
1488
|
+
}
|
|
1489
|
+
async function streamHydratableElement(element, controller, encoder, ctx, isComponentRoot) {
|
|
1490
|
+
const { tag, props, children } = element;
|
|
1491
|
+
if (tag === "") {
|
|
1492
|
+
for (const child of children) {
|
|
1493
|
+
await streamHydratableNodeToController(child, controller, encoder, ctx);
|
|
1494
|
+
}
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
if (tag === Show || tag === For) {
|
|
1498
|
+
await streamHydratableElement(tag(props), controller, encoder, ctx, isComponentRoot);
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
if (isShowElement(element)) {
|
|
1502
|
+
const when = readReactive3(props.when);
|
|
1503
|
+
await streamHydratableNodeToController(when ? resolveShowChildren3(element, when) : props.fallback, controller, encoder, ctx, isComponentRoot);
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
if (isForElement(element)) {
|
|
1507
|
+
await streamHydratableForElement(element, controller, encoder, ctx);
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1510
|
+
if (typeof tag === "function") {
|
|
1511
|
+
await streamHydratableComponent(tag, props, controller, encoder, ctx, true);
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
if (typeof tag === "string") {
|
|
1515
|
+
await streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
await streamHydratableNodeToController(children, controller, encoder, ctx);
|
|
1519
|
+
}
|
|
1520
|
+
async function streamHydratableComponent(component, props, controller, encoder, ctx, isComponentRoot) {
|
|
1521
|
+
const parentInstance = getCurrentInstance();
|
|
1522
|
+
const instance = createComponentInstance(component, props, parentInstance);
|
|
1523
|
+
if (parentInstance) {
|
|
1524
|
+
parentInstance.children.push(instance);
|
|
1525
|
+
}
|
|
1526
|
+
const prev = setCurrentInstance(instance);
|
|
1527
|
+
try {
|
|
1528
|
+
const result = await component(props);
|
|
1529
|
+
await streamHydratableNodeToController(result, controller, encoder, ctx, isComponentRoot);
|
|
1530
|
+
} finally {
|
|
1531
|
+
setCurrentInstance(prev);
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
async function streamHydratableIntrinsic(tag, props, children, controller, encoder, ctx, isComponentRoot) {
|
|
1535
|
+
const attrs = renderHydratableAttributes(props, ctx, isComponentRoot);
|
|
1536
|
+
const dangerous = props.dangerouslySetInnerHTML;
|
|
1537
|
+
enqueue(controller, encoder, attrs ? `<${tag}${attrs}>` : `<${tag}>`);
|
|
1538
|
+
if (VOID_ELEMENTS4.has(tag)) {
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
if (dangerous && typeof dangerous.__html === "string") {
|
|
1542
|
+
enqueue(controller, encoder, dangerous.__html);
|
|
1543
|
+
} else {
|
|
1544
|
+
for (const child of children) {
|
|
1545
|
+
await streamHydratableNodeToController(child, controller, encoder, ctx);
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
enqueue(controller, encoder, `</${tag}>`);
|
|
1549
|
+
}
|
|
1550
|
+
async function streamHydratableForElement(element, controller, encoder, ctx) {
|
|
1551
|
+
const props = element.props;
|
|
1552
|
+
const each = readReactive3(props.each);
|
|
1553
|
+
if (!Array.isArray(each) || typeof props.children !== "function") {
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
for (let index = 0;index < each.length; index++) {
|
|
1557
|
+
await streamHydratableNodeToController(props.children(each[index], () => index), controller, encoder, ctx);
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
function renderHydratableAttributes(props, ctx, isComponentRoot) {
|
|
1561
|
+
let attrs = "";
|
|
1562
|
+
if (isComponentRoot) {
|
|
1563
|
+
attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
|
|
1564
|
+
}
|
|
1565
|
+
const eventParts = [];
|
|
1566
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1567
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
|
|
1568
|
+
continue;
|
|
1569
|
+
}
|
|
1570
|
+
if (isEventProp(key)) {
|
|
1571
|
+
eventParts.push(`${toEventName(key)}:${ctx.eventIndex++}`);
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
const resolvedValue = readReactive3(value);
|
|
1575
|
+
if (resolvedValue == null || resolvedValue === false)
|
|
1576
|
+
continue;
|
|
1577
|
+
const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
1578
|
+
if (resolvedValue === true) {
|
|
1579
|
+
attrs += ` ${attrName}`;
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
|
|
1583
|
+
}
|
|
1584
|
+
if (eventParts.length > 0) {
|
|
1585
|
+
attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
|
|
1586
|
+
}
|
|
1587
|
+
return attrs;
|
|
1588
|
+
}
|
|
1589
|
+
function enqueue(controller, encoder, html) {
|
|
1590
|
+
controller.enqueue(encoder.encode(html));
|
|
1591
|
+
}
|
|
1592
|
+
async function streamForElement(element, controller, encoder) {
|
|
1593
|
+
const props = element.props;
|
|
1594
|
+
const each = readReactive3(props.each);
|
|
1595
|
+
if (!Array.isArray(each) || typeof props.children !== "function") {
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
for (let index = 0;index < each.length; index++) {
|
|
1599
|
+
await streamNode(props.children(each[index], () => index), controller, encoder);
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
function resolveShowChildren3(element, value) {
|
|
1603
|
+
const children = element.props.children ?? element.children;
|
|
1604
|
+
if (typeof children === "function") {
|
|
1605
|
+
return children(value);
|
|
1606
|
+
}
|
|
1607
|
+
return children;
|
|
1608
|
+
}
|
|
1609
|
+
function readReactive3(value) {
|
|
1610
|
+
return isSignal(value) || isComputed(value) ? value.value : value;
|
|
1611
|
+
}
|
|
1612
|
+
// src/server/hydration-markers.ts
|
|
1613
|
+
function createHydrationContext() {
|
|
1614
|
+
return { componentIndex: 0, textIndex: 0, eventIndex: 0 };
|
|
1615
|
+
}
|
|
1616
|
+
async function renderToHydratableString(component, props) {
|
|
1617
|
+
const ctx = createHydrationContext();
|
|
1618
|
+
const mergedProps = props ?? {};
|
|
1619
|
+
const instance = createComponentInstance(component, mergedProps, null);
|
|
1620
|
+
const prev = setCurrentInstance(instance);
|
|
1621
|
+
try {
|
|
1622
|
+
const result = await component(mergedProps);
|
|
1623
|
+
if (result && typeof result === "object" && "tag" in result) {
|
|
1624
|
+
return renderElementH(result, ctx, true);
|
|
1625
|
+
}
|
|
1626
|
+
return renderNodeH(result, ctx);
|
|
1627
|
+
} finally {
|
|
1628
|
+
setCurrentInstance(prev);
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
async function renderNodeToHydratableString(node) {
|
|
1632
|
+
const ctx = createHydrationContext();
|
|
1633
|
+
return renderNodeH(node, ctx);
|
|
1634
|
+
}
|
|
1635
|
+
var VOID_ELEMENTS5 = new Set([
|
|
1636
|
+
"area",
|
|
1637
|
+
"base",
|
|
1638
|
+
"br",
|
|
1639
|
+
"col",
|
|
1640
|
+
"embed",
|
|
1641
|
+
"hr",
|
|
1642
|
+
"img",
|
|
1643
|
+
"input",
|
|
1644
|
+
"link",
|
|
1645
|
+
"meta",
|
|
1646
|
+
"param",
|
|
1647
|
+
"source",
|
|
1648
|
+
"track",
|
|
1649
|
+
"wbr"
|
|
1650
|
+
]);
|
|
1651
|
+
function renderNodeH(node, ctx) {
|
|
1652
|
+
if (node == null || typeof node === "boolean")
|
|
1653
|
+
return "";
|
|
1654
|
+
if (typeof node === "string")
|
|
1655
|
+
return escapeHtml(node);
|
|
1656
|
+
if (typeof node === "number")
|
|
1657
|
+
return String(node);
|
|
1658
|
+
if (node instanceof HtmlEscapedString)
|
|
1659
|
+
return node.value;
|
|
1660
|
+
if (isSignal(node) || isComputed(node)) {
|
|
1661
|
+
const value = node.value;
|
|
1662
|
+
const idx = ctx.textIndex++;
|
|
1663
|
+
return `${textMarkerOpen(idx)}${escapeHtml(String(value))}${textMarkerCloseStr()}`;
|
|
1664
|
+
}
|
|
1665
|
+
if (Array.isArray(node)) {
|
|
1666
|
+
return node.map((child) => renderNodeH(child, ctx)).join("");
|
|
1667
|
+
}
|
|
1668
|
+
if (node instanceof Promise) {
|
|
1669
|
+
return "";
|
|
1670
|
+
}
|
|
1671
|
+
if (typeof node === "object" && "tag" in node) {
|
|
1672
|
+
return renderElementH(node, ctx, false);
|
|
1673
|
+
}
|
|
1674
|
+
return escapeHtml(String(node));
|
|
1675
|
+
}
|
|
1676
|
+
function renderElementH(element, ctx, isComponentRoot) {
|
|
1677
|
+
const { tag, props, children } = element;
|
|
1678
|
+
if (tag === "") {
|
|
1679
|
+
return children.map((child) => renderNodeH(child, ctx)).join("");
|
|
1680
|
+
}
|
|
1681
|
+
if (tag === Show || tag === For) {
|
|
1682
|
+
return renderElementH(tag(props), ctx, isComponentRoot);
|
|
1683
|
+
}
|
|
1684
|
+
if (isShowElement(element)) {
|
|
1685
|
+
const when = readReactive4(props.when);
|
|
1686
|
+
const content = when ? resolveShowChildren4(element, when) : props.fallback;
|
|
1687
|
+
return renderNodeMaybeRoot(content, ctx, isComponentRoot);
|
|
1688
|
+
}
|
|
1689
|
+
if (isForElement(element)) {
|
|
1690
|
+
return renderForElementH(element, ctx);
|
|
1691
|
+
}
|
|
1692
|
+
if (typeof tag === "function") {
|
|
1693
|
+
return renderComponentH(tag, props, ctx);
|
|
1694
|
+
}
|
|
1695
|
+
if (typeof tag === "string") {
|
|
1696
|
+
return renderIntrinsicH(tag, props, children, ctx, isComponentRoot);
|
|
1697
|
+
}
|
|
1698
|
+
return children.map((child) => renderNodeH(child, ctx)).join("");
|
|
1699
|
+
}
|
|
1700
|
+
function renderComponentH(component, props, ctx) {
|
|
1701
|
+
const parentInstance = getCurrentInstance();
|
|
1702
|
+
const instance = createComponentInstance(component, props, parentInstance);
|
|
1703
|
+
if (parentInstance) {
|
|
1704
|
+
parentInstance.children.push(instance);
|
|
1705
|
+
}
|
|
1706
|
+
const prev = setCurrentInstance(instance);
|
|
1707
|
+
try {
|
|
1708
|
+
const result = component(props);
|
|
1709
|
+
if (result && typeof result === "object" && "tag" in result) {
|
|
1710
|
+
return renderElementH(result, ctx, true);
|
|
1711
|
+
}
|
|
1712
|
+
return renderNodeH(result, ctx);
|
|
1713
|
+
} finally {
|
|
1714
|
+
setCurrentInstance(prev);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
function renderIntrinsicH(tag, props, children, ctx, isComponentRoot) {
|
|
1718
|
+
let attrs = "";
|
|
1719
|
+
if (isComponentRoot) {
|
|
1720
|
+
attrs += ` ${COMP_ID_ATTR}="${compId(ctx.componentIndex++)}"`;
|
|
1721
|
+
}
|
|
1722
|
+
const eventParts = [];
|
|
1723
|
+
for (const [key, value] of Object.entries(props)) {
|
|
1724
|
+
if (key === "children" || key === "key" || key === "ref" || key === "dangerouslySetInnerHTML") {
|
|
1725
|
+
continue;
|
|
1726
|
+
}
|
|
1727
|
+
if (isEventProp(key)) {
|
|
1728
|
+
const eventName = toEventName(key);
|
|
1729
|
+
eventParts.push(`${eventName}:${ctx.eventIndex++}`);
|
|
1730
|
+
continue;
|
|
1731
|
+
}
|
|
1732
|
+
if (value == null || value === false)
|
|
1733
|
+
continue;
|
|
1734
|
+
let resolvedValue = value;
|
|
1735
|
+
if (isSignal(value) || isComputed(value)) {
|
|
1736
|
+
resolvedValue = value.value;
|
|
1737
|
+
}
|
|
1738
|
+
if (resolvedValue === true) {
|
|
1739
|
+
const attrName2 = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
1740
|
+
attrs += ` ${attrName2}`;
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
1744
|
+
attrs += ` ${attrName}="${escapeHtml(String(resolvedValue))}"`;
|
|
1745
|
+
}
|
|
1746
|
+
if (eventParts.length > 0) {
|
|
1747
|
+
attrs += ` ${EVENT_ATTR}="${eventParts.join(",")}"`;
|
|
1748
|
+
}
|
|
1749
|
+
if (VOID_ELEMENTS5.has(tag)) {
|
|
1750
|
+
return `<${tag}${attrs}>`;
|
|
1751
|
+
}
|
|
1752
|
+
const dangerous = props.dangerouslySetInnerHTML;
|
|
1753
|
+
if (dangerous && typeof dangerous.__html === "string") {
|
|
1754
|
+
return `<${tag}${attrs}>${dangerous.__html}</${tag}>`;
|
|
1755
|
+
}
|
|
1756
|
+
const childrenHtml = children.map((child) => renderNodeH(child, ctx)).join("");
|
|
1757
|
+
return `<${tag}${attrs}>${childrenHtml}</${tag}>`;
|
|
1758
|
+
}
|
|
1759
|
+
function renderNodeMaybeRoot(node, ctx, isComponentRoot) {
|
|
1760
|
+
if (isComponentRoot && node && typeof node === "object" && !Array.isArray(node) && "tag" in node) {
|
|
1761
|
+
return renderElementH(node, ctx, true);
|
|
1762
|
+
}
|
|
1763
|
+
return renderNodeH(node, ctx);
|
|
1764
|
+
}
|
|
1765
|
+
function renderForElementH(element, ctx) {
|
|
1766
|
+
const props = element.props;
|
|
1767
|
+
const each = readReactive4(props.each);
|
|
1768
|
+
if (!Array.isArray(each) || typeof props.children !== "function") {
|
|
1769
|
+
return "";
|
|
1770
|
+
}
|
|
1771
|
+
return each.map((item, index) => renderNodeH(props.children(item, () => index), ctx)).join("");
|
|
1772
|
+
}
|
|
1773
|
+
function resolveShowChildren4(element, value) {
|
|
1774
|
+
const children = element.props.children ?? element.children;
|
|
1775
|
+
if (typeof children === "function") {
|
|
1776
|
+
return children(value);
|
|
1777
|
+
}
|
|
1778
|
+
return children;
|
|
1779
|
+
}
|
|
1780
|
+
function readReactive4(value) {
|
|
1781
|
+
return isSignal(value) || isComputed(value) ? value.value : value;
|
|
1782
|
+
}
|
|
1783
|
+
// src/reactivity/batch.ts
|
|
1784
|
+
var batchDepth = 0;
|
|
1785
|
+
function batch(fn) {
|
|
1786
|
+
batchDepth++;
|
|
1787
|
+
try {
|
|
1788
|
+
fn();
|
|
1789
|
+
} finally {
|
|
1790
|
+
batchDepth--;
|
|
1791
|
+
if (batchDepth === 0) {
|
|
1792
|
+
flushSync();
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
// src/component/lifecycle.ts
|
|
1797
|
+
function onMounted(fn) {
|
|
1798
|
+
const instance = getCurrentInstance();
|
|
1799
|
+
if (!instance) {
|
|
1800
|
+
throw new Error("onMounted() called outside of component setup.");
|
|
1801
|
+
}
|
|
1802
|
+
instance._mountedHooks.push(() => withInstance(instance, fn));
|
|
1803
|
+
}
|
|
1804
|
+
function onUnmounted(fn) {
|
|
1805
|
+
const instance = getCurrentInstance();
|
|
1806
|
+
if (!instance) {
|
|
1807
|
+
throw new Error("onUnmounted() called outside of component setup.");
|
|
1808
|
+
}
|
|
1809
|
+
instance._unmountedHooks.push(() => withInstance(instance, fn));
|
|
1810
|
+
}
|
|
1811
|
+
function onUpdated(fn) {
|
|
1812
|
+
const instance = getCurrentInstance();
|
|
1813
|
+
if (!instance) {
|
|
1814
|
+
throw new Error("onUpdated() called outside of component setup.");
|
|
1815
|
+
}
|
|
1816
|
+
instance._updatedHooks.push(() => withInstance(instance, fn));
|
|
1817
|
+
}
|
|
1818
|
+
function onError(fn) {
|
|
1819
|
+
const instance = getCurrentInstance();
|
|
1820
|
+
if (!instance) {
|
|
1821
|
+
throw new Error("onError() called outside of component setup.");
|
|
1822
|
+
}
|
|
1823
|
+
instance._errorHooks.push((err) => withInstance(instance, () => fn(err)));
|
|
1824
|
+
}
|
|
1825
|
+
// src/component/create.ts
|
|
1826
|
+
function createComponent(fn) {
|
|
1827
|
+
const component = (props) => fn(props);
|
|
1828
|
+
component._SinwanComponent = true;
|
|
1829
|
+
component._displayName = fn.name || "AnonymousComponent";
|
|
1830
|
+
return component;
|
|
1831
|
+
}
|
|
1832
|
+
function createPage(fn) {
|
|
1833
|
+
const page = (data) => fn(data);
|
|
1834
|
+
page._SinwanPage = true;
|
|
1835
|
+
page._displayName = fn.name || "AnonymousPage";
|
|
1836
|
+
return page;
|
|
1837
|
+
}
|
|
1838
|
+
function createLayout(fn) {
|
|
1839
|
+
return createComponent(fn);
|
|
1840
|
+
}
|
|
1841
|
+
// src/component/provide-inject.ts
|
|
1842
|
+
function provide(key, value) {
|
|
1843
|
+
const instance = getCurrentInstance();
|
|
1844
|
+
if (!instance) {
|
|
1845
|
+
throw new Error("provide() called outside of component setup.");
|
|
1846
|
+
}
|
|
1847
|
+
instance.provides[key] = value;
|
|
1848
|
+
}
|
|
1849
|
+
function inject(key, defaultValue) {
|
|
1850
|
+
const instance = getCurrentInstance();
|
|
1851
|
+
if (!instance) {
|
|
1852
|
+
throw new Error("inject() called outside of component setup.");
|
|
1853
|
+
}
|
|
1854
|
+
if (key in instance.provides) {
|
|
1855
|
+
return instance.provides[key];
|
|
1856
|
+
}
|
|
1857
|
+
if (arguments.length >= 2) {
|
|
1858
|
+
return defaultValue;
|
|
1859
|
+
}
|
|
1860
|
+
console.warn(`[Sinwan] inject() key "${String(key)}" not found and no default provided.`);
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
// src/hydration/walk.ts
|
|
1864
|
+
function advance(cursor) {
|
|
1865
|
+
const node = cursor.current;
|
|
1866
|
+
if (node) {
|
|
1867
|
+
cursor.current = node.nextSibling;
|
|
1868
|
+
}
|
|
1869
|
+
return node;
|
|
1870
|
+
}
|
|
1871
|
+
function hydrateNode(node, cursor) {
|
|
1872
|
+
if (node == null || typeof node === "boolean") {
|
|
1873
|
+
const textNode2 = advance(cursor);
|
|
1874
|
+
return { type: "text", node: textNode2 ?? document.createTextNode("") };
|
|
1875
|
+
}
|
|
1876
|
+
if (typeof node === "string") {
|
|
1877
|
+
const textNode2 = advance(cursor);
|
|
1878
|
+
return { type: "text", node: textNode2 };
|
|
1879
|
+
}
|
|
1880
|
+
if (typeof node === "number") {
|
|
1881
|
+
const textNode2 = advance(cursor);
|
|
1882
|
+
return { type: "text", node: textNode2 };
|
|
1883
|
+
}
|
|
1884
|
+
if (node instanceof HtmlEscapedString) {
|
|
1885
|
+
const textNode2 = advance(cursor);
|
|
1886
|
+
return { type: "text", node: textNode2 };
|
|
1887
|
+
}
|
|
1888
|
+
if (isSignal(node) || isComputed(node)) {
|
|
1889
|
+
return hydrateReactiveText(node, cursor);
|
|
1890
|
+
}
|
|
1891
|
+
if (Array.isArray(node)) {
|
|
1892
|
+
return hydrateArray(node, cursor);
|
|
1336
1893
|
}
|
|
1337
1894
|
if (typeof node === "object" && node !== null && "tag" in node) {
|
|
1338
1895
|
return hydrateElement(node, cursor);
|
|
@@ -1342,6 +1899,7 @@ function hydrateNode(node, cursor) {
|
|
|
1342
1899
|
}
|
|
1343
1900
|
function hydrateReactiveText(reactive, cursor) {
|
|
1344
1901
|
const openComment = cursor.current;
|
|
1902
|
+
const owner = getCurrentInstance();
|
|
1345
1903
|
if (openComment && openComment.nodeType === 8 && parseTextOpenMarker(openComment) >= 0) {
|
|
1346
1904
|
advance(cursor);
|
|
1347
1905
|
const textNode2 = advance(cursor);
|
|
@@ -1349,21 +1907,36 @@ function hydrateReactiveText(reactive, cursor) {
|
|
|
1349
1907
|
if (closeComment && closeComment.nodeType === 8 && isTextCloseMarker(closeComment)) {
|
|
1350
1908
|
advance(cursor);
|
|
1351
1909
|
}
|
|
1910
|
+
let initialized2 = false;
|
|
1352
1911
|
const dispose2 = effect(() => {
|
|
1353
1912
|
textNode2.data = String(reactive.value);
|
|
1913
|
+
if (initialized2) {
|
|
1914
|
+
queueUpdatedHooks(owner);
|
|
1915
|
+
}
|
|
1916
|
+
initialized2 = true;
|
|
1354
1917
|
});
|
|
1355
1918
|
return { type: "reactive-text", node: textNode2, dispose: dispose2 };
|
|
1356
1919
|
}
|
|
1357
1920
|
const textNode = advance(cursor);
|
|
1358
1921
|
if (textNode) {
|
|
1922
|
+
let initialized2 = false;
|
|
1359
1923
|
const dispose2 = effect(() => {
|
|
1360
1924
|
textNode.data = String(reactive.value);
|
|
1925
|
+
if (initialized2) {
|
|
1926
|
+
queueUpdatedHooks(owner);
|
|
1927
|
+
}
|
|
1928
|
+
initialized2 = true;
|
|
1361
1929
|
});
|
|
1362
1930
|
return { type: "reactive-text", node: textNode, dispose: dispose2 };
|
|
1363
1931
|
}
|
|
1364
1932
|
const newText = document.createTextNode(String(reactive.value));
|
|
1933
|
+
let initialized = false;
|
|
1365
1934
|
const dispose = effect(() => {
|
|
1366
1935
|
newText.data = String(reactive.value);
|
|
1936
|
+
if (initialized) {
|
|
1937
|
+
queueUpdatedHooks(owner);
|
|
1938
|
+
}
|
|
1939
|
+
initialized = true;
|
|
1367
1940
|
});
|
|
1368
1941
|
return { type: "reactive-text", node: newText, dispose };
|
|
1369
1942
|
}
|
|
@@ -1372,6 +1945,12 @@ function hydrateElement(element, cursor) {
|
|
|
1372
1945
|
if (tag === "") {
|
|
1373
1946
|
return hydrateArray(children, cursor);
|
|
1374
1947
|
}
|
|
1948
|
+
if (tag === Show || tag === For) {
|
|
1949
|
+
return hydrateElement(tag(props), cursor);
|
|
1950
|
+
}
|
|
1951
|
+
if (isShowElement(element) || isForElement(element)) {
|
|
1952
|
+
return hydrateControlFlow(element, cursor);
|
|
1953
|
+
}
|
|
1375
1954
|
if (typeof tag === "function") {
|
|
1376
1955
|
return hydrateComponent(tag, props, cursor);
|
|
1377
1956
|
}
|
|
@@ -1390,6 +1969,7 @@ function hydrateIntrinsic(tag, props, children, cursor) {
|
|
|
1390
1969
|
el.removeAttribute("data-sinwan-ev");
|
|
1391
1970
|
const attrDisposers = hydrateAttributes(el, props);
|
|
1392
1971
|
const eventCleanups = bindEvents(el, props);
|
|
1972
|
+
const refCleanup = applyRef2(el, props.ref);
|
|
1393
1973
|
const childCursor = {
|
|
1394
1974
|
parent: el,
|
|
1395
1975
|
current: el.firstChild
|
|
@@ -1403,15 +1983,18 @@ function hydrateIntrinsic(tag, props, children, cursor) {
|
|
|
1403
1983
|
node: el,
|
|
1404
1984
|
children: mountedChildren,
|
|
1405
1985
|
eventCleanups,
|
|
1406
|
-
attrDisposers
|
|
1986
|
+
attrDisposers,
|
|
1987
|
+
refCleanup
|
|
1407
1988
|
};
|
|
1408
1989
|
}
|
|
1409
1990
|
function hydrateAttributes(el, props) {
|
|
1410
1991
|
const disposers = [];
|
|
1992
|
+
const owner = getCurrentInstance();
|
|
1411
1993
|
for (const [key, value] of Object.entries(props)) {
|
|
1412
1994
|
if (key === "children" || key === "key" || key === "ref" || isEventProp(key))
|
|
1413
1995
|
continue;
|
|
1414
1996
|
if (isSignal(value) || isComputed(value)) {
|
|
1997
|
+
let initialized = false;
|
|
1415
1998
|
const dispose = effect(() => {
|
|
1416
1999
|
const v = value.value;
|
|
1417
2000
|
const attrName = key === "className" ? "class" : key === "htmlFor" ? "for" : key;
|
|
@@ -1422,12 +2005,63 @@ function hydrateAttributes(el, props) {
|
|
|
1422
2005
|
} else {
|
|
1423
2006
|
el.setAttribute(attrName, String(v));
|
|
1424
2007
|
}
|
|
2008
|
+
if (initialized) {
|
|
2009
|
+
queueUpdatedHooks(owner);
|
|
2010
|
+
}
|
|
2011
|
+
initialized = true;
|
|
1425
2012
|
});
|
|
1426
2013
|
disposers.push(dispose);
|
|
1427
2014
|
}
|
|
1428
2015
|
}
|
|
1429
2016
|
return disposers;
|
|
1430
2017
|
}
|
|
2018
|
+
function hydrateControlFlow(element, cursor) {
|
|
2019
|
+
if (isShowElement(element)) {
|
|
2020
|
+
const when = readReactive5(element.props.when);
|
|
2021
|
+
const content = when ? resolveShowChildren5(element, when) : element.props.fallback;
|
|
2022
|
+
return hydrateContent(content, cursor);
|
|
2023
|
+
}
|
|
2024
|
+
if (isForElement(element)) {
|
|
2025
|
+
const props = element.props;
|
|
2026
|
+
const items = readReactive5(props.each);
|
|
2027
|
+
const children = Array.isArray(items) && typeof props.children === "function" ? items.map((item, index) => props.children(item, () => index)) : [];
|
|
2028
|
+
return hydrateArray(children, cursor);
|
|
2029
|
+
}
|
|
2030
|
+
return hydrateArray(element.children, cursor);
|
|
2031
|
+
}
|
|
2032
|
+
function hydrateContent(content, cursor) {
|
|
2033
|
+
if (content == null || typeof content === "boolean") {
|
|
2034
|
+
return hydrateArray([], cursor);
|
|
2035
|
+
}
|
|
2036
|
+
return Array.isArray(content) ? hydrateArray(content, cursor) : hydrateNode(content, cursor);
|
|
2037
|
+
}
|
|
2038
|
+
function resolveShowChildren5(element, value) {
|
|
2039
|
+
const children = element.props.children ?? element.children;
|
|
2040
|
+
if (typeof children === "function") {
|
|
2041
|
+
return children(value);
|
|
2042
|
+
}
|
|
2043
|
+
return children;
|
|
2044
|
+
}
|
|
2045
|
+
function readReactive5(value) {
|
|
2046
|
+
return isSignal(value) || isComputed(value) ? value.value : value;
|
|
2047
|
+
}
|
|
2048
|
+
function applyRef2(el, ref) {
|
|
2049
|
+
const value = ref;
|
|
2050
|
+
if (!value) {
|
|
2051
|
+
return null;
|
|
2052
|
+
}
|
|
2053
|
+
if (typeof value === "function") {
|
|
2054
|
+
value(el);
|
|
2055
|
+
return () => value(null);
|
|
2056
|
+
}
|
|
2057
|
+
if (typeof value === "object" && "current" in value) {
|
|
2058
|
+
value.current = el;
|
|
2059
|
+
return () => {
|
|
2060
|
+
value.current = null;
|
|
2061
|
+
};
|
|
2062
|
+
}
|
|
2063
|
+
return null;
|
|
2064
|
+
}
|
|
1431
2065
|
function hydrateComponent(component, props, cursor) {
|
|
1432
2066
|
const parentInstance = getCurrentInstance();
|
|
1433
2067
|
const instance = createComponentInstance(component, props, parentInstance);
|
|
@@ -1516,8 +2150,12 @@ function hydrate(component, container, props) {
|
|
|
1516
2150
|
export {
|
|
1517
2151
|
unmountNode,
|
|
1518
2152
|
streamPage,
|
|
2153
|
+
streamHydratablePage,
|
|
2154
|
+
streamHydratableNode,
|
|
1519
2155
|
signal,
|
|
2156
|
+
setDOMOps,
|
|
1520
2157
|
safeHtml,
|
|
2158
|
+
resetDOMOps,
|
|
1521
2159
|
renderToString,
|
|
1522
2160
|
renderToHydratableString,
|
|
1523
2161
|
renderPage,
|
|
@@ -1547,14 +2185,17 @@ export {
|
|
|
1547
2185
|
getCurrentInstance,
|
|
1548
2186
|
escapeHtml,
|
|
1549
2187
|
effect,
|
|
2188
|
+
domOps,
|
|
1550
2189
|
createPage,
|
|
1551
2190
|
createLayout,
|
|
1552
2191
|
createComponent,
|
|
1553
2192
|
computed,
|
|
1554
2193
|
batch,
|
|
2194
|
+
Show,
|
|
1555
2195
|
HtmlEscapedString,
|
|
1556
|
-
Fragment
|
|
2196
|
+
Fragment,
|
|
2197
|
+
For
|
|
1557
2198
|
};
|
|
1558
2199
|
|
|
1559
|
-
//# debugId=
|
|
2200
|
+
//# debugId=14DE79AF90B411D764756E2164756E21
|
|
1560
2201
|
//# sourceMappingURL=index.development.js.map
|