synstate-react-hooks 1.0.1 → 2.0.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
@@ -110,3 +110,45 @@ const UserProfile = (): React.JSX.Element => {
110
110
  );
111
111
  };
112
112
  ```
113
+
114
+ ## Subscribing to Observables: `useObservableValue`
115
+
116
+ Use `useObservableValue` to read any `Observable` — including derived ones produced by `pipe` / `combine` — from a React component. It is implemented on top of `useSyncExternalStore`, so the component re-renders whenever the source emits.
117
+
118
+ ### Overloads
119
+
120
+ | Signature | Return type | When to use |
121
+ | ------------------------------------------------------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------- |
122
+ | `useObservableValue<A>(obs: InitializedObservable<A>)` | `A` | The observable always has a current value (e.g. came from `createState`, or a `pipe` chain that preserves the initial value). |
123
+ | `useObservableValue<A>(obs: Observable<A>)` | `A \| undefined` | The observable may not have emitted yet (no initial value). |
124
+ | `useObservableValue<A, B = A>(obs: Observable<A>, initialValue: B)` | `A \| B` | Provide a fallback used while the observable has no value. Implemented via `Optional.unwrapOr`. |
125
+
126
+ ### Example
127
+
128
+ ```tsx
129
+ import type * as React from 'react';
130
+ import { map, type Observable } from 'synstate';
131
+ import { createState, useObservableValue } from 'synstate-react-hooks';
132
+
133
+ const [useCount, setCount, { state: count$ }] = createState(0);
134
+
135
+ // Derived InitializedObservable — no fallback needed.
136
+ const doubled$ = count$.pipe(map((n) => n * 2));
137
+
138
+ // Imagine an Observable<string> that has no initial value
139
+ // (e.g. one waiting on an async source).
140
+ declare const userName$: Observable<string>;
141
+
142
+ const Profile = (): React.JSX.Element => {
143
+ const doubled = useObservableValue(doubled$); // number
144
+
145
+ const userName = useObservableValue(userName$, 'Guest'); // string
146
+
147
+ return (
148
+ <div>
149
+ <p>{`Doubled count: ${doubled}`}</p>
150
+ <p>{`Hello, ${userName}`}</p>
151
+ </div>
152
+ );
153
+ };
154
+ ```
@@ -1,5 +1,5 @@
1
1
  import { type InitializedObservable } from 'synstate';
2
- export declare const createBooleanState: (initialState: boolean) => readonly [useCurrentValue: () => boolean, Readonly<{
2
+ export declare const createBooleanState: (initialState: boolean) => readonly [useCurrentValue: () => boolean, utils: Readonly<{
3
3
  state: InitializedObservable<boolean>;
4
4
  setTrue: () => void;
5
5
  setFalse: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"create-boolean-state.d.mts","sourceRoot":"","sources":["../src/create-boolean-state.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,kBAAkB,GAC7B,cAAc,OAAO,KACpB,SAAS,CACV,eAAe,EAAE,MAAM,OAAO,EAC9B,QAAQ,CAAC;IACP,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;IACrC,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,KAAK,OAAO,CAAC;IAC/D,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC,CA+BH,CAAC"}
1
+ {"version":3,"file":"create-boolean-state.d.mts","sourceRoot":"","sources":["../src/create-boolean-state.mts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,EAE3B,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,kBAAkB,iBACf,OAAO,KACpB,SAAS,CACV,eAAe,EAAE,MAAM,OAAO,EAC9B,KAAK,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC;IACrC,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,KAAK,OAAO,CAAC;IAC/D,UAAU,EAAE,MAAM,OAAO,CAAC;IAC1B,WAAW,EAAE,MAAM,OAAO,CAAC;IAC3B,YAAY,EAAE,OAAO,CAAC;CACvB,CAAC,CA+BH,CAAC"}
@@ -2,22 +2,33 @@ import { createBooleanState as createBooleanState$1 } from 'synstate';
2
2
  import { useObservableValue } from './use-observable-value.mjs';
3
3
 
4
4
  const createBooleanState = (initialState) => {
5
- const [state, { setTrue, setFalse, setState, toggle, updateState, resetState, getSnapshot, },] = createBooleanState$1(initialState);
6
- const useCurrentValue = () => useObservableValue(state);
7
- return [
8
- useCurrentValue,
9
- {
10
- state,
11
- setTrue,
12
- setFalse,
13
- setState,
14
- toggle,
15
- updateState,
16
- resetState,
17
- getSnapshot,
18
- initialState,
19
- },
20
- ];
5
+ const [
6
+ state,
7
+ {
8
+ setTrue,
9
+ setFalse,
10
+ setState,
11
+ toggle,
12
+ updateState,
13
+ resetState,
14
+ getSnapshot
15
+ }
16
+ ] = createBooleanState$1(initialState);
17
+ const useCurrentValue = () => useObservableValue(state);
18
+ return [
19
+ useCurrentValue,
20
+ {
21
+ state,
22
+ setTrue,
23
+ setFalse,
24
+ setState,
25
+ toggle,
26
+ updateState,
27
+ resetState,
28
+ getSnapshot,
29
+ initialState
30
+ }
31
+ ];
21
32
  };
22
33
 
23
34
  export { createBooleanState };
@@ -1 +1 @@
1
- {"version":3,"file":"create-boolean-state.mjs","sources":["../src/create-boolean-state.mts"],"sourcesContent":[null],"names":["createBooleanStateBase"],"mappings":";;;AAMO,MAAM,kBAAkB,GAAG,CAChC,YAAqB,KAcnB;IACF,MAAM,CACJ,KAAK,EACL,EACE,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,WAAW,EACX,UAAU,EACV,WAAW,GACZ,EACF,GAAGA,oBAAsB,CAAC,YAAY,CAAC;IAExC,MAAM,eAAe,GAAG,MAAe,kBAAkB,CAAC,KAAK,CAAC;IAEhE,OAAO;QACL,eAAe;AACf,QAAA;YACE,KAAK;YACL,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,MAAM;YACN,WAAW;YACX,UAAU;YACV,WAAW;YACX,YAAY;AACb,SAAA;KACO;AACZ;;;;"}
1
+ {"version":3,"file":"create-boolean-state.mjs","sources":["../src/create-boolean-state.mts"],"sourcesContent":["import {\n type InitializedObservable,\n createBooleanState as createBooleanStateBase,\n} from 'synstate';\nimport { useObservableValue } from './use-observable-value.mjs';\n\nexport const createBooleanState = (\n initialState: boolean,\n): readonly [\n useCurrentValue: () => boolean,\n utils: Readonly<{\n state: InitializedObservable<boolean>;\n setTrue: () => void;\n setFalse: () => void;\n setState: (next: boolean) => boolean;\n toggle: () => boolean;\n updateState: (updateFn: (prev: boolean) => boolean) => boolean;\n resetState: () => boolean;\n getSnapshot: () => boolean;\n initialState: boolean;\n }>,\n] => {\n const [\n state,\n {\n setTrue,\n setFalse,\n setState,\n toggle,\n updateState,\n resetState,\n getSnapshot,\n },\n ] = createBooleanStateBase(initialState);\n\n const useCurrentValue = (): boolean => useObservableValue(state);\n\n return [\n useCurrentValue,\n {\n state,\n setTrue,\n setFalse,\n setState,\n toggle,\n updateState,\n resetState,\n getSnapshot,\n initialState,\n },\n ] as const;\n};\n"],"names":["createBooleanStateBase"],"mappings":";;;AAMO,MAAM,kBAAA,GAAqB,CAChC,YAAA,KAcG;AACH,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA;AAAA,MACE,OAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA;AAAA;AACF,GACF,GAAIA,qBAAuB,YAAY,CAAA;AAEvC,EAAA,MAAM,eAAA,GAAkB,MAAe,kBAAA,CAAmB,KAAK,CAAA;AAE/D,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA;AAAA,MACE,KAAA;AAAA,MACA,OAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA,MAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AACF;;;;"}
@@ -1,6 +1,6 @@
1
1
  import { type InitializedObservable } from 'synstate';
2
2
  import { type Reducer } from 'ts-type-forge';
3
- export declare const createReducer: <S, A>(reducer: Reducer<S, A>, initialState: S) => readonly [useCurrentValue: () => S, dispatch: (action: A) => S, Readonly<{
3
+ export declare const createReducer: <S, A>(reducer: Reducer<S, A>, initialState: S) => readonly [useCurrentValue: () => S, dispatch: (action: A) => S, utils: Readonly<{
4
4
  state: InitializedObservable<S>;
5
5
  getSnapshot: () => S;
6
6
  initialState: S;
@@ -1 +1 @@
1
- {"version":3,"file":"create-reducer.d.mts","sourceRoot":"","sources":["../src/create-reducer.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,EAChC,SAAS,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,cAAc,CAAC,KACd,SAAS,CACV,eAAe,EAAE,MAAM,CAAC,EACxB,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAC1B,QAAQ,CAAC;IACP,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAUH,CAAC"}
1
+ {"version":3,"file":"create-reducer.d.mts","sourceRoot":"","sources":["../src/create-reducer.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,eAAO,MAAM,aAAa,GAAI,CAAC,EAAE,CAAC,WACvB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,gBACR,CAAC,KACd,SAAS,CACV,eAAe,EAAE,MAAM,CAAC,EACxB,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,EAC1B,KAAK,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAUH,CAAC"}
@@ -2,9 +2,12 @@ import { createReducer as createReducer$1 } from 'synstate';
2
2
  import { useObservableValue } from './use-observable-value.mjs';
3
3
 
4
4
  const createReducer = (reducer, initialState) => {
5
- const [state, dispatch, { getSnapshot }] = createReducer$1(reducer, initialState);
6
- const useCurrentValue = () => useObservableValue(state);
7
- return [useCurrentValue, dispatch, { state, getSnapshot, initialState }];
5
+ const [state, dispatch, { getSnapshot }] = createReducer$1(
6
+ reducer,
7
+ initialState
8
+ );
9
+ const useCurrentValue = () => useObservableValue(state);
10
+ return [useCurrentValue, dispatch, { state, getSnapshot, initialState }];
8
11
  };
9
12
 
10
13
  export { createReducer };
@@ -1 +1 @@
1
- {"version":3,"file":"create-reducer.mjs","sources":["../src/create-reducer.mts"],"sourcesContent":[null],"names":["createReducerBase"],"mappings":";;;MAOa,aAAa,GAAG,CAC3B,OAAsB,EACtB,YAAe,KASb;AACF,IAAA,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,CAAC,GAAGA,eAAiB,CAC1D,OAAO,EACP,YAAY,CACb;IAED,MAAM,eAAe,GAAG,MAAS,kBAAkB,CAAC,KAAK,CAAC;AAE1D,IAAA,OAAO,CAAC,eAAe,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AAC1E;;;;"}
1
+ {"version":3,"file":"create-reducer.mjs","sources":["../src/create-reducer.mts"],"sourcesContent":["import {\n createReducer as createReducerBase,\n type InitializedObservable,\n} from 'synstate';\nimport { type Reducer } from 'ts-type-forge';\nimport { useObservableValue } from './use-observable-value.mjs';\n\nexport const createReducer = <S, A>(\n reducer: Reducer<S, A>,\n initialState: S,\n): readonly [\n useCurrentValue: () => S,\n dispatch: (action: A) => S,\n utils: Readonly<{\n state: InitializedObservable<S>;\n getSnapshot: () => S;\n initialState: S;\n }>,\n] => {\n const [state, dispatch, { getSnapshot }] = createReducerBase(\n reducer,\n initialState,\n );\n\n const useCurrentValue = (): S => useObservableValue(state);\n\n return [useCurrentValue, dispatch, { state, getSnapshot, initialState }];\n};\n"],"names":["createReducerBase"],"mappings":";;;AAOO,MAAM,aAAA,GAAgB,CAC3B,OAAA,EACA,YAAA,KASG;AACH,EAAA,MAAM,CAAC,KAAA,EAAO,QAAA,EAAU,EAAE,WAAA,EAAa,CAAA,GAAIA,eAAA;AAAA,IACzC,OAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,MAAM,eAAA,GAAkB,MAAS,kBAAA,CAAmB,KAAK,CAAA;AAEzD,EAAA,OAAO,CAAC,eAAA,EAAiB,QAAA,EAAU,EAAE,KAAA,EAAO,WAAA,EAAa,cAAc,CAAA;AACzE;;;;"}
@@ -1,5 +1,5 @@
1
1
  import { type InitializedObservable } from 'synstate';
2
- export declare const createState: <S>(initialState: S) => readonly [useCurrentValue: () => S, setState: (v: S) => S, Readonly<{
2
+ export declare const createState: <S>(initialState: S) => readonly [useCurrentValue: () => S, setState: (v: S) => S, utils: Readonly<{
3
3
  state: InitializedObservable<S>;
4
4
  updateState: (updateFn: (prev: S) => S) => S;
5
5
  resetState: () => S;
@@ -1 +1 @@
1
- {"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../src/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,WAAW,GAAI,CAAC,EAC3B,cAAc,CAAC,KACd,SAAS,CACV,eAAe,EAAE,MAAM,CAAC,EACxB,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,QAAQ,CAAC;IACP,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAChC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAkBH,CAAC"}
1
+ {"version":3,"file":"create-state.d.mts","sourceRoot":"","sources":["../src/create-state.mts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAGlB,eAAO,MAAM,WAAW,GAAI,CAAC,gBACb,CAAC,KACd,SAAS,CACV,eAAe,EAAE,MAAM,CAAC,EACxB,QAAQ,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EACrB,KAAK,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IAChC,WAAW,EAAE,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,CAAC;CACjB,CAAC,CAkBH,CAAC"}
@@ -2,19 +2,19 @@ import { createState as createState$1 } from 'synstate';
2
2
  import { useObservableValue } from './use-observable-value.mjs';
3
3
 
4
4
  const createState = (initialState) => {
5
- const [state, setState, { updateState, resetState, getSnapshot }] = createState$1(initialState);
6
- const useCurrentValue = () => useObservableValue(state);
7
- return [
8
- useCurrentValue,
9
- setState,
10
- {
11
- state,
12
- updateState,
13
- resetState,
14
- getSnapshot,
15
- initialState,
16
- },
17
- ];
5
+ const [state, setState, { updateState, resetState, getSnapshot }] = createState$1(initialState);
6
+ const useCurrentValue = () => useObservableValue(state);
7
+ return [
8
+ useCurrentValue,
9
+ setState,
10
+ {
11
+ state,
12
+ updateState,
13
+ resetState,
14
+ getSnapshot,
15
+ initialState
16
+ }
17
+ ];
18
18
  };
19
19
 
20
20
  export { createState };
@@ -1 +1 @@
1
- {"version":3,"file":"create-state.mjs","sources":["../src/create-state.mts"],"sourcesContent":[null],"names":["createStateBase"],"mappings":";;;AAMO,MAAM,WAAW,GAAG,CACzB,YAAe,KAWb;AACF,IAAA,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,GAC/DA,aAAe,CAAC,YAAY,CAAC;IAE/B,MAAM,eAAe,GAAG,MAAS,kBAAkB,CAAC,KAAK,CAAC;IAE1D,OAAO;QACL,eAAe;QACf,QAAQ;AACR,QAAA;YACE,KAAK;YACL,WAAW;YACX,UAAU;YACV,WAAW;YACX,YAAY;AACb,SAAA;KACO;AACZ;;;;"}
1
+ {"version":3,"file":"create-state.mjs","sources":["../src/create-state.mts"],"sourcesContent":["import {\n createState as createStateBase,\n type InitializedObservable,\n} from 'synstate';\nimport { useObservableValue } from './use-observable-value.mjs';\n\nexport const createState = <S,>(\n initialState: S,\n): readonly [\n useCurrentValue: () => S,\n setState: (v: S) => S,\n utils: Readonly<{\n state: InitializedObservable<S>;\n updateState: (updateFn: (prev: S) => S) => S;\n resetState: () => S;\n getSnapshot: () => S;\n initialState: S;\n }>,\n] => {\n const [state, setState, { updateState, resetState, getSnapshot }] =\n createStateBase(initialState);\n\n const useCurrentValue = (): S => useObservableValue(state);\n\n return [\n useCurrentValue,\n setState,\n {\n state,\n updateState,\n resetState,\n getSnapshot,\n initialState,\n },\n ] as const;\n};\n"],"names":["createStateBase"],"mappings":";;;AAMO,MAAM,WAAA,GAAc,CACzB,YAAA,KAWG;AACH,EAAA,MAAM,CAAC,KAAA,EAAO,QAAA,EAAU,EAAE,WAAA,EAAa,YAAY,WAAA,EAAa,CAAA,GAC9DA,aAAA,CAAgB,YAAY,CAAA;AAE9B,EAAA,MAAM,eAAA,GAAkB,MAAS,kBAAA,CAAmB,KAAK,CAAA;AAEzD,EAAA,OAAO;AAAA,IACL,eAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,MACE,KAAA;AAAA,MACA,WAAA;AAAA,MACA,UAAA;AAAA,MACA,WAAA;AAAA,MACA;AAAA;AACF,GACF;AACF;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-observable-effect.d.mts","sourceRoot":"","sources":["../src/use-observable-effect.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,mBAAmB,GAAI,CAAC,EACnC,aAAa,UAAU,CAAC,CAAC,CAAC,EAC1B,gBAAgB,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,KAC7B,IAQF,CAAC"}
1
+ {"version":3,"file":"use-observable-effect.d.mts","sourceRoot":"","sources":["../src/use-observable-effect.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAE3C,eAAO,MAAM,mBAAmB,GAAI,CAAC,eACtB,UAAU,CAAC,CAAC,CAAC,kBACV,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,KAC7B,IAQF,CAAC"}
@@ -1,12 +1,12 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  const useObservableEffect = (observable$, subscriptionFn) => {
4
- React.useEffect(() => {
5
- const s = observable$.subscribe(subscriptionFn);
6
- return () => {
7
- s.unsubscribe();
8
- };
9
- }, []);
4
+ React.useEffect(() => {
5
+ const s = observable$.subscribe(subscriptionFn);
6
+ return () => {
7
+ s.unsubscribe();
8
+ };
9
+ }, []);
10
10
  };
11
11
 
12
12
  export { useObservableEffect };
@@ -1 +1 @@
1
- {"version":3,"file":"use-observable-effect.mjs","sources":["../src/use-observable-effect.mts"],"sourcesContent":[null],"names":[],"mappings":";;MAGa,mBAAmB,GAAG,CACjC,WAA0B,EAC1B,cAA8B,KACtB;AACR,IAAA,KAAK,CAAC,SAAS,CAAC,MAAK;QACnB,MAAM,CAAC,GAAG,WAAW,CAAC,SAAS,CAAC,cAAc,CAAC;AAE/C,QAAA,OAAO,MAAK;YACV,CAAC,CAAC,WAAW,EAAE;AACjB,QAAA,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;AACR;;;;"}
1
+ {"version":3,"file":"use-observable-effect.mjs","sources":["../src/use-observable-effect.mts"],"sourcesContent":["import * as React from 'react';\nimport { type Observable } from 'synstate';\n\nexport const useObservableEffect = <A,>(\n observable$: Observable<A>,\n subscriptionFn: (v: A) => void,\n): void => {\n React.useEffect(() => {\n const s = observable$.subscribe(subscriptionFn);\n\n return () => {\n s.unsubscribe();\n };\n }, []);\n};\n"],"names":[],"mappings":";;AAGO,MAAM,mBAAA,GAAsB,CACjC,WAAA,EACA,cAAA,KACS;AACT,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,MAAM,CAAA,GAAI,WAAA,CAAY,SAAA,CAAU,cAAc,CAAA;AAE9C,IAAA,OAAO,MAAM;AACX,MAAA,CAAA,CAAE,WAAA,EAAY;AAAA,IAChB,CAAA;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AACP;;;;"}
@@ -2,11 +2,14 @@ import * as React from 'react';
2
2
  import { Optional } from 'ts-data-forge';
3
3
 
4
4
  function useObservableValue(observable$, initialValue) {
5
- const value = React.useSyncExternalStore((onStoreChange) => {
6
- const { unsubscribe } = observable$.subscribe(onStoreChange);
7
- return unsubscribe;
8
- }, () => observable$.getSnapshot());
9
- return Optional.unwrapOr(value, initialValue);
5
+ const value = React.useSyncExternalStore(
6
+ (onStoreChange) => {
7
+ const { unsubscribe } = observable$.subscribe(onStoreChange);
8
+ return unsubscribe;
9
+ },
10
+ () => observable$.getSnapshot()
11
+ );
12
+ return Optional.unwrapOr(value, initialValue);
10
13
  }
11
14
 
12
15
  export { useObservableValue };
@@ -1 +1 @@
1
- {"version":3,"file":"use-observable-value.mjs","sources":["../src/use-observable-value.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAoBM,SAAU,kBAAkB,CAChC,WAA0B,EAC1B,YAAgB,EAAA;IAEhB,MAAM,KAAK,GAAG,KAAK,CAAC,oBAAoB,CACtC,CAAC,aAAyB,KAAI;QAC5B,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,aAAa,CAAC;AAE5D,QAAA,OAAO,WAAW;IACpB,CAAC,EACD,MAAM,WAAW,CAAC,WAAW,EAAE,CAChC;IAED,OAAO,QAAQ,CAAC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;AAC/C;;;;"}
1
+ {"version":3,"file":"use-observable-value.mjs","sources":["../src/use-observable-value.mts"],"sourcesContent":["import * as React from 'react';\nimport { type InitializedObservable, type Observable } from 'synstate';\nimport { Optional } from 'ts-data-forge';\n\nexport function useObservableValue<A, B = A>(\n observable$: Observable<A>,\n initialValue: B,\n): A | B;\n\nexport function useObservableValue<A>(observable$: InitializedObservable<A>): A;\n\nexport function useObservableValue<A>(\n observable$: Observable<A>,\n): A | undefined;\n\nexport function useObservableValue<A, B = A>(\n observable$: Observable<A>,\n initialValue: B,\n): A | B;\n\nexport function useObservableValue<A, B = A>(\n observable$: Observable<A>,\n initialValue?: B,\n): A | B | undefined {\n const value = React.useSyncExternalStore(\n (onStoreChange: () => void) => {\n const { unsubscribe } = observable$.subscribe(onStoreChange);\n\n return unsubscribe;\n },\n () => observable$.getSnapshot(),\n );\n\n return Optional.unwrapOr(value, initialValue);\n}\n"],"names":[],"mappings":";;;AAoBO,SAAS,kBAAA,CACd,aACA,YAAA,EACmB;AACnB,EAAA,MAAM,QAAQ,KAAA,CAAM,oBAAA;AAAA,IAClB,CAAC,aAAA,KAA8B;AAC7B,MAAA,MAAM,EAAE,WAAA,EAAY,GAAI,WAAA,CAAY,UAAU,aAAa,CAAA;AAE3D,MAAA,OAAO,WAAA;AAAA,IACT,CAAA;AAAA,IACA,MAAM,YAAY,WAAA;AAAY,GAChC;AAEA,EAAA,OAAO,QAAA,CAAS,QAAA,CAAS,KAAA,EAAO,YAAY,CAAA;AAC9C;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-value-as-observable.d.mts","sourceRoot":"","sources":["../src/use-value-as-observable.mts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,oBAAoB,GAAI,CAAC,EAAG,OAAO,CAAC,KAAG,UAAU,CAAC,CAAC,CA0B/D,CAAC"}
1
+ {"version":3,"file":"use-value-as-observable.d.mts","sourceRoot":"","sources":["../src/use-value-as-observable.mts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,UAAU,CAAC;AAElB,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAU,CAAC,KAAG,UAAU,CAAC,CAAC,CA0B/D,CAAC"}
@@ -2,19 +2,25 @@ import * as React from 'react';
2
2
  import { source, withInitialValue } from 'synstate';
3
3
 
4
4
  const useValueAsObservable = (input) => {
5
- const sourceObservable = React.useMemo(source, []);
6
- const state = React.useMemo(() => sourceObservable.pipe(withInitialValue(input)), []);
7
- React.useEffect(() => () => {
8
- state.complete();
9
- }, []);
10
- const setState = React.useCallback((nextState) => {
11
- sourceObservable.next(nextState);
12
- return nextState;
13
- }, []);
14
- React.useEffect(() => {
15
- setState(input);
16
- }, [input]);
17
- return state;
5
+ const sourceObservable = React.useMemo(source, []);
6
+ const state = React.useMemo(
7
+ () => sourceObservable.pipe(withInitialValue(input)),
8
+ []
9
+ );
10
+ React.useEffect(
11
+ () => () => {
12
+ state.complete();
13
+ },
14
+ []
15
+ );
16
+ const setState = React.useCallback((nextState) => {
17
+ sourceObservable.next(nextState);
18
+ return nextState;
19
+ }, []);
20
+ React.useEffect(() => {
21
+ setState(input);
22
+ }, [input]);
23
+ return state;
18
24
  };
19
25
 
20
26
  export { useValueAsObservable };
@@ -1 +1 @@
1
- {"version":3,"file":"use-value-as-observable.mjs","sources":["../src/use-value-as-observable.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAQO,MAAM,oBAAoB,GAAG,CAAK,KAAQ,KAAmB;IAClE,MAAM,gBAAgB,GAAG,KAAK,CAAC,OAAO,CAAsB,MAAM,EAAE,EAAE,CAAC;IAEvE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CACzB,MAAM,gBAAgB,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,EACpD,EAAE,CACH;AAED,IAAA,KAAK,CAAC,SAAS,CACb,MAAM,MAAK;QACT,KAAK,CAAC,QAAQ,EAAE;IAClB,CAAC,EACD,EAAE,CACH;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,SAAY,KAAO;AACrD,QAAA,gBAAgB,CAAC,IAAI,CAAC,SAAS,CAAC;AAEhC,QAAA,OAAO,SAAS;IAClB,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,KAAK,CAAC,SAAS,CAAC,MAAK;QACnB,QAAQ,CAAC,KAAK,CAAC;AACjB,IAAA,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAEX,IAAA,OAAO,KAAK;AACd;;;;"}
1
+ {"version":3,"file":"use-value-as-observable.mjs","sources":["../src/use-value-as-observable.mts"],"sourcesContent":["import * as React from 'react';\nimport {\n source,\n withInitialValue,\n type Observable,\n type SourceObservable,\n} from 'synstate';\n\nexport const useValueAsObservable = <A,>(input: A): Observable<A> => {\n const sourceObservable = React.useMemo<SourceObservable<A>>(source, []);\n\n const state = React.useMemo(\n () => sourceObservable.pipe(withInitialValue(input)),\n [],\n );\n\n React.useEffect(\n () => () => {\n state.complete();\n },\n [],\n );\n\n const setState = React.useCallback((nextState: A): A => {\n sourceObservable.next(nextState);\n\n return nextState;\n }, []);\n\n React.useEffect(() => {\n setState(input);\n }, [input]);\n\n return state;\n};\n"],"names":[],"mappings":";;;AAQO,MAAM,oBAAA,GAAuB,CAAK,KAAA,KAA4B;AACnE,EAAA,MAAM,gBAAA,GAAmB,KAAA,CAAM,OAAA,CAA6B,MAAA,EAAQ,EAAE,CAAA;AAEtE,EAAA,MAAM,QAAQ,KAAA,CAAM,OAAA;AAAA,IAClB,MAAM,gBAAA,CAAiB,IAAA,CAAK,gBAAA,CAAiB,KAAK,CAAC,CAAA;AAAA,IACnD;AAAC,GACH;AAEA,EAAA,KAAA,CAAM,SAAA;AAAA,IACJ,MAAM,MAAM;AACV,MAAA,KAAA,CAAM,QAAA,EAAS;AAAA,IACjB,CAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,MAAM,QAAA,GAAW,KAAA,CAAM,WAAA,CAAY,CAAC,SAAA,KAAoB;AACtD,IAAA,gBAAA,CAAiB,KAAK,SAAS,CAAA;AAE/B,IAAA,OAAO,SAAA;AAAA,EACT,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,KAAA,CAAM,UAAU,MAAM;AACpB,IAAA,QAAA,CAAS,KAAK,CAAA;AAAA,EAChB,CAAA,EAAG,CAAC,KAAK,CAAC,CAAA;AAEV,EAAA,OAAO,KAAA;AACT;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "synstate-react-hooks",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "Type-safe State Management Library for TypeScript/JavaScript",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,15 +27,15 @@
27
27
  "LICENSE"
28
28
  ],
29
29
  "dependencies": {
30
- "ts-data-forge": "6.9.4",
31
- "ts-type-forge": "3.0.0",
32
- "synstate": "1.0.1"
30
+ "ts-data-forge": "^14.2.0",
31
+ "ts-type-forge": "^9.2.0",
32
+ "synstate": "2.0.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/argparse": "2.0.17",
36
- "@types/react": "19.2.14",
37
- "argparse": "2.0.1",
38
- "react": "19.2.5"
36
+ "@types/react": "19.2.18",
37
+ "argparse": "3.0.0",
38
+ "react": "19.2.8"
39
39
  },
40
40
  "peerDependencies": {
41
41
  "react": ">=18.0.0"
@@ -49,7 +49,8 @@
49
49
  "doc": "run-s doc:embed doc:embed:jsdoc fmt",
50
50
  "doc:embed": "tsx ./scripts/cmd/embed-examples.mts",
51
51
  "doc:embed:jsdoc": "tsx ./scripts/cmd/embed-examples-in-jsdoc.mts",
52
- "fmt": "format-uncommitted",
52
+ "fmt": "format-uncommitted --cwd .",
53
+ "fmt:diff": "format-diff-from origin/main --cwd .",
53
54
  "fmt:full": "pnpm run z:prettier .",
54
55
  "gen:re-export": "run-s gen:re-export:script fmt",
55
56
  "gen:re-export:script": "tsx ./scripts/cmd/generate-re-export-script.mts",
@@ -63,10 +64,9 @@
63
64
  "test:cov:ui": "vite preview --outDir ./coverage",
64
65
  "test:ui": "pnpm run z:vitest:node --ui",
65
66
  "testw": "pnpm run z:vitest:node watch",
66
- "tsc": "tsc --noEmit",
67
- "tscw": "tsc --noEmit --watch",
68
- "type-check": "tsc --noEmit",
69
- "update-packages": "pnpm update --latest",
67
+ "tsc": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
68
+ "tscw": "node ../../node_modules/typescript-native/bin/tsc --noEmit --watch",
69
+ "type-check": "node ../../node_modules/typescript-native/bin/tsc --noEmit",
70
70
  "z:prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --ignore-path ../../.gitignore --ignore-unknown --no-error-on-unmatched-pattern --write",
71
71
  "z:vitest": "vitest --config ./configs/vitest.config.mts",
72
72
  "z:vitest:node": "pnpm run z:vitest --project='Node.js'"
@@ -8,7 +8,7 @@ export const createBooleanState = (
8
8
  initialState: boolean,
9
9
  ): readonly [
10
10
  useCurrentValue: () => boolean,
11
- Readonly<{
11
+ utils: Readonly<{
12
12
  state: InitializedObservable<boolean>;
13
13
  setTrue: () => void;
14
14
  setFalse: () => void;
@@ -11,7 +11,7 @@ export const createReducer = <S, A>(
11
11
  ): readonly [
12
12
  useCurrentValue: () => S,
13
13
  dispatch: (action: A) => S,
14
- Readonly<{
14
+ utils: Readonly<{
15
15
  state: InitializedObservable<S>;
16
16
  getSnapshot: () => S;
17
17
  initialState: S;
@@ -9,7 +9,7 @@ export const createState = <S,>(
9
9
  ): readonly [
10
10
  useCurrentValue: () => S,
11
11
  setState: (v: S) => S,
12
- Readonly<{
12
+ utils: Readonly<{
13
13
  state: InitializedObservable<S>;
14
14
  updateState: (updateFn: (prev: S) => S) => S;
15
15
  resetState: () => S;