@chhsiao1981/use-thunk 13.0.0 → 14.0.2

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.
Files changed (95) hide show
  1. package/README.md +109 -83
  2. package/dist/dispatch.d.ts +3 -3
  3. package/dist/index.d.ts +11 -14
  4. package/dist/index.js +173 -0
  5. package/dist/index.umd.cjs +1 -0
  6. package/{types → dist}/states/index.d.ts +2 -2
  7. package/dist/thunkContext/ThunkContext.d.ts +7 -0
  8. package/{types → dist}/thunkModule/index.d.ts +1 -1
  9. package/package.json +28 -17
  10. package/dist/ThunkContext.d.ts +0 -7
  11. package/dist/action.d.ts +0 -11
  12. package/dist/createReducer.d.ts +0 -4
  13. package/dist/createThunk.d.ts +0 -4
  14. package/dist/dispatchFuncMap.d.ts +0 -18
  15. package/dist/genUUID.d.ts +0 -1
  16. package/dist/init.d.ts +0 -16
  17. package/dist/reduceMap.d.ts +0 -6
  18. package/dist/reducer.d.ts +0 -5
  19. package/dist/remove.d.ts +0 -5
  20. package/dist/setDefaultID.d.ts +0 -5
  21. package/dist/stateTypes.d.ts +0 -16
  22. package/dist/states.d.ts +0 -9
  23. package/dist/thunk.d.ts +0 -15
  24. package/dist/thunkContextMap.d.ts +0 -15
  25. package/dist/thunkContextTypes.d.ts +0 -8
  26. package/dist/thunkModuleFuncMap.d.ts +0 -7
  27. package/dist/update.d.ts +0 -6
  28. package/dist/useThunk.d.ts +0 -12
  29. package/dist/useThunkReducer.d.ts +0 -17
  30. package/src/action/ActionOrThunk.ts +0 -5
  31. package/src/action/baseAction.ts +0 -6
  32. package/src/action/index.ts +0 -16
  33. package/src/action/thunk.ts +0 -13
  34. package/src/defaultThunks/index.ts +0 -15
  35. package/src/defaultThunks/init/index.ts +0 -27
  36. package/src/defaultThunks/init/initCore.ts +0 -31
  37. package/src/defaultThunks/remove.ts +0 -35
  38. package/src/defaultThunks/setDefaultID.ts +0 -18
  39. package/src/defaultThunks/update.ts +0 -26
  40. package/src/defaultThunks/upsert.ts +0 -27
  41. package/src/dispatch.ts +0 -7
  42. package/src/get.ts +0 -4
  43. package/src/index.ts +0 -58
  44. package/src/reducer/createReducer.ts +0 -18
  45. package/src/reducer/defaultReduceMap.ts +0 -26
  46. package/src/reducer/index.ts +0 -12
  47. package/src/reducer/reduceMap.ts +0 -6
  48. package/src/registerThunk.ts +0 -29
  49. package/src/set/index.ts +0 -9
  50. package/src/set/setMap.ts +0 -59
  51. package/src/states/index.ts +0 -84
  52. package/src/states/types.ts +0 -23
  53. package/src/thunkContext/ThunkContext.tsx +0 -46
  54. package/src/thunkContext/index.ts +0 -9
  55. package/src/thunkContext/thunkContextMap.ts +0 -22
  56. package/src/thunkContext/types.ts +0 -8
  57. package/src/thunkModule/defaultDoModule.ts +0 -13
  58. package/src/thunkModule/index.ts +0 -21
  59. package/src/useThunk/index.ts +0 -48
  60. package/src/useThunk/useThunkReducer.ts +0 -100
  61. package/src/utils/deepCopy.ts +0 -30
  62. package/src/utils/genID.ts +0 -6
  63. package/src/utils/index.ts +0 -3
  64. package/types/dispatch.d.ts +0 -4
  65. package/types/index.d.ts +0 -12
  66. package/types/thunkContext/ThunkContext.d.ts +0 -7
  67. /package/{types → dist}/action/ActionOrThunk.d.ts +0 -0
  68. /package/{types → dist}/action/baseAction.d.ts +0 -0
  69. /package/{types → dist}/action/index.d.ts +0 -0
  70. /package/{types → dist}/action/thunk.d.ts +0 -0
  71. /package/{types → dist}/defaultThunks/index.d.ts +0 -0
  72. /package/{types → dist}/defaultThunks/init/index.d.ts +0 -0
  73. /package/{types → dist}/defaultThunks/init/initCore.d.ts +0 -0
  74. /package/{types → dist}/defaultThunks/remove.d.ts +0 -0
  75. /package/{types → dist}/defaultThunks/setDefaultID.d.ts +0 -0
  76. /package/{types → dist}/defaultThunks/update.d.ts +0 -0
  77. /package/{types → dist}/defaultThunks/upsert.d.ts +0 -0
  78. /package/{types → dist}/get.d.ts +0 -0
  79. /package/{types → dist}/reducer/createReducer.d.ts +0 -0
  80. /package/{types → dist}/reducer/defaultReduceMap.d.ts +0 -0
  81. /package/{types → dist}/reducer/index.d.ts +0 -0
  82. /package/{types → dist}/reducer/reduceMap.d.ts +0 -0
  83. /package/{types → dist}/registerThunk.d.ts +0 -0
  84. /package/{types → dist}/set/index.d.ts +0 -0
  85. /package/{types → dist}/set/setMap.d.ts +0 -0
  86. /package/{types → dist}/states/types.d.ts +0 -0
  87. /package/{types → dist}/thunkContext/index.d.ts +0 -0
  88. /package/{types → dist}/thunkContext/thunkContextMap.d.ts +0 -0
  89. /package/{types → dist}/thunkContext/types.d.ts +0 -0
  90. /package/{types → dist}/thunkModule/defaultDoModule.d.ts +0 -0
  91. /package/{types → dist}/useThunk/index.d.ts +0 -0
  92. /package/{types → dist}/useThunk/useThunkReducer.d.ts +0 -0
  93. /package/{types → dist}/utils/deepCopy.d.ts +0 -0
  94. /package/{types → dist}/utils/genID.d.ts +0 -0
  95. /package/{types → dist}/utils/index.d.ts +0 -0
