react-hooks-global-states 10.2.0 → 11.0.0-beta.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.
@@ -1,104 +1,241 @@
1
- import { type PropsWithChildren, Context as ReactContext } from 'react';
2
- import type { ActionCollectionConfig, StateHook, StateSetter, ActionCollectionResult, StateGetter, BaseMetadata, MetadataSetter, GlobalStoreCallbacks, UseHookConfig, ObservableFragment, MetadataGetter } from './types';
3
- export type Context<State, Actions, Metadata extends BaseMetadata | unknown> = {
4
- setMetadata: MetadataSetter<Metadata>;
5
- setState: StateSetter<State>;
6
- getState: StateGetter<State>;
7
- getMetadata: () => Metadata;
1
+ import React, { type PropsWithChildren, Context as ReactContext } from 'react';
2
+ import type { ActionCollectionConfig, ActionCollectionResult, BaseMetadata, MetadataSetter, GlobalStoreCallbacks, UseHookConfig, SubscribeToState, AnyFunction } from './types';
3
+ /**
4
+ * @description Context API
5
+ */
6
+ export type ContextApi<State, Actions, Metadata extends BaseMetadata> = {
8
7
  actions: Actions;
8
+ getMetadata: () => Metadata;
9
+ getState: () => State;
10
+ setMetadata: MetadataSetter<Metadata>;
11
+ setState: React.Dispatch<React.SetStateAction<State>>;
12
+ subscribe: SubscribeToState<State>;
9
13
  };
10
- export type ContextProvider<State, Actions, Metadata extends BaseMetadata | unknown> = React.FC<PropsWithChildren<{
11
- value?: State | ((initialValue: State) => State);
14
+ export type ContextProviderExtensions<State, Actions, Metadata extends BaseMetadata> = {
12
15
  /**
13
- * Callback called when the context is created.
14
- */
15
- onCreated?: (context: Context<State, Actions, Metadata>) => void;
16
- }>> & {
17
- /**F
18
16
  * Creates a provider wrapper which allows to capture the context value,
19
17
  * useful for testing purposes.
18
+ * @param options configuration options for the provider wrapper
19
+ * @param options.value optional initial state or initializer function
20
+ * @param options.onCreated optional callback invoked after the context is created
21
+ * @returns an object containing the wrapper component and a reference to the context value
20
22
  */
21
23
  makeProviderWrapper: (options?: {
22
24
  value?: State | ((initialValue: State) => State);
23
- onCreated?: (context: Context<State, Actions, Metadata>) => void;
25
+ onCreated?: (context: ContextApi<State, Actions, Metadata>) => void;
24
26
  }) => {
27
+ /**
28
+ * Provider for the context
29
+ */
25
30
  wrapper: React.FC<PropsWithChildren<{
26
31
  value?: State | ((initialValue: State) => State);
27
32
  }>>;
28
33
  /**
29
- * Returns access to the created context
30
- * context.current will hold the context value
34
+ * Reference to the current context value
31
35
  */
32
36
  context: {
33
- current: Context<State, Actions, Metadata>;
37
+ current: ContextApi<State, Actions, Metadata>;
34
38
  };
35
39
  };
36
40
  };
37
- export type StateControlsHook<State, StateMutator, Metadata extends BaseMetadata | unknown> = () => Readonly<[
38
- retriever: StateGetter<State>,
39
- mutator: StateMutator,
40
- metadata: MetadataGetter<Metadata>
41
- ]>;
42
- export type ObservableBuilderHook<State, StateMutator, Metadata extends BaseMetadata | unknown> = <Fragment>(this: ContextHook<State, StateMutator, Metadata>, mainSelector: (state: State) => Fragment, args?: {
43
- isEqual?: (current: Fragment, next: Fragment) => boolean;
44
- isEqualRoot?: (current: State, next: State) => boolean;
45
- name?: string;
46
- }) => ObservableFragment<Fragment>;
47
- export interface ContextBaseHook<State, StateMutator, Metadata extends BaseMetadata | unknown> {
41
+ /**
42
+ * @description Creates a React context provider component for the given global state.
43
+ * @param value Optional initial state or initializer function, useful for testing.
44
+ * @param onCreated Optional callback invoked after the context is created, receiving the full context instance.
45
+ */
46
+ export type ContextProvider<State, Actions, Metadata extends BaseMetadata> = React.FC<PropsWithChildren<{
47
+ value?: State | ((initialValue: State) => State);
48
+ onCreated?: (context: ContextApi<State, Actions, Metadata>) => void;
49
+ }>> & ContextProviderExtensions<State, Actions, Metadata>;
50
+ export interface ContextBaseHook<State, StateMutator, Metadata extends BaseMetadata> {
51
+ /**
52
+ * @description Retrieves the full state, state mutator (setState or actions), and metadata.
53
+ */
48
54
  (): Readonly<[state: State, stateMutator: StateMutator, metadata: Metadata]>;
49
- <Derivate>(selector: (state: State) => Derivate, dependencies?: unknown[]): Readonly<[
50
- state: Derivate,
51
- stateMutator: StateMutator,
52
- metadata: Metadata
53
- ]>;
54
- <Derivate>(selector: (state: State) => Derivate, config?: UseHookConfig<Derivate, State>): Readonly<[
55
- state: Derivate,
56
- stateMutator: StateMutator,
57
- metadata: Metadata
58
- ]>;
55
+ /**
56
+ * @description Retrieves a derived value from the state using the provided selector function.
57
+ * @param selector A function that selects a part of the state.
58
+ * @param dependencies Optional array of dependencies to control when the selector is re-evaluated.
59
+ * @returns A read-only tuple containing the derived state, state mutator (setState or actions), and metadata.
60
+ */
61
+ <Derivate>(selector: (state: State) => Derivate, dependencies?: unknown[]): Readonly<[state: Derivate, stateMutator: StateMutator, metadata: Metadata]>;
62
+ /**
63
+ * @description Retrieves a derived value from the state using the provided selector function.
64
+ * @param selector A function that selects a part of the state.
65
+ * @param dependencies Optional array of dependencies to control when the selector is re-evaluated.
66
+ * @returns A read-only tuple containing the derived state, state mutator (setState or actions), and metadata.
67
+ */
68
+ <Derivate>(selector: (state: State) => Derivate, config?: UseHookConfig<Derivate, State>): Readonly<[state: Derivate, stateMutator: StateMutator, metadata: Metadata]>;
59
69
  }
60
- export interface ContextHook<State, StateMutator, Metadata extends BaseMetadata | unknown> extends HookExtensions<State, StateMutator, Metadata>, ContextBaseHook<State, StateMutator, Metadata> {
70
+ /**
71
+ * @description Hook for accessing a context's state, mutator (setState or actions), and metadata.
72
+ * @returns A read-only tuple containing:
73
+ * - state: the current state, or the derived value when a selector is used
74
+ * - stateMutator: a function or actions collection to update the state
75
+ * - metadata: the current context metadata
76
+ *
77
+ * @example
78
+ * ```tsx
79
+ * // Simple usage (full state)
80
+ * const [state, setState] = useTodosContext();
81
+ *
82
+ * // With a selector (preferred for render isolation)
83
+ * const [todos, actions] = useTodosContext(s => s.todos);
84
+ *
85
+ * actions.setTodos(next);
86
+ * ```
87
+ */
88
+ export interface ContextHook<State, StateMutator, Metadata extends BaseMetadata> extends HookExtensions<State, StateMutator, Metadata>, ContextBaseHook<State, StateMutator, Metadata> {
61
89
  }
62
- export type HookExtensions<State, StateMutator, Metadata extends BaseMetadata | unknown> = {
63
- stateControls: () => readonly [
64
- useStateControls: StateControlsHook<State, StateMutator, Metadata>,
65
- useObservableBuilder: ObservableBuilderHook<State, StateMutator, Metadata>
66
- ];
90
+ export type HookExtensions<State, StateMutator, Metadata extends BaseMetadata> = {
91
+ /**
92
+ * @description Creates a derived hook that subscribes to a selected fragment of the context state.
93
+ * The selector determines which portion of the state the new hook exposes.
94
+ * This hook must be used within the corresponding context provider.
95
+ *
96
+ * @param selector A function that selects a part of the state.
97
+ * @param args Optional configuration for the derived hook, including:
98
+ * - isEqual: A function to compare the current and next selected fragment for equality.
99
+ * - isEqualRoot: A function to compare the entire state for equality.
100
+ * - name: An optional name for debugging purposes.
101
+ * @returns A new context hook that provides access to the selected fragment of the state,
102
+ * along with the state mutator and metadata.
103
+ *
104
+ * @example
105
+ * ```tsx
106
+ * const useTodos = createContext({
107
+ * todos: [],
108
+ * filter: '',
109
+ * }, {
110
+ * actions: {
111
+ * setFilter(filter: string) {
112
+ * ...
113
+ * });
114
+ *
115
+ * const useFilter = useTodos.createSelectorHook((state) => {
116
+ * return state.filter;
117
+ * });
118
+ *
119
+ * function FilterComponent() {
120
+ * // The selector only listen to the selected fragment (filter)
121
+ * // But has access to the full actions collection
122
+ * const [filter, { setFilter }] = useFilter();
123
+ *
124
+ * return (
125
+ * <input
126
+ * value={filter}
127
+ * onChange={(e) => setFilter(e.target.value)}
128
+ * />
129
+ * );
130
+ * }
131
+ * ```
132
+ */
67
133
  createSelectorHook: <Derivate>(this: ContextHook<State, StateMutator, Metadata>, selector: (state: State) => Derivate, args?: Omit<UseHookConfig<Derivate, State>, 'dependencies'> & {
68
134
  name?: string;
69
135
  }) => ContextBaseHook<Derivate, StateMutator, Metadata>;
136
+ /**
137
+ * @description Hook that provides non-reactive access to the context API.
138
+ * This allows direct interaction with the context’s state, metadata, and actions
139
+ * without triggering component re-renders.
140
+ * @returns An object containing the context API methods and properties.
141
+ */
142
+ api: () => ContextApi<State, StateMutator, Metadata>;
70
143
  };
71
144
  export interface CreateContext {
72
- <State>(value: State | (() => State)): [
73
- ContextHook<State, StateSetter<State>, BaseMetadata>,
74
- ContextProvider<State, null, BaseMetadata>,
75
- ReactContext<StateHook<State, StateSetter<State>, BaseMetadata> | null>
76
- ];
77
- <State, Metadata extends BaseMetadata | unknown, ActionsConfig extends ActionCollectionConfig<State, Metadata> | null | {}, PublicStateMutator = keyof ActionsConfig extends never | undefined ? StateSetter<State> : ActionCollectionResult<State, Metadata, NonNullable<ActionsConfig>>>(value: State | (() => State), args: {
145
+ /**
146
+ * @description Creates a highly granular React context with its associated provider and state hook.
147
+ * @param value Initial state value or initializer function.
148
+ * @returns An object containing:
149
+ * - **`use`** — A custom hook to read and mutate the context state.
150
+ * Supports selectors for granular subscriptions and returns `[state, stateMutator, metadata]`.
151
+ * - **`Provider`** — A React component that provides the context to its descendants.
152
+ * It accepts an optional initial value and `onCreated` callback.
153
+ * - **`Context`** — The raw React `Context` object for advanced usage, such as integration with
154
+ * external tools or non-React consumers.
155
+ */
156
+ <State>(value: State | (() => State)): {
157
+ use: ContextHook<State, React.Dispatch<React.SetStateAction<State>>, BaseMetadata>;
158
+ Provider: ContextProvider<State, null, BaseMetadata>;
159
+ Context: ReactContext<ContextHook<State, React.Dispatch<React.SetStateAction<State>>, BaseMetadata> | null>;
160
+ };
161
+ /**
162
+ * @description Creates a highly granular React context with its associated provider and state hook.
163
+ * @param value Initial state value or initializer function.
164
+ * @param args Additional configuration for the context.
165
+ * @param args.name Optional name for debugging purposes.
166
+ * @param args.metadata Optional non-reactive metadata associated with the state.
167
+ * @param args.callbacks Optional lifecycle callbacks for the context.
168
+ * @param args.actions Optional actions to restrict state mutations [if provided `setState` will be nullified].
169
+ * @returns An object containing:
170
+ * - **`use`** — A custom hook to read and mutate the context state.
171
+ * Supports selectors for granular subscriptions and returns `[state, stateMutator, metadata]`.
172
+ * - **`Provider`** — A React component that provides the context to its descendants.
173
+ * It accepts an optional initial value and `onCreated` callback.
174
+ * - **`Context`** — The raw React `Context` object for advanced usage, such as integration with
175
+ * external tools or non-React consumers.
176
+ */
177
+ <State, Metadata extends BaseMetadata, ActionsConfig extends ActionCollectionConfig<State, Metadata> | null | {}, PublicStateMutator = keyof ActionsConfig extends never | undefined ? React.Dispatch<React.SetStateAction<State>> : ActionCollectionResult<State, Metadata, NonNullable<ActionsConfig>>>(value: State | (() => State), args: {
78
178
  name?: string;
79
179
  metadata?: Metadata | (() => Metadata);
80
180
  callbacks?: GlobalStoreCallbacks<State, Metadata> & {
81
181
  onUnMount?: () => void;
82
182
  };
83
183
  actions?: ActionsConfig;
84
- }): [
85
- ContextHook<State, PublicStateMutator, Metadata>,
86
- ContextProvider<State, PublicStateMutator, Metadata>,
87
- ReactContext<StateHook<State, PublicStateMutator, Metadata> | null>
88
- ];
89
- <State, Metadata extends BaseMetadata | unknown, ActionsConfig extends ActionCollectionConfig<State, Metadata>>(value: State | (() => State), args: {
184
+ }): {
185
+ use: ContextHook<State, PublicStateMutator, Metadata>;
186
+ Provider: ContextProvider<State, PublicStateMutator, Metadata>;
187
+ Context: ReactContext<ContextHook<State, PublicStateMutator, Metadata> | null>;
188
+ };
189
+ /**
190
+ * @description Creates a highly granular React context with its associated provider and state hook.
191
+ * @param value Initial state value or initializer function.
192
+ * @param args Additional configuration for the context.
193
+ * @param args.name Optional name for debugging purposes.
194
+ * @param args.metadata Optional non-reactive metadata associated with the state.
195
+ * @param args.callbacks Optional lifecycle callbacks for the context.
196
+ * @param args.actions Optional actions to restrict state mutations [if provided `setState` will be nullified].
197
+ * @returns An object containing:
198
+ * - **`use`** — A custom hook to read and mutate the context state.
199
+ * Supports selectors for granular subscriptions and returns `[state, stateMutator, metadata]`.
200
+ * - **`Provider`** — A React component that provides the context to its descendants.
201
+ * It accepts an optional initial value and `onCreated` callback.
202
+ * - **`Context`** — The raw React `Context` object for advanced usage, such as integration with
203
+ * external tools or non-React consumers.
204
+ */
205
+ <State, Metadata extends BaseMetadata, ActionsConfig extends ActionCollectionConfig<State, Metadata>>(value: State | (() => State), args: {
90
206
  name?: string;
91
207
  metadata?: Metadata | (() => Metadata);
92
208
  callbacks?: GlobalStoreCallbacks<State, Metadata> & {
93
209
  onUnMount?: () => void;
94
210
  };
95
211
  actions: ActionsConfig;
96
- }): [
97
- ContextHook<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata>,
98
- ContextProvider<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata>,
99
- ReactContext<StateHook<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata> | null>
100
- ];
212
+ }): {
213
+ use: ContextHook<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata>;
214
+ Provider: ContextProvider<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata>;
215
+ Context: ReactContext<ContextHook<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata> | null>;
216
+ };
101
217
  }
218
+ /**
219
+ * @description Creates a highly granular React context with its associated provider and state hook.
220
+ * Unlike the native `React.createContext`, this version provides fine-grained reactivity and supports
221
+ * state selection, metadata handling, and optional custom actions for controlled mutations.
222
+ *
223
+ * Components using the generated hook only re-render when the selected part of the state changes,
224
+ * making it efficient for large or deeply nested state trees.
225
+ */
102
226
  export declare const createContext: CreateContext;
103
- export type InferContextType<Provider extends ContextProvider<any, any, any>> = ReturnType<Provider['makeProviderWrapper']>['context']['current'];
227
+ /**
228
+ * @description Infers the context API type
229
+ *
230
+ * @example
231
+ * ```ts
232
+ * const counter = createContext(0);
233
+ *
234
+ * type CounterContextApi = InferContextApi<typeof counter.Context>;
235
+ *
236
+ * // Equivalent to:
237
+ * ContextApi<number, React.Dispatch<React.SetStateAction<number>>, BaseMetadata>;
238
+ * ```
239
+ */
240
+ export type InferContextApi<Context extends ReactContext<ContextHook<any, any, any> | null>> = NonNullable<React.ContextType<Context>> extends ContextHook<infer State, infer StateMutator, infer Metadata> ? ContextApi<State, StateMutator extends AnyFunction ? null : StateMutator, Metadata> : never;
104
241
  export default createContext;
package/createContext.js CHANGED
@@ -1 +1 @@
1
- var e,t;e=this,t=(e,t,r,o)=>(()=>{"use strict";var n={155:t=>{t.exports=e},506:e=>{e.exports=t},639:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createContext=void 0;var o=r(155),n=r(778),a=r(506),i=r(773);t.createContext=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.createContext)(null),u=function(u){var s=u.children,l=u.value,c=u.onCreated,f=(0,o.useMemo)((function(){var r,o=function(){return(0,a.isFunction)(e)?e():e},u=(0,i.isNil)(l)?o():(0,a.isFunction)(l)?l(o()):l,s=new n.GlobalStore(u,Object.assign(Object.assign({},t),{metadata:null!==(r=(0,a.isFunction)(t.metadata)?t.metadata():t.metadata)&&void 0!==r?r:{}})),c=s.getHook();return{store:s,parentHook:c}}),[]),v=f.store,d=f.parentHook;return(0,o.useEffect)((function(){return function(){var e,t,r,o;null===(t=null===(e=v.callbacks)||void 0===e?void 0:e.onUnMount)||void 0===t||t.call(e),null===(o=(r=v).__onUnMountContext)||void 0===o||o.call(r,v,d),v.dispose()}}),[v,d]),null==c||c(v.getConfigCallbackParam()),(0,o.createElement)(r.Provider,{value:d},s)},s=function(){var e=(0,o.useContext)(r);if(!e)throw new Error("ContextHook must be used within a ContextProvider");return e.apply(void 0,arguments)};s.createSelectorHook=function(e,t){return function(){var n=(0,o.useContext)(r);if((0,i.isNil)(n))throw new Error("SelectorHook must be used within a ContextProvider");var a=(0,o.useRef)(e);a.current=e;var u=(0,o.useMemo)((function(){return(0,i.isNil)(e)?n:n.createSelectorHook((function(){return a.current.apply(a,arguments)}),t)}),[n]);return(0,o.useEffect)((function(){return function(){null==u||u.dispose()}}),[u]),u.apply(void 0,arguments)}};var l=function(){var e=(0,o.useContext)(r);if((0,i.isNil)(e))throw new Error("useStateControls must be used within a ContextProvider");return e.stateControls()},c=function(e,t){var n=(0,o.useContext)(r);if((0,i.isNil)(n))throw new Error("useObservableBuilder must be used within a ContextProvider");return n.createObservable(e,t)};return s.stateControls=function(){return[l,c]},u.makeProviderWrapper=function(e){var t={current:void 0};return{wrapper:function(r){var n=r.children;return(0,o.createElement)(u,{value:null==e?void 0:e.value,onCreated:function(r){var o;t.current=r,null===(o=null==e?void 0:e.onCreated)||void 0===o||o.call(e,r)}},n)},context:t}},[s,u,r]},t.default=t.createContext},773:e=>{e.exports=r},778:e=>{e.exports=o}},a={};return function e(t){var r=a[t];if(void 0!==r)return r.exports;var o=a[t]={exports:{}};return n[t](o,o.exports,e),o.exports}(639)})(),"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("json-storage-formatter/isFunction"),require("json-storage-formatter/isNil"),require("./GlobalStore.js")):"function"==typeof define&&define.amd?define(["react","json-storage-formatter/isFunction","json-storage-formatter/isNil","./GlobalStore.js"],t):"object"==typeof exports?exports["react-hooks-global-states"]=t(require("react"),require("json-storage-formatter/isFunction"),require("json-storage-formatter/isNil"),require("./GlobalStore.js")):e["react-hooks-global-states"]=t(e.react,e["json-storage-formatter/isFunction"],e["json-storage-formatter/isNil"],e["./GlobalStore.js"]);
1
+ var e,t;e=this,t=(e,t,r,o)=>(()=>{"use strict";var n={155:t=>{t.exports=e},506:e=>{e.exports=t},639:(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createContext=void 0;var o=r(155),n=r(778),a=r(506),i=r(773);t.createContext=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=(0,o.createContext)(null),u=function(u){var s=u.children,l=u.value,c=u.onCreated,f=(0,o.useMemo)((function(){var r,o=function(){return(0,a.isFunction)(e)?e():e},u=(0,i.isNil)(l)?o():(0,a.isFunction)(l)?l(o()):l;return new n.GlobalStore(u,Object.assign(Object.assign({},t),{metadata:null!==(r=(0,a.isFunction)(t.metadata)?t.metadata():t.metadata)&&void 0!==r?r:{}}))}),[]);return(0,o.useEffect)((function(){return function(){var e,t,r,o;null===(t=null===(e=f.callbacks)||void 0===e?void 0:e.onUnMount)||void 0===t||t.call(e,f),null===(o=(r=f).__onUnMountContext)||void 0===o||o.call(r,f),f.dispose()}}),[f]),null==c||c(f.getConfigCallbackParam()),(0,o.createElement)(r.Provider,{value:f.use},s)},s={makeProviderWrapper:function(e){var t={current:void 0};return{wrapper:function(r){var n=r.children;return(0,o.createElement)(u,{value:null==e?void 0:e.value,onCreated:function(r){var o;t.current=r,null===(o=null==e?void 0:e.onCreated)||void 0===o||o.call(e,r)}},n)},context:t}}},l=function(){var e=(0,o.useContext)(r);if(!e)throw new Error("use hook must be used within a ContextProvider");return e.apply(void 0,arguments)},c={createSelectorHook:function(e,t){return function(){var n=(0,o.useContext)(r);if((0,i.isNil)(n))throw new Error("SelectorHook must be used within a ContextProvider");var a=(0,o.useRef)(e);a.current=e;var u=(0,o.useMemo)((function(){return n.createSelectorHook((function(){return a.current.apply(a,arguments)}),t)}),[n]);return(0,o.useEffect)((function(){return function(){null==u||u.dispose()}}),[u]),u.apply(void 0,arguments)}},api:function(){var e=(0,o.useContext)(r);if(!e)throw new Error("api hook must be used within a ContextProvider");return e}};return Object.assign(u,s),Object.assign(l,c),{use:l,Provider:u,Context:r}},t.default=t.createContext},773:e=>{e.exports=r},778:e=>{e.exports=o}},a={};return function e(t){var r=a[t];if(void 0!==r)return r.exports;var o=a[t]={exports:{}};return n[t](o,o.exports,e),o.exports}(639)})(),"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("json-storage-formatter/isFunction"),require("json-storage-formatter/isNil"),require("./GlobalStore.js")):"function"==typeof define&&define.amd?define(["react","json-storage-formatter/isFunction","json-storage-formatter/isNil","./GlobalStore.js"],t):"object"==typeof exports?exports["react-hooks-global-states"]=t(require("react"),require("json-storage-formatter/isFunction"),require("json-storage-formatter/isNil"),require("./GlobalStore.js")):e["react-hooks-global-states"]=t(e.react,e["json-storage-formatter/isFunction"],e["json-storage-formatter/isNil"],e["./GlobalStore.js"]);
@@ -1,19 +1,145 @@
1
- import type { ActionCollectionConfig, StateSetter, ActionCollectionResult, StateHook, BaseMetadata, GlobalStoreCallbacks } from './types';
1
+ import type { ActionCollectionConfig, ActionCollectionResult, StateHook, BaseMetadata, GlobalStoreCallbacks } from './types';
2
2
  export interface CreateGlobalState {
3
- <State>(state: State): StateHook<State, StateSetter<State>, BaseMetadata>;
4
- <State, Metadata extends BaseMetadata | unknown, ActionsConfig extends ActionCollectionConfig<State, Metadata> | null | {}, PublicStateMutator = keyof ActionsConfig extends never | undefined ? StateSetter<State> : ActionCollectionResult<State, Metadata, NonNullable<ActionsConfig>>>(state: State, args: {
3
+ /**
4
+ * Creates a global state hook.
5
+ * @param state initial state value
6
+ * @returns a state hook for your components
7
+ * @example
8
+ * const useCounter = createGlobalState(0);
9
+ *
10
+ * function Counter() {
11
+ * const [count, setCount] = useCounter();
12
+ * return (
13
+ * <div>
14
+ * <p>Count: {count}</p>
15
+ * <button onClick={() =>
16
+ * setCount(prev => prev + 1)
17
+ * }>Increment</button>
18
+ * </div>
19
+ * );
20
+ * }
21
+ */
22
+ <State, StateDispatch = React.Dispatch<React.SetStateAction<State>>>(state: State): StateHook<State, StateDispatch, StateDispatch, BaseMetadata>;
23
+ /**
24
+ * Creates a global state hook that you can use across your application
25
+ * @param state initial state value
26
+ * @param args additional configuration for the global state
27
+ * @param args.name optional name for debugging purposes
28
+ * @param args.metadata optional non-reactive metadata associated with the state
29
+ * @param args.callbacks optional lifecycle callbacks for the global state
30
+ * @param args.actions optional actions to restrict state mutations [if provided `setState` will be nullified]
31
+ * @returns a state hook that you can use in your components
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * const useCounter = createGlobalState(0, {
36
+ * actions: {
37
+ * increase() {
38
+ * return ({ setState }) => {
39
+ * setState((c) => c + 1);
40
+ * };
41
+ * },
42
+ * decrease(amount: number) {
43
+ * return ({ setState }) => {
44
+ * setState((c) => c - amount);
45
+ * };
46
+ * },
47
+ * },
48
+ * });
49
+ *
50
+ * function Counter() {
51
+ * const [count, {
52
+ * increase,
53
+ * decrease
54
+ * }] = useCounter();
55
+ *
56
+ * return (
57
+ * <div>
58
+ * <p>Count: {count}</p>
59
+ * <button onClick={increase}>
60
+ * Increment
61
+ * </button>
62
+ * <button onClick={() => {
63
+ * decrease(1);
64
+ * }}>
65
+ * Decrement
66
+ * </button>
67
+ * </div>
68
+ * );
69
+ * }
70
+ * ```
71
+ */
72
+ <State, Metadata extends BaseMetadata, ActionsConfig extends ActionCollectionConfig<State, Metadata> | null | {}, PublicStateMutator = keyof ActionsConfig extends never | undefined ? React.Dispatch<React.SetStateAction<State>> : ActionCollectionResult<State, Metadata, NonNullable<ActionsConfig>>, StateDispatch = React.Dispatch<React.SetStateAction<State>>>(state: State, args: {
5
73
  name?: string;
6
74
  metadata?: Metadata;
7
75
  callbacks?: GlobalStoreCallbacks<State, Metadata>;
8
76
  actions?: ActionsConfig;
9
- }): StateHook<State, PublicStateMutator, Metadata>;
10
- <State, Metadata extends BaseMetadata | unknown, ActionsConfig extends ActionCollectionConfig<State, Metadata>>(state: State, args: {
77
+ }): StateHook<State, StateDispatch, PublicStateMutator, Metadata>;
78
+ /**
79
+ * Creates a global state hook that you can use across your application
80
+ * @param state initial state value
81
+ * @param args additional configuration for the global state
82
+ * @param args.name optional name for debugging purposes
83
+ * @param args.metadata optional non-reactive metadata associated with the state
84
+ * @param args.callbacks optional lifecycle callbacks for the global state
85
+ * @param args.actions optional actions to restrict state mutations [if provided `setState` will be nullified]
86
+ * @returns a state hook that you can use in your components
87
+ *
88
+ * @example
89
+ * ```tsx
90
+ * const useCounter = createGlobalState(0, {
91
+ * actions: {
92
+ * increase() {
93
+ * return ({ setState }) => {
94
+ * setState((c) => c + 1);
95
+ * };
96
+ * },
97
+ * decrease(amount: number) {
98
+ * return ({ setState }) => {
99
+ * setState((c) => c - amount);
100
+ * };
101
+ * },
102
+ * },
103
+ * });
104
+ *
105
+ * function Counter() {
106
+ * const [count, {
107
+ * increase,
108
+ * decrease
109
+ * }] = useCounter();
110
+ *
111
+ * return (
112
+ * <div>
113
+ * <p>Count: {count}</p>
114
+ * <button onClick={increase}>
115
+ * Increment
116
+ * </button>
117
+ * <button onClick={() => {
118
+ * decrease(1);
119
+ * }}>
120
+ * Decrement
121
+ * </button>
122
+ * </div>
123
+ * );
124
+ * }
125
+ * ```
126
+ */
127
+ <State, Metadata extends BaseMetadata, ActionsConfig extends ActionCollectionConfig<State, Metadata>, StateDispatch = React.Dispatch<React.SetStateAction<State>>>(state: State, args: {
11
128
  name?: string;
12
129
  metadata?: Metadata;
13
130
  callbacks?: GlobalStoreCallbacks<State, Metadata>;
14
131
  actions: ActionsConfig;
15
- }): StateHook<State, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata>;
132
+ }): StateHook<State, StateDispatch, ActionCollectionResult<State, Metadata, ActionsConfig>, Metadata>;
16
133
  }
134
+ /**
135
+ * Creates a global state hook
136
+ */
17
137
  export declare const createGlobalState: CreateGlobalState;
18
- export type InferActionsType<Hook extends StateHook<any, any, any>> = ReturnType<Hook['stateControls']>['1'];
19
- export default createGlobalState;
138
+ /**
139
+ * Infers the actions type from a StateHook
140
+ * @example
141
+ * ```ts
142
+ * type CounterActions = InferActionsType<typeof useCounter>;
143
+ * ```
144
+ */
145
+ export type InferActionsType<Hook extends StateHook<any, any, any, any>> = ReturnType<Hook['actions']>['1'];
@@ -1 +1 @@
1
- var e;e=e=>(()=>{"use strict";var t={778:t=>{t.exports=e},840:(e,t,o)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createGlobalState=void 0;var r=o(778);t.createGlobalState=function(e,t){return new r.GlobalStore(e,t).getHook()},t.default=t.createGlobalState}},o={};return function e(r){var a=o[r];if(void 0!==a)return a.exports;var l=o[r]={exports:{}};return t[r](l,l.exports,e),l.exports}(840)})(),"object"==typeof exports&&"object"==typeof module?module.exports=e(require("./GlobalStore.js")):"function"==typeof define&&define.amd?define(["./GlobalStore.js"],e):"object"==typeof exports?exports["react-hooks-global-states"]=e(require("./GlobalStore.js")):this["react-hooks-global-states"]=e(this["./GlobalStore.js"]);
1
+ var e;e=e=>(()=>{"use strict";var t={778:t=>{t.exports=e}},r={};function o(e){var a=r[e];if(void 0!==a)return a.exports;var s=r[e]={exports:{}};return t[e](s,s.exports,o),s.exports}var a={};return(()=>{var e=a;Object.defineProperty(e,"__esModule",{value:!0}),e.createGlobalState=void 0;var t=o(778);e.createGlobalState=function(){for(var e=arguments.length,r=new Array(e),o=0;o<e;o++)r[o]=arguments[o];var a=r[0],s=r[1];return new t.GlobalStore(a,s).use}})(),a})(),"object"==typeof exports&&"object"==typeof module?module.exports=e(require("./GlobalStore.js")):"function"==typeof define&&define.amd?define(["./GlobalStore.js"],e):"object"==typeof exports?exports["react-hooks-global-states"]=e(require("./GlobalStore.js")):this["react-hooks-global-states"]=e(this["./GlobalStore.js"]);
package/index.d.ts CHANGED
@@ -1,12 +1,9 @@
1
- export { StateSetter, HookExtensions, ObservableFragment, MetadataSetter, StateChanges, StoreTools, ActionCollectionResult, GlobalStoreCallbacks, UseHookConfig, UnsubscribeCallback, SubscribeCallbackConfig, SubscribeCallback, StateGetter, BaseMetadata, MetadataGetter, CustomGlobalHookBuilderParams, SelectorCallback, SubscriberParameters, SubscriptionCallback, StateHook, ActionCollectionConfig, } from './types';
1
+ export { StateApi as HookExtensions, ObservableFragment, MetadataSetter, StateChanges, StoreTools, ActionCollectionResult, GlobalStoreCallbacks, UseHookConfig, UnsubscribeCallback, SubscribeCallbackConfig, SubscribeCallback, BaseMetadata, MetadataGetter, CustomGlobalHookBuilderParams, SelectorCallback, SubscriberParameters, SubscriptionCallback, StateHook, ActionCollectionConfig, } from './types';
2
2
  export { GlobalStore } from './GlobalStore';
