@adimm/x-injection-reactjs 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,18 +1,16 @@
1
1
  import * as react from 'react';
2
- import { ProviderModuleOptions, IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule } from '@adimm/x-injection';
2
+ import react__default from 'react';
3
+ import { IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule, ProviderModuleOptions, CloneParams } from '@adimm/x-injection';
3
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
5
 
5
6
  interface IComponentProviderModuleNaked extends IComponentProviderModule {
6
7
  /** Indicates if this module has been initialized by a React Component or not. */
7
8
  _initializedFromComponent: boolean;
8
- /** The {@link ProviderModuleOptions | options} with which the module has been originally initialized. */
9
- _initialOptions: ProviderModuleOptions;
10
9
  /**
11
- * Instantiate a new {@link IComponentProviderModule} which will be supplied to the React Component.
12
- *
13
- * All the `providers` will be injected into a `singleton` scope.
10
+ * It is used internally by the `ProviderModule` to create a new cloned
11
+ * module which will be consumed only by that specific component instance.
14
12
  */
15
- _convertToContextualizedComponentInstance(): IComponentProviderModule;
13
+ _createContextualizedComponentInstance(): IComponentProviderModule;
16
14
  }
17
15
 
18
16
  interface IComponentProviderModule extends IProviderModule {
@@ -30,214 +28,140 @@ interface IComponentProviderModule extends IProviderModule {
30
28
  dispose(): void;
31
29
  }
32
30
 
33
- interface UseInjectSharedOptions {
34
- }
31
+ type PropsWithModule<P extends Record<string, any>> = P & {
32
+ /**
33
+ * The {@link IComponentProviderModule | Module} which this component should consume.
34
+ *
35
+ * **Note:** _You can easily override this in your unit tests to provide a module having mocked providers_
36
+ * _without the need to create a new mocked component by using the composable `ProvideModule` method._
37
+ */
38
+ module?: IComponentProviderModule;
39
+ };
35
40
 
36
- /**
37
- * The `React.Context` value to be provided to a `React.Provider`.
38
- *
39
- * Its default value is a reference to the {@link AppModule}.
40
- */
41
- declare const REACT_X_INJECTION_CONTEXT: react.Context<{
42
- ctx: IComponentProviderModule;
43
- }>;
44
- declare const REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT: react.Context<Map<string, IComponentProviderModule>>;
41
+ declare const REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT: react.Context<IComponentProviderModule>;
45
42
 
46
43
  /**
47
- * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.
44
+ * Low-level hook which can be used to resolve a single dependency from the current
45
+ * context module.
48
46
  *
49
- * **Note:** _By using this hook, the dependency will be injected on each re-render process._
50
- * _If you need to inject the dependency only once, you must use the `useInject` hook._
51
- * _It basically acts like a `Transient` scope, ensuring that a new dependency is injected on each re-render._
47
+ * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_
48
+ * _`hookFactory` method to compose a custom hook._
52
49
  *
53
50
  * @param provider The {@link ProviderToken}.
54
- * @param options See {@link UseInjectSharedOptions}.
55
- * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.
51
+ * @param options See {@link UseInjectOptions}.
52
+ * @returns The resolved {@link T | dependency}.
56
53
  */
57
- declare function useInjectOnRender<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
58
- type UseInjectOptions = UseInjectSharedOptions & {
54
+ declare function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
55
+ type UseInjectOptions = {
59
56
  /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */
60
57
  isOptional?: boolean;
61
58
  };
62
59
 
63
60
  /**
64
- * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.
65
- *
66
- * **Note:** _By using this hook, the dependency will be injected only once after the first component mount process._
67
- * _If you need to re-inject the dependency on each re-render, you must use the `useInjectOnRender` hook._
68
- * _It basically acts like a `Request` scope, ensuring that even a `Transient` dependency does not mutate during re-renders._
69
- *
70
- * @param provider The {@link ProviderToken}.
71
- * @param options See {@link UseInjectSharedOptions}.
72
- * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.
73
- */
74
- declare function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
75
-
76
- /**
77
- * Can be used to retrieve many resolved `dependencies` from the module container at once.
78
- *
79
- * **Note:** _By using this hook, the dependencies will be injected only once after the first component mount process._
80
- * _If you need to re-inject the dependencies on each re-render, you must use the `useInjectManyOnRender` hook._
81
- *
82
- * @param options See {@link UseInjectSharedOptions}.
83
- * @param deps Either one or more {@link ProviderToken}.
84
- * @returns Tuple containing the {@link D | dependencies}.
85
- */
86
- declare function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({ deps, options, }: {
87
- deps: [...(D | unknown[])];
88
- options?: UseInjectSharedOptions;
89
- }): ProviderModuleGetManySignature<D>;
90
-
91
- /**
92
- * Can be used to retrieve many resolved `dependencies` from the module container at once.
61
+ * Low-level hook which can be used to resolve multiple dependencies at once from the current
62
+ * context module.
93
63
  *
94
- * **Note:** _By using this hook, the dependencies will be injected on each re-render process._
95
- * _If you need to inject the dependencies only once, you must use the `useInjectMany` hook._
64
+ * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_
65
+ * _`hookFactory` method to compose a custom hook._
96
66
  *
97
- * @param options See {@link UseInjectSharedOptions}.
98
67
  * @param deps Either one or more {@link ProviderToken}.
99
68
  * @returns Tuple containing the {@link D | dependencies}.
100
69
  */
101
- declare function useInjectManyOnRender<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({ deps, }: {
102
- deps: [...(D | unknown[])];
103
- options?: UseInjectSharedOptions;
104
- }): ProviderModuleGetManySignature<D>;
105
-
106
- declare function useExposeComponentModuleContext(): void;
107
-
108
- /**
109
- * This is an **experimental** hook which can be used to make sure that a component will re-render when a children
110
- * exposes its internal context module.
111
- *
112
- * It works best with the `useInjectOnRender` hook, as it'll re-resolve all the required dependencies
113
- * of the injected ProviderToken.
114
- *
115
- * **Use it carefully as it may lead to unnecessary re-render cycles or it may even not work as expected!**
116
- * **It's safer to use the `TapIntoComponent` wrapper component with the `contextInstance` to manually inject the**
117
- * **contextualized dependencies of the children into a parent component service!**
118
- *
119
- * @experimental
120
- */
121
- declare function useRerenderOnChildrenModuleContextLoaded(): void;
122
-
123
- interface ModuleProviderProps {
124
- children?: React.ReactNode;
125
- render?: () => React.ReactNode;
126
- /** The {@link IComponentProviderModule | ComponentProviderModule} instance which must be accessible by this component. */
127
- module: IComponentProviderModule;
128
- /**
129
- * Provide an object containing the initialization {@link ProviderModuleConstructor | options} so the {@link ModuleProviderProps.module | module}
130
- * can be re-initialized when the component re-mounts _**(It'll happen only if it has been previously disposed!)**_.
131
- *
132
- * **Note:** _This is an advanced option and should be used only if you fully understand how the {@link ModuleProviderProps.module | module}_
133
- * _initialization process works!_
134
- * _For more details refer to the {@link https://adimarianmutu.github.io/x-injection/index.html | xInjection} offical docs._
135
- */
136
- tryReInitModuleOnMount?: ProviderModuleOptions;
137
- /**
138
- * When set to `true` it'll automatically dispose
139
- * the provided {@link ModuleProviderProps.module | module} during the
140
- * component `unmount` process.
141
- *
142
- * **Note:** _This is an advanced option and should be used only if you fully understand how the {@link ModuleProviderProps.module | module}_
143
- * _dispose process works!_
144
- * _For more details refer to the {@link https://adimarianmutu.github.io/x-injection/index.html | xInjection} offical docs._
145
- *
146
- * Defaults to `false`.
147
- */
148
- disposeModuleOnUnmount?: boolean;
149
- }
70
+ declare function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>(...deps: D | unknown[]): ProviderModuleGetManySignature<D>;
150
71
 
151
- declare function ModuleProvider({ children, render, module, tryReInitModuleOnMount, disposeModuleOnUnmount, }: ModuleProviderProps): react_jsx_runtime.JSX.Element;
72
+ /** Can be used to retrieve the {@link IComponentProviderModule} from the current context. */
73
+ declare function useComponentModule(): IComponentProviderModule;
152
74
 
153
75
  /** A superset of the {@link ProviderModule} used to integrate within a `React` component. */
154
76
  declare class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {
155
77
  protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];
156
- protected readonly _initialOptions: IComponentProviderModuleNaked['_initialOptions'];
157
78
  constructor(options: ProviderModuleOptions);
158
79
  toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
80
+ clone(options?: CloneParams): IComponentProviderModule;
159
81
  dispose(): void;
160
82
  /**
161
83
  * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**
162
84
  *
163
- * See {@link IComponentProviderModuleNaked._convertToContextualizedComponentInstance}.
85
+ * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.
164
86
  */
165
- protected _convertToContextualizedComponentInstance(): IComponentProviderModule;
87
+ protected _createContextualizedComponentInstance(): IComponentProviderModule;
166
88
  }
167
89
 
168
- interface TapIntoComponentContextProps {
169
- children: React.ReactNode;
170
- /**
171
- * A callback can be provided to fully get access to the `ProviderModule` of the component instance,
172
- * as long as the component is exposing it by using the `useExposeComponentModuleContext` hook.
173
- *
174
- * @param ctx A context map of modules.
175
- *
176
- * @example
177
- * ```tsx
178
- * function UserComponent(props: UserComponentProps) {
179
- * // This is required in order to correctly expose the ctx!
180
- * useExposeComponentModuleContext();
181
- *
182
- * const [userProfileSettings, userSecuritySettings] = useInjectMany({ deps: [UserProfileSettings, UserSecuritySettings] });
183
- *
184
- * return null;
185
- * }
186
- *
187
- * function UserPage(props: UserPageProps) {
188
- * return (
189
- * <TapIntoComponent
190
- * contextInstance={(ctx)) => ({
191
- * tryGet: UserComponentModule,
192
- * thenDo: (ctx) => {
193
- * const services = ctx.getMany(...);
194
- * }
195
- * })}>
196
- * <UserComponent {...props.userComponentProps} />
197
- * </TapIntoComponent>
198
- * );
199
- * }
200
- * ```
201
- *
202
- * **Or without the fluid syntax:**
203
- *
204
- * ```tsx
205
- * function UserPage(props: UserPageProps) {
206
- * return (
207
- * <TapIntoComponent
208
- * contextInstance={(ctxMap)) => {
209
- * const ctx = ctxMap.get(UserComponentModule.toString());
210
- * if (!ctx) return;
211
- *
212
- * const services = ctx.getMany(...);
213
- * }}>
214
- * <UserComponent {...props.userComponentProps} />
215
- * </TapIntoComponent>
216
- * );
217
- * }
218
- * ````
219
- */
220
- contextInstance?: (ctx: Map<string, IComponentProviderModule>) => void | WithComponentInstanceCtxFluidSyntax;
221
- }
222
- interface WithComponentInstanceCtxFluidSyntax {
223
- /** The {@link IComponentProviderModule | module} to look for in the `context map`. */
224
- tryGet: IComponentProviderModule;
225
- /**
226
- * Provide a callback which will be invoked when the `context map` has
227
- * the {@link tryGet | module} requested.
228
- *
229
- * @param module The contextualized instance of the {@link IComponentProviderModule} extracted from the children.
230
- */
231
- thenDo: (module: IComponentProviderModule) => void | Promise<void>;
232
- }
90
+ /**
91
+ * Can be used to easily provide a {@link module} to any component.
92
+ *
93
+ * @example
94
+ * ```tsx
95
+ * interface MyComponentProps {
96
+ * firstName: string;
97
+ * lastName: string;
98
+ * }
99
+ *
100
+ * export const MyComponent = provideModuleToComponent(
101
+ * MyComponentModule,
102
+ * ({ firstName, lastName }: MyComponentProps) => {
103
+ * const service = useInject(MyComponentService);
104
+ *
105
+ * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>
106
+ * }
107
+ * );
108
+ *
109
+ * function App() {
110
+ * return <MyComponent firstName={'John'} lastName={'Doe'} />;
111
+ * }
112
+ * ```
113
+ *
114
+ * @param module The {@link IComponentProviderModule | Module} which should be consumed by the {@link component}.
115
+ * @returns The provided {@link toComponent | Component}.
116
+ */
117
+ declare function provideModuleToComponent<P extends Record<string, any>, C extends ReactElementWithProviderModule<P> = ReactElementWithProviderModule<P>>(module: IComponentProviderModule, component: ReactElementWithProviderModule<P>): C;
118
+ type ReactElementWithProviderModule<P extends Record<string, any>> = (p: PropsWithModule<P>) => React.ReactNode;
233
119
 
234
120
  /**
235
- * This component is the standard way to "tap into" an instance of the component
236
- * in order to get access to its scoped module container and its _(exposed)_ dependencies _instances_.
121
+ * Can be used to easily provide a {@link module} to any component.
237
122
  *
238
- * @param contextInstance See {@link TapIntoComponentContextProps.contextInstance}.
239
- * @param exposed See {@link TapIntoComponentContextProps.exposed}.
123
+ * @example
124
+ * ```tsx
125
+ * interface MyComponentProps {
126
+ * firstName: string;
127
+ * lastName: string;
128
+ * }
129
+ *
130
+ * function MyComponent({ firstName, lastName }: MyComponentProps) {
131
+ * const service = useInject(MyComponentService);
132
+ *
133
+ * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>
134
+ * }
135
+ *
136
+ * function App() {
137
+ * return (
138
+ * <ProvideModule module={MyComponentModule}>
139
+ * <MyComponent firstName={'John'} lastName={'Doe'} />
140
+ * </ProvideModule>
141
+ * );
142
+ * }
143
+ * ```
144
+ *
145
+ * @param param0 See {@link ProvideModuleFunctionParams}.
146
+ * @returns The provided {@link toComponent | Component}.
240
147
  */
241
- declare function TapIntoComponent({ children, contextInstance }: TapIntoComponentContextProps): react_jsx_runtime.JSX.Element;
148
+ declare function ProvideModule({ module, children }: ProvideModuleFunctionParams): react_jsx_runtime.JSX.Element;
149
+ interface ProvideModuleFunctionParams {
150
+ /** The {@link IComponentProviderModule | Module} which should be consumed by the {@link children | component}. */
151
+ module: IComponentProviderModule;
152
+ children: react__default.ReactElement;
153
+ }
154
+
155
+ declare function hookFactory<P extends HookParams, D extends any[], T>({ use: hook, inject, }: HookFactoryParams<P, D, T>): (p: P) => T;
156
+ interface HookFactoryParams<P extends HookParams, D extends any[], T> {
157
+ use: HookWithProviderModuleDependencies<P, D, T>;
158
+ inject: ProviderToken[];
159
+ }
160
+ type HookWithProviderModuleDependencies<P extends HookParams, D extends any[], T> = (p: HookWithDeps<P, D>) => T;
161
+ type HookWithDeps<P extends HookParams, D extends any[]> = P & {
162
+ /** Array containing the resolved dependencies from the component context. */
163
+ deps: D;
164
+ };
165
+ type HookParams = Record<string, any> | void;
242
166
 
243
- export { ComponentProviderModule, type IComponentProviderModule, type IComponentProviderModuleNaked, ModuleProvider, REACT_X_INJECTION_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT, TapIntoComponent, type TapIntoComponentContextProps, type UseInjectOptions, type UseInjectSharedOptions, type WithComponentInstanceCtxFluidSyntax, useExposeComponentModuleContext, useInject, useInjectMany, useInjectManyOnRender, useInjectOnRender, useRerenderOnChildrenModuleContextLoaded };
167
+ export { ComponentProviderModule, type HookFactoryParams, type HookWithDeps, type HookWithProviderModuleDependencies, type IComponentProviderModule, type IComponentProviderModuleNaked, type PropsWithModule, ProvideModule, type ProvideModuleFunctionParams, REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT, type ReactElementWithProviderModule, type UseInjectOptions, hookFactory, provideModuleToComponent, useComponentModule, useInject, useInjectMany };