@adimm/x-injection-reactjs 0.2.4 → 0.3.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
@@ -120,7 +120,7 @@ If you prefer to use the `const Component = () => {}` syntax, then you must use
120
120
 
121
121
  ```tsx
122
122
  // The UserInfo component will correctly infer the interface of `UserInfoProps` automatically!
123
- export const UserInfo = provideModuleToComponent(UserComponentModule, ({ firstName, lastName }: UserInfoProps) => {
123
+ export const UserInfo = provideModuleToComponent<UserInfoProps>(UserComponentModule, ({ firstName, lastName }) => {
124
124
  const userService = useInject(UserService);
125
125
 
126
126
  userService.firstName = firstName;
@@ -263,7 +263,7 @@ export interface InputboxProps {
263
263
  initialValue: string;
264
264
  }
265
265
 
266
- export const Inputbox = provideModuleToComponent(InputboxModule, ({ initialValue }: InputboxProps) => {
266
+ export const Inputbox = provideModuleToComponent<InputboxProps>(InputboxModule, ({ initialValue }) => {
267
267
  const service = useInject(InputboxService);
268
268
  const [, setCurrentValue] = useState(initialValue);
269
269
  service.setStateValue = setCurrentValue;
@@ -304,7 +304,7 @@ export interface ListviewProps {
304
304
  items: any[];
305
305
  }
306
306
 
307
- export const Listview = provideModuleToComponent(ListviewModule, ({ items }: ListviewProps) => {
307
+ export const Listview = provideModuleToComponent<ListviewProps>(ListviewModule, ({ items }) => {
308
308
  const service = useInject(ListviewService);
309
309
 
310
310
  /* Remaining fancy implementation */
@@ -362,7 +362,7 @@ export interface DropdownProps {
362
362
  initialSelectedValue: number;
363
363
  }
364
364
 
365
- export const Dropdown = provideModuleToComponent(
365
+ export const Dropdown = provideModuleToComponent<DropdownProps>(
366
366
  ListviewModule,
367
367
  ({
368
368
  listviewProps,
@@ -370,7 +370,7 @@ export const Dropdown = provideModuleToComponent(
370
370
  // Here it is important that we get access to the contextualized module
371
371
  // so we can forward it to the `Listview` component!
372
372
  module,
373
- }: DropdownProps) => {
373
+ }) => {
374
374
  const service = useInject(DropdownService);
375
375
 
376
376
  /* Remaining fancy implementation */
@@ -437,14 +437,14 @@ export interface AutocompleteProps {
437
437
  currentText: string;
438
438
  }
439
439
 
440
- export const Autocomplete = provideModuleToComponent(
440
+ export const Autocomplete = provideModuleToComponent<AutocompleteProps>(
441
441
  AutocompleteModule,
442
442
  ({
443
443
  dropdownProps,
444
444
  currentText,
445
445
 
446
446
  module,
447
- }: AutocompleteProps) => {
447
+ }) => {
448
448
  const service = useInject(AutocompleteService);
449
449
 
450
450
  console.log(service.dropdownService.listviewService.items);
package/dist/index.cjs CHANGED
@@ -21,12 +21,12 @@ var e, t = Object.create, o = Object.defineProperty, r = Object.getOwnPropertyDe
21
21
  });
22
22
  })(c, {
23
23
  ComponentProviderModule: () => C,
24
- ProvideModule: () => q,
24
+ ProvideModule: () => _,
25
25
  REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT: () => p,
26
- hookFactory: () => R,
27
- provideModuleToComponent: () => I,
26
+ hookFactory: () => q,
27
+ provideModuleToComponent: () => z,
28
28
  useComponentModule: () => f,
29
- useInject: () => v,
29
+ useInject: () => h,
30
30
  useInjectMany: () => M
31
31
  }), module.exports = (e = c, a(o({}, "__esModule", {
32
32
  value: !0
@@ -38,7 +38,7 @@ function f() {
38
38
  return (0, m.useContext)(p);
39
39
  }
40
40
 
41
- function v(e, t) {
41
+ function h(e, t) {
42
42
  return f().get(e, t?.isOptional);
43
43
  }
44
44
 
@@ -46,27 +46,40 @@ function M(...e) {
46
46
  return f().getMany(...e);
47
47
  }
48
48
 
49
- s(f, "useComponentModule"), s(v, "useInject"), s(M, "useInjectMany");
49
+ s(f, "useComponentModule"), s(h, "useInject"), s(M, "useInjectMany");
50
50
 
51
- var h = require("@adimm/x-injection"), C = class e extends h.ProviderModule {
51
+ var v = require("@adimm/x-injection"), C = class e extends v.ProviderModule {
52
52
  static {
53
53
  s(this, "ComponentProviderModule");
54
54
  }
55
- _initializedFromComponent;
55
+ originalIdentifier;
56
+ hasContextualizedImports;
57
+ initializedFromComponent;
56
58
  constructor(e) {
57
- super(h.ProviderModuleHelpers.buildInternalConstructorParams({
59
+ const t = Symbol(`Component${e.identifier.description}`), o = !e.markAsGlobal && (e.contextualizeImports ?? !0), r = o ? new Map : void 0;
60
+ super(v.ProviderModuleHelpers.buildInternalConstructorParams({
58
61
  ...e,
59
- defaultScope: e.defaultScope ?? h.InjectionScope.Singleton,
60
- identifier: Symbol(`Component${e.identifier.description}`)
61
- })), this._initializedFromComponent = !1;
62
+ defaultScope: e.defaultScope ?? v.InjectionScope.Singleton,
63
+ identifier: t,
64
+ imports: o ? e.imports?.map((e => {
65
+ const n = "function" == typeof e ? e() : e;
66
+ return o ? () => {
67
+ const e = n._createContextualizedComponentInstance(t);
68
+ return r.set(n.originalIdentifier.toString(), e), e;
69
+ } : n;
70
+ })) : e.imports,
71
+ dynamicExports: s(((e, t) => o ? t.map((e => {
72
+ if (!(e instanceof v.ProviderModule)) return e;
73
+ return r.get(e.originalIdentifier.toString());
74
+ })) : t), "dynamicExports")
75
+ })), this.originalIdentifier = e.identifier, this.hasContextualizedImports = o,
76
+ this.initializedFromComponent = !1;
62
77
  }
63
78
  toNaked() {
64
79
  return this;
65
80
  }
66
81
  clone(t) {
67
- let o = [ ...this.providers ];
68
- t?.providersMap && (o = o.map((e => t.providersMap(e, this))));
69
- const r = new e(h.ProviderModuleHelpers.buildInternalConstructorParams({
82
+ const o = t, r = new e(v.ProviderModuleHelpers.buildInternalConstructorParams({
70
83
  isAppModule: this.isAppModule,
71
84
  markAsGlobal: this.isMarkedAsGlobal,
72
85
  identifier: Symbol(this.identifier.description.replace("Component", "")),
@@ -74,65 +87,68 @@ var h = require("@adimm/x-injection"), C = class e extends h.ProviderModule {
74
87
  dynamicExports: this.dynamicExports,
75
88
  onReady: this.onReady,
76
89
  onDispose: this.onDispose,
77
- importedProvidersMap: t?.importedProvidersMap,
90
+ contextualizeImports: this.hasContextualizedImports,
91
+ importedProvidersMap: this.importedProvidersMap,
78
92
  imports: [ ...this.imports ],
79
- providers: o,
80
- exports: [ ...this.exports ]
93
+ providers: [ ...this.providers ],
94
+ exports: [ ...this.exports ],
95
+ ...o
81
96
  }));
82
- return r._initializedFromComponent = this._initializedFromComponent, r;
97
+ return r.initializedFromComponent = this.initializedFromComponent, r;
83
98
  }
84
- dispose() {
85
- this._dispose();
99
+ async dispose() {
100
+ await super.dispose();
86
101
  }
87
- _createContextualizedComponentInstance() {
88
- if (this._initializedFromComponent) return this;
89
- const e = this.clone().toNaked();
90
- return e.identifier = Symbol(`Contextualized${e.identifier.description}`), e._initializedFromComponent = !0,
91
- e;
102
+ _createContextualizedComponentInstance(e) {
103
+ if (this.initializedFromComponent) return this;
104
+ const t = this.clone().toNaked();
105
+ return t.identifier = Symbol(`${e ? `[Parent:${e.description ?? "Unknown"}]` : ""}Contextualized${t.identifier.description}`),
106
+ t.initializedFromComponent = !0, t;
92
107
  }
93
- }, y = d(require("react"), 1), P = require("react"), b = require("react");
108
+ }, y = d(require("react"), 1), P = require("react"), x = require("react");
94
109
 
95
- function j(e) {
96
- const t = (0, b.useRef)(void 0), o = (0, b.useRef)(!1), r = (0, b.useRef)(!1), [, n] = (0,
97
- b.useState)(0);
98
- o.current && (r.current = !0), (0, b.useEffect)((() => (o.current || (t.current = e(),
110
+ function I(e) {
111
+ const t = (0, x.useRef)(void 0), o = (0, x.useRef)(!1), r = (0, x.useRef)(!1), [, n] = (0,
112
+ x.useState)(0);
113
+ o.current && (r.current = !0), (0, x.useEffect)((() => (o.current || (t.current = e(),
99
114
  o.current = !0), n((e => e + 1)), () => {
100
115
  r.current && t.current?.();
101
116
  })), []);
102
117
  }
103
118
 
104
- function _(e, t) {
119
+ function b(e, t) {
105
120
  const o = (0, P.useMemo)((() => {
106
121
  const o = (t ?? e).toNaked();
107
122
  return o.isMarkedAsGlobal ? o : o._createContextualizedComponentInstance();
108
123
  }), [ e, t ]);
109
- return j((() => () => {
124
+ return I((() => () => {
110
125
  o.dispose();
111
126
  })), o;
112
127
  }
113
128
 
114
- s(j, "useEffectOnce"), s(_, "useContextualizedModule");
129
+ s(I, "useEffectOnce"), s(b, "useContextualizedModule");
115
130
 
116
- var x = require("@adimm/x-injection");
131
+ var g, j = require("@adimm/x-injection");
117
132
 
118
- function E(e, t, o) {
119
- const r = {
120
- ...t
121
- };
122
- return ("object" == typeof e && "type" in e && (0, x.isFunction)(e.type) || (0,
123
- x.isFunction)(e)) && (r.module = o), r;
124
- }
125
-
126
- s(E, "forwardPropsWithModule");
133
+ !function(e) {
134
+ function t(e, t, o) {
135
+ const r = {
136
+ ...t
137
+ };
138
+ return ("object" == typeof e && "type" in e && (0, j.isFunction)(e.type) || (0,
139
+ j.isFunction)(e)) && (r.module = o), r;
140
+ }
141
+ s(t, "forwardPropsWithModule"), e.forwardPropsWithModule = t;
142
+ }(g || (g = {}));
127
143
 
128
- var O = y.default.memo(g);
144
+ var E = y.default.memo(O);
129
145
 
130
- function I(e, t) {
146
+ function z(e, t) {
131
147
  return o => {
132
- const r = _(e, o.module);
148
+ const r = b(e, o.module);
133
149
  return y.default.createElement(p.Provider, {
134
150
  value: r
135
- }, y.default.createElement(O, {
151
+ }, y.default.createElement(E, {
136
152
  module: r,
137
153
  componentProps: o,
138
154
  component: t
@@ -140,33 +156,33 @@ function I(e, t) {
140
156
  };
141
157
  }
142
158
 
143
- function g({module: e, component: t, componentProps: o}) {
144
- return y.default.createElement(y.default.Fragment, null, t(E(t, o, e)));
159
+ function O({module: e, component: t, componentProps: o}) {
160
+ return y.default.createElement(y.default.Fragment, null, t(g.forwardPropsWithModule(t, o, e)));
145
161
  }
146
162
 
147
- s(I, "provideModuleToComponent"), s(g, "_ComponentRenderer");
163
+ s(z, "provideModuleToComponent"), s(O, "_ComponentRenderer");
148
164
 
149
- var F = d(require("react"), 1);
165
+ var w = d(require("react"), 1);
150
166
 
151
- function q({module: e, children: t}) {
152
- const o = t.props ?? {}, r = _(e, o.module), n = (0, F.useMemo)((() => F.default.cloneElement(t, E(t, o, r))), [ o, r ]);
153
- return F.default.createElement(p.Provider, {
167
+ function _({module: e, children: t}) {
168
+ const o = t.props ?? {}, r = b(e, o.module), n = (0, w.useMemo)((() => w.default.cloneElement(t, g.forwardPropsWithModule(t, o, r))), [ o, r ]);
169
+ return w.default.createElement(p.Provider, {
154
170
  value: r
155
171
  }, n);
156
172
  }
157
173
 
158
- s(q, "ProvideModule");
174
+ s(_, "ProvideModule");
159
175
 
160
- var z = require("react"), S = require("@adimm/x-injection"), k = class e extends S.InjectionProviderModuleError {
176
+ var F = require("react"), S = require("@adimm/x-injection"), k = class e extends S.InjectionProviderModuleError {
161
177
  static {
162
178
  s(this, "InjectionHookFactoryError");
163
179
  }
164
180
  name=e.name;
165
181
  };
166
182
 
167
- function R({use: e, inject: t}) {
183
+ function q({use: e, inject: t}) {
168
184
  return o => {
169
- const r = f(), n = (0, z.useMemo)((() => {
185
+ const r = f(), n = (0, F.useMemo)((() => {
170
186
  if (0 === t.length) throw new k(r, "The 'deps' property array is missing!");
171
187
  return r.getMany(...t);
172
188
  }), [ t ]);
@@ -177,4 +193,4 @@ function R({use: e, inject: t}) {
177
193
  };
178
194
  }
179
195
 
180
- s(R, "hookFactory");//# sourceMappingURL=index.cjs.map
196
+ s(q, "hookFactory");//# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/react-context.ts","../src/core/hooks/use-component-module.ts","../src/core/hooks/use-inject.ts","../src/core/hooks/use-inject-many.ts","../src/core/component-provider-module.ts","../src/core/provide-module/provide-module.arrow-function.tsx","../src/helpers/hooks/use-contextualized-module.ts","../src/helpers/hooks/use-effect-once.ts","../src/helpers/forward-props-with-module.ts","../src/core/provide-module/provide-module.provider.tsx","../src/core/hook-factory.ts","../src/errors/hook-factory.ts"],"sourcesContent":["export * from './core';\nexport type * from './types';\n","import { AppModule } from '@adimm/x-injection';\nimport { createContext } from 'react';\n\nimport type { IComponentProviderModule } from '../types';\n\nexport const REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT = createContext<IComponentProviderModule>(AppModule as any);\n","import { useContext } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/** Can be used to retrieve the {@link IComponentProviderModule} from the current context. */\nexport function useComponentModule(): IComponentProviderModule {\n return useContext(REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT);\n}\n","import type { ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve a single dependency from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectOptions}.\n * @returns The resolved {@link T | dependency}.\n */\nexport function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n const componentModule = useComponentModule();\n\n return componentModule.get(provider, options?.isOptional);\n}\n\nexport type UseInjectOptions = {\n /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */\n isOptional?: boolean;\n};\n","import type { ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve multiple dependencies at once from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param deps Either one or more {@link ProviderToken}.\n * @returns Tuple containing the {@link D | dependencies}.\n */\nexport function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>(\n ...deps: D | unknown[]\n): ProviderModuleGetManySignature<D> {\n const componentModule = useComponentModule();\n\n return componentModule.getMany(...deps);\n}\n","import {\n InjectionScope,\n ProviderModule,\n ProviderModuleHelpers,\n type CloneParams,\n type IProviderModuleNaked,\n type ProviderModuleOptions,\n} from '@adimm/x-injection';\n\nimport type { IComponentProviderModule, IComponentProviderModuleNaked } from '../types';\n\n/** A superset of the {@link ProviderModule} used to integrate within a `React` component. */\nexport class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {\n protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];\n\n constructor(options: ProviderModuleOptions) {\n super(\n ProviderModuleHelpers.buildInternalConstructorParams({\n ...options,\n defaultScope: options.defaultScope ?? InjectionScope.Singleton,\n identifier: Symbol(`Component${options.identifier.description}`),\n })\n );\n\n this._initializedFromComponent = false;\n }\n\n override toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked {\n return this as any;\n }\n\n /* istanbul ignore next */\n override clone(options?: CloneParams): IComponentProviderModule {\n let providers = [...this.providers];\n\n if (options?.providersMap) {\n providers = providers.map((provider) => options.providersMap!(provider, this));\n }\n\n const clonedModule = new ComponentProviderModule(\n ProviderModuleHelpers.buildInternalConstructorParams({\n isAppModule: this.isAppModule,\n markAsGlobal: this.isMarkedAsGlobal,\n identifier: Symbol(this.identifier.description!.replace('Component', '')),\n defaultScope: this.defaultScope.native,\n dynamicExports: this.dynamicExports,\n onReady: this.onReady,\n onDispose: this.onDispose,\n importedProvidersMap: options?.importedProvidersMap,\n imports: [...this.imports],\n providers,\n exports: [...this.exports],\n })\n );\n\n //@ts-expect-error Read-only method.\n clonedModule._initializedFromComponent = this._initializedFromComponent;\n\n return clonedModule;\n }\n\n /* istanbul ignore next */\n dispose(): void {\n this._dispose();\n }\n\n //#region IComponentProviderModuleNaked methods\n\n /**\n * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**\n *\n * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.\n */\n protected _createContextualizedComponentInstance(): IComponentProviderModule {\n if (this._initializedFromComponent) return this;\n\n const ctxModule = this.clone().toNaked();\n\n //@ts-expect-error Read-only property\n ctxModule.identifier = Symbol(`Contextualized${ctxModule.identifier.description}`);\n ctxModule._initializedFromComponent = true;\n\n return ctxModule;\n }\n\n //#endregion\n}\n","import React from 'react';\n\nimport { forwardPropsWithModule, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule, PropsWithModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\nconst ComponentRenderer = React.memo(_ComponentRenderer);\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * export const MyComponent = provideModuleToComponent(\n * MyComponentModule,\n * ({ firstName, lastName }: MyComponentProps) => {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n * );\n *\n * function App() {\n * return <MyComponent firstName={'John'} lastName={'Doe'} />;\n * }\n * ```\n *\n * @param module The {@link IComponentProviderModule | Module} which should be consumed by the {@link component}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function provideModuleToComponent<\n P extends Record<string, any>,\n C extends ReactElementWithProviderModule<P> = ReactElementWithProviderModule<P>,\n>(module: IComponentProviderModule, component: ReactElementWithProviderModule<P>): C {\n return ((componentProps: PropsWithModule<P>) => {\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n <ComponentRenderer module={moduleCtx} componentProps={componentProps} component={component as any} />\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n }) as any;\n}\n\nfunction _ComponentRenderer<P extends Record<string, any>>({\n module,\n component,\n componentProps,\n}: {\n module: IComponentProviderModule;\n component: ReactElementWithProviderModule<P>;\n componentProps: P;\n}) {\n return <>{component(forwardPropsWithModule(component, componentProps, module))}</>;\n}\n\nexport type ReactElementWithProviderModule<P extends Record<string, any>> = (p: PropsWithModule<P>) => React.ReactNode;\n","import { useMemo } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { useEffectOnce } from './use-effect-once';\n\nexport function useContextualizedModule(\n originalModule: IComponentProviderModule,\n forwardedModule?: IComponentProviderModule\n): IComponentProviderModule {\n const ctxModule = useMemo(() => {\n const module = (forwardedModule ?? originalModule).toNaked();\n\n if (module.isMarkedAsGlobal) return module;\n\n return module._createContextualizedComponentInstance();\n }, [originalModule, forwardedModule]);\n\n useEffectOnce(() => {\n return () => {\n ctxModule.dispose();\n };\n });\n\n return ctxModule;\n}\n","import { useEffect, useRef, useState } from 'react';\n\n// Credits: https://stackoverflow.com/a/74000921\n\n/** Custom {@link useEffect} hook which will be run once. _(In `StrictMode` as well)_ */\nexport function useEffectOnce(effect: () => React.EffectCallback) {\n const destroyFunc = useRef<React.EffectCallback>(undefined);\n const effectCalled = useRef(false);\n const renderAfterCalled = useRef(false);\n const [, forceRerender] = useState(0);\n\n if (effectCalled.current) renderAfterCalled.current = true;\n\n useEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect();\n effectCalled.current = true;\n }\n\n // this forces one render after the effect is run\n forceRerender((x) => x + 1);\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) return;\n\n destroyFunc.current?.();\n };\n }, []);\n}\n","import { isFunction } from '@adimm/x-injection';\n\nimport type { ReactElementWithProviderModule } from '../core';\nimport type { IComponentProviderModule, PropsWithModule } from '../types';\n\nexport function forwardPropsWithModule<P extends Record<string, any>>(\n component: ReactElementWithProviderModule<P> | React.ReactElement,\n props: Record<string, any>,\n module: IComponentProviderModule\n): PropsWithModule<P> {\n const isReactElement = typeof component === 'object' && 'type' in component;\n\n const result = {\n ...props,\n } as any;\n\n if ((isReactElement && isFunction(component.type)) || isFunction(component)) {\n result['module'] = module;\n }\n\n return result;\n}\n","import React, { useMemo } from 'react';\n\nimport { forwardPropsWithModule, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * function MyComponent({ firstName, lastName }: MyComponentProps) {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n *\n * function App() {\n * return (\n * <ProvideModule module={MyComponentModule}>\n * <MyComponent firstName={'John'} lastName={'Doe'} />\n * </ProvideModule>\n * );\n * }\n * ```\n *\n * @param param0 See {@link ProvideModuleFunctionParams}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function ProvideModule({ module, children }: ProvideModuleFunctionParams) {\n /* istanbul ignore next */\n const componentProps = (children.props ?? {}) as any;\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n const component = useMemo(\n () => React.cloneElement(children, forwardPropsWithModule(children, componentProps, moduleCtx)),\n [componentProps, moduleCtx]\n );\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n {component}\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n}\n\nexport interface ProvideModuleFunctionParams {\n /** The {@link IComponentProviderModule | Module} which should be consumed by the {@link children | component}. */\n module: IComponentProviderModule;\n\n children: React.ReactElement;\n}\n","import type { ProviderToken } from '@adimm/x-injection';\nimport { useMemo } from 'react';\n\nimport { InjectionHookFactoryError } from '../errors';\nimport { useComponentModule } from './hooks';\n\nexport function hookFactory<P extends HookParams, D extends any[], T>({\n use: hook,\n inject,\n}: HookFactoryParams<P, D, T>): (p: P) => T {\n return (p: P) => {\n const componentModule = useComponentModule();\n\n const deps = useMemo(() => {\n if (inject.length === 0) {\n throw new InjectionHookFactoryError(componentModule, `The 'deps' property array is missing!`);\n }\n\n return componentModule.getMany(...inject);\n }, [inject]);\n\n return hook({ ...p, deps: [...deps] } as any);\n };\n}\n\nexport interface HookFactoryParams<P extends HookParams, D extends any[], T> {\n use: HookWithProviderModuleDependencies<P, D, T>;\n inject: ProviderToken[];\n}\n\nexport type HookWithProviderModuleDependencies<P extends HookParams, D extends any[], T> = (p: HookWithDeps<P, D>) => T;\n\nexport type HookWithDeps<P extends HookParams, D extends any[]> = P & {\n /** Array containing the resolved dependencies from the component context. */\n deps: D;\n};\n\ntype HookParams = Record<string, any> | void;\n","import { InjectionProviderModuleError } from '@adimm/x-injection';\n\nexport class InjectionHookFactoryError extends InjectionProviderModuleError {\n override name = InjectionHookFactoryError.name;\n}\n"],"mappings":"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","names":["REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","createContext","AppModule","import_react","useComponentModule","useContext","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","useInject","provider","options","componentModule","useComponentModule","get","isOptional","useInjectMany","deps","componentModule","useComponentModule","getMany","import_x_injection","ComponentProviderModule","ProviderModule","_initializedFromComponent","constructor","options","ProviderModuleHelpers","buildInternalConstructorParams","defaultScope","InjectionScope","Singleton","identifier","Symbol","description","toNaked","clone","providers","providersMap","map","provider","clonedModule","isAppModule","markAsGlobal","isMarkedAsGlobal","replace","native","dynamicExports","onReady","onDispose","importedProvidersMap","imports","exports","dispose","_dispose","_createContextualizedComponentInstance","ctxModule","import_react","import_react","import_react","useEffectOnce","effect","destroyFunc","useRef","undefined","effectCalled","renderAfterCalled","forceRerender","useState","current","useEffect","x","useContextualizedModule","originalModule","forwardedModule","ctxModule","useMemo","module","toNaked","isMarkedAsGlobal","_createContextualizedComponentInstance","useEffectOnce","dispose","import_x_injection","forwardPropsWithModule","component","props","module","isReactElement","result","isFunction","type","ComponentRenderer","React","memo","_ComponentRenderer","provideModuleToComponent","module","component","componentProps","moduleCtx","useContextualizedModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","forwardPropsWithModule","import_react","ProvideModule","module","children","componentProps","props","moduleCtx","useContextualizedModule","component","useMemo","React","cloneElement","forwardPropsWithModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","import_react","import_x_injection","InjectionHookFactoryError","InjectionProviderModuleError","name","hookFactory","use","hook","inject","p","componentModule","useComponentModule","deps","useMemo","length","InjectionHookFactoryError","getMany"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/react-context.ts","../src/core/hooks/use-component-module.ts","../src/core/hooks/use-inject.ts","../src/core/hooks/use-inject-many.ts","../src/core/component-provider-module.ts","../src/core/provide-module/provide-module.arrow-function.tsx","../src/helpers/hooks/use-contextualized-module.ts","../src/helpers/hooks/use-effect-once.ts","../src/helpers/component-provider-module.ts","../src/core/provide-module/provide-module.provider.tsx","../src/core/hook-factory.ts","../src/errors/hook-factory.ts"],"sourcesContent":["export * from './core';\nexport type * from './types';\n","import { AppModule } from '@adimm/x-injection';\nimport { createContext } from 'react';\n\nimport type { IComponentProviderModule } from '../types';\n\nexport const REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT = createContext<IComponentProviderModule>(AppModule as any);\n","import { useContext } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/** Can be used to retrieve the {@link IComponentProviderModule} from the current context. */\nexport function useComponentModule(): IComponentProviderModule {\n return useContext(REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT);\n}\n","import type { ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve a single dependency from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectOptions}.\n * @returns The resolved {@link T | dependency}.\n */\nexport function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n const componentModule = useComponentModule();\n\n return componentModule.get(provider, options?.isOptional);\n}\n\nexport type UseInjectOptions = {\n /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */\n isOptional?: boolean;\n};\n","import type { ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve multiple dependencies at once from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param deps Either one or more {@link ProviderToken}.\n * @returns Tuple containing the {@link D | dependencies}.\n */\nexport function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>(\n ...deps: D | unknown[]\n): ProviderModuleGetManySignature<D> {\n const componentModule = useComponentModule();\n\n return componentModule.getMany(...deps);\n}\n","import {\n InjectionScope,\n ProviderModule,\n ProviderModuleHelpers,\n type IProviderModule,\n type IProviderModuleNaked,\n type ProviderModuleOptionsInternal,\n} from '@adimm/x-injection';\n\nimport type { ComponentProviderModuleOptions, IComponentProviderModule, IComponentProviderModuleNaked } from '../types';\n\n/** A superset of the {@link ProviderModule} used to integrate within a `React` component. */\nexport class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {\n protected readonly originalIdentifier: symbol;\n protected readonly hasContextualizedImports: IComponentProviderModuleNaked['hasContextualizedImports'];\n protected readonly initializedFromComponent: IComponentProviderModuleNaked['initializedFromComponent'];\n\n constructor(options: ComponentProviderModuleOptions) {\n const identifier = Symbol(`Component${options.identifier.description}`);\n const contextualizeImports = options.markAsGlobal ? false : options.contextualizeImports ?? true;\n const contextualizedImportsCache: Map<string, IProviderModule> | undefined = contextualizeImports\n ? new Map()\n : undefined;\n\n super(\n ProviderModuleHelpers.buildInternalConstructorParams({\n ...options,\n defaultScope: options.defaultScope ?? InjectionScope.Singleton,\n identifier: identifier,\n imports: !contextualizeImports\n ? options.imports\n : options.imports?.map((imp) => {\n const module = (typeof imp === 'function' ? imp() : imp) as IComponentProviderModuleNaked;\n /* istanbul ignore next */\n if (!contextualizeImports) return module;\n\n return () => {\n const ctxModule = module._createContextualizedComponentInstance(identifier);\n\n contextualizedImportsCache!.set(module.originalIdentifier.toString(), ctxModule);\n\n return ctxModule;\n };\n }),\n dynamicExports: (_, exports) => {\n if (!contextualizeImports) return exports;\n\n return exports.map((exp) => {\n if (!(exp instanceof ProviderModule)) return exp;\n\n const cachedCtxModule = contextualizedImportsCache!.get(\n (exp as unknown as IComponentProviderModuleNaked).originalIdentifier.toString()\n )!;\n\n return cachedCtxModule;\n });\n },\n })\n );\n\n this.originalIdentifier = options.identifier;\n this.hasContextualizedImports = contextualizeImports;\n this.initializedFromComponent = false;\n }\n\n override toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked {\n return this as any;\n }\n\n /* istanbul ignore next */\n override clone(options?: Partial<ComponentProviderModuleOptions>): IComponentProviderModule {\n const _options = options as ProviderModuleOptionsInternal;\n\n const clonedModule = new ComponentProviderModule(\n ProviderModuleHelpers.buildInternalConstructorParams({\n isAppModule: this.isAppModule,\n markAsGlobal: this.isMarkedAsGlobal,\n identifier: Symbol(this.identifier.description!.replace('Component', '')),\n defaultScope: this.defaultScope.native,\n dynamicExports: this.dynamicExports,\n onReady: this.onReady,\n onDispose: this.onDispose,\n contextualizeImports: this.hasContextualizedImports,\n importedProvidersMap: this.importedProvidersMap,\n imports: [...this.imports],\n providers: [...this.providers],\n exports: [...this.exports],\n ..._options,\n } as ComponentProviderModuleOptions)\n );\n\n //@ts-expect-error Read-only method.\n clonedModule.initializedFromComponent = this.initializedFromComponent;\n\n return clonedModule;\n }\n\n /* istanbul ignore next */\n override async dispose(): Promise<void> {\n await super.dispose();\n }\n\n //#region IComponentProviderModuleNaked methods\n\n /**\n * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**\n *\n * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.\n */\n protected _createContextualizedComponentInstance(parentIdentifier?: symbol): IComponentProviderModule {\n if (this.initializedFromComponent) return this;\n\n const ctxModule = this.clone().toNaked();\n\n /* istanbul ignore next */\n //@ts-expect-error Read-only property\n ctxModule.identifier = Symbol(\n `${parentIdentifier ? `[Parent:${parentIdentifier.description ?? 'Unknown'}]` : ''}Contextualized${ctxModule.identifier.description}`\n );\n ctxModule.initializedFromComponent = true;\n\n return ctxModule;\n }\n\n //#endregion\n}\n","import React from 'react';\n\nimport { ComponentProviderModuleHelpers, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule, PropsWithModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\nconst ComponentRenderer = React.memo(_ComponentRenderer);\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * export const MyComponent = provideModuleToComponent<MyComponentProps>(\n * MyComponentModule,\n * ({ firstName, lastName }) => {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n * );\n *\n * function App() {\n * return <MyComponent firstName={'John'} lastName={'Doe'} />;\n * }\n * ```\n *\n * @param module The {@link IComponentProviderModule | Module} which should be consumed by the {@link component}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function provideModuleToComponent<\n P extends Record<string, any>,\n C extends ReactElementWithProviderModule<P> = ReactElementWithProviderModule<P>,\n>(module: IComponentProviderModule, component: ReactElementWithProviderModule<P>): C {\n return ((componentProps: PropsWithModule<P>) => {\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n <ComponentRenderer module={moduleCtx} componentProps={componentProps} component={component as any} />\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n }) as any;\n}\n\nfunction _ComponentRenderer<P extends Record<string, any>>({\n module,\n component,\n componentProps,\n}: {\n module: IComponentProviderModule;\n component: ReactElementWithProviderModule<P>;\n componentProps: P;\n}) {\n return <>{component(ComponentProviderModuleHelpers.forwardPropsWithModule(component, componentProps, module))}</>;\n}\n\nexport type ReactElementWithProviderModule<P extends Record<string, any>> = (p: PropsWithModule<P>) => React.ReactNode;\n","import { useMemo } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { useEffectOnce } from './use-effect-once';\n\nexport function useContextualizedModule(\n originalModule: IComponentProviderModule,\n forwardedModule?: IComponentProviderModule\n): IComponentProviderModule {\n const ctxModule = useMemo(() => {\n const module = (forwardedModule ?? originalModule).toNaked();\n\n if (module.isMarkedAsGlobal) return module;\n\n return module._createContextualizedComponentInstance();\n }, [originalModule, forwardedModule]);\n\n useEffectOnce(() => {\n return () => {\n ctxModule.dispose();\n };\n });\n\n return ctxModule;\n}\n","import { useEffect, useRef, useState } from 'react';\n\n// Credits: https://stackoverflow.com/a/74000921\n\n/** Custom {@link useEffect} hook which will be run once. _(In `StrictMode` as well)_ */\nexport function useEffectOnce(effect: () => React.EffectCallback) {\n const destroyFunc = useRef<React.EffectCallback>(undefined);\n const effectCalled = useRef(false);\n const renderAfterCalled = useRef(false);\n const [, forceRerender] = useState(0);\n\n if (effectCalled.current) renderAfterCalled.current = true;\n\n useEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect();\n effectCalled.current = true;\n }\n\n // this forces one render after the effect is run\n forceRerender((x) => x + 1);\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) return;\n\n destroyFunc.current?.();\n };\n }, []);\n}\n","import { isFunction } from '@adimm/x-injection';\n\nimport type { ReactElementWithProviderModule } from '../core';\nimport type { IComponentProviderModule, PropsWithModule } from '../types';\n\nexport namespace ComponentProviderModuleHelpers {\n export function forwardPropsWithModule<P extends Record<string, any>>(\n component: ReactElementWithProviderModule<P> | React.ReactElement,\n props: Record<string, any>,\n module: IComponentProviderModule\n ): PropsWithModule<P> {\n const isReactElement = typeof component === 'object' && 'type' in component;\n\n const result = {\n ...props,\n } as any;\n\n if ((isReactElement && isFunction(component.type)) || isFunction(component)) {\n result['module'] = module;\n }\n\n return result;\n }\n}\n","import React, { useMemo } from 'react';\n\nimport { ComponentProviderModuleHelpers, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * function MyComponent({ firstName, lastName }: MyComponentProps) {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n *\n * function App() {\n * return (\n * <ProvideModule module={MyComponentModule}>\n * <MyComponent firstName={'John'} lastName={'Doe'} />\n * </ProvideModule>\n * );\n * }\n * ```\n *\n * @param param0 See {@link ProvideModuleFunctionParams}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function ProvideModule({ module, children }: ProvideModuleFunctionParams) {\n /* istanbul ignore next */\n const componentProps = (children.props ?? {}) as any;\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n const component = useMemo(\n () =>\n React.cloneElement(\n children,\n ComponentProviderModuleHelpers.forwardPropsWithModule(children, componentProps, moduleCtx)\n ),\n [componentProps, moduleCtx]\n );\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n {component}\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n}\n\nexport interface ProvideModuleFunctionParams {\n /** The {@link IComponentProviderModule | Module} which should be consumed by the {@link children | component}. */\n module: IComponentProviderModule;\n\n children: React.ReactElement;\n}\n","import type { ProviderToken } from '@adimm/x-injection';\nimport { useMemo } from 'react';\n\nimport { InjectionHookFactoryError } from '../errors';\nimport { useComponentModule } from './hooks';\n\nexport function hookFactory<P extends HookParams, D extends any[], T>({\n use: hook,\n inject,\n}: HookFactoryParams<P, D, T>): (p: P) => T {\n return (p: P) => {\n const componentModule = useComponentModule();\n\n const deps = useMemo(() => {\n if (inject.length === 0) {\n throw new InjectionHookFactoryError(componentModule, `The 'deps' property array is missing!`);\n }\n\n return componentModule.getMany(...inject);\n }, [inject]);\n\n return hook({ ...p, deps: [...deps] } as any);\n };\n}\n\nexport interface HookFactoryParams<P extends HookParams, D extends any[], T> {\n use: HookWithProviderModuleDependencies<P, D, T>;\n inject: ProviderToken[];\n}\n\nexport type HookWithProviderModuleDependencies<P extends HookParams, D extends any[], T> = (p: HookWithDeps<P, D>) => T;\n\nexport type HookWithDeps<P extends HookParams, D extends any[]> = P & {\n /** Array containing the resolved dependencies from the component context. */\n deps: D;\n};\n\ntype HookParams = Record<string, any> | void;\n","import { InjectionProviderModuleError } from '@adimm/x-injection';\n\nexport class InjectionHookFactoryError extends InjectionProviderModuleError {\n override name = InjectionHookFactoryError.name;\n}\n"],"mappings":"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","names":["REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","createContext","AppModule","import_react","useComponentModule","useContext","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","useInject","provider","options","componentModule","useComponentModule","get","isOptional","useInjectMany","deps","componentModule","useComponentModule","getMany","import_x_injection","ComponentProviderModule","ProviderModule","originalIdentifier","hasContextualizedImports","initializedFromComponent","constructor","options","identifier","Symbol","description","contextualizeImports","markAsGlobal","contextualizedImportsCache","Map","undefined","ProviderModuleHelpers","buildInternalConstructorParams","defaultScope","InjectionScope","Singleton","imports","map","imp","module","ctxModule","_createContextualizedComponentInstance","set","toString","dynamicExports","_","exports","exp","cachedCtxModule","get","toNaked","clone","_options","clonedModule","isAppModule","isMarkedAsGlobal","replace","native","onReady","onDispose","importedProvidersMap","providers","dispose","parentIdentifier","import_react","import_react","import_react","useEffectOnce","effect","destroyFunc","useRef","undefined","effectCalled","renderAfterCalled","forceRerender","useState","current","useEffect","x","useContextualizedModule","originalModule","forwardedModule","ctxModule","useMemo","module","toNaked","isMarkedAsGlobal","_createContextualizedComponentInstance","useEffectOnce","dispose","import_x_injection","ComponentProviderModuleHelpers","forwardPropsWithModule","component","props","module","isReactElement","result","isFunction","type","ComponentRenderer","React","memo","_ComponentRenderer","provideModuleToComponent","module","component","componentProps","moduleCtx","useContextualizedModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","ComponentProviderModuleHelpers","forwardPropsWithModule","import_react","ProvideModule","module","children","componentProps","props","moduleCtx","useContextualizedModule","component","useMemo","React","cloneElement","ComponentProviderModuleHelpers","forwardPropsWithModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","import_react","import_x_injection","InjectionHookFactoryError","InjectionProviderModuleError","name","hookFactory","use","hook","inject","p","componentModule","useComponentModule","deps","useMemo","length","InjectionHookFactoryError","getMany"]}
package/dist/index.d.cts CHANGED
@@ -1,16 +1,42 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule, ProviderModuleOptions, CloneParams } from '@adimm/x-injection';
3
+ import { ProviderModuleOptions, IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule } from '@adimm/x-injection';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
 