3
3
  export { GlobalStoreAbstract } from './GlobalStoreAbstract';
4
4
  export { createGlobalState, type InferActionsType } from './createGlobalState';
5
- export { createCustomGlobalState } from './createCustomGlobalState';
6
5
  export { shallowCompare } from './shallowCompare';
7
6
  export { uniqueId } from './uniqueId';
8
7
  export { throwWrongKeyOnActionCollectionConfig } from './throwWrongKeyOnActionCollectionConfig';
9
8
  export { isRecord } from './isRecord';
10
- export { useStableState } from './useStableState';
11
- export { type Context, type ContextProvider, type ContextHook, type CreateContext, type InferContextType, createContext, } from './createContext';
12
- export { generateStackHash } from './generateStackHash';
9
+ export { type ContextApi as Context, type ContextProvider, type ContextHook, type CreateContext, type InferContextApi as InferContextType, createContext, } from './createContext';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-hooks-global-states",
3
- "version": "10.2.0",
3
+ "version": "11.0.0-beta.0",
4
4
  "description": "This is a package to easily handling global-state across your react-components using hooks.",
5
5
  "main": "./bundle.js",
6
6
  "types": "./index.d.ts",
@@ -26,11 +26,6 @@
26
26
  "require": "./GlobalStoreAbstract.js",
