@cajoa/core 0.11.0 → 0.12.1
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/dist/index.cjs +150 -12
- package/dist/index.d.cts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +148 -12
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,10 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
ErrorBoundary: () => ErrorBoundary,
|
|
23
24
|
For: () => For,
|
|
24
25
|
Fragment: () => Fragment,
|
|
25
26
|
Show: () => Show,
|
|
26
27
|
batch: () => batch,
|
|
28
|
+
catchError: () => catchError,
|
|
27
29
|
createContext: () => createContext,
|
|
28
30
|
createEffect: () => createEffect,
|
|
29
31
|
createMemo: () => createMemo,
|
|
@@ -44,6 +46,19 @@ __export(index_exports, {
|
|
|
44
46
|
});
|
|
45
47
|
module.exports = __toCommonJS(index_exports);
|
|
46
48
|
|
|
49
|
+
// src/dev.ts
|
|
50
|
+
function isDev() {
|
|
51
|
+
return globalThis.__CAJOA_DEV__ === true;
|
|
52
|
+
}
|
|
53
|
+
function warn(message) {
|
|
54
|
+
if (isDev() && typeof console !== "undefined")
|
|
55
|
+
console.warn(`[cajoa] ${message}`);
|
|
56
|
+
}
|
|
57
|
+
function logError(message, error) {
|
|
58
|
+
if (isDev() && typeof console !== "undefined")
|
|
59
|
+
console.error(`[cajoa] ${message}`, error);
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
// src/reactivity/signal.ts
|
|
48
63
|
var currentOwner = null;
|
|
49
64
|
var currentEffect = null;
|
|
@@ -57,6 +72,18 @@ function cleanComputation(c) {
|
|
|
57
72
|
c.deps.clear();
|
|
58
73
|
clean(c);
|
|
59
74
|
}
|
|
75
|
+
function addCleanup(fn) {
|
|
76
|
+
currentOwner?.cleanups.push(fn);
|
|
77
|
+
}
|
|
78
|
+
function handleError(error, owner) {
|
|
79
|
+
for (let o = owner; o; o = o.parent) {
|
|
80
|
+
if (o.errorHandler) {
|
|
81
|
+
o.errorHandler(error);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
60
87
|
var batchDepth = 0;
|
|
61
88
|
var pending = /* @__PURE__ */ new Set();
|
|
62
89
|
function flush() {
|
|
@@ -109,20 +136,27 @@ function createEffect(fn) {
|
|
|
109
136
|
currentEffect = effect;
|
|
110
137
|
try {
|
|
111
138
|
fn();
|
|
139
|
+
} catch (error) {
|
|
140
|
+
handleError(error, effect);
|
|
112
141
|
} finally {
|
|
113
142
|
currentOwner = prevOwner;
|
|
114
143
|
currentEffect = prevEffect;
|
|
115
144
|
}
|
|
116
145
|
}
|
|
117
146
|
};
|
|
118
|
-
|
|
147
|
+
addCleanup(() => {
|
|
119
148
|
effect.disposed = true;
|
|
120
149
|
cleanComputation(effect);
|
|
121
150
|
});
|
|
122
151
|
effect.run();
|
|
123
152
|
}
|
|
124
153
|
function onCleanup(fn) {
|
|
125
|
-
currentOwner
|
|
154
|
+
if (!currentOwner) {
|
|
155
|
+
warn(
|
|
156
|
+
"onCleanup() was called outside of a component or effect, so this cleanup will never run."
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
addCleanup(fn);
|
|
126
160
|
}
|
|
127
161
|
function createRoot(fn) {
|
|
128
162
|
const root = { cleanups: [], parent: currentOwner };
|
|
@@ -146,12 +180,48 @@ function onMount(fn) {
|
|
|
146
180
|
currentEffect = null;
|
|
147
181
|
try {
|
|
148
182
|
fn();
|
|
183
|
+
} catch (error) {
|
|
184
|
+
handleError(error, owner);
|
|
149
185
|
} finally {
|
|
150
186
|
currentOwner = prevOwner;
|
|
151
187
|
currentEffect = prevEffect;
|
|
152
188
|
}
|
|
153
189
|
});
|
|
154
190
|
}
|
|
191
|
+
function untrack(fn) {
|
|
192
|
+
const prev = currentEffect;
|
|
193
|
+
currentEffect = null;
|
|
194
|
+
try {
|
|
195
|
+
return fn();
|
|
196
|
+
} finally {
|
|
197
|
+
currentEffect = prev;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function catchError(fn, handler) {
|
|
201
|
+
const owner = {
|
|
202
|
+
cleanups: [],
|
|
203
|
+
parent: currentOwner,
|
|
204
|
+
errorHandler: handler
|
|
205
|
+
};
|
|
206
|
+
addCleanup(() => clean(owner));
|
|
207
|
+
const prevOwner = currentOwner;
|
|
208
|
+
currentOwner = owner;
|
|
209
|
+
let result;
|
|
210
|
+
let thrown = null;
|
|
211
|
+
try {
|
|
212
|
+
result = fn();
|
|
213
|
+
} catch (error) {
|
|
214
|
+
clean(owner);
|
|
215
|
+
thrown = { error };
|
|
216
|
+
} finally {
|
|
217
|
+
currentOwner = prevOwner;
|
|
218
|
+
}
|
|
219
|
+
if (thrown) {
|
|
220
|
+
handler(thrown.error);
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
155
225
|
function createContext(defaultValue) {
|
|
156
226
|
return { id: /* @__PURE__ */ Symbol("cajoa-context"), defaultValue };
|
|
157
227
|
}
|
|
@@ -161,7 +231,7 @@ function provide(ctx, value, fn) {
|
|
|
161
231
|
parent: currentOwner,
|
|
162
232
|
context: /* @__PURE__ */ new Map([[ctx.id, value]])
|
|
163
233
|
};
|
|
164
|
-
|
|
234
|
+
addCleanup(() => clean(owner));
|
|
165
235
|
const prev = currentOwner;
|
|
166
236
|
currentOwner = owner;
|
|
167
237
|
try {
|
|
@@ -171,20 +241,16 @@ function provide(ctx, value, fn) {
|
|
|
171
241
|
}
|
|
172
242
|
}
|
|
173
243
|
function useContext(ctx) {
|
|
244
|
+
if (!currentOwner) {
|
|
245
|
+
warn(
|
|
246
|
+
"useContext() was called outside of a component or effect, so it can only return the default value. Call it at the top of your component and use the value later."
|
|
247
|
+
);
|
|
248
|
+
}
|
|
174
249
|
for (let o = currentOwner; o; o = o.parent) {
|
|
175
250
|
if (o.context?.has(ctx.id)) return o.context.get(ctx.id);
|
|
176
251
|
}
|
|
177
252
|
return ctx.defaultValue;
|
|
178
253
|
}
|
|
179
|
-
function untrack(fn) {
|
|
180
|
-
const prev = currentEffect;
|
|
181
|
-
currentEffect = null;
|
|
182
|
-
try {
|
|
183
|
-
return fn();
|
|
184
|
-
} finally {
|
|
185
|
-
currentEffect = prev;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
254
|
|
|
189
255
|
// src/reactivity/memo.ts
|
|
190
256
|
function createMemo(fn) {
|
|
@@ -228,11 +294,21 @@ function h(tag, props, ...children) {
|
|
|
228
294
|
if (onRef) untrack(() => onRef(el));
|
|
229
295
|
return el;
|
|
230
296
|
}
|
|
297
|
+
function materialize(value) {
|
|
298
|
+
if (typeof value !== "function") return value;
|
|
299
|
+
const holder = getRenderer().createFragment();
|
|
300
|
+
appendChildren(holder, [value]);
|
|
301
|
+
return holder;
|
|
302
|
+
}
|
|
231
303
|
function toNodes(value) {
|
|
232
304
|
const r = getRenderer();
|
|
233
305
|
const out = [];
|
|
234
306
|
for (const v of [value].flat(Infinity)) {
|
|
235
307
|
if (v == null || typeof v === "boolean") continue;
|
|
308
|
+
if (typeof v === "function") {
|
|
309
|
+
out.push(materialize(v));
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
236
312
|
out.push(r.isNode(v) ? v : r.createText(String(v)));
|
|
237
313
|
}
|
|
238
314
|
return out;
|
|
@@ -273,6 +349,11 @@ function render(component, container) {
|
|
|
273
349
|
return createRoot((dispose) => {
|
|
274
350
|
const r = getRenderer();
|
|
275
351
|
const node = component();
|
|
352
|
+
if (typeof node === "function") {
|
|
353
|
+
throw new Error(
|
|
354
|
+
"render(): the component returned a function (for example <Show>, <For>, <Router> or <ErrorBoundary>). Wrap it in an element, such as <div>\u2026</div>."
|
|
355
|
+
);
|
|
356
|
+
}
|
|
276
357
|
r.clear(container);
|
|
277
358
|
r.insert(container, node);
|
|
278
359
|
return () => {
|
|
@@ -304,6 +385,11 @@ function For(props) {
|
|
|
304
385
|
const nodes = [];
|
|
305
386
|
items.forEach((item, i) => {
|
|
306
387
|
const k = props.key ? props.key(item, i) : item;
|
|
388
|
+
if (next.has(k)) {
|
|
389
|
+
warn(
|
|
390
|
+
`<For> found a duplicate key (${String(k)}). Keys must be unique, otherwise one item replaces another.`
|
|
391
|
+
);
|
|
392
|
+
}
|
|
307
393
|
let entry = cache.get(k);
|
|
308
394
|
if (!entry) {
|
|
309
395
|
entry = createRoot((dispose) => ({
|
|
@@ -322,6 +408,56 @@ function For(props) {
|
|
|
322
408
|
};
|
|
323
409
|
}
|
|
324
410
|
|
|
411
|
+
// src/components/error-boundary.ts
|
|
412
|
+
function resolve2(value) {
|
|
413
|
+
return typeof value === "function" ? value() : value;
|
|
414
|
+
}
|
|
415
|
+
function ErrorBoundary(props) {
|
|
416
|
+
const [version, setVersion] = createSignal(0);
|
|
417
|
+
let failure = null;
|
|
418
|
+
const caught = (error) => {
|
|
419
|
+
logError("ErrorBoundary caught an error:", error);
|
|
420
|
+
props.onError?.(error);
|
|
421
|
+
};
|
|
422
|
+
const reset = () => {
|
|
423
|
+
failure = null;
|
|
424
|
+
setVersion((v) => v + 1);
|
|
425
|
+
};
|
|
426
|
+
const fail = (error) => {
|
|
427
|
+
caught(error);
|
|
428
|
+
failure = { error };
|
|
429
|
+
setVersion((v) => v + 1);
|
|
430
|
+
};
|
|
431
|
+
const showFallback = (error) => typeof props.fallback === "function" ? props.fallback(
|
|
432
|
+
error,
|
|
433
|
+
reset
|
|
434
|
+
) : props.fallback;
|
|
435
|
+
return () => {
|
|
436
|
+
version();
|
|
437
|
+
const current2 = failure;
|
|
438
|
+
if (current2) return untrack(() => showFallback(current2.error));
|
|
439
|
+
let creating = true;
|
|
440
|
+
let early = null;
|
|
441
|
+
const content = untrack(
|
|
442
|
+
() => catchError(
|
|
443
|
+
() => materialize(resolve2(props.children ?? null)),
|
|
444
|
+
(error) => {
|
|
445
|
+
if (creating) early = { error };
|
|
446
|
+
else fail(error);
|
|
447
|
+
}
|
|
448
|
+
)
|
|
449
|
+
);
|
|
450
|
+
creating = false;
|
|
451
|
+
const first = early;
|
|
452
|
+
if (first) {
|
|
453
|
+
caught(first.error);
|
|
454
|
+
failure = first;
|
|
455
|
+
return untrack(() => showFallback(first.error));
|
|
456
|
+
}
|
|
457
|
+
return content;
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
325
461
|
// src/jsx-runtime.ts
|
|
326
462
|
function jsx(type, props) {
|
|
327
463
|
if (typeof type === "function") return type(props ?? {});
|
|
@@ -338,10 +474,12 @@ function Fragment(props) {
|
|
|
338
474
|
}
|
|
339
475
|
// Annotate the CommonJS export names for ESM import in node:
|
|
340
476
|
0 && (module.exports = {
|
|
477
|
+
ErrorBoundary,
|
|
341
478
|
For,
|
|
342
479
|
Fragment,
|
|
343
480
|
Show,
|
|
344
481
|
batch,
|
|
482
|
+
catchError,
|
|
345
483
|
createContext,
|
|
346
484
|
createEffect,
|
|
347
485
|
createMemo,
|
package/dist/index.d.cts
CHANGED
|
@@ -5,6 +5,8 @@ declare function createEffect(fn: () => void): void;
|
|
|
5
5
|
declare function onCleanup(fn: Cleanup): void;
|
|
6
6
|
declare function createRoot<T>(fn: (dispose: () => void) => T): T;
|
|
7
7
|
declare function onMount(fn: () => void): void;
|
|
8
|
+
declare function untrack<T>(fn: () => T): T;
|
|
9
|
+
declare function catchError<T>(fn: () => T, handler: (error: unknown) => void): T | undefined;
|
|
8
10
|
interface Context<T> {
|
|
9
11
|
readonly id: symbol;
|
|
10
12
|
readonly defaultValue: T;
|
|
@@ -12,7 +14,6 @@ interface Context<T> {
|
|
|
12
14
|
declare function createContext<T>(defaultValue: T): Context<T>;
|
|
13
15
|
declare function provide<T, R>(ctx: Context<T>, value: T, fn: () => R): R;
|
|
14
16
|
declare function useContext<T>(ctx: Context<T>): T;
|
|
15
|
-
declare function untrack<T>(fn: () => T): T;
|
|
16
17
|
|
|
17
18
|
declare function createMemo<T>(fn: () => T): () => T;
|
|
18
19
|
|
|
@@ -36,11 +37,11 @@ declare function h(tag: string, props: Record<string, any> | null, ...children:
|
|
|
36
37
|
|
|
37
38
|
declare function render(component: () => HostNode, container: HostNode): () => void;
|
|
38
39
|
|
|
39
|
-
type Lazy<T> = T | (() => T);
|
|
40
|
+
type Lazy$1<T> = T | (() => T);
|
|
40
41
|
declare function Show<T>(props: {
|
|
41
|
-
when: Lazy<T>;
|
|
42
|
-
children?: Lazy<Child>;
|
|
43
|
-
fallback?: Lazy<Child>;
|
|
42
|
+
when: Lazy$1<T>;
|
|
43
|
+
children?: Lazy$1<Child>;
|
|
44
|
+
fallback?: Lazy$1<Child>;
|
|
44
45
|
}): () => string | number | boolean | object | null;
|
|
45
46
|
|
|
46
47
|
declare function For<T>(props: {
|
|
@@ -49,6 +50,13 @@ declare function For<T>(props: {
|
|
|
49
50
|
key?: (item: T, index: number) => unknown;
|
|
50
51
|
}): () => object[];
|
|
51
52
|
|
|
53
|
+
type Lazy<T> = T | (() => T);
|
|
54
|
+
declare function ErrorBoundary(props: {
|
|
55
|
+
fallback: Child | ((error: unknown, reset: () => void) => Child);
|
|
56
|
+
children?: Lazy<Child>;
|
|
57
|
+
onError?: (error: unknown) => void;
|
|
58
|
+
}): () => unknown;
|
|
59
|
+
|
|
52
60
|
declare function jsx(type: any, props: Record<string, any> | null): any;
|
|
53
61
|
declare const jsxs: typeof jsx;
|
|
54
62
|
declare const jsxDEV: typeof jsx;
|
|
@@ -68,5 +76,5 @@ declare function Fragment(props: {
|
|
|
68
76
|
declare function setRenderer(renderer: Renderer): void;
|
|
69
77
|
declare function getRenderer(): Renderer;
|
|
70
78
|
|
|
71
|
-
export { For, Fragment, JSX, Show, batch, createContext, createEffect, createMemo, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
|
|
79
|
+
export { ErrorBoundary, For, Fragment, JSX, Show, batch, catchError, createContext, createEffect, createMemo, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
|
|
72
80
|
export type { Child, Context, HostNode, Renderer };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ declare function createEffect(fn: () => void): void;
|
|
|
5
5
|
declare function onCleanup(fn: Cleanup): void;
|
|
6
6
|
declare function createRoot<T>(fn: (dispose: () => void) => T): T;
|
|
7
7
|
declare function onMount(fn: () => void): void;
|
|
8
|
+
declare function untrack<T>(fn: () => T): T;
|
|
9
|
+
declare function catchError<T>(fn: () => T, handler: (error: unknown) => void): T | undefined;
|
|
8
10
|
interface Context<T> {
|
|
9
11
|
readonly id: symbol;
|
|
10
12
|
readonly defaultValue: T;
|
|
@@ -12,7 +14,6 @@ interface Context<T> {
|
|
|
12
14
|
declare function createContext<T>(defaultValue: T): Context<T>;
|
|
13
15
|
declare function provide<T, R>(ctx: Context<T>, value: T, fn: () => R): R;
|
|
14
16
|
declare function useContext<T>(ctx: Context<T>): T;
|
|
15
|
-
declare function untrack<T>(fn: () => T): T;
|
|
16
17
|
|
|
17
18
|
declare function createMemo<T>(fn: () => T): () => T;
|
|
18
19
|
|
|
@@ -36,11 +37,11 @@ declare function h(tag: string, props: Record<string, any> | null, ...children:
|
|
|
36
37
|
|
|
37
38
|
declare function render(component: () => HostNode, container: HostNode): () => void;
|
|
38
39
|
|
|
39
|
-
type Lazy<T> = T | (() => T);
|
|
40
|
+
type Lazy$1<T> = T | (() => T);
|
|
40
41
|
declare function Show<T>(props: {
|
|
41
|
-
when: Lazy<T>;
|
|
42
|
-
children?: Lazy<Child>;
|
|
43
|
-
fallback?: Lazy<Child>;
|
|
42
|
+
when: Lazy$1<T>;
|
|
43
|
+
children?: Lazy$1<Child>;
|
|
44
|
+
fallback?: Lazy$1<Child>;
|
|
44
45
|
}): () => string | number | boolean | object | null;
|
|
45
46
|
|
|
46
47
|
declare function For<T>(props: {
|
|
@@ -49,6 +50,13 @@ declare function For<T>(props: {
|
|
|
49
50
|
key?: (item: T, index: number) => unknown;
|
|
50
51
|
}): () => object[];
|
|
51
52
|
|
|
53
|
+
type Lazy<T> = T | (() => T);
|
|
54
|
+
declare function ErrorBoundary(props: {
|
|
55
|
+
fallback: Child | ((error: unknown, reset: () => void) => Child);
|
|
56
|
+
children?: Lazy<Child>;
|
|
57
|
+
onError?: (error: unknown) => void;
|
|
58
|
+
}): () => unknown;
|
|
59
|
+
|
|
52
60
|
declare function jsx(type: any, props: Record<string, any> | null): any;
|
|
53
61
|
declare const jsxs: typeof jsx;
|
|
54
62
|
declare const jsxDEV: typeof jsx;
|
|
@@ -68,5 +76,5 @@ declare function Fragment(props: {
|
|
|
68
76
|
declare function setRenderer(renderer: Renderer): void;
|
|
69
77
|
declare function getRenderer(): Renderer;
|
|
70
78
|
|
|
71
|
-
export { For, Fragment, JSX, Show, batch, createContext, createEffect, createMemo, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
|
|
79
|
+
export { ErrorBoundary, For, Fragment, JSX, Show, batch, catchError, createContext, createEffect, createMemo, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
|
|
72
80
|
export type { Child, Context, HostNode, Renderer };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
// src/dev.ts
|
|
2
|
+
function isDev() {
|
|
3
|
+
return globalThis.__CAJOA_DEV__ === true;
|
|
4
|
+
}
|
|
5
|
+
function warn(message) {
|
|
6
|
+
if (isDev() && typeof console !== "undefined")
|
|
7
|
+
console.warn(`[cajoa] ${message}`);
|
|
8
|
+
}
|
|
9
|
+
function logError(message, error) {
|
|
10
|
+
if (isDev() && typeof console !== "undefined")
|
|
11
|
+
console.error(`[cajoa] ${message}`, error);
|
|
12
|
+
}
|
|
13
|
+
|
|
1
14
|
// src/reactivity/signal.ts
|
|
2
15
|
var currentOwner = null;
|
|
3
16
|
var currentEffect = null;
|
|
@@ -11,6 +24,18 @@ function cleanComputation(c) {
|
|
|
11
24
|
c.deps.clear();
|
|
12
25
|
clean(c);
|
|
13
26
|
}
|
|
27
|
+
function addCleanup(fn) {
|
|
28
|
+
currentOwner?.cleanups.push(fn);
|
|
29
|
+
}
|
|
30
|
+
function handleError(error, owner) {
|
|
31
|
+
for (let o = owner; o; o = o.parent) {
|
|
32
|
+
if (o.errorHandler) {
|
|
33
|
+
o.errorHandler(error);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
14
39
|
var batchDepth = 0;
|
|
15
40
|
var pending = /* @__PURE__ */ new Set();
|
|
16
41
|
function flush() {
|
|
@@ -63,20 +88,27 @@ function createEffect(fn) {
|
|
|
63
88
|
currentEffect = effect;
|
|
64
89
|
try {
|
|
65
90
|
fn();
|
|
91
|
+
} catch (error) {
|
|
92
|
+
handleError(error, effect);
|
|
66
93
|
} finally {
|
|
67
94
|
currentOwner = prevOwner;
|
|
68
95
|
currentEffect = prevEffect;
|
|
69
96
|
}
|
|
70
97
|
}
|
|
71
98
|
};
|
|
72
|
-
|
|
99
|
+
addCleanup(() => {
|
|
73
100
|
effect.disposed = true;
|
|
74
101
|
cleanComputation(effect);
|
|
75
102
|
});
|
|
76
103
|
effect.run();
|
|
77
104
|
}
|
|
78
105
|
function onCleanup(fn) {
|
|
79
|
-
currentOwner
|
|
106
|
+
if (!currentOwner) {
|
|
107
|
+
warn(
|
|
108
|
+
"onCleanup() was called outside of a component or effect, so this cleanup will never run."
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
addCleanup(fn);
|
|
80
112
|
}
|
|
81
113
|
function createRoot(fn) {
|
|
82
114
|
const root = { cleanups: [], parent: currentOwner };
|
|
@@ -100,12 +132,48 @@ function onMount(fn) {
|
|
|
100
132
|
currentEffect = null;
|
|
101
133
|
try {
|
|
102
134
|
fn();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
handleError(error, owner);
|
|
103
137
|
} finally {
|
|
104
138
|
currentOwner = prevOwner;
|
|
105
139
|
currentEffect = prevEffect;
|
|
106
140
|
}
|
|
107
141
|
});
|
|
108
142
|
}
|
|
143
|
+
function untrack(fn) {
|
|
144
|
+
const prev = currentEffect;
|
|
145
|
+
currentEffect = null;
|
|
146
|
+
try {
|
|
147
|
+
return fn();
|
|
148
|
+
} finally {
|
|
149
|
+
currentEffect = prev;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function catchError(fn, handler) {
|
|
153
|
+
const owner = {
|
|
154
|
+
cleanups: [],
|
|
155
|
+
parent: currentOwner,
|
|
156
|
+
errorHandler: handler
|
|
157
|
+
};
|
|
158
|
+
addCleanup(() => clean(owner));
|
|
159
|
+
const prevOwner = currentOwner;
|
|
160
|
+
currentOwner = owner;
|
|
161
|
+
let result;
|
|
162
|
+
let thrown = null;
|
|
163
|
+
try {
|
|
164
|
+
result = fn();
|
|
165
|
+
} catch (error) {
|
|
166
|
+
clean(owner);
|
|
167
|
+
thrown = { error };
|
|
168
|
+
} finally {
|
|
169
|
+
currentOwner = prevOwner;
|
|
170
|
+
}
|
|
171
|
+
if (thrown) {
|
|
172
|
+
handler(thrown.error);
|
|
173
|
+
return void 0;
|
|
174
|
+
}
|
|
175
|
+
return result;
|
|
176
|
+
}
|
|
109
177
|
function createContext(defaultValue) {
|
|
110
178
|
return { id: /* @__PURE__ */ Symbol("cajoa-context"), defaultValue };
|
|
111
179
|
}
|
|
@@ -115,7 +183,7 @@ function provide(ctx, value, fn) {
|
|
|
115
183
|
parent: currentOwner,
|
|
116
184
|
context: /* @__PURE__ */ new Map([[ctx.id, value]])
|
|
117
185
|
};
|
|
118
|
-
|
|
186
|
+
addCleanup(() => clean(owner));
|
|
119
187
|
const prev = currentOwner;
|
|
120
188
|
currentOwner = owner;
|
|
121
189
|
try {
|
|
@@ -125,20 +193,16 @@ function provide(ctx, value, fn) {
|
|
|
125
193
|
}
|
|
126
194
|
}
|
|
127
195
|
function useContext(ctx) {
|
|
196
|
+
if (!currentOwner) {
|
|
197
|
+
warn(
|
|
198
|
+
"useContext() was called outside of a component or effect, so it can only return the default value. Call it at the top of your component and use the value later."
|
|
199
|
+
);
|
|
200
|
+
}
|
|
128
201
|
for (let o = currentOwner; o; o = o.parent) {
|
|
129
202
|
if (o.context?.has(ctx.id)) return o.context.get(ctx.id);
|
|
130
203
|
}
|
|
131
204
|
return ctx.defaultValue;
|
|
132
205
|
}
|
|
133
|
-
function untrack(fn) {
|
|
134
|
-
const prev = currentEffect;
|
|
135
|
-
currentEffect = null;
|
|
136
|
-
try {
|
|
137
|
-
return fn();
|
|
138
|
-
} finally {
|
|
139
|
-
currentEffect = prev;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
206
|
|
|
143
207
|
// src/reactivity/memo.ts
|
|
144
208
|
function createMemo(fn) {
|
|
@@ -182,11 +246,21 @@ function h(tag, props, ...children) {
|
|
|
182
246
|
if (onRef) untrack(() => onRef(el));
|
|
183
247
|
return el;
|
|
184
248
|
}
|
|
249
|
+
function materialize(value) {
|
|
250
|
+
if (typeof value !== "function") return value;
|
|
251
|
+
const holder = getRenderer().createFragment();
|
|
252
|
+
appendChildren(holder, [value]);
|
|
253
|
+
return holder;
|
|
254
|
+
}
|
|
185
255
|
function toNodes(value) {
|
|
186
256
|
const r = getRenderer();
|
|
187
257
|
const out = [];
|
|
188
258
|
for (const v of [value].flat(Infinity)) {
|
|
189
259
|
if (v == null || typeof v === "boolean") continue;
|
|
260
|
+
if (typeof v === "function") {
|
|
261
|
+
out.push(materialize(v));
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
190
264
|
out.push(r.isNode(v) ? v : r.createText(String(v)));
|
|
191
265
|
}
|
|
192
266
|
return out;
|
|
@@ -227,6 +301,11 @@ function render(component, container) {
|
|
|
227
301
|
return createRoot((dispose) => {
|
|
228
302
|
const r = getRenderer();
|
|
229
303
|
const node = component();
|
|
304
|
+
if (typeof node === "function") {
|
|
305
|
+
throw new Error(
|
|
306
|
+
"render(): the component returned a function (for example <Show>, <For>, <Router> or <ErrorBoundary>). Wrap it in an element, such as <div>\u2026</div>."
|
|
307
|
+
);
|
|
308
|
+
}
|
|
230
309
|
r.clear(container);
|
|
231
310
|
r.insert(container, node);
|
|
232
311
|
return () => {
|
|
@@ -258,6 +337,11 @@ function For(props) {
|
|
|
258
337
|
const nodes = [];
|
|
259
338
|
items.forEach((item, i) => {
|
|
260
339
|
const k = props.key ? props.key(item, i) : item;
|
|
340
|
+
if (next.has(k)) {
|
|
341
|
+
warn(
|
|
342
|
+
`<For> found a duplicate key (${String(k)}). Keys must be unique, otherwise one item replaces another.`
|
|
343
|
+
);
|
|
344
|
+
}
|
|
261
345
|
let entry = cache.get(k);
|
|
262
346
|
if (!entry) {
|
|
263
347
|
entry = createRoot((dispose) => ({
|
|
@@ -276,6 +360,56 @@ function For(props) {
|
|
|
276
360
|
};
|
|
277
361
|
}
|
|
278
362
|
|
|
363
|
+
// src/components/error-boundary.ts
|
|
364
|
+
function resolve2(value) {
|
|
365
|
+
return typeof value === "function" ? value() : value;
|
|
366
|
+
}
|
|
367
|
+
function ErrorBoundary(props) {
|
|
368
|
+
const [version, setVersion] = createSignal(0);
|
|
369
|
+
let failure = null;
|
|
370
|
+
const caught = (error) => {
|
|
371
|
+
logError("ErrorBoundary caught an error:", error);
|
|
372
|
+
props.onError?.(error);
|
|
373
|
+
};
|
|
374
|
+
const reset = () => {
|
|
375
|
+
failure = null;
|
|
376
|
+
setVersion((v) => v + 1);
|
|
377
|
+
};
|
|
378
|
+
const fail = (error) => {
|
|
379
|
+
caught(error);
|
|
380
|
+
failure = { error };
|
|
381
|
+
setVersion((v) => v + 1);
|
|
382
|
+
};
|
|
383
|
+
const showFallback = (error) => typeof props.fallback === "function" ? props.fallback(
|
|
384
|
+
error,
|
|
385
|
+
reset
|
|
386
|
+
) : props.fallback;
|
|
387
|
+
return () => {
|
|
388
|
+
version();
|
|
389
|
+
const current2 = failure;
|
|
390
|
+
if (current2) return untrack(() => showFallback(current2.error));
|
|
391
|
+
let creating = true;
|
|
392
|
+
let early = null;
|
|
393
|
+
const content = untrack(
|
|
394
|
+
() => catchError(
|
|
395
|
+
() => materialize(resolve2(props.children ?? null)),
|
|
396
|
+
(error) => {
|
|
397
|
+
if (creating) early = { error };
|
|
398
|
+
else fail(error);
|
|
399
|
+
}
|
|
400
|
+
)
|
|
401
|
+
);
|
|
402
|
+
creating = false;
|
|
403
|
+
const first = early;
|
|
404
|
+
if (first) {
|
|
405
|
+
caught(first.error);
|
|
406
|
+
failure = first;
|
|
407
|
+
return untrack(() => showFallback(first.error));
|
|
408
|
+
}
|
|
409
|
+
return content;
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
|
|
279
413
|
// src/jsx-runtime.ts
|
|
280
414
|
function jsx(type, props) {
|
|
281
415
|
if (typeof type === "function") return type(props ?? {});
|
|
@@ -291,10 +425,12 @@ function Fragment(props) {
|
|
|
291
425
|
return frag;
|
|
292
426
|
}
|
|
293
427
|
export {
|
|
428
|
+
ErrorBoundary,
|
|
294
429
|
For,
|
|
295
430
|
Fragment,
|
|
296
431
|
Show,
|
|
297
432
|
batch,
|
|
433
|
+
catchError,
|
|
298
434
|
createContext,
|
|
299
435
|
createEffect,
|
|
300
436
|
createMemo,
|