6
+ interface ComponentProviderModuleOptions extends ProviderModuleOptions {
7
+ /**
8
+ * When set to `true`, it'll automatically `contextualize` all the `imports` array.
9
+ *
10
+ * **Note:** _This is required when you have a parent component which renders one or more children
11
+ * and does also need to control their providers._
12
+ * _If not set to `true`, then the children providers would be resolved from their original `module`, therefore_
13
+ * _if your parent component has multiple instances of itself, all its children will actually share_
14
+ * _the same providers, especially when their module injection scope is set to `Singleton` (by default)._
15
+ *
16
+ * **Note2:** _If a module has {@link ProviderModuleOptions.markAsGlobal | markAsGlobal} set to `true`,_
17
+ * _this will automatically default to `false`._
18
+ *
19
+ * Defaults to `true`.
20
+ */
21
+ contextualizeImports?: boolean;
22
+ }
23
+
6
24
  interface IComponentProviderModuleNaked extends IComponentProviderModule {
25
+ /**
26
+ * The original `id` which was assigned to this module.
27
+ *
28
+ * **Note:** _The module initial {@link ComponentProviderModuleOptions.identifier | id} will be suffixed with `Contextualized`._
29
+ */
30
+ originalIdentifier: symbol;
31
+ /** See {@link ComponentProviderModuleOptions.contextualizeImports}. */
32
+ hasContextualizedImports: ComponentProviderModuleOptions['contextualizeImports'];
7
33
  /** Indicates if this module has been initialized by a React Component or not. */
8
- _initializedFromComponent: boolean;
34
+ initializedFromComponent: boolean;
9
35
  /**
10
36
  * It is used internally by the `ProviderModule` to create a new cloned
11
37
  * module which will be consumed only by that specific component instance.
12
38
  */
13
- _createContextualizedComponentInstance(): IComponentProviderModule;
39
+ _createContextualizedComponentInstance(parentIdentifier?: symbol): IComponentProviderModule;
14
40
  }