27
27
  "types": "./GlobalStoreAbstract.d.ts"
28
28
  },
29
- "./createCustomGlobalState": {
30
- "import": "./createCustomGlobalState.js",
31
- "require": "./createCustomGlobalState.js",
32
- "types": "./createCustomGlobalState.d.ts"
33
- },
34
29
  "./createGlobalState": {
35
30
  "import": "./createGlobalState.js",
36
31
  "require": "./createGlobalState.js",
@@ -60,16 +55,6 @@
60
55
  "import": "./uniqueId.js",
61
56
  "require": "./uniqueId.js",
62
57
  "types": "./uniqueId.d.ts"
63
- },
64
- "./useStableState": {
65
- "import": "./useStableState.js",
66
- "require": "./useStableState.js",
67
- "types": "./useStableState.d.ts"
68
- },
69
- "./generateStackHash": {
70
- "import": "./generateStackHash.js",
71
- "require": "./generateStackHash.js",
72
- "types": "./generateStackHash.d.ts"
73
58
  }
74
59
  },
75
60
  "files": [
@@ -77,7 +62,8 @@
77
62
  "*.d.ts"
78
63
  ],
79
64
  "scripts": {
80
- "test:debug": "node --inspect-brk node_modules/.bin/jest --watch --runInBand",
65
+ "format": "prettier --write .",
66
+ "test-debug": "node --inspect-brk node_modules/.bin/jest --runInBand --detectOpenHandles",
81
67
  "test:quick": "jest --maxWorkers=4 -c --no-watchman -u",
82
68
  "test:coverage": "jest --maxWorkers=4 -c --colors --no-watchman --verbose --coverage",
83
69
  "build": "yarn clean && webpack --config webpack.config.js",
@@ -137,6 +123,7 @@
137
123
  "jest": "^29.7.0",
138
124
  "jest-environment-jsdom": "^30.0.4",
139
125
  "json-storage-formatter": "^2.0.9",
126
+ "prettier": "^3.6.2",
140
127
  "react": "^18.2.0",
141
128
  "react-dom": "^18.2.0",
142
129
  "ts-jest": "^29.1.1",
@@ -1,13 +1,52 @@
1
1
  /**
2
- * Returns true if the two values are equal.
2
+ * @description It performs a shallow comparison of the values.
3
+ * @param value1 - The first value to compare.
4
+ * @param value2 - The second value to compare.
5
+ * @returns True if the values are equal, false otherwise.
3
6
  */
4
7
  export declare const shallowCompare: <T>(value1: T, value2: T) => boolean;
5
8
  export declare const isArray: (value: unknown) => value is unknown[];
6
9
  export declare const isMap: (value: unknown) => value is Map<unknown, unknown>;
7
10
  export declare const isSet: (value: unknown) => value is Set<unknown>;
11
+ /**
12
+ * @description Determines whether a simple equality check (using `===`) is sufficient
13
+ * to compare the provided values. This helps decide when a deep equality check
14
+ * is unnecessary or inefficient.
15
+ *
16
+ * Simple equality checks are considered valid when:
17
+ * - The values have different types (comparison will trivially return false)
18
+ * - Either value is null or undefined
19
+ * - Both values are primitive types (string, number, boolean, symbol, bigint)
20
+ * - Both values are Date objects
21
+ * - Both values are functions
22
+ *
23
+ * @param value1 - The first value to compare.
24
+ * @param value2 - The second value to compare.
25
+ * @returns `true` if a simple `===` check is sufficient, `false` if a deep comparison may be required.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * canCheckSimpleEquality(42, 42); // true (primitive numbers)
30
+ * canCheckSimpleEquality({ a: 1 }, { a: 1 }); // false (objects)
31
+ * canCheckSimpleEquality([1, 2], [1, 2]); // false (arrays)
32
+ * canCheckSimpleEquality('a', 1); // true (different types, shallow check enough)
33
+ * ```
34
+ */
8
35
  export declare const canCheckSimpleEquality: (value1: unknown, value2: unknown) => boolean;
9
- export declare const isEqualArray: <T>(array1: T[], array2: T[]) => boolean;
10
- export declare const isEqualMap: <K, V>(map1: Map<K, V>, map2: Map<K, V>) => boolean;
11
- export declare const isEqualSet: <T>(set1: Set<T>, set2: Set<T>) => boolean;
36
+ /**
37
+ * @description Performs a shallow comparison between two arrays.
38
+ */
39
+ export declare const isEqualArray: <T>(array1: T[], array2: T[]) => array1 is T[];
40
+ /**
41
+ * @description Performs a shallow comparison between two maps.
42
+ */
43
+ export declare const isEqualMap: <K, V>(map1: Map<K, V>, map2: Map<K, V>) => map1 is Map<K, V>;
44
+ /**
45
+ * @description Performs a shallow comparison between two sets.
46
+ */
47
+ export declare const isEqualSet: <T>(set1: Set<T>, set2: Set<T>) => set1 is Set<T>;
48
+ /**
49
+ * @description Performs a shallow comparison between two objects.
50
+ */
12
51
  export declare const isEqualObject: <T extends Record<string, unknown>>(value1: T, value2: T) => boolean;
13
52
  export default shallowCompare;