rask-ui 0.12.4 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -11
- package/dist/component.d.ts +2 -2
- package/dist/component.d.ts.map +1 -1
- package/dist/component.js +3 -4
- package/dist/createContext.d.ts +4 -2
- package/dist/createContext.d.ts.map +1 -1
- package/dist/createContext.js +7 -11
- package/dist/createView.d.ts +5 -1
- package/dist/createView.d.ts.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/useAsync.d.ts +27 -0
- package/dist/useAsync.d.ts.map +1 -0
- package/dist/useAsync.js +72 -0
- package/dist/useComputed.d.ts +5 -0
- package/dist/useComputed.d.ts.map +1 -0
- package/dist/useComputed.js +69 -0
- package/dist/useEffect.d.ts +2 -0
- package/dist/useEffect.d.ts.map +1 -0
- package/dist/useEffect.js +29 -0
- package/dist/useQuery.d.ts +25 -0
- package/dist/useQuery.d.ts.map +1 -0
- package/dist/useQuery.js +25 -0
- package/dist/useRouter.d.ts +8 -0
- package/dist/useRouter.d.ts.map +1 -0
- package/dist/useRouter.js +27 -0
- package/dist/useState.d.ts +28 -0
- package/dist/useState.d.ts.map +1 -0
- package/dist/useState.js +129 -0
- package/dist/useTask.d.ts +25 -0
- package/dist/useTask.d.ts.map +1 -0
- package/dist/useTask.js +70 -0
- package/dist/useView.d.ts +28 -0
- package/dist/useView.d.ts.map +1 -0
- package/dist/useView.js +77 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,10 +25,10 @@ npm run dev
|
|
|
25
25
|
## Quick Example
|
|
26
26
|
|
|
27
27
|
```tsx
|
|
28
|
-
import {
|
|
28
|
+
import { useState, render } from "rask-ui";
|
|
29
29
|
|
|
30
30
|
function Counter() {
|
|
31
|
-
const state =
|
|
31
|
+
const state = useState({ count: 0 });
|
|
32
32
|
|
|
33
33
|
return () => (
|
|
34
34
|
<div>
|
|
@@ -41,17 +41,17 @@ function Counter() {
|
|
|
41
41
|
render(<Counter />, document.getElementById("app"));
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
## Reactive
|
|
44
|
+
## Reactive Hooks
|
|
45
45
|
|
|
46
|
-
RASK provides a set of reactive
|
|
46
|
+
RASK provides a set of reactive hooks for building interactive UIs. These hooks are bound to components like in React, but they are reactive:
|
|
47
47
|
|
|
48
|
-
- **`
|
|
49
|
-
- **`
|
|
50
|
-
- **`
|
|
51
|
-
- **`
|
|
52
|
-
- **`
|
|
53
|
-
- **`createContext`** - Share data through the component tree
|
|
54
|
-
- **`
|
|
48
|
+
- **`useState`** - Create reactive state objects
|
|
49
|
+
- **`useEffect`** - Run side effects when dependencies change
|
|
50
|
+
- **`useComputed`** - Derive values from state with automatic caching
|
|
51
|
+
- **`useAsync`** - Manage async operations (fetch, mutations, polling, etc.)
|
|
52
|
+
- **`useRouter`** - Type-safe client-side routing
|
|
53
|
+
- **`createContext`** / **`useContext`** - Share data through the component tree
|
|
54
|
+
- **`useView`** - Compose state and methods into reusable objects
|
|
55
55
|
|
|
56
56
|
Visit [rask-ui.io](https://rask-ui.io) for complete API documentation and guides.
|
|
57
57
|
|
package/dist/component.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export declare class RaskStatelessComponent extends Component {
|
|
|
8
8
|
render(): VNode;
|
|
9
9
|
}
|
|
10
10
|
export declare function getCurrentComponent(): RaskStatefulComponent<any> | undefined;
|
|
11
|
-
export declare function
|
|
12
|
-
export declare function
|
|
11
|
+
export declare function useMountEffect(cb: () => void): void;
|
|
12
|
+
export declare function useCleanup(cb: () => void): void;
|
|
13
13
|
export type RaskStatefulFunctionComponent<P extends Props<any>> = (() => () => VNode) | ((props: P) => () => VNode);
|
|
14
14
|
export declare class RaskStatefulComponent<P extends Props<any>> extends Component<P> {
|
|
15
15
|
setup: RaskStatefulFunctionComponent<P>;
|
package/dist/component.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAExE,OAAO,EAAsB,QAAQ,EAAU,MAAM,eAAe,CAAC;AAIrE,MAAM,MAAM,8BAA8B,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,IAC3D,CAAC,MAAM,KAAK,CAAC,GACb,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC;AAE1B,qBAAa,sBAAuB,SAAQ,SAAS;IAC3C,QAAQ,EAAE,8BAA8B,CAAC,GAAG,CAAC,CAAC;IACtD,QAAQ,WAEL;IACH,qBAAqB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAUrD,MAAM;CAOP;AAID,wBAAgB,mBAAmB,2CAElC;AAED,wBAAgB,
|
|
1
|
+
{"version":3,"file":"component.d.ts","sourceRoot":"","sources":["../src/component.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAExE,OAAO,EAAsB,QAAQ,EAAU,MAAM,eAAe,CAAC;AAIrE,MAAM,MAAM,8BAA8B,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,IAC3D,CAAC,MAAM,KAAK,CAAC,GACb,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,KAAK,CAAC,CAAC;AAE1B,qBAAa,sBAAuB,SAAQ,SAAS;IAC3C,QAAQ,EAAE,8BAA8B,CAAC,GAAG,CAAC,CAAC;IACtD,QAAQ,WAEL;IACH,qBAAqB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAUrD,MAAM;CAOP;AAID,wBAAgB,mBAAmB,2CAElC;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,IAAI,QAM5C;AAED,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,IAAI,QAMxC;AAED,MAAM,MAAM,6BAA6B,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,IAC1D,CAAC,MAAM,MAAM,KAAK,CAAC,GACnB,CAAC,CAAC,KAAK,EAAE,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC;AAEhC,qBAAa,qBAAqB,CAAC,CAAC,SAAS,KAAK,CAAC,GAAG,CAAC,CAAE,SAAQ,SAAS,CAAC,CAAC,CAAC;IACnE,KAAK,EAAE,6BAA6B,CAAC,CAAC,CAAC,CAAC;IAChD,OAAO,CAAC,QAAQ,CAAC,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAC,CAAa;IACnC,OAAO,CAAC,QAAQ,CAKb;IAEH,WAAW,UAAS;IAEpB,OAAO,CAAC,UAAU,CAAQ;IAG1B,OAAO,CAAC,SAAS,CAAmB;IACpC,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,IAAI,CAAA;KAAE,CAAC,CAAM;IAC3D,QAAQ,gBAAa;IACrB,eAAe;IAUf,QAAQ,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAM;IACjC,UAAU,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAM;IACnC,OAAO,CAAC,mBAAmB;IAyD3B,iBAAiB,IAAI,IAAI;IAGzB,oBAAoB,IAAI,IAAI;IAG5B;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,GAAG;IAkBlC,qBAAqB,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,CAAC,GAAG,OAAO;IAWrD,MAAM;CA0CP;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,SAO9D"}
|
package/dist/component.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createComponentVNode, Component } from "inferno";
|
|
2
2
|
import { getCurrentObserver, Observer, Signal } from "./observation";
|
|
3
3
|
import { syncBatch } from "./batch";
|
|
4
|
-
import { PROXY_MARKER } from "./
|
|
4
|
+
import { PROXY_MARKER } from "./useState";
|
|
5
5
|
export class RaskStatelessComponent extends Component {
|
|
6
6
|
observer = new Observer(() => {
|
|
7
7
|
this.forceUpdate();
|
|
@@ -26,13 +26,13 @@ let currentComponent;
|
|
|
26
26
|
export function getCurrentComponent() {
|
|
27
27
|
return currentComponent;
|
|
28
28
|
}
|
|
29
|
-
export function
|
|
29
|
+
export function useMountEffect(cb) {
|
|
30
30
|
if (!currentComponent) {
|
|
31
31
|
throw new Error("Only use createMountEffect in component setup");
|
|
32
32
|
}
|
|
33
33
|
currentComponent.onMounts.push(cb);
|
|
34
34
|
}
|
|
35
|
-
export function
|
|
35
|
+
export function useCleanup(cb) {
|
|
36
36
|
if (!currentComponent || currentComponent.isRendering) {
|
|
37
37
|
throw new Error("Only use createCleanup in component setup");
|
|
38
38
|
}
|
|
@@ -169,7 +169,6 @@ export class RaskStatefulComponent extends Component {
|
|
|
169
169
|
let result = null;
|
|
170
170
|
try {
|
|
171
171
|
this.isRendering = true;
|
|
172
|
-
console.log("WTF", this.setup.name);
|
|
173
172
|
result = this.renderFn();
|
|
174
173
|
this.isRendering = false;
|
|
175
174
|
this.willRender = false;
|
package/dist/createContext.d.ts
CHANGED
|
@@ -22,9 +22,11 @@
|
|
|
22
22
|
*
|
|
23
23
|
* @returns Context object with inject() and get() methods
|
|
24
24
|
*/
|
|
25
|
-
export
|
|
25
|
+
export type Context<T> = {
|
|
26
26
|
inject(value: T): void;
|
|
27
27
|
get(): T;
|
|
28
|
-
hasValue(): boolean;
|
|
29
28
|
};
|
|
29
|
+
export declare function createContext<T>(): Context<T>;
|
|
30
|
+
export declare function useContext<T>(context: Context<T>, value: T): void;
|
|
31
|
+
export declare function useContext<T>(context: Context<T>): T;
|
|
30
32
|
//# sourceMappingURL=createContext.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createContext.d.ts","sourceRoot":"","sources":["../src/createContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,wBAAgB,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"createContext.d.ts","sourceRoot":"","sources":["../src/createContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IACvB,MAAM,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACvB,GAAG,IAAI,CAAC,CAAC;CACV,CAAC;AAEF,wBAAgB,aAAa,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAqC7C;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;AACnE,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC"}
|
package/dist/createContext.js
CHANGED
|
@@ -46,17 +46,13 @@ export function createContext() {
|
|
|
46
46
|
}
|
|
47
47
|
return contextValue;
|
|
48
48
|
},
|
|
49
|
-
hasValue() {
|
|
50
|
-
let currentComponent = getCurrentComponent();
|
|
51
|
-
if (!currentComponent) {
|
|
52
|
-
throw new Error("You can not get context outside component setup");
|
|
53
|
-
}
|
|
54
|
-
if (typeof currentComponent.context.getContext !== "function") {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
const contextValue = currentComponent.context.getContext(context);
|
|
58
|
-
return Boolean(contextValue);
|
|
59
|
-
},
|
|
60
49
|
};
|
|
61
50
|
return context;
|
|
62
51
|
}
|
|
52
|
+
export function useContext(context, value) {
|
|
53
|
+
if (value) {
|
|
54
|
+
context.inject(value);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
return context.get();
|
|
58
|
+
}
|
package/dist/createView.d.ts
CHANGED
|
@@ -8,7 +8,11 @@ type MergeTwo<A extends object, B extends object> = A extends any ? Simplify<Omi
|
|
|
8
8
|
type MergeMany<T extends readonly object[]> = T extends [
|
|
9
9
|
infer H extends object,
|
|
10
10
|
...infer R extends object[]
|
|
11
|
-
] ?
|
|
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;
|
|
12
16
|
/**
|
|
13
17
|
* Creates a view that merges multiple objects (reactive or not) into a single
|
|
14
18
|
* object while maintaining reactivity through getters. Properties from later
|
package/dist/createView.d.ts.map
CHANGED
|
@@ -1 +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,
|
|
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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export { render } from "./render";
|
|
2
|
-
export {
|
|
3
|
-
export { createContext } from "./createContext";
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
2
|
+
export { useCleanup, useMountEffect, RaskStatefulComponent, RaskStatelessComponent, } from "./component";
|
|
3
|
+
export { createContext, useContext } from "./createContext";
|
|
4
|
+
export { useState, assignState } from "./useState";
|
|
5
|
+
export { useAsync, Async } from "./useAsync";
|
|
6
6
|
export { ErrorBoundary } from "./error";
|
|
7
7
|
export { createRef } from "inferno";
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
8
|
+
export { useView } from "./useView";
|
|
9
|
+
export { useEffect } from "./useEffect";
|
|
10
|
+
export { useComputed } from "./useComputed";
|
|
11
11
|
export { syncBatch } from "./batch";
|
|
12
12
|
export { inspect } from "./inspect";
|
|
13
|
-
export { Router,
|
|
13
|
+
export { Router, useRouter } from "./useRouter";
|
|
14
14
|
export { createVNode, createComponentVNode, createFragment, createTextVNode, normalizeProps, Component, } from "inferno";
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EACL,UAAU,EACV,cAAc,EACd,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,GACV,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export { render } from "./render";
|
|
2
|
-
export {
|
|
3
|
-
export { createContext } from "./createContext";
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
2
|
+
export { useCleanup, useMountEffect, RaskStatefulComponent, RaskStatelessComponent, } from "./component";
|
|
3
|
+
export { createContext, useContext } from "./createContext";
|
|
4
|
+
export { useState, assignState } from "./useState";
|
|
5
|
+
export { useAsync } from "./useAsync";
|
|
6
6
|
export { ErrorBoundary } from "./error";
|
|
7
7
|
export { createRef } from "inferno";
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
8
|
+
export { useView } from "./useView";
|
|
9
|
+
export { useEffect } from "./useEffect";
|
|
10
|
+
export { useComputed } from "./useComputed";
|
|
11
11
|
export { syncBatch } from "./batch";
|
|
12
12
|
export { inspect } from "./inspect";
|
|
13
|
-
export {
|
|
13
|
+
export { useRouter } from "./useRouter";
|
|
14
14
|
// Re-export Inferno JSX runtime functions so users don't need to install Inferno directly
|
|
15
15
|
export { createVNode, createComponentVNode, createFragment, createTextVNode, normalizeProps, Component, } from "inferno";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type AsyncState<P, T, I = null> = {
|
|
2
|
+
isPending: false;
|
|
3
|
+
params: null;
|
|
4
|
+
value: I;
|
|
5
|
+
error: null;
|
|
6
|
+
} | {
|
|
7
|
+
isPending: true;
|
|
8
|
+
value: T | I;
|
|
9
|
+
params: P;
|
|
10
|
+
error: null;
|
|
11
|
+
} | {
|
|
12
|
+
isPending: false;
|
|
13
|
+
params: null;
|
|
14
|
+
value: T;
|
|
15
|
+
error: null;
|
|
16
|
+
} | {
|
|
17
|
+
isPending: false;
|
|
18
|
+
params: null;
|
|
19
|
+
value: T | I;
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
export type Async<A, B = never, I = null> = [B] extends [never] ? [AsyncState<null, A, I>, () => void] : [AsyncState<A, B, I>, (params: A) => void];
|
|
23
|
+
export declare function useAsync<T>(initialValue: T, fn: (params: undefined, signal: AbortSignal) => Promise<T>): Async<T, never, T>;
|
|
24
|
+
export declare function useAsync<P, T>(initialValue: T, fn: (params: P, signal: AbortSignal) => Promise<T>): Async<P, T, T>;
|
|
25
|
+
export declare function useAsync<T>(fn: (params: undefined, signal: AbortSignal) => Promise<T>): Async<T>;
|
|
26
|
+
export declare function useAsync<P, T>(fn: (params: P, signal: AbortSignal) => Promise<T>): Async<P, T>;
|
|
27
|
+
//# sourceMappingURL=useAsync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAsync.d.ts","sourceRoot":"","sources":["../src/useAsync.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,IACjC;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,MAAM,EAAE,CAAC,CAAC;IACV,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,IAAI,CAAC;CACb,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,MAAM,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEN,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAC3D,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,GACpC,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;AAE/C,wBAAgB,QAAQ,CAAC,CAAC,EACxB,YAAY,EAAE,CAAC,EACf,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACzD,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACtB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,YAAY,EAAE,CAAC,EACf,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACjD,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAClB,wBAAgB,QAAQ,CAAC,CAAC,EACxB,EAAE,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACzD,KAAK,CAAC,CAAC,CAAC,CAAC;AACZ,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACjD,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC"}
|
package/dist/useAsync.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useCleanup, getCurrentComponent } from "./component";
|
|
2
|
+
import { assignState, useState } from "./useState";
|
|
3
|
+
export function useAsync(...args) {
|
|
4
|
+
const currentComponent = getCurrentComponent();
|
|
5
|
+
if (!currentComponent || currentComponent.isRendering) {
|
|
6
|
+
throw new Error("Only use createTask in component setup");
|
|
7
|
+
}
|
|
8
|
+
const value = args.length === 2 ? args[0] : null;
|
|
9
|
+
const fn = args.length === 2 ? args[1] : args[0];
|
|
10
|
+
const state = useState({
|
|
11
|
+
isPending: false,
|
|
12
|
+
value,
|
|
13
|
+
error: null,
|
|
14
|
+
params: null,
|
|
15
|
+
});
|
|
16
|
+
let currentAbortController;
|
|
17
|
+
const fetch = (params) => {
|
|
18
|
+
currentAbortController?.abort();
|
|
19
|
+
const abortController = (currentAbortController = new AbortController());
|
|
20
|
+
const promise = fn(params, abortController.signal);
|
|
21
|
+
promise
|
|
22
|
+
.then((result) => {
|
|
23
|
+
if (abortController.signal.aborted) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
assignState(state, {
|
|
27
|
+
isPending: false,
|
|
28
|
+
value: result,
|
|
29
|
+
error: null,
|
|
30
|
+
params: null,
|
|
31
|
+
});
|
|
32
|
+
})
|
|
33
|
+
.catch((error) => {
|
|
34
|
+
if (abortController.signal.aborted) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
assignState(state, {
|
|
38
|
+
isPending: false,
|
|
39
|
+
value: state.value,
|
|
40
|
+
error: String(error),
|
|
41
|
+
params: null,
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
return promise;
|
|
45
|
+
};
|
|
46
|
+
useCleanup(() => currentAbortController?.abort());
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
get isPending() {
|
|
50
|
+
return state.isPending;
|
|
51
|
+
},
|
|
52
|
+
get value() {
|
|
53
|
+
return state.value;
|
|
54
|
+
},
|
|
55
|
+
get error() {
|
|
56
|
+
return state.error;
|
|
57
|
+
},
|
|
58
|
+
get params() {
|
|
59
|
+
return state.params;
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
(params) => {
|
|
63
|
+
fetch(params);
|
|
64
|
+
assignState(state, {
|
|
65
|
+
isPending: true,
|
|
66
|
+
value: state.value,
|
|
67
|
+
error: null,
|
|
68
|
+
params: (params || null),
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useComputed.d.ts","sourceRoot":"","sources":["../src/useComputed.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,IAAI;KACzD,CAAC,IAAI,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACjC,CAAC;AAEF,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,EAC7D,QAAQ,EAAE,CAAC,GACV,QAAQ,CAAC,CAAC,CAAC,CA0Eb"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getCurrentComponent, useCleanup } from "./component";
|
|
2
|
+
import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
|
|
3
|
+
import { getCurrentObserver, Observer, Signal } from "./observation";
|
|
4
|
+
export function useComputed(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
|
+
useCleanup(() => 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 @@
|
|
|
1
|
+
{"version":3,"file":"useEffect.d.ts","sourceRoot":"","sources":["../src/useEffect.ts"],"names":[],"mappings":"AAIA,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,QA2BtD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { syncBatch } from "./batch";
|
|
2
|
+
import { useCleanup, getCurrentComponent } from "./component";
|
|
3
|
+
import { Observer } from "./observation";
|
|
4
|
+
export function useEffect(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
|
+
useCleanup(() => {
|
|
25
|
+
observer.dispose();
|
|
26
|
+
disposer?.();
|
|
27
|
+
});
|
|
28
|
+
runEffect();
|
|
29
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
type QueryState<T, I = null> = {
|
|
2
|
+
isPending: true;
|
|
3
|
+
error: null;
|
|
4
|
+
value: I;
|
|
5
|
+
} | {
|
|
6
|
+
isPending: false;
|
|
7
|
+
error: null;
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
isPending: false;
|
|
11
|
+
error: string;
|
|
12
|
+
value: I | null;
|
|
13
|
+
};
|
|
14
|
+
export type Query<T, P, I = null> = [
|
|
15
|
+
QueryState<T, I>,
|
|
16
|
+
[
|
|
17
|
+
P
|
|
18
|
+
] extends [never] ? (params: P) => void : () => void
|
|
19
|
+
];
|
|
20
|
+
export declare function useQuery<T>(query: () => Promise<T>): Query<T, never>;
|
|
21
|
+
export declare function useQuery<T>(query: () => Promise<T>, initialValue: T): Query<T, never, T>;
|
|
22
|
+
export declare function useQuery<T, P>(query: (params: P) => Promise<T>): Query<T, never>;
|
|
23
|
+
export declare function useQuery<T, P>(query: (params: P) => Promise<T>, initialValue: T): Query<T, never, T>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=useQuery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useQuery.d.ts","sourceRoot":"","sources":["../src/useQuery.ts"],"names":[],"mappings":"AAGA,KAAK,UAAU,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,IACvB;IACE,SAAS,EAAE,IAAI,CAAC;IAChB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC;CACV,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC;IACZ,KAAK,EAAE,CAAC,CAAC;CACV,GACD;IACE,SAAS,EAAE,KAAK,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CACjB,CAAC;AAEN,MAAM,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,IAAI;IAClC,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC;IAChB;QAAC,CAAC;KAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI;CACvD,CAAC;AAEF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACtE,wBAAgB,QAAQ,CAAC,CAAC,EACxB,KAAK,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACvB,YAAY,EAAE,CAAC,GACd,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACtB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,GAC/B,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACnB,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAC3B,KAAK,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAChC,YAAY,EAAE,CAAC,GACd,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC"}
|
package/dist/useQuery.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useEffect } from "./useEffect";
|
|
2
|
+
import { useTask } from "./useTask";
|
|
3
|
+
export function useQuery(query, initialValue) {
|
|
4
|
+
const [taskState, runTask] = useTask(query);
|
|
5
|
+
let lastValue = initialValue === undefined ? null : initialValue;
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (taskState.result) {
|
|
8
|
+
lastValue = taskState.result;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
return [
|
|
12
|
+
{
|
|
13
|
+
get value() {
|
|
14
|
+
return taskState.result || lastValue;
|
|
15
|
+
},
|
|
16
|
+
get isPending() {
|
|
17
|
+
return taskState.isPending;
|
|
18
|
+
},
|
|
19
|
+
get error() {
|
|
20
|
+
return taskState.error;
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
runTask,
|
|
24
|
+
];
|
|
25
|
+
}
|
|
@@ -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 useRouter<const T extends RoutesConfig>(config: T, options?: {
|
|
6
|
+
base?: string;
|
|
7
|
+
}): Router<T>;
|
|
8
|
+
//# sourceMappingURL=useRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRouter.d.ts","sourceRoot":"","sources":["../src/useRouter.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,SAAS,CAAC,KAAK,CAAC,CAAC,SAAS,YAAY,EACpD,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 { useCleanup, getCurrentComponent } from "./component";
|
|
4
|
+
export function useRouter(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
|
+
useCleanup(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
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare function assignState<T extends object>(state: T, newState: T): T;
|
|
2
|
+
/**
|
|
3
|
+
* Creates a reactive state object that tracks property access and notifies observers on changes.
|
|
4
|
+
*
|
|
5
|
+
* @warning **Do not destructure the returned reactive object!** Destructuring breaks reactivity
|
|
6
|
+
* because it extracts plain values instead of maintaining proxy access. This is the same rule
|
|
7
|
+
* as Solid.js signals.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // ❌ Bad - destructuring loses reactivity
|
|
11
|
+
* function Component(props) {
|
|
12
|
+
* const state = createState({ count: 0, name: "foo" });
|
|
13
|
+
* const { count, name } = state; // Don't do this!
|
|
14
|
+
* return () => <div>{count} {name}</div>; // Won't update!
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* // ✅ Good - access properties directly in render
|
|
18
|
+
* function Component(props) {
|
|
19
|
+
* const state = createState({ count: 0, name: "foo" });
|
|
20
|
+
* return () => <div>{state.count} {state.name}</div>; // Reactive!
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* @param state - The initial state object to make reactive
|
|
24
|
+
* @returns A reactive proxy of the state object
|
|
25
|
+
*/
|
|
26
|
+
export declare function useState<T extends object>(state: T): T;
|
|
27
|
+
export declare const PROXY_MARKER: unique symbol;
|
|
28
|
+
//# sourceMappingURL=useState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useState.d.ts","sourceRoot":"","sources":["../src/useState.ts"],"names":[],"mappings":"AAIA,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,KAElE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAOtD;AAGD,eAAO,MAAM,YAAY,eAAoB,CAAC"}
|
package/dist/useState.js
ADDED
|
@@ -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 useState(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,25 @@
|
|
|
1
|
+
export type TaskState<P, T> = {
|
|
2
|
+
isPending: false;
|
|
3
|
+
params: null;
|
|
4
|
+
result: null;
|
|
5
|
+
error: null;
|
|
6
|
+
} | {
|
|
7
|
+
isPending: true;
|
|
8
|
+
result: T | null;
|
|
9
|
+
params: P;
|
|
10
|
+
error: null;
|
|
11
|
+
} | {
|
|
12
|
+
isPending: false;
|
|
13
|
+
params: null;
|
|
14
|
+
result: T;
|
|
15
|
+
error: null;
|
|
16
|
+
} | {
|
|
17
|
+
isPending: false;
|
|
18
|
+
params: null;
|
|
19
|
+
result: null;
|
|
20
|
+
error: string;
|
|
21
|
+
};
|
|
22
|
+
export type Task<A, B = never> = [B] extends [never] ? [TaskState<null, A>, () => void] : [TaskState<A, B>, (params: A) => void];
|
|
23
|
+
export declare function useTask<T>(task: (params: undefined, signal: AbortSignal) => Promise<T>): Task<T>;
|
|
24
|
+
export declare function useTask<P, T>(task: (params: P, signal: AbortSignal) => Promise<T>): Task<P, T>;
|
|
25
|
+
//# sourceMappingURL=useTask.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTask.d.ts","sourceRoot":"","sources":["../src/useTask.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,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,GAChC,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,CAAC;AAE3C,wBAAgB,OAAO,CAAC,CAAC,EACvB,IAAI,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAC3D,IAAI,CAAC,CAAC,CAAC,CAAC;AACX,wBAAgB,OAAO,CAAC,CAAC,EAAE,CAAC,EAC1B,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GACnD,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC"}
|
package/dist/useTask.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { useCleanup, getCurrentComponent } from "./component";
|
|
2
|
+
import { assignState, useState } from "./useState";
|
|
3
|
+
export function useTask(task) {
|
|
4
|
+
const currentComponent = getCurrentComponent();
|
|
5
|
+
if (!currentComponent || currentComponent.isRendering) {
|
|
6
|
+
throw new Error("Only use createTask in component setup");
|
|
7
|
+
}
|
|
8
|
+
const state = useState({
|
|
9
|
+
isPending: 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
|
+
isPending: 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
|
+
isPending: false,
|
|
37
|
+
result: null,
|
|
38
|
+
error: String(error),
|
|
39
|
+
params: null,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
return promise;
|
|
43
|
+
};
|
|
44
|
+
useCleanup(() => currentAbortController?.abort());
|
|
45
|
+
return [
|
|
46
|
+
{
|
|
47
|
+
get isPending() {
|
|
48
|
+
return state.isPending;
|
|
49
|
+
},
|
|
50
|
+
get result() {
|
|
51
|
+
return state.result;
|
|
52
|
+
},
|
|
53
|
+
get error() {
|
|
54
|
+
return state.error;
|
|
55
|
+
},
|
|
56
|
+
get params() {
|
|
57
|
+
return state.params;
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
(params) => {
|
|
61
|
+
fetch(params);
|
|
62
|
+
assignState(state, {
|
|
63
|
+
isPending: true,
|
|
64
|
+
result: null,
|
|
65
|
+
error: null,
|
|
66
|
+
params: (params || null),
|
|
67
|
+
});
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
}
|
|
@@ -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 useView<A extends object>(a: A): A;
|
|
25
|
+
export declare function useView<A extends object, B extends object>(a: A, b: B): MergeTwo<A, B>;
|
|
26
|
+
export declare function useView<T extends readonly object[]>(...args: T): MergeMany<T>;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=useView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useView.d.ts","sourceRoot":"","sources":["../src/useView.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,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;AACnD,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,EACxD,CAAC,EAAE,CAAC,EACJ,CAAC,EAAE,CAAC,GACH,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAClB,wBAAgB,OAAO,CAAC,CAAC,SAAS,SAAS,MAAM,EAAE,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC"}
|
package/dist/useView.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { getCurrentComponent } from "./component";
|
|
2
|
+
import { INSPECT_MARKER, INSPECTOR_ENABLED } from "./inspect";
|
|
3
|
+
export function useView(...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
|
+
}
|