15
41
 
16
42
  interface IComponentProviderModule extends IProviderModule {
@@ -25,7 +51,7 @@ interface IComponentProviderModule extends IProviderModule {
25
51
  *
26
52
  * _eg: When changing page, removable components and so on._
27
53
  */
28
- dispose(): void;
54
+ dispose(): Promise<void>;
29
55
  }
30
56
 
31
57
  type PropsWithModule<P extends Record<string, any>> = P & {
@@ -74,17 +100,19 @@ declare function useComponentModule(): IComponentProviderModule;
74
100
 
75
101
  /** A superset of the {@link ProviderModule} used to integrate within a `React` component. */
76
102
  declare class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {
77
- protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];
78
- constructor(options: ProviderModuleOptions);
103
+ protected readonly originalIdentifier: symbol;
104
+ protected readonly hasContextualizedImports: IComponentProviderModuleNaked['hasContextualizedImports'];
105
+ protected readonly initializedFromComponent: IComponentProviderModuleNaked['initializedFromComponent'];
106
+ constructor(options: ComponentProviderModuleOptions);
79
107
  toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
80
- clone(options?: CloneParams): IComponentProviderModule;
81
- dispose(): void;
108
+ clone(options?: Partial<ComponentProviderModuleOptions>): IComponentProviderModule;
109
+ dispose(): Promise<void>;
82
110
  /**
83
111
  * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**
84
112
  *
85
113
  * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.
86
114
  */
87
- protected _createContextualizedComponentInstance(): IComponentProviderModule;
115
+ protected _createContextualizedComponentInstance(parentIdentifier?: symbol): IComponentProviderModule;
88
116
  }
89
117
 
90
118
  /**
@@ -97,9 +125,9 @@ declare class ComponentProviderModule extends ProviderModule implements ICompone
97
125
  * lastName: string;
98
126
  * }
99
127
  *
100
- * export const MyComponent = provideModuleToComponent(
128
+ * export const MyComponent = provideModuleToComponent<MyComponentProps>(
101
129
  * MyComponentModule,
102
- * ({ firstName, lastName }: MyComponentProps) => {
130
+ * ({ firstName, lastName }) => {
103
131
  * const service = useInject(MyComponentService);
104
132
  *
105
133
  * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>
@@ -164,4 +192,4 @@ type HookWithDeps<P extends HookParams, D extends any[]> = P & {
164
192
  };
165
193
  type HookParams = Record<string, any> | void;
166
194
 
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 };
195
+ export { ComponentProviderModule, type ComponentProviderModuleOptions, 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 };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,42 @@
1
1
  import * as React from 'react';
2
2
  import React__default from 'react';
3
- import { IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule, ProviderModuleOptions, CloneParams } from '@adimm/x-injection';
3
+ import { ProviderModuleOptions, IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule } from '@adimm/x-injection';
4
4
  import * as react_jsx_runtime from 'react/jsx-runtime';
5
5
 
6
+ interface ComponentProviderModuleOptions extends ProviderModuleOptions {
7
+ /**
8
+ * When set to `true`, it'll automatically `contextualize` all the `imports` array.
9
+ *
10
+ * **Note:** _This is required when you have a parent component which renders one or more children
11
+ * and does also need to control their providers._
12
+ * _If not set to `true`, then the children providers would be resolved from their original `module`, therefore_
13
+ * _if your parent component has multiple instances of itself, all its children will actually share_
14
+ * _the same providers, especially when their module injection scope is set to `Singleton` (by default)._
15
+ *
16
+ * **Note2:** _If a module has {@link ProviderModuleOptions.markAsGlobal | markAsGlobal} set to `true`,_
17
+ * _this will automatically default to `false`._
18
+ *
19
+ * Defaults to `true`.
20
+ */
21
+ contextualizeImports?: boolean;
22
+ }
23
+
6
24
  interface IComponentProviderModuleNaked extends IComponentProviderModule {
25
+ /**
26
+ * The original `id` which was assigned to this module.
27
+ *
28
+ * **Note:** _The module initial {@link ComponentProviderModuleOptions.identifier | id} will be suffixed with `Contextualized`._
29
+ */
30
+ originalIdentifier: symbol;
31
+ /** See {@link ComponentProviderModuleOptions.contextualizeImports}. */
32
+ hasContextualizedImports: ComponentProviderModuleOptions['contextualizeImports'];
7
33
  /** Indicates if this module has been initialized by a React Component or not. */
8
- _initializedFromComponent: boolean;
34
+ initializedFromComponent: boolean;
9
35
  /**
10
36
  * It is used internally by the `ProviderModule` to create a new cloned
11
37
  * module which will be consumed only by that specific component instance.
12
38
  */
13
- _createContextualizedComponentInstance(): IComponentProviderModule;
39
+ _createContextualizedComponentInstance(parentIdentifier?: symbol): IComponentProviderModule;
14
40
  }
