rask-ui 0.20.5 → 0.21.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.
Files changed (103) hide show
  1. package/dist/createComputed.d.ts +4 -0
  2. package/dist/createComputed.d.ts.map +1 -0
  3. package/dist/createComputed.js +69 -0
  4. package/dist/createEffect.d.ts +2 -0
  5. package/dist/createEffect.d.ts.map +1 -0
  6. package/dist/createEffect.js +29 -0
  7. package/dist/createRouter.d.ts +8 -0
  8. package/dist/createRouter.d.ts.map +1 -0
  9. package/dist/createRouter.js +27 -0
  10. package/dist/createState.d.ts +2 -0
  11. package/dist/createState.d.ts.map +1 -1
  12. package/dist/createState.js +40 -5
  13. package/dist/createTask.d.ts +31 -0
  14. package/dist/createTask.d.ts.map +1 -0
  15. package/dist/createTask.js +79 -0
  16. package/dist/createView.d.ts +18 -44
  17. package/dist/createView.d.ts.map +1 -1
  18. package/dist/createView.js +57 -48
  19. package/dist/error.d.ts +3 -14
  20. package/dist/error.d.ts.map +1 -1
  21. package/dist/error.js +14 -15
  22. package/dist/jsx.d.ts +10 -256
  23. package/dist/patchInferno.d.ts +6 -0
  24. package/dist/patchInferno.d.ts.map +1 -0
  25. package/dist/patchInferno.js +53 -0
  26. package/dist/scheduler.d.ts +4 -0
  27. package/dist/scheduler.d.ts.map +1 -0
  28. package/dist/scheduler.js +107 -0
  29. package/dist/tests/batch.test.d.ts +2 -0
  30. package/dist/tests/batch.test.d.ts.map +1 -0
  31. package/dist/tests/batch.test.js +244 -0
  32. package/dist/tests/createComputed.test.d.ts +2 -0
  33. package/dist/tests/createComputed.test.d.ts.map +1 -0
  34. package/dist/tests/createComputed.test.js +257 -0
  35. package/dist/tests/createContext.test.d.ts +2 -0
  36. package/dist/tests/createContext.test.d.ts.map +1 -0
  37. package/dist/tests/createContext.test.js +136 -0
  38. package/dist/tests/createEffect.test.d.ts +2 -0
  39. package/dist/tests/createEffect.test.d.ts.map +1 -0
  40. package/dist/tests/createEffect.test.js +467 -0
  41. package/dist/tests/createState.test.d.ts.map +1 -0
  42. package/dist/tests/createState.test.js +144 -0
  43. package/dist/tests/createTask.test.d.ts +2 -0
  44. package/dist/tests/createTask.test.d.ts.map +1 -0
  45. package/dist/tests/createTask.test.js +322 -0
  46. package/dist/tests/createView.test.d.ts.map +1 -0
  47. package/dist/{createView.test.js → tests/createView.test.js} +40 -40
  48. package/dist/tests/error.test.d.ts +2 -0
  49. package/dist/tests/error.test.d.ts.map +1 -0
  50. package/dist/tests/error.test.js +168 -0
  51. package/dist/tests/observation.test.d.ts.map +1 -0
  52. package/dist/tests/observation.test.js +341 -0
  53. package/dist/types.d.ts +2 -1
  54. package/dist/types.d.ts.map +1 -1
  55. package/dist/useComputed.d.ts +5 -0
  56. package/dist/useComputed.d.ts.map +1 -0
  57. package/dist/useComputed.js +69 -0
  58. package/dist/useQuery.d.ts +25 -0
  59. package/dist/useQuery.d.ts.map +1 -0
  60. package/dist/useQuery.js +25 -0
  61. package/dist/useSuspendAsync.d.ts +18 -0
  62. package/dist/useSuspendAsync.d.ts.map +1 -0
  63. package/dist/useSuspendAsync.js +37 -0
  64. package/dist/useTask.d.ts +25 -0
  65. package/dist/useTask.d.ts.map +1 -0
  66. package/dist/useTask.js +70 -0
  67. package/package.json +1 -1
  68. package/swc-plugin/target/wasm32-wasip1/release/swc_plugin_rask_component.wasm +0 -0
  69. package/dist/asyncState.d.ts +0 -16
  70. package/dist/asyncState.d.ts.map +0 -1
  71. package/dist/asyncState.js +0 -24
  72. package/dist/context.d.ts +0 -5
  73. package/dist/context.d.ts.map +0 -1
  74. package/dist/context.js +0 -29
  75. package/dist/createAsync.test.d.ts +0 -2
  76. package/dist/createAsync.test.d.ts.map +0 -1
  77. package/dist/createAsync.test.js +0 -110
  78. package/dist/createMutation.test.d.ts +0 -2
  79. package/dist/createMutation.test.d.ts.map +0 -1
  80. package/dist/createMutation.test.js +0 -168
  81. package/dist/createQuery.test.d.ts +0 -2
  82. package/dist/createQuery.test.d.ts.map +0 -1
  83. package/dist/createQuery.test.js +0 -156
  84. package/dist/createRef.d.ts +0 -6
  85. package/dist/createRef.d.ts.map +0 -1
  86. package/dist/createRef.js +0 -8
  87. package/dist/createState.test.d.ts.map +0 -1
  88. package/dist/createState.test.js +0 -111
  89. package/dist/createView.test.d.ts.map +0 -1
  90. package/dist/observation.test.d.ts.map +0 -1
  91. package/dist/observation.test.js +0 -150
  92. package/dist/suspense.d.ts +0 -25
  93. package/dist/suspense.d.ts.map +0 -1
  94. package/dist/suspense.js +0 -97
  95. package/dist/test-setup.d.ts +0 -16
  96. package/dist/test-setup.d.ts.map +0 -1
  97. package/dist/test-setup.js +0 -40
  98. package/dist/test.d.ts +0 -2
  99. package/dist/test.d.ts.map +0 -1
  100. package/dist/test.js +0 -24
  101. /package/dist/{createState.test.d.ts → tests/createState.test.d.ts} +0 -0
  102. /package/dist/{createView.test.d.ts → tests/createView.test.d.ts} +0 -0
  103. /package/dist/{observation.test.d.ts → tests/observation.test.d.ts} +0 -0
