@chhsiao1981/use-thunk 10.2.0 → 10.4.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
@@ -290,11 +290,11 @@ classStateUser = {
290
290
 
291
291
  ### Basic
292
292
 
293
- ##### `useThunk(theDo: ThunkModuleFunc): [ClassState, DispatchedAction]`
293
+ ##### `useThunk(theDo: ThunkModuleFunc): [ClassState, DispatchedFuncMap]`
294
294
 
295
295
  Similar to `React.useReducer`, but we use `useThunk`, and we also bind the actions with dispatch (similar concept as `mapDispatchToProps`).s
296
296
 
297
- return: `[ClassState<S>, DispatchedAction<S>]`
297
+ return: `[ClassState<S>, DispatchedFuncMap<S, R>]`
298
298
 
299
299
  ##### `init({myID, parentID, doParent, state}, myuuidv4?)`
300
300
 
@@ -318,14 +318,16 @@ generate uuid for react-object.
318
318
 
319
319
  Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `null` if not available.
320
320
 
321
- ##### `getStateOrDefault(state: ClassState, myID?: string): State`
321
+ ##### `mustGetState(state: ClassState, myID?: string): State`
322
322
 
323
323
  Get the state of `myID`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
324
324
 
325
- ##### `getStateByThunk(theUseThunk: UseThunk, myID?: string): [State, DispatchedActionMap, theID]`
325
+ ##### `mustGetStateByThunk(theUseThunk: UseThunk, myID?: string): [State, DispatchedActionMap, theID]`
326
326
 
327
327
  Get the state of `myID` by `UseThunk`. Get the state of `defaultID` if `myID` is not present. Return `defaultState` if not available.
328
328
 
329
+ return: `[S, DispatchedFuncMap<S, R>, theID]`
330
+
329
331
  ##### `getDefaultID(state: ClassState): string`
330
332
 
331
333
  get the default id.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chhsiao1981/use-thunk",
3
- "version": "10.2.0",
3
+ "version": "10.4.0",
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",
@@ -56,7 +56,7 @@
56
56
  "vite": "^6.4.1",
57
57
  "vitest": "^4.1.0"
58
58
  },