15
41
 
16
42
  interface IComponentProviderModule extends IProviderModule {
@@ -25,7 +51,7 @@ interface IComponentProviderModule extends IProviderModule {
25
51
  *
26
52
  * _eg: When changing page, removable components and so on._
27
53
  */
28
- dispose(): void;
54
+ dispose(): Promise<void>;
29
55
  }
30
56
 
31
57
  type PropsWithModule<P extends Record<string, any>> = P & {
@@ -74,17 +100,19 @@ declare function useComponentModule(): IComponentProviderModule;
74
100
 
75
101
  /** A superset of the {@link ProviderModule} used to integrate within a `React` component. */
76
102
  declare class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {
77
- protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];
78
- constructor(options: ProviderModuleOptions);
103
+ protected readonly originalIdentifier: symbol;
104
+ protected readonly hasContextualizedImports: IComponentProviderModuleNaked['hasContextualizedImports'];
105
+ protected readonly initializedFromComponent: IComponentProviderModuleNaked['initializedFromComponent'];
106
+ constructor(options: ComponentProviderModuleOptions);
79
107
  toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
80
- clone(options?: CloneParams): IComponentProviderModule;
81
- dispose(): void;
108
+ clone(options?: Partial<ComponentProviderModuleOptions>): IComponentProviderModule;
109
+ dispose(): Promise<void>;
82
110
  /**
83
111
  * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**
84
112
  *
85
113
  * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.
86
114
  */
87
- protected _createContextualizedComponentInstance(): IComponentProviderModule;
115
+ protected _createContextualizedComponentInstance(parentIdentifier?: symbol): IComponentProviderModule;
88
116
  }
89
117
 
90
118
  /**
@@ -97,9 +125,9 @@ declare class ComponentProviderModule extends ProviderModule implements ICompone
97
125
  * lastName: string;
98
126
  * }
99
127
  *
100
- * export const MyComponent = provideModuleToComponent(
128
+ * export const MyComponent = provideModuleToComponent<MyComponentProps>(
101
129
  * MyComponentModule,
102
- * ({ firstName, lastName }: MyComponentProps) => {
130
+ * ({ firstName, lastName }) => {
103
131
  * const service = useInject(MyComponentService);
104
132
  *
105
133
  * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>
@@ -164,4 +192,4 @@ type HookWithDeps<P extends HookParams, D extends any[]> = P & {
164
192
  };
165
193
  type HookParams = Record<string, any> | void;
166
194
 
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 };
195
+ export { ComponentProviderModule, type ComponentProviderModuleOptions, 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 };
package/dist/index.js CHANGED
@@ -27,25 +27,38 @@ t(s, "useComponentModule"), t(a, "useInject"), t(m, "useInjectMany");
27
27
 
28
28
  import { InjectionScope as c, ProviderModule as p, ProviderModuleHelpers as d } from "@adimm/x-injection";
29
29
 
30
- var u = class e extends p {
30
+ var u, l = class e extends p {
31
31
  static {
32
32
  t(this, "ComponentProviderModule");
33
33
  }
34
- _initializedFromComponent;
34
+ originalIdentifier;
35
+ hasContextualizedImports;
36
+ initializedFromComponent;
35
37
  constructor(e) {
38
+ const o = Symbol(`Component${e.identifier.description}`), n = !e.markAsGlobal && (e.contextualizeImports ?? !0), r = n ? new Map : void 0;
36
39
  super(d.buildInternalConstructorParams({
37
40
  ...e,
38
41
  defaultScope: e.defaultScope ?? c.Singleton,
39
- identifier: Symbol(`Component${e.identifier.description}`)
40
- })), this._initializedFromComponent = !1;
42
+ identifier: o,
43
+ imports: n ? e.imports?.map((e => {
44
+ const t = "function" == typeof e ? e() : e;
45
+ return n ? () => {
46
+ const e = t._createContextualizedComponentInstance(o);
47
+ return r.set(t.originalIdentifier.toString(), e), e;
48
+ } : t;
49
+ })) : e.imports,
50
+ dynamicExports: t(((e, t) => n ? t.map((e => {
51
+ if (!(e instanceof p)) return e;
52
+ return r.get(e.originalIdentifier.toString());
53
+ })) : t), "dynamicExports")
54
+ })), this.originalIdentifier = e.identifier, this.hasContextualizedImports = n,
55
+ this.initializedFromComponent = !1;
41
56
  }
42
57
  toNaked() {
43
58
  return this;
44
59
  }
45
60
  clone(t) {
46
- let o = [ ...this.providers ];
47
- t?.providersMap && (o = o.map((e => t.providersMap(e, this))));
48
- const n = new e(d.buildInternalConstructorParams({
61
+ const o = t, n = new e(d.buildInternalConstructorParams({
49
62
  isAppModule: this.isAppModule,
50
63
  markAsGlobal: this.isMarkedAsGlobal,
51
64
  identifier: Symbol(this.identifier.description.replace("Component", "")),
@@ -53,40 +66,42 @@ var u = class e extends p {
53
66
  dynamicExports: this.dynamicExports,
54
67
  onReady: this.onReady,
55
68
  onDispose: this.onDispose,
56
- importedProvidersMap: t?.importedProvidersMap,
69
+ contextualizeImports: this.hasContextualizedImports,
70
+ importedProvidersMap: this.importedProvidersMap,
57
71
  imports: [ ...this.imports ],
58
- providers: o,
59
- exports: [ ...this.exports ]
72
+ providers: [ ...this.providers ],
73
+ exports: [ ...this.exports ],
74
+ ...o
60
75
  }));
61
- return n._initializedFromComponent = this._initializedFromComponent, n;
76
+ return n.initializedFromComponent = this.initializedFromComponent, n;
62
77
  }
63
- dispose() {
64
- this._dispose();
78
+ async dispose() {
79
+ await super.dispose();
65
80
  }
66
- _createContextualizedComponentInstance() {
67
- if (this._initializedFromComponent) return this;
68
- const e = this.clone().toNaked();
69
- return e.identifier = Symbol(`Contextualized${e.identifier.description}`), e._initializedFromComponent = !0,
70
- e;
81
+ _createContextualizedComponentInstance(e) {
82
+ if (this.initializedFromComponent) return this;
83
+ const t = this.clone().toNaked();
84
+ return t.identifier = Symbol(`${e ? `[Parent:${e.description ?? "Unknown"}]` : ""}Contextualized${t.identifier.description}`),
85
+ t.initializedFromComponent = !0, t;
71
86
  }
72
87
  };
73
88
 
74
- import l from "react";
89
+ import f from "react";
75
90
 
76
- import { useMemo as f } from "react";
91
+ import { useMemo as h } from "react";
77
92
 
78
- import { useEffect as h, useRef as v, useState as C } from "react";
93
+ import { useEffect as C, useRef as x, useState as y } from "react";
79
94
 
80
95
  function M(e) {
81
- const t = v(void 0), o = v(!1), n = v(!1), [, r] = C(0);
82
- o.current && (n.current = !0), h((() => (o.current || (t.current = e(), o.current = !0),
96
+ const t = x(void 0), o = x(!1), n = x(!1), [, r] = y(0);
97
+ o.current && (n.current = !0), C((() => (o.current || (t.current = e(), o.current = !0),
83
98
  r((e => e + 1)), () => {
84
99
  n.current && t.current?.();
85
100
  })), []);
86
101
  }
87
102
 
88
- function y(e, t) {
89
- const o = f((() => {
103
+ function v(e, t) {
104
+ const o = h((() => {
90
105
  const o = (t ?? e).toNaked();
91
106
  return o.isMarkedAsGlobal ? o : o._createContextualizedComponentInstance();
92
107
  }), [ e, t ]);
@@ -95,28 +110,29 @@ function y(e, t) {
95
110
  })), o;
96
111
  }
97
112
 
98
- t(M, "useEffectOnce"), t(y, "useContextualizedModule");
113
+ t(M, "useEffectOnce"), t(v, "useContextualizedModule");
99
114
 
100
- import { isFunction as x } from "@adimm/x-injection";
115
+ import { isFunction as I } from "@adimm/x-injection";
101
116
 
102
- function P(e, t, o) {
103
- const n = {
104
- ...t
105
- };
106
- return ("object" == typeof e && "type" in e && x(e.type) || x(e)) && (n.module = o),
107
- n;
108
- }
109
-
110
- t(P, "forwardPropsWithModule");
117
+ !function(e) {
118
+ function o(e, t, o) {
119
+ const n = {
120
+ ...t
121
+ };
122
+ return ("object" == typeof e && "type" in e && I(e.type) || I(e)) && (n.module = o),
123
+ n;
124
+ }
125
+ t(o, "forwardPropsWithModule"), e.forwardPropsWithModule = o;
126
+ }(u || (u = {}));
111
127
 
112
- var b = l.memo(z);
128
+ var z = f.memo(g);
113
129
 
114
- function j(e, t) {
130
+ function P(e, t) {
115
131
  return o => {
116
- const n = y(e, o.module);
117
- return l.createElement(r.Provider, {
132
+ const n = v(e, o.module);
133
+ return f.createElement(r.Provider, {
118
134
  value: n
119
- }, l.createElement(b, {
135
+ }, f.createElement(z, {
120
136
  module: n,
121
137
  componentProps: o,
122
138
  component: t
@@ -124,37 +140,37 @@ function j(e, t) {
124
140
  };
125
141
  }
126
142
 
127
- function z({module: e, component: t, componentProps: o}) {
128
- return l.createElement(l.Fragment, null, t(P(t, o, e)));
143
+ function g({module: e, component: t, componentProps: o}) {
144
+ return f.createElement(f.Fragment, null, t(u.forwardPropsWithModule(t, o, e)));
129
145
  }
130
146
 
131
- t(j, "provideModuleToComponent"), t(z, "_ComponentRenderer");
147
+ t(P, "provideModuleToComponent"), t(g, "_ComponentRenderer");
132
148
 
133
- import _, { useMemo as E } from "react";
149
+ import b, { useMemo as E } from "react";
134
150
 
135
- function F({module: e, children: t}) {
136
- const o = t.props ?? {}, n = y(e, o.module), i = E((() => _.cloneElement(t, P(t, o, n))), [ o, n ]);
137
- return _.createElement(r.Provider, {
151
+ function j({module: e, children: t}) {
152
+ const o = t.props ?? {}, n = v(e, o.module), i = E((() => b.cloneElement(t, u.forwardPropsWithModule(t, o, n))), [ o, n ]);
153
+ return b.createElement(r.Provider, {
138
154
  value: n
139
155
  }, i);
140
156
  }
141
157
 
142
- t(F, "ProvideModule");
158
+ t(j, "ProvideModule");
143
159
 
144
- import { useMemo as g } from "react";
160
+ import { useMemo as k } from "react";
145
161
 
146
- import { InjectionProviderModuleError as k } from "@adimm/x-injection";
162
+ import { InjectionProviderModuleError as w } from "@adimm/x-injection";
147
163
 
148
- var S = class e extends k {
164
+ var S = class e extends w {
149
165
  static {
150
166
  t(this, "InjectionHookFactoryError");
151
167
  }
152
168
  name=e.name;
153
169
  };
154
170
 
155
- function I({use: e, inject: t}) {
171
+ function F({use: e, inject: t}) {
156
172
  return o => {
157
- const n = s(), r = g((() => {
173
+ const n = s(), r = k((() => {
158
174
  if (0 === t.length) throw new S(n, "The 'deps' property array is missing!");
159
175
  return n.getMany(...t);
160
176
  }), [ t ]);
@@ -165,6 +181,6 @@ function I({use: e, inject: t}) {
165
181
  };
166
182
  }
167
183
 
168
- t(I, "hookFactory");
184
+ t(F, "hookFactory");
169
185
 
170
- export { u as ComponentProviderModule, F as ProvideModule, r as REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT, I as hookFactory, j as provideModuleToComponent, s as useComponentModule, a as useInject, m as useInjectMany };//# sourceMappingURL=index.js.map
186
+ export { l as ComponentProviderModule, j as ProvideModule, r as REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT, F as hookFactory, P as provideModuleToComponent, s as useComponentModule, a as useInject, m as useInjectMany };//# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/react-context.ts","../src/core/hooks/use-component-module.ts","../src/core/hooks/use-inject.ts","../src/core/hooks/use-inject-many.ts","../src/core/component-provider-module.ts","../src/core/provide-module/provide-module.arrow-function.tsx","../src/helpers/hooks/use-contextualized-module.ts","../src/helpers/hooks/use-effect-once.ts","../src/helpers/forward-props-with-module.ts","../src/core/provide-module/provide-module.provider.tsx","../src/core/hook-factory.ts","../src/errors/hook-factory.ts"],"sourcesContent":["import { AppModule } from '@adimm/x-injection';\nimport { createContext } from 'react';\n\nimport type { IComponentProviderModule } from '../types';\n\nexport const REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT = createContext<IComponentProviderModule>(AppModule as any);\n","import { useContext } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/** Can be used to retrieve the {@link IComponentProviderModule} from the current context. */\nexport function useComponentModule(): IComponentProviderModule {\n return useContext(REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT);\n}\n","import type { ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve a single dependency from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectOptions}.\n * @returns The resolved {@link T | dependency}.\n */\nexport function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n const componentModule = useComponentModule();\n\n return componentModule.get(provider, options?.isOptional);\n}\n\nexport type UseInjectOptions = {\n /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */\n isOptional?: boolean;\n};\n","import type { ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve multiple dependencies at once from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param deps Either one or more {@link ProviderToken}.\n * @returns Tuple containing the {@link D | dependencies}.\n */\nexport function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>(\n ...deps: D | unknown[]\n): ProviderModuleGetManySignature<D> {\n const componentModule = useComponentModule();\n\n return componentModule.getMany(...deps);\n}\n","import {\n InjectionScope,\n ProviderModule,\n ProviderModuleHelpers,\n type CloneParams,\n type IProviderModuleNaked,\n type ProviderModuleOptions,\n} from '@adimm/x-injection';\n\nimport type { IComponentProviderModule, IComponentProviderModuleNaked } from '../types';\n\n/** A superset of the {@link ProviderModule} used to integrate within a `React` component. */\nexport class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {\n protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];\n\n constructor(options: ProviderModuleOptions) {\n super(\n ProviderModuleHelpers.buildInternalConstructorParams({\n ...options,\n defaultScope: options.defaultScope ?? InjectionScope.Singleton,\n identifier: Symbol(`Component${options.identifier.description}`),\n })\n );\n\n this._initializedFromComponent = false;\n }\n\n override toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked {\n return this as any;\n }\n\n /* istanbul ignore next */\n override clone(options?: CloneParams): IComponentProviderModule {\n let providers = [...this.providers];\n\n if (options?.providersMap) {\n providers = providers.map((provider) => options.providersMap!(provider, this));\n }\n\n const clonedModule = new ComponentProviderModule(\n ProviderModuleHelpers.buildInternalConstructorParams({\n isAppModule: this.isAppModule,\n markAsGlobal: this.isMarkedAsGlobal,\n identifier: Symbol(this.identifier.description!.replace('Component', '')),\n defaultScope: this.defaultScope.native,\n dynamicExports: this.dynamicExports,\n onReady: this.onReady,\n onDispose: this.onDispose,\n importedProvidersMap: options?.importedProvidersMap,\n imports: [...this.imports],\n providers,\n exports: [...this.exports],\n })\n );\n\n //@ts-expect-error Read-only method.\n clonedModule._initializedFromComponent = this._initializedFromComponent;\n\n return clonedModule;\n }\n\n /* istanbul ignore next */\n dispose(): void {\n this._dispose();\n }\n\n //#region IComponentProviderModuleNaked methods\n\n /**\n * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**\n *\n * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.\n */\n protected _createContextualizedComponentInstance(): IComponentProviderModule {\n if (this._initializedFromComponent) return this;\n\n const ctxModule = this.clone().toNaked();\n\n //@ts-expect-error Read-only property\n ctxModule.identifier = Symbol(`Contextualized${ctxModule.identifier.description}`);\n ctxModule._initializedFromComponent = true;\n\n return ctxModule;\n }\n\n //#endregion\n}\n","import React from 'react';\n\nimport { forwardPropsWithModule, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule, PropsWithModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\nconst ComponentRenderer = React.memo(_ComponentRenderer);\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * export const MyComponent = provideModuleToComponent(\n * MyComponentModule,\n * ({ firstName, lastName }: MyComponentProps) => {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n * );\n *\n * function App() {\n * return <MyComponent firstName={'John'} lastName={'Doe'} />;\n * }\n * ```\n *\n * @param module The {@link IComponentProviderModule | Module} which should be consumed by the {@link component}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function provideModuleToComponent<\n P extends Record<string, any>,\n C extends ReactElementWithProviderModule<P> = ReactElementWithProviderModule<P>,\n>(module: IComponentProviderModule, component: ReactElementWithProviderModule<P>): C {\n return ((componentProps: PropsWithModule<P>) => {\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n <ComponentRenderer module={moduleCtx} componentProps={componentProps} component={component as any} />\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n }) as any;\n}\n\nfunction _ComponentRenderer<P extends Record<string, any>>({\n module,\n component,\n componentProps,\n}: {\n module: IComponentProviderModule;\n component: ReactElementWithProviderModule<P>;\n componentProps: P;\n}) {\n return <>{component(forwardPropsWithModule(component, componentProps, module))}</>;\n}\n\nexport type ReactElementWithProviderModule<P extends Record<string, any>> = (p: PropsWithModule<P>) => React.ReactNode;\n","import { useMemo } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { useEffectOnce } from './use-effect-once';\n\nexport function useContextualizedModule(\n originalModule: IComponentProviderModule,\n forwardedModule?: IComponentProviderModule\n): IComponentProviderModule {\n const ctxModule = useMemo(() => {\n const module = (forwardedModule ?? originalModule).toNaked();\n\n if (module.isMarkedAsGlobal) return module;\n\n return module._createContextualizedComponentInstance();\n }, [originalModule, forwardedModule]);\n\n useEffectOnce(() => {\n return () => {\n ctxModule.dispose();\n };\n });\n\n return ctxModule;\n}\n","import { useEffect, useRef, useState } from 'react';\n\n// Credits: https://stackoverflow.com/a/74000921\n\n/** Custom {@link useEffect} hook which will be run once. _(In `StrictMode` as well)_ */\nexport function useEffectOnce(effect: () => React.EffectCallback) {\n const destroyFunc = useRef<React.EffectCallback>(undefined);\n const effectCalled = useRef(false);\n const renderAfterCalled = useRef(false);\n const [, forceRerender] = useState(0);\n\n if (effectCalled.current) renderAfterCalled.current = true;\n\n useEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect();\n effectCalled.current = true;\n }\n\n // this forces one render after the effect is run\n forceRerender((x) => x + 1);\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) return;\n\n destroyFunc.current?.();\n };\n }, []);\n}\n","import { isFunction } from '@adimm/x-injection';\n\nimport type { ReactElementWithProviderModule } from '../core';\nimport type { IComponentProviderModule, PropsWithModule } from '../types';\n\nexport function forwardPropsWithModule<P extends Record<string, any>>(\n component: ReactElementWithProviderModule<P> | React.ReactElement,\n props: Record<string, any>,\n module: IComponentProviderModule\n): PropsWithModule<P> {\n const isReactElement = typeof component === 'object' && 'type' in component;\n\n const result = {\n ...props,\n } as any;\n\n if ((isReactElement && isFunction(component.type)) || isFunction(component)) {\n result['module'] = module;\n }\n\n return result;\n}\n","import React, { useMemo } from 'react';\n\nimport { forwardPropsWithModule, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * function MyComponent({ firstName, lastName }: MyComponentProps) {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n *\n * function App() {\n * return (\n * <ProvideModule module={MyComponentModule}>\n * <MyComponent firstName={'John'} lastName={'Doe'} />\n * </ProvideModule>\n * );\n * }\n * ```\n *\n * @param param0 See {@link ProvideModuleFunctionParams}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function ProvideModule({ module, children }: ProvideModuleFunctionParams) {\n /* istanbul ignore next */\n const componentProps = (children.props ?? {}) as any;\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n const component = useMemo(\n () => React.cloneElement(children, forwardPropsWithModule(children, componentProps, moduleCtx)),\n [componentProps, moduleCtx]\n );\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n {component}\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n}\n\nexport interface ProvideModuleFunctionParams {\n /** The {@link IComponentProviderModule | Module} which should be consumed by the {@link children | component}. */\n module: IComponentProviderModule;\n\n children: React.ReactElement;\n}\n","import type { ProviderToken } from '@adimm/x-injection';\nimport { useMemo } from 'react';\n\nimport { InjectionHookFactoryError } from '../errors';\nimport { useComponentModule } from './hooks';\n\nexport function hookFactory<P extends HookParams, D extends any[], T>({\n use: hook,\n inject,\n}: HookFactoryParams<P, D, T>): (p: P) => T {\n return (p: P) => {\n const componentModule = useComponentModule();\n\n const deps = useMemo(() => {\n if (inject.length === 0) {\n throw new InjectionHookFactoryError(componentModule, `The 'deps' property array is missing!`);\n }\n\n return componentModule.getMany(...inject);\n }, [inject]);\n\n return hook({ ...p, deps: [...deps] } as any);\n };\n}\n\nexport interface HookFactoryParams<P extends HookParams, D extends any[], T> {\n use: HookWithProviderModuleDependencies<P, D, T>;\n inject: ProviderToken[];\n}\n\nexport type HookWithProviderModuleDependencies<P extends HookParams, D extends any[], T> = (p: HookWithDeps<P, D>) => T;\n\nexport type HookWithDeps<P extends HookParams, D extends any[]> = P & {\n /** Array containing the resolved dependencies from the component context. */\n deps: D;\n};\n\ntype HookParams = Record<string, any> | void;\n","import { InjectionProviderModuleError } from '@adimm/x-injection';\n\nexport class InjectionHookFactoryError extends InjectionProviderModuleError {\n override name = InjectionHookFactoryError.name;\n}\n"],"mappings":"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","names":["AppModule","createContext","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","useContext","useComponentModule","useContext","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","useInject","provider","options","componentModule","useComponentModule","get","isOptional","useInjectMany","deps","componentModule","useComponentModule","getMany","InjectionScope","ProviderModule","ProviderModuleHelpers","ComponentProviderModule","ProviderModule","_initializedFromComponent","constructor","options","ProviderModuleHelpers","buildInternalConstructorParams","defaultScope","InjectionScope","Singleton","identifier","Symbol","description","toNaked","clone","providers","providersMap","map","provider","clonedModule","isAppModule","markAsGlobal","isMarkedAsGlobal","replace","native","dynamicExports","onReady","onDispose","importedProvidersMap","imports","exports","dispose","_dispose","_createContextualizedComponentInstance","ctxModule","React","useMemo","useEffect","useRef","useState","useEffectOnce","effect","destroyFunc","useRef","undefined","effectCalled","renderAfterCalled","forceRerender","useState","current","useEffect","x","useContextualizedModule","originalModule","forwardedModule","ctxModule","useMemo","module","toNaked","isMarkedAsGlobal","_createContextualizedComponentInstance","useEffectOnce","dispose","isFunction","forwardPropsWithModule","component","props","module","isReactElement","result","isFunction","type","ComponentRenderer","React","memo","_ComponentRenderer","provideModuleToComponent","module","component","componentProps","moduleCtx","useContextualizedModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","forwardPropsWithModule","React","useMemo","ProvideModule","module","children","componentProps","props","moduleCtx","useContextualizedModule","component","useMemo","React","cloneElement","forwardPropsWithModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","useMemo","InjectionProviderModuleError","InjectionHookFactoryError","InjectionProviderModuleError","name","hookFactory","use","hook","inject","p","componentModule","useComponentModule","deps","useMemo","length","InjectionHookFactoryError","getMany"]}
1
+ {"version":3,"sources":["../src/core/react-context.ts","../src/core/hooks/use-component-module.ts","../src/core/hooks/use-inject.ts","../src/core/hooks/use-inject-many.ts","../src/core/component-provider-module.ts","../src/core/provide-module/provide-module.arrow-function.tsx","../src/helpers/hooks/use-contextualized-module.ts","../src/helpers/hooks/use-effect-once.ts","../src/helpers/component-provider-module.ts","../src/core/provide-module/provide-module.provider.tsx","../src/core/hook-factory.ts","../src/errors/hook-factory.ts"],"sourcesContent":["import { AppModule } from '@adimm/x-injection';\nimport { createContext } from 'react';\n\nimport type { IComponentProviderModule } from '../types';\n\nexport const REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT = createContext<IComponentProviderModule>(AppModule as any);\n","import { useContext } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/** Can be used to retrieve the {@link IComponentProviderModule} from the current context. */\nexport function useComponentModule(): IComponentProviderModule {\n return useContext(REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT);\n}\n","import type { ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve a single dependency from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectOptions}.\n * @returns The resolved {@link T | dependency}.\n */\nexport function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n const componentModule = useComponentModule();\n\n return componentModule.get(provider, options?.isOptional);\n}\n\nexport type UseInjectOptions = {\n /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */\n isOptional?: boolean;\n};\n","import type { ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderToken } from '@adimm/x-injection';\n\nimport { useComponentModule } from './use-component-module';\n\n/**\n * Low-level hook which can be used to resolve multiple dependencies at once from the current\n * context module.\n *\n * **Note:** _In order to better modularize your code-base, you should strive to create custom hooks by using the_\n * _`hookFactory` method to compose a custom hook._\n *\n * @param deps Either one or more {@link ProviderToken}.\n * @returns Tuple containing the {@link D | dependencies}.\n */\nexport function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>(\n ...deps: D | unknown[]\n): ProviderModuleGetManySignature<D> {\n const componentModule = useComponentModule();\n\n return componentModule.getMany(...deps);\n}\n","import {\n InjectionScope,\n ProviderModule,\n ProviderModuleHelpers,\n type IProviderModule,\n type IProviderModuleNaked,\n type ProviderModuleOptionsInternal,\n} from '@adimm/x-injection';\n\nimport type { ComponentProviderModuleOptions, IComponentProviderModule, IComponentProviderModuleNaked } from '../types';\n\n/** A superset of the {@link ProviderModule} used to integrate within a `React` component. */\nexport class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {\n protected readonly originalIdentifier: symbol;\n protected readonly hasContextualizedImports: IComponentProviderModuleNaked['hasContextualizedImports'];\n protected readonly initializedFromComponent: IComponentProviderModuleNaked['initializedFromComponent'];\n\n constructor(options: ComponentProviderModuleOptions) {\n const identifier = Symbol(`Component${options.identifier.description}`);\n const contextualizeImports = options.markAsGlobal ? false : options.contextualizeImports ?? true;\n const contextualizedImportsCache: Map<string, IProviderModule> | undefined = contextualizeImports\n ? new Map()\n : undefined;\n\n super(\n ProviderModuleHelpers.buildInternalConstructorParams({\n ...options,\n defaultScope: options.defaultScope ?? InjectionScope.Singleton,\n identifier: identifier,\n imports: !contextualizeImports\n ? options.imports\n : options.imports?.map((imp) => {\n const module = (typeof imp === 'function' ? imp() : imp) as IComponentProviderModuleNaked;\n /* istanbul ignore next */\n if (!contextualizeImports) return module;\n\n return () => {\n const ctxModule = module._createContextualizedComponentInstance(identifier);\n\n contextualizedImportsCache!.set(module.originalIdentifier.toString(), ctxModule);\n\n return ctxModule;\n };\n }),\n dynamicExports: (_, exports) => {\n if (!contextualizeImports) return exports;\n\n return exports.map((exp) => {\n if (!(exp instanceof ProviderModule)) return exp;\n\n const cachedCtxModule = contextualizedImportsCache!.get(\n (exp as unknown as IComponentProviderModuleNaked).originalIdentifier.toString()\n )!;\n\n return cachedCtxModule;\n });\n },\n })\n );\n\n this.originalIdentifier = options.identifier;\n this.hasContextualizedImports = contextualizeImports;\n this.initializedFromComponent = false;\n }\n\n override toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked {\n return this as any;\n }\n\n /* istanbul ignore next */\n override clone(options?: Partial<ComponentProviderModuleOptions>): IComponentProviderModule {\n const _options = options as ProviderModuleOptionsInternal;\n\n const clonedModule = new ComponentProviderModule(\n ProviderModuleHelpers.buildInternalConstructorParams({\n isAppModule: this.isAppModule,\n markAsGlobal: this.isMarkedAsGlobal,\n identifier: Symbol(this.identifier.description!.replace('Component', '')),\n defaultScope: this.defaultScope.native,\n dynamicExports: this.dynamicExports,\n onReady: this.onReady,\n onDispose: this.onDispose,\n contextualizeImports: this.hasContextualizedImports,\n importedProvidersMap: this.importedProvidersMap,\n imports: [...this.imports],\n providers: [...this.providers],\n exports: [...this.exports],\n ..._options,\n } as ComponentProviderModuleOptions)\n );\n\n //@ts-expect-error Read-only method.\n clonedModule.initializedFromComponent = this.initializedFromComponent;\n\n return clonedModule;\n }\n\n /* istanbul ignore next */\n override async dispose(): Promise<void> {\n await super.dispose();\n }\n\n //#region IComponentProviderModuleNaked methods\n\n /**\n * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**\n *\n * See {@link IComponentProviderModuleNaked._createContextualizedComponentInstance}.\n */\n protected _createContextualizedComponentInstance(parentIdentifier?: symbol): IComponentProviderModule {\n if (this.initializedFromComponent) return this;\n\n const ctxModule = this.clone().toNaked();\n\n /* istanbul ignore next */\n //@ts-expect-error Read-only property\n ctxModule.identifier = Symbol(\n `${parentIdentifier ? `[Parent:${parentIdentifier.description ?? 'Unknown'}]` : ''}Contextualized${ctxModule.identifier.description}`\n );\n ctxModule.initializedFromComponent = true;\n\n return ctxModule;\n }\n\n //#endregion\n}\n","import React from 'react';\n\nimport { ComponentProviderModuleHelpers, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule, PropsWithModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\nconst ComponentRenderer = React.memo(_ComponentRenderer);\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * export const MyComponent = provideModuleToComponent<MyComponentProps>(\n * MyComponentModule,\n * ({ firstName, lastName }) => {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n * );\n *\n * function App() {\n * return <MyComponent firstName={'John'} lastName={'Doe'} />;\n * }\n * ```\n *\n * @param module The {@link IComponentProviderModule | Module} which should be consumed by the {@link component}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function provideModuleToComponent<\n P extends Record<string, any>,\n C extends ReactElementWithProviderModule<P> = ReactElementWithProviderModule<P>,\n>(module: IComponentProviderModule, component: ReactElementWithProviderModule<P>): C {\n return ((componentProps: PropsWithModule<P>) => {\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n <ComponentRenderer module={moduleCtx} componentProps={componentProps} component={component as any} />\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n }) as any;\n}\n\nfunction _ComponentRenderer<P extends Record<string, any>>({\n module,\n component,\n componentProps,\n}: {\n module: IComponentProviderModule;\n component: ReactElementWithProviderModule<P>;\n componentProps: P;\n}) {\n return <>{component(ComponentProviderModuleHelpers.forwardPropsWithModule(component, componentProps, module))}</>;\n}\n\nexport type ReactElementWithProviderModule<P extends Record<string, any>> = (p: PropsWithModule<P>) => React.ReactNode;\n","import { useMemo } from 'react';\n\nimport type { IComponentProviderModule } from '../../types';\nimport { useEffectOnce } from './use-effect-once';\n\nexport function useContextualizedModule(\n originalModule: IComponentProviderModule,\n forwardedModule?: IComponentProviderModule\n): IComponentProviderModule {\n const ctxModule = useMemo(() => {\n const module = (forwardedModule ?? originalModule).toNaked();\n\n if (module.isMarkedAsGlobal) return module;\n\n return module._createContextualizedComponentInstance();\n }, [originalModule, forwardedModule]);\n\n useEffectOnce(() => {\n return () => {\n ctxModule.dispose();\n };\n });\n\n return ctxModule;\n}\n","import { useEffect, useRef, useState } from 'react';\n\n// Credits: https://stackoverflow.com/a/74000921\n\n/** Custom {@link useEffect} hook which will be run once. _(In `StrictMode` as well)_ */\nexport function useEffectOnce(effect: () => React.EffectCallback) {\n const destroyFunc = useRef<React.EffectCallback>(undefined);\n const effectCalled = useRef(false);\n const renderAfterCalled = useRef(false);\n const [, forceRerender] = useState(0);\n\n if (effectCalled.current) renderAfterCalled.current = true;\n\n useEffect(() => {\n // only execute the effect first time around\n if (!effectCalled.current) {\n destroyFunc.current = effect();\n effectCalled.current = true;\n }\n\n // this forces one render after the effect is run\n forceRerender((x) => x + 1);\n\n return () => {\n // if the comp didn't render since the useEffect was called,\n // we know it's the dummy React cycle\n if (!renderAfterCalled.current) return;\n\n destroyFunc.current?.();\n };\n }, []);\n}\n","import { isFunction } from '@adimm/x-injection';\n\nimport type { ReactElementWithProviderModule } from '../core';\nimport type { IComponentProviderModule, PropsWithModule } from '../types';\n\nexport namespace ComponentProviderModuleHelpers {\n export function forwardPropsWithModule<P extends Record<string, any>>(\n component: ReactElementWithProviderModule<P> | React.ReactElement,\n props: Record<string, any>,\n module: IComponentProviderModule\n ): PropsWithModule<P> {\n const isReactElement = typeof component === 'object' && 'type' in component;\n\n const result = {\n ...props,\n } as any;\n\n if ((isReactElement && isFunction(component.type)) || isFunction(component)) {\n result['module'] = module;\n }\n\n return result;\n }\n}\n","import React, { useMemo } from 'react';\n\nimport { ComponentProviderModuleHelpers, useContextualizedModule } from '../../helpers';\nimport type { IComponentProviderModule } from '../../types';\nimport { REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT } from '../react-context';\n\n/**\n * Can be used to easily provide a {@link module} to any component.\n *\n * @example\n * ```tsx\n * interface MyComponentProps {\n * firstName: string;\n * lastName: string;\n * }\n *\n * function MyComponent({ firstName, lastName }: MyComponentProps) {\n * const service = useInject(MyComponentService);\n *\n * return <h1>Hello {service.computeUserName(firstName, lastName)}!</h1>\n * }\n *\n * function App() {\n * return (\n * <ProvideModule module={MyComponentModule}>\n * <MyComponent firstName={'John'} lastName={'Doe'} />\n * </ProvideModule>\n * );\n * }\n * ```\n *\n * @param param0 See {@link ProvideModuleFunctionParams}.\n * @returns The provided {@link toComponent | Component}.\n */\nexport function ProvideModule({ module, children }: ProvideModuleFunctionParams) {\n /* istanbul ignore next */\n const componentProps = (children.props ?? {}) as any;\n const moduleCtx = useContextualizedModule(module, componentProps.module);\n const component = useMemo(\n () =>\n React.cloneElement(\n children,\n ComponentProviderModuleHelpers.forwardPropsWithModule(children, componentProps, moduleCtx)\n ),\n [componentProps, moduleCtx]\n );\n\n return (\n <REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider value={moduleCtx}>\n {component}\n </REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT.Provider>\n );\n}\n\nexport interface ProvideModuleFunctionParams {\n /** The {@link IComponentProviderModule | Module} which should be consumed by the {@link children | component}. */\n module: IComponentProviderModule;\n\n children: React.ReactElement;\n}\n","import type { ProviderToken } from '@adimm/x-injection';\nimport { useMemo } from 'react';\n\nimport { InjectionHookFactoryError } from '../errors';\nimport { useComponentModule } from './hooks';\n\nexport function hookFactory<P extends HookParams, D extends any[], T>({\n use: hook,\n inject,\n}: HookFactoryParams<P, D, T>): (p: P) => T {\n return (p: P) => {\n const componentModule = useComponentModule();\n\n const deps = useMemo(() => {\n if (inject.length === 0) {\n throw new InjectionHookFactoryError(componentModule, `The 'deps' property array is missing!`);\n }\n\n return componentModule.getMany(...inject);\n }, [inject]);\n\n return hook({ ...p, deps: [...deps] } as any);\n };\n}\n\nexport interface HookFactoryParams<P extends HookParams, D extends any[], T> {\n use: HookWithProviderModuleDependencies<P, D, T>;\n inject: ProviderToken[];\n}\n\nexport type HookWithProviderModuleDependencies<P extends HookParams, D extends any[], T> = (p: HookWithDeps<P, D>) => T;\n\nexport type HookWithDeps<P extends HookParams, D extends any[]> = P & {\n /** Array containing the resolved dependencies from the component context. */\n deps: D;\n};\n\ntype HookParams = Record<string, any> | void;\n","import { InjectionProviderModuleError } from '@adimm/x-injection';\n\nexport class InjectionHookFactoryError extends InjectionProviderModuleError {\n override name = InjectionHookFactoryError.name;\n}\n"],"mappings":"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","names":["AppModule","createContext","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","useContext","useComponentModule","useContext","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","useInject","provider","options","componentModule","useComponentModule","get","isOptional","useInjectMany","deps","componentModule","useComponentModule","getMany","InjectionScope","ProviderModule","ProviderModuleHelpers","ComponentProviderModule","ProviderModule","originalIdentifier","hasContextualizedImports","initializedFromComponent","constructor","options","identifier","Symbol","description","contextualizeImports","markAsGlobal","contextualizedImportsCache","Map","undefined","ProviderModuleHelpers","buildInternalConstructorParams","defaultScope","InjectionScope","Singleton","imports","map","imp","module","ctxModule","_createContextualizedComponentInstance","set","toString","dynamicExports","_","exports","exp","cachedCtxModule","get","toNaked","clone","_options","clonedModule","isAppModule","isMarkedAsGlobal","replace","native","onReady","onDispose","importedProvidersMap","providers","dispose","parentIdentifier","React","useMemo","useEffect","useRef","useState","useEffectOnce","effect","destroyFunc","useRef","undefined","effectCalled","renderAfterCalled","forceRerender","useState","current","useEffect","x","useContextualizedModule","originalModule","forwardedModule","ctxModule","useMemo","module","toNaked","isMarkedAsGlobal","_createContextualizedComponentInstance","useEffectOnce","dispose","isFunction","ComponentProviderModuleHelpers","forwardPropsWithModule","component","props","module","isReactElement","result","isFunction","type","ComponentRenderer","React","memo","_ComponentRenderer","provideModuleToComponent","module","component","componentProps","moduleCtx","useContextualizedModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","ComponentProviderModuleHelpers","forwardPropsWithModule","React","useMemo","ProvideModule","module","children","componentProps","props","moduleCtx","useContextualizedModule","component","useMemo","React","cloneElement","ComponentProviderModuleHelpers","forwardPropsWithModule","REACT_X_INJECTION_PROVIDER_MODULE_CONTEXT","Provider","value","useMemo","InjectionProviderModuleError","InjectionHookFactoryError","InjectionProviderModuleError","name","hookFactory","use","hook","inject","p","componentModule","useComponentModule","deps","useMemo","length","InjectionHookFactoryError","getMany"]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@adimm/x-injection-reactjs",
3
3
  "description": "ReactJS integration of the `xInjection` library.",
4
- "version": "0.2.4",
4
+ "version": "0.3.0",
5
5
  "author": "Adi-Marian Mutu",
6
6
  "homepage": "https://github.com/AdiMarianMutu/x-injection-reactjs#readme",
7
7
  "bugs": "https://github.com/AdiMarianMutu/x-injection-reactjs/issues",
@@ -38,7 +38,7 @@
38
38
  "v:bump-major": "npm version major -m \"chore: update lib major version %s\""
39
39
  },
40
40
  "dependencies": {
41
- "@adimm/x-injection": "^0.6.4",
41
+ "@adimm/x-injection": "^0.7.0",
42
42
  "react": ">=18.0.0"
43
43
  },
44
44
  "devDependencies": {