package/README.md CHANGED
@@ -14,7 +14,7 @@ For usage examples, please refer to [demo-use-thunk](https://github.com/chhsiao1
14
14
 
15
15
  ## Install
16
16
 
17
- npm install --save @chhsiao1981/use-thunk
17
+ npm install @chhsiao1981/use-thunk
18
18
 
19
19
  ## Getting Started
20
20
 
@@ -104,10 +104,6 @@ createRoot(document.getElementById("root")!).render(
104
104
  )
105
105
  ```
106
106
 
107
- ## Introduction
108
-
109
-
110
-
111
107
  ## Development Pattern
112
108
  ### Must Included in a Thunk Module
113
109
 
@@ -165,14 +161,23 @@ createRoot(document.getElementById("root")!).render(
165
161
  )
166
162
  ```
167
163
 
168
- ## Normalized State
164
+ ## Introduction
165
+
166
+ Global state management (GSM) is tricky when developing complex ReactJS applications. [Redux/RTK](https://redux-toolkit.js.org/) and [zustand](https://zustand-demo.pmnd.rs/) focus on "We create stores that manage the global states". However, the stores can quickly become gigantic functions in complex ReacJS applications. On the other hand, `useContext` is too primitive for complex ReactJS applications.
167
+
168
+ `use-thunk` uses a different approach: All the data management is through module-based functions. With `use-thunk`:
169
+ 1. We treat the files as modules, and we write the module-based functions like what we typically do in other programming languages.
170
+ 2. React components can focus on data presentation, with obtaining the data from thunk modules.
171
+ 3. From React components' perspective, we directly call `do[Module].function(id)`.
172
+ 4. There is only 1 `ThunkContext`, which wraps around `<App />` in `main.tsx`. We no longer need to worry that the `Context` may appear in unexpected code-base and affect the underlying `useContext`.
173
+
174
+ ### Normalized State
169
175
 
170
- The general concept of normalized state can be found in [Normalizing State Shape](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape)
171
- with the following features:
176
+ The general concept of normalized state can be found in [Normalizing State Shape](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape). We use the following hierarchy to represent the normalized states:
172
177
 
173
- 1. ClassState: the state of the class, including the nodes and the defaultID of the class.
174
- 2. NodeState: the state of a node, including the id of the node and the content (state) of the node.
175
- 3. State: the content of the node, represented as a state.
178
+ 1. ModuleState: the state of a module, including the nodes and related information of the module.
179
+ 2. NodeState: the state of a node, including the id of the node and the data (state) of the node.
180
+ 3. State: the data of the node, represented as a state.
176
181
 
177
182
  For example, the example [in the redux link](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape) is represented as:
178
183
 
@@ -180,24 +185,24 @@ For example, the example [in the redux link](https://redux.js.org/recipes/struct
180
185
  moduleStatePost = {
181
186
  name: 'post',
182
187
  nodes: {
183
- [uuid-post1] : {
184
- id: uuid-post1,
188
+ [postID1] : {
189
+ id: postID1,
185
190
  state: {
186
- author : uuid-user1,
191
+ author : userID1,
187
192
  body : "......",
188
- comments: [uuid-comment1, uuid-comment2]
193
+ comments: [commentID1, commentID2]
189
194
  },
190
195
  },
191
- [uuid-post2] : {
192
- id : uuid-post2,
196
+ [postID2] : {
197
+ id : postID2,
193
198
  state: {
194
- author : uuid-user2,
199
+ author : userID2,
195
200
  body : "......",
196
- comments: [uuid-comment3, uuid-comment4, uuid-comment5]
201
+ comments: [commentID3, commentID4, commentID5]
197
202
  }
198
203
  }
199
204
  },
200
- defaultID,s
205
+ defaultID,
201
206
  defaultState,
202
207
  }
203
208
  ```
@@ -206,40 +211,40 @@ and:
206
211
 
207
212
  ```ts
208
213
  moduleStateComment = {
209
- myClass: 'module',
214
+ name: 'comment',
210
215
  nodes: {
211
- [uuid-comment1] : {
212
- id: uuid-comment1,
216
+ [commentID1] : {
217
+ id: commentID1,
213
218
  state: {
214
- author : uuid-user2,
219
+ author : userID2,
215
220
  comment : ".....",
216
221
  }
217
222
  },
218
- [uuid-comment2] : {
219
- id : uuid-comment2,
223
+ [commentID2] : {
224
+ id : commentID2,
220
225
  state: {
221
- author : uuid-user3,
226
+ author : userID3,
222
227
  comment : ".....",
223
228
  }
224
229
  },
225
- [uuid-comment3] : {
226
- id : uuid-comment3,
230
+ [commentID3] : {
231
+ id : commentID3,
227
232
  state: {
228
- author : uuid-user3,
233
+ author : userID3,
229
234
  comment : ".....",
230
235
  }
231
236
  },
232
- [uuid-comment4] : {
233
- id : uuid-comment4,
237
+ [commentID4] : {
238
+ id : commentID4,
234
239
  state: {
235
- author : uuid-user1,
240
+ author : userID1,
236
241
  comment : ".....",
237
242
  }
238
243
  },
239
- [uuid-comment5] : {
240
- id : uuid-comment5,
244
+ [commentID5] : {
245
+ id : commentID5,
241
246
  state: {
242
- author : uuid-user3,
247
+ author : userID3,
243
248
  comment : ".....",
244
249
  }
245
250
  }
@@ -254,22 +259,22 @@ and:
254
259
  moduleStateUser = {
255
260
  name: 'user',
256
261
  nodes: {
257
- [uuid-user1] : {
258
- id: uuid-user1,
262
+ [userID1] : {
263
+ id: userID1,
259
264
  state: {
260
265
  username : "user1",
261
266
  name : "User 1",
262
267
  }
263
268
  },
264
- [uuid-user2] : {
265
- id: uuid-user2,
269
+ [userID2] : {
270
+ id: userID2,
266
271
  state: {
267
272
  username : "user2",
268
273
  name : "User 2",
269
274
  }
270
275
  },
271
- [uuid-user3] : {
272
- id: uuid-user3,
276
+ [userID3] : {
277
+ id: userID3,
273
278
  state: {
274
279
  username : "user3",
275
280
  name : "User 3",
@@ -285,12 +290,35 @@ moduleStateUser = {
285
290
 
286
291
  #### Types
287
292
 
288
- ##### `type Thunk`
293
+ ##### `ThunkModule<S extends State>`
294
+
295
+ ```ts
296
+ export type ThunkModule<S extends State> = {
297
+ name: string
298
+ defaultState: S
299
+
300
+ // The rest of the variables are doModule.
301
+ // Specifying index-signatures to include all the variables.
302
+ [action: string]: ThunkFunc<S> | string | S
303
+ }
304
+ ```
305
+
306
+ A ThunkModule represents a self-contained domain state slice implemented within a single file. It encapsulates the module's identity, its initial data structure, and the business logic workflows (thunk functions) that act upon it.
307
+
308
+ ##### `ThunkFunc<S extends State>`
309
+
310
+ ```ts
311
+ export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>
312
+ ```
313
+
314
+ The thunk functions in a thunk module.
315
+
316
+ ##### `Thunk`
289
317
 
290
318
  `Thunk` is defined as:
291
319
 
292
320
  ```ts
293
- export type Thunk<S extends State> = (
321
+ export type Thunk<S extends State> = async (
294
322
  set: set<S>,
295
323
  get: (id?: string) => S,
296
324
  getOrNull: (id?: string) => S | null | undefined,
@@ -299,20 +327,17 @@ export type Thunk<S extends State> = (
299
327
  ) => void
300
328
  ```
301
329
 
302
- We generally use only `set` and `get`.
303
-
304
- ##### `ThunkModule<S extends State>`
330
+ `Thunk`s can be async functions if needed (ex: `fetch` data).
305
331
 
306
- ```ts
307
- export type ThunkModule<S extends State> = {
308
- name: string
309
- defaultState: S
332
+ We generally use only `set` and `get`.
310
333
 
311
- // The rest of the variables are doModule.
312
- // Specifying index-signatures to include all the variables.
313
- [action: string]: ThunkFunc<S> | string | S
314
- }
315
- ```
334
+ * `set`: can be used in the following setting:
335
+ * `set(ThunkFunc())`: calling a thunk function.
336
+ * `set(id, data: Partial<S>)`: upsert state of `id` (syntax sugar of `set(upsert(id, data))`).
337
+ * `get`: (Guaranteed) get the state of `id` (or `defaultID` if `id` is not present).
338
+ * `getOrNull`: get the state of `id`. Get the state of `defaultID` if `id` is not present. Return `null` if `id` or state is not available.
339
+ * `dispatch`: `dispatch(ThunkFunc())` (calling a thunk function).
340
+ * `getModuleState`: get the whole module state.
316
341
 
317
342
  ##### `doModule<S extends State>`
318
343
 
@@ -322,17 +347,19 @@ export interface doModule<S extends State> {
322
347
  }
323
348
  ```
324
349
 
325
- ##### `ThunkFunc<S extends State>`
350
+ ##### `toDoModule`
326
351
 
327
352
  ```ts
328
- export type ThunkFunc<S extends State> = (...params: any[]) => Thunk<S>
353
+ export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'defaultState'>
329
354
  ```
330
355
 
356
+ Converting `ThunkModule` to `doModule` by omitting `name` and `defaultState`.
357
+
331
358
  #### RegisterThunk / ThunkContext / useThunk
332
359
 
333
360
  ##### `registerThunk(module: ThunkModule)`
334
361
 
335
- register a thunk module.
362
+ Register a thunk module.
336
363
 
337
364
  ##### `<ThunkContext>{children}</ThunkContext>`
338
365
 
@@ -340,18 +367,24 @@ Rendering thunk context.
340
367
 
341
368
  ##### `useThunk(theDo: ThunkModule): UseThunk`
342
369
 
343
- Similar to `React.useReducer`, but we use `useThunk`, and we also bind the actions with `set` (similar concept as `mapDispatchToProps`).
370
+ Similar to `React.useReducer`, but we use `useThunk`. In addition, we bind the thunk functions with `dispatch`, so we can directly use `do[Module].[function]()` (similar concept as `zustand`).
344
371
 
345
372
  return: `UseThunk`
346
373
 
347
374
  #### State
348
375
 
349
- ##### `getState(theUseThunk: UseThunk, myID?: string): [state, doModule, theID]`
376
+ ##### `getState(theUseThunk: UseThunk, id?: string): [state, doModule, theID]`
350
377
 
351
- Get the state of `myID` by `UseThunk`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
378
+ (Guaranteed) Get the state of `id` (or `defaultID` if `id` is not present) by `UseThunk`. If `defaultID` is not available, generate new ID as `defaultID`. If state is not available, clone `defaultState` as the state.
352
379
 
353
380
  return: `[state, doModule, theID]`
354
- o
381
+
382
+ #### Misc
383
+
384
+ ##### `genID(): string`
385
+
386
+ Generate `id` for the state.
387
+
355
388
  ### Advanced Usage
356
389
 
357
390
  #### types
@@ -370,37 +403,30 @@ export type setMap<S extends State, T extends doModule<S>> = {
370
403
  } & Omit<DefaultSetMap, keyof T>
371
404
  ```
372
405
 
373
- #### Default Thunk Functions.
406
+ #### Primitive Thunk Functions.
374
407
 
375
- ##### `init({myID, parentID, doParent, state})`
408
+ ##### `init({id, parentID, doParent, state})`
376
409
 
377
- initialize the state.
410
+ Initialize the state.
378
411
 
379
- ##### `update(myID, data)`
412
+ ##### `update(id, data)`
380
413
 
381
- update the data to myID.
414
+ Update the data to `id`.
382
415
 
383
- ##### `upsert(myID, data)`
416
+ ##### `upsert(id, data)`
384
417
 
385
- initialize the state if it does not exist, and update the data to myID.
418
+ Initialize the state with `defaultState` if it does not exist, and update the data to `id`.
386
419
 
387
- ##### `remove(myID)`
420
+ ##### `remove(id)`
388
421
 
389
- remove the state.
422
+ Remove the state.
390
423
 
391
424
  #### State
392
425
 
393
- ##### `getStateOrNullByModule(moduleState: ModuleState, myID?: string): state | null`
394
-
395
- Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `null` if not available.
396
-
397
- ##### `getStateByModule(moduleState: ModuleState, myID?: string): state`
398
-
399
- Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
426
+ ##### `getStateOrNullByModule(moduleState: ModuleState, id?: string): state | null`
400
427
 
401
- #### Misc
402
-
403
- ##### `genID(): string`
428
+ Get the state of `id`. Get the state of `defaultID` if `id` is not present. Return `null` if not available.
404
429
 
405
- generate id for the state.
430
+ ##### `getStateByModule(moduleState: ModuleState, id?: string): state`
406
431
 
432
+ (Guaranteed) Get the state of `id` (or `defaultID` if `id` is not present) by module state. If `defaultID` is not available, generate new ID as `defaultID`. If state is not available, clone `defaultState` as the state.
@@ -1,4 +1,4 @@
1
- import type { Dispatch as rDispatch } from 'react';
1
+ import type { Dispatch } from 'react';
2
2
  import type { ActionOrThunk } from './action';
3
- import type { State } from './stateTypes';
4
- export type Dispatch<S extends State> = rDispatch<ActionOrThunk<S>>;
3
+ import type { State } from './states';
4
+ export type dispatch<S extends State> = Dispatch<ActionOrThunk<S>>;
package/dist/index.d.ts CHANGED
@@ -1,15 +1,12 @@
1
- import type { GetClassState, Thunk } from './action';
2
- import createThunk, { registerThunk } from './createThunk';
3
- import type { Dispatch } from './dispatch';
4
- import type { DispatchFuncMap } from './dispatchFuncMap';
5
- import { genUUID } from './genUUID';
6
- import { type InitParams, init } from './init';
7
- import { remove } from './remove';
8
- import { setDefaultID } from './setDefaultID';
9
- import { getDefaultID, getNode, getState, mustGetState, mustGetStateByThunk } from './states';
10
- import type { ClassState, NodeState, NodeStateMap, State } from './stateTypes';
11
- import ThunkContext from './ThunkContext';
12
- import type { ThunkModule, ThunkModuleToFunc } from './thunk';
13
- import { setData, update } from './update';
1
+ import type { getModuleState, Thunk, ThunkFunc } from './action';
2
+ import { type InitParams, init, remove, setDefaultID, update, upsert } from './defaultThunks';
3
+ import type { dispatch } from './dispatch';
4
+ import type { get, getOrNull } from './get';
5
+ import registerThunk from './registerThunk';
6
+ import type { set, setMap } from './set';
7
+ import { getDefaultID, getNodeOrNull, getState, getStateByModule, getStateOrNullByModule, type ModuleState, type State } from './states';
8
+ import { ThunkContext } from './thunkContext';
9
+ import type { doModule, ThunkModule, toDoModule } from './thunkModule';
14
10
  import useThunk, { type UseThunk } from './useThunk';
15
- export { createThunk, registerThunk, useThunk, ThunkContext, type UseThunk, type State, type NodeState, type NodeStateMap, type ClassState, type GetClassState, type Thunk, type ThunkModule, type ThunkModuleToFunc, type Dispatch, type DispatchFuncMap, getDefaultID, getNode, getState, mustGetState, mustGetStateByThunk, init, type InitParams, setData, update, remove, setDefaultID, genUUID, };
11
+ import { genID } from './utils';
12
+ export { type Thunk, type set, type get, type getOrNull, type dispatch, type getModuleState, registerThunk, useThunk, type UseThunk, ThunkContext, type State, getState, type ModuleState, type ThunkModule, type toDoModule, type doModule, type ThunkFunc, init, type InitParams, update, upsert, remove, genID, type setMap, setDefaultID, getNodeOrNull, getDefaultID, getStateOrNullByModule, getStateByModule, };
package/dist/index.js ADDED
@@ -0,0 +1,173 @@
1
+ import { createContext as e, useCallback as t, useContext as n, useMemo as r, useState as i } from "react";
2
+ import { jsx as a } from "react/jsx-runtime";
3
+ //#region src/utils/deepCopy.ts
4
+ var o = (e) => {
5
+ if (typeof e != "object" || !e) return e;
6
+ if (e instanceof Date) return new Date(e.getTime());
7
+ if (Array.isArray(e)) return e.map((e) => o(e));
8
+ let t = {};
9
+ for (let n in e) e.hasOwnProperty(n) && (t[n] = o(e[n]));
10
+ return t;
11
+ }, s = 1, c = () => (s += 1, `${s}`), l = "@chhsiao1981/use-thunk/SET_DEFAULT_ID", u = (e) => ({
12
+ myID: e,
13
+ type: l
14
+ }), d = (e, t) => {
15
+ let { myID: n } = t;
16
+ return Object.assign({}, e, {
17
+ defaultID: n,
18
+ isInitDefaultID: !0
19
+ });
20
+ }, f = "@chhsiao1981/use-thunk/INIT", p = (e, t) => ({
21
+ myID: e,
22
+ type: f,
23
+ state: t
24
+ }), m = (e, t) => {
25
+ let { myID: n, state: r } = t, i = {
26
+ id: n,
27
+ state: r
28
+ }, a = Object.assign({}, e.nodes, { [n]: i });
29
+ return Object.assign({}, e, { nodes: a });
30
+ }, h = (e) => (t, n, r, i, a) => {
31
+ let o = e.myID ?? c(), { state: s } = e;
32
+ t(p(o, s));
33
+ let { defaultID: l } = a();
34
+ l || t(u(o));
35
+ }, g = "@chhsiao1981/use-thunk/UPDATE", _ = (e, t) => ({
36
+ myID: e,
37
+ type: g,
38
+ data: t
39
+ }), v = (e, t) => {
40
+ let { myID: n, data: r } = t, i = e.nodes[n];
41
+ if (!i) return e;
42
+ let a = Object.assign({}, i.state, r), o = Object.assign({}, i, { state: a }), s = Object.assign({}, e.nodes, { [n]: o });
43
+ return Object.assign({}, e, { nodes: s });
44
+ }, y = "@chhsiao1981/use-thunk/REMOVE", b = (e) => ({
45
+ myID: e,
46
+ type: y
47
+ }), x = (e, t) => {
48
+ let { myID: n } = t;
49
+ if (!e.nodes[n]) return e;
50
+ let r = Object.keys(e.nodes).filter((e) => e !== n).reduce((t, n) => (t[n] = e.nodes[n], t), {}), i = Object.assign({}, e, { nodes: r });
51
+ return i.defaultID === n && (i.defaultID = null), i;
52
+ }, S = "@chhsiao1981/use-thunk/UPSERT", C = (e, t) => ({
53
+ myID: e,
54
+ type: S,
55
+ data: t
56
+ }), w = (e, t) => {
57
+ let { myID: n, data: r } = t, i = e.nodes[n] ?? {
58
+ id: n,
59
+ state: o(e.defaultState)
60
+ }, a = Object.assign({}, i.state, r), s = Object.assign({}, i, { state: a }), c = Object.assign({}, e.nodes, { [n]: s });
61
+ return Object.assign({}, e, { nodes: c });
62
+ }, T = {
63
+ theMap: {},
64
+ theList: []
65
+ }, E = (e) => {
66
+ let { modules: t, children: n } = e, o = t || T.theList;
67
+ if (o.length === 0) return n;
68
+ let s = o[0], { context: c, refModuleState: l } = T.theMap[s], [u, d] = i(l.current);
69
+ l.current = u;
70
+ let f = r(() => ({
71
+ refModuleState: l,
72
+ setModuleState: d
73
+ }), [u]), p = o.length === 1 ? n : E({
74
+ modules: o.slice(1),
75
+ children: n
76
+ });
77
+ return /* @__PURE__ */ a(c.Provider, {
78
+ value: f,
79
+ children: p
80
+ });
81
+ }, D = (t) => {
82
+ let { name: n, defaultState: r } = t;
83
+ if (T.theMap[n]) {
84
+ console.warn("registerThunk: already init:", n);
85
+ return;
86
+ }
87
+ let i = {
88
+ name: n,
89
+ nodes: {},
90
+ defaultState: r
91
+ }, a = () => {}, o = { current: i }, s = e({
92
+ refModuleState: o,
93
+ setModuleState: a
94
+ });
95
+ T.theMap[n] = {
96
+ context: s,
97
+ refModuleState: o
98
+ }, T.theList = Object.keys(T.theMap).sort(), console.info("registerThunk: done:", n);
99
+ }, O = (e, t = !1) => e.defaultID ?? (t ? c() : ""), k = (e, t) => {
100
+ let n = t || O(e);
101
+ return n && e.nodes[n] || null;
102
+ }, A = (e, t) => {
103
+ let n = t || O(e);
104
+ if (!n) return null;
105
+ let r = e.nodes[n];
106
+ return r ? r.state : null;
107
+ }, j = (e, t) => {
108
+ let n = t || O(e, !0), r = A(e, n);
109
+ if (r) return r;
110
+ let i = o(e.defaultState), a = {
111
+ id: n,
112
+ state: i
113
+ };
114
+ return e.nodes[n] = a, e.isInitDefaultID || e.defaultID || (e.defaultID = n, e.isInitDefaultID = !0), i;
115
+ }, M = (e, t) => {
116
+ let [n, r] = e, i = t || O(n, !0);
117
+ return [
118
+ j(n, i),
119
+ r,
120
+ i
121
+ ];
122
+ }, N = {
123
+ [f]: m,
124
+ [g]: v,
125
+ [y]: x,
126
+ [S]: w,
127
+ [l]: d
128
+ }, P = () => (e, t) => t && N[t.type] ? N[t.type](e, t) : e, F = {
129
+ init: h,
130
+ update: _,
131
+ remove: b
132
+ }, I = (e, t, n) => (Object.keys(e).filter((t) => typeof e[t] == "function").reduce((n, r) => {
133
+ if (n[r]) return n;
134
+ let i = e[r];
135
+ return n[r] = (...e) => t(i(...e)), n;
136
+ }, n), Object.keys(F).reduce((e, n) => {
137
+ if (e[n]) return e;
138
+ let r = F[n];
139
+ return e[n] = (...e) => t(r(...e)), e;
140
+ }, n), n), L = (e, r) => {
141
+ let { context: i } = T.theMap[r], { refModuleState: a, setModuleState: o } = n(i), s = t(() => a.current, [a]), c = t((e) => {
142
+ a.current = e, o(e);
143
+ }, [a, o]), l = t((e) => A(s(), e), [s]), u = t((e) => j(s(), e), [s]), d = t((t) => e(s(), t), [e, s]), f = t((e) => {
144
+ if (typeof e == "function") {
145
+ e(p, u, l, f, s);
146
+ return;
147
+ }
148
+ c(d(e));
149
+ }, [
150
+ s,
151
+ c,
152
+ d
153
+ ]), p = t((e, t) => {
154
+ if (typeof e == "string") {
155
+ if (!t) return;
156
+ c(d(C(e, t)));
157
+ return;
158
+ }
159
+ f(e);
160
+ }, [
161
+ s,
162
+ c,
163
+ d
164
+ ]);
165
+ return [a.current, p];
166
+ }, R = {}, z = (e) => {
167
+ let { name: t } = e, n = !R[t];
168
+ n && (R[t] = {});
169
+ let i = R[t], [a, o] = L(r(() => P(), []), t), s = r(() => [a, i], [a, i]);
170
+ return n && I(e, o, i), s;
171
+ };
172
+ //#endregion
173
+ export { E as ThunkContext, c as genID, O as getDefaultID, k as getNodeOrNull, M as getState, j as getStateByModule, A as getStateOrNullByModule, h as init, D as registerThunk, b as remove, u as setDefaultID, _ as update, C as upsert, z as useThunk };
@@ -0,0 +1 @@
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e[`@chhsiao1981/use-thunk`]={},e.React,e.ReactJSXRuntime))})(this,function(e,t,n){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var r=e=>{if(typeof e!=`object`||!e)return e;if(e instanceof Date)return new Date(e.getTime());if(Array.isArray(e))return e.map(e=>r(e));let t={};for(let n in e)e.hasOwnProperty(n)&&(t[n]=r(e[n]));return t},i=1,a=()=>(i+=1,`${i}`),o=`@chhsiao1981/use-thunk/SET_DEFAULT_ID`,s=e=>({myID:e,type:o}),c=(e,t)=>{let{myID:n}=t;return Object.assign({},e,{defaultID:n,isInitDefaultID:!0})},l=`@chhsiao1981/use-thunk/INIT`,u=(e,t)=>({myID:e,type:l,state:t}),d=(e,t)=>{let{myID:n,state:r}=t,i={id:n,state:r},a=Object.assign({},e.nodes,{[n]:i});return Object.assign({},e,{nodes:a})},f=e=>(t,n,r,i,o)=>{let c=e.myID??a(),{state:l}=e;t(u(c,l));let{defaultID:d}=o();d||t(s(c))},p=`@chhsiao1981/use-thunk/UPDATE`,m=(e,t)=>({myID:e,type:p,data:t}),h=(e,t)=>{let{myID:n,data:r}=t,i=e.nodes[n];if(!i)return e;let a=Object.assign({},i.state,r),o=Object.assign({},i,{state:a}),s=Object.assign({},e.nodes,{[n]:o});return Object.assign({},e,{nodes:s})},g=`@chhsiao1981/use-thunk/REMOVE`,_=e=>({myID:e,type:g}),v=(e,t)=>{let{myID:n}=t;if(!e.nodes[n])return e;let r=Object.keys(e.nodes).filter(e=>e!==n).reduce((t,n)=>(t[n]=e.nodes[n],t),{}),i=Object.assign({},e,{nodes:r});return i.defaultID===n&&(i.defaultID=null),i},y=`@chhsiao1981/use-thunk/UPSERT`,b=(e,t)=>({myID:e,type:y,data:t}),x=(e,t)=>{let{myID:n,data:i}=t,a=e.nodes[n]??{id:n,state:r(e.defaultState)},o=Object.assign({},a.state,i),s=Object.assign({},a,{state:o}),c=Object.assign({},e.nodes,{[n]:s});return Object.assign({},e,{nodes:c})},S={theMap:{},theList:[]},C=e=>{let{modules:r,children:i}=e,a=r||S.theList;if(a.length===0)return i;let o=a[0],{context:s,refModuleState:c}=S.theMap[o],[l,u]=(0,t.useState)(c.current);c.current=l;let d=(0,t.useMemo)(()=>({refModuleState:c,setModuleState:u}),[l]),f=a.length===1?i:C({modules:a.slice(1),children:i});return(0,n.jsx)(s.Provider,{value:d,children:f})},w=e=>{let{name:n,defaultState:r}=e;if(S.theMap[n]){console.warn(`registerThunk: already init:`,n);return}let i={name:n,nodes:{},defaultState:r},a=()=>{},o={current:i},s=(0,t.createContext)({refModuleState:o,setModuleState:a});S.theMap[n]={context:s,refModuleState:o},S.theList=Object.keys(S.theMap).sort(),console.info(`registerThunk: done:`,n)},T=(e,t=!1)=>e.defaultID??(t?a():``),E=(e,t)=>{let n=t||T(e);return n&&e.nodes[n]||null},D=(e,t)=>{let n=t||T(e);if(!n)return null;let r=e.nodes[n];return r?r.state:null},O=(e,t)=>{let n=t||T(e,!0),i=D(e,n);if(i)return i;let a=r(e.defaultState),o={id:n,state:a};return e.nodes[n]=o,e.isInitDefaultID||e.defaultID||(e.defaultID=n,e.isInitDefaultID=!0),a},k=(e,t)=>{let[n,r]=e,i=t||T(n,!0);return[O(n,i),r,i]},A={[l]:d,[p]:h,[g]:v,[y]:x,[o]:c},j=()=>(e,t)=>t&&A[t.type]?A[t.type](e,t):e,M={init:f,update:m,remove:_},N=(e,t,n)=>(Object.keys(e).filter(t=>typeof e[t]==`function`).reduce((n,r)=>{if(n[r])return n;let i=e[r];return n[r]=(...e)=>t(i(...e)),n},n),Object.keys(M).reduce((e,n)=>{if(e[n])return e;let r=M[n];return e[n]=(...e)=>t(r(...e)),e},n),n),P=(e,n)=>{let{context:r}=S.theMap[n],{refModuleState:i,setModuleState:a}=(0,t.useContext)(r),o=(0,t.useCallback)(()=>i.current,[i]),s=(0,t.useCallback)(e=>{i.current=e,a(e)},[i,a]),c=(0,t.useCallback)(e=>D(o(),e),[o]),l=(0,t.useCallback)(e=>O(o(),e),[o]),u=(0,t.useCallback)(t=>e(o(),t),[e,o]),d=(0,t.useCallback)(e=>{if(typeof e==`function`){e(f,l,c,d,o);return}s(u(e))},[o,s,u]),f=(0,t.useCallback)((e,t)=>{if(typeof e==`string`){if(!t)return;s(u(b(e,t)));return}d(e)},[o,s,u]);return[i.current,f]},F={};e.ThunkContext=C,e.genID=a,e.getDefaultID=T,e.getNodeOrNull=E,e.getState=k,e.getStateByModule=O,e.getStateOrNullByModule=D,e.init=f,e.registerThunk=w,e.remove=_,e.setDefaultID=s,e.update=m,e.upsert=b,e.useThunk=e=>{let{name:n}=e,r=!F[n];r&&(F[n]={});let i=F[n],[a,o]=P((0,t.useMemo)(()=>j(),[]),n),s=(0,t.useMemo)(()=>[a,i],[a,i]);return r&&N(e,o,i),s}});
@@ -2,8 +2,8 @@ import type { setMap } from '../set';
2
2
  import type { doModule } from '../thunkModule';
3
3
  import type { UseThunk } from '../useThunk';
4
4
  import type { ModuleState, NodeState, NodeStateMap, State } from './types';
5
- export type { ModuleState, NodeState, State, NodeStateMap };
6
- export declare const getDefaultID: <S extends State>(moduleState: ModuleState<S>) => string;
5
+ export type { ModuleState, NodeState, NodeStateMap, State };
6
+ export declare const getDefaultID: <S extends State>(moduleState: ModuleState<S>, isMust?: boolean) => string;
7
7
  export declare const getNodeOrNull: <S extends State>(moduleState: ModuleState<S>, myID?: string) => Readonly<NodeState<S> | null>;
8
8
  export declare const getStateOrNullByModule: <S extends State>(moduleState: ModuleState<S>, myID?: string) => Readonly<S | null>;
9
9
  export declare const getStateByModule: <S extends State>(moduleState: ModuleState<S>, myID?: string) => Readonly<S>;
@@ -0,0 +1,7 @@
1
+ import { type JSX, type ReactNode } from 'react';
2
+ type Props = {
3
+ modules?: string[];
4
+ children?: ReactNode;
5
+ };
6
+ declare const ThunkContext: (props: Props) => JSX.Element;
7
+ export default ThunkContext;
@@ -10,4 +10,4 @@ export type ThunkModule<S extends State> = {
10
10
  defaultState: S;
11
11
  [action: string]: ThunkFunc<S> | string | S;
12
12
  };
13
- export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'default' | 'defaultState'>;
13
+ export type toDoModule<T extends ThunkModule<any>> = Omit<T, 'name' | 'defaultState'>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chhsiao1981/use-thunk",
3
- "version": "13.0.0",
3
+ "version": "14.0.2",
4
4
  "type": "module",
5
5
  "description": "A framework easily using useThunk to manage the data-state.",
6
6
  "homepage": "https://github.com/chhsiao1981/use-thunk",
@@ -8,12 +8,19 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/chhsiao1981/use-thunk"
10
10
  },
11
- "main": "src/index.ts",
12
- "types": "types/index.d.ts",
11
+ "main": "dist/index.umd.cjs",
12
+ "module": "dist/index.js",
13
+ "types": "dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js",
18
+ "require": "./dist/index.umd.cjs",
19
+ "default": "./dist/index.umd.cjs"
20
+ }
21
+ },
13
22
  "files": [
14
- "src",
15
- "dist",
16
- "types"
23
+ "dist"
17
24
  ],
18
25
  "author": {
19
26
  "name": "Chuan-Heng Hsiao",
@@ -24,34 +31,38 @@
24
31
  "useThunk"
25
32
  ],
26
33
  "scripts": {
27
- "clean:lib": "rimraf ./dist/* ./types/*",
28
34
  "compile:lib": "vite build",
29
- "build:lib": "npm run clean:lib && npm run types && npm run compile:lib",
30
- "build": "npm run build:lib",
35
+ "compile:types": "tsc -b",
36
+ "build": "npm run compile:lib && npm run compile:types",
37
+
31
38
  "lint": "biome lint --error-on-warnings",
32
39
  "test": "vitest run",
33
- "types": "tsc -b",
34
- "coverage": "vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml",
35
- "tsd": "npx -p typescript tsc src/*.ts --declaration --allowJs --emitDeclarationOnly --strict --jsx react-jsx --outDir types"
40
+ "coverage": "vitest run --coverage --reporter=junit --outputFile=test-report.junit.xml"
36
41
  },
37
42
  "license": "MIT",
38
43
  "devDependencies": {
39
- "@codecov/vite-plugin": "^2.0.1",
44
+ "@babel/core": "^7.29.0",
45
+ "@biomejs/biome": "^2.5.1",
46
+ "@rolldown/plugin-babel": "^0.2.3",
47
+ "@types/babel__core": "^7.20.5",
40
48
  "@types/node": "^25.9.3",
41
- "@types/react": ">=18.3.1",
42
49
  "@types/react-dom": ">=18.3.1",
43
- "@vitejs/plugin-react-swc": "^4.3.1",
50
+ "@vitejs/plugin-react": "^6.0.1",
44
51
  "@vitest/coverage-v8": "^4.1.8",
52
+ "babel-plugin-react-compiler": "^1.0.0",
45
53
  "globals": "^17.6.0",
46
54
  "happy-dom": "^20.10.2",
47
55
  "jiti": "^2.7.0",
48
56
  "react-dom": ">=18.3.1",
49
- "rimraf": "^6.1.3",
50
57
  "typescript": "~5.9.3",
51
- "vite": "^6.4.1",
58
+ "vite": "^8.0.16",
52
59
  "vitest": "^4.1.8"
53
60
  },
61
+ "dependencies": {
62
+ "react-compiler-runtime": "^1.0.0"
63
+ },
54
64
  "peerDependencies": {
65
+ "@types/react": ">=18.3.1",
55
66
  "react": ">=18.3.1"
56
67
  }
57
68
  }