@iadev93/zuno-react 0.0.10 → 0.0.12

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
@@ -23,9 +23,18 @@ Peer dependency:
23
23
  ```tsx
24
24
  import { createZunoReact } from "@iadev93/zuno-react";
25
25
 
26
- const zuno = createZunoReact();
27
-
28
- const counter = zuno.store("counter", () => 0);
26
+ const zuno = createZunoReact({
27
+ // Optional: Enable batching
28
+ batchSync: true,
29
+ });
30
+
31
+ const counter = zuno.store(
32
+ "counter",
33
+ () => 0,
34
+ undefined,
35
+ // Optional: Custom equality
36
+ (a, b) => a === b
37
+ );
29
38
 
30
39
  function App() {
31
40
  const value = counter.use();
package/dist/index.d.mts CHANGED
@@ -21,8 +21,9 @@ type Selector<TState, TSelected> = (state: TState) => TSelected;
21
21
  type BoundStore<T> = {
22
22
  key: string;
23
23
  get: () => T;
24
- set: (next: T | ((prev: T) => T)) => Promise<any>;
24
+ set: (next: T | ((prev: T) => T)) => Promise<unknown>;
25
25
  subscribe: (cb: (state: T) => void) => () => void;
26
+ equals: (v1: any, v2: any) => boolean;
26
27
  raw: () => ZunoSubscribableStore<T>;
27
28
  };
28
29
  /**
@@ -30,8 +31,12 @@ type BoundStore<T> = {
30
31
  * retrieve, and update stores.
31
32
  */
32
33
  type ZunoCore = {
33
- store<T>(storeKey: string, init: () => T): BoundStore<T>;
34
- set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;
34
+ store<T>(storeKey: string, init: () => T, reducer?: (prev: T, intent: any) => T, equals?: (v1: any, v2: any) => boolean): BoundStore<T>;
35
+ set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<unknown>;
36
+ mutate(storeKey: string, intent: {
37
+ type: string;
38
+ payload?: unknown;
39
+ }): Promise<unknown>;
35
40
  get<T>(storeKey: string, init?: () => T): T;
36
41
  stop?: () => void;
37
42
  };
@@ -51,8 +56,12 @@ type ReactBoundStore<T> = BoundStore<T> & {
51
56
  * @returns A React-enhanced Zuno instance.
52
57
  */
53
58
  declare const bindReact: (zuno: ZunoCore) => {
54
- store: <T>(storeKey: string, init: () => T) => ReactBoundStore<T>;
55
- set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;
59
+ store: <T>(storeKey: string, init: () => T, reducer?: (prev: T, intent: any) => T, equals?: (v1: any, v2: any) => boolean) => ReactBoundStore<T>;
60
+ set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<unknown>;
61
+ mutate(storeKey: string, intent: {
62
+ type: string;
63
+ payload?: unknown;
64
+ }): Promise<unknown>;
56
65
  get<T>(storeKey: string, init?: () => T): T;
57
66
  stop?: () => void;
58
67
  };
@@ -63,8 +72,12 @@ declare const bindReact: (zuno: ZunoCore) => {
63
72
  * @returns An object with a `store` method that returns stores with a `use` hook.
64
73
  */
65
74
  declare const createZunoReact: (opts: CreateZunoOptions) => {
66
- store: <T>(storeKey: string, init: () => T) => ReactBoundStore<T>;
67
- set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;
75
+ store: <T>(storeKey: string, init: () => T, reducer?: (prev: T, intent: any) => T, equals?: (v1: any, v2: any) => boolean) => ReactBoundStore<T>;
76
+ set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<unknown>;
77
+ mutate(storeKey: string, intent: {
78
+ type: string;
79
+ payload?: unknown;
80
+ }): Promise<unknown>;
68
81
  get<T>(storeKey: string, init?: () => T): T;
69
82
  stop?: () => void;
70
83
  };
package/dist/index.d.ts CHANGED
@@ -21,8 +21,9 @@ type Selector<TState, TSelected> = (state: TState) => TSelected;
21
21
  type BoundStore<T> = {
22
22
  key: string;
23
23
  get: () => T;
24
- set: (next: T | ((prev: T) => T)) => Promise<any>;
24
+ set: (next: T | ((prev: T) => T)) => Promise<unknown>;
25
25
  subscribe: (cb: (state: T) => void) => () => void;
26
+ equals: (v1: any, v2: any) => boolean;
26
27
  raw: () => ZunoSubscribableStore<T>;
27
28
  };
28
29
  /**
@@ -30,8 +31,12 @@ type BoundStore<T> = {
30
31
  * retrieve, and update stores.
31
32
  */
32
33
  type ZunoCore = {
33
- store<T>(storeKey: string, init: () => T): BoundStore<T>;
34
- set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;
34
+ store<T>(storeKey: string, init: () => T, reducer?: (prev: T, intent: any) => T, equals?: (v1: any, v2: any) => boolean): BoundStore<T>;
35
+ set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<unknown>;
36
+ mutate(storeKey: string, intent: {
37
+ type: string;
38
+ payload?: unknown;
39
+ }): Promise<unknown>;
35
40
  get<T>(storeKey: string, init?: () => T): T;
36
41
  stop?: () => void;
37
42
  };
@@ -51,8 +56,12 @@ type ReactBoundStore<T> = BoundStore<T> & {
51
56
  * @returns A React-enhanced Zuno instance.
52
57
  */
53
58
  declare const bindReact: (zuno: ZunoCore) => {
54
- store: <T>(storeKey: string, init: () => T) => ReactBoundStore<T>;
55
- set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;
59
+ store: <T>(storeKey: string, init: () => T, reducer?: (prev: T, intent: any) => T, equals?: (v1: any, v2: any) => boolean) => ReactBoundStore<T>;
60
+ set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<unknown>;
61
+ mutate(storeKey: string, intent: {
62
+ type: string;
63
+ payload?: unknown;
64
+ }): Promise<unknown>;
56
65
  get<T>(storeKey: string, init?: () => T): T;
57
66
  stop?: () => void;
58
67
  };
@@ -63,8 +72,12 @@ declare const bindReact: (zuno: ZunoCore) => {
63
72
  * @returns An object with a `store` method that returns stores with a `use` hook.
64
73
  */
65
74
  declare const createZunoReact: (opts: CreateZunoOptions) => {
66
- store: <T>(storeKey: string, init: () => T) => ReactBoundStore<T>;
67
- set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;
75
+ store: <T>(storeKey: string, init: () => T, reducer?: (prev: T, intent: any) => T, equals?: (v1: any, v2: any) => boolean) => ReactBoundStore<T>;
76
+ set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<unknown>;
77
+ mutate(storeKey: string, intent: {
78
+ type: string;
79
+ payload?: unknown;
80
+ }): Promise<unknown>;
68
81
  get<T>(storeKey: string, init?: () => T): T;
69
82
  stop?: () => void;
70
83
  };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- 'use strict';var e=require('react'),zuno=require('@iadev93/zuno');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var e__namespace=/*#__PURE__*/_interopNamespace(e);var l=Object.is,y=a=>{let T=(t,u,n=l)=>{let o=e__namespace.useMemo(()=>u??(r=>r),[u]),s=e__namespace.useRef(null),c=e__namespace.useRef(false),i=e__namespace.useCallback(()=>{let r=o(t.getSnapshot());if(!c.current)return c.current=true,s.current=r,r;let S=s.current;return n(S,r)?S:(s.current=r,r)},[t,o,n]),p=e__namespace.useCallback(r=>t.subscribe(r),[t]),d=e__namespace.useCallback(()=>{let r=t.getServerSnapshot?t.getServerSnapshot():t.getSnapshot();return o(r)},[t,o]);return e__namespace.useEffect(()=>{c.current=false,s.current=null;},[o,n]),e__namespace.useSyncExternalStore(p,i,d)};return {...a,store:(t,u)=>{let n=a.store(t,u);return {...n,use:(o,s=l)=>{let c=e__namespace.useMemo(()=>zuno.toReadable(n.raw()),[t]);return T(c,o,s)}}}}},x=a=>{let T=zuno.createZuno(a);return y(T)};exports.bindReact=y;exports.createZunoReact=x;//# sourceMappingURL=index.js.map
1
+ 'use strict';var zuno=require('@iadev93/zuno'),e=require('react');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var e__namespace=/*#__PURE__*/_interopNamespace(e);var p=Object.is,R=c=>{let l=(n,u,T=p)=>{let s=e__namespace.useMemo(()=>u??(t=>t),[u]),o=e__namespace.useRef(null),r=e__namespace.useRef(false),a=e__namespace.useCallback(()=>{let t=s(n.getSnapshot());if(!r.current)return r.current=true,o.current=t,t;let i=o.current;return T(i,t)?i:(o.current=t,t)},[n,s,T]),S=e__namespace.useCallback(t=>n.subscribe(t),[n]),d=e__namespace.useCallback(()=>{let t=n.getServerSnapshot?n.getServerSnapshot():n.getSnapshot();return s(t)},[n,s]);return e__namespace.useEffect(()=>{r.current=false,o.current=null;},[]),e__namespace.useSyncExternalStore(S,a,d)};return {...c,store:(n,u,T,s)=>{let o=c.store(n,u,T,s);return {...o,use:(r,a=p)=>{let S=e__namespace.useMemo(()=>zuno.toReadable(o.raw()),[]);return l(S,r,a)},equals:(r,a)=>o.equals(r,a)}}}},f=c=>{let l=zuno.createZuno(c);return R(l)};exports.bindReact=R;exports.createZunoReact=f;//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["defaultEq","bindReact","zuno","useExternalStore","readable","selector","equalityFn","select","e","s","lastRef","hasLast","getSnapshot","next","prev","subscribe","onChange","getServerSnapshot","storeKey","init","base","toReadable","createZunoReact","opts","createZuno"],"mappings":"waAsBA,IAAMA,CAAAA,CAA6B,MAAA,CAAO,GA4C7BC,CAAAA,CAAaC,CAAAA,EAAmB,CAI3C,IAAMC,CAAAA,CAAmB,CACvBC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAAoCN,CAAAA,GACtB,CACd,IAAMO,EAAeC,YAAA,CAAA,OAAA,CAAQ,IACnBH,IACJI,CAAAA,EAAcA,CAAAA,CAAAA,CACjB,CAACJ,CAAQ,CAAC,CAAA,CAEPK,CAAAA,CAAgBF,YAAA,CAAA,MAAA,CAAyB,IAAI,EAC7CG,CAAAA,CAAgBH,YAAA,CAAA,MAAA,CAAO,KAAK,CAAA,CAE5BI,CAAAA,CAAoBJ,yBAAY,IAAM,CAC1C,IAAMK,CAAAA,CAAON,CAAAA,CAAOH,CAAAA,CAAS,aAAa,CAAA,CAE1C,GAAI,CAACO,CAAAA,CAAQ,QACX,OAAAA,CAAAA,CAAQ,OAAA,CAAU,IAAA,CAClBD,CAAAA,CAAQ,OAAA,CAAUG,EACXA,CAAAA,CAGT,IAAMC,EAAOJ,CAAAA,CAAQ,OAAA,CACrB,OAAIJ,CAAAA,CAAWQ,CAAAA,CAAMD,CAAI,CAAA,CAAUC,CAAAA,EAEnCJ,CAAAA,CAAQ,QAAUG,CAAAA,CACXA,CAAAA,CACT,EAAG,CAACT,CAAAA,CAAUG,EAAQD,CAAU,CAAC,CAAA,CAE3BS,CAAAA,CAAkBP,YAAA,CAAA,WAAA,CACrBQ,CAAAA,EAAyBZ,EAAS,SAAA,CAAUY,CAAQ,EACrD,CAACZ,CAAQ,CACX,CAAA,CAEMa,CAAAA,CAA0BT,YAAA,CAAA,WAAA,CAAY,IAAM,CAChD,IAAMC,EAAIL,CAAAA,CAAS,iBAAA,CAAoBA,EAAS,iBAAA,EAAkB,CAAIA,EAAS,WAAA,EAAY,CAC3F,OAAOG,CAAAA,CAAOE,CAAC,CACjB,EAAG,CAACL,CAAAA,CAAUG,CAAM,CAAC,CAAA,CAErB,OAAMC,YAAA,CAAA,SAAA,CAAU,IAAM,CACpBG,CAAAA,CAAQ,OAAA,CAAU,KAAA,CAClBD,EAAQ,OAAA,CAAU,KACpB,EAAG,CAACH,CAAAA,CAAQD,CAAU,CAAC,CAAA,CAEVE,YAAA,CAAA,oBAAA,CAAqBO,CAAAA,CAAWH,CAAAA,CAAaK,CAAiB,CAC7E,CAAA,CAuBA,OAAO,CACL,GAAGf,CAAAA,CACH,MApBY,CAAKgB,CAAAA,CAAkBC,CAAAA,GAAsC,CACzE,IAAMC,CAAAA,CAAOlB,EAAK,KAAA,CAASgB,CAAAA,CAAUC,CAAI,CAAA,CAEzC,OAAO,CACL,GAAGC,CAAAA,CACH,GAAA,CAAK,CACHf,CAAAA,CACAC,CAAAA,CAAoCN,IACjC,CACH,IAAMI,EAAiBI,YAAA,CAAA,OAAA,CACrB,IAAMa,gBAAWD,CAAAA,CAAK,GAAA,EAAiC,CAAA,CACvD,CAACF,CAAQ,CACX,CAAA,CACA,OAAOf,EAA+BC,CAAAA,CAAUC,CAAAA,CAAUC,CAAU,CACtE,CACF,CACF,CAKA,CACF,CAAA,CAQagB,EAAmBC,CAAAA,EAA4B,CAC1D,IAAMrB,CAAAA,CAAOsB,eAAAA,CAAWD,CAAI,CAAA,CAC5B,OAAOtB,CAAAA,CAAUC,CAAI,CACvB","file":"index.js","sourcesContent":["import * as React from \"react\";\nimport { type ZunoReadable, type ZunoSubscribableStore, toReadable, createZuno, type CreateZunoOptions } from \"@iadev93/zuno\";\n\n/**\n * Type definition for an equality function.\n * It takes two values of the same type and returns true if they are considered equal, false otherwise.\n * Used to prevent unnecessary re-renders in React hooks when the selected state hasn't \"meaningfully\" changed.\n */\nexport type EqualityFn<T> = (a: T, b: T) => boolean;\n\n/**\n * Type definition for a selector function.\n * It takes the full state of a store and returns a selected portion of that state.\n * This allows components to subscribe only to the parts of the state they care about,\n * optimizing performance by avoiding re-renders for unrelated state changes.\n */\nexport type Selector<TState, TSelected> = (state: TState) => TSelected;\n\n/**\n * The default equality function, using `Object.is` for strict equality comparison.\n * This is a common and safe default for comparing primitive values and references.\n */\nconst defaultEq: EqualityFn<any> = Object.is;\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n key: string;\n get: () => T;\n set: (next: T | ((prev: T) => T)) => Promise<any>;\n subscribe: (cb: (state: T) => void) => () => void;\n raw: () => ZunoSubscribableStore<T>;\n};\n\n/**\n * The core interface for the Zuno library, providing methods to create,\n * retrieve, and update stores.\n */\nexport type ZunoCore = {\n store<T>(storeKey: string, init: () => T): BoundStore<T>;\n set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;\n get<T>(storeKey: string, init?: () => T): T;\n stop?: () => void;\n};\n\n/**\n * An extended interface for a Zuno store that includes React-specific features.\n */\nexport type ReactBoundStore<T> = BoundStore<T> & {\n /**\n * React hook for this store.\n * Optional selector + equality for derived values and avoiding rerenders.\n */\n use: <TSelected = T>(\n selector?: Selector<T, TSelected>,\n equalityFn?: EqualityFn<TSelected>\n ) => TSelected;\n};\n\n/**\n * Binds Zuno to React.\n * @param zuno The Zuno instance to bind.\n * @returns A React-enhanced Zuno instance.\n */\nexport const bindReact = (zuno: ZunoCore) => {\n /**\n * A custom hook for accessing a Zuno store in a React component.\n */\n const useExternalStore = <TState, TSelected = TState>(\n readable: ZunoReadable<TState>,\n selector?: Selector<TState, TSelected>,\n equalityFn: EqualityFn<TSelected> = defaultEq\n ): TSelected => {\n const select = React.useMemo(() => {\n return (selector ??\n ((s: TState) => s as unknown as TSelected)) as Selector<TState, TSelected>;\n }, [selector]);\n\n const lastRef = React.useRef<TSelected | null>(null);\n const hasLast = React.useRef(false);\n\n const getSnapshot = React.useCallback(() => {\n const next = select(readable.getSnapshot());\n\n if (!hasLast.current) {\n hasLast.current = true;\n lastRef.current = next;\n return next;\n }\n\n const prev = lastRef.current as TSelected;\n if (equalityFn(prev, next)) return prev;\n\n lastRef.current = next;\n return next;\n }, [readable, select, equalityFn]);\n\n const subscribe = React.useCallback(\n (onChange: () => void) => readable.subscribe(onChange),\n [readable]\n );\n\n const getServerSnapshot = React.useCallback(() => {\n const s = readable.getServerSnapshot ? readable.getServerSnapshot() : readable.getSnapshot();\n return select(s);\n }, [readable, select]);\n\n React.useEffect(() => {\n hasLast.current = false;\n lastRef.current = null;\n }, [select, equalityFn]);\n\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n };\n\n /**\n * Creates a React-enhanced store.\n */\n const store = <T,>(storeKey: string, init: () => T): ReactBoundStore<T> => {\n const base = zuno.store<T>(storeKey, init);\n\n return {\n ...base,\n use: <TSelected = T>(\n selector?: Selector<T, TSelected>,\n equalityFn: EqualityFn<TSelected> = defaultEq\n ) => {\n const readable = React.useMemo(\n () => toReadable(base.raw() as ZunoSubscribableStore<T>),\n [storeKey]\n );\n return useExternalStore<T, TSelected>(readable, selector, equalityFn);\n },\n };\n };\n\n return {\n ...zuno,\n store,\n };\n};\n\n/**\n * Creates a Zuno instance and returns a React-enhanced instance.\n * \n * @param opts The options for the Zuno instance.\n * @returns An object with a `store` method that returns stores with a `use` hook.\n */\nexport const createZunoReact = (opts: CreateZunoOptions) => {\n const zuno = createZuno(opts);\n return bindReact(zuno);\n};\n\n// Convenience re-export\nexport type { ZunoReadable } from \"@iadev93/zuno\";\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["defaultEq","bindReact","zuno","useExternalStore","readable","selector","equalityFn","select","e","s","lastRef","hasLast","getSnapshot","next","prev","subscribe","onChange","getServerSnapshot","storeKey","init","reducer","equals","base","toReadable","v1","v2","createZunoReact","opts","createZuno"],"mappings":"waA4BA,IAAMA,CAAAA,CAAiC,MAAA,CAAO,GA0DjCC,CAAAA,CAAaC,CAAAA,EAAmB,CAI5C,IAAMC,CAAAA,CAAmB,CACxBC,EACAC,CAAAA,CACAC,CAAAA,CAAoCN,CAAAA,GACrB,CACf,IAAMO,CAAAA,CAAeC,qBAAQ,IACpBH,CAAAA,GACLI,GAAcA,CAAAA,CAAAA,CAIf,CAACJ,CAAQ,CAAC,CAAA,CAEPK,CAAAA,CAAgBF,YAAA,CAAA,MAAA,CAAyB,IAAI,CAAA,CAC7CG,EAAgBH,YAAA,CAAA,MAAA,CAAO,KAAK,CAAA,CAE5BI,CAAAA,CAAoBJ,YAAA,CAAA,WAAA,CAAY,IAAM,CAC3C,IAAMK,CAAAA,CAAON,CAAAA,CAAOH,CAAAA,CAAS,WAAA,EAAa,EAE1C,GAAI,CAACO,EAAQ,OAAA,CACZ,OAAAA,EAAQ,OAAA,CAAU,IAAA,CAClBD,CAAAA,CAAQ,OAAA,CAAUG,CAAAA,CACXA,CAAAA,CAGR,IAAMC,CAAAA,CAAOJ,CAAAA,CAAQ,OAAA,CACrB,OAAIJ,CAAAA,CAAWQ,CAAAA,CAAMD,CAAI,CAAA,CAAUC,CAAAA,EAEnCJ,CAAAA,CAAQ,OAAA,CAAUG,CAAAA,CACXA,CAAAA,CACR,EAAG,CAACT,CAAAA,CAAUG,CAAAA,CAAQD,CAAU,CAAC,CAAA,CAE3BS,EAAkBP,YAAA,CAAA,WAAA,CACtBQ,CAAAA,EAAyBZ,CAAAA,CAAS,SAAA,CAAUY,CAAQ,CAAA,CACrD,CAACZ,CAAQ,CACV,CAAA,CAEMa,CAAAA,CAA0BT,YAAA,CAAA,WAAA,CAAY,IAAM,CACjD,IAAMC,CAAAA,CAAIL,CAAAA,CAAS,iBAAA,CAChBA,CAAAA,CAAS,iBAAA,GACTA,CAAAA,CAAS,WAAA,GACZ,OAAOG,CAAAA,CAAOE,CAAC,CAChB,CAAA,CAAG,CAACL,CAAAA,CAAUG,CAAM,CAAC,EAErB,OAAMC,YAAA,CAAA,SAAA,CAAU,IAAM,CACrBG,CAAAA,CAAQ,OAAA,CAAU,MAClBD,CAAAA,CAAQ,OAAA,CAAU,KACnB,CAAA,CAAG,EAAE,EAEQF,YAAA,CAAA,oBAAA,CACZO,CAAAA,CACAH,EACAK,CACD,CACD,EA6BA,OAAO,CACN,GAAGf,CAAAA,CACH,KAAA,CA1Ba,CACbgB,EACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,GACwB,CACxB,IAAMC,CAAAA,CAAOpB,EAAK,KAAA,CAASgB,CAAAA,CAAUC,CAAAA,CAAMC,CAAAA,CAASC,CAAM,CAAA,CAE1D,OAAO,CACN,GAAGC,EACH,GAAA,CAAK,CACJjB,EACAC,CAAAA,CAAoCN,CAAAA,GAChC,CACJ,IAAMI,CAAAA,CAAiBI,YAAA,CAAA,OAAA,CACtB,IAAMe,eAAAA,CAAWD,CAAAA,CAAK,GAAA,EAAiC,CAAA,CACvD,EACD,CAAA,CACA,OAAOnB,CAAAA,CAA+BC,CAAAA,CAAUC,CAAAA,CAAUC,CAAU,CACrE,CAAA,CACA,MAAA,CAAQ,CAACkB,CAAAA,CAAIC,CAAAA,GAAOH,CAAAA,CAAK,OAAOE,CAAAA,CAAIC,CAAE,CACvC,CACD,CAKA,CACD,EAQaC,CAAAA,CAAmBC,CAAAA,EAA4B,CAC3D,IAAMzB,CAAAA,CAAO0B,eAAAA,CAAWD,CAAI,CAAA,CAC5B,OAAO1B,CAAAA,CAAUC,CAAI,CACtB","file":"index.js","sourcesContent":["import {\n\ttype CreateZunoOptions,\n\tcreateZuno,\n\ttoReadable,\n\ttype ZunoReadable,\n\ttype ZunoSubscribableStore,\n} from \"@iadev93/zuno\";\nimport * as React from \"react\";\n\n/**\n * Type definition for an equality function.\n * It takes two values of the same type and returns true if they are considered equal, false otherwise.\n * Used to prevent unnecessary re-renders in React hooks when the selected state hasn't \"meaningfully\" changed.\n */\nexport type EqualityFn<T> = (a: T, b: T) => boolean;\n\n/**\n * Type definition for a selector function.\n * It takes the full state of a store and returns a selected portion of that state.\n * This allows components to subscribe only to the parts of the state they care about,\n * optimizing performance by avoiding re-renders for unrelated state changes.\n */\nexport type Selector<TState, TSelected> = (state: TState) => TSelected;\n\n/**\n * The default equality function, using `Object.is` for strict equality comparison.\n * This is a common and safe default for comparing primitive values and references.\n */\nconst defaultEq: EqualityFn<unknown> = Object.is;\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n\tkey: string;\n\tget: () => T;\n\tset: (next: T | ((prev: T) => T)) => Promise<unknown>;\n\tsubscribe: (cb: (state: T) => void) => () => void;\n\tequals: (v1: any, v2: any) => boolean;\n\traw: () => ZunoSubscribableStore<T>;\n};\n\n/**\n * The core interface for the Zuno library, providing methods to create,\n * retrieve, and update stores.\n */\nexport type ZunoCore = {\n\tstore<T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: any) => T,\n\t\tequals?: (v1: any, v2: any) => boolean,\n\t): BoundStore<T>;\n\tset<T>(\n\t\tstoreKey: string,\n\t\tnext: T | ((prev: T) => T),\n\t\tinit?: () => T,\n\t): Promise<unknown>;\n\tmutate(\n\t\tstoreKey: string,\n\t\tintent: { type: string; payload?: unknown },\n\t): Promise<unknown>;\n\tget<T>(storeKey: string, init?: () => T): T;\n\tstop?: () => void;\n};\n\n/**\n * An extended interface for a Zuno store that includes React-specific features.\n */\nexport type ReactBoundStore<T> = BoundStore<T> & {\n\t/**\n\t * React hook for this store.\n\t * Optional selector + equality for derived values and avoiding rerenders.\n\t */\n\tuse: <TSelected = T>(\n\t\tselector?: Selector<T, TSelected>,\n\t\tequalityFn?: EqualityFn<TSelected>,\n\t) => TSelected;\n};\n\n/**\n * Binds Zuno to React.\n * @param zuno The Zuno instance to bind.\n * @returns A React-enhanced Zuno instance.\n */\nexport const bindReact = (zuno: ZunoCore) => {\n\t/**\n\t * A custom hook for accessing a Zuno store in a React component.\n\t */\n\tconst useExternalStore = <TState, TSelected = TState>(\n\t\treadable: ZunoReadable<TState>,\n\t\tselector?: Selector<TState, TSelected>,\n\t\tequalityFn: EqualityFn<TSelected> = defaultEq,\n\t): TSelected => {\n\t\tconst select = React.useMemo(() => {\n\t\t\treturn (selector ??\n\t\t\t\t((s: TState) => s as unknown as TSelected)) as Selector<\n\t\t\t\tTState,\n\t\t\t\tTSelected\n\t\t\t>;\n\t\t}, [selector]);\n\n\t\tconst lastRef = React.useRef<TSelected | null>(null);\n\t\tconst hasLast = React.useRef(false);\n\n\t\tconst getSnapshot = React.useCallback(() => {\n\t\t\tconst next = select(readable.getSnapshot());\n\n\t\t\tif (!hasLast.current) {\n\t\t\t\thasLast.current = true;\n\t\t\t\tlastRef.current = next;\n\t\t\t\treturn next;\n\t\t\t}\n\n\t\t\tconst prev = lastRef.current as TSelected;\n\t\t\tif (equalityFn(prev, next)) return prev;\n\n\t\t\tlastRef.current = next;\n\t\t\treturn next;\n\t\t}, [readable, select, equalityFn]);\n\n\t\tconst subscribe = React.useCallback(\n\t\t\t(onChange: () => void) => readable.subscribe(onChange),\n\t\t\t[readable],\n\t\t);\n\n\t\tconst getServerSnapshot = React.useCallback(() => {\n\t\t\tconst s = readable.getServerSnapshot\n\t\t\t\t? readable.getServerSnapshot()\n\t\t\t\t: readable.getSnapshot();\n\t\t\treturn select(s);\n\t\t}, [readable, select]);\n\n\t\tReact.useEffect(() => {\n\t\t\thasLast.current = false;\n\t\t\tlastRef.current = null;\n\t\t}, []);\n\n\t\treturn React.useSyncExternalStore(\n\t\t\tsubscribe,\n\t\t\tgetSnapshot,\n\t\t\tgetServerSnapshot,\n\t\t);\n\t};\n\n\t/**\n\t * Creates a React-enhanced store.\n\t */\n\tconst store = <T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: any) => T,\n\t\tequals?: (v1: any, v2: any) => boolean,\n\t): ReactBoundStore<T> => {\n\t\tconst base = zuno.store<T>(storeKey, init, reducer, equals);\n\n\t\treturn {\n\t\t\t...base,\n\t\t\tuse: <TSelected = T>(\n\t\t\t\tselector?: Selector<T, TSelected>,\n\t\t\t\tequalityFn: EqualityFn<TSelected> = defaultEq,\n\t\t\t) => {\n\t\t\t\tconst readable = React.useMemo(\n\t\t\t\t\t() => toReadable(base.raw() as ZunoSubscribableStore<T>),\n\t\t\t\t\t[],\n\t\t\t\t);\n\t\t\t\treturn useExternalStore<T, TSelected>(readable, selector, equalityFn);\n\t\t\t},\n\t\t\tequals: (v1, v2) => base.equals(v1, v2),\n\t\t};\n\t};\n\n\treturn {\n\t\t...zuno,\n\t\tstore,\n\t};\n};\n\n/**\n * Creates a Zuno instance and returns a React-enhanced instance.\n *\n * @param opts The options for the Zuno instance.\n * @returns An object with a `store` method that returns stores with a `use` hook.\n */\nexport const createZunoReact = (opts: CreateZunoOptions) => {\n\tconst zuno = createZuno(opts);\n\treturn bindReact(zuno);\n};\n\n// Convenience re-export\nexport type { ZunoReadable } from \"@iadev93/zuno\";\n"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import*as e from'react';import {toReadable,createZuno}from'@iadev93/zuno';var l=Object.is,y=a=>{let T=(t,u,n=l)=>{let o=e.useMemo(()=>u??(r=>r),[u]),s=e.useRef(null),c=e.useRef(false),i=e.useCallback(()=>{let r=o(t.getSnapshot());if(!c.current)return c.current=true,s.current=r,r;let S=s.current;return n(S,r)?S:(s.current=r,r)},[t,o,n]),p=e.useCallback(r=>t.subscribe(r),[t]),d=e.useCallback(()=>{let r=t.getServerSnapshot?t.getServerSnapshot():t.getSnapshot();return o(r)},[t,o]);return e.useEffect(()=>{c.current=false,s.current=null;},[o,n]),e.useSyncExternalStore(p,i,d)};return {...a,store:(t,u)=>{let n=a.store(t,u);return {...n,use:(o,s=l)=>{let c=e.useMemo(()=>toReadable(n.raw()),[t]);return T(c,o,s)}}}}},x=a=>{let T=createZuno(a);return y(T)};export{y as bindReact,x as createZunoReact};//# sourceMappingURL=index.mjs.map
1
+ import {toReadable,createZuno}from'@iadev93/zuno';import*as e from'react';var p=Object.is,R=c=>{let l=(n,u,T=p)=>{let s=e.useMemo(()=>u??(t=>t),[u]),o=e.useRef(null),r=e.useRef(false),a=e.useCallback(()=>{let t=s(n.getSnapshot());if(!r.current)return r.current=true,o.current=t,t;let i=o.current;return T(i,t)?i:(o.current=t,t)},[n,s,T]),S=e.useCallback(t=>n.subscribe(t),[n]),d=e.useCallback(()=>{let t=n.getServerSnapshot?n.getServerSnapshot():n.getSnapshot();return s(t)},[n,s]);return e.useEffect(()=>{r.current=false,o.current=null;},[]),e.useSyncExternalStore(S,a,d)};return {...c,store:(n,u,T,s)=>{let o=c.store(n,u,T,s);return {...o,use:(r,a=p)=>{let S=e.useMemo(()=>toReadable(o.raw()),[]);return l(S,r,a)},equals:(r,a)=>o.equals(r,a)}}}},f=c=>{let l=createZuno(c);return R(l)};export{R as bindReact,f as createZunoReact};//# sourceMappingURL=index.mjs.map
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["defaultEq","bindReact","zuno","useExternalStore","readable","selector","equalityFn","select","s","lastRef","hasLast","getSnapshot","next","prev","subscribe","onChange","getServerSnapshot","storeKey","init","base","toReadable","createZunoReact","opts","createZuno"],"mappings":"0EAsBA,IAAMA,CAAAA,CAA6B,MAAA,CAAO,GA4C7BC,CAAAA,CAAaC,CAAAA,EAAmB,CAI3C,IAAMC,CAAAA,CAAmB,CACvBC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CAAoCN,CAAAA,GACtB,CACd,IAAMO,EAAe,CAAA,CAAA,OAAA,CAAQ,IACnBF,IACJG,CAAAA,EAAcA,CAAAA,CAAAA,CACjB,CAACH,CAAQ,CAAC,CAAA,CAEPI,CAAAA,CAAgB,CAAA,CAAA,MAAA,CAAyB,IAAI,EAC7CC,CAAAA,CAAgB,CAAA,CAAA,MAAA,CAAO,KAAK,CAAA,CAE5BC,CAAAA,CAAoB,cAAY,IAAM,CAC1C,IAAMC,CAAAA,CAAOL,CAAAA,CAAOH,CAAAA,CAAS,aAAa,CAAA,CAE1C,GAAI,CAACM,CAAAA,CAAQ,QACX,OAAAA,CAAAA,CAAQ,OAAA,CAAU,IAAA,CAClBD,CAAAA,CAAQ,OAAA,CAAUG,EACXA,CAAAA,CAGT,IAAMC,EAAOJ,CAAAA,CAAQ,OAAA,CACrB,OAAIH,CAAAA,CAAWO,CAAAA,CAAMD,CAAI,CAAA,CAAUC,CAAAA,EAEnCJ,CAAAA,CAAQ,QAAUG,CAAAA,CACXA,CAAAA,CACT,EAAG,CAACR,CAAAA,CAAUG,EAAQD,CAAU,CAAC,CAAA,CAE3BQ,CAAAA,CAAkB,CAAA,CAAA,WAAA,CACrBC,CAAAA,EAAyBX,EAAS,SAAA,CAAUW,CAAQ,EACrD,CAACX,CAAQ,CACX,CAAA,CAEMY,CAAAA,CAA0B,CAAA,CAAA,WAAA,CAAY,IAAM,CAChD,IAAMR,EAAIJ,CAAAA,CAAS,iBAAA,CAAoBA,EAAS,iBAAA,EAAkB,CAAIA,EAAS,WAAA,EAAY,CAC3F,OAAOG,CAAAA,CAAOC,CAAC,CACjB,EAAG,CAACJ,CAAAA,CAAUG,CAAM,CAAC,CAAA,CAErB,OAAM,CAAA,CAAA,SAAA,CAAU,IAAM,CACpBG,CAAAA,CAAQ,OAAA,CAAU,KAAA,CAClBD,EAAQ,OAAA,CAAU,KACpB,EAAG,CAACF,CAAAA,CAAQD,CAAU,CAAC,CAAA,CAEV,CAAA,CAAA,oBAAA,CAAqBQ,CAAAA,CAAWH,CAAAA,CAAaK,CAAiB,CAC7E,CAAA,CAuBA,OAAO,CACL,GAAGd,CAAAA,CACH,MApBY,CAAKe,CAAAA,CAAkBC,CAAAA,GAAsC,CACzE,IAAMC,CAAAA,CAAOjB,EAAK,KAAA,CAASe,CAAAA,CAAUC,CAAI,CAAA,CAEzC,OAAO,CACL,GAAGC,CAAAA,CACH,GAAA,CAAK,CACHd,CAAAA,CACAC,CAAAA,CAAoCN,IACjC,CACH,IAAMI,EAAiB,CAAA,CAAA,OAAA,CACrB,IAAMgB,WAAWD,CAAAA,CAAK,GAAA,EAAiC,CAAA,CACvD,CAACF,CAAQ,CACX,CAAA,CACA,OAAOd,EAA+BC,CAAAA,CAAUC,CAAAA,CAAUC,CAAU,CACtE,CACF,CACF,CAKA,CACF,CAAA,CAQae,EAAmBC,CAAAA,EAA4B,CAC1D,IAAMpB,CAAAA,CAAOqB,UAAAA,CAAWD,CAAI,CAAA,CAC5B,OAAOrB,CAAAA,CAAUC,CAAI,CACvB","file":"index.mjs","sourcesContent":["import * as React from \"react\";\nimport { type ZunoReadable, type ZunoSubscribableStore, toReadable, createZuno, type CreateZunoOptions } from \"@iadev93/zuno\";\n\n/**\n * Type definition for an equality function.\n * It takes two values of the same type and returns true if they are considered equal, false otherwise.\n * Used to prevent unnecessary re-renders in React hooks when the selected state hasn't \"meaningfully\" changed.\n */\nexport type EqualityFn<T> = (a: T, b: T) => boolean;\n\n/**\n * Type definition for a selector function.\n * It takes the full state of a store and returns a selected portion of that state.\n * This allows components to subscribe only to the parts of the state they care about,\n * optimizing performance by avoiding re-renders for unrelated state changes.\n */\nexport type Selector<TState, TSelected> = (state: TState) => TSelected;\n\n/**\n * The default equality function, using `Object.is` for strict equality comparison.\n * This is a common and safe default for comparing primitive values and references.\n */\nconst defaultEq: EqualityFn<any> = Object.is;\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n key: string;\n get: () => T;\n set: (next: T | ((prev: T) => T)) => Promise<any>;\n subscribe: (cb: (state: T) => void) => () => void;\n raw: () => ZunoSubscribableStore<T>;\n};\n\n/**\n * The core interface for the Zuno library, providing methods to create,\n * retrieve, and update stores.\n */\nexport type ZunoCore = {\n store<T>(storeKey: string, init: () => T): BoundStore<T>;\n set<T>(storeKey: string, next: T | ((prev: T) => T), init?: () => T): Promise<any>;\n get<T>(storeKey: string, init?: () => T): T;\n stop?: () => void;\n};\n\n/**\n * An extended interface for a Zuno store that includes React-specific features.\n */\nexport type ReactBoundStore<T> = BoundStore<T> & {\n /**\n * React hook for this store.\n * Optional selector + equality for derived values and avoiding rerenders.\n */\n use: <TSelected = T>(\n selector?: Selector<T, TSelected>,\n equalityFn?: EqualityFn<TSelected>\n ) => TSelected;\n};\n\n/**\n * Binds Zuno to React.\n * @param zuno The Zuno instance to bind.\n * @returns A React-enhanced Zuno instance.\n */\nexport const bindReact = (zuno: ZunoCore) => {\n /**\n * A custom hook for accessing a Zuno store in a React component.\n */\n const useExternalStore = <TState, TSelected = TState>(\n readable: ZunoReadable<TState>,\n selector?: Selector<TState, TSelected>,\n equalityFn: EqualityFn<TSelected> = defaultEq\n ): TSelected => {\n const select = React.useMemo(() => {\n return (selector ??\n ((s: TState) => s as unknown as TSelected)) as Selector<TState, TSelected>;\n }, [selector]);\n\n const lastRef = React.useRef<TSelected | null>(null);\n const hasLast = React.useRef(false);\n\n const getSnapshot = React.useCallback(() => {\n const next = select(readable.getSnapshot());\n\n if (!hasLast.current) {\n hasLast.current = true;\n lastRef.current = next;\n return next;\n }\n\n const prev = lastRef.current as TSelected;\n if (equalityFn(prev, next)) return prev;\n\n lastRef.current = next;\n return next;\n }, [readable, select, equalityFn]);\n\n const subscribe = React.useCallback(\n (onChange: () => void) => readable.subscribe(onChange),\n [readable]\n );\n\n const getServerSnapshot = React.useCallback(() => {\n const s = readable.getServerSnapshot ? readable.getServerSnapshot() : readable.getSnapshot();\n return select(s);\n }, [readable, select]);\n\n React.useEffect(() => {\n hasLast.current = false;\n lastRef.current = null;\n }, [select, equalityFn]);\n\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n };\n\n /**\n * Creates a React-enhanced store.\n */\n const store = <T,>(storeKey: string, init: () => T): ReactBoundStore<T> => {\n const base = zuno.store<T>(storeKey, init);\n\n return {\n ...base,\n use: <TSelected = T>(\n selector?: Selector<T, TSelected>,\n equalityFn: EqualityFn<TSelected> = defaultEq\n ) => {\n const readable = React.useMemo(\n () => toReadable(base.raw() as ZunoSubscribableStore<T>),\n [storeKey]\n );\n return useExternalStore<T, TSelected>(readable, selector, equalityFn);\n },\n };\n };\n\n return {\n ...zuno,\n store,\n };\n};\n\n/**\n * Creates a Zuno instance and returns a React-enhanced instance.\n * \n * @param opts The options for the Zuno instance.\n * @returns An object with a `store` method that returns stores with a `use` hook.\n */\nexport const createZunoReact = (opts: CreateZunoOptions) => {\n const zuno = createZuno(opts);\n return bindReact(zuno);\n};\n\n// Convenience re-export\nexport type { ZunoReadable } from \"@iadev93/zuno\";\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["defaultEq","bindReact","zuno","useExternalStore","readable","selector","equalityFn","select","s","lastRef","hasLast","getSnapshot","next","prev","subscribe","onChange","getServerSnapshot","storeKey","init","reducer","equals","base","toReadable","v1","v2","createZunoReact","opts","createZuno"],"mappings":"0EA4BA,IAAMA,CAAAA,CAAiC,MAAA,CAAO,GA0DjCC,CAAAA,CAAaC,CAAAA,EAAmB,CAI5C,IAAMC,CAAAA,CAAmB,CACxBC,EACAC,CAAAA,CACAC,CAAAA,CAAoCN,CAAAA,GACrB,CACf,IAAMO,CAAAA,CAAe,UAAQ,IACpBF,CAAAA,GACLG,GAAcA,CAAAA,CAAAA,CAIf,CAACH,CAAQ,CAAC,CAAA,CAEPI,CAAAA,CAAgB,CAAA,CAAA,MAAA,CAAyB,IAAI,CAAA,CAC7CC,EAAgB,CAAA,CAAA,MAAA,CAAO,KAAK,CAAA,CAE5BC,CAAAA,CAAoB,CAAA,CAAA,WAAA,CAAY,IAAM,CAC3C,IAAMC,CAAAA,CAAOL,CAAAA,CAAOH,CAAAA,CAAS,WAAA,EAAa,EAE1C,GAAI,CAACM,EAAQ,OAAA,CACZ,OAAAA,EAAQ,OAAA,CAAU,IAAA,CAClBD,CAAAA,CAAQ,OAAA,CAAUG,CAAAA,CACXA,CAAAA,CAGR,IAAMC,CAAAA,CAAOJ,CAAAA,CAAQ,OAAA,CACrB,OAAIH,CAAAA,CAAWO,CAAAA,CAAMD,CAAI,CAAA,CAAUC,CAAAA,EAEnCJ,CAAAA,CAAQ,OAAA,CAAUG,CAAAA,CACXA,CAAAA,CACR,EAAG,CAACR,CAAAA,CAAUG,CAAAA,CAAQD,CAAU,CAAC,CAAA,CAE3BQ,EAAkB,CAAA,CAAA,WAAA,CACtBC,CAAAA,EAAyBX,CAAAA,CAAS,SAAA,CAAUW,CAAQ,CAAA,CACrD,CAACX,CAAQ,CACV,CAAA,CAEMY,CAAAA,CAA0B,CAAA,CAAA,WAAA,CAAY,IAAM,CACjD,IAAMR,CAAAA,CAAIJ,CAAAA,CAAS,iBAAA,CAChBA,CAAAA,CAAS,iBAAA,GACTA,CAAAA,CAAS,WAAA,GACZ,OAAOG,CAAAA,CAAOC,CAAC,CAChB,CAAA,CAAG,CAACJ,CAAAA,CAAUG,CAAM,CAAC,EAErB,OAAM,CAAA,CAAA,SAAA,CAAU,IAAM,CACrBG,CAAAA,CAAQ,OAAA,CAAU,MAClBD,CAAAA,CAAQ,OAAA,CAAU,KACnB,CAAA,CAAG,EAAE,EAEQ,CAAA,CAAA,oBAAA,CACZK,CAAAA,CACAH,EACAK,CACD,CACD,EA6BA,OAAO,CACN,GAAGd,CAAAA,CACH,KAAA,CA1Ba,CACbe,EACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,GACwB,CACxB,IAAMC,CAAAA,CAAOnB,EAAK,KAAA,CAASe,CAAAA,CAAUC,CAAAA,CAAMC,CAAAA,CAASC,CAAM,CAAA,CAE1D,OAAO,CACN,GAAGC,EACH,GAAA,CAAK,CACJhB,EACAC,CAAAA,CAAoCN,CAAAA,GAChC,CACJ,IAAMI,CAAAA,CAAiB,CAAA,CAAA,OAAA,CACtB,IAAMkB,UAAAA,CAAWD,CAAAA,CAAK,GAAA,EAAiC,CAAA,CACvD,EACD,CAAA,CACA,OAAOlB,CAAAA,CAA+BC,CAAAA,CAAUC,CAAAA,CAAUC,CAAU,CACrE,CAAA,CACA,MAAA,CAAQ,CAACiB,CAAAA,CAAIC,CAAAA,GAAOH,CAAAA,CAAK,OAAOE,CAAAA,CAAIC,CAAE,CACvC,CACD,CAKA,CACD,EAQaC,CAAAA,CAAmBC,CAAAA,EAA4B,CAC3D,IAAMxB,CAAAA,CAAOyB,UAAAA,CAAWD,CAAI,CAAA,CAC5B,OAAOzB,CAAAA,CAAUC,CAAI,CACtB","file":"index.mjs","sourcesContent":["import {\n\ttype CreateZunoOptions,\n\tcreateZuno,\n\ttoReadable,\n\ttype ZunoReadable,\n\ttype ZunoSubscribableStore,\n} from \"@iadev93/zuno\";\nimport * as React from \"react\";\n\n/**\n * Type definition for an equality function.\n * It takes two values of the same type and returns true if they are considered equal, false otherwise.\n * Used to prevent unnecessary re-renders in React hooks when the selected state hasn't \"meaningfully\" changed.\n */\nexport type EqualityFn<T> = (a: T, b: T) => boolean;\n\n/**\n * Type definition for a selector function.\n * It takes the full state of a store and returns a selected portion of that state.\n * This allows components to subscribe only to the parts of the state they care about,\n * optimizing performance by avoiding re-renders for unrelated state changes.\n */\nexport type Selector<TState, TSelected> = (state: TState) => TSelected;\n\n/**\n * The default equality function, using `Object.is` for strict equality comparison.\n * This is a common and safe default for comparing primitive values and references.\n */\nconst defaultEq: EqualityFn<unknown> = Object.is;\n\n/**\n * An extended interface for a Zuno store that includes methods for setting state\n * and a unique key identifier. This represents a store that has been \"bound\" or registered.\n */\nexport type BoundStore<T> = {\n\tkey: string;\n\tget: () => T;\n\tset: (next: T | ((prev: T) => T)) => Promise<unknown>;\n\tsubscribe: (cb: (state: T) => void) => () => void;\n\tequals: (v1: any, v2: any) => boolean;\n\traw: () => ZunoSubscribableStore<T>;\n};\n\n/**\n * The core interface for the Zuno library, providing methods to create,\n * retrieve, and update stores.\n */\nexport type ZunoCore = {\n\tstore<T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: any) => T,\n\t\tequals?: (v1: any, v2: any) => boolean,\n\t): BoundStore<T>;\n\tset<T>(\n\t\tstoreKey: string,\n\t\tnext: T | ((prev: T) => T),\n\t\tinit?: () => T,\n\t): Promise<unknown>;\n\tmutate(\n\t\tstoreKey: string,\n\t\tintent: { type: string; payload?: unknown },\n\t): Promise<unknown>;\n\tget<T>(storeKey: string, init?: () => T): T;\n\tstop?: () => void;\n};\n\n/**\n * An extended interface for a Zuno store that includes React-specific features.\n */\nexport type ReactBoundStore<T> = BoundStore<T> & {\n\t/**\n\t * React hook for this store.\n\t * Optional selector + equality for derived values and avoiding rerenders.\n\t */\n\tuse: <TSelected = T>(\n\t\tselector?: Selector<T, TSelected>,\n\t\tequalityFn?: EqualityFn<TSelected>,\n\t) => TSelected;\n};\n\n/**\n * Binds Zuno to React.\n * @param zuno The Zuno instance to bind.\n * @returns A React-enhanced Zuno instance.\n */\nexport const bindReact = (zuno: ZunoCore) => {\n\t/**\n\t * A custom hook for accessing a Zuno store in a React component.\n\t */\n\tconst useExternalStore = <TState, TSelected = TState>(\n\t\treadable: ZunoReadable<TState>,\n\t\tselector?: Selector<TState, TSelected>,\n\t\tequalityFn: EqualityFn<TSelected> = defaultEq,\n\t): TSelected => {\n\t\tconst select = React.useMemo(() => {\n\t\t\treturn (selector ??\n\t\t\t\t((s: TState) => s as unknown as TSelected)) as Selector<\n\t\t\t\tTState,\n\t\t\t\tTSelected\n\t\t\t>;\n\t\t}, [selector]);\n\n\t\tconst lastRef = React.useRef<TSelected | null>(null);\n\t\tconst hasLast = React.useRef(false);\n\n\t\tconst getSnapshot = React.useCallback(() => {\n\t\t\tconst next = select(readable.getSnapshot());\n\n\t\t\tif (!hasLast.current) {\n\t\t\t\thasLast.current = true;\n\t\t\t\tlastRef.current = next;\n\t\t\t\treturn next;\n\t\t\t}\n\n\t\t\tconst prev = lastRef.current as TSelected;\n\t\t\tif (equalityFn(prev, next)) return prev;\n\n\t\t\tlastRef.current = next;\n\t\t\treturn next;\n\t\t}, [readable, select, equalityFn]);\n\n\t\tconst subscribe = React.useCallback(\n\t\t\t(onChange: () => void) => readable.subscribe(onChange),\n\t\t\t[readable],\n\t\t);\n\n\t\tconst getServerSnapshot = React.useCallback(() => {\n\t\t\tconst s = readable.getServerSnapshot\n\t\t\t\t? readable.getServerSnapshot()\n\t\t\t\t: readable.getSnapshot();\n\t\t\treturn select(s);\n\t\t}, [readable, select]);\n\n\t\tReact.useEffect(() => {\n\t\t\thasLast.current = false;\n\t\t\tlastRef.current = null;\n\t\t}, []);\n\n\t\treturn React.useSyncExternalStore(\n\t\t\tsubscribe,\n\t\t\tgetSnapshot,\n\t\t\tgetServerSnapshot,\n\t\t);\n\t};\n\n\t/**\n\t * Creates a React-enhanced store.\n\t */\n\tconst store = <T>(\n\t\tstoreKey: string,\n\t\tinit: () => T,\n\t\treducer?: (prev: T, intent: any) => T,\n\t\tequals?: (v1: any, v2: any) => boolean,\n\t): ReactBoundStore<T> => {\n\t\tconst base = zuno.store<T>(storeKey, init, reducer, equals);\n\n\t\treturn {\n\t\t\t...base,\n\t\t\tuse: <TSelected = T>(\n\t\t\t\tselector?: Selector<T, TSelected>,\n\t\t\t\tequalityFn: EqualityFn<TSelected> = defaultEq,\n\t\t\t) => {\n\t\t\t\tconst readable = React.useMemo(\n\t\t\t\t\t() => toReadable(base.raw() as ZunoSubscribableStore<T>),\n\t\t\t\t\t[],\n\t\t\t\t);\n\t\t\t\treturn useExternalStore<T, TSelected>(readable, selector, equalityFn);\n\t\t\t},\n\t\t\tequals: (v1, v2) => base.equals(v1, v2),\n\t\t};\n\t};\n\n\treturn {\n\t\t...zuno,\n\t\tstore,\n\t};\n};\n\n/**\n * Creates a Zuno instance and returns a React-enhanced instance.\n *\n * @param opts The options for the Zuno instance.\n * @returns An object with a `store` method that returns stores with a `use` hook.\n */\nexport const createZunoReact = (opts: CreateZunoOptions) => {\n\tconst zuno = createZuno(opts);\n\treturn bindReact(zuno);\n};\n\n// Convenience re-export\nexport type { ZunoReadable } from \"@iadev93/zuno\";\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iadev93/zuno-react",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [
@@ -17,13 +17,13 @@
17
17
  },
18
18
  "peerDependencies": {
19
19
  "react": ">=18",
20
- "@iadev93/zuno": "0.0.7"
20
+ "@iadev93/zuno": "0.0.9"
21
21
  },
22
22
  "devDependencies": {
23
23
  "@types/react": "^18.0.0",
24
24
  "tsup": "^8.5.1",
25
25
  "typescript": "^5.9.3",
26
- "@iadev93/zuno": "0.0.7"
26
+ "@iadev93/zuno": "0.0.9"
27
27
  },
28
28
  "keywords": [
29
29
  "zuno",