@cajoa/core 0.13.0 → 0.14.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/dist/index.cjs CHANGED
@@ -20,10 +20,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ Dynamic: () => Dynamic,
23
24
  ErrorBoundary: () => ErrorBoundary,
24
25
  For: () => For,
25
26
  Fragment: () => Fragment,
27
+ Match: () => Match,
28
+ Portal: () => Portal,
26
29
  Show: () => Show,
30
+ Suspense: () => Suspense,
31
+ Switch: () => Switch,
27
32
  batch: () => batch,
28
33
  catchError: () => catchError,
29
34
  createContext: () => createContext,
@@ -37,6 +42,7 @@ __export(index_exports, {
37
42
  jsx: () => jsx,
38
43
  jsxDEV: () => jsxDEV,
39
44
  jsxs: () => jsxs,
45
+ lazy: () => lazy,
40
46
  onCleanup: () => onCleanup,
41
47
  onMount: () => onMount,
42
48
  provide: () => provide,
@@ -48,12 +54,22 @@ __export(index_exports, {
48
54
  module.exports = __toCommonJS(index_exports);
49
55
 
50
56
  // src/dev.ts
57
+ var muted = 0;
51
58
  function isDev() {
52
59
  return globalThis.__CAJOA_DEV__ === true;
53
60
  }
61
+ function quietly(fn) {
62
+ muted++;
63
+ try {
64
+ return fn();
65
+ } finally {
66
+ muted--;
67
+ }
68
+ }
54
69
  function warn(message) {
55
- if (isDev() && typeof console !== "undefined")
70
+ if (muted === 0 && isDev() && typeof console !== "undefined") {
56
71
  console.warn(`[cajoa] ${message}`);
72
+ }
57
73
  }
58
74
  function logError(message, error) {
59
75
  if (isDev() && typeof console !== "undefined")
@@ -260,6 +276,13 @@ function createMemo(fn) {
260
276
  return value;
261
277
  }
262
278
 
279
+ // src/reactivity/suspense.ts
280
+ var SuspenseContext = createContext(null);
281
+ function trackPending() {
282
+ const state = quietly(() => useContext(SuspenseContext));
283
+ return state ? () => state.add() : void 0;
284
+ }
285
+
263
286
  // src/reactivity/resource.ts
264
287
  function isPromiseLike(value) {
265
288
  return typeof value?.then === "function";
@@ -273,8 +296,12 @@ function createResource(a, b) {
273
296
  const [loading, setLoading] = createSignal(false);
274
297
  const [version, setVersion] = createSignal(0);
275
298
  let run = 0;
299
+ const track = trackPending();
300
+ let release;
301
+ let settled = false;
276
302
  const finish = (id, outcome) => {
277
303
  if (id !== run) return;
304
+ settled = true;
278
305
  batch(() => {
279
306
  setLoading(false);
280
307
  if ("error" in outcome) {
@@ -284,6 +311,8 @@ function createResource(a, b) {
284
311
  setData(() => outcome.value);
285
312
  }
286
313
  });
314
+ release?.();
315
+ release = void 0;
287
316
  };
288
317
  createEffect(() => {
289
318
  const s = source();
@@ -292,6 +321,8 @@ function createResource(a, b) {
292
321
  const id = run;
293
322
  onCleanup(() => {
294
323
  run++;
324
+ release?.();
325
+ release = void 0;
295
326
  });
296
327
  if (s === false || s === null || s === void 0) {
297
328
  batch(() => {
@@ -301,6 +332,7 @@ function createResource(a, b) {
301
332
  });
302
333
  return;
303
334
  }
335
+ if (!settled && track && !release) release = track();
304
336
  setLoading(true);
305
337
  setFailure(null);
306
338
  let result;
@@ -537,6 +569,32 @@ function ErrorBoundary(props) {
537
569
  };
538
570
  }
539
571
 
572
+ // src/components/switch.ts
573
+ function resolve3(value) {
574
+ return typeof value === "function" ? value() : value;
575
+ }
576
+ function Match(props) {
577
+ return { __match: true, when: props.when, children: props.children };
578
+ }
579
+ var isMatch = (value) => typeof value === "object" && value !== null && value.__match === true;
580
+ function Switch(props) {
581
+ const matches = [props.children].flat(Infinity).filter(isMatch);
582
+ const selected = createMemo(() => {
583
+ for (let i = 0; i < matches.length; i++) {
584
+ if (resolve3(matches[i].when)) return i;
585
+ }
586
+ return -1;
587
+ });
588
+ return () => {
589
+ const i = selected();
590
+ return untrack(
591
+ () => resolve3(
592
+ i === -1 ? props.fallback ?? null : matches[i].children ?? null
593
+ )
594
+ );
595
+ };
596
+ }
597
+
540
598
  // src/jsx-runtime.ts
541
599
  function jsx(type, props) {
542
600
  if (typeof type === "function") return type(props ?? {});
@@ -551,12 +609,127 @@ function Fragment(props) {
551
609
  appendChildren(frag, props.children === void 0 ? [] : [props.children]);
552
610
  return frag;
553
611
  }
612
+
613
+ // src/components/dynamic.ts
614
+ function Dynamic(props) {
615
+ const { is, ...rest } = props;
616
+ const read = typeof is === "function" ? is : () => is;
617
+ return () => {
618
+ const target = read();
619
+ if (target == null || target === false) return null;
620
+ if (typeof target !== "string" && typeof target !== "function") {
621
+ throw new Error(
622
+ `<Dynamic>: \`is\` must be a tag name, or a function that returns a tag name or a component (got ${typeof target}). To render a component directly, write is={() => MyComponent}.`
623
+ );
624
+ }
625
+ return untrack(() => jsx(target, rest));
626
+ };
627
+ }
628
+
629
+ // src/components/portal.ts
630
+ function resolve4(value) {
631
+ return typeof value === "function" ? value() : value;
632
+ }
633
+ function Portal(props) {
634
+ const r = getRenderer();
635
+ const mount = props.mount ?? r.portalRoot?.();
636
+ if (!mount) {
637
+ throw new Error(
638
+ "<Portal>: nowhere to render into. Pass a `mount` element (this renderer has no default)."
639
+ );
640
+ }
641
+ const start = r.createMarker();
642
+ const end = r.createMarker();
643
+ r.insert(mount, start);
644
+ r.insert(
645
+ mount,
646
+ materialize(() => resolve4(props.children ?? null))
647
+ );
648
+ r.insert(mount, end);
649
+ onCleanup(() => {
650
+ let node = r.nextSibling(start);
651
+ while (node && node !== end) {
652
+ const next = r.nextSibling(node);
653
+ r.remove(node);
654
+ node = next;
655
+ }
656
+ r.remove(start);
657
+ r.remove(end);
658
+ });
659
+ return null;
660
+ }
661
+
662
+ // src/components/suspense.ts
663
+ function resolve5(value) {
664
+ return typeof value === "function" ? value() : value;
665
+ }
666
+ function Suspense(props) {
667
+ const [pending2, setPending] = createSignal(0);
668
+ const [ready, setReady] = createSignal(false);
669
+ const state = {
670
+ add() {
671
+ setPending((n) => n + 1);
672
+ let released = false;
673
+ return () => {
674
+ if (released) return;
675
+ released = true;
676
+ setPending((n) => n - 1);
677
+ };
678
+ }
679
+ };
680
+ const content = untrack(
681
+ () => provide(
682
+ SuspenseContext,
683
+ state,
684
+ () => materialize(resolve5(props.children ?? null))
685
+ )
686
+ );
687
+ createEffect(() => {
688
+ if (pending2() === 0) setReady(true);
689
+ });
690
+ return () => ready() ? content : untrack(() => resolve5(props.fallback ?? null));
691
+ }
692
+
693
+ // src/components/lazy.ts
694
+ function lazy(loader) {
695
+ let promise;
696
+ let component;
697
+ let failure = null;
698
+ const load = () => promise ??= loader().then(
699
+ (module2) => {
700
+ component = typeof module2 === "function" ? module2 : module2.default;
701
+ },
702
+ (error) => {
703
+ failure = { error };
704
+ }
705
+ );
706
+ return function LazyComponent(props) {
707
+ if (component) return component(props);
708
+ if (failure) throw failure.error;
709
+ const release = trackPending()?.();
710
+ const [done, setDone] = createSignal(false);
711
+ load().then(() => {
712
+ setDone(true);
713
+ release?.();
714
+ });
715
+ return () => {
716
+ done();
717
+ if (failure) throw failure.error;
718
+ return component ? untrack(() => component(props)) : null;
719
+ };
720
+ };
721
+ }
554
722
  // Annotate the CommonJS export names for ESM import in node:
555
723
  0 && (module.exports = {
724
+ Dynamic,
556
725
  ErrorBoundary,
557
726
  For,
558
727
  Fragment,
728
+ Match,
729
+ Portal,
559
730
  Show,
731
+ Suspense,
732
+ Switch,
560
733
  batch,
561
734
  catchError,
562
735
  createContext,
@@ -570,6 +743,7 @@ function Fragment(props) {
570
743
  jsx,
571
744
  jsxDEV,
572
745
  jsxs,
746
+ lazy,
573
747
  onCleanup,
574
748
  onMount,
575
749
  provide,
package/dist/index.d.cts CHANGED
@@ -41,6 +41,7 @@ interface Renderer<N = any> {
41
41
  remove(node: N): void;
42
42
  nextSibling(node: N): N | null;
43
43
  parentNode(node: N): N | null;
44
+ portalRoot?(): N;
44
45
  clear(parent: N): void;
45
46
  setProp(el: N, name: string, value: unknown): void;
46
47
  }
@@ -50,11 +51,11 @@ declare function h(tag: string, props: Record<string, any> | null, ...children:
50
51
 
51
52
  declare function render(component: () => HostNode, container: HostNode): () => void;
52
53
 
53
- type Lazy$1<T> = T | (() => T);
54
+ type Lazy$4<T> = T | (() => T);
54
55
  declare function Show<T>(props: {
55
- when: Lazy$1<T>;
56
- children?: Lazy$1<Child>;
57
- fallback?: Lazy$1<Child>;
56
+ when: Lazy$4<T>;
57
+ children?: Lazy$4<Child>;
58
+ fallback?: Lazy$4<Child>;
58
59
  }): () => string | number | boolean | object | null;
59
60
 
60
61
  declare function For<T>(props: {
@@ -63,13 +64,51 @@ declare function For<T>(props: {
63
64
  key?: (item: T, index: number) => unknown;
64
65
  }): () => object[];
65
66
 
66
- type Lazy<T> = T | (() => T);
67
+ type Lazy$3<T> = T | (() => T);
67
68
  declare function ErrorBoundary(props: {
68
69
  fallback: Child | ((error: unknown, reset: () => void) => Child);
69
- children?: Lazy<Child>;
70
+ children?: Lazy$3<Child>;
70
71
  onError?: (error: unknown) => void;
71
72
  }): () => unknown;
72
73
 
74
+ type Lazy$2<T> = T | (() => T);
75
+ interface MatchDef {
76
+ __match: true;
77
+ when: Lazy$2<unknown>;
78
+ children?: Lazy$2<Child>;
79
+ }
80
+ declare function Match(props: {
81
+ when: Lazy$2<unknown>;
82
+ children?: Lazy$2<Child>;
83
+ }): MatchDef;
84
+ declare function Switch(props: {
85
+ fallback?: Lazy$2<Child>;
86
+ children?: unknown;
87
+ }): () => string | number | boolean | object | null;
88
+
89
+ type Target = string | ((props: any) => unknown) | null | undefined | false;
90
+ declare function Dynamic(props: {
91
+ is: Target | (() => Target);
92
+ [key: string]: unknown;
93
+ }): () => any;
94
+
95
+ type Lazy$1<T> = T | (() => T);
96
+ declare function Portal(props: {
97
+ mount?: HostNode;
98
+ children?: Lazy$1<Child>;
99
+ }): null;
100
+
101
+ type Lazy<T> = T | (() => T);
102
+ declare function Suspense(props: {
103
+ fallback?: Lazy<Child>;
104
+ children?: Lazy<Child>;
105
+ }): () => unknown;
106
+
107
+ type Component<P> = (props: P) => unknown;
108
+ declare function lazy<P = Record<string, unknown>>(loader: () => Promise<{
109
+ default: Component<P>;
110
+ } | Component<P>>): Component<P>;
111
+
73
112
  declare function jsx(type: any, props: Record<string, any> | null): any;
74
113
  declare const jsxs: typeof jsx;
75
114
  declare const jsxDEV: typeof jsx;
@@ -89,5 +128,5 @@ declare function Fragment(props: {
89
128
  declare function setRenderer(renderer: Renderer): void;
90
129
  declare function getRenderer(): Renderer;
91
130
 
92
- export { ErrorBoundary, For, Fragment, JSX, Show, batch, catchError, createContext, createEffect, createMemo, createResource, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
93
- export type { Child, Context, HostNode, Renderer, Resource, ResourceActions };
131
+ export { Dynamic, ErrorBoundary, For, Fragment, JSX, Match, Portal, Show, Suspense, Switch, batch, catchError, createContext, createEffect, createMemo, createResource, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, lazy, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
132
+ export type { Child, Context, HostNode, MatchDef, Renderer, Resource, ResourceActions };
package/dist/index.d.ts CHANGED
@@ -41,6 +41,7 @@ interface Renderer<N = any> {
41
41
  remove(node: N): void;
42
42
  nextSibling(node: N): N | null;
43
43
  parentNode(node: N): N | null;
44
+ portalRoot?(): N;
44
45
  clear(parent: N): void;
45
46
  setProp(el: N, name: string, value: unknown): void;
46
47
  }
@@ -50,11 +51,11 @@ declare function h(tag: string, props: Record<string, any> | null, ...children:
50
51
 
51
52
  declare function render(component: () => HostNode, container: HostNode): () => void;
52
53
 
53
- type Lazy$1<T> = T | (() => T);
54
+ type Lazy$4<T> = T | (() => T);
54
55
  declare function Show<T>(props: {
55
- when: Lazy$1<T>;
56
- children?: Lazy$1<Child>;
57
- fallback?: Lazy$1<Child>;
56
+ when: Lazy$4<T>;
57
+ children?: Lazy$4<Child>;
58
+ fallback?: Lazy$4<Child>;
58
59
  }): () => string | number | boolean | object | null;
59
60
 
60
61
  declare function For<T>(props: {
@@ -63,13 +64,51 @@ declare function For<T>(props: {
63
64
  key?: (item: T, index: number) => unknown;
64
65
  }): () => object[];
65
66
 
66
- type Lazy<T> = T | (() => T);
67
+ type Lazy$3<T> = T | (() => T);
67
68
  declare function ErrorBoundary(props: {
68
69
  fallback: Child | ((error: unknown, reset: () => void) => Child);
69
- children?: Lazy<Child>;
70
+ children?: Lazy$3<Child>;
70
71
  onError?: (error: unknown) => void;
71
72
  }): () => unknown;
72
73
 
74
+ type Lazy$2<T> = T | (() => T);
75
+ interface MatchDef {
76
+ __match: true;
77
+ when: Lazy$2<unknown>;
78
+ children?: Lazy$2<Child>;
79
+ }
80
+ declare function Match(props: {
81
+ when: Lazy$2<unknown>;
82
+ children?: Lazy$2<Child>;
83
+ }): MatchDef;
84
+ declare function Switch(props: {
85
+ fallback?: Lazy$2<Child>;
86
+ children?: unknown;
87
+ }): () => string | number | boolean | object | null;
88
+
89
+ type Target = string | ((props: any) => unknown) | null | undefined | false;
90
+ declare function Dynamic(props: {
91
+ is: Target | (() => Target);
92
+ [key: string]: unknown;
93
+ }): () => any;
94
+
95
+ type Lazy$1<T> = T | (() => T);
96
+ declare function Portal(props: {
97
+ mount?: HostNode;
98
+ children?: Lazy$1<Child>;
99
+ }): null;
100
+
101
+ type Lazy<T> = T | (() => T);
102
+ declare function Suspense(props: {
103
+ fallback?: Lazy<Child>;
104
+ children?: Lazy<Child>;
105
+ }): () => unknown;
106
+
107
+ type Component<P> = (props: P) => unknown;
108
+ declare function lazy<P = Record<string, unknown>>(loader: () => Promise<{
109
+ default: Component<P>;
110
+ } | Component<P>>): Component<P>;
111
+
73
112
  declare function jsx(type: any, props: Record<string, any> | null): any;
74
113
  declare const jsxs: typeof jsx;
75
114
  declare const jsxDEV: typeof jsx;
@@ -89,5 +128,5 @@ declare function Fragment(props: {
89
128
  declare function setRenderer(renderer: Renderer): void;
90
129
  declare function getRenderer(): Renderer;
91
130
 
92
- export { ErrorBoundary, For, Fragment, JSX, Show, batch, catchError, createContext, createEffect, createMemo, createResource, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
93
- export type { Child, Context, HostNode, Renderer, Resource, ResourceActions };
131
+ export { Dynamic, ErrorBoundary, For, Fragment, JSX, Match, Portal, Show, Suspense, Switch, batch, catchError, createContext, createEffect, createMemo, createResource, createRoot, createSignal, getRenderer, h, jsx, jsxDEV, jsxs, lazy, onCleanup, onMount, provide, render, setRenderer, untrack, useContext };
132
+ export type { Child, Context, HostNode, MatchDef, Renderer, Resource, ResourceActions };
package/dist/index.js CHANGED
@@ -1,10 +1,20 @@
1
1
  // src/dev.ts
2
+ var muted = 0;
2
3
  function isDev() {
3
4
  return globalThis.__CAJOA_DEV__ === true;
4
5
  }
6
+ function quietly(fn) {
7
+ muted++;
8
+ try {
9
+ return fn();
10
+ } finally {
11
+ muted--;
12
+ }
13
+ }
5
14
  function warn(message) {
6
- if (isDev() && typeof console !== "undefined")
15
+ if (muted === 0 && isDev() && typeof console !== "undefined") {
7
16
  console.warn(`[cajoa] ${message}`);
17
+ }
8
18
  }
9
19
  function logError(message, error) {
10
20
  if (isDev() && typeof console !== "undefined")
@@ -211,6 +221,13 @@ function createMemo(fn) {
211
221
  return value;
212
222
  }
213
223
 
224
+ // src/reactivity/suspense.ts
225
+ var SuspenseContext = createContext(null);
226
+ function trackPending() {
227
+ const state = quietly(() => useContext(SuspenseContext));
228
+ return state ? () => state.add() : void 0;
229
+ }
230
+
214
231
  // src/reactivity/resource.ts
215
232
  function isPromiseLike(value) {
216
233
  return typeof value?.then === "function";
@@ -224,8 +241,12 @@ function createResource(a, b) {
224
241
  const [loading, setLoading] = createSignal(false);
225
242
  const [version, setVersion] = createSignal(0);
226
243
  let run = 0;
244
+ const track = trackPending();
245
+ let release;
246
+ let settled = false;
227
247
  const finish = (id, outcome) => {
228
248
  if (id !== run) return;
249
+ settled = true;
229
250
  batch(() => {
230
251
  setLoading(false);
231
252
  if ("error" in outcome) {
@@ -235,6 +256,8 @@ function createResource(a, b) {
235
256
  setData(() => outcome.value);
236
257
  }
237
258
  });
259
+ release?.();
260
+ release = void 0;
238
261
  };
239
262
  createEffect(() => {
240
263
  const s = source();
@@ -243,6 +266,8 @@ function createResource(a, b) {
243
266
  const id = run;
244
267
  onCleanup(() => {
245
268
  run++;
269
+ release?.();
270
+ release = void 0;
246
271
  });
247
272
  if (s === false || s === null || s === void 0) {
248
273
  batch(() => {
@@ -252,6 +277,7 @@ function createResource(a, b) {
252
277
  });
253
278
  return;
254
279
  }
280
+ if (!settled && track && !release) release = track();
255
281
  setLoading(true);
256
282
  setFailure(null);
257
283
  let result;
@@ -488,6 +514,32 @@ function ErrorBoundary(props) {
488
514
  };
489
515
  }
490
516
 
517
+ // src/components/switch.ts
518
+ function resolve3(value) {
519
+ return typeof value === "function" ? value() : value;
520
+ }
521
+ function Match(props) {
522
+ return { __match: true, when: props.when, children: props.children };
523
+ }
524
+ var isMatch = (value) => typeof value === "object" && value !== null && value.__match === true;
525
+ function Switch(props) {
526
+ const matches = [props.children].flat(Infinity).filter(isMatch);
527
+ const selected = createMemo(() => {
528
+ for (let i = 0; i < matches.length; i++) {
529
+ if (resolve3(matches[i].when)) return i;
530
+ }
531
+ return -1;
532
+ });
533
+ return () => {
534
+ const i = selected();
535
+ return untrack(
536
+ () => resolve3(
537
+ i === -1 ? props.fallback ?? null : matches[i].children ?? null
538
+ )
539
+ );
540
+ };
541
+ }
542
+
491
543
  // src/jsx-runtime.ts
492
544
  function jsx(type, props) {
493
545
  if (typeof type === "function") return type(props ?? {});
@@ -502,11 +554,126 @@ function Fragment(props) {
502
554
  appendChildren(frag, props.children === void 0 ? [] : [props.children]);
503
555
  return frag;
504
556
  }
557
+
558
+ // src/components/dynamic.ts
559
+ function Dynamic(props) {
560
+ const { is, ...rest } = props;
561
+ const read = typeof is === "function" ? is : () => is;
562
+ return () => {
563
+ const target = read();
564
+ if (target == null || target === false) return null;
565
+ if (typeof target !== "string" && typeof target !== "function") {
566
+ throw new Error(
567
+ `<Dynamic>: \`is\` must be a tag name, or a function that returns a tag name or a component (got ${typeof target}). To render a component directly, write is={() => MyComponent}.`
568
+ );
569
+ }
570
+ return untrack(() => jsx(target, rest));
571
+ };
572
+ }
573
+
574
+ // src/components/portal.ts
575
+ function resolve4(value) {
576
+ return typeof value === "function" ? value() : value;
577
+ }
578
+ function Portal(props) {
579
+ const r = getRenderer();
580
+ const mount = props.mount ?? r.portalRoot?.();
581
+ if (!mount) {
582
+ throw new Error(
583
+ "<Portal>: nowhere to render into. Pass a `mount` element (this renderer has no default)."
584
+ );
585
+ }
586
+ const start = r.createMarker();
587
+ const end = r.createMarker();
588
+ r.insert(mount, start);
589
+ r.insert(
590
+ mount,
591
+ materialize(() => resolve4(props.children ?? null))
592
+ );
593
+ r.insert(mount, end);
594
+ onCleanup(() => {
595
+ let node = r.nextSibling(start);
596
+ while (node && node !== end) {
597
+ const next = r.nextSibling(node);
598
+ r.remove(node);
599
+ node = next;
600
+ }
601
+ r.remove(start);
602
+ r.remove(end);
603
+ });
604
+ return null;
605
+ }
606
+
607
+ // src/components/suspense.ts
608
+ function resolve5(value) {
609
+ return typeof value === "function" ? value() : value;
610
+ }
611
+ function Suspense(props) {
612
+ const [pending2, setPending] = createSignal(0);
613
+ const [ready, setReady] = createSignal(false);
614
+ const state = {
615
+ add() {
616
+ setPending((n) => n + 1);
617
+ let released = false;
618
+ return () => {
619
+ if (released) return;
620
+ released = true;
621
+ setPending((n) => n - 1);
622
+ };
623
+ }
624
+ };
625
+ const content = untrack(
626
+ () => provide(
627
+ SuspenseContext,
628
+ state,
629
+ () => materialize(resolve5(props.children ?? null))
630
+ )
631
+ );
632
+ createEffect(() => {
633
+ if (pending2() === 0) setReady(true);
634
+ });
635
+ return () => ready() ? content : untrack(() => resolve5(props.fallback ?? null));
636
+ }
637
+
638
+ // src/components/lazy.ts
639
+ function lazy(loader) {
640
+ let promise;
641
+ let component;
642
+ let failure = null;
643
+ const load = () => promise ??= loader().then(
644
+ (module) => {
645
+ component = typeof module === "function" ? module : module.default;
646
+ },
647
+ (error) => {
648
+ failure = { error };
649
+ }
650
+ );
651
+ return function LazyComponent(props) {
652
+ if (component) return component(props);
653
+ if (failure) throw failure.error;
654
+ const release = trackPending()?.();
655
+ const [done, setDone] = createSignal(false);
656
+ load().then(() => {
657
+ setDone(true);
658
+ release?.();
659
+ });
660
+ return () => {
661
+ done();
662
+ if (failure) throw failure.error;
663
+ return component ? untrack(() => component(props)) : null;
664
+ };
665
+ };
666
+ }
505
667
  export {
668
+ Dynamic,
506
669
  ErrorBoundary,
507
670
  For,
508
671
  Fragment,
672
+ Match,
673
+ Portal,
509
674
  Show,
675
+ Suspense,
676
+ Switch,
510
677
  batch,
511
678
  catchError,
512
679
  createContext,
@@ -520,6 +687,7 @@ export {
520
687
  jsx,
521
688
  jsxDEV,
522
689
  jsxs,
690
+ lazy,
523
691
  onCleanup,
524
692
  onMount,
525
693
  provide,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cajoa/core",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
4
4
  "description": "Cajoa core: signals, JSX runtime and the renderer interface.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",