rask-ui 0.12.5 → 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 CHANGED
@@ -25,10 +25,10 @@ npm run dev
25
25
  ## Quick Example
26
26
 
27
27
  ```tsx
28
- import { createState, render } from "rask-ui";
28
+ import { useState, render } from "rask-ui";
29
29
 
30
30
  function Counter() {
31
- const state = createState({ count: 0 });
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 Primitives
44
+ ## Reactive Hooks
45
45
 
46
- RASK provides a set of reactive primitives for building interactive UIs:
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
- - **`createState`** - Create reactive state objects
49
- - **`createEffect`** - Run side effects when dependencies change
50
- - **`createComputed`** - Derive values from state with automatic caching
51
- - **`createTask`** - Manage async operations (fetch, mutations, etc.)
52
- - **`createRouter`** - Type-safe client-side routing
53
- - **`createContext`** - Share data through the component tree
54
- - **`createView`** - Compose state and methods into reusable objects
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
 
@@ -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 createMountEffect(cb: () => void): void;
12
- export declare function createCleanup(cb: () => void): void;
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>;
@@ -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,iBAAiB,CAAC,EAAE,EAAE,MAAM,IAAI,QAM/C;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,IAAI,QAM3C;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;CA2CP;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,SAO9D"}
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 "./createState";
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 createMountEffect(cb) {
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 createCleanup(cb) {
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;
@@ -22,9 +22,11 @@
22
22
  *
23
23
  * @returns Context object with inject() and get() methods
24
24
  */
25
- export declare function createContext<T>(): {
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;kBAEb,CAAC;WASR,CAAC;;EA2CX"}
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"}
@@ -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/index.d.ts CHANGED
@@ -1,15 +1,15 @@
1
1
  export { render } from "./render";
2
- export { createCleanup, createMountEffect, RaskStatefulComponent, RaskStatelessComponent, } from "./component";
3
- export { createContext } from "./createContext";
4
- export { createState, assignState } from "./createState";
5
- export { createTask, TaskState as Task } from "./createTask";
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 { createView } from "./createView";
9
- export { createEffect } from "./createEffect";
10
- export { createComputed } from "./createComputed";
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, createRouter } from "./createRouter";
13
+ export { Router, useRouter } from "./useRouter";
14
14
  export { createVNode, createComponentVNode, createFragment, createTextVNode, normalizeProps, Component, } from "inferno";
15
15
  //# sourceMappingURL=index.d.ts.map
@@ -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,aAAa,EACb,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,SAAS,IAAI,IAAI,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGtD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,GACV,MAAM,SAAS,CAAC"}
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 { createCleanup, createMountEffect, RaskStatefulComponent, RaskStatelessComponent, } from "./component";
3
- export { createContext } from "./createContext";
4
- export { createState, assignState } from "./createState";
5
- export { createTask } from "./createTask";
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 { createView } from "./createView";
9
- export { createEffect } from "./createEffect";
10
- export { createComputed } from "./createComputed";
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 { createRouter } from "./createRouter";
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"}
@@ -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,5 @@
1
+ export type Computed<T extends Record<string, () => any>> = {
2
+ [K in keyof T]: ReturnType<T[K]>;
3
+ };
4
+ export declare function useComputed<T extends Record<string, () => any>>(computed: T): Computed<T>;
5
+ //# sourceMappingURL=useComputed.d.ts.map
@@ -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,2 @@
1
+ export declare function useEffect(cb: () => void | (() => void)): void;
2
+ //# sourceMappingURL=useEffect.d.ts.map
@@ -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"}
@@ -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"}
@@ -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"}
@@ -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"}
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rask-ui",
3
- "version": "0.12.5",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",