rask-ui 0.27.0 → 0.28.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.
Files changed (87) hide show
  1. package/dist/compiler.d.ts +4 -0
  2. package/dist/compiler.d.ts.map +1 -0
  3. package/dist/compiler.js +7 -0
  4. package/dist/component.d.ts.map +1 -1
  5. package/dist/component.js +9 -4
  6. package/dist/createAsync.d.ts +39 -0
  7. package/dist/createAsync.d.ts.map +1 -0
  8. package/dist/createAsync.js +47 -0
  9. package/dist/createComputed.d.ts +4 -0
  10. package/dist/createComputed.d.ts.map +1 -0
  11. package/dist/createComputed.js +69 -0
  12. package/dist/createEffect.d.ts +2 -0
  13. package/dist/createEffect.d.ts.map +1 -0
  14. package/dist/createEffect.js +29 -0
  15. package/dist/createMutation.d.ts +43 -0
  16. package/dist/createMutation.d.ts.map +1 -0
  17. package/dist/createMutation.js +76 -0
  18. package/dist/createQuery.d.ts +42 -0
  19. package/dist/createQuery.d.ts.map +1 -0
  20. package/dist/createQuery.js +80 -0
  21. package/dist/createRouter.d.ts +8 -0
  22. package/dist/createRouter.d.ts.map +1 -0
  23. package/dist/createRouter.js +27 -0
  24. package/dist/createState.d.ts +28 -0
  25. package/dist/createState.d.ts.map +1 -0
  26. package/dist/createState.js +129 -0
  27. package/dist/createTask.d.ts +31 -0
  28. package/dist/createTask.d.ts.map +1 -0
  29. package/dist/createTask.js +79 -0
  30. package/dist/createView.d.ts +28 -0
  31. package/dist/createView.d.ts.map +1 -0
  32. package/dist/createView.js +77 -0
  33. package/dist/error.d.ts +5 -0
  34. package/dist/error.d.ts.map +1 -0
  35. package/dist/error.js +16 -0
  36. package/dist/jsx.d.ts +11 -0
  37. package/dist/patchInferno.d.ts +6 -0
  38. package/dist/patchInferno.d.ts.map +1 -0
  39. package/dist/patchInferno.js +53 -0
  40. package/dist/scheduler.d.ts +4 -0
  41. package/dist/scheduler.d.ts.map +1 -0
  42. package/dist/scheduler.js +107 -0
  43. package/dist/tests/batch.test.d.ts +2 -0
  44. package/dist/tests/batch.test.d.ts.map +1 -0
  45. package/dist/tests/batch.test.js +244 -0
  46. package/dist/tests/createComputed.test.d.ts +2 -0
  47. package/dist/tests/createComputed.test.d.ts.map +1 -0
  48. package/dist/tests/createComputed.test.js +257 -0
  49. package/dist/tests/createContext.test.d.ts +2 -0
  50. package/dist/tests/createContext.test.d.ts.map +1 -0
  51. package/dist/tests/createContext.test.js +136 -0
  52. package/dist/tests/createEffect.test.d.ts +2 -0
  53. package/dist/tests/createEffect.test.d.ts.map +1 -0
  54. package/dist/tests/createEffect.test.js +467 -0
  55. package/dist/tests/createState.test.d.ts +2 -0
  56. package/dist/tests/createState.test.d.ts.map +1 -0
  57. package/dist/tests/createState.test.js +144 -0
  58. package/dist/tests/createTask.test.d.ts +2 -0
  59. package/dist/tests/createTask.test.d.ts.map +1 -0
  60. package/dist/tests/createTask.test.js +322 -0
  61. package/dist/tests/createView.test.d.ts +2 -0
  62. package/dist/tests/createView.test.d.ts.map +1 -0
  63. package/dist/tests/createView.test.js +203 -0
  64. package/dist/tests/error.test.d.ts +2 -0
  65. package/dist/tests/error.test.d.ts.map +1 -0
  66. package/dist/tests/error.test.js +168 -0
  67. package/dist/tests/observation.test.d.ts +2 -0
  68. package/dist/tests/observation.test.d.ts.map +1 -0
  69. package/dist/tests/observation.test.js +341 -0
  70. package/dist/transformer.d.ts.map +1 -1
  71. package/dist/transformer.js +1 -1
  72. package/dist/types.d.ts +6 -1
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/useComputed.d.ts +5 -0
  75. package/dist/useComputed.d.ts.map +1 -0
  76. package/dist/useComputed.js +69 -0
  77. package/dist/useQuery.d.ts +25 -0
  78. package/dist/useQuery.d.ts.map +1 -0
  79. package/dist/useQuery.js +25 -0
  80. package/dist/useSuspendAsync.d.ts +18 -0
  81. package/dist/useSuspendAsync.d.ts.map +1 -0
  82. package/dist/useSuspendAsync.js +37 -0
  83. package/dist/useTask.d.ts +25 -0
  84. package/dist/useTask.d.ts.map +1 -0
  85. package/dist/useTask.js +70 -0
  86. package/package.json +1 -1
  87. package/swc-plugin/target/wasm32-wasip1/release/swc_plugin_rask_component.wasm +0 -0