@@ -0,0 +1,4 @@
1
+ export declare function createComputed<T extends Record<string, () => any>>(computed: T): {
2
+ [K in keyof T]: ReturnType<T[K]>;
3
+ };
4
+ //# sourceMappingURL=createComputed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createComputed.d.ts","sourceRoot":"","sources":["../src/createComputed.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,EAChE,QAAQ,EAAE,CAAC,GACV;KACA,CAAC,IAAI,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACjC,CA0EA"}
@@ -0,0 +1,69 @@
1
+ import { getCurrentComponent, createCleanup } from "./component";
2
+ import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
3
+ import { getCurrentObserver, Observer, Signal } from "./observation";
4
+ export function createComputed(computed) {
5
+ const currentComponent = getCurrentComponent();
6
+ const proxy = {};
7
+ let notifyInspectorRef = {};
8
+ for (const prop in computed) {
9
+ let isDirty = true;
10
+ let value;
11
+ const signal = new Signal();
12
+ const computedObserver = new Observer(() => {
13
+ isDirty = true;
14
+ signal.notify();
15
+ if (INSPECTOR_ENABLED) {
16
+ notifyInspectorRef.current?.notify({
17
+ type: "computed",
18
+ path: notifyInspectorRef.current.path.concat(prop),
19
+ isDirty: true,
20
+ value,
21
+ });
22
+ }
23
+ });
24
+ createCleanup(() => computedObserver.dispose());
25
+ Object.defineProperty(proxy, prop, {
26
+ enumerable: true,
27
+ configurable: true,
28
+ get() {
29
+ const currentObserver = getCurrentObserver();
30
+ if (currentObserver) {
31
+ currentObserver.subscribeSignal(signal);
32
+ }
33
+ if (isDirty) {
34
+ const stopObserving = computedObserver.observe();
35
+ value = computed[prop]();
36
+ stopObserving();
37
+ isDirty = false;
38
+ if (INSPECTOR_ENABLED) {
39
+ notifyInspectorRef.current?.notify({
40
+ type: "computed",
41
+ path: notifyInspectorRef.current.path.concat(prop),
42
+ isDirty: false,
43
+ value,
44
+ });
45
+ }
46
+ return value;
47
+ }
48
+ return value;
49
+ },
50
+ });
51
+ }
52
+ if (INSPECTOR_ENABLED) {
53
+ Object.defineProperty(proxy, INSPECT_MARKER, {
54
+ enumerable: false,
55
+ configurable: false,
56
+ get() {
57
+ return !notifyInspectorRef.current;
58
+ },
59
+ set: (value) => {
60
+ Object.defineProperty(notifyInspectorRef, "current", {
61
+ get() {
62
+ return value.current;
63
+ },
64
+ });
65
+ },
66
+ });
67
+ }
68
+ return proxy;
69
+ }
@@ -0,0 +1,2 @@
1
+ export declare function createEffect(cb: () => void | (() => void)): void;
2
+ //# sourceMappingURL=createEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createEffect.d.ts","sourceRoot":"","sources":["../src/createEffect.ts"],"names":[],"mappings":"AAIA,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,QA2BzD"}
@@ -0,0 +1,29 @@
1
+ import { syncBatch } from "./batch";
2
+ import { createCleanup, getCurrentComponent } from "./component";
3
+ import { Observer } from "./observation";
4
+ export function createEffect(cb) {
5
+ const component = getCurrentComponent();
6
+ if (!component || component.isRendering) {
7
+ throw new Error("Only use createEffect in component setup");
8
+ }
9
+ let disposer;
10
+ const observer = new Observer(() => {
11
+ syncBatch(runEffect);
12
+ });
13
+ const runEffect = () => {
14
+ try {
15
+ disposer?.();
16
+ }
17
+ catch (error) {
18
+ console.error("Error in effect dispose function:", error);
19
+ }
20
+ const stopObserving = observer.observe();
21
+ disposer = cb();
22
+ stopObserving();
23
+ };
24
+ createCleanup(() => {
25
+ observer.dispose();
26
+ disposer?.();
27
+ });
28
+ runEffect();
29
+ }
@@ -0,0 +1,8 @@
1
+ import { RoutesConfig, TRouter, TRoutes } from "typed-client-router";
2
+ export type Router<T extends RoutesConfig> = Omit<TRouter<T>, "current" | "listen" | "pathname"> & {
3
+ route?: TRoutes<T>;
4
+ };
5
+ export declare function createRouter<const T extends RoutesConfig>(config: T, options?: {
6
+ base?: string;
7
+ }): Router<T>;
8
+ //# sourceMappingURL=createRouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createRouter.d.ts","sourceRoot":"","sources":["../src/createRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,OAAO,EACP,OAAO,EACR,MAAM,qBAAqB,CAAC;AAI7B,MAAM,MAAM,MAAM,CAAC,CAAC,SAAS,YAAY,IAAI,IAAI,CAC/C,OAAO,CAAC,CAAC,CAAC,EACV,SAAS,GAAG,QAAQ,GAAG,UAAU,CAClC,GAAG;IACF,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CACpB,CAAC;AAEF,wBAAgB,YAAY,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,EACvD,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GACA,MAAM,CAAC,CAAC,CAAC,CA4BX"}
@@ -0,0 +1,27 @@
1
+ import { createRouter as internalCreateRouter, } from "typed-client-router";
2
+ import { getCurrentObserver, Signal } from "./observation";
3
+ import { createCleanup, getCurrentComponent } from "./component";
4
+ export function createRouter(config, options) {
5
+ if (!getCurrentComponent()) {
6
+ throw new Error("Only use createRouter in component setup");
7
+ }
8
+ const router = internalCreateRouter(config, options);
9
+ const signal = new Signal();
10
+ createCleanup(router.listen(() => signal.notify()));
11
+ return {
12
+ get route() {
13
+ const observer = getCurrentObserver();
14
+ if (observer) {
15
+ observer.subscribeSignal(signal);
16
+ }
17
+ return router.current;
18
+ },
19
+ get queries() {
20
+ return router.queries;
21
+ },
22
+ setQuery: router.setQuery,
23
+ push: router.push,
24
+ replace: router.replace,
25
+ url: router.url,
26
+ };
27
+ }
@@ -1,3 +1,4 @@
1
+ export declare function assignState<T extends object>(state: T, newState: T): T;
1
2
  /**
2
3
  * Creates a reactive state object that tracks property access and notifies observers on changes.
3
4
  *
@@ -23,4 +24,5 @@
23
24
  * @returns A reactive proxy of the state object
24
25
  */
