cajoa 0.4.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 +23 -3
- package/dist/index.cjs +5 -408
- package/dist/index.d.cts +2 -76
- package/dist/index.d.ts +2 -76
- package/dist/index.js +3 -378
- 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
|
|
|
@@ -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,22 @@ 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
|
+
|
|
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
|
+
|
|
162
178
|
## Good to know
|
|
163
179
|
|
|
164
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.
|
|
@@ -174,6 +190,7 @@ Routes are matched in order, so put `path="*"` last.
|
|
|
174
190
|
- Single-page apps need a server fallback to `index.html` for unknown paths.
|
|
175
191
|
- `createMemo` can show a brief inconsistent state when memos depend on each other.
|
|
176
192
|
- `set` calls are not batched automatically inside event handlers. Wrap them in `batch()`.
|
|
193
|
+
- The Router and event names (`onClick`) are still web-specific for now.
|
|
177
194
|
|
|
178
195
|
## Roadmap
|
|
179
196
|
|
|
@@ -185,8 +202,11 @@ Routes are matched in order, so put `path="*"` last.
|
|
|
185
202
|
- [x] Context
|
|
186
203
|
- [x] JSX support
|
|
187
204
|
- [x] Fragments
|
|
188
|
-
- [ ] Vite plugin (removes the two rules above)
|
|
189
205
|
- [x] Router
|
|
206
|
+
- [x] Renderer abstraction (core no longer depends on DOM)
|
|
207
|
+
- [ ] Split into packages ('@cajoa/core', '@cajoa/dom')
|
|
208
|
+
- [ ] Vite plugin (removes the two rules above)
|
|
209
|
+
- [ ] Native renderer (mobile, desktop)
|
|
190
210
|
- [ ] SSR
|
|
191
211
|
|
|
192
212
|
## Development
|
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,415 +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
|
-
h: () => h,
|
|
36
|
-
jsx: () => jsx,
|
|
37
|
-
jsxDEV: () => jsxDEV,
|
|
38
|
-
jsxs: () => jsxs,
|
|
39
|
-
navigate: () => navigate,
|
|
40
|
-
onCleanup: () => onCleanup,
|
|
41
|
-
onMount: () => onMount,
|
|
42
|
-
provide: () => provide,
|
|
43
|
-
render: () => render,
|
|
44
|
-
untrack: () => untrack,
|
|
45
|
-
useContext: () => useContext,
|
|
46
|
-
useParams: () => useParams,
|
|
47
|
-
usePath: () => usePath
|
|
48
|
-
});
|
|
49
19
|
module.exports = __toCommonJS(index_exports);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
var currentOwner = null;
|
|
53
|
-
var currentEffect = null;
|
|
54
|
-
function clean(owner) {
|
|
55
|
-
const fns = owner.cleanups;
|
|
56
|
-
owner.cleanups = [];
|
|
57
|
-
for (const fn of fns) fn();
|
|
58
|
-
}
|
|
59
|
-
function cleanComputation(c) {
|
|
60
|
-
for (const subs of c.deps) subs.delete(c);
|
|
61
|
-
c.deps.clear();
|
|
62
|
-
clean(c);
|
|
63
|
-
}
|
|
64
|
-
var batchDepth = 0;
|
|
65
|
-
var pending = /* @__PURE__ */ new Set();
|
|
66
|
-
function flush() {
|
|
67
|
-
const effects = [...pending];
|
|
68
|
-
pending.clear();
|
|
69
|
-
effects.forEach((effect) => effect.run());
|
|
70
|
-
}
|
|
71
|
-
function batch(fn) {
|
|
72
|
-
batchDepth++;
|
|
73
|
-
try {
|
|
74
|
-
return fn();
|
|
75
|
-
} finally {
|
|
76
|
-
batchDepth--;
|
|
77
|
-
if (batchDepth === 0) flush();
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function createSignal(value) {
|
|
81
|
-
const subs = /* @__PURE__ */ new Set();
|
|
82
|
-
const get = () => {
|
|
83
|
-
if (currentEffect) {
|
|
84
|
-
subs.add(currentEffect);
|
|
85
|
-
currentEffect.deps.add(subs);
|
|
86
|
-
}
|
|
87
|
-
return value;
|
|
88
|
-
};
|
|
89
|
-
const set = (next) => {
|
|
90
|
-
const v = typeof next === "function" ? next(value) : next;
|
|
91
|
-
if (Object.is(v, value)) return;
|
|
92
|
-
value = v;
|
|
93
|
-
for (const effect of [...subs]) {
|
|
94
|
-
if (batchDepth > 0)
|
|
95
|
-
pending.add(effect);
|
|
96
|
-
else effect.run();
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
return [get, set];
|
|
100
|
-
}
|
|
101
|
-
function createEffect(fn) {
|
|
102
|
-
const effect = {
|
|
103
|
-
cleanups: [],
|
|
104
|
-
parent: currentOwner,
|
|
105
|
-
deps: /* @__PURE__ */ new Set(),
|
|
106
|
-
disposed: false,
|
|
107
|
-
run() {
|
|
108
|
-
if (effect.disposed) return;
|
|
109
|
-
cleanComputation(effect);
|
|
110
|
-
const prevOwner = currentOwner;
|
|
111
|
-
const prevEffect = currentEffect;
|
|
112
|
-
currentOwner = effect;
|
|
113
|
-
currentEffect = effect;
|
|
114
|
-
try {
|
|
115
|
-
fn();
|
|
116
|
-
} finally {
|
|
117
|
-
currentOwner = prevOwner;
|
|
118
|
-
currentEffect = prevEffect;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
onCleanup(() => {
|
|
123
|
-
effect.disposed = true;
|
|
124
|
-
cleanComputation(effect);
|
|
125
|
-
});
|
|
126
|
-
effect.run();
|
|
127
|
-
}
|
|
128
|
-
function onCleanup(fn) {
|
|
129
|
-
currentOwner?.cleanups.push(fn);
|
|
130
|
-
}
|
|
131
|
-
function createRoot(fn) {
|
|
132
|
-
const root = { cleanups: [], parent: currentOwner };
|
|
133
|
-
const prevOwner = currentOwner;
|
|
134
|
-
const prevEffect = currentEffect;
|
|
135
|
-
currentOwner = root;
|
|
136
|
-
currentEffect = null;
|
|
137
|
-
try {
|
|
138
|
-
return fn(() => clean(root));
|
|
139
|
-
} finally {
|
|
140
|
-
currentOwner = prevOwner;
|
|
141
|
-
currentEffect = prevEffect;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
function onMount(fn) {
|
|
145
|
-
const owner = currentOwner;
|
|
146
|
-
queueMicrotask(() => {
|
|
147
|
-
const prevOwner = currentOwner;
|
|
148
|
-
const prevEffect = currentEffect;
|
|
149
|
-
currentOwner = owner;
|
|
150
|
-
currentEffect = null;
|
|
151
|
-
try {
|
|
152
|
-
fn();
|
|
153
|
-
} finally {
|
|
154
|
-
currentOwner = prevOwner;
|
|
155
|
-
currentEffect = prevEffect;
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
function createContext(defaultValue) {
|
|
160
|
-
return { id: /* @__PURE__ */ Symbol("cajoa-context"), defaultValue };
|
|
161
|
-
}
|
|
162
|
-
function provide(ctx, value, fn) {
|
|
163
|
-
const owner = {
|
|
164
|
-
cleanups: [],
|
|
165
|
-
parent: currentOwner,
|
|
166
|
-
context: /* @__PURE__ */ new Map([[ctx.id, value]])
|
|
167
|
-
};
|
|
168
|
-
onCleanup(() => clean(owner));
|
|
169
|
-
const prev = currentOwner;
|
|
170
|
-
currentOwner = owner;
|
|
171
|
-
try {
|
|
172
|
-
return fn();
|
|
173
|
-
} finally {
|
|
174
|
-
currentOwner = prev;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function useContext(ctx) {
|
|
178
|
-
for (let o = currentOwner; o; o = o.parent) {
|
|
179
|
-
if (o.context?.has(ctx.id)) return o.context.get(ctx.id);
|
|
180
|
-
}
|
|
181
|
-
return ctx.defaultValue;
|
|
182
|
-
}
|
|
183
|
-
function untrack(fn) {
|
|
184
|
-
const prev = currentEffect;
|
|
185
|
-
currentEffect = null;
|
|
186
|
-
try {
|
|
187
|
-
return fn();
|
|
188
|
-
} finally {
|
|
189
|
-
currentEffect = prev;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// src/dom/h.ts
|
|
194
|
-
function h(tag, props, ...children) {
|
|
195
|
-
const el = document.createElement(tag);
|
|
196
|
-
for (const [key, value] of Object.entries(props ?? {})) {
|
|
197
|
-
setProp(el, key, value);
|
|
198
|
-
}
|
|
199
|
-
appendChildren(el, children);
|
|
200
|
-
return el;
|
|
201
|
-
}
|
|
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
|
-
function toNodes(value) {
|
|
217
|
-
const out = [];
|
|
218
|
-
for (const v of [value].flat(Infinity)) {
|
|
219
|
-
if (v == null || typeof v === "boolean") continue;
|
|
220
|
-
out.push(v instanceof Node ? v : document.createTextNode(String(v)));
|
|
221
|
-
}
|
|
222
|
-
return out;
|
|
223
|
-
}
|
|
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
|
-
function reconcile(start, end, next) {
|
|
247
|
-
const keep = new Set(next);
|
|
248
|
-
let cur = start.nextSibling;
|
|
249
|
-
while (cur && cur !== end) {
|
|
250
|
-
const after = cur.nextSibling;
|
|
251
|
-
if (!keep.has(cur)) cur.remove();
|
|
252
|
-
cur = after;
|
|
253
|
-
}
|
|
254
|
-
const parent = end.parentNode;
|
|
255
|
-
let ref = start.nextSibling;
|
|
256
|
-
for (const node of next) {
|
|
257
|
-
if (node === ref)
|
|
258
|
-
ref = ref.nextSibling;
|
|
259
|
-
else parent.insertBefore(node, ref);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// src/dom/render.ts
|
|
264
|
-
function render(component, container) {
|
|
265
|
-
return createRoot((dispose) => {
|
|
266
|
-
container.replaceChildren(component());
|
|
267
|
-
return () => {
|
|
268
|
-
dispose();
|
|
269
|
-
container.replaceChildren();
|
|
270
|
-
};
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// src/reactivity/memo.ts
|
|
275
|
-
function createMemo(fn) {
|
|
276
|
-
const [value, setValue] = createSignal(void 0);
|
|
277
|
-
createEffect(() => setValue(() => fn()));
|
|
278
|
-
return value;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// src/components/show.ts
|
|
282
|
-
function Show(props) {
|
|
283
|
-
const visible = createMemo(() => !!props.when());
|
|
284
|
-
return () => visible() ? untrack(() => props.children()) : untrack(() => props.fallback?.() ?? null);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// src/components/for.ts
|
|
288
|
-
function For(props) {
|
|
289
|
-
let cache = /* @__PURE__ */ new Map();
|
|
290
|
-
onCleanup(() => {
|
|
291
|
-
cache.forEach((e) => e.dispose());
|
|
292
|
-
cache.clear();
|
|
293
|
-
});
|
|
294
|
-
return () => {
|
|
295
|
-
const items = props.each();
|
|
296
|
-
const next = /* @__PURE__ */ new Map();
|
|
297
|
-
const nodes = [];
|
|
298
|
-
items.forEach((item, i) => {
|
|
299
|
-
const k = props.key ? props.key(item, i) : item;
|
|
300
|
-
let entry = cache.get(k);
|
|
301
|
-
if (!entry) {
|
|
302
|
-
entry = createRoot((dispose) => ({
|
|
303
|
-
node: props.children(item, i),
|
|
304
|
-
dispose
|
|
305
|
-
}));
|
|
306
|
-
}
|
|
307
|
-
next.set(k, entry);
|
|
308
|
-
nodes.push(entry.node);
|
|
309
|
-
});
|
|
310
|
-
cache.forEach((entry, k) => {
|
|
311
|
-
if (!next.has(k)) entry.dispose();
|
|
312
|
-
});
|
|
313
|
-
cache = next;
|
|
314
|
-
return nodes;
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// src/jsx-runtime.ts
|
|
319
|
-
function jsx(type, props) {
|
|
320
|
-
if (typeof type === "function") return type(props ?? {});
|
|
321
|
-
const { children, ...rest } = props ?? {};
|
|
322
|
-
const kids = children === void 0 ? [] : [children];
|
|
323
|
-
return h(type, rest, ...kids);
|
|
324
|
-
}
|
|
325
|
-
var jsxs = jsx;
|
|
326
|
-
var jsxDEV = jsx;
|
|
327
|
-
function Fragment(props) {
|
|
328
|
-
const frag = document.createDocumentFragment();
|
|
329
|
-
appendChildren(frag, props.children === void 0 ? [] : [props.children]);
|
|
330
|
-
return frag;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// src/router.ts
|
|
334
|
-
var read = () => typeof location === "undefined" ? "/" : location.pathname;
|
|
335
|
-
var [path, setPath] = createSignal(read());
|
|
336
|
-
var listening = false;
|
|
337
|
-
function listen() {
|
|
338
|
-
if (listening || typeof window === "undefined") return;
|
|
339
|
-
listening = true;
|
|
340
|
-
window.addEventListener("popstate", () => setPath(read()));
|
|
341
|
-
}
|
|
342
|
-
function navigate(to, options = {}) {
|
|
343
|
-
if (new URL(to, location.href).href === location.href) return;
|
|
344
|
-
history[options.replace ? "replaceState" : "pushState"](null, "", to);
|
|
345
|
-
setPath(read());
|
|
346
|
-
}
|
|
347
|
-
var usePath = () => path;
|
|
348
|
-
var Params = createContext({});
|
|
349
|
-
function useParams() {
|
|
350
|
-
return useContext(Params);
|
|
351
|
-
}
|
|
352
|
-
var split = (s) => s.split("/").filter(Boolean);
|
|
353
|
-
function decode(s) {
|
|
354
|
-
try {
|
|
355
|
-
return decodeURIComponent(s);
|
|
356
|
-
} catch {
|
|
357
|
-
return s;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
function match(pattern, pathname) {
|
|
361
|
-
if (pattern === "*") return {};
|
|
362
|
-
const p = split(pattern);
|
|
363
|
-
const u = split(pathname);
|
|
364
|
-
if (p.length !== u.length) return null;
|
|
365
|
-
const params = {};
|
|
366
|
-
for (let i = 0; i < p.length; i++) {
|
|
367
|
-
if (p[i].startsWith(":")) params[p[i].slice(1)] = decode(u[i]);
|
|
368
|
-
else if (p[i] !== u[i]) return null;
|
|
369
|
-
}
|
|
370
|
-
return params;
|
|
371
|
-
}
|
|
372
|
-
function Route(props) {
|
|
373
|
-
return { __route: true, path: props.path, component: props.component };
|
|
374
|
-
}
|
|
375
|
-
function Router(props) {
|
|
376
|
-
listen();
|
|
377
|
-
const routes = [props.children].flat(Infinity).filter(
|
|
378
|
-
(r) => r?.__route === true
|
|
379
|
-
);
|
|
380
|
-
return () => {
|
|
381
|
-
const current = path();
|
|
382
|
-
for (const route of routes) {
|
|
383
|
-
const params = match(route.path, current);
|
|
384
|
-
if (params) {
|
|
385
|
-
return untrack(() => provide(Params, params, () => route.component()));
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return null;
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
function Link(props) {
|
|
392
|
-
const { href, children, ...rest } = props;
|
|
393
|
-
const onClick = (e) => {
|
|
394
|
-
if (/^[a-z][a-z0-9+.-]*:|^\/\//i.test(href)) return;
|
|
395
|
-
if (e.defaultPrevented || e.button !== 0) return;
|
|
396
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
397
|
-
e.preventDefault();
|
|
398
|
-
navigate(href);
|
|
399
|
-
};
|
|
400
|
-
return h("a", { ...rest, href, onClick }, children);
|
|
401
|
-
}
|
|
20
|
+
__reExport(index_exports, require("@cajoa/core"), module.exports);
|
|
21
|
+
__reExport(index_exports, require("@cajoa/dom"), module.exports);
|
|
402
22
|
// Annotate the CommonJS export names for ESM import in node:
|
|
403
23
|
0 && (module.exports = {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
Link,
|
|
407
|
-
Route,
|
|
408
|
-
Router,
|
|
409
|
-
Show,
|
|
410
|
-
batch,
|
|
411
|
-
createContext,
|
|
412
|
-
createEffect,
|
|
413
|
-
createMemo,
|
|
414
|
-
createRoot,
|
|
415
|
-
createSignal,
|
|
416
|
-
h,
|
|
417
|
-
jsx,
|
|
418
|
-
jsxDEV,
|
|
419
|
-
jsxs,
|
|
420
|
-
navigate,
|
|
421
|
-
onCleanup,
|
|
422
|
-
onMount,
|
|
423
|
-
provide,
|
|
424
|
-
render,
|
|
425
|
-
untrack,
|
|
426
|
-
useContext,
|
|
427
|
-
useParams,
|
|
428
|
-
usePath
|
|
24
|
+
...require("@cajoa/core"),
|
|
25
|
+
...require("@cajoa/dom")
|
|
429
26
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,76 +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
|
-
}): DocumentFragment;
|
|
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
|
-
export { For, Fragment, JSX, Link, Route, Router, Show, batch, createContext, createEffect, createMemo, createRoot, createSignal, h, jsx, jsxDEV, jsxs, navigate, onCleanup, onMount, provide, render, untrack, useContext, useParams, usePath };
|
|
76
|
-
export type { Child, Context, RouteDef };
|
|
1
|
+
export * from '@cajoa/core';
|
|
2
|
+
export * from '@cajoa/dom';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,76 +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
|
-
}): DocumentFragment;
|
|
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
|
-
export { For, Fragment, JSX, Link, Route, Router, Show, batch, createContext, createEffect, createMemo, createRoot, createSignal, h, jsx, jsxDEV, jsxs, navigate, onCleanup, onMount, provide, render, untrack, useContext, useParams, usePath };
|
|
76
|
-
export type { Child, Context, RouteDef };
|
|
1
|
+
export * from '@cajoa/core';
|
|
2
|
+
export * from '@cajoa/dom';
|
package/dist/index.js
CHANGED
|
@@ -1,378 +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/dom/h.ts
|
|
144
|
-
function h(tag, props, ...children) {
|
|
145
|
-
const el = document.createElement(tag);
|
|
146
|
-
for (const [key, value] of Object.entries(props ?? {})) {
|
|
147
|
-
setProp(el, key, value);
|
|
148
|
-
}
|
|
149
|
-
appendChildren(el, children);
|
|
150
|
-
return el;
|
|
151
|
-
}
|
|
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
|
-
function toNodes(value) {
|
|
167
|
-
const out = [];
|
|
168
|
-
for (const v of [value].flat(Infinity)) {
|
|
169
|
-
if (v == null || typeof v === "boolean") continue;
|
|
170
|
-
out.push(v instanceof Node ? v : document.createTextNode(String(v)));
|
|
171
|
-
}
|
|
172
|
-
return out;
|
|
173
|
-
}
|
|
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
|
-
function reconcile(start, end, next) {
|
|
197
|
-
const keep = new Set(next);
|
|
198
|
-
let cur = start.nextSibling;
|
|
199
|
-
while (cur && cur !== end) {
|
|
200
|
-
const after = cur.nextSibling;
|
|
201
|
-
if (!keep.has(cur)) cur.remove();
|
|
202
|
-
cur = after;
|
|
203
|
-
}
|
|
204
|
-
const parent = end.parentNode;
|
|
205
|
-
let ref = start.nextSibling;
|
|
206
|
-
for (const node of next) {
|
|
207
|
-
if (node === ref)
|
|
208
|
-
ref = ref.nextSibling;
|
|
209
|
-
else parent.insertBefore(node, ref);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// src/dom/render.ts
|
|
214
|
-
function render(component, container) {
|
|
215
|
-
return createRoot((dispose) => {
|
|
216
|
-
container.replaceChildren(component());
|
|
217
|
-
return () => {
|
|
218
|
-
dispose();
|
|
219
|
-
container.replaceChildren();
|
|
220
|
-
};
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// src/reactivity/memo.ts
|
|
225
|
-
function createMemo(fn) {
|
|
226
|
-
const [value, setValue] = createSignal(void 0);
|
|
227
|
-
createEffect(() => setValue(() => fn()));
|
|
228
|
-
return value;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
// src/components/show.ts
|
|
232
|
-
function Show(props) {
|
|
233
|
-
const visible = createMemo(() => !!props.when());
|
|
234
|
-
return () => visible() ? untrack(() => props.children()) : untrack(() => props.fallback?.() ?? null);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
// src/components/for.ts
|
|
238
|
-
function For(props) {
|
|
239
|
-
let cache = /* @__PURE__ */ new Map();
|
|
240
|
-
onCleanup(() => {
|
|
241
|
-
cache.forEach((e) => e.dispose());
|
|
242
|
-
cache.clear();
|
|
243
|
-
});
|
|
244
|
-
return () => {
|
|
245
|
-
const items = props.each();
|
|
246
|
-
const next = /* @__PURE__ */ new Map();
|
|
247
|
-
const nodes = [];
|
|
248
|
-
items.forEach((item, i) => {
|
|
249
|
-
const k = props.key ? props.key(item, i) : item;
|
|
250
|
-
let entry = cache.get(k);
|
|
251
|
-
if (!entry) {
|
|
252
|
-
entry = createRoot((dispose) => ({
|
|
253
|
-
node: props.children(item, i),
|
|
254
|
-
dispose
|
|
255
|
-
}));
|
|
256
|
-
}
|
|
257
|
-
next.set(k, entry);
|
|
258
|
-
nodes.push(entry.node);
|
|
259
|
-
});
|
|
260
|
-
cache.forEach((entry, k) => {
|
|
261
|
-
if (!next.has(k)) entry.dispose();
|
|
262
|
-
});
|
|
263
|
-
cache = next;
|
|
264
|
-
return nodes;
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// src/jsx-runtime.ts
|
|
269
|
-
function jsx(type, props) {
|
|
270
|
-
if (typeof type === "function") return type(props ?? {});
|
|
271
|
-
const { children, ...rest } = props ?? {};
|
|
272
|
-
const kids = children === void 0 ? [] : [children];
|
|
273
|
-
return h(type, rest, ...kids);
|
|
274
|
-
}
|
|
275
|
-
var jsxs = jsx;
|
|
276
|
-
var jsxDEV = jsx;
|
|
277
|
-
function Fragment(props) {
|
|
278
|
-
const frag = document.createDocumentFragment();
|
|
279
|
-
appendChildren(frag, props.children === void 0 ? [] : [props.children]);
|
|
280
|
-
return frag;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// src/router.ts
|
|
284
|
-
var read = () => typeof location === "undefined" ? "/" : location.pathname;
|
|
285
|
-
var [path, setPath] = createSignal(read());
|
|
286
|
-
var listening = false;
|
|
287
|
-
function listen() {
|
|
288
|
-
if (listening || typeof window === "undefined") return;
|
|
289
|
-
listening = true;
|
|
290
|
-
window.addEventListener("popstate", () => setPath(read()));
|
|
291
|
-
}
|
|
292
|
-
function navigate(to, options = {}) {
|
|
293
|
-
if (new URL(to, location.href).href === location.href) return;
|
|
294
|
-
history[options.replace ? "replaceState" : "pushState"](null, "", to);
|
|
295
|
-
setPath(read());
|
|
296
|
-
}
|
|
297
|
-
var usePath = () => path;
|
|
298
|
-
var Params = createContext({});
|
|
299
|
-
function useParams() {
|
|
300
|
-
return useContext(Params);
|
|
301
|
-
}
|
|
302
|
-
var split = (s) => s.split("/").filter(Boolean);
|
|
303
|
-
function decode(s) {
|
|
304
|
-
try {
|
|
305
|
-
return decodeURIComponent(s);
|
|
306
|
-
} catch {
|
|
307
|
-
return s;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
function match(pattern, pathname) {
|
|
311
|
-
if (pattern === "*") return {};
|
|
312
|
-
const p = split(pattern);
|
|
313
|
-
const u = split(pathname);
|
|
314
|
-
if (p.length !== u.length) return null;
|
|
315
|
-
const params = {};
|
|
316
|
-
for (let i = 0; i < p.length; i++) {
|
|
317
|
-
if (p[i].startsWith(":")) params[p[i].slice(1)] = decode(u[i]);
|
|
318
|
-
else if (p[i] !== u[i]) return null;
|
|
319
|
-
}
|
|
320
|
-
return params;
|
|
321
|
-
}
|
|
322
|
-
function Route(props) {
|
|
323
|
-
return { __route: true, path: props.path, component: props.component };
|
|
324
|
-
}
|
|
325
|
-
function Router(props) {
|
|
326
|
-
listen();
|
|
327
|
-
const routes = [props.children].flat(Infinity).filter(
|
|
328
|
-
(r) => r?.__route === true
|
|
329
|
-
);
|
|
330
|
-
return () => {
|
|
331
|
-
const current = path();
|
|
332
|
-
for (const route of routes) {
|
|
333
|
-
const params = match(route.path, current);
|
|
334
|
-
if (params) {
|
|
335
|
-
return untrack(() => provide(Params, params, () => route.component()));
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
return null;
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
function Link(props) {
|
|
342
|
-
const { href, children, ...rest } = props;
|
|
343
|
-
const onClick = (e) => {
|
|
344
|
-
if (/^[a-z][a-z0-9+.-]*:|^\/\//i.test(href)) return;
|
|
345
|
-
if (e.defaultPrevented || e.button !== 0) return;
|
|
346
|
-
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return;
|
|
347
|
-
e.preventDefault();
|
|
348
|
-
navigate(href);
|
|
349
|
-
};
|
|
350
|
-
return h("a", { ...rest, href, onClick }, children);
|
|
351
|
-
}
|
|
352
|
-
export {
|
|
353
|
-
For,
|
|
354
|
-
Fragment,
|
|
355
|
-
Link,
|
|
356
|
-
Route,
|
|
357
|
-
Router,
|
|
358
|
-
Show,
|
|
359
|
-
batch,
|
|
360
|
-
createContext,
|
|
361
|
-
createEffect,
|
|
362
|
-
createMemo,
|
|
363
|
-
createRoot,
|
|
364
|
-
createSignal,
|
|
365
|
-
h,
|
|
366
|
-
jsx,
|
|
367
|
-
jsxDEV,
|
|
368
|
-
jsxs,
|
|
369
|
-
navigate,
|
|
370
|
-
onCleanup,
|
|
371
|
-
onMount,
|
|
372
|
-
provide,
|
|
373
|
-
render,
|
|
374
|
-
untrack,
|
|
375
|
-
useContext,
|
|
376
|
-
useParams,
|
|
377
|
-
usePath
|
|
378
|
-
};
|
|
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
|
+
}
|