react-state-monad 1.0.18 → 1.0.20
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/.github/workflows/publish.yml +72 -72
- package/LICENSE +673 -673
- package/README.md +267 -267
- package/dist/index.cjs +17 -0
- package/dist/index.d.cts +11 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +16 -0
- package/package.json +1 -1
- package/src/hooks/types.ts +12 -12
- package/src/hooks/useElementState.ts +25 -25
- package/src/hooks/useEmptyState.ts +12 -12
- package/src/hooks/useFieldState.ts +58 -21
- package/src/hooks/useNullSafety.ts +23 -23
- package/src/hooks/useRemapArray.ts +50 -50
- package/src/hooks/useStateObject.ts +14 -14
- package/src/implementations/emptyState.ts +42 -42
- package/src/implementations/validState.ts +59 -59
- package/src/index.ts +10 -10
- package/src/stateObject.ts +70 -70
- package/tsconfig.json +15 -15
package/README.md
CHANGED
@@ -1,268 +1,268 @@
|
|
1
|
-
# React State Monad
|
2
|
-
|
3
|
-
[](https://www.npmjs.com/package/react-state-monad/)
|
4
|
-
[](https://github.com/alvmivan/react-state-monad/releases/latest)
|
5
|
-
[](./LICENSE)
|
6
|
-
|
7
|
-
A set of hooks to manage/transform/filter states with monads in React.
|
8
|
-
|
9
|
-
## Description
|
10
|
-
|
11
|
-
`react-state-monad` provides a set of monadic state management utilities, specifically designed to work seamlessly with
|
12
|
-
React's state hooks. It allows you to manage, transform, and filter states in a functional and declarative way using
|
13
|
-
monads like `Maybe` and `Option`.
|
14
|
-
|
15
|
-
This library leverages the power of monads to encapsulate state changes, enabling a cleaner, more predictable way to
|
16
|
-
handle various state conditions in React.
|
17
|
-
|
18
|
-
## Features
|
19
|
-
|
20
|
-
- Manage state using monads like `Maybe` and `Option`.
|
21
|
-
- Simplify handling of undefined or null values in state.
|
22
|
-
- Leverage functional programming patterns in React state management.
|
23
|
-
- Support for TypeScript with full type definitions.
|
24
|
-
|
25
|
-
## Installation
|
26
|
-
|
27
|
-
You can install `react-state-monad` using npm or yarn:
|
28
|
-
|
29
|
-
```bash
|
30
|
-
npm install react-state-monad
|
31
|
-
```
|
32
|
-
|
33
|
-
or
|
34
|
-
|
35
|
-
```bash
|
36
|
-
yarn add react-state-monad
|
37
|
-
```
|
38
|
-
|
39
|
-
## Usage
|
40
|
-
|
41
|
-
Here's an example of how you can use the hooks in your React components:
|
42
|
-
|
43
|
-
### `useStateObject<T>`
|
44
|
-
|
45
|
-
This hook initializes a StateObject with the provided initial value. It uses React's useState hook to manage the
|
46
|
-
internal state and returns a StateObject that represents the current state.
|
47
|
-
|
48
|
-
Parameters: `initialState`: The initial value of the state. This value can be of any type, determined by the generic
|
49
|
-
type `T`.
|
50
|
-
|
51
|
-
Returns a `StateObject` of type `T` representing the initialized state. This `StateObject` is an instance
|
52
|
-
of `ValidState`, which
|
53
|
-
encapsulates the state value and provides a `setValue` function to update it.
|
54
|
-
|
55
|
-
### `useEmptyState<T>`
|
56
|
-
|
57
|
-
This hook initializes a `StateObject` with an empty state. It is useful as a fallback when no valid state is available.
|
58
|
-
|
59
|
-
Parameters: None.
|
60
|
-
|
61
|
-
Returns a `StateObject` of type `T` representing an empty state. This `StateObject` is an instance of `EmptyState`,
|
62
|
-
which encapsulates the absence of a state value.
|
63
|
-
|
64
|
-
### `useElementState<T>`
|
65
|
-
|
66
|
-
This hook allows you to derive and update a specific element in an array within a `StateObject`. It is useful for
|
67
|
-
managing state at a granular level within an array.
|
68
|
-
|
69
|
-
Parameters:
|
70
|
-
|
71
|
-
- `state`: The `StateObject` containing an array.
|
72
|
-
- `index`: The index of the element to be derived.
|
73
|
-
|
74
|
-
Returns a `StateObject` of type `T` representing the element at the given index. If the index is out of bounds or the
|
75
|
-
state is empty, it returns an instance of `EmptyState`. Otherwise, it returns an instance of `ValidState`, which
|
76
|
-
encapsulates the element value and provides a `setValue` function to update it.
|
77
|
-
|
78
|
-
### `useFieldState<TOriginal, TField>`
|
79
|
-
|
80
|
-
This hook derives a field from the state object and creates a new `StateObject` for the field's value. It is useful for
|
81
|
-
managing state at a granular level within an object.
|
82
|
-
|
83
|
-
Parameters:
|
84
|
-
|
85
|
-
- `state`: The `StateObject` containing the original state.
|
86
|
-
- `field`: The field name to be derived from the state.
|
87
|
-
|
88
|
-
Returns a `StateObject` of type `TField` representing the derived field. This `StateObject` is an instance
|
89
|
-
of `ValidState`, which encapsulates the field value and provides a `setValue` function to update it.
|
90
|
-
|
91
|
-
For example:
|
92
|
-
|
93
|
-
```jsx
|
94
|
-
import React from 'react';
|
95
|
-
import {useStateObject, useFieldState} from 'react-state-monad';
|
96
|
-
|
97
|
-
const MyComponent = () => {
|
98
|
-
const userState = useStateObject({
|
99
|
-
name: 'John Doe',
|
100
|
-
age: 30,
|
101
|
-
});
|
102
|
-
|
103
|
-
const nameState = useFieldState(userState, 'name');
|
104
|
-
const ageState = useFieldState(userState, 'age');
|
105
|
-
|
106
|
-
return (
|
107
|
-
<div>
|
108
|
-
<input
|
109
|
-
type="text"
|
110
|
-
value={nameState.value}
|
111
|
-
onChange={(e) => nameState.value = e.target.value}
|
112
|
-
/>
|
113
|
-
<input
|
114
|
-
type="number"
|
115
|
-
value={ageState.value}
|
116
|
-
onChange={(e) => ageState.value = parseInt(e.target.value, 10)}
|
117
|
-
/>
|
118
|
-
</div>
|
119
|
-
);
|
120
|
-
};
|
121
|
-
|
122
|
-
export default MyComponent;
|
123
|
-
```
|
124
|
-
|
125
|
-
### `useRemapArray<T>`
|
126
|
-
|
127
|
-
This hook maps each element in an array within a `StateObject` to a new `StateObject`, allowing for independent updates
|
128
|
-
of each element while keeping the overall array state synchronized.
|
129
|
-
|
130
|
-
Parameters:
|
131
|
-
|
132
|
-
- `state`: The `StateObject` containing an array.
|
133
|
-
|
134
|
-
Returns an array of new `StateObject`s, each representing an element in the original array. This allows individual
|
135
|
-
updates while keeping the array state synchronized. If the state has no value, it returns an empty array.
|
136
|
-
|
137
|
-
|
138
|
-
### `useNullSafety<TOrigin>`
|
139
|
-
|
140
|
-
This hook ensures a `StateObject` contains a defined, non-null value. If the `StateObject`'s value is `undefined` or `null`, it returns an `EmptyState`. Otherwise, it returns a `ValidState` with the value and a setter to update the value.
|
141
|
-
|
142
|
-
Parameters:
|
143
|
-
|
144
|
-
- `state`: The `StateObject` which may contain a value, `undefined`, or `null`.
|
145
|
-
|
146
|
-
Returns a `StateObject` of type `TOrigin` representing the value if it is defined and non-null, otherwise an `EmptyState`.
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
### Complete Example
|
154
|
-
|
155
|
-
Here's a more complete example demonstrating the usage of `useStateObject`, `useFieldState`, `useElementState`,
|
156
|
-
and `useRemapArray` hooks in a React component:
|
157
|
-
|
158
|
-
```tsx
|
159
|
-
|
160
|
-
const AgeField = (props: { ageState: StateObject<number> }) => <div>
|
161
|
-
<label>Age:</label>
|
162
|
-
<input
|
163
|
-
type="number"
|
164
|
-
value={props.ageState.value}
|
165
|
-
onChange={x => props.ageState.value = parseInt(x.target.value, 10)}
|
166
|
-
/>
|
167
|
-
</div>;
|
168
|
-
|
169
|
-
|
170
|
-
const NameField = (props: { nameState: StateObject<string> }) => {
|
171
|
-
return <div>
|
172
|
-
<label>Name:</label>
|
173
|
-
<input
|
174
|
-
type="text"
|
175
|
-
value={props.nameState.value}
|
176
|
-
onChange={x => props.nameState.value = x.target.value}
|
177
|
-
/>
|
178
|
-
</div>;
|
179
|
-
}
|
180
|
-
|
181
|
-
const HobbyField = (props: { hobbyState: StateObject<string> }) => {
|
182
|
-
return <div>
|
183
|
-
<input
|
184
|
-
type="text"
|
185
|
-
value={props.hobbyState.value}
|
186
|
-
onChange={x => props.hobbyState.value = x.target.value}
|
187
|
-
/>
|
188
|
-
</div>;
|
189
|
-
}
|
190
|
-
|
191
|
-
const HobbiesField = (props: { hobbiesState: StateObject<string[]> }) => {
|
192
|
-
|
193
|
-
const hobbyStates: StateObject<string>[] = useRemapArray(props.hobbiesState);
|
194
|
-
|
195
|
-
const addHobby = () => {
|
196
|
-
// Always use the setter to update arrays, do not modify them directly to ensure React state consistency.
|
197
|
-
// Immutability is key 💗
|
198
|
-
props.hobbiesState.value = [...props.hobbiesState.value, ''];
|
199
|
-
}
|
200
|
-
|
201
|
-
return <div>
|
202
|
-
<label>Hobbies:</label>
|
203
|
-
{
|
204
|
-
hobbyStates.map((hobbyState, index) => <HobbyField key={index} hobbyState={hobbyState}/>)
|
205
|
-
}
|
206
|
-
<button onClick={addHobby}>Add Hobby</button>
|
207
|
-
</div>;
|
208
|
-
|
209
|
-
|
210
|
-
};
|
211
|
-
|
212
|
-
export const UserProfile = () => {
|
213
|
-
|
214
|
-
type DudeData = {
|
215
|
-
name: string;
|
216
|
-
age: number;
|
217
|
-
hobbies: string[];
|
218
|
-
}
|
219
|
-
// Initialize state with an object containing user details and an array of hobbies
|
220
|
-
const userState: StateObject<DudeData> = useStateObject({
|
221
|
-
name: 'John Doe',
|
222
|
-
age: 30,
|
223
|
-
hobbies: ['Reading', 'Traveling', 'Cooking'],
|
224
|
-
});
|
225
|
-
|
226
|
-
// Derive state for individual fields
|
227
|
-
const nameState: StateObject<string> = useFieldState(userState, 'name');
|
228
|
-
const ageState: StateObject<number> = useFieldState(userState, 'age');
|
229
|
-
|
230
|
-
// Derive state for hobbies array
|
231
|
-
const hobbiesState: StateObject<string[]> = useFieldState(userState, 'hobbies');
|
232
|
-
|
233
|
-
|
234
|
-
return (
|
235
|
-
<div>
|
236
|
-
<h1>User Profile</h1>
|
237
|
-
<NameField nameState={nameState}/>
|
238
|
-
<AgeField ageState={ageState}/>
|
239
|
-
<HobbiesField hobbiesState={hobbiesState}/>
|
240
|
-
</div>
|
241
|
-
);
|
242
|
-
};
|
243
|
-
```
|
244
|
-
|
245
|
-
## Contributing
|
246
|
-
|
247
|
-
Contributions are welcome! If you'd like to contribute to this library, please fork the repository and submit a pull
|
248
|
-
request.
|
249
|
-
|
250
|
-
How to Contribute
|
251
|
-
Fork the repository.
|
252
|
-
|
253
|
-
* Create a new branch for your feature `git checkout -b feature-name`
|
254
|
-
* Commit your changes `git commit -am 'Add new feature'`
|
255
|
-
* Push to the branch `git push origin feature-name`
|
256
|
-
* Open a pull request. I'll be happy to review it!
|
257
|
-
|
258
|
-
## License
|
259
|
-
|
260
|
-
This project is licensed under the GPL-3.0 License.
|
261
|
-
|
262
|
-
## Author
|
263
|
-
|
264
|
-
`Marcos Alvarez`
|
265
|
-
|
266
|
-
[<img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" width="38" height="38">](https://github.com/alvmivan)
|
267
|
-
[<img src="https://www.linkedin.com/favicon.ico" width="40" height="40">](https://www.linkedin.com/in/marcos-alvarez-40651b150/)
|
1
|
+
# React State Monad
|
2
|
+
|
3
|
+
[](https://www.npmjs.com/package/react-state-monad/)
|
4
|
+
[](https://github.com/alvmivan/react-state-monad/releases/latest)
|
5
|
+
[](./LICENSE)
|
6
|
+
|
7
|
+
A set of hooks to manage/transform/filter states with monads in React.
|
8
|
+
|
9
|
+
## Description
|
10
|
+
|
11
|
+
`react-state-monad` provides a set of monadic state management utilities, specifically designed to work seamlessly with
|
12
|
+
React's state hooks. It allows you to manage, transform, and filter states in a functional and declarative way using
|
13
|
+
monads like `Maybe` and `Option`.
|
14
|
+
|
15
|
+
This library leverages the power of monads to encapsulate state changes, enabling a cleaner, more predictable way to
|
16
|
+
handle various state conditions in React.
|
17
|
+
|
18
|
+
## Features
|
19
|
+
|
20
|
+
- Manage state using monads like `Maybe` and `Option`.
|
21
|
+
- Simplify handling of undefined or null values in state.
|
22
|
+
- Leverage functional programming patterns in React state management.
|
23
|
+
- Support for TypeScript with full type definitions.
|
24
|
+
|
25
|
+
## Installation
|
26
|
+
|
27
|
+
You can install `react-state-monad` using npm or yarn:
|
28
|
+
|
29
|
+
```bash
|
30
|
+
npm install react-state-monad
|
31
|
+
```
|
32
|
+
|
33
|
+
or
|
34
|
+
|
35
|
+
```bash
|
36
|
+
yarn add react-state-monad
|
37
|
+
```
|
38
|
+
|
39
|
+
## Usage
|
40
|
+
|
41
|
+
Here's an example of how you can use the hooks in your React components:
|
42
|
+
|
43
|
+
### `useStateObject<T>`
|
44
|
+
|
45
|
+
This hook initializes a StateObject with the provided initial value. It uses React's useState hook to manage the
|
46
|
+
internal state and returns a StateObject that represents the current state.
|
47
|
+
|
48
|
+
Parameters: `initialState`: The initial value of the state. This value can be of any type, determined by the generic
|
49
|
+
type `T`.
|
50
|
+
|
51
|
+
Returns a `StateObject` of type `T` representing the initialized state. This `StateObject` is an instance
|
52
|
+
of `ValidState`, which
|
53
|
+
encapsulates the state value and provides a `setValue` function to update it.
|
54
|
+
|
55
|
+
### `useEmptyState<T>`
|
56
|
+
|
57
|
+
This hook initializes a `StateObject` with an empty state. It is useful as a fallback when no valid state is available.
|
58
|
+
|
59
|
+
Parameters: None.
|
60
|
+
|
61
|
+
Returns a `StateObject` of type `T` representing an empty state. This `StateObject` is an instance of `EmptyState`,
|
62
|
+
which encapsulates the absence of a state value.
|
63
|
+
|
64
|
+
### `useElementState<T>`
|
65
|
+
|
66
|
+
This hook allows you to derive and update a specific element in an array within a `StateObject`. It is useful for
|
67
|
+
managing state at a granular level within an array.
|
68
|
+
|
69
|
+
Parameters:
|
70
|
+
|
71
|
+
- `state`: The `StateObject` containing an array.
|
72
|
+
- `index`: The index of the element to be derived.
|
73
|
+
|
74
|
+
Returns a `StateObject` of type `T` representing the element at the given index. If the index is out of bounds or the
|
75
|
+
state is empty, it returns an instance of `EmptyState`. Otherwise, it returns an instance of `ValidState`, which
|
76
|
+
encapsulates the element value and provides a `setValue` function to update it.
|
77
|
+
|
78
|
+
### `useFieldState<TOriginal, TField>`
|
79
|
+
|
80
|
+
This hook derives a field from the state object and creates a new `StateObject` for the field's value. It is useful for
|
81
|
+
managing state at a granular level within an object.
|
82
|
+
|
83
|
+
Parameters:
|
84
|
+
|
85
|
+
- `state`: The `StateObject` containing the original state.
|
86
|
+
- `field`: The field name to be derived from the state.
|
87
|
+
|
88
|
+
Returns a `StateObject` of type `TField` representing the derived field. This `StateObject` is an instance
|
89
|
+
of `ValidState`, which encapsulates the field value and provides a `setValue` function to update it.
|
90
|
+
|
91
|
+
For example:
|
92
|
+
|
93
|
+
```jsx
|
94
|
+
import React from 'react';
|
95
|
+
import {useStateObject, useFieldState} from 'react-state-monad';
|
96
|
+
|
97
|
+
const MyComponent = () => {
|
98
|
+
const userState = useStateObject({
|
99
|
+
name: 'John Doe',
|
100
|
+
age: 30,
|
101
|
+
});
|
102
|
+
|
103
|
+
const nameState = useFieldState(userState, 'name');
|
104
|
+
const ageState = useFieldState(userState, 'age');
|
105
|
+
|
106
|
+
return (
|
107
|
+
<div>
|
108
|
+
<input
|
109
|
+
type="text"
|
110
|
+
value={nameState.value}
|
111
|
+
onChange={(e) => nameState.value = e.target.value}
|
112
|
+
/>
|
113
|
+
<input
|
114
|
+
type="number"
|
115
|
+
value={ageState.value}
|
116
|
+
onChange={(e) => ageState.value = parseInt(e.target.value, 10)}
|
117
|
+
/>
|
118
|
+
</div>
|
119
|
+
);
|
120
|
+
};
|
121
|
+
|
122
|
+
export default MyComponent;
|
123
|
+
```
|
124
|
+
|
125
|
+
### `useRemapArray<T>`
|
126
|
+
|
127
|
+
This hook maps each element in an array within a `StateObject` to a new `StateObject`, allowing for independent updates
|
128
|
+
of each element while keeping the overall array state synchronized.
|
129
|
+
|
130
|
+
Parameters:
|
131
|
+
|
132
|
+
- `state`: The `StateObject` containing an array.
|
133
|
+
|
134
|
+
Returns an array of new `StateObject`s, each representing an element in the original array. This allows individual
|
135
|
+
updates while keeping the array state synchronized. If the state has no value, it returns an empty array.
|
136
|
+
|
137
|
+
|
138
|
+
### `useNullSafety<TOrigin>`
|
139
|
+
|
140
|
+
This hook ensures a `StateObject` contains a defined, non-null value. If the `StateObject`'s value is `undefined` or `null`, it returns an `EmptyState`. Otherwise, it returns a `ValidState` with the value and a setter to update the value.
|
141
|
+
|
142
|
+
Parameters:
|
143
|
+
|
144
|
+
- `state`: The `StateObject` which may contain a value, `undefined`, or `null`.
|
145
|
+
|
146
|
+
Returns a `StateObject` of type `TOrigin` representing the value if it is defined and non-null, otherwise an `EmptyState`.
|
147
|
+
|
148
|
+
|
149
|
+
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
### Complete Example
|
154
|
+
|
155
|
+
Here's a more complete example demonstrating the usage of `useStateObject`, `useFieldState`, `useElementState`,
|
156
|
+
and `useRemapArray` hooks in a React component:
|
157
|
+
|
158
|
+
```tsx
|
159
|
+
|
160
|
+
const AgeField = (props: { ageState: StateObject<number> }) => <div>
|
161
|
+
<label>Age:</label>
|
162
|
+
<input
|
163
|
+
type="number"
|
164
|
+
value={props.ageState.value}
|
165
|
+
onChange={x => props.ageState.value = parseInt(x.target.value, 10)}
|
166
|
+
/>
|
167
|
+
</div>;
|
168
|
+
|
169
|
+
|
170
|
+
const NameField = (props: { nameState: StateObject<string> }) => {
|
171
|
+
return <div>
|
172
|
+
<label>Name:</label>
|
173
|
+
<input
|
174
|
+
type="text"
|
175
|
+
value={props.nameState.value}
|
176
|
+
onChange={x => props.nameState.value = x.target.value}
|
177
|
+
/>
|
178
|
+
</div>;
|
179
|
+
}
|
180
|
+
|
181
|
+
const HobbyField = (props: { hobbyState: StateObject<string> }) => {
|
182
|
+
return <div>
|
183
|
+
<input
|
184
|
+
type="text"
|
185
|
+
value={props.hobbyState.value}
|
186
|
+
onChange={x => props.hobbyState.value = x.target.value}
|
187
|
+
/>
|
188
|
+
</div>;
|
189
|
+
}
|
190
|
+
|
191
|
+
const HobbiesField = (props: { hobbiesState: StateObject<string[]> }) => {
|
192
|
+
|
193
|
+
const hobbyStates: StateObject<string>[] = useRemapArray(props.hobbiesState);
|
194
|
+
|
195
|
+
const addHobby = () => {
|
196
|
+
// Always use the setter to update arrays, do not modify them directly to ensure React state consistency.
|
197
|
+
// Immutability is key 💗
|
198
|
+
props.hobbiesState.value = [...props.hobbiesState.value, ''];
|
199
|
+
}
|
200
|
+
|
201
|
+
return <div>
|
202
|
+
<label>Hobbies:</label>
|
203
|
+
{
|
204
|
+
hobbyStates.map((hobbyState, index) => <HobbyField key={index} hobbyState={hobbyState}/>)
|
205
|
+
}
|
206
|
+
<button onClick={addHobby}>Add Hobby</button>
|
207
|
+
</div>;
|
208
|
+
|
209
|
+
|
210
|
+
};
|
211
|
+
|
212
|
+
export const UserProfile = () => {
|
213
|
+
|
214
|
+
type DudeData = {
|
215
|
+
name: string;
|
216
|
+
age: number;
|
217
|
+
hobbies: string[];
|
218
|
+
}
|
219
|
+
// Initialize state with an object containing user details and an array of hobbies
|
220
|
+
const userState: StateObject<DudeData> = useStateObject({
|
221
|
+
name: 'John Doe',
|
222
|
+
age: 30,
|
223
|
+
hobbies: ['Reading', 'Traveling', 'Cooking'],
|
224
|
+
});
|
225
|
+
|
226
|
+
// Derive state for individual fields
|
227
|
+
const nameState: StateObject<string> = useFieldState(userState, 'name');
|
228
|
+
const ageState: StateObject<number> = useFieldState(userState, 'age');
|
229
|
+
|
230
|
+
// Derive state for hobbies array
|
231
|
+
const hobbiesState: StateObject<string[]> = useFieldState(userState, 'hobbies');
|
232
|
+
|
233
|
+
|
234
|
+
return (
|
235
|
+
<div>
|
236
|
+
<h1>User Profile</h1>
|
237
|
+
<NameField nameState={nameState}/>
|
238
|
+
<AgeField ageState={ageState}/>
|
239
|
+
<HobbiesField hobbiesState={hobbiesState}/>
|
240
|
+
</div>
|
241
|
+
);
|
242
|
+
};
|
243
|
+
```
|
244
|
+
|
245
|
+
## Contributing
|
246
|
+
|
247
|
+
Contributions are welcome! If you'd like to contribute to this library, please fork the repository and submit a pull
|
248
|
+
request.
|
249
|
+
|
250
|
+
How to Contribute
|
251
|
+
Fork the repository.
|
252
|
+
|
253
|
+
* Create a new branch for your feature `git checkout -b feature-name`
|
254
|
+
* Commit your changes `git commit -am 'Add new feature'`
|
255
|
+
* Push to the branch `git push origin feature-name`
|
256
|
+
* Open a pull request. I'll be happy to review it!
|
257
|
+
|
258
|
+
## License
|
259
|
+
|
260
|
+
This project is licensed under the GPL-3.0 License.
|
261
|
+
|
262
|
+
## Author
|
263
|
+
|
264
|
+
`Marcos Alvarez`
|
265
|
+
|
266
|
+
[<img src="https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png" width="38" height="38">](https://github.com/alvmivan)
|
267
|
+
[<img src="https://www.linkedin.com/favicon.ico" width="40" height="40">](https://www.linkedin.com/in/marcos-alvarez-40651b150/)
|
268
268
|
[<img src="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/gmail.ico" width="40" height="40">](mailto:alvmivan@gmail.com)
|
package/dist/index.cjs
CHANGED
@@ -27,6 +27,7 @@ __export(index_exports, {
|
|
27
27
|
useFieldState: () => useFieldState,
|
28
28
|
useNullSafety: () => useNullSafety,
|
29
29
|
useRemapArray: () => useRemapArray,
|
30
|
+
useRemapKeysState: () => useRemapKeysState,
|
30
31
|
useStateObject: () => useStateObject
|
31
32
|
});
|
32
33
|
module.exports = __toCommonJS(index_exports);
|
@@ -40,6 +41,21 @@ function useFieldState(state, field) {
|
|
40
41
|
// Updates the field with the new value.
|
41
42
|
);
|
42
43
|
}
|
44
|
+
function useRemapKeysState(state) {
|
45
|
+
if (!state.hasValue) {
|
46
|
+
return /* @__PURE__ */ new Map();
|
47
|
+
}
|
48
|
+
if (Array.isArray(state.value)) {
|
49
|
+
console.warn("useRemapKeysState should be used with objects, use useRemapArray for arrays");
|
50
|
+
return /* @__PURE__ */ new Map();
|
51
|
+
}
|
52
|
+
const keys = Object.keys(state.value);
|
53
|
+
const map = /* @__PURE__ */ new Map();
|
54
|
+
keys.forEach((key) => {
|
55
|
+
map.set(key, useFieldState(state, key));
|
56
|
+
});
|
57
|
+
return map;
|
58
|
+
}
|
43
59
|
|
44
60
|
// src/implementations/emptyState.ts
|
45
61
|
var EmptyState = class _EmptyState {
|
@@ -175,5 +191,6 @@ var index_default = void 0;
|
|
175
191
|
useFieldState,
|
176
192
|
useNullSafety,
|
177
193
|
useRemapArray,
|
194
|
+
useRemapKeysState,
|
178
195
|
useStateObject
|
179
196
|
});
|
package/dist/index.d.cts
CHANGED
@@ -78,6 +78,16 @@ type ValidFieldFrom<TObject, TField> = {
|
|
78
78
|
* @returns A new StateObject for the derived field.
|
79
79
|
*/
|
80
80
|
declare function useFieldState<TOriginal, TField>(state: StateObject<TOriginal>, field: ValidFieldFrom<TOriginal, TField>): StateObject<TField>;
|
81
|
+
/**
|
82
|
+
* Hook that remaps the keys of an object within a StateObject to a Map of StateObjects,
|
83
|
+
* allowing for independent updates of each key while keeping the overall object state synchronized.
|
84
|
+
*
|
85
|
+
* @template TOriginal - The type of the original state object.
|
86
|
+
* @param state - The StateObject containing the original object.
|
87
|
+
* @returns A Map where each key is mapped to a new StateObject representing the value of that key,
|
88
|
+
* allowing individual updates while keeping the object state synchronized.
|
89
|
+
*/
|
90
|
+
declare function useRemapKeysState<TOriginal extends object, TField>(state: StateObject<TOriginal>): Map<string, StateObject<TField>>;
|
81
91
|
|
82
92
|
/**
|
83
93
|
* Hook that allows you to derive and update a specific element in an array within a StateObject.
|
@@ -141,4 +151,4 @@ declare function useNullSafety<TOrigin>(state: StateObject<TOrigin | undefined |
|
|
141
151
|
|
142
152
|
declare const _default: undefined;
|
143
153
|
|
144
|
-
export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useNullSafety, useRemapArray, useStateObject };
|
154
|
+
export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useNullSafety, useRemapArray, useRemapKeysState, useStateObject };
|
package/dist/index.d.ts
CHANGED
@@ -78,6 +78,16 @@ type ValidFieldFrom<TObject, TField> = {
|
|
78
78
|
* @returns A new StateObject for the derived field.
|
79
79
|
*/
|
80
80
|
declare function useFieldState<TOriginal, TField>(state: StateObject<TOriginal>, field: ValidFieldFrom<TOriginal, TField>): StateObject<TField>;
|
81
|
+
/**
|
82
|
+
* Hook that remaps the keys of an object within a StateObject to a Map of StateObjects,
|
83
|
+
* allowing for independent updates of each key while keeping the overall object state synchronized.
|
84
|
+
*
|
85
|
+
* @template TOriginal - The type of the original state object.
|
86
|
+
* @param state - The StateObject containing the original object.
|
87
|
+
* @returns A Map where each key is mapped to a new StateObject representing the value of that key,
|
88
|
+
* allowing individual updates while keeping the object state synchronized.
|
89
|
+
*/
|
90
|
+
declare function useRemapKeysState<TOriginal extends object, TField>(state: StateObject<TOriginal>): Map<string, StateObject<TField>>;
|
81
91
|
|
82
92
|
/**
|
83
93
|
* Hook that allows you to derive and update a specific element in an array within a StateObject.
|
@@ -141,4 +151,4 @@ declare function useNullSafety<TOrigin>(state: StateObject<TOrigin | undefined |
|
|
141
151
|
|
142
152
|
declare const _default: undefined;
|
143
153
|
|
144
|
-
export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useNullSafety, useRemapArray, useStateObject };
|
154
|
+
export { type StateObject, _default as default, useArrayState, useElementState, useEmptyState, useFieldState, useNullSafety, useRemapArray, useRemapKeysState, useStateObject };
|
package/dist/index.js
CHANGED
@@ -7,6 +7,21 @@ function useFieldState(state, field) {
|
|
7
7
|
// Updates the field with the new value.
|
8
8
|
);
|
9
9
|
}
|
10
|
+
function useRemapKeysState(state) {
|
11
|
+
if (!state.hasValue) {
|
12
|
+
return /* @__PURE__ */ new Map();
|
13
|
+
}
|
14
|
+
if (Array.isArray(state.value)) {
|
15
|
+
console.warn("useRemapKeysState should be used with objects, use useRemapArray for arrays");
|
16
|
+
return /* @__PURE__ */ new Map();
|
17
|
+
}
|
18
|
+
const keys = Object.keys(state.value);
|
19
|
+
const map = /* @__PURE__ */ new Map();
|
20
|
+
keys.forEach((key) => {
|
21
|
+
map.set(key, useFieldState(state, key));
|
22
|
+
});
|
23
|
+
return map;
|
24
|
+
}
|
10
25
|
|
11
26
|
// src/implementations/emptyState.ts
|
12
27
|
var EmptyState = class _EmptyState {
|
@@ -142,5 +157,6 @@ export {
|
|
142
157
|
useFieldState,
|
143
158
|
useNullSafety,
|
144
159
|
useRemapArray,
|
160
|
+
useRemapKeysState,
|
145
161
|
useStateObject
|
146
162
|
};
|