59
- "dependencies": {
59
+ "peerDependencies": {
60
60
  "react": ">=18.3.1",
61
61
  "uuid": "^14.0.0"
62
62
  }
@@ -1,28 +1,31 @@
1
- import { type JSX, useMemo, useState } from 'react'
1
+ import { type ReactNode, useMemo, useState } from 'react'
2
2
  import { THUNK_CONTEXT_MAP } from './thunkContextMap'
3
3
 
4
4
  type Props = {
5
5
  classes?: string[]
6
- children?: JSX.Element | JSX.Element[]
6
+ children?: ReactNode
7
7
  }
8
- const ThunkContext = (props: Props): JSX.Element => {
9
- let { classes, children } = props
10
- if (!classes) {
11
- classes = THUNK_CONTEXT_MAP.theList
12
- }
8
+
9
+ const ThunkContext = (props: Props): ReactNode => {
10
+ const { classes: propsClasses, children } = props
11
+ const classes = propsClasses || THUNK_CONTEXT_MAP.theList
12
+ // 0. if there is no Thunk classes (no registerThunk): return children.
13
13
  if (classes.length === 0) {
14
- // @ts-expect-error with children
15
14
  return children
16
15
  }
17
16
 
17
+ // render the 0th class.
18
18
  const theClass = classes[0]
19
19
 
20
+ // 1. get the context and classState from context map.
20
21
  const { context: Context_m, refClassState } = THUNK_CONTEXT_MAP.theMap[theClass]
21
22
 
23
+ // 2. setup classState.
22
24
  // biome-ignore lint/correctness/useHookAtTopLevel: the order is fixed.
23
25
  const [classState, setClassState] = useState(refClassState.current)
24
-
25
26
  refClassState.current = classState
27
+
28
+ // 3. value reset only if classState is changed.
26
29
  // biome-ignore lint/correctness/useHookAtTopLevel: the order is fixed.
27
30
  const value = useMemo(
28
31
  () => ({
@@ -32,9 +35,11 @@ const ThunkContext = (props: Props): JSX.Element => {
32
35
  [classState],
33
36
  )
34
37
 
38
+ // 4. get theChildren
35
39
  const theChildren =
36
40
  classes.length === 1 ? children : ThunkContext({ classes: classes.slice(1), children })
37
41
 
42
+ // 5. return context.
38
43
  return <Context_m.Provider value={value}>{theChildren}</Context_m.Provider>
39
44
  }
40
45
 
@@ -27,7 +27,7 @@ export const constructDispatchMap = <
27
27
  T extends ThunkModuleFunc<S>,
28
28
  A extends BaseAction,
29
29
  >(
30
- theDo: ThunkModule<S, T>,
30
+ theDo: ThunkModule<S>,
31
31
  dispatch: (action: A | rThunk<S, A>) => void,
32
32
  dispatchMap: DispatchFuncMap<S, T>,
33
33
  ) => {
@@ -40,7 +40,8 @@ export const constructDispatchMap = <
40
40
  return val
41
41
  }
42
42
 
43
- const action: ActionFunc<S> = theDo[eachAction]
43
+ // because action is a function.
44
+ const action = theDo[eachAction] as ActionFunc<S>
44
45
 
45
46
  // @ts-expect-error eachAction is in DispatchFuncMap<S, R>
46
47
  // biome-ignore lint/suspicious/noExplicitAny: action parameters can be any types.
package/src/index.ts CHANGED
@@ -7,8 +7,8 @@ import registerThunk from './registerThunk'
7
7
  import { remove } from './remove'
8
8
  import { setData } from './setData'
9
9
  import { setDefaultID } from './setDefaultID'
10
- import { getDefaultID, getNode, getState, getStateByThunk, getStateOrDefault } from './states'
11
- import type { ClassState, NodeMeta, NodeState, NodeStateMap, State } from './stateTypes'
10
+ import { getDefaultID, getNode, getState, mustGetState, mustGetStateByThunk } from './states'
11
+ import type { ClassState, NodeState, NodeStateMap, State } from './stateTypes'
12
12
  import ThunkContext from './ThunkContext'
13
13
  import type { ThunkModule, ThunkModuleToFunc } from './thunk'
14
14
  import useThunk, { type UseThunk } from './useThunk'
@@ -20,7 +20,6 @@ export {
20
20
  type UseThunk,
21
21
  type State,
22
22
  type NodeState,
23
- type NodeMeta,
24
23
  type NodeStateMap,
25
24
  // type NodeStateMapByClass, // XXX for global state
26
25
  type ClassState,
@@ -39,8 +38,8 @@ export {
39
38
  getDefaultID,
40
39
  getNode,
41
40
  getState,
42
- getStateOrDefault,
43
- getStateByThunk,
41
+ mustGetState,
42
+ mustGetStateByThunk,
44
43
  init,
45
44
  type InitParams,
46
45
  setData,
@@ -1,17 +1,18 @@
1
1
  import { createContext, type Dispatch, type SetStateAction } from 'react'
2
2
  import type { ClassState, State } from './stateTypes'
3
- import type { ThunkModule, ThunkModuleFunc } from './thunk'
3
+ import type { ThunkModule } from './thunk'
4
4
  import { THUNK_CONTEXT_MAP } from './thunkContextMap'
5
5
 
6
- export default <S extends State, R extends ThunkModuleFunc<S>>(theDo: ThunkModule<S, R>) => {
6
+ export default <S extends State>(theDo: ThunkModule<S>) => {
7
7
  const { myClass, defaultState } = theDo
8
8
 
9
9
  if (THUNK_CONTEXT_MAP.theMap[myClass]) {
10
- // already init
11
- console.info('regsterThunk: already init:', myClass)
10
+ // 1. already init
11
+ console.warn('regsterThunk: already init:', myClass)
12
12
  return
13
13
  }
14
14
 
15
+ // 2. to initialize classState, setClassState, and refClassState.
15
16
  const classState: ClassState<S> = {
16
17
  myClass,
17
18
  nodes: {},
@@ -19,15 +20,20 @@ export default <S extends State, R extends ThunkModuleFunc<S>>(theDo: ThunkModul
19
20
  }
20
21
  const setClassState: Dispatch<SetStateAction<ClassState<S>>> = () => {}
21
22
  const refClassState = { current: classState }
23
+
24
+ // 3. create context
22
25
  const context = createContext({
23
26
  refClassState,
24
27
  setClassState,
25
28
  })
26
29
 
30
+ // 4. setup THUNK_CONTEXT_MAP.theMap.
27
31
  THUNK_CONTEXT_MAP.theMap[myClass] = {
28
32
  context,
29
33
  refClassState,
30
34
  }
35
+
36
+ // 5. setup THUNK_CONTEXT_MAP.theList, to ensure the rendering order.
31
37
  const theList = Object.keys(THUNK_CONTEXT_MAP.theMap)
32
38
  theList.sort()
33
39
  THUNK_CONTEXT_MAP.theList = theList
package/src/stateTypes.ts CHANGED
@@ -13,10 +13,6 @@ export type NodeStateMap<S extends State> = {
13
13
  [key: string]: NodeState<S>
14
14
  }
15
15
 
16
- export type NodeStateMapByClass<S extends State> = {
17
- [className: string]: NodeStateMap<S>
18
- }
19
-
20
16
  // ClassState
21
17
  export type ClassState<S extends State> = {
22
18
  myClass: string
@@ -24,11 +20,3 @@ export type ClassState<S extends State> = {
24
20
  nodes: NodeStateMap<S>
25
21
  defaultState: S
26
22
  }
27
-
28
- // Node
29
- export type NodeMeta = {
30
- id: string
31
- theClass: string
32
- // @ts-expect-error do can be any type.
33
- do: DispatchFuncMap
34
- }
package/src/states.ts CHANGED
@@ -32,16 +32,16 @@ export const getState = <S extends State>(classState: ClassState<S>, myID?: stri
32
32
  return me.state
33
33
  }
34
34
 
35
- export const getStateOrDefault = <S extends State>(classState: ClassState<S>, myID?: string): S => {
35
+ export const mustGetState = <S extends State>(classState: ClassState<S>, myID?: string): S => {
36
36
  return getState(classState, myID) || classState.defaultState
37
37
  }
38
38
 
39
- export const getStateByThunk = <S extends State, R extends ThunkModuleFunc<S>>(
39
+ export const mustGetStateByThunk = <S extends State, R extends ThunkModuleFunc<S>>(
40
40
  theUseThunk: UseThunk<S, R>,
41
41
  myID?: string,
42
42
  ): [S, DispatchFuncMap<S, R>, string] => {
43
43
  const [classState, theDo] = theUseThunk
44
44
  const theID = myID ? myID : getDefaultID(classState)
45
- const state = getStateOrDefault(classState, theID)
45
+ const state = mustGetState(classState, theID)
46
46
  return [state, theDo, theID]
47
47
  }
package/src/thunk.ts CHANGED
@@ -2,15 +2,19 @@ import type { ActionFunc } from './action'
2
2
  import type { Reducer } from './reducer'
3
3
  import type { State } from './stateTypes'
4
4
 
5
- export interface ThunkModuleFunc<S extends State> {
5
+ export interface ThunkModuleBase<S extends State> {
6
+ [idx: string]: ActionFunc<S> | string | Reducer<S> | S | undefined
7
+ }
8
+
9
+ export interface ThunkModuleFunc<S extends State> extends ThunkModuleBase<S> {
6
10
  [action: string]: ActionFunc<S>
7
11
  }
8
12
 
9
13
  // This is used as the parameter for useThunk.
10
- export type ThunkModule<S extends State, T extends ThunkModuleFunc<S>> = {
14
+ export type ThunkModule<S extends State> = {
11
15
  myClass: string
12
16
  default?: Reducer<S>
13
17
  defaultState: S
14
- } & T
18
+ } & ThunkModuleBase<S>
15
19
 
16
20
  export type ThunkModuleToFunc<T> = Omit<T, 'myClass' | 'default' | 'defaultState'>
@@ -8,7 +8,7 @@ export type ThunkContextMap = {
8
8
  // biome-ignore lint/suspicious/noExplicitAny: ThunkContextMap can be any type
9
9
  context: rContext<Context<any>>
10
10
 
11
- // INFO We need to use refClassState to sync all the classState in all ops.
11
+ // we need to use refClassState to sync all the classState in all ops.
12
12
  // biome-ignore lint/suspicious/noExplicitAny: ThunkContextMap can be any type
13
13
  refClassState: { current: ClassState<any> }
14
14
  }
package/src/useThunk.ts CHANGED
@@ -21,7 +21,7 @@ export type UseThunk<S extends State, R extends ThunkModuleFunc<S>> = [
21
21
  * useThunk
22
22
  **********/
23
23
  export default <S extends State, R extends ThunkModuleFunc<S>>(
24
- theDo: ThunkModule<S, R>,
24
+ theDo: ThunkModule<S>,
25
25
  ): UseThunk<S, R> => {
26
26
  const { myClass } = theDo
27
27
 
@@ -55,10 +55,12 @@ export default <S extends State, A extends BaseAction>(
55
55
  const dispatch = useCallback(
56
56
  (action: A | Thunk<S, A>) => {
57
57
  if (typeof action === 'function') {
58
+ // action is Thunk<S, A>
58
59
  action(dispatch, getClassState)
59
60
  return
60
61
  }
61
62
 
63
+ // action is not function. so action is A
62
64
  const newClassState = reduce(action)
63
65
  setClassState(newClassState)
64
66
  },
package/types/index.d.ts CHANGED
@@ -7,9 +7,9 @@ import registerThunk from './registerThunk';
7
7
  import { remove } from './remove';
8
8
  import { setData } from './setData';
9
9
  import { setDefaultID } from './setDefaultID';
10
- import { getDefaultID, getNode, getState, getStateByThunk, getStateOrDefault } from './states';
11
- import type { ClassState, NodeMeta, NodeState, NodeStateMap, State } from './stateTypes';
10
+ import { getDefaultID, getNode, getState, mustGetState, mustGetStateByThunk } from './states';
11
+ import type { ClassState, NodeState, NodeStateMap, State } from './stateTypes';
12
12
  import ThunkContext from './ThunkContext';
13
13
  import type { ThunkModule, ThunkModuleToFunc } from './thunk';
14
14
  import useThunk, { type UseThunk } from './useThunk';
15
- export { registerThunk, useThunk, ThunkContext, type UseThunk, type State, type NodeState, type NodeMeta, type NodeStateMap, type ClassState, type GetClassState, type Thunk, type ThunkModule, type ThunkModuleToFunc, type Dispatch, type DispatchFuncMap, getDefaultID, getNode, getState, getStateOrDefault, getStateByThunk, init, type InitParams, setData, remove, setDefaultID, genUUID, };
15
+ export { 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, remove, setDefaultID, genUUID, };
@@ -8,17 +8,9 @@ export type NodeState<S extends State> = {
8
8
  export type NodeStateMap<S extends State> = {
9
9
  [key: string]: NodeState<S>;
10
10
  };
11
- export type NodeStateMapByClass<S extends State> = {
12
- [className: string]: NodeStateMap<S>;
13
- };
14
11
  export type ClassState<S extends State> = {
15
12
  myClass: string;
16
13
  defaultID?: string | null;
17
14
  nodes: NodeStateMap<S>;
18
15
  defaultState: S;
19
16
  };
20
- export type NodeMeta = {
21
- id: string;
22
- theClass: string;
23
- do: DispatchFuncMap;
24
- };
package/types/states.d.ts CHANGED
@@ -5,5 +5,5 @@ import type { UseThunk } from './useThunk';
5
5
  export declare const getDefaultID: <S extends State>(classState: ClassState<S>) => string;
6
6
  export declare const getNode: <S extends State>(classState: ClassState<S>, myID?: string) => NodeState<S> | null;
7
7
  export declare const getState: <S extends State>(classState: ClassState<S>, myID?: string) => S | null;
8
- export declare const getStateOrDefault: <S extends State>(classState: ClassState<S>, myID?: string) => S;
9
- export declare const getStateByThunk: <S extends State, R extends ThunkModuleFunc<S>>(theUseThunk: UseThunk<S, R>, myID?: string) => [S, DispatchFuncMap<S, R>, string];
8
+ export declare const mustGetState: <S extends State>(classState: ClassState<S>, myID?: string) => S;
9
+ export declare const mustGetStateByThunk: <S extends State, R extends ThunkModuleFunc<S>>(theUseThunk: UseThunk<S, R>, myID?: string) => [S, DispatchFuncMap<S, R>, string];