cajoa 0.5.0 → 0.6.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 +9 -1
- package/dist/index.cjs +5 -440
- package/dist/index.d.cts +2 -95
- package/dist/index.d.ts +2 -95
- package/dist/index.js +3 -407
- package/package.json +20 -58
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.6 (early stage).** The API may still change. Not production-ready yet.
|
|
7
7
|
|
|
8
8
|
## Why Cajoa?
|
|
9
9
|
|
|
@@ -167,6 +167,14 @@ Routes are matched in order, so put `path="*"` last.
|
|
|
167
167
|
| `getRenderer()` | Returns the current renderer. |
|
|
168
168
|
| `domRenderer` | The built-in DOM renderer. |
|
|
169
169
|
|
|
170
|
+
## Packages
|
|
171
|
+
|
|
172
|
+
| Package | What it is |
|
|
173
|
+
| ------------- | -------------------------------------------------------------------- |
|
|
174
|
+
| `cajoa` | The package most apps install (core + DOM) |
|
|
175
|
+
| `@cajoa/core` | Renderer-agnostic core: signals, JSX runtime, `Show`, `For`, context |
|
|
176
|
+
| `@cajoa/dom` | DOM renderer and router |
|
|
177
|
+
|
|
170
178
|
## Good to know
|
|
171
179
|
|
|
172
180
|
- `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.
|
package/dist/index.cjs
CHANGED
|
@@ -3,10 +3,6 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
6
|
var __copyProps = (to, from, except, desc) => {
|
|
11
7
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
8
|
for (let key of __getOwnPropNames(from))
|
|
@@ -15,447 +11,16 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
11
|
}
|
|
16
12
|
return to;
|
|
17
13
|
};
|
|
14
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
18
15
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
16
|
|
|
20
17
|
// src/index.ts
|
|
21
18
|
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
For: () => For,
|
|
24
|
-
Fragment: () => Fragment,
|
|
25
|
-
Link: () => Link,
|
|
26
|
-
Route: () => Route,
|
|
27
|
-
Router: () => Router,
|
|
28
|
-
Show: () => Show,
|
|
29
|
-
batch: () => batch,
|
|
30
|
-
createContext: () => createContext,
|
|
31
|
-
createEffect: () => createEffect,
|
|
32
|
-
createMemo: () => createMemo,
|
|
33
|
-
createRoot: () => createRoot,
|
|
34
|
-
createSignal: () => createSignal,
|
|
35
|
-
domRenderer: () => domRenderer,
|
|
36
|
-
getRenderer: () => getRenderer,
|
|
37
|
-
h: () => h,
|
|
38
|
-
jsx: () => jsx,
|
|
39
|
-
jsxDEV: () => jsxDEV,
|
|
40
|
-
jsxs: () => jsxs,
|
|
41
|
-
navigate: () => navigate,
|
|
42
|
-
onCleanup: () => onCleanup,
|
|
43
|
-
onMount: () => onMount,
|
|
44
|
-
provide: () => provide,
|
|
45
|
-
render: () => render,
|
|
46
|
-
setRenderer: () => setRenderer,
|
|
47
|
-
untrack: () => untrack,
|
|
48
|
-
useContext: () => useContext,
|
|
49
|
-
useParams: () => useParams,
|
|
50
|
-
usePath: () => usePath
|
|
51
|
-
});
|
|
52
19
|
module.exports = __toCommonJS(index_exports);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
var currentOwner = null;
|
|
56
|
-
var currentEffect = null;
|
|
57
|
-
function clean(owner) {
|
|
58
|
-
const fns = owner.cleanups;
|
|
59
|
-
owner.cleanups = [];
|
|
60
|
-
for (const fn of fns) fn();
|
|
61
|
-
}
|
|
62
|
-
function cleanComputation(c) {
|
|
63
|
-
for (const subs of c.deps) subs.delete(c);
|
|
64
|
-
c.deps.clear();
|
|
65
|
-
clean(c);
|
|
66
|
-
}
|
|
67
|
-
var batchDepth = 0;
|
|
68
|
-
var pending = /* @__PURE__ */ new Set();
|
|
69
|
-
function flush() {
|
|
70
|
-
const effects = [...pending];
|
|
71
|
-
pending.clear();
|
|
72
|
-
effects.forEach((effect) => effect.run());
|
|
73
|
-
}
|
|
74
|
-
function batch(fn) {
|
|
75
|
-
batchDepth++;
|
|
76
|
-
try {
|
|
77
|
-
return fn();
|
|
78
|
-
} finally {
|
|
79
|
-
batchDepth--;
|
|
80
|
-
if (batchDepth === 0) flush();
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
function createSignal(value) {
|
|
84
|
-
const subs = /* @__PURE__ */ new Set();
|
|
85
|
-
const get = () => {
|
|
86
|
-
if (currentEffect) {
|
|
87
|
-
subs.add(currentEffect);
|
|
88
|
-
currentEffect.deps.add(subs);
|
|
89
|
-
}
|
|
90
|
-
return value;
|
|
91
|
-
};
|
|
92
|
-
const set = (next) => {
|
|
93
|
-
const v = typeof next === "function" ? next(value) : next;
|
|
94
|
-
if (Object.is(v, value)) return;
|
|
95
|
-
value = v;
|
|
96
|
-
for (const effect of [...subs]) {
|
|
97
|
-
if (batchDepth > 0)
|
|
98
|
-
pending.add(effect);
|
|
99
|
-
else effect.run();
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
return [get, set];
|
|
103
|
-
}
|
|
104
|
-
function createEffect(fn) {
|
|
105
|
-
const effect = {
|
|
106
|
-
cleanups: [],
|
|
107
|
-
parent: currentOwner,
|
|
108
|
-
deps: /* @__PURE__ */ new Set(),
|
|
109
|
-
disposed: false,
|
|
110
|
-
run() {
|
|
111
|
-
if (effect.disposed) return;
|
|
112
|
-
cleanComputation(effect);
|
|
113
|
-
const prevOwner = currentOwner;
|
|
114
|
-
const prevEffect = currentEffect;
|
|
115
|
-
currentOwner = effect;
|
|
116
|
-
currentEffect = effect;
|
|
117
|
-
try {
|
|
118
|
-
fn();
|
|
119
|
-
} finally {
|
|
120
|
-
currentOwner = prevOwner;
|
|
121
|
-
currentEffect = prevEffect;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
onCleanup(() => {
|
|
126
|
-
effect.disposed = true;
|
|
127
|
-
cleanComputation(effect);
|
|
128
|
-
});
|
|
129
|
-
effect.run();
|
|
130
|
-
}
|
|
131
|
-
function onCleanup(fn) {
|
|
132
|
-
currentOwner?.cleanups.push(fn);
|
|
133
|
-
}
|
|
134
|
-
function createRoot(fn) {
|
|
135
|
-
const root = { cleanups: [], parent: currentOwner };
|
|
136
|
-
const prevOwner = currentOwner;
|
|
137
|
-
const prevEffect = currentEffect;
|
|
138
|
-
currentOwner = root;
|
|
139
|
-
currentEffect = null;
|
|
140
|
-
try {
|
|
141
|
-
return fn(() => clean(root));
|
|
142
|
-
} finally {
|
|
143
|
-
currentOwner = prevOwner;
|
|
144
|
-
currentEffect = prevEffect;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
function onMount(fn) {
|
|
148
|
-
const owner = currentOwner;
|
|
149
|
-
queueMicrotask(() => {
|
|
150
|
-
const prevOwner = currentOwner;
|
|
151
|
-
const prevEffect = currentEffect;
|
|
152
|
-
currentOwner = owner;
|
|
153
|
-
currentEffect = null;
|
|
154
|
-
try {
|
|
155
|
-
fn();
|
|
156
|
-
} finally {
|
|
157
|
-
currentOwner = prevOwner;
|
|
158
|
-
currentEffect = prevEffect;
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
function createContext(defaultValue) {
|
|
163
|
-
return { id: /* @__PURE__ */ Symbol("cajoa-context"), defaultValue };
|
|
164
|
-
}
|
|
165
|
-
function provide(ctx, value, fn) {
|
|
166
|
-
const owner = {
|
|
167
|
-
cleanups: [],
|
|
168
|
-
parent: currentOwner,
|
|
169
|
-
context: /* @__PURE__ */ new Map([[ctx.id, value]])
|
|
170
|
-
};
|
|
171
|
-
onCleanup(() => clean(owner));
|
|
172
|
-
const prev = currentOwner;
|
|
173
|
-
currentOwner = owner;
|
|
174
|
-
try {
|
|
175
|
-
return fn();
|
|
176
|
-
} finally {
|
|
177
|
-
currentOwner = prev;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
function useContext(ctx) {
|
|
181
|
-
for (let o = currentOwner; o; o = o.parent) {
|
|
182
|
-
if (o.context?.has(ctx.id)) return o.context.get(ctx.id);
|
|
183
|
-
}
|
|
184
|
-
return ctx.defaultValue;
|
|
185
|
-
}
|
|
186
|
-
function untrack(fn) {
|
|
187
|
-
const prev = currentEffect;
|
|
188
|
-
currentEffect = null;
|
|
189
|
-
try {
|
|
190
|
-
return fn();
|
|
191
|
-
} finally {
|
|
192
|
-
currentEffect = prev;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
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
|
-
|
|
235
|
-
// src/dom/h.ts
|
|
236
|
-
function h(tag, props, ...children) {
|
|
237
|
-
const r = getRenderer();
|
|
238
|
-
const el = r.createElement(tag);
|
|
239
|
-
for (const [key, value] of Object.entries(props ?? {})) {
|
|
240
|
-
if (typeof value === "function" && !key.startsWith("on")) {
|
|
241
|
-
createEffect(() => r.setProp(el, key, value()));
|
|
242
|
-
} else {
|
|
243
|
-
r.setProp(el, key, value);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
appendChildren(el, children);
|
|
247
|
-
return el;
|
|
248
|
-
}
|
|
249
|
-
function toNodes(value) {
|
|
250
|
-
const r = getRenderer();
|
|
251
|
-
const out = [];
|
|
252
|
-
for (const v of [value].flat(Infinity)) {
|
|
253
|
-
if (v == null || typeof v === "boolean") continue;
|
|
254
|
-
out.push(r.isNode(v) ? v : r.createText(String(v)));
|
|
255
|
-
}
|
|
256
|
-
return out;
|
|
257
|
-
}
|
|
258
|
-
function reconcile(start, end, next) {
|
|
259
|
-
const r = getRenderer();
|
|
260
|
-
const keep = new Set(next);
|
|
261
|
-
let cur = r.nextSibling(start);
|
|
262
|
-
while (cur && cur !== end) {
|
|
263
|
-
const after = r.nextSibling(cur);
|
|
264
|
-
if (!keep.has(cur)) r.remove(cur);
|
|
265
|
-
cur = after;
|
|
266
|
-
}
|
|
267
|
-
const parent = r.parentNode(end);
|
|
268
|
-
let ref = r.nextSibling(start);
|
|
269
|
-
for (const node of next) {
|
|
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
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// src/dom/render.ts
|
|
290
|
-
function render(component, container) {
|
|
291
|
-
return createRoot((dispose) => {
|
|
292
|
-
const r = getRenderer();
|
|
293
|
-
const node = component();
|
|
294
|
-
r.clear(container);
|
|
295
|
-
r.insert(container, node);
|
|
296
|
-
return () => {
|
|
297
|
-
dispose();
|
|
298
|
-
r.clear(container);
|
|
299
|
-
};
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// src/reactivity/memo.ts
|
|
304
|
-
function createMemo(fn) {
|
|
305
|
-
const [value, setValue] = createSignal(void 0);
|
|
306
|
-
createEffect(() => setValue(() => fn()));
|
|
307
|
-
return value;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// src/components/show.ts
|
|
311
|
-
function Show(props) {
|
|
312
|
-
const visible = createMemo(() => !!props.when());
|
|
313
|
-
return () => visible() ? untrack(() => props.children()) : untrack(() => props.fallback?.() ?? null);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// src/components/for.ts
|
|
317
|
-
function For(props) {
|
|
318
|
-
let cache = /* @__PURE__ */ new Map();
|
|
319
|
-
onCleanup(() => {
|
|
320
|
-
cache.forEach((e) => e.dispose());
|
|
321
|
-
cache.clear();
|
|
322
|
-
});
|
|
323
|
-
return () => {
|
|
324
|
-
const items = props.each();
|
|
325
|
-
const next = /* @__PURE__ */ new Map();
|
|
326
|
-
const nodes = [];
|
|
327
|
-
items.forEach((item, i) => {
|
|
328
|
-
const k = props.key ? props.key(item, i) : item;
|
|
329
|
-
let entry = cache.get(k);
|
|
330
|
-
if (!entry) {
|
|
331
|
-
entry = createRoot((dispose) => ({
|
|
332
|
-
node: props.children(item, i),
|
|
333
|
-
dispose
|
|
334
|
-
}));
|
|
335
|
-
}
|
|
336
|
-
next.set(k, entry);
|
|
337
|
-
nodes.push(entry.node);
|
|
338
|
-
});
|
|
339
|
-
cache.forEach((entry, k) => {
|
|
340
|
-
if (!next.has(k)) entry.dispose();
|
|
341
|
-
});
|
|
342
|
-
cache = next;
|
|
343
|
-
return nodes;
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// src/jsx-runtime.ts
|
|
348
|
-
function jsx(type, props) {
|
|
349
|
-
if (typeof type === "function") return type(props ?? {});
|
|
350
|
-
const { children, ...rest } = props ?? {};
|
|
351
|
-
const kids = children === void 0 ? [] : [children];
|
|
352
|
-
return h(type, rest, ...kids);
|
|
353
|
-
}
|
|
354
|
-
var jsxs = jsx;
|
|
355
|
-
var jsxDEV = jsx;
|
|
356
|
-
function Fragment(props) {
|
|
357
|
-
const frag = getRenderer().createFragment();
|
|
358
|
-
appendChildren(frag, props.children === void 0 ? [] : [props.children]);
|
|
359
|
-
return frag;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// src/router.ts
|
|
363
|
-
var read = () => typeof location === "undefined" ? "/" : location.pathname;
|
|
364
|
-
var [path, setPath] = createSignal(read());
|
|
365
|
-
var listening = false;
|
|
366
|
-
function listen() {
|
|
367
|
-
if (listening || typeof window === "undefined") return;
|
|
368
|
-
listening = true;
|
|
369
|
-
window.addEventListener("popstate", () => setPath(read()));
|
|
370
|
-
}
|
|
371
|
-
function navigate(to, options = {}) {
|
|
372
|
-
if (new URL(to, location.href).href === location.href) return;
|
|
373
|
-
history[options.replace ? "replaceState" : "pushState"](null, "", to);
|
|
374
|
-
setPath(read());
|
|
375
|
-
}
|
|
376
|
-
var usePath = () => path;
|
|
377
|
-
var Params = createContext({});
|
|
378
|
-
function useParams() {
|
|
379
|
-
return useContext(Params);
|
|
380
|
-
}
|
|
381
|
-
var split = (s) => s.split("/").filter(Boolean);
|
|
382
|
-
function decode(s) {
|
|
383
|
-
try {
|
|
384
|
-
return decodeURIComponent(s);
|
|
385
|
-
} catch {
|
|
386
|
-
return s;
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
function match(pattern, pathname) {
|
|
390
|
-
if (pattern === "*") return {};
|
|
391
|
-
const p = split(pattern);
|
|
392
|
-
const u = split(pathname);
|
|
393
|
-
if (p.length !== u.length) return null;
|
|
394
|
-
const params = {};
|
|
395
|
-
for (let i = 0; i < p.length; i++) {
|
|
396
|
-
if (p[i].startsWith(":")) params[p[i].slice(1)] = decode(u[i]);
|
|
397
|
-
else if (p[i] !== u[i]) return null;
|
|
398
|
-
}
|
|
399
|
-
return params;
|
|
400
|
-
}
|
|
401
|
-
function Route(props) {
|
|
402
|
-
return { __route: true, path: props.path, component: props.component };
|
|
403
|
-
}
|
|
404
|
-
function Router(props) {
|
|
405
|
-
listen();
|
|
406
|
-
const routes = [props.children].flat(Infinity).filter(
|
|
407
|
-
(r) => r?.__route === true
|
|
408
|
-
);
|
|
409
|
-
return () => {
|
|
410
|
-
const current2 = path();
|
|
411
|
-
for (const route of routes) {
|
|
412
|
-
const params = match(route.path, current2);
|
|
413
|
-
if (params) {
|
|
414
|
-
return untrack(() => provide(Params, params, () => route.component()));
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
return null;
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
function Link(props) {
|
|
421
|
-
const { href, children, ...rest } = props;
|
|
422
|
-
const onClick = (e) => {
|
|
423
|
-
if (/^[a-z][a-z0-9+.-]*:|^\/\//i.test(href)) return;
|
|
424
|
-
if (e.defaultPrevented || e.button !== 0) return;
|
|
425
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
426
|
-
e.preventDefault();
|
|
427
|
-
navigate(href);
|
|
428
|
-
};
|
|
429
|
-
return h("a", { ...rest, href, onClick }, children);
|
|
430
|
-
}
|
|
20
|
+
__reExport(index_exports, require("@cajoa/core"), module.exports);
|
|
21
|
+
__reExport(index_exports, require("@cajoa/dom"), module.exports);
|
|
431
22
|
// Annotate the CommonJS export names for ESM import in node:
|
|
432
23
|
0 && (module.exports = {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
Link,
|
|
436
|
-
Route,
|
|
437
|
-
Router,
|
|
438
|
-
Show,
|
|
439
|
-
batch,
|
|
440
|
-
createContext,
|
|
441
|
-
createEffect,
|
|
442
|
-
createMemo,
|
|
443
|
-
createRoot,
|
|
444
|
-
createSignal,
|
|
445
|
-
domRenderer,
|
|
446
|
-
getRenderer,
|
|
447
|
-
h,
|
|
448
|
-
jsx,
|
|
449
|
-
jsxDEV,
|
|
450
|
-
jsxs,
|
|
451
|
-
navigate,
|
|
452
|
-
onCleanup,
|
|
453
|
-
onMount,
|
|
454
|
-
provide,
|
|
455
|
-
render,
|
|
456
|
-
setRenderer,
|
|
457
|
-
untrack,
|
|
458
|
-
useContext,
|
|
459
|
-
useParams,
|
|
460
|
-
usePath
|
|
24
|
+
...require("@cajoa/core"),
|
|
25
|
+
...require("@cajoa/dom")
|
|
461
26
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,95 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
declare function createSignal<T>(value: T): readonly [() => T, (next: T | ((prev: T) => T)) => void];
|
|
4
|
-
declare function createEffect(fn: () => void): void;
|
|
5
|
-
declare function onCleanup(fn: Cleanup): void;
|
|
6
|
-
declare function createRoot<T>(fn: (dispose: () => void) => T): T;
|
|
7
|
-
declare function onMount(fn: () => void): void;
|
|
8
|
-
interface Context<T> {
|
|
9
|
-
readonly id: symbol;
|
|
10
|
-
readonly defaultValue: T;
|
|
11
|
-
}
|
|
12
|
-
declare function createContext<T>(defaultValue: T): Context<T>;
|
|
13
|
-
declare function provide<T, R>(ctx: Context<T>, value: T, fn: () => R): R;
|
|
14
|
-
declare function useContext<T>(ctx: Context<T>): T;
|
|
15
|
-
declare function untrack<T>(fn: () => T): T;
|
|
16
|
-
|
|
17
|
-
type Child = string | number | boolean | null | undefined | Node | (() => unknown) | Child[];
|
|
18
|
-
declare function h(tag: string, props: Record<string, any> | null, ...children: Child[]): HTMLElement;
|
|
19
|
-
|
|
20
|
-
declare function render(component: () => Node, container: Element): () => void;
|
|
21
|
-
|
|
22
|
-
declare function Show<T>(props: {
|
|
23
|
-
when: () => T;
|
|
24
|
-
children: () => Child;
|
|
25
|
-
fallback?: () => Child;
|
|
26
|
-
}): () => Child;
|
|
27
|
-
|
|
28
|
-
declare function For<T>(props: {
|
|
29
|
-
each: () => T[];
|
|
30
|
-
children: (item: T, index: number) => Node;
|
|
31
|
-
key?: (item: T, index: number) => unknown;
|
|
32
|
-
}): () => Node[];
|
|
33
|
-
|
|
34
|
-
declare function createMemo<T>(fn: () => T): () => T;
|
|
35
|
-
|
|
36
|
-
declare function jsx(type: any, props: Record<string, any> | null): any;
|
|
37
|
-
declare const jsxs: typeof jsx;
|
|
38
|
-
declare const jsxDEV: typeof jsx;
|
|
39
|
-
declare namespace JSX {
|
|
40
|
-
type Element = any;
|
|
41
|
-
interface IntrinsicElements {
|
|
42
|
-
[tag: string]: any;
|
|
43
|
-
}
|
|
44
|
-
interface ElementChildrenAttribute {
|
|
45
|
-
children: {};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
declare function Fragment(props: {
|
|
49
|
-
children?: Child;
|
|
50
|
-
}): any;
|
|
51
|
-
|
|
52
|
-
declare function navigate(to: string, options?: {
|
|
53
|
-
replace?: boolean;
|
|
54
|
-
}): void;
|
|
55
|
-
declare const usePath: () => () => string;
|
|
56
|
-
declare function useParams(): Record<string, string>;
|
|
57
|
-
interface RouteDef {
|
|
58
|
-
__route: true;
|
|
59
|
-
path: string;
|
|
60
|
-
component: () => unknown;
|
|
61
|
-
}
|
|
62
|
-
declare function Route(props: {
|
|
63
|
-
path: string;
|
|
64
|
-
component: () => unknown;
|
|
65
|
-
}): RouteDef;
|
|
66
|
-
declare function Router(props: {
|
|
67
|
-
children?: unknown;
|
|
68
|
-
}): () => unknown;
|
|
69
|
-
declare function Link(props: {
|
|
70
|
-
href: string;
|
|
71
|
-
children?: unknown;
|
|
72
|
-
[key: string]: unknown;
|
|
73
|
-
}): HTMLElement;
|
|
74
|
-
|
|
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 };
|
|
1
|
+
export * from '@cajoa/core';
|
|
2
|
+
export * from '@cajoa/dom';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,95 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
declare function createSignal<T>(value: T): readonly [() => T, (next: T | ((prev: T) => T)) => void];
|
|
4
|
-
declare function createEffect(fn: () => void): void;
|
|
5
|
-
declare function onCleanup(fn: Cleanup): void;
|
|
6
|
-
declare function createRoot<T>(fn: (dispose: () => void) => T): T;
|
|
7
|
-
declare function onMount(fn: () => void): void;
|
|
8
|
-
interface Context<T> {
|
|
9
|
-
readonly id: symbol;
|
|
10
|
-
readonly defaultValue: T;
|
|
11
|
-
}
|
|
12
|
-
declare function createContext<T>(defaultValue: T): Context<T>;
|
|
13
|
-
declare function provide<T, R>(ctx: Context<T>, value: T, fn: () => R): R;
|
|
14
|
-
declare function useContext<T>(ctx: Context<T>): T;
|
|
15
|
-
declare function untrack<T>(fn: () => T): T;
|
|
16
|
-
|
|
17
|
-
type Child = string | number | boolean | null | undefined | Node | (() => unknown) | Child[];
|
|
18
|
-
declare function h(tag: string, props: Record<string, any> | null, ...children: Child[]): HTMLElement;
|
|
19
|
-
|
|
20
|
-
declare function render(component: () => Node, container: Element): () => void;
|
|
21
|
-
|
|
22
|
-
declare function Show<T>(props: {
|
|
23
|
-
when: () => T;
|
|
24
|
-
children: () => Child;
|
|
25
|
-
fallback?: () => Child;
|
|
26
|
-
}): () => Child;
|
|
27
|
-
|
|
28
|
-
declare function For<T>(props: {
|
|
29
|
-
each: () => T[];
|
|
30
|
-
children: (item: T, index: number) => Node;
|
|
31
|
-
key?: (item: T, index: number) => unknown;
|
|
32
|
-
}): () => Node[];
|
|
33
|
-
|
|
34
|
-
declare function createMemo<T>(fn: () => T): () => T;
|
|
35
|
-
|
|
36
|
-
declare function jsx(type: any, props: Record<string, any> | null): any;
|
|
37
|
-
declare const jsxs: typeof jsx;
|
|
38
|
-
declare const jsxDEV: typeof jsx;
|
|
39
|
-
declare namespace JSX {
|
|
40
|
-
type Element = any;
|
|
41
|
-
interface IntrinsicElements {
|
|
42
|
-
[tag: string]: any;
|
|
43
|
-
}
|
|
44
|
-
interface ElementChildrenAttribute {
|
|
45
|
-
children: {};
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
declare function Fragment(props: {
|
|
49
|
-
children?: Child;
|
|
50
|
-
}): any;
|
|
51
|
-
|
|
52
|
-
declare function navigate(to: string, options?: {
|
|
53
|
-
replace?: boolean;
|
|
54
|
-
}): void;
|
|
55
|
-
declare const usePath: () => () => string;
|
|
56
|
-
declare function useParams(): Record<string, string>;
|
|
57
|
-
interface RouteDef {
|
|
58
|
-
__route: true;
|
|
59
|
-
path: string;
|
|
60
|
-
component: () => unknown;
|
|
61
|
-
}
|
|
62
|
-
declare function Route(props: {
|
|
63
|
-
path: string;
|
|
64
|
-
component: () => unknown;
|
|
65
|
-
}): RouteDef;
|
|
66
|
-
declare function Router(props: {
|
|
67
|
-
children?: unknown;
|
|
68
|
-
}): () => unknown;
|
|
69
|
-
declare function Link(props: {
|
|
70
|
-
href: string;
|
|
71
|
-
children?: unknown;
|
|
72
|
-
[key: string]: unknown;
|
|
73
|
-
}): HTMLElement;
|
|
74
|
-
|
|
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 };
|
|
1
|
+
export * from '@cajoa/core';
|
|
2
|
+
export * from '@cajoa/dom';
|
package/dist/index.js
CHANGED
|
@@ -1,407 +1,3 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function clean(owner) {
|
|
5
|
-
const fns = owner.cleanups;
|
|
6
|
-
owner.cleanups = [];
|
|
7
|
-
for (const fn of fns) fn();
|
|
8
|
-
}
|
|
9
|
-
function cleanComputation(c) {
|
|
10
|
-
for (const subs of c.deps) subs.delete(c);
|
|
11
|
-
c.deps.clear();
|
|
12
|
-
clean(c);
|
|
13
|
-
}
|
|
14
|
-
var batchDepth = 0;
|
|
15
|
-
var pending = /* @__PURE__ */ new Set();
|
|
16
|
-
function flush() {
|
|
17
|
-
const effects = [...pending];
|
|
18
|
-
pending.clear();
|
|
19
|
-
effects.forEach((effect) => effect.run());
|
|
20
|
-
}
|
|
21
|
-
function batch(fn) {
|
|
22
|
-
batchDepth++;
|
|
23
|
-
try {
|
|
24
|
-
return fn();
|
|
25
|
-
} finally {
|
|
26
|
-
batchDepth--;
|
|
27
|
-
if (batchDepth === 0) flush();
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function createSignal(value) {
|
|
31
|
-
const subs = /* @__PURE__ */ new Set();
|
|
32
|
-
const get = () => {
|
|
33
|
-
if (currentEffect) {
|
|
34
|
-
subs.add(currentEffect);
|
|
35
|
-
currentEffect.deps.add(subs);
|
|
36
|
-
}
|
|
37
|
-
return value;
|
|
38
|
-
};
|
|
39
|
-
const set = (next) => {
|
|
40
|
-
const v = typeof next === "function" ? next(value) : next;
|
|
41
|
-
if (Object.is(v, value)) return;
|
|
42
|
-
value = v;
|
|
43
|
-
for (const effect of [...subs]) {
|
|
44
|
-
if (batchDepth > 0)
|
|
45
|
-
pending.add(effect);
|
|
46
|
-
else effect.run();
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
return [get, set];
|
|
50
|
-
}
|
|
51
|
-
function createEffect(fn) {
|
|
52
|
-
const effect = {
|
|
53
|
-
cleanups: [],
|
|
54
|
-
parent: currentOwner,
|
|
55
|
-
deps: /* @__PURE__ */ new Set(),
|
|
56
|
-
disposed: false,
|
|
57
|
-
run() {
|
|
58
|
-
if (effect.disposed) return;
|
|
59
|
-
cleanComputation(effect);
|
|
60
|
-
const prevOwner = currentOwner;
|
|
61
|
-
const prevEffect = currentEffect;
|
|
62
|
-
currentOwner = effect;
|
|
63
|
-
currentEffect = effect;
|
|
64
|
-
try {
|
|
65
|
-
fn();
|
|
66
|
-
} finally {
|
|
67
|
-
currentOwner = prevOwner;
|
|
68
|
-
currentEffect = prevEffect;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
onCleanup(() => {
|
|
73
|
-
effect.disposed = true;
|
|
74
|
-
cleanComputation(effect);
|
|
75
|
-
});
|
|
76
|
-
effect.run();
|
|
77
|
-
}
|
|
78
|
-
function onCleanup(fn) {
|
|
79
|
-
currentOwner?.cleanups.push(fn);
|
|
80
|
-
}
|
|
81
|
-
function createRoot(fn) {
|
|
82
|
-
const root = { cleanups: [], parent: currentOwner };
|
|
83
|
-
const prevOwner = currentOwner;
|
|
84
|
-
const prevEffect = currentEffect;
|
|
85
|
-
currentOwner = root;
|
|
86
|
-
currentEffect = null;
|
|
87
|
-
try {
|
|
88
|
-
return fn(() => clean(root));
|
|
89
|
-
} finally {
|
|
90
|
-
currentOwner = prevOwner;
|
|
91
|
-
currentEffect = prevEffect;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
function onMount(fn) {
|
|
95
|
-
const owner = currentOwner;
|
|
96
|
-
queueMicrotask(() => {
|
|
97
|
-
const prevOwner = currentOwner;
|
|
98
|
-
const prevEffect = currentEffect;
|
|
99
|
-
currentOwner = owner;
|
|
100
|
-
currentEffect = null;
|
|
101
|
-
try {
|
|
102
|
-
fn();
|
|
103
|
-
} finally {
|
|
104
|
-
currentOwner = prevOwner;
|
|
105
|
-
currentEffect = prevEffect;
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function createContext(defaultValue) {
|
|
110
|
-
return { id: /* @__PURE__ */ Symbol("cajoa-context"), defaultValue };
|
|
111
|
-
}
|
|
112
|
-
function provide(ctx, value, fn) {
|
|
113
|
-
const owner = {
|
|
114
|
-
cleanups: [],
|
|
115
|
-
parent: currentOwner,
|
|
116
|
-
context: /* @__PURE__ */ new Map([[ctx.id, value]])
|
|
117
|
-
};
|
|
118
|
-
onCleanup(() => clean(owner));
|
|
119
|
-
const prev = currentOwner;
|
|
120
|
-
currentOwner = owner;
|
|
121
|
-
try {
|
|
122
|
-
return fn();
|
|
123
|
-
} finally {
|
|
124
|
-
currentOwner = prev;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function useContext(ctx) {
|
|
128
|
-
for (let o = currentOwner; o; o = o.parent) {
|
|
129
|
-
if (o.context?.has(ctx.id)) return o.context.get(ctx.id);
|
|
130
|
-
}
|
|
131
|
-
return ctx.defaultValue;
|
|
132
|
-
}
|
|
133
|
-
function untrack(fn) {
|
|
134
|
-
const prev = currentEffect;
|
|
135
|
-
currentEffect = null;
|
|
136
|
-
try {
|
|
137
|
-
return fn();
|
|
138
|
-
} finally {
|
|
139
|
-
currentEffect = prev;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
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
|
-
|
|
182
|
-
// src/dom/h.ts
|
|
183
|
-
function h(tag, props, ...children) {
|
|
184
|
-
const r = getRenderer();
|
|
185
|
-
const el = r.createElement(tag);
|
|
186
|
-
for (const [key, value] of Object.entries(props ?? {})) {
|
|
187
|
-
if (typeof value === "function" && !key.startsWith("on")) {
|
|
188
|
-
createEffect(() => r.setProp(el, key, value()));
|
|
189
|
-
} else {
|
|
190
|
-
r.setProp(el, key, value);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
appendChildren(el, children);
|
|
194
|
-
return el;
|
|
195
|
-
}
|
|
196
|
-
function toNodes(value) {
|
|
197
|
-
const r = getRenderer();
|
|
198
|
-
const out = [];
|
|
199
|
-
for (const v of [value].flat(Infinity)) {
|
|
200
|
-
if (v == null || typeof v === "boolean") continue;
|
|
201
|
-
out.push(r.isNode(v) ? v : r.createText(String(v)));
|
|
202
|
-
}
|
|
203
|
-
return out;
|
|
204
|
-
}
|
|
205
|
-
function reconcile(start, end, next) {
|
|
206
|
-
const r = getRenderer();
|
|
207
|
-
const keep = new Set(next);
|
|
208
|
-
let cur = r.nextSibling(start);
|
|
209
|
-
while (cur && cur !== end) {
|
|
210
|
-
const after = r.nextSibling(cur);
|
|
211
|
-
if (!keep.has(cur)) r.remove(cur);
|
|
212
|
-
cur = after;
|
|
213
|
-
}
|
|
214
|
-
const parent = r.parentNode(end);
|
|
215
|
-
let ref = r.nextSibling(start);
|
|
216
|
-
for (const node of next) {
|
|
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
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// src/dom/render.ts
|
|
237
|
-
function render(component, container) {
|
|
238
|
-
return createRoot((dispose) => {
|
|
239
|
-
const r = getRenderer();
|
|
240
|
-
const node = component();
|
|
241
|
-
r.clear(container);
|
|
242
|
-
r.insert(container, node);
|
|
243
|
-
return () => {
|
|
244
|
-
dispose();
|
|
245
|
-
r.clear(container);
|
|
246
|
-
};
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// src/reactivity/memo.ts
|
|
251
|
-
function createMemo(fn) {
|
|
252
|
-
const [value, setValue] = createSignal(void 0);
|
|
253
|
-
createEffect(() => setValue(() => fn()));
|
|
254
|
-
return value;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
// src/components/show.ts
|
|
258
|
-
function Show(props) {
|
|
259
|
-
const visible = createMemo(() => !!props.when());
|
|
260
|
-
return () => visible() ? untrack(() => props.children()) : untrack(() => props.fallback?.() ?? null);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// src/components/for.ts
|
|
264
|
-
function For(props) {
|
|
265
|
-
let cache = /* @__PURE__ */ new Map();
|
|
266
|
-
onCleanup(() => {
|
|
267
|
-
cache.forEach((e) => e.dispose());
|
|
268
|
-
cache.clear();
|
|
269
|
-
});
|
|
270
|
-
return () => {
|
|
271
|
-
const items = props.each();
|
|
272
|
-
const next = /* @__PURE__ */ new Map();
|
|
273
|
-
const nodes = [];
|
|
274
|
-
items.forEach((item, i) => {
|
|
275
|
-
const k = props.key ? props.key(item, i) : item;
|
|
276
|
-
let entry = cache.get(k);
|
|
277
|
-
if (!entry) {
|
|
278
|
-
entry = createRoot((dispose) => ({
|
|
279
|
-
node: props.children(item, i),
|
|
280
|
-
dispose
|
|
281
|
-
}));
|
|
282
|
-
}
|
|
283
|
-
next.set(k, entry);
|
|
284
|
-
nodes.push(entry.node);
|
|
285
|
-
});
|
|
286
|
-
cache.forEach((entry, k) => {
|
|
287
|
-
if (!next.has(k)) entry.dispose();
|
|
288
|
-
});
|
|
289
|
-
cache = next;
|
|
290
|
-
return nodes;
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
// src/jsx-runtime.ts
|
|
295
|
-
function jsx(type, props) {
|
|
296
|
-
if (typeof type === "function") return type(props ?? {});
|
|
297
|
-
const { children, ...rest } = props ?? {};
|
|
298
|
-
const kids = children === void 0 ? [] : [children];
|
|
299
|
-
return h(type, rest, ...kids);
|
|
300
|
-
}
|
|
301
|
-
var jsxs = jsx;
|
|
302
|
-
var jsxDEV = jsx;
|
|
303
|
-
function Fragment(props) {
|
|
304
|
-
const frag = getRenderer().createFragment();
|
|
305
|
-
appendChildren(frag, props.children === void 0 ? [] : [props.children]);
|
|
306
|
-
return frag;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// src/router.ts
|
|
310
|
-
var read = () => typeof location === "undefined" ? "/" : location.pathname;
|
|
311
|
-
var [path, setPath] = createSignal(read());
|
|
312
|
-
var listening = false;
|
|
313
|
-
function listen() {
|
|
314
|
-
if (listening || typeof window === "undefined") return;
|
|
315
|
-
listening = true;
|
|
316
|
-
window.addEventListener("popstate", () => setPath(read()));
|
|
317
|
-
}
|
|
318
|
-
function navigate(to, options = {}) {
|
|
319
|
-
if (new URL(to, location.href).href === location.href) return;
|
|
320
|
-
history[options.replace ? "replaceState" : "pushState"](null, "", to);
|
|
321
|
-
setPath(read());
|
|
322
|
-
}
|
|
323
|
-
var usePath = () => path;
|
|
324
|
-
var Params = createContext({});
|
|
325
|
-
function useParams() {
|
|
326
|
-
return useContext(Params);
|
|
327
|
-
}
|
|
328
|
-
var split = (s) => s.split("/").filter(Boolean);
|
|
329
|
-
function decode(s) {
|
|
330
|
-
try {
|
|
331
|
-
return decodeURIComponent(s);
|
|
332
|
-
} catch {
|
|
333
|
-
return s;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
function match(pattern, pathname) {
|
|
337
|
-
if (pattern === "*") return {};
|
|
338
|
-
const p = split(pattern);
|
|
339
|
-
const u = split(pathname);
|
|
340
|
-
if (p.length !== u.length) return null;
|
|
341
|
-
const params = {};
|
|
342
|
-
for (let i = 0; i < p.length; i++) {
|
|
343
|
-
if (p[i].startsWith(":")) params[p[i].slice(1)] = decode(u[i]);
|
|
344
|
-
else if (p[i] !== u[i]) return null;
|
|
345
|
-
}
|
|
346
|
-
return params;
|
|
347
|
-
}
|
|
348
|
-
function Route(props) {
|
|
349
|
-
return { __route: true, path: props.path, component: props.component };
|
|
350
|
-
}
|
|
351
|
-
function Router(props) {
|
|
352
|
-
listen();
|
|
353
|
-
const routes = [props.children].flat(Infinity).filter(
|
|
354
|
-
(r) => r?.__route === true
|
|
355
|
-
);
|
|
356
|
-
return () => {
|
|
357
|
-
const current2 = path();
|
|
358
|
-
for (const route of routes) {
|
|
359
|
-
const params = match(route.path, current2);
|
|
360
|
-
if (params) {
|
|
361
|
-
return untrack(() => provide(Params, params, () => route.component()));
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
return null;
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
function Link(props) {
|
|
368
|
-
const { href, children, ...rest } = props;
|
|
369
|
-
const onClick = (e) => {
|
|
370
|
-
if (/^[a-z][a-z0-9+.-]*:|^\/\//i.test(href)) return;
|
|
371
|
-
if (e.defaultPrevented || e.button !== 0) return;
|
|
372
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
373
|
-
e.preventDefault();
|
|
374
|
-
navigate(href);
|
|
375
|
-
};
|
|
376
|
-
return h("a", { ...rest, href, onClick }, children);
|
|
377
|
-
}
|
|
378
|
-
export {
|
|
379
|
-
For,
|
|
380
|
-
Fragment,
|
|
381
|
-
Link,
|
|
382
|
-
Route,
|
|
383
|
-
Router,
|
|
384
|
-
Show,
|
|
385
|
-
batch,
|
|
386
|
-
createContext,
|
|
387
|
-
createEffect,
|
|
388
|
-
createMemo,
|
|
389
|
-
createRoot,
|
|
390
|
-
createSignal,
|
|
391
|
-
domRenderer,
|
|
392
|
-
getRenderer,
|
|
393
|
-
h,
|
|
394
|
-
jsx,
|
|
395
|
-
jsxDEV,
|
|
396
|
-
jsxs,
|
|
397
|
-
navigate,
|
|
398
|
-
onCleanup,
|
|
399
|
-
onMount,
|
|
400
|
-
provide,
|
|
401
|
-
render,
|
|
402
|
-
setRenderer,
|
|
403
|
-
untrack,
|
|
404
|
-
useContext,
|
|
405
|
-
useParams,
|
|
406
|
-
usePath
|
|
407
|
-
};
|
|
1
|
+
// src/index.ts
|
|
2
|
+
export * from "@cajoa/core";
|
|
3
|
+
export * from "@cajoa/dom";
|
package/package.json
CHANGED
|
@@ -1,78 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cajoa",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "A beginner-friendly
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "A small, beginner-friendly frontend framework built on signals and JSX.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
7
7
|
"module": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"import": {
|
|
12
|
-
|
|
13
|
-
"default": "./dist/index.js"
|
|
14
|
-
},
|
|
15
|
-
"require": {
|
|
16
|
-
"types": "./dist/index.d.cts",
|
|
17
|
-
"default": "./dist/index.cjs"
|
|
18
|
-
}
|
|
11
|
+
"import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
|
|
12
|
+
"require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
|
|
19
13
|
},
|
|
20
14
|
"./jsx-runtime": {
|
|
21
|
-
"import": {
|
|
22
|
-
|
|
23
|
-
"default": "./dist/index.js"
|
|
24
|
-
},
|
|
25
|
-
"require": {
|
|
26
|
-
"types": "./dist/index.d.cts",
|
|
27
|
-
"default": "./dist/index.cjs"
|
|
28
|
-
}
|
|
15
|
+
"import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
|
|
16
|
+
"require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
|
|
29
17
|
},
|
|
30
18
|
"./jsx-dev-runtime": {
|
|
31
|
-
"import": {
|
|
32
|
-
|
|
33
|
-
"default": "./dist/index.js"
|
|
34
|
-
},
|
|
35
|
-
"require": {
|
|
36
|
-
"types": "./dist/index.d.cts",
|
|
37
|
-
"default": "./dist/index.cjs"
|
|
38
|
-
}
|
|
19
|
+
"import": { "types": "./dist/index.d.ts", "default": "./dist/index.js" },
|
|
20
|
+
"require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" }
|
|
39
21
|
}
|
|
40
22
|
},
|
|
41
|
-
"files": [
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"typecheck": "tsc --noEmit",
|
|
47
|
-
"dev": "vite --open /playground/",
|
|
48
|
-
"build": "tsup src/index.ts --format esm,cjs --dts --clean",
|
|
49
|
-
"test": "vitest",
|
|
50
|
-
"prepublishOnly": "vitest run && npm run build"
|
|
23
|
+
"files": ["dist"],
|
|
24
|
+
"sideEffects": true,
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@cajoa/core": "^0.6.0",
|
|
27
|
+
"@cajoa/dom": "^0.6.0"
|
|
51
28
|
},
|
|
29
|
+
"scripts": { "build": "tsup src/index.ts --format esm,cjs --dts --clean" },
|
|
52
30
|
"repository": {
|
|
53
31
|
"type": "git",
|
|
54
|
-
"url": "git+https://github.com/CajoaTS/Cajoa.git"
|
|
32
|
+
"url": "git+https://github.com/CajoaTS/Cajoa.git",
|
|
33
|
+
"directory": "packages/cajoa"
|
|
55
34
|
},
|
|
56
|
-
"keywords": [
|
|
57
|
-
"frontend",
|
|
58
|
-
"framework",
|
|
59
|
-
"signals",
|
|
60
|
-
"reactive",
|
|
61
|
-
"ui",
|
|
62
|
-
"cajoa"
|
|
63
|
-
],
|
|
35
|
+
"keywords": ["frontend", "framework", "signals", "reactive", "ui", "cajoa"],
|
|
64
36
|
"author": "cjmgrc",
|
|
65
37
|
"license": "Apache-2.0",
|
|
66
|
-
"bugs": {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"homepage": "https://github.com/CajoaTS/Cajoa#readme",
|
|
70
|
-
"devDependencies": {
|
|
71
|
-
"@types/node": "^26.6.5",
|
|
72
|
-
"jsdom": "^29.1.1",
|
|
73
|
-
"tsup": "^9.0.0",
|
|
74
|
-
"typescript": "^5.9.3",
|
|
75
|
-
"vite": "^8.3.4",
|
|
76
|
-
"vitest": "^5.0.5"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
38
|
+
"bugs": { "url": "https://github.com/CajoaTS/Cajoa/issues" },
|
|
39
|
+
"homepage": "https://github.com/CajoaTS/Cajoa#readme"
|
|
40
|
+
}
|