25
26
  export declare function createState<T extends object>(state: T): T;
27
+ export declare const PROXY_MARKER: unique symbol;
26
28
  //# sourceMappingURL=createState.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createState.d.ts","sourceRoot":"","sources":["../src/createState.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEzD"}
1
+ {"version":3,"file":"createState.d.ts","sourceRoot":"","sources":["../src/createState.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,KAElE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAOzD;AAGD,eAAO,MAAM,YAAY,eAAoB,CAAC"}
@@ -1,4 +1,9 @@
1
+ import { getCurrentComponent } from "./component";
2
+ import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
1
3
  import { getCurrentObserver, Signal } from "./observation";
4
+ export function assignState(state, newState) {
5
+ return Object.assign(state, newState);
6
+ }
2
7
  /**
3
8
  * Creates a reactive state object that tracks property access and notifies observers on changes.
4
9
  *
@@ -24,11 +29,14 @@ import { getCurrentObserver, Signal } from "./observation";
24
29
  * @returns A reactive proxy of the state object
25
30
  */
26
31
  export function createState(state) {
27
- return getProxy(state);
32
+ if (getCurrentComponent()?.isRendering) {
33
+ throw new Error("createState cannot be called during render. Call it in component setup or globally.");
34
+ }
35
+ return getProxy(state, {});
28
36
  }
29
37
  const proxyCache = new WeakMap();
30
- const PROXY_MARKER = Symbol("isProxy");
31
- function getProxy(value) {
38
+ export const PROXY_MARKER = Symbol("isProxy");
39
+ function getProxy(value, notifyInspectorRef) {
32
40
  // Check if already a proxy to avoid double-wrapping
33
41
  if (PROXY_MARKER in value) {
34
42
  return value;
@@ -43,6 +51,9 @@ function getProxy(value) {
43
51
  if (key === PROXY_MARKER) {
44
52
  return true;
45
53
  }
54
+ if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
55
+ return true;
56
+ }
46
57
  return Reflect.has(target, key);
47
58
  },
48
59
  get(target, key) {
@@ -50,6 +61,9 @@ function getProxy(value) {
50
61
  if (key === PROXY_MARKER) {
51
62
  return true;
52
63
  }
64
+ if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
65
+ return !notifyInspectorRef.current;
66
+ }
53
67
  const value = Reflect.get(target, key);
54
68
  if (typeof key === "symbol" || typeof value === "function") {
55
69
  return value;
@@ -61,11 +75,26 @@ function getProxy(value) {
61
75
  }
62
76
  if (Array.isArray(value) ||
63
77
  (typeof value === "object" && value !== null)) {
64
- return getProxy(value);
78
+ return getProxy(value, INSPECTOR_ENABLED && notifyInspectorRef.current
79
+ ? {
80
+ current: {
81
+ notify: notifyInspectorRef.current.notify,
82
+ path: notifyInspectorRef.current.path.concat(key),
83
+ },
84
+ }
85
+ : notifyInspectorRef);
65
86
  }
66
87
  return value;
67
88
  },
68
89
  set(target, key, newValue) {
90
+ if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
91
+ Object.defineProperty(notifyInspectorRef, "current", {
92
+ get() {
93
+ return newValue.current;
94
+ },
95
+ });
96
+ return Reflect.set(target, key, newValue);
97
+ }
69
98
  if (typeof key === "symbol") {
70
99
  return Reflect.set(target, key, newValue);
71
100
  }
@@ -73,10 +102,16 @@ function getProxy(value) {
73
102
  const setResult = Reflect.set(target, key, newValue);
74
103
  // We only notify if actual change, though array length actually updates under the hood
75
104
  if (newValue !== oldValue || (Array.isArray(value) && key === "length")) {
76
- console.log("WTF", key, newValue);
77
105
  const signal = signals[key];
78
106
  signal?.notify();
79
107
  }
108
+ if (INSPECTOR_ENABLED) {
109
+ notifyInspectorRef.current?.notify({
110
+ type: "mutation",
111
+ path: notifyInspectorRef.current.path,
112
+ value: newValue,
113
+ });
114
+ }
80
115
  return setResult;
81
116
  },
82
117
  deleteProperty(target, key) {
@@ -0,0 +1,31 @@
1
+ export type TaskState<P, T> = {
2
+ isRunning: false;
3
+ params: null;
4
+ result: null;
5
+ error: null;
6
+ } | {
7
+ isRunning: true;
8
+ result: T | null;
9
+ params: P;
10
+ error: null;
11
+ } | {
12
+ isRunning: false;
13
+ params: null;
14
+ result: T;
15
+ error: null;
16
+ } | {
17
+ isRunning: false;
18
+ params: null;
19
+ result: null;
20
+ error: string;
21
+ };
22
+ export type Task<A, B = never> = [B] extends [never] ? TaskState<null, A> & {
23
+ run(): Promise<A>;
24
+ rerun(): Promise<A>;
25
+ } : TaskState<A, B> & {
26
+ run(params: A): Promise<B>;
27
+ rerun(params: A): Promise<B>;
28
+ };
29
+ export declare function createTask<T>(task: (params: undefined, signal: AbortSignal) => Promise<T>): Task<T>;
30
+ export declare function createTask<P, T>(task: (params: P, signal: AbortSignal) => Promise<T>): Task<P, T>;
31
+ //# sourceMappingURL=createTask.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createTask.d.ts","sourceRoot":"","sources":["../src/createTask.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,IACtB;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC;IACjB,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAChD,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG;IACnB,GAAG,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAClB,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC;CACrB,GACD,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IAChB,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3B,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC9B,CAAC;AAEN,wBAAgB,UAAU,CAAC,CAAC,EAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3D,IAAI,CAAC,CAAC,CAAC,CAAC;AACX,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAC7B,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACnD,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,79 @@
1
+ import { createCleanup, getCurrentComponent } from "./component";
2
+ import { assignState, createState } from "./createState";
3
+ export function createTask(task) {
4
+ const currentComponent = getCurrentComponent();
5
+ if (!currentComponent || currentComponent.isRendering) {
6
+ throw new Error("Only use createTask in component setup");
7
+ }
8
+ const state = createState({
9
+ isRunning: false,
10
+ result: null,
11
+ error: null,
12
+ params: null,
13
+ });
14
+ let currentAbortController;
15
+ const fetch = (params) => {
16
+ currentAbortController?.abort();
17
+ const abortController = (currentAbortController = new AbortController());
18
+ const promise = task(params, abortController.signal);
19
+ promise
20
+ .then((result) => {
21
+ if (abortController.signal.aborted) {
22
+ return;
23
+ }
24
+ assignState(state, {
25
+ isRunning: false,
26
+ result,
27
+ error: null,
28
+ params: null,
29
+ });
30
+ })
31
+ .catch((error) => {
32
+ if (abortController.signal.aborted) {
33
+ return;
34
+ }
35
+ assignState(state, {
36
+ isRunning: false,
37
+ result: null,
38
+ error: String(error),
39
+ params: null,
40
+ });
41
+ });
42
+ return promise;
43
+ };
44
+ createCleanup(() => currentAbortController?.abort());
45
+ return {
46
+ get isRunning() {
47
+ return state.isRunning;
48
+ },
49
+ get result() {
50
+ return state.result;
51
+ },
52
+ get error() {
53
+ return state.error;
54
+ },
55
+ get params() {
56
+ return state.params;
57
+ },
58
+ run(params) {
59
+ const promise = fetch(params);
60
+ assignState(state, {
61
+ isRunning: true,
62
+ result: null,
63
+ error: null,
64
+ params: (params || null),
65
+ });
66
+ return promise;
67
+ },
68
+ rerun(params) {
69
+ const promise = fetch(params);
70
+ assignState(state, {
71
+ isRunning: true,
72
+ result: state.result,
73
+ error: null,
74
+ params: (params || null),
75
+ });
76
+ return promise;
77
+ },
78
+ };
79
+ }
@@ -1,54 +1,28 @@
1
- type Simplify<T> = {
1
+ type Simplify<T> = T extends any ? {
2
2
  [K in keyof T]: T[K];
3
- } & {};
4
- type MergeTwo<A extends object, B extends object> = Simplify<Omit<A, keyof B> & B>;
3
+ } : never;
4
+ type UndefinedKeys<T> = {
5
+ [K in keyof T]-?: [T[K]] extends [undefined] ? K : never;
6
+ }[keyof T];
7
+ type MergeTwo<A extends object, B extends object> = A extends any ? Simplify<Omit<A, keyof B> & Omit<B, UndefinedKeys<B>>> : never;
5
8
  type MergeMany<T extends readonly object[]> = T extends [
6
9
  infer H extends object,
7
10
  ...infer R extends object[]
8
- ] ? MergeTwo<H, MergeMany<R>> : {};
11
+ ] ? MergeManyAcc<H, R> : {};
12
+ type MergeManyAcc<Acc extends object, Rest extends object[]> = Rest extends [
13
+ infer H extends object,
14
+ ...infer R extends object[]
15
+ ] ? MergeManyAcc<MergeTwo<Acc, H>, R> : Acc;
9
16
  /**
10
- * Creates a view that merges multiple objects (reactive or not) into a single object while
11
- * maintaining reactivity through getters. Properties from later arguments override earlier ones.
12
- *
13
- * @warning **Do not destructure the returned view object!** Destructuring breaks reactivity
14
- * because it extracts plain values instead of maintaining getter access. This is the same rule
15
- * as other reactive primitives.
16
- *
17
- * @example
18
- * // ❌ Bad - destructuring loses reactivity
19
- * function Component() {
20
- * const state = createState({ count: 0 });
21
- * const helpers = { increment: () => state.count++ };
22
- * const view = createView(state, helpers);
23
- * const { count, increment } = view; // Don't do this!
24
- * return () => <button onClick={increment}>{count}</button>; // Won't update!
25
- * }
26
- *
27
- * // ✅ Good - access properties directly in render
28
- * function Component() {
29
- * const state = createState({ count: 0 });
30
- * const helpers = { increment: () => state.count++ };
31
- * const view = createView(state, helpers);
32
- * return () => <button onClick={view.increment}>{view.count}</button>; // Reactive!
33
- * }
34
- *
35
- * @example
36
- * // Merge multiple reactive objects
37
- * const state = createState({ count: 0 });
38
- * const user = createState({ name: "Alice" });
39
- * const view = createView(state, user);
40
- * // view has both count and name properties, maintaining reactivity
41
- *
42
- * @example
43
- * // Later arguments override earlier ones
44
- * const a = { x: 1, y: 2 };
45
- * const b = { y: 3, z: 4 };
46
- * const view = createView(a, b);
47
- * // view.x === 1, view.y === 3, view.z === 4
17
+ * Creates a view that merges multiple objects (reactive or not) into a single
18
+ * object while maintaining reactivity through getters. Properties from later
19
+ * arguments override earlier ones.
48
20
  *
49
- * @param args - Objects to merge (reactive or plain objects)
50
- * @returns A view object with getters for all properties, maintaining reactivity
21
+ * ⚠️ Do not destructure the returned view object; always read properties
22
+ * directly from the view to preserve reactivity.
51
23
  */
24
+ export declare function createView<A extends object>(a: A): A;
25
+ export declare function createView<A extends object, B extends object>(a: A, b: B): MergeTwo<A, B>;
52
26
  export declare function createView<T extends readonly object[]>(...args: T): MergeMany<T>;
53
27
  export {};
54
28
  //# sourceMappingURL=createView.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"createView.d.ts","sourceRoot":"","sources":["../src/createView.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,EAAE,CAAC;AAEjD,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,QAAQ,CAC1D,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,CACrB,CAAC;AAEF,KAAK,SAAS,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,CAAC,SAAS;IACtD,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,GACzB,EAAE,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACpD,GAAG,IAAI,EAAE,CAAC,GACT,SAAS,CAAC,CAAC,CAAC,CA0Bd"}
1
+ {"version":3,"file":"createView.d.ts","sourceRoot":"","sources":["../src/createView.ts"],"names":[],"mappings":"AAGA,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,GAAG,KAAK,CAAC;AAEpE,KAAK,aAAa,CAAC,CAAC,IAAI;KACrB,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK;CACzD,CAAC,MAAM,CAAC,CAAC,CAAC;AAEX,KAAK,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,IAAI,CAAC,SAAS,GAAG,GAC7D,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACtD,KAAK,CAAC;AAEV,KAAK,SAAS,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,IAAI,CAAC,SAAS;IACtD,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAClB,EAAE,CAAC;AAEP,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,EAAE,IAAI,SAAS,MAAM,EAAE,IAAI,IAAI,SAAS;IAC1E,MAAM,CAAC,SAAS,MAAM;IACtB,GAAG,MAAM,CAAC,SAAS,MAAM,EAAE;CAC5B,GACG,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,GAAG,CAAC;AAER;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AACtD,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EAC3D,CAAC,EAAE,CAAC,EACJ,CAAC,EAAE,CAAC,GACH,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAClB,wBAAgB,UAAU,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EACpD,GAAG,IAAI,EAAE,CAAC,GACT,SAAS,CAAC,CAAC,CAAC,CAAC"}
@@ -1,68 +1,77 @@
1
- /**
2
- * Creates a view that merges multiple objects (reactive or not) into a single object while
3
- * maintaining reactivity through getters. Properties from later arguments override earlier ones.
4
- *
5
- * @warning **Do not destructure the returned view object!** Destructuring breaks reactivity
6
- * because it extracts plain values instead of maintaining getter access. This is the same rule
7
- * as other reactive primitives.
8
- *
9
- * @example
10
- * // ❌ Bad - destructuring loses reactivity
11
- * function Component() {
12
- * const state = createState({ count: 0 });
13
- * const helpers = { increment: () => state.count++ };
14
- * const view = createView(state, helpers);
15
- * const { count, increment } = view; // Don't do this!
16
- * return () => <button onClick={increment}>{count}</button>; // Won't update!
17
- * }
18
- *
19
- * // ✅ Good - access properties directly in render
20
- * function Component() {
21
- * const state = createState({ count: 0 });
22
- * const helpers = { increment: () => state.count++ };
23
- * const view = createView(state, helpers);
24
- * return () => <button onClick={view.increment}>{view.count}</button>; // Reactive!
25
- * }
26
- *
27
- * @example
28
- * // Merge multiple reactive objects
29
- * const state = createState({ count: 0 });
30
- * const user = createState({ name: "Alice" });
31
- * const view = createView(state, user);
32
- * // view has both count and name properties, maintaining reactivity
33
- *
34
- * @example
35
- * // Later arguments override earlier ones
36
- * const a = { x: 1, y: 2 };
37
- * const b = { y: 3, z: 4 };
38
- * const view = createView(a, b);
39
- * // view.x === 1, view.y === 3, view.z === 4
40
- *
41
- * @param args - Objects to merge (reactive or plain objects)
42
- * @returns A view object with getters for all properties, maintaining reactivity
43
- */
1
+ import { getCurrentComponent } from "./component";
2
+ import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
44
3
  export function createView(...args) {
4
+ if (!getCurrentComponent()) {
5
+ throw new Error("Only use createView in component setup");
6
+ }
45
7
  const result = {};
46
8
  const seen = new Set();
9
+ let notifyInspectorRef = {};
47
10
  for (let i = args.length - 1; i >= 0; i--) {
48
11
  const src = args[i];
49
- // mimic Object.assign: only enumerable own property keys
12
+ if (!src)
13
+ continue;
14
+ if (INSPECTOR_ENABLED && src[INSPECT_MARKER]) {
15
+ src[INSPECT_MARKER] = notifyInspectorRef;
16
+ }
17
+ // Mimic Object.assign: only enumerable own property keys
50
18
  for (const key of Reflect.ownKeys(src)) {
51
19
  if (seen.has(key))
52
20
  continue;
53
21
  const desc = Object.getOwnPropertyDescriptor(src, key);
54
22
  if (!desc || !desc.enumerable)
55
23
  continue;
56
- // Capture the current source for this key (last write wins).
57
24
  Object.defineProperty(result, key, {
58
25
  enumerable: true,
59
26
  configurable: true,
60
- get: () => src[key],
61
- // Optional write-through (commented out by default):
62
- // set: (value) => { (src as any)[key as any] = value; },
27
+ get: () => {
28
+ const value = src[key];
29
+ if (!INSPECTOR_ENABLED || !notifyInspectorRef.current) {
30
+ return value;
31
+ }
32
+ // Propagate inspector marker into nested observables
33
+ if (value?.[INSPECT_MARKER]) {
34
+ value[INSPECT_MARKER] = {
35
+ current: {
36
+ notify: notifyInspectorRef.current.notify,
37
+ path: notifyInspectorRef.current.path.concat(key),
38
+ },
39
+ };
40
+ }
41
+ else if (typeof value === "function") {
42
+ // Wrap actions to notify inspector
43
+ return (...params) => {
44
+ notifyInspectorRef.current.notify({
45
+ type: "action",
46
+ path: notifyInspectorRef.current.path.concat(key),
47
+ params,
48
+ });
49
+ return value(...params);
50
+ };
51
+ }
52
+ return value;
53
+ },
63
54
  });
64
55
  seen.add(key);
65
56
  }
66
57
  }
58
+ if (INSPECTOR_ENABLED) {
59
+ Object.defineProperty(result, INSPECT_MARKER, {
60
+ enumerable: false,
61
+ configurable: false,
62
+ get() {
63
+ return !notifyInspectorRef.current;
64
+ },
65
+ set: (value) => {
66
+ Object.defineProperty(notifyInspectorRef, "current", {
67
+ configurable: true,
68
+ get() {
69
+ return value.current;
70
+ },
71
+ });
72
+ },
73
+ });
74
+ }
75
+ // The overload signatures expose a precise type; this is the shared impl.
67
76
  return result;
68
77
  }
package/dist/error.d.ts CHANGED
@@ -1,16 +1,5 @@
1
- import { Component, VNode } from "inferno";
2
- export declare class ErrorBoundary extends Component<{
3
- children: any;
4
- error: (error: unknown) => VNode;
5
- }, {
1
+ export declare const CatchErrorContext: import("./createContext").Context<(error: unknown) => void>;
2
+ export declare function useCatchError(): {
6
3
  error: unknown;
7
- }> {
8
- getChildContext(): {
9
- notifyError: (error: unknown) => void;
10
- };
11
- state: {
12
- error: null;
13
- };
14
- render(): any;
15
- }
4
+ };
16
5
  //# sourceMappingURL=error.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE3C,qBAAa,aAAc,SAAQ,SAAS,CAC1C;IAAE,QAAQ,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,KAAK,CAAA;CAAE,EACnD;IAAE,KAAK,EAAE,OAAO,CAAA;CAAE,CACnB;IACC,eAAe;6BAEU,OAAO;;IAKhC,KAAK;;MAAmB;IAExB,MAAM;CAOP"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../src/error.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,iBAAiB,4CAAyB,OAAO,KAAK,IAAI,CAAG,CAAC;AAE3E,wBAAgB,aAAa;WAQK,OAAO;EAOxC"}
package/dist/error.js CHANGED
@@ -1,17 +1,16 @@
1
- import { Component } from "inferno";
2
- export class ErrorBoundary extends Component {
3
- getChildContext() {
4
- return {
5
- notifyError: (error) => {
6
- this.setState({ error });
7
- },
8
- };
9
- }
10
- state = { error: null };
11
- render() {
12
- if (this.state.error) {
13
- return this.props.error(this.state.error);
14
- }
15
- return this.props.children;
1
+ import { useState } from "./useState";
2
+ import { createContext, useInjectContext } from "./createContext";
3
+ import { getCurrentComponent } from "./component";
4
+ export const CatchErrorContext = createContext();
5
+ export function useCatchError() {
6
+ const currentComponent = getCurrentComponent();
7
+ if (!currentComponent || currentComponent.isRendering) {
8
+ throw new Error("Only use the useCatchError hook in setup");
16
9
  }
10
+ const inject = useInjectContext(CatchErrorContext);
11
+ const state = useState({
12
+ error: null,
13
+ });
14
+ inject((error) => (state.error = error));
15
+ return state;
17
16
  }