@view-models/react 1.0.0 → 1.2.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/dist/useModelState.d.ts +64 -2
- package/dist/useModelState.d.ts.map +1 -1
- package/dist/useModelState.js +29 -0
- package/package.json +2 -3
- package/src/useModelState.ts +67 -2
package/dist/useModelState.d.ts
CHANGED
|
@@ -1,3 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Function that gets called when the state changes.
|
|
3
|
+
*
|
|
4
|
+
* @template T - The state type
|
|
5
|
+
* @param state - The new state
|
|
6
|
+
*/
|
|
7
|
+
export type ViewModelListener = () => void;
|
|
8
|
+
export interface ViewModel<T> {
|
|
9
|
+
/**
|
|
10
|
+
* Subscribe to state changes.
|
|
11
|
+
*
|
|
12
|
+
* The listener will be called immediately after any state update.
|
|
13
|
+
*
|
|
14
|
+
* @param listener - Function to call when state changes
|
|
15
|
+
* @returns Function to unsubscribe the listener
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const unsubscribe = viewModel.subscribe((state) => {
|
|
20
|
+
* console.log('State changed:', state);
|
|
21
|
+
* });
|
|
22
|
+
*
|
|
23
|
+
* // Later, when you want to stop listening:
|
|
24
|
+
* unsubscribe();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
subscribe(listener: ViewModelListener): () => void;
|
|
28
|
+
/**
|
|
29
|
+
* Get the current state.
|
|
30
|
+
*
|
|
31
|
+
* @returns The current state
|
|
32
|
+
*/
|
|
33
|
+
get state(): T;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A React hook that subscribes a component to a ViewModel's state updates.
|
|
37
|
+
*
|
|
38
|
+
* This hook connects a React component to a ViewModel instance, automatically
|
|
39
|
+
* subscribing to state changes and triggering re-renders when the state updates.
|
|
40
|
+
*
|
|
41
|
+
* @template T - The state type, which must extend the State interface
|
|
42
|
+
* @param model - The ViewModel instance to subscribe to
|
|
43
|
+
* @returns The current state from the ViewModel
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* class CounterViewModel extends ViewModel<{ count: number }> {
|
|
48
|
+
* increment = () => this.update(({ count }) => ({ count: count + 1 }));
|
|
49
|
+
* }
|
|
50
|
+
*
|
|
51
|
+
* function Counter() {
|
|
52
|
+
* const counterModel = useMemo(() => new CounterViewModel({ count: 0 }), []);
|
|
53
|
+
* const { count } = useModelState(counterModel);
|
|
54
|
+
*
|
|
55
|
+
* return (
|
|
56
|
+
* <div>
|
|
57
|
+
* <p>Count: {count}</p>
|
|
58
|
+
* <button onClick={counterModel.increment}>+</button>
|
|
59
|
+
* </div>
|
|
60
|
+
* );
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function useModelState<T>(model: ViewModel<T>): T;
|
|
3
65
|
//# sourceMappingURL=useModelState.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModelState.d.ts","sourceRoot":"","sources":["../src/useModelState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useModelState.d.ts","sourceRoot":"","sources":["../src/useModelState.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC;AAE3C,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B;;;;;;;;;;;;;;;;;OAiBG;IACH,SAAS,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,IAAI,CAAC;IAEnD;;;;OAIG;IACH,IAAI,KAAK,IAAI,CAAC,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAEvD"}
|
package/dist/useModelState.js
CHANGED
|
@@ -1,4 +1,33 @@
|
|
|
1
1
|
import { useSyncExternalStore } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A React hook that subscribes a component to a ViewModel's state updates.
|
|
4
|
+
*
|
|
5
|
+
* This hook connects a React component to a ViewModel instance, automatically
|
|
6
|
+
* subscribing to state changes and triggering re-renders when the state updates.
|
|
7
|
+
*
|
|
8
|
+
* @template T - The state type, which must extend the State interface
|
|
9
|
+
* @param model - The ViewModel instance to subscribe to
|
|
10
|
+
* @returns The current state from the ViewModel
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* class CounterViewModel extends ViewModel<{ count: number }> {
|
|
15
|
+
* increment = () => this.update(({ count }) => ({ count: count + 1 }));
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* function Counter() {
|
|
19
|
+
* const counterModel = useMemo(() => new CounterViewModel({ count: 0 }), []);
|
|
20
|
+
* const { count } = useModelState(counterModel);
|
|
21
|
+
*
|
|
22
|
+
* return (
|
|
23
|
+
* <div>
|
|
24
|
+
* <p>Count: {count}</p>
|
|
25
|
+
* <button onClick={counterModel.increment}>+</button>
|
|
26
|
+
* </div>
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
2
31
|
export function useModelState(model) {
|
|
3
32
|
return useSyncExternalStore(model.subscribe.bind(model), () => model.state);
|
|
4
33
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@view-models/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "React integration for @view-models/core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -45,13 +45,12 @@
|
|
|
45
45
|
"node": ">=18.0.0"
|
|
46
46
|
},
|
|
47
47
|
"peerDependencies": {
|
|
48
|
-
"@view-models/core": "^1.1.0",
|
|
49
48
|
"react": ">=17.0.0"
|
|
50
49
|
},
|
|
51
50
|
"devDependencies": {
|
|
52
51
|
"@testing-library/react": "^16.1.0",
|
|
53
52
|
"@types/react": "^18.3.18",
|
|
54
|
-
"@view-models/core": "^
|
|
53
|
+
"@view-models/core": "^2.0.0",
|
|
55
54
|
"@vitest/coverage-v8": "^2.1.8",
|
|
56
55
|
"jsdom": "^26.0.0",
|
|
57
56
|
"prettier": "^3.4.2",
|
package/src/useModelState.ts
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
import { useSyncExternalStore } from "react";
|
|
2
|
-
import type { ViewModel, State } from "@view-models/core";
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Function that gets called when the state changes.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The state type
|
|
7
|
+
* @param state - The new state
|
|
8
|
+
*/
|
|
9
|
+
export type ViewModelListener = () => void;
|
|
10
|
+
|
|
11
|
+
export interface ViewModel<T> {
|
|
12
|
+
/**
|
|
13
|
+
* Subscribe to state changes.
|
|
14
|
+
*
|
|
15
|
+
* The listener will be called immediately after any state update.
|
|
16
|
+
*
|
|
17
|
+
* @param listener - Function to call when state changes
|
|
18
|
+
* @returns Function to unsubscribe the listener
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const unsubscribe = viewModel.subscribe((state) => {
|
|
23
|
+
* console.log('State changed:', state);
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Later, when you want to stop listening:
|
|
27
|
+
* unsubscribe();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
subscribe(listener: ViewModelListener): () => void;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the current state.
|
|
34
|
+
*
|
|
35
|
+
* @returns The current state
|
|
36
|
+
*/
|
|
37
|
+
get state(): T;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A React hook that subscribes a component to a ViewModel's state updates.
|
|
42
|
+
*
|
|
43
|
+
* This hook connects a React component to a ViewModel instance, automatically
|
|
44
|
+
* subscribing to state changes and triggering re-renders when the state updates.
|
|
45
|
+
*
|
|
46
|
+
* @template T - The state type, which must extend the State interface
|
|
47
|
+
* @param model - The ViewModel instance to subscribe to
|
|
48
|
+
* @returns The current state from the ViewModel
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```tsx
|
|
52
|
+
* class CounterViewModel extends ViewModel<{ count: number }> {
|
|
53
|
+
* increment = () => this.update(({ count }) => ({ count: count + 1 }));
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* function Counter() {
|
|
57
|
+
* const counterModel = useMemo(() => new CounterViewModel({ count: 0 }), []);
|
|
58
|
+
* const { count } = useModelState(counterModel);
|
|
59
|
+
*
|
|
60
|
+
* return (
|
|
61
|
+
* <div>
|
|
62
|
+
* <p>Count: {count}</p>
|
|
63
|
+
* <button onClick={counterModel.increment}>+</button>
|
|
64
|
+
* </div>
|
|
65
|
+
* );
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function useModelState<T>(model: ViewModel<T>): T {
|
|
5
70
|
return useSyncExternalStore(model.subscribe.bind(model), () => model.state);
|
|
6
71
|
}
|