cajoa 0.4.0 → 0.5.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 +15 -3
- package/dist/index.cjs +84 -52
- package/dist/index.d.cts +22 -3
- package/dist/index.d.ts +22 -3
- package/dist/index.js +81 -52
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
A small, beginner-friendly frontend framework built on **signals** and **JSX**.
|
|
4
4
|
No virtual DOM, no hooks rules, no re-rendering components.
|
|
5
5
|
|
|
6
|
-
> ⚠️ **v0.
|
|
6
|
+
> ⚠️ **v0.5 (early stage).** The API may still change. Not production-ready yet.
|
|
7
7
|
|
|
8
8
|
## Why Cajoa?
|
|
9
9
|
|
|
@@ -15,7 +15,7 @@ No virtual DOM, no hooks rules, no re-rendering components.
|
|
|
15
15
|
## Install
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
npm
|
|
18
|
+
npm create cajoa@latest my-app
|
|
19
19
|
```
|
|
20
20
|
|
|
21
21
|
## Setup (JSX)
|
|
@@ -159,6 +159,14 @@ Routes are matched in order, so put `path="*"` last.
|
|
|
159
159
|
| `usePath()` | Returns a signal getter for the current pathname. |
|
|
160
160
|
| `untrack(fn)` | Runs `fn` without subscribing to signals. |
|
|
161
161
|
|
|
162
|
+
### Renderer
|
|
163
|
+
|
|
164
|
+
| Function | What it does |
|
|
165
|
+
| ----------------------- | ------------------------------------------------------------------ |
|
|
166
|
+
| `setRenderer(renderer)` | Swaps the renderer (default: DOM). Used to target other platforms. |
|
|
167
|
+
| `getRenderer()` | Returns the current renderer. |
|
|
168
|
+
| `domRenderer` | The built-in DOM renderer. |
|
|
169
|
+
|
|
162
170
|
## Good to know
|
|
163
171
|
|
|
164
172
|
- `For` uses the item itself as the key by default. If you pass `key`, items with the same key are **not** re-rendered when their data changes, so keys must be unique and the item should hold its own signals if it needs to update.
|
|
@@ -174,6 +182,7 @@ Routes are matched in order, so put `path="*"` last.
|
|
|
174
182
|
- Single-page apps need a server fallback to `index.html` for unknown paths.
|
|
175
183
|
- `createMemo` can show a brief inconsistent state when memos depend on each other.
|
|
176
184
|
- `set` calls are not batched automatically inside event handlers. Wrap them in `batch()`.
|
|
185
|
+
- The Router and event names (`onClick`) are still web-specific for now.
|
|
177
186
|
|
|
178
187
|
## Roadmap
|
|
179
188
|
|
|
@@ -185,8 +194,11 @@ Routes are matched in order, so put `path="*"` last.
|
|
|
185
194
|
- [x] Context
|
|
186
195
|
- [x] JSX support
|
|
187
196
|
- [x] Fragments
|
|
188
|
-
- [ ] Vite plugin (removes the two rules above)
|
|
189
197
|
- [x] Router
|
|
198
|
+
- [x] Renderer abstraction (core no longer depends on DOM)
|
|
199
|
+
- [ ] Split into packages ('@cajoa/core', '@cajoa/dom')
|
|
200
|
+
- [ ] Vite plugin (removes the two rules above)
|
|
201
|
+
- [ ] Native renderer (mobile, desktop)
|
|
190
202
|
- [ ] SSR
|
|
191
203
|
|
|
192
204
|
## Development
|
package/dist/index.cjs
CHANGED
|
@@ -32,6 +32,8 @@ __export(index_exports, {
|
|
|
32
32
|
createMemo: () => createMemo,
|
|
33
33
|
createRoot: () => createRoot,
|
|
34
34
|
createSignal: () => createSignal,
|
|
35
|
+
domRenderer: () => domRenderer,
|
|
36
|
+
getRenderer: () => getRenderer,
|
|
35
37
|
h: () => h,
|
|
36
38
|
jsx: () => jsx,
|
|
37
39
|
jsxDEV: () => jsxDEV,
|
|
@@ -41,6 +43,7 @@ __export(index_exports, {
|
|
|
41
43
|
onMount: () => onMount,
|
|
42
44
|
provide: () => provide,
|
|
43
45
|
render: () => render,
|
|
46
|
+
setRenderer: () => setRenderer,
|
|
44
47
|
untrack: () => untrack,
|
|
45
48
|
useContext: () => useContext,
|
|
46
49
|
useParams: () => useParams,
|
|
@@ -190,83 +193,109 @@ function untrack(fn) {
|
|
|
190
193
|
}
|
|
191
194
|
}
|
|
192
195
|
|
|
196
|
+
// src/renderer/dom.ts
|
|
197
|
+
var domRenderer = {
|
|
198
|
+
createElement: (tag) => document.createElement(tag),
|
|
199
|
+
createText: (value) => document.createTextNode(value),
|
|
200
|
+
createMarker: () => document.createComment(""),
|
|
201
|
+
createFragment: () => document.createDocumentFragment(),
|
|
202
|
+
isNode: (v) => typeof Node !== "undefined" && v instanceof Node,
|
|
203
|
+
insert: (parent, node, anchor = null) => {
|
|
204
|
+
parent.insertBefore(node, anchor);
|
|
205
|
+
},
|
|
206
|
+
remove: (node) => {
|
|
207
|
+
node.remove();
|
|
208
|
+
},
|
|
209
|
+
nextSibling: (node) => node.nextSibling,
|
|
210
|
+
parentNode: (node) => node.parentNode,
|
|
211
|
+
clear: (parent) => {
|
|
212
|
+
parent.replaceChildren();
|
|
213
|
+
},
|
|
214
|
+
setProp(el, key, value) {
|
|
215
|
+
const e = el;
|
|
216
|
+
if (key.startsWith("on") && typeof value === "function") {
|
|
217
|
+
e.addEventListener(key.slice(2).toLowerCase(), value);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const name = key === "className" ? "class" : key;
|
|
221
|
+
if (value == null || value === false) e.removeAttribute(name);
|
|
222
|
+
else e.setAttribute(name, value === true ? "" : String(value));
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/renderer/index.ts
|
|
227
|
+
var current = domRenderer;
|
|
228
|
+
function setRenderer(renderer) {
|
|
229
|
+
current = renderer;
|
|
230
|
+
}
|
|
231
|
+
function getRenderer() {
|
|
232
|
+
return current;
|
|
233
|
+
}
|
|
234
|
+
|
|
193
235
|
// src/dom/h.ts
|
|
194
236
|
function h(tag, props, ...children) {
|
|
195
|
-
const
|
|
237
|
+
const r = getRenderer();
|
|
238
|
+
const el = r.createElement(tag);
|
|
196
239
|
for (const [key, value] of Object.entries(props ?? {})) {
|
|
197
|
-
|
|
240
|
+
if (typeof value === "function" && !key.startsWith("on")) {
|
|
241
|
+
createEffect(() => r.setProp(el, key, value()));
|
|
242
|
+
} else {
|
|
243
|
+
r.setProp(el, key, value);
|
|
244
|
+
}
|
|
198
245
|
}
|
|
199
246
|
appendChildren(el, children);
|
|
200
247
|
return el;
|
|
201
248
|
}
|
|
202
|
-
function setProp(el, key, value) {
|
|
203
|
-
if (key.startsWith("on") && typeof value === "function") {
|
|
204
|
-
el.addEventListener(key.slice(2).toLowerCase(), value);
|
|
205
|
-
} else if (typeof value === "function") {
|
|
206
|
-
createEffect(() => applyAttr(el, key, value()));
|
|
207
|
-
} else {
|
|
208
|
-
applyAttr(el, key, value);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
function applyAttr(el, key, value) {
|
|
212
|
-
const name = key === "className" ? "class" : key;
|
|
213
|
-
if (value == null || value === false) el.removeAttribute(name);
|
|
214
|
-
else el.setAttribute(name, value === true ? "" : String(value));
|
|
215
|
-
}
|
|
216
249
|
function toNodes(value) {
|
|
250
|
+
const r = getRenderer();
|
|
217
251
|
const out = [];
|
|
218
252
|
for (const v of [value].flat(Infinity)) {
|
|
219
253
|
if (v == null || typeof v === "boolean") continue;
|
|
220
|
-
out.push(v
|
|
254
|
+
out.push(r.isNode(v) ? v : r.createText(String(v)));
|
|
221
255
|
}
|
|
222
256
|
return out;
|
|
223
257
|
}
|
|
224
|
-
function appendChildren(parent, children) {
|
|
225
|
-
const pending2 = [...children].reverse();
|
|
226
|
-
while (pending2.length > 0) {
|
|
227
|
-
const child = pending2.pop();
|
|
228
|
-
if (Array.isArray(child)) {
|
|
229
|
-
for (let i = child.length - 1; i >= 0; i--) {
|
|
230
|
-
pending2.push(child[i]);
|
|
231
|
-
}
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
if (typeof child === "function") {
|
|
235
|
-
const start = document.createComment("");
|
|
236
|
-
const end = document.createComment("");
|
|
237
|
-
parent.append(start, end);
|
|
238
|
-
createEffect(() => {
|
|
239
|
-
reconcile(start, end, toNodes(child()));
|
|
240
|
-
});
|
|
241
|
-
} else {
|
|
242
|
-
parent.append(...toNodes(child));
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
258
|
function reconcile(start, end, next) {
|
|
259
|
+
const r = getRenderer();
|
|
247
260
|
const keep = new Set(next);
|
|
248
|
-
let cur =
|
|
261
|
+
let cur = r.nextSibling(start);
|
|
249
262
|
while (cur && cur !== end) {
|
|
250
|
-
const after =
|
|
251
|
-
if (!keep.has(cur))
|
|
263
|
+
const after = r.nextSibling(cur);
|
|
264
|
+
if (!keep.has(cur)) r.remove(cur);
|
|
252
265
|
cur = after;
|
|
253
266
|
}
|
|
254
|
-
const parent =
|
|
255
|
-
let ref =
|
|
267
|
+
const parent = r.parentNode(end);
|
|
268
|
+
let ref = r.nextSibling(start);
|
|
256
269
|
for (const node of next) {
|
|
257
|
-
if (node === ref)
|
|
258
|
-
|
|
259
|
-
|
|
270
|
+
if (node === ref) ref = r.nextSibling(ref);
|
|
271
|
+
else r.insert(parent, node, ref);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
function appendChildren(parent, children) {
|
|
275
|
+
const r = getRenderer();
|
|
276
|
+
for (const child of children.flat(Infinity)) {
|
|
277
|
+
if (typeof child === "function") {
|
|
278
|
+
const start = r.createMarker();
|
|
279
|
+
const end = r.createMarker();
|
|
280
|
+
r.insert(parent, start);
|
|
281
|
+
r.insert(parent, end);
|
|
282
|
+
createEffect(() => reconcile(start, end, toNodes(child())));
|
|
283
|
+
} else {
|
|
284
|
+
for (const node of toNodes(child)) r.insert(parent, node);
|
|
285
|
+
}
|
|
260
286
|
}
|
|
261
287
|
}
|
|
262
288
|
|
|
263
289
|
// src/dom/render.ts
|
|
264
290
|
function render(component, container) {
|
|
265
291
|
return createRoot((dispose) => {
|
|
266
|
-
|
|
292
|
+
const r = getRenderer();
|
|
293
|
+
const node = component();
|
|
294
|
+
r.clear(container);
|
|
295
|
+
r.insert(container, node);
|
|
267
296
|
return () => {
|
|
268
297
|
dispose();
|
|
269
|
-
|
|
298
|
+
r.clear(container);
|
|
270
299
|
};
|
|
271
300
|
});
|
|
272
301
|
}
|
|
@@ -325,7 +354,7 @@ function jsx(type, props) {
|
|
|
325
354
|
var jsxs = jsx;
|
|
326
355
|
var jsxDEV = jsx;
|
|
327
356
|
function Fragment(props) {
|
|
328
|
-
const frag =
|
|
357
|
+
const frag = getRenderer().createFragment();
|
|
329
358
|
appendChildren(frag, props.children === void 0 ? [] : [props.children]);
|
|
330
359
|
return frag;
|
|
331
360
|
}
|
|
@@ -378,9 +407,9 @@ function Router(props) {
|
|
|
378
407
|
(r) => r?.__route === true
|
|
379
408
|
);
|
|
380
409
|
return () => {
|
|
381
|
-
const
|
|
410
|
+
const current2 = path();
|
|
382
411
|
for (const route of routes) {
|
|
383
|
-
const params = match(route.path,
|
|
412
|
+
const params = match(route.path, current2);
|
|
384
413
|
if (params) {
|
|
385
414
|
return untrack(() => provide(Params, params, () => route.component()));
|
|
386
415
|
}
|
|
@@ -413,6 +442,8 @@ function Link(props) {
|
|
|
413
442
|
createMemo,
|
|
414
443
|
createRoot,
|
|
415
444
|
createSignal,
|
|
445
|
+
domRenderer,
|
|
446
|
+
getRenderer,
|
|
416
447
|
h,
|
|
417
448
|
jsx,
|
|
418
449
|
jsxDEV,
|
|
@@ -422,6 +453,7 @@ function Link(props) {
|
|
|
422
453
|
onMount,
|
|
423
454
|
provide,
|
|
424
455
|
render,
|
|
456
|
+
setRenderer,
|
|
425
457
|
untrack,
|
|
426
458
|
useContext,
|
|
427
459
|
useParams,
|
package/dist/index.d.cts
CHANGED
|
@@ -47,7 +47,7 @@ declare namespace JSX {
|
|
|
47
47
|
}
|
|
48
48
|
declare function Fragment(props: {
|
|
49
49
|
children?: Child;
|
|
50
|
-
}):
|
|
50
|
+
}): any;
|
|
51
51
|
|
|
52
52
|
declare function navigate(to: string, options?: {
|
|
53
53
|
replace?: boolean;
|
|
@@ -72,5 +72,24 @@ declare function Link(props: {
|
|
|
72
72
|
[key: string]: unknown;
|
|
73
73
|
}): HTMLElement;
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
interface Renderer<N = any> {
|
|
76
|
+
createElement(tag: string): N;
|
|
77
|
+
createText(value: string): N;
|
|
78
|
+
createMarker(): N;
|
|
79
|
+
createFragment(): N;
|
|
80
|
+
isNode(value: unknown): value is N;
|
|
81
|
+
insert(parent: N, node: N, anchor?: N | null): void;
|
|
82
|
+
remove(node: N): void;
|
|
83
|
+
nextSibling(node: N): N | null;
|
|
84
|
+
parentNode(node: N): N | null;
|
|
85
|
+
clear(parent: N): void;
|
|
86
|
+
setProp(el: N, name: string, value: unknown): void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
declare function setRenderer(renderer: Renderer): void;
|
|
90
|
+
declare function getRenderer(): Renderer;
|
|
91
|
+
|
|
92
|
+
declare const domRenderer: Renderer<Node>;
|
|
93
|
+
|
|
94
|
+
export { For, Fragment, JSX, Link, Route, Router, Show, batch, createContext, createEffect, createMemo, createRoot, createSignal, domRenderer, getRenderer, h, jsx, jsxDEV, jsxs, navigate, onCleanup, onMount, provide, render, setRenderer, untrack, useContext, useParams, usePath };
|
|
95
|
+
export type { Child, Context, Renderer, RouteDef };
|
package/dist/index.d.ts
CHANGED
|
@@ -47,7 +47,7 @@ declare namespace JSX {
|
|
|
47
47
|
}
|
|
48
48
|
declare function Fragment(props: {
|
|
49
49
|
children?: Child;
|
|
50
|
-
}):
|
|
50
|
+
}): any;
|
|
51
51
|
|
|
52
52
|
declare function navigate(to: string, options?: {
|
|
53
53
|
replace?: boolean;
|
|
@@ -72,5 +72,24 @@ declare function Link(props: {
|
|
|
72
72
|
[key: string]: unknown;
|
|
73
73
|
}): HTMLElement;
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
interface Renderer<N = any> {
|
|
76
|
+
createElement(tag: string): N;
|
|
77
|
+
createText(value: string): N;
|
|
78
|
+
createMarker(): N;
|
|
79
|
+
createFragment(): N;
|
|
80
|
+
isNode(value: unknown): value is N;
|
|
81
|
+
insert(parent: N, node: N, anchor?: N | null): void;
|
|
82
|
+
remove(node: N): void;
|
|
83
|
+
nextSibling(node: N): N | null;
|
|
84
|
+
parentNode(node: N): N | null;
|
|
85
|
+
clear(parent: N): void;
|
|
86
|
+
setProp(el: N, name: string, value: unknown): void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
declare function setRenderer(renderer: Renderer): void;
|
|
90
|
+
declare function getRenderer(): Renderer;
|
|
91
|
+
|
|
92
|
+
declare const domRenderer: Renderer<Node>;
|
|
93
|
+
|
|
94
|
+
export { For, Fragment, JSX, Link, Route, Router, Show, batch, createContext, createEffect, createMemo, createRoot, createSignal, domRenderer, getRenderer, h, jsx, jsxDEV, jsxs, navigate, onCleanup, onMount, provide, render, setRenderer, untrack, useContext, useParams, usePath };
|
|
95
|
+
export type { Child, Context, Renderer, RouteDef };
|
package/dist/index.js
CHANGED
|
@@ -140,83 +140,109 @@ function untrack(fn) {
|
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
// src/renderer/dom.ts
|
|
144
|
+
var domRenderer = {
|
|
145
|
+
createElement: (tag) => document.createElement(tag),
|
|
146
|
+
createText: (value) => document.createTextNode(value),
|
|
147
|
+
createMarker: () => document.createComment(""),
|
|
148
|
+
createFragment: () => document.createDocumentFragment(),
|
|
149
|
+
isNode: (v) => typeof Node !== "undefined" && v instanceof Node,
|
|
150
|
+
insert: (parent, node, anchor = null) => {
|
|
151
|
+
parent.insertBefore(node, anchor);
|
|
152
|
+
},
|
|
153
|
+
remove: (node) => {
|
|
154
|
+
node.remove();
|
|
155
|
+
},
|
|
156
|
+
nextSibling: (node) => node.nextSibling,
|
|
157
|
+
parentNode: (node) => node.parentNode,
|
|
158
|
+
clear: (parent) => {
|
|
159
|
+
parent.replaceChildren();
|
|
160
|
+
},
|
|
161
|
+
setProp(el, key, value) {
|
|
162
|
+
const e = el;
|
|
163
|
+
if (key.startsWith("on") && typeof value === "function") {
|
|
164
|
+
e.addEventListener(key.slice(2).toLowerCase(), value);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const name = key === "className" ? "class" : key;
|
|
168
|
+
if (value == null || value === false) e.removeAttribute(name);
|
|
169
|
+
else e.setAttribute(name, value === true ? "" : String(value));
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// src/renderer/index.ts
|
|
174
|
+
var current = domRenderer;
|
|
175
|
+
function setRenderer(renderer) {
|
|
176
|
+
current = renderer;
|
|
177
|
+
}
|
|
178
|
+
function getRenderer() {
|
|
179
|
+
return current;
|
|
180
|
+
}
|
|
181
|
+
|
|
143
182
|
// src/dom/h.ts
|
|
144
183
|
function h(tag, props, ...children) {
|
|
145
|
-
const
|
|
184
|
+
const r = getRenderer();
|
|
185
|
+
const el = r.createElement(tag);
|
|
146
186
|
for (const [key, value] of Object.entries(props ?? {})) {
|
|
147
|
-
|
|
187
|
+
if (typeof value === "function" && !key.startsWith("on")) {
|
|
188
|
+
createEffect(() => r.setProp(el, key, value()));
|
|
189
|
+
} else {
|
|
190
|
+
r.setProp(el, key, value);
|
|
191
|
+
}
|
|
148
192
|
}
|
|
149
193
|
appendChildren(el, children);
|
|
150
194
|
return el;
|
|
151
195
|
}
|
|
152
|
-
function setProp(el, key, value) {
|
|
153
|
-
if (key.startsWith("on") && typeof value === "function") {
|
|
154
|
-
el.addEventListener(key.slice(2).toLowerCase(), value);
|
|
155
|
-
} else if (typeof value === "function") {
|
|
156
|
-
createEffect(() => applyAttr(el, key, value()));
|
|
157
|
-
} else {
|
|
158
|
-
applyAttr(el, key, value);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
function applyAttr(el, key, value) {
|
|
162
|
-
const name = key === "className" ? "class" : key;
|
|
163
|
-
if (value == null || value === false) el.removeAttribute(name);
|
|
164
|
-
else el.setAttribute(name, value === true ? "" : String(value));
|
|
165
|
-
}
|
|
166
196
|
function toNodes(value) {
|
|
197
|
+
const r = getRenderer();
|
|
167
198
|
const out = [];
|
|
168
199
|
for (const v of [value].flat(Infinity)) {
|
|
169
200
|
if (v == null || typeof v === "boolean") continue;
|
|
170
|
-
out.push(v
|
|
201
|
+
out.push(r.isNode(v) ? v : r.createText(String(v)));
|
|
171
202
|
}
|
|
172
203
|
return out;
|
|
173
204
|
}
|
|
174
|
-
function appendChildren(parent, children) {
|
|
175
|
-
const pending2 = [...children].reverse();
|
|
176
|
-
while (pending2.length > 0) {
|
|
177
|
-
const child = pending2.pop();
|
|
178
|
-
if (Array.isArray(child)) {
|
|
179
|
-
for (let i = child.length - 1; i >= 0; i--) {
|
|
180
|
-
pending2.push(child[i]);
|
|
181
|
-
}
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
if (typeof child === "function") {
|
|
185
|
-
const start = document.createComment("");
|
|
186
|
-
const end = document.createComment("");
|
|
187
|
-
parent.append(start, end);
|
|
188
|
-
createEffect(() => {
|
|
189
|
-
reconcile(start, end, toNodes(child()));
|
|
190
|
-
});
|
|
191
|
-
} else {
|
|
192
|
-
parent.append(...toNodes(child));
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
205
|
function reconcile(start, end, next) {
|
|
206
|
+
const r = getRenderer();
|
|
197
207
|
const keep = new Set(next);
|
|
198
|
-
let cur =
|
|
208
|
+
let cur = r.nextSibling(start);
|
|
199
209
|
while (cur && cur !== end) {
|
|
200
|
-
const after =
|
|
201
|
-
if (!keep.has(cur))
|
|
210
|
+
const after = r.nextSibling(cur);
|
|
211
|
+
if (!keep.has(cur)) r.remove(cur);
|
|
202
212
|
cur = after;
|
|
203
213
|
}
|
|
204
|
-
const parent =
|
|
205
|
-
let ref =
|
|
214
|
+
const parent = r.parentNode(end);
|
|
215
|
+
let ref = r.nextSibling(start);
|
|
206
216
|
for (const node of next) {
|
|
207
|
-
if (node === ref)
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
if (node === ref) ref = r.nextSibling(ref);
|
|
218
|
+
else r.insert(parent, node, ref);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function appendChildren(parent, children) {
|
|
222
|
+
const r = getRenderer();
|
|
223
|
+
for (const child of children.flat(Infinity)) {
|
|
224
|
+
if (typeof child === "function") {
|
|
225
|
+
const start = r.createMarker();
|
|
226
|
+
const end = r.createMarker();
|
|
227
|
+
r.insert(parent, start);
|
|
228
|
+
r.insert(parent, end);
|
|
229
|
+
createEffect(() => reconcile(start, end, toNodes(child())));
|
|
230
|
+
} else {
|
|
231
|
+
for (const node of toNodes(child)) r.insert(parent, node);
|
|
232
|
+
}
|
|
210
233
|
}
|
|
211
234
|
}
|
|
212
235
|
|
|
213
236
|
// src/dom/render.ts
|
|
214
237
|
function render(component, container) {
|
|
215
238
|
return createRoot((dispose) => {
|
|
216
|
-
|
|
239
|
+
const r = getRenderer();
|
|
240
|
+
const node = component();
|
|
241
|
+
r.clear(container);
|
|
242
|
+
r.insert(container, node);
|
|
217
243
|
return () => {
|
|
218
244
|
dispose();
|
|
219
|
-
|
|
245
|
+
r.clear(container);
|
|
220
246
|
};
|
|
221
247
|
});
|
|
222
248
|
}
|
|
@@ -275,7 +301,7 @@ function jsx(type, props) {
|
|
|
275
301
|
var jsxs = jsx;
|
|
276
302
|
var jsxDEV = jsx;
|
|
277
303
|
function Fragment(props) {
|
|
278
|
-
const frag =
|
|
304
|
+
const frag = getRenderer().createFragment();
|
|
279
305
|
appendChildren(frag, props.children === void 0 ? [] : [props.children]);
|
|
280
306
|
return frag;
|
|
281
307
|
}
|
|
@@ -328,9 +354,9 @@ function Router(props) {
|
|
|
328
354
|
(r) => r?.__route === true
|
|
329
355
|
);
|
|
330
356
|
return () => {
|
|
331
|
-
const
|
|
357
|
+
const current2 = path();
|
|
332
358
|
for (const route of routes) {
|
|
333
|
-
const params = match(route.path,
|
|
359
|
+
const params = match(route.path, current2);
|
|
334
360
|
if (params) {
|
|
335
361
|
return untrack(() => provide(Params, params, () => route.component()));
|
|
336
362
|
}
|
|
@@ -362,6 +388,8 @@ export {
|
|
|
362
388
|
createMemo,
|
|
363
389
|
createRoot,
|
|
364
390
|
createSignal,
|
|
391
|
+
domRenderer,
|
|
392
|
+
getRenderer,
|
|
365
393
|
h,
|
|
366
394
|
jsx,
|
|
367
395
|
jsxDEV,
|
|
@@ -371,6 +399,7 @@ export {
|
|
|
371
399
|
onMount,
|
|
372
400
|
provide,
|
|
373
401
|
render,
|
|
402
|
+
setRenderer,
|
|
374
403
|
untrack,
|
|
375
404
|
useContext,
|
|
376
405
|
useParams,
|