@@ -0,0 +1,129 @@
1
+ import { getCurrentComponent } from "./component";
2
+ import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
3
+ import { getCurrentObserver, Signal } from "./observation";
4
+ export function assignState(state, newState) {
5
+ return Object.assign(state, newState);
6
+ }
7
+ /**
8
+ * Creates a reactive state object that tracks property access and notifies observers on changes.
9
+ *
10
+ * @warning **Do not destructure the returned reactive object!** Destructuring breaks reactivity
11
+ * because it extracts plain values instead of maintaining proxy access. This is the same rule
12
+ * as Solid.js signals.
13
+ *
14
+ * @example
15
+ * // ❌ Bad - destructuring loses reactivity
16
+ * function Component(props) {
17
+ * const state = createState({ count: 0, name: "foo" });
18
+ * const { count, name } = state; // Don't do this!
19
+ * return () => <div>{count} {name}</div>; // Won't update!
20
+ * }
21
+ *
22
+ * // ✅ Good - access properties directly in render
23
+ * function Component(props) {
24
+ * const state = createState({ count: 0, name: "foo" });
25
+ * return () => <div>{state.count} {state.name}</div>; // Reactive!
26
+ * }
27
+ *
28
+ * @param state - The initial state object to make reactive
29
+ * @returns A reactive proxy of the state object
30
+ */
31
+ export function createState(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, {});
36
+ }
37
+ const proxyCache = new WeakMap();
38
+ export const PROXY_MARKER = Symbol("isProxy");
39
+ function getProxy(value, notifyInspectorRef) {
40
+ // Check if already a proxy to avoid double-wrapping
41
+ if (PROXY_MARKER in value) {
42
+ return value;
43
+ }
44
+ if (proxyCache.has(value)) {
45
+ return proxyCache.get(value);
46
+ }
47
+ const signals = {};
48
+ const proxy = new Proxy(value, {
49
+ has(target, key) {
50
+ // Support the "in" operator check for PROXY_MARKER
51
+ if (key === PROXY_MARKER) {
52
+ return true;
53
+ }
54
+ if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
55
+ return true;
56
+ }
57
+ return Reflect.has(target, key);
58
+ },
59
+ get(target, key) {
60
+ // Mark this as a proxy to prevent double-wrapping
61
+ if (key === PROXY_MARKER) {
62
+ return true;
63
+ }
64
+ if (INSPECTOR_ENABLED && key === INSPECT_MARKER) {
65
+ return !notifyInspectorRef.current;
66
+ }
67
+ const value = Reflect.get(target, key);
68
+ if (typeof key === "symbol" || typeof value === "function") {
69
+ return value;
70
+ }
71
+ const observer = getCurrentObserver();
72
+ if (observer) {
73
+ const signal = (signals[key] = signals[key] || new Signal());
74
+ observer.subscribeSignal(signal);
75
+ }
76
+ if (Array.isArray(value) ||
77
+ (typeof value === "object" && value !== null)) {
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);
86
+ }
87
+ return value;
88
+ },
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
+ }
98
+ if (typeof key === "symbol") {
99
+ return Reflect.set(target, key, newValue);
100
+ }
101
+ const oldValue = Reflect.get(target, key);
102
+ const setResult = Reflect.set(target, key, newValue);
103
+ // We only notify if actual change, though array length actually updates under the hood
104
+ if (newValue !== oldValue || (Array.isArray(value) && key === "length")) {
105
+ const signal = signals[key];
106
+ signal?.notify();
107
+ }
108
+ if (INSPECTOR_ENABLED) {
109
+ notifyInspectorRef.current?.notify({
110
+ type: "mutation",
111
+ path: notifyInspectorRef.current.path,
112
+ value: newValue,
113
+ });
114
+ }
115
+ return setResult;
116
+ },
117
+ deleteProperty(target, key) {
118
+ if (typeof key === "symbol") {
119
+ return Reflect.deleteProperty(target, key);
120
+ }
121
+ const signal = signals[key];
122
+ signal?.notify();
123
+ delete signals[key];
124
+ return Reflect.deleteProperty(target, key);
125
+ },
126
+ });
127
+ proxyCache.set(value, proxy);
128
+ return proxy;
129
+ }
@@ -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
+ }
@@ -0,0 +1,28 @@
1
+ type Simplify<T> = T extends any ? {
2
+ [K in keyof T]: T[K];
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;
8
+ type MergeMany<T extends readonly object[]> = T extends [
9
+ infer H extends object,
10
+ ...infer R extends object[]
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;
16
+ /**
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.
20
+ *
21
+ * ⚠️ Do not destructure the returned view object; always read properties
22
+ * directly from the view to preserve reactivity.
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>;
26
+ export declare function createView<T extends readonly object[]>(...args: T): MergeMany<T>;
27
+ export {};
28
+ //# sourceMappingURL=createView.d.ts.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,77 @@
1
+ import { getCurrentComponent } from "./component";
2
+ import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
3
+ export function createView(...args) {
4
+ if (!getCurrentComponent()) {
5
+ throw new Error("Only use createView in component setup");
6
+ }
7
+ const result = {};
8
+ const seen = new Set();
9
+ let notifyInspectorRef = {};
10
+ for (let i = args.length - 1; i >= 0; i--) {
11
+ const src = args[i];
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
18
+ for (const key of Reflect.ownKeys(src)) {
19
+ if (seen.has(key))
20
+ continue;
21
+ const desc = Object.getOwnPropertyDescriptor(src, key);
22
+ if (!desc || !desc.enumerable)
23
+ continue;
24
+ Object.defineProperty(result, key, {
25
+ enumerable: true,
26
+ configurable: true,
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
+ },
54
+ });
55
+ seen.add(key);
56
+ }
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.
76
+ return result;
77
+ }
@@ -0,0 +1,5 @@
1
+ export declare const CatchErrorContext: import("./createContext").Context<(error: unknown) => void>;
2
+ export declare function useCatchError(): {
3
+ error: unknown;
4
+ };
5
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
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 ADDED
@@ -0,0 +1,16 @@
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");
9
+ }
10
+ const inject = useInjectContext(CatchErrorContext);
11
+ const state = useState({
12
+ error: null,
13
+ });
14
+ inject((error) => (state.error = error));
15
+ return state;
16
+ }
package/dist/jsx.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ // JSX type definitions
2
+ // Re-export Inferno's comprehensive JSX types
3
+ import 'inferno';
4
+
5
+ // Re-export useful Inferno types for convenience
6
+ export type {
7
+ InfernoNode,
8
+ InfernoChild,
9
+ Component,
10
+ ComponentType,
11
+ } from 'inferno';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Temporarily patches document.addEventListener during render to capture
3
+ * and wrap Inferno's delegated event listeners with syncBatch
4
+ */
5
+ export declare function patchInfernoEventHandling(renderFn: () => void): void;
6
+ //# sourceMappingURL=patchInferno.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patchInferno.d.ts","sourceRoot":"","sources":["../src/patchInferno.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,IAAI,QA0D7D"}
@@ -0,0 +1,53 @@
1
+ import { syncBatch } from "./batch";
2
+ /**
3
+ * Temporarily patches document.addEventListener during render to capture
4
+ * and wrap Inferno's delegated event listeners with syncBatch
5
+ */
6
+ export function patchInfernoEventHandling(renderFn) {
7
+ const originalAddEventListener = document.addEventListener.bind(document);
8
+ const patchedEvents = new Set();
9
+ // Inferno's delegated events
10
+ const INFERNO_EVENTS = [
11
+ "click",
12
+ "dblclick",
13
+ "focusin",
14
+ "focusout",
15
+ "keydown",
16
+ "keypress",
17
+ "keyup",
18
+ "mousedown",
19
+ "mousemove",
20
+ "mouseup",
21
+ "touchend",
22
+ "touchmove",
23
+ "touchstart",
24
+ "change",
25
+ "input",
26
+ "submit",
27
+ ];
28
+ // Temporarily replace addEventListener
29
+ document.addEventListener = function (type, listener, options) {
30
+ // Only wrap Inferno's delegated event listeners
31
+ if (INFERNO_EVENTS.includes(type) &&
32
+ typeof listener === "function" &&
33
+ !patchedEvents.has(type)) {
34
+ patchedEvents.add(type);
35
+ const wrappedListener = function (event) {
36
+ syncBatch(() => {
37
+ listener.call(this, event);
38
+ });
39
+ };
40
+ return originalAddEventListener(type, wrappedListener, options);
41
+ }
42
+ // @ts-ignore
43
+ return originalAddEventListener(type, listener, options);
44
+ };
45
+ try {
46
+ // Call render - Inferno will synchronously attach its listeners
47
+ renderFn();
48
+ }
49
+ finally {
50
+ // Restore original addEventListener
51
+ document.addEventListener = originalAddEventListener;
52
+ }
53
+ }
@@ -0,0 +1,4 @@
1
+ export declare function markDirty(): void;
2
+ export declare function enqueueUpdateFromSetter(): void;
3
+ export declare function installGlobalBatching(target?: EventTarget): () => void;
4
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAIA,wBAAgB,SAAS,SAExB;AAeD,wBAAgB,uBAAuB,SAWtC;AAmED,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,WAAoB,cAoBjE"}
@@ -0,0 +1,107 @@
1
+ let depth = 0; // batching scope nesting
2
+ let dirty = false; // has any state update been enqueued?
3
+ let scheduled = false; // async flush scheduled?
4
+ export function markDirty() {
5
+ dirty = true;
6
+ }
7
+ function performWork() {
8
+ // TODO: call your Inferno render/commit once.
9
+ // infernoRender(vnode, container);
10
+ }
11
+ function flushNow() {
12
+ scheduled = false;
13
+ if (!dirty)
14
+ return;
15
+ dirty = false;
16
+ performWork();
17
+ }
18
+ // Called by setters after enqueueing their state change
19
+ export function enqueueUpdateFromSetter() {
20
+ dirty = true;
21
+ if (depth > 0) {
22
+ // We're inside a batched input event; we'll flush on exit (same frame).
23
+ return;
24
+ }
25
+ if (!scheduled) {
26
+ scheduled = true;
27
+ queueMicrotask(flushNow); // one flush per task
28
+ }
29
+ }
30
+ // Batch-scope control used by the global capture listeners
31
+ function enter() {
32
+ depth++;
33
+ }
34
+ function exit() {
35
+ if (--depth === 0) {
36
+ // End of the event propagation; commit now (before next paint).
37
+ flushNow();
38
+ }
39
+ }
40
+ // eventBatching.ts
41
+ const INTERACTIVE_EVENTS = [
42
+ // Pointer + mouse
43
+ "click",
44
+ "dblclick",
45
+ "contextmenu",
46
+ "mousedown",
47
+ "mouseup",
48
+ "mousemove",
49
+ "pointerdown",
50
+ "pointerup",
51
+ "pointermove",
52
+ "touchstart",
53
+ "touchmove",
54
+ "touchend",
55
+ "touchcancel",
56
+ "dragstart",
57
+ "drag",
58
+ "dragend",
59
+ "dragenter",
60
+ "dragleave",
61
+ "dragover",
62
+ "drop",
63
+ "wheel",
64
+ // Keyboard
65
+ "keydown",
66
+ "keypress",
67
+ "keyup",
68
+ // Focus & input
69
+ "focus",
70
+ "blur",
71
+ "focusin",
72
+ "focusout",
73
+ "input",
74
+ "beforeinput",
75
+ "change",
76
+ "compositionstart",
77
+ "compositionupdate",
78
+ "compositionend",
79
+ // Forms
80
+ "submit",
81
+ "reset",
82
+ // Selection / clipboard
83
+ "select",
84
+ "selectionchange",
85
+ "copy",
86
+ "cut",
87
+ "paste",
88
+ ];
89
+ export function installGlobalBatching(target = window) {
90
+ const handlers = [];
91
+ INTERACTIVE_EVENTS.forEach((type) => {
92
+ const onCapture = () => {
93
+ enter();
94
+ // Close the scope after all handlers (capture→target→bubble) have run.
95
+ queueMicrotask(exit);
96
+ };
97
+ target.addEventListener(type, onCapture, { capture: true });
98
+ handlers.push([onCapture, { capture: true }]);
99
+ });
100
+ // Return a disposer so you can remove on unmount
101
+ return () => {
102
+ INTERACTIVE_EVENTS.forEach((type, i) => {
103
+ const [fn, opts] = handlers[i];
104
+ target.removeEventListener(type, fn, opts);
105
+ });
106
+ };
107
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=batch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.test.d.ts","sourceRoot":"","sources":["../../src/tests/batch.test.ts"],"names":[],"mappings":""}