@adimm/x-injection-reactjs 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Adi-Marian Mutu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,226 @@
1
+ <h1 align="center">
2
+ xInjection ReactJS&nbsp;<a href="https://www.npmjs.com/package/@adimm/x-injection-reactjs" target="__blank" alt="Release Version"><img src="https://img.shields.io/npm/v/@adimm/x-injection-reactjs?color=0476bc&label="></a>
3
+ <img src="https://flat.badgen.net/npm/license/@adimm/x-injection-reactjs" alt="License">
4
+ </h1>
5
+
6
+ <p align="center">
7
+ <a href="https://github.com/AdiMarianMutu/x-injection-reactjs/actions/workflows/ci.yml?query=branch%3Amain" target="__blank"><img src="https://github.com/AdiMarianMutu/x-injection-reactjs/actions/workflows/ci.yml/badge.svg?branch=main"></a>
8
+ <a href="https://github.com/AdiMarianMutu/x-injection-reactjs/actions/workflows/publish.yml" target="__blank"><img src="https://github.com/AdiMarianMutu/x-injection-reactjs/actions/workflows/publish.yml/badge.svg"></a>
9
+ <br>
10
+ <img src="https://flat.badgen.net/bundlephobia/minzip/@adimm/x-injection-reactjs">
11
+ <a href="https://www.npmjs.com/package/@adimm/x-injection-reactjs" target="__blank" alt="Monthly Downloads"><img src="https://flat.badgen.net/npm/dm/@adimm/x-injection-reactjs"></a>
12
+ </p>
13
+
14
+ ## Table of Contents
15
+
16
+ - [Table of Contents](#table-of-contents)
17
+ - [Overview](#overview)
18
+ - [Installation](#installation)
19
+ - [TypeScript Configuration](#typescript-configuration)
20
+ - [Getting Started](#getting-started)
21
+ - [Examples](#examples)
22
+ - [Component with private context](#component-with-private-context)
23
+ - [Component with public context](#component-with-public-context)
24
+ - [Safe method](#safe-method)
25
+ - [Experimental method](#experimental-method)
26
+ - [Documentation](#documentation)
27
+ - [Contributing](#contributing)
28
+
29
+ ## Overview
30
+
31
+ **xInjection** is a robust Inversion of Control [(IoC)](https://en.wikipedia.org/wiki/Inversion_of_control) library that extends [InversifyJS](https://github.com/inversify/InversifyJS) with a modular, [NestJS](https://github.com/nestjs/nest)-inspired Dependency Injection [(DI)](https://en.wikipedia.org/wiki/Dependency_injection) system. It enables you to **encapsulate** dependencies with fine-grained control using **[ProviderModule](https://adimarianmutu.github.io/x-injection/classes/ProviderModule.html)** classes, allowing for clean **separation** of concerns and **scalable** architecture.
32
+
33
+ Each `ProviderModule` manages its _own_ container, supporting easy **decoupling** and _explicit_ control over which providers are **exported** and **imported** across modules. The global **[AppModule](https://adimarianmutu.github.io/x-injection/variables/AppModule.html)** is always available, ensuring a seamless foundation for your application's DI needs.
34
+
35
+ > For more details and info please access the [xInjection](https://github.com/AdiMarianMutu/x-injection) library repository.
36
+
37
+ ## Installation
38
+
39
+ First, ensure you have [`reflect-metadata`](https://www.npmjs.com/package/reflect-metadata) installed:
40
+
41
+ ```sh
42
+ npm i reflect-metadata
43
+ ```
44
+
45
+ Then install `xInjection` for React:
46
+
47
+ ```sh
48
+ npm i @adimm/x-injection-reactjs
49
+ ```
50
+
51
+ > You may also have to install the parent library via `npm i @adimm/x-injection`
52
+
53
+ ### TypeScript Configuration
54
+
55
+ Add the following options to your `tsconfig.json` to enable decorator metadata:
56
+
57
+ ```json
58
+ {
59
+ "compilerOptions": {
60
+ "experimentalDecorators": true,
61
+ "emitDecoratorMetadata": true
62
+ }
63
+ }
64
+ ```
65
+
66
+ ## Getting Started
67
+
68
+ If you never used the parent library (`xInjection`), then please access the official [xInjection Repository](https://github.com/AdiMarianMutu/x-injection?tab=readme-ov-file#registering-global-providers) to better understand how to use its `ReactJS` implementation.
69
+
70
+ ## Examples
71
+
72
+ ### Component with private context
73
+
74
+ A component with a private context it means that when it'll inject dependencies from a module within its instance,
75
+ a parent component will not be able to access those dependencies instances.
76
+
77
+ ```tsx
78
+ export class RandomNumberService {
79
+ generate(): number {
80
+ /* ... */
81
+ }
82
+ }
83
+
84
+ // Make sure to use the `ComponentProviderModule` from `@adimm/x-injection-reactjs` not the `ProviderModule` from `@adimm/x-injection`!
85
+ export const RandomNumberComponentModule = new ComponentProviderModule({
86
+ identifier: Symbol('RandomNumberComponentModule'),
87
+ providers: [RandomNumberService],
88
+ });
89
+
90
+ export function RandomNumberComponent(props: RandomNumberComponentProps) {
91
+ const service = useInject(RandomNumberService);
92
+
93
+ return <h1>A random number: {service.generate()}</h1>;
94
+ }
95
+ ```
96
+
97
+ ### Component with public context
98
+
99
+ #### Safe method
100
+
101
+ ```tsx
102
+ export class RandomNumberService {
103
+ generate(): number {
104
+ /* ... */
105
+ }
106
+ }
107
+
108
+ // Make sure to use the `ComponentProviderModule` from `@adimm/x-injection-reactjs` not the `ProviderModule` from `@adimm/x-injection`!
109
+ export const RandomNumberComponentModule = new ComponentProviderModule({
110
+ identifier: Symbol('RandomNumberComponentModule'),
111
+ providers: [RandomNumberService],
112
+ exports: [RandomNumberService],
113
+ });
114
+
115
+ export function RandomNumberComponent(props: RandomNumberComponentProps) {
116
+ // This hook is necessary in order to expose the component instance
117
+ // context up to the parent component
118
+ useExposeComponentModuleContext();
119
+
120
+ const service = useInject(RandomNumberService);
121
+
122
+ return <h1>A random number: {service.generate()}</h1>;
123
+ }
124
+
125
+ ////////////////////////////////////////
126
+
127
+ export class ParentService {
128
+ constructor(public readonly randomNumberService: RandomNumberService) {}
129
+
130
+ injectRandomNumberService(service: RandomNumberService): void {
131
+ this.randomNumberService = service;
132
+ }
133
+ }
134
+
135
+ export const ParentServiceComponentModule = new ComponentProviderModule({
136
+ identifier: Symbol('ParentServiceComponentModule'),
137
+ imports: [RandomNumberComponentModule],
138
+ providers: [ParentService],
139
+ });
140
+
141
+ export function ParentComponent(props: ParentComponentProps) {
142
+ const service = useInject(ParentService);
143
+
144
+ return (
145
+ <>
146
+ <TapIntoComponent
147
+ // By using the fluid syntax
148
+ contextInstance={() => ({
149
+ // If one of the children did expose the `RandomNumberComponentModule`
150
+ // module, we'll be able to access its instance.
151
+ tryGet: RandomNumberComponentModule,
152
+ thenDo: (ctx) => {
153
+ const randomNumberService_FromComponentInstance = ctx.get(RandomNumberComponentModule);
154
+
155
+ service.injectRandomNumberService(randomNumberService_FromComponentInstance);
156
+ },
157
+ })}>
158
+ <RandomNumberComponent />
159
+ </TapIntoComponent>
160
+
161
+ <TapIntoComponent
162
+ // By accessing the entire underlying context map which may contain even more
163
+ // modules exposed by more children down the tree.
164
+ contextInstance={(ctxMap) => {
165
+ const ctx = ctxMap.get(RandomNumberComponentModule.toString());
166
+ if (!ctx) return;
167
+
168
+ const randomNumberService_FromComponentInstance = ctx.get(RandomNumberComponentModule);
169
+
170
+ service.injectRandomNumberService(randomNumberService_FromComponentInstance);
171
+ }}>
172
+ <RandomNumberComponent />
173
+ </TapIntoComponent>
174
+ </>
175
+ );
176
+ }
177
+ ```
178
+
179
+ #### Experimental method
180
+
181
+ There is another method which is currently in _experimental_ mode and it may not always work as expected, it may even produce unnecessary re-render cycles
182
+ or introduce unknown bugs, please use it carefully and with diligence!
183
+
184
+ ```tsx
185
+ export function ParentComponent(props: ParentComponentProps) {
186
+ // By using this hook, the component will always re-render whenever
187
+ // a child using a ProviderModule which is also imported into the parent ProviderModule,
188
+ // has mounted and rendered!
189
+ useRerenderOnChildrenModuleContextLoaded();
190
+
191
+ // We should use the `useInjectOnRender` instead of the default `useInject`
192
+ // hook which re-uses the same instance of the injected dependency
193
+ // between re-renders.
194
+ //
195
+ // Note: It may still work with the `useInject` hook too, but it may not be predictable.
196
+ const service = useInjectOnRender(ParentService);
197
+
198
+ // At this point the `service.randomNumberService` instance should be the one
199
+ // from the `RandomNumberComponent` below.
200
+ //
201
+ // Note: Expect during the 1st render cycle to not be the same instance as the one used by the child component!
202
+ // The `xInjection` container will still supply the correct provider to the
203
+ // constructor parameter, but it'll be a new transient instance.
204
+ console.log(service.randomNumberService.generate());
205
+
206
+ // As we are now using the `useRerenderOnChildrenModuleContextLoaded` hook
207
+ // there's no need anymore for the `TapIntoComponent` wrapper.
208
+ return <RandomNumberComponent />;
209
+ }
210
+ ```
211
+
212
+ ## Documentation
213
+
214
+ Comprehensive, auto-generated documentation is available at:
215
+
216
+ 👉 [https://adimarianmutu.github.io/x-injection-reactjs/index.html](https://adimarianmutu.github.io/x-injection-reactjs/index.html)
217
+
218
+ ## Contributing
219
+
220
+ Pull requests are warmly welcomed! 😃
221
+
222
+ Please ensure your contributions adhere to the project's code style. See the repository for more details.
223
+
224
+ ---
225
+
226
+ > For questions, feature requests, or bug reports, feel free to open an [issue](https://github.com/AdiMarianMutu/x-injection-reactjs/issues) on GitHub!
package/dist/index.cjs ADDED
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+
3
+ var e, t = Object.defineProperty, n = Object.getOwnPropertyDescriptor, o = Object.getOwnPropertyNames, r = Object.prototype.hasOwnProperty, i = (e, n) => t(e, "name", {
4
+ value: n,
5
+ configurable: !0
6
+ }), u = {};
7
+
8
+ ((e, n) => {
9
+ for (var o in n) t(e, o, {
10
+ get: n[o],
11
+ enumerable: !0
12
+ });
13
+ })(u, {
14
+ ComponentProviderModule: () => S,
15
+ ModuleProvider: () => M,
16
+ REACT_X_INJECTION_CONTEXT: () => m,
17
+ REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT: () => f,
18
+ REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE: () => O,
19
+ TapIntoComponent: () => b,
20
+ useExposeComponentModuleContext: () => h,
21
+ useInject: () => E,
22
+ useInjectMany: () => N,
23
+ useInjectManyOnRender: () => R,
24
+ useInjectOnRender: () => v,
25
+ useRerenderOnChildrenModuleContextLoaded: () => y
26
+ }), module.exports = (e = u, ((e, i, u, s) => {
27
+ if (i && "object" == typeof i || "function" == typeof i) for (let c of o(i)) r.call(e, c) || c === u || t(e, c, {
28
+ get: () => i[c],
29
+ enumerable: !(s = n(i, c)) || s.enumerable
30
+ });
31
+ return e;
32
+ })(t({}, "__esModule", {
33
+ value: !0
34
+ }), e));
35
+
36
+ var s = require("react");
37
+
38
+ function c(e) {
39
+ const t = (0, s.useRef)(null);
40
+ return null === t.current && (t.current = {
41
+ value: e()
42
+ }), t.current?.value;
43
+ }
44
+
45
+ i(c, "useOnce");
46
+
47
+ var a = require("react");
48
+
49
+ function d(e) {
50
+ const t = (0, a.useRef)(void 0), n = (0, a.useRef)(!1), o = (0, a.useRef)(!1), [, r] = (0,
51
+ a.useState)(0);
52
+ n.current && (o.current = !0), (0, a.useEffect)((() => (n.current || (t.current = e(),
53
+ n.current = !0), r((e => e + 1)), () => {
54
+ o.current && t.current?.();
55
+ })), []);
56
+ }
57
+
58
+ i(d, "useEffectOnce");
59
+
60
+ var l = require("react"), p = require("@adimm/x-injection"), C = require("react"), m = (0,
61
+ C.createContext)(p.AppModule), f = (0, C.createContext)(new Map), O = (0, C.createContext)({
62
+ r: 0
63
+ }), x = require("react");
64
+
65
+ function M({children: e, module: t, tryReInitModuleOnMount: n, disposeModuleOnUnmount: o}) {
66
+ const r = t.toNaked().isAppModule, i = {
67
+ ctx: (0, x.useMemo)((() => r ? t : t.toNaked()._convertToContextualizedComponentInstance()), [ e, t, n, o ])
68
+ };
69
+ return React.createElement(m.Provider, {
70
+ value: i
71
+ }, React.createElement(O.Provider, {
72
+ value: {
73
+ r: 0
74
+ }
75
+ }, React.createElement(_, {
76
+ children: e,
77
+ module: i,
78
+ tryReInitModuleOnMount: n,
79
+ disposeModuleOnUnmount: o
80
+ })));
81
+ }
82
+
83
+ function _({children: e, module: t, tryReInitModuleOnMount: n, disposeModuleOnUnmount: o = !1}) {
84
+ const r = (0, x.useContext)(f), i = (0, x.useContext)(O);
85
+ return d((() => {
86
+ const e = t.ctx.toNaked();
87
+ if (r) {
88
+ const e = t.ctx.toNaked().imports.map((e => r.get(e.toString())?.toString() === e.toString() ? r.get(e.toString()) : e));
89
+ e.length > 0 && (t.ctx.toNaked()._lazyInit({
90
+ ...t.ctx.toNaked()._initialOptions,
91
+ imports: e
92
+ }), i.r++);
93
+ }
94
+ return e.isDisposed && n && e._lazyInit(n), () => {
95
+ o && !e.isDisposed && e._dispose();
96
+ };
97
+ })), e;
98
+ }
99
+
100
+ function v(e, t) {
101
+ return (0, l.useContext)(m).ctx.get(e, t?.isOptional);
102
+ }
103
+
104
+ function E(e, t) {
105
+ return c((() => v(e, t)));
106
+ }
107
+
108
+ i(M, "ModuleProvider"), i(_, "XInjectionChildrenRenderer"), i(v, "useInjectOnRender"),
109
+ i(E, "useInject");
110
+
111
+ var I = require("react");
112
+
113
+ function R({deps: e}) {
114
+ return (0, I.useContext)(m).ctx.getMany(...e);
115
+ }
116
+
117
+ function N({deps: e, options: t}) {
118
+ return c((() => R({
119
+ options: t,
120
+ deps: e
121
+ })));
122
+ }
123
+
124
+ i(R, "useInjectManyOnRender"), i(N, "useInjectMany");
125
+
126
+ var g = require("react");
127
+
128
+ function h() {
129
+ const e = (0, g.useContext)(m);
130
+ (0, g.useContext)(f).set(e.ctx.toString(), e.ctx);
131
+ }
132
+
133
+ i(h, "useExposeComponentModuleContext");
134
+
135
+ var j = require("react");
136
+
137
+ function y() {
138
+ const e = (0, j.useContext)(O), [, t] = (0, j.useState)(0);
139
+ (0, j.useEffect)((() => {
140
+ t((e => e + 1));
141
+ }), [ e.r ]);
142
+ }
143
+
144
+ i(y, "useRerenderOnChildrenModuleContextLoaded");
145
+
146
+ var P = require("@adimm/x-injection"), S = class e extends P.ProviderModule {
147
+ static {
148
+ i(this, "ComponentProviderModule");
149
+ }
150
+ _initializedFromComponent;
151
+ _initialOptions;
152
+ constructor(e) {
153
+ super(P.ProviderModuleHelpers.buildInternalConstructorParams({
154
+ ...e,
155
+ defaultScope: e.defaultScope ?? P.InjectionScope.Transient,
156
+ identifier: Symbol(`Component${e.identifier.description}`)
157
+ })), this._initializedFromComponent = !1, this._initialOptions = e;
158
+ }
159
+ toNaked() {
160
+ return this;
161
+ }
162
+ dispose() {
163
+ this._dispose();
164
+ }
165
+ _convertToContextualizedComponentInstance() {
166
+ if (this.isAppModule || this.isDisposed) return this;
167
+ const t = this._getProviders().map((e => (0, P.isClassOrFunction)(e) ? (0, P.isClass)(e) ? {
168
+ scope: P.InjectionScope.Singleton,
169
+ provide: e,
170
+ useClass: e
171
+ } : {
172
+ provide: e,
173
+ useValue: e
174
+ } : {
175
+ ...e,
176
+ scope: P.InjectionScope.Singleton
177
+ })), n = new e({
178
+ ...this._initialOptions,
179
+ providers: t
180
+ });
181
+ return n._initializedFromComponent = !0, n;
182
+ }
183
+ }, T = require("react");
184
+
185
+ function b({children: e, contextInstance: t}) {
186
+ const n = (0, T.useMemo)((() => new Map), []);
187
+ return React.createElement(f.Provider, {
188
+ value: n
189
+ }, React.createElement(q, {
190
+ contextInstance: t
191
+ }), e);
192
+ }
193
+
194
+ function q({contextInstance: e}) {
195
+ const t = (0, T.useContext)(f);
196
+ return (0, T.useEffect)((() => {
197
+ const n = e?.(t);
198
+ if (!n) return;
199
+ const o = t.get(n.tryGet.toString());
200
+ o && n.thenDo(o);
201
+ }), [ t ]), null;
202
+ }
203
+
204
+ i(b, "TapIntoComponent"), i(q, "CtxExposer");//# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/helpers/hooks/use-once.ts","../src/helpers/hooks/use-effect-once.ts","../src/core/hooks/use-inject-on-render.ts","../src/core/providers/module-provider/react-context.ts","../src/core/providers/module-provider/module.provider.tsx","../src/core/hooks/use-inject.ts","../src/core/hooks/use-inject-many-on-render.ts","../src/core/hooks/use-inject-many.ts","../src/core/hooks/use-expose-component-module-context.ts","../src/core/hooks/use-rerender-on-children-module-context-loaded.ts","../src/core/component-provider-module.ts","../src/core/utils/tap-into-component-context/tap-into-component-context.tsx"],"sourcesContent":["export * from './core';\nexport type * from './types';\n","import { useRef } from 'react';\n\nexport function useOnce<T>(fn: () => T): T {\n const ref = useRef<OnceValue<T> | null>(null);\n\n if (ref.current === null) {\n ref.current = { value: fn() };\n }\n\n return ref.current?.value;\n}\n\ntype OnceValue<T> = { value: T };\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 type { ProviderToken } from '@adimm/x-injection';\nimport { useContext } from 'react';\n\nimport type { UseInjectSharedOptions } from '../../types';\nimport { REACT_X_INJECTION_CONTEXT } from '../providers';\n\n/**\n * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.\n *\n * **Note:** _By using this hook, the dependency will be injected on each re-render process._\n * _If you need to inject the dependency only once, you must use the `useInject` hook._\n * _It basically acts like a `Transient` scope, ensuring that a new dependency is injected on each re-render._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectSharedOptions}.\n * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.\n */\nexport function useInjectOnRender<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n const componentModule = useContext(REACT_X_INJECTION_CONTEXT);\n\n return componentModule.ctx.get(provider, options?.isOptional);\n}\n\nexport type UseInjectOptions = UseInjectSharedOptions & {\n /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */\n isOptional?: boolean;\n};\n","import { AppModule } from '@adimm/x-injection';\nimport { createContext } from 'react';\n\nimport type { IComponentProviderModule } from '../../../types';\n\n/**\n * The `React.Context` value to be provided to a `React.Provider`.\n *\n * Its default value is a reference to the {@link AppModule}.\n */\nexport const REACT_X_INJECTION_CONTEXT = createContext<{ ctx: IComponentProviderModule }>(AppModule as any);\n\nexport const REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT = createContext<Map<string, IComponentProviderModule>>(\n new Map()\n);\n\nexport const REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE = createContext<{ r: number }>({ r: 0 });\n","import { useContext, useMemo } from 'react';\nimport type { Except } from 'type-fest';\n\nimport { useEffectOnce } from '../../../helpers';\nimport type { IComponentProviderModule, IComponentProviderModuleNaked } from '../../../types';\nimport type { ModuleProviderProps } from './models';\nimport {\n REACT_X_INJECTION_CONTEXT,\n REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT,\n REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE,\n} from './react-context';\n\nexport function ModuleProvider({\n children,\n module,\n tryReInitModuleOnMount,\n disposeModuleOnUnmount,\n}: ModuleProviderProps) {\n const isAppModule = module.toNaked().isAppModule;\n\n const moduleCtxReference = {\n ctx: useMemo(() => {\n return isAppModule ? module : module.toNaked()._convertToContextualizedComponentInstance();\n }, [children, module, tryReInitModuleOnMount, disposeModuleOnUnmount]),\n };\n\n return (\n <REACT_X_INJECTION_CONTEXT.Provider value={moduleCtxReference}>\n <REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE.Provider value={{ r: 0 }}>\n <XInjectionChildrenRenderer\n children={children}\n module={moduleCtxReference}\n tryReInitModuleOnMount={tryReInitModuleOnMount}\n disposeModuleOnUnmount={disposeModuleOnUnmount}\n />\n </REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE.Provider>\n </REACT_X_INJECTION_CONTEXT.Provider>\n );\n}\n\nfunction XInjectionChildrenRenderer({\n children,\n module,\n tryReInitModuleOnMount,\n disposeModuleOnUnmount = false,\n}: Except<ModuleProviderProps, 'module'> & { module: { ctx: IComponentProviderModule } }) {\n const componentModuleInstance = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT);\n const rerenderParentCtx = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE);\n\n // We use the `useEffectOnce` custom hook in order\n // to make sure that if the developer is providing the\n // `tryReInitModuleOnMount` and/or `disposeModuleOnUnmount` options\n // we do not early dispose the module when React double re-renders the\n // component while StrictMode is enabled.\n // This hook guarantees that the same behavior is expected with or without StrictMode.\n //\n // https://react.dev/reference/react/StrictMode\n useEffectOnce(() => {\n // ON MOUNT\n\n const moduleNaked = module.ctx.toNaked();\n\n if (componentModuleInstance) {\n const contextualizedImportedModules = module.ctx.toNaked().imports.map((importedModule) => {\n const shouldReplaceImportedModuleWithContextualized =\n componentModuleInstance.get(importedModule.toString())?.toString() === importedModule.toString();\n\n /* istanbul ignore next */\n if (!shouldReplaceImportedModuleWithContextualized)\n return importedModule as unknown as IComponentProviderModuleNaked;\n\n return componentModuleInstance.get(importedModule.toString()) as IComponentProviderModuleNaked;\n });\n\n if (contextualizedImportedModules.length > 0) {\n module.ctx.toNaked()._lazyInit({\n ...module.ctx.toNaked()._initialOptions,\n imports: contextualizedImportedModules,\n });\n\n // This will force the parent to re-render when using the `useRerenderOnChildrenModuleContextLoaded` hook.\n rerenderParentCtx.r++;\n }\n }\n\n /* istanbul ignore next */\n if (moduleNaked.isDisposed && tryReInitModuleOnMount) {\n /* istanbul ignore next */\n moduleNaked._lazyInit(tryReInitModuleOnMount);\n }\n\n return () => {\n // ON UNMOUNT\n\n if (!disposeModuleOnUnmount || moduleNaked.isDisposed) return;\n\n moduleNaked._dispose();\n };\n });\n\n return children;\n}\n","import type { ProviderToken } from '@adimm/x-injection';\n\nimport { useOnce } from '../../helpers';\nimport { useInjectOnRender, type UseInjectOptions } from './use-inject-on-render';\n\n/**\n * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.\n *\n * **Note:** _By using this hook, the dependency will be injected only once after the first component mount process._\n * _If you need to re-inject the dependency on each re-render, you must use the `useInjectOnRender` hook._\n * _It basically acts like a `Request` scope, ensuring that even a `Transient` dependency does not mutate during re-renders._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectSharedOptions}.\n * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.\n */\nexport function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n return useOnce(() => useInjectOnRender(provider, options));\n}\n","import type {\n ProviderModuleGetManyParam,\n ProviderModuleGetManySignature,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ProviderToken,\n} from '@adimm/x-injection';\nimport { useContext } from 'react';\n\nimport type { UseInjectSharedOptions } from '../../types';\nimport { REACT_X_INJECTION_CONTEXT } from '../providers';\n\n/**\n * Can be used to retrieve many resolved `dependencies` from the module container at once.\n *\n * **Note:** _By using this hook, the dependencies will be injected on each re-render process._\n * _If you need to inject the dependencies only once, you must use the `useInjectMany` hook._\n *\n * @param options See {@link UseInjectSharedOptions}.\n * @param deps Either one or more {@link ProviderToken}.\n * @returns Tuple containing the {@link D | dependencies}.\n */\nexport function useInjectManyOnRender<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({\n deps,\n}: {\n deps: [...(D | unknown[])];\n options?: UseInjectSharedOptions;\n}): ProviderModuleGetManySignature<D> {\n const componentModule = useContext(REACT_X_INJECTION_CONTEXT);\n\n return componentModule.ctx.getMany(...deps);\n}\n","import type { ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderToken } from '@adimm/x-injection';\n\nimport { useOnce } from '../../helpers';\nimport type { UseInjectSharedOptions } from '../../types';\nimport { useInjectManyOnRender } from './use-inject-many-on-render';\n\n/**\n * Can be used to retrieve many resolved `dependencies` from the module container at once.\n *\n * **Note:** _By using this hook, the dependencies will be injected only once after the first component mount process._\n * _If you need to re-inject the dependencies on each re-render, you must use the `useInjectManyOnRender` hook._\n *\n * @param options See {@link UseInjectSharedOptions}.\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,\n options,\n}: {\n deps: [...(D | unknown[])];\n options?: UseInjectSharedOptions;\n}): ProviderModuleGetManySignature<D> {\n return useOnce(() => useInjectManyOnRender({ options, deps }));\n}\n","import { useContext } from 'react';\n\nimport { REACT_X_INJECTION_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT } from '../providers';\n\nexport function useExposeComponentModuleContext(): void {\n const componentModule = useContext(REACT_X_INJECTION_CONTEXT);\n const exposed = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT);\n\n exposed.set(componentModule.ctx.toString(), componentModule.ctx);\n}\n","import { useContext, useEffect, useState } from 'react';\n\nimport { REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE } from '../providers';\n\n/**\n * This is an **experimental** hook which can be used to make sure that a component will re-render when a children\n * exposes its internal context module.\n *\n * It works best with the `useInjectOnRender` hook, as it'll re-resolve all the required dependencies\n * of the injected ProviderToken.\n *\n * **Use it carefully as it may lead to unnecessary re-render cycles or it may even not work as expected!**\n * **It's safer to use the `TapIntoComponent` wrapper component with the `contextInstance` to manually inject the**\n * **contextualized dependencies of the children into a parent component service!**\n *\n * @experimental\n */\nexport function useRerenderOnChildrenModuleContextLoaded(): void {\n const rerenderParentCtx = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE);\n const [, setRerender] = useState(0);\n\n useEffect(() => {\n setRerender((x) => x + 1);\n }, [rerenderParentCtx.r]);\n}\n","import {\n InjectionScope,\n isClass,\n isClassOrFunction,\n ProviderModule,\n ProviderModuleHelpers,\n type DependencyProvider,\n type IProviderModuleNaked,\n type ProviderClassToken,\n type ProviderModuleOptions,\n type ProviderValueToken,\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 protected readonly _initialOptions: IComponentProviderModuleNaked['_initialOptions'];\n\n constructor(options: ProviderModuleOptions) {\n super(\n ProviderModuleHelpers.buildInternalConstructorParams({\n ...options,\n // By default components should have all their providers\n // defined as transient because a component may have more than one instance of itself.\n defaultScope: options.defaultScope ?? InjectionScope.Transient,\n identifier: Symbol(`Component${options.identifier.description}`),\n })\n );\n\n this._initializedFromComponent = false;\n this._initialOptions = options;\n }\n\n override toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked {\n return this as any;\n }\n\n /* istanbul ignore next */\n dispose(): void {\n this._dispose();\n }\n\n /**\n * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**\n *\n * See {@link IComponentProviderModuleNaked._convertToContextualizedComponentInstance}.\n */\n /* istanbul ignore next */\n protected _convertToContextualizedComponentInstance(): IComponentProviderModule {\n if (this.isAppModule || this.isDisposed) return this;\n\n const contextualizedProviders = this._getProviders().map((provider) => {\n if (!isClassOrFunction(provider)) {\n return {\n ...provider,\n scope: InjectionScope.Singleton,\n } as DependencyProvider;\n }\n\n if (isClass(provider)) {\n return {\n scope: InjectionScope.Singleton,\n provide: provider,\n useClass: provider,\n } as ProviderClassToken<any>;\n }\n\n return {\n provide: provider,\n useValue: provider,\n } as ProviderValueToken<any>;\n });\n\n const componentModule = new ComponentProviderModule({\n ...this._initialOptions,\n providers: contextualizedProviders,\n });\n\n //@ts-expect-error Read-only property.\n componentModule._initializedFromComponent = true;\n\n return componentModule;\n }\n}\n","import { useContext, useEffect, useMemo } from 'react';\nimport type { Except } from 'type-fest';\n\nimport { REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT } from '../../providers';\nimport type { TapIntoComponentContextProps } from './interfaces';\n\n/**\n * This component is the standard way to \"tap into\" an instance of the component\n * in order to get access to its scoped module container and its _(exposed)_ dependencies _instances_.\n *\n * @param contextInstance See {@link TapIntoComponentContextProps.contextInstance}.\n * @param exposed See {@link TapIntoComponentContextProps.exposed}.\n */\nexport function TapIntoComponent({ children, contextInstance }: TapIntoComponentContextProps) {\n const moduleContextMap = useMemo(() => new Map(), []);\n\n return (\n <REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT.Provider value={moduleContextMap}>\n <CtxExposer contextInstance={contextInstance} />\n {children}\n </REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT.Provider>\n );\n}\n\nfunction CtxExposer({ contextInstance }: Except<TapIntoComponentContextProps, 'children'>) {\n const ctxMap = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT);\n\n useEffect(() => {\n const fluidSyntax = contextInstance?.(ctxMap);\n if (!fluidSyntax) return;\n\n const moduleCtx = ctxMap.get(fluidSyntax.tryGet.toString());\n /* istanbul ignore next */\n if (!moduleCtx) return;\n\n fluidSyntax.thenDo(moduleCtx);\n }, [ctxMap]);\n\n return null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;;;;ACAA,mBAAuB;AAEhB,SAASA,QAAWC,IAAW;AACpC,QAAMC,UAAMC,qBAA4B,IAAA;AAExC,MAAID,IAAIE,YAAY,MAAM;AACxBF,QAAIE,UAAU;MAAEC,OAAOJ,GAAAA;IAAK;EAC9B;AAEA,SAAOC,IAAIE,SAASC;AACtB;AARgBL;;;ACFhB,IAAAM,gBAA4C;AAKrC,SAASC,cAAcC,QAAkC;AAC9D,QAAMC,kBAAcC,sBAA6BC,MAAAA;AACjD,QAAMC,mBAAeF,sBAAO,KAAA;AAC5B,QAAMG,wBAAoBH,sBAAO,KAAA;AACjC,QAAM,CAAA,EAAGI,aAAAA,QAAiBC,wBAAS,CAAA;AAEnC,MAAIH,aAAaI,QAASH,mBAAkBG,UAAU;AAEtDC,+BAAU,MAAA;AAER,QAAI,CAACL,aAAaI,SAAS;AACzBP,kBAAYO,UAAUR,OAAAA;AACtBI,mBAAaI,UAAU;IACzB;AAGAF,kBAAc,CAACI,MAAMA,IAAI,CAAA;AAEzB,WAAO,MAAA;AAGL,UAAI,CAACL,kBAAkBG,QAAS;AAEhCP,kBAAYO,UAAO;IACrB;EACF,GAAG,CAAA,CAAE;AACP;AA1BgBT;;;ACJhB,IAAAY,gBAA2B;;;ACD3B,yBAA0B;AAC1B,IAAAC,gBAA8B;AASvB,IAAMC,gCAA4BC,6BAAiDC,4BAAAA;AAEnF,IAAMC,yDAAqDF,6BAChE,oBAAIG,IAAAA,CAAAA;AAGC,IAAMC,iEAA6DJ,6BAA6B;EAAEK,GAAG;AAAE,CAAA;;;AChB9G,IAAAC,gBAAoC;AAY7B,SAASC,eAAe,EAC7BC,UACAC,QAAAA,SACAC,wBACAC,uBAAsB,GACF;AACpB,QAAMC,cAAcH,QAAOI,QAAO,EAAGD;AAErC,QAAME,qBAAqB;IACzBC,SAAKC,uBAAQ,MAAA;AACX,aAAOJ,cAAcH,UAASA,QAAOI,QAAO,EAAGI,0CAAyC;IAC1F,GAAG;MAACT;MAAUC;MAAQC;MAAwBC;KAAuB;EACvE;AAEA,SACE,sBAAA,cAACO,0BAA0BC,UAAQ;IAACC,OAAON;KACzC,sBAAA,cAACO,2DAA2DF,UAAQ;IAACC,OAAO;MAAEE,GAAG;IAAE;KACjF,sBAAA,cAACC,4BAAAA;IACCf;IACAC,QAAQK;IACRJ;IACAC;;AAKV;AA1BgBJ;AA4BhB,SAASgB,2BAA2B,EAClCf,UACAC,QAAAA,SACAC,wBACAC,yBAAyB,MAAK,GACwD;AACtF,QAAMa,8BAA0BC,0BAAWC,kDAAAA;AAC3C,QAAMC,wBAAoBF,0BAAWJ,0DAAAA;AAUrCO,gBAAc,MAAA;AAGZ,UAAMC,cAAcpB,QAAOM,IAAIF,QAAO;AAEtC,QAAIW,yBAAyB;AAC3B,YAAMM,gCAAgCrB,QAAOM,IAAIF,QAAO,EAAGkB,QAAQC,IAAI,CAACC,mBAAAA;AACtE,cAAMC,gDACJV,wBAAwBW,IAAIF,eAAeG,SAAQ,CAAA,GAAKA,SAAAA,MAAeH,eAAeG,SAAQ;AAGhG,YAAI,CAACF,8CACH,QAAOD;AAET,eAAOT,wBAAwBW,IAAIF,eAAeG,SAAQ,CAAA;MAC5D,CAAA;AAEA,UAAIN,8BAA8BO,SAAS,GAAG;AAC5C5B,QAAAA,QAAOM,IAAIF,QAAO,EAAGyB,UAAU;UAC7B,GAAG7B,QAAOM,IAAIF,QAAO,EAAG0B;UACxBR,SAASD;QACX,CAAA;AAGAH,0BAAkBL;MACpB;IACF;AAGA,QAAIO,YAAYW,cAAc9B,wBAAwB;AAEpDmB,kBAAYS,UAAU5B,sBAAAA;IACxB;AAEA,WAAO,MAAA;AAGL,UAAI,CAACC,0BAA0BkB,YAAYW,WAAY;AAEvDX,kBAAYY,SAAQ;IACtB;EACF,CAAA;AAEA,SAAOjC;AACT;AA7DSe;;;AFvBF,SAASmB,kBAAqBC,UAA4BC,SAA0B;AACzF,QAAMC,sBAAkBC,0BAAWC,yBAAAA;AAEnC,SAAOF,gBAAgBG,IAAIC,IAAIN,UAAUC,SAASM,UAAAA;AACpD;AAJgBR;;;AGDT,SAASS,UAAaC,UAA4BC,SAA0B;AACjF,SAAOC,QAAQ,MAAMC,kBAAkBH,UAAUC,OAAAA,CAAAA;AACnD;AAFgBF;;;ACVhB,IAAAK,gBAA2B;AAepB,SAASC,sBAAqF,EACnGC,KAAI,GAIL;AACC,QAAMC,sBAAkBC,0BAAWC,yBAAAA;AAEnC,SAAOF,gBAAgBG,IAAIC,QAAO,GAAIL,IAAAA;AACxC;AATgBD;;;ACLT,SAASO,cAA6E,EAC3FC,MACAC,QAAO,GAIR;AACC,SAAOC,QAAQ,MAAMC,sBAAsB;IAAEF;IAASD;EAAK,CAAA,CAAA;AAC7D;AARgBD;;;AChBhB,IAAAK,gBAA2B;AAIpB,SAASC,kCAAAA;AACd,QAAMC,sBAAkBC,0BAAWC,yBAAAA;AACnC,QAAMC,cAAUF,0BAAWG,kDAAAA;AAE3BD,UAAQE,IAAIL,gBAAgBM,IAAIC,SAAQ,GAAIP,gBAAgBM,GAAG;AACjE;AALgBP;;;ACJhB,IAAAS,gBAAgD;AAiBzC,SAASC,2CAAAA;AACd,QAAMC,wBAAoBC,0BAAWC,0DAAAA;AACrC,QAAM,CAAA,EAAGC,WAAAA,QAAeC,wBAAS,CAAA;AAEjCC,+BAAU,MAAA;AACRF,gBAAY,CAACG,MAAMA,IAAI,CAAA;EACzB,GAAG;IAACN,kBAAkBO;GAAE;AAC1B;AAPgBR;;;ACjBhB,IAAAS,sBAWO;AAKA,IAAMC,0BAAN,MAAMA,iCAAgCC,mCAAAA;EAhB7C,OAgB6CA;;;EACxBC;EACAC;EAEnBC,YAAYC,SAAgC;AAC1C,UACEC,0CAAsBC,+BAA+B;MACnD,GAAGF;;;MAGHG,cAAcH,QAAQG,gBAAgBC,mCAAeC;MACrDC,YAAYC,OAAO,YAAYP,QAAQM,WAAWE,WAAW,EAAE;IACjE,CAAA,CAAA;AAGF,SAAKX,4BAA4B;AACjC,SAAKC,kBAAkBE;EACzB;EAESS,UAAgE;AACvE,WAAO;EACT;;EAGAC,UAAgB;AACd,SAAKC,SAAQ;EACf;;;;;;;EAQUC,4CAAsE;AAC9E,QAAI,KAAKC,eAAe,KAAKC,WAAY,QAAO;AAEhD,UAAMC,0BAA0B,KAAKC,cAAa,EAAGC,IAAI,CAACC,aAAAA;AACxD,UAAI,KAACC,uCAAkBD,QAAAA,GAAW;AAChC,eAAO;UACL,GAAGA;UACHE,OAAOhB,mCAAeiB;QACxB;MACF;AAEA,cAAIC,6BAAQJ,QAAAA,GAAW;AACrB,eAAO;UACLE,OAAOhB,mCAAeiB;UACtBE,SAASL;UACTM,UAAUN;QACZ;MACF;AAEA,aAAO;QACLK,SAASL;QACTO,UAAUP;MACZ;IACF,CAAA;AAEA,UAAMQ,kBAAkB,IAAI/B,yBAAwB;MAClD,GAAG,KAAKG;MACR6B,WAAWZ;IACb,CAAA;AAGAW,oBAAgB7B,4BAA4B;AAE5C,WAAO6B;EACT;AACF;;;ACrFA,IAAAE,gBAA+C;AAaxC,SAASC,iBAAiB,EAAEC,UAAUC,gBAAe,GAAgC;AAC1F,QAAMC,uBAAmBC,uBAAQ,MAAM,oBAAIC,IAAAA,GAAO,CAAA,CAAE;AAEpD,SACE,sBAAA,cAACC,mDAAmDC,UAAQ;IAACC,OAAOL;KAClE,sBAAA,cAACM,YAAAA;IAAWP;MACXD,QAAAA;AAGP;AATgBD;AAWhB,SAASS,WAAW,EAAEP,gBAAe,GAAoD;AACvF,QAAMQ,aAASC,0BAAWL,kDAAAA;AAE1BM,+BAAU,MAAA;AACR,UAAMC,cAAcX,kBAAkBQ,MAAAA;AACtC,QAAI,CAACG,YAAa;AAElB,UAAMC,YAAYJ,OAAOK,IAAIF,YAAYG,OAAOC,SAAQ,CAAA;AAExD,QAAI,CAACH,UAAW;AAEhBD,gBAAYK,OAAOJ,SAAAA;EACrB,GAAG;IAACJ;GAAO;AAEX,SAAO;AACT;AAfSD;","names":["useOnce","fn","ref","useRef","current","value","import_react","useEffectOnce","effect","destroyFunc","useRef","undefined","effectCalled","renderAfterCalled","forceRerender","useState","current","useEffect","x","import_react","import_react","REACT_X_INJECTION_CONTEXT","createContext","AppModule","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","Map","REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE","r","import_react","ModuleProvider","children","module","tryReInitModuleOnMount","disposeModuleOnUnmount","isAppModule","toNaked","moduleCtxReference","ctx","useMemo","_convertToContextualizedComponentInstance","REACT_X_INJECTION_CONTEXT","Provider","value","REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE","r","XInjectionChildrenRenderer","componentModuleInstance","useContext","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","rerenderParentCtx","useEffectOnce","moduleNaked","contextualizedImportedModules","imports","map","importedModule","shouldReplaceImportedModuleWithContextualized","get","toString","length","_lazyInit","_initialOptions","isDisposed","_dispose","useInjectOnRender","provider","options","componentModule","useContext","REACT_X_INJECTION_CONTEXT","ctx","get","isOptional","useInject","provider","options","useOnce","useInjectOnRender","import_react","useInjectManyOnRender","deps","componentModule","useContext","REACT_X_INJECTION_CONTEXT","ctx","getMany","useInjectMany","deps","options","useOnce","useInjectManyOnRender","import_react","useExposeComponentModuleContext","componentModule","useContext","REACT_X_INJECTION_CONTEXT","exposed","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","set","ctx","toString","import_react","useRerenderOnChildrenModuleContextLoaded","rerenderParentCtx","useContext","REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE","setRerender","useState","useEffect","x","r","import_x_injection","ComponentProviderModule","ProviderModule","_initializedFromComponent","_initialOptions","constructor","options","ProviderModuleHelpers","buildInternalConstructorParams","defaultScope","InjectionScope","Transient","identifier","Symbol","description","toNaked","dispose","_dispose","_convertToContextualizedComponentInstance","isAppModule","isDisposed","contextualizedProviders","_getProviders","map","provider","isClassOrFunction","scope","Singleton","isClass","provide","useClass","useValue","componentModule","providers","import_react","TapIntoComponent","children","contextInstance","moduleContextMap","useMemo","Map","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","Provider","value","CtxExposer","ctxMap","useContext","useEffect","fluidSyntax","moduleCtx","get","tryGet","toString","thenDo"]}
@@ -0,0 +1,245 @@
1
+ import { ProviderModuleOptions, IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule } from '@adimm/x-injection';
2
+ import * as react from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ interface IComponentProviderModuleNaked extends IComponentProviderModule {
6
+ /** Indicates if this module has been initialized by a React Component or not. */
7
+ _initializedFromComponent: boolean;
8
+ /** The {@link ProviderModuleOptions | options} with which the module has been originally initialized. */
9
+ _initialOptions: ProviderModuleOptions;
10
+ /**
11
+ * Instantiate a new {@link IComponentProviderModule} which will be supplied to the React Component.
12
+ *
13
+ * All the `providers` will be injected into a `singleton` scope.
14
+ */
15
+ _convertToContextualizedComponentInstance(): IComponentProviderModule;
16
+ }
17
+
18
+ interface IComponentProviderModule extends IProviderModule {
19
+ /**
20
+ * Casts the current module type to the {@link IComponentProviderModuleNaked} type.
21
+ *
22
+ * **Internally used and for testing purposes!**
23
+ */
24
+ toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
25
+ /**
26
+ * Should be invoked only when the component is not needed anymore.
27
+ *
28
+ * _eg: When changing page, removable components and so on._
29
+ */
30
+ dispose(): void;
31
+ }
32
+
33
+ interface UseInjectSharedOptions {
34
+ }
35
+
36
+ /**
37
+ * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.
38
+ *
39
+ * **Note:** _By using this hook, the dependency will be injected on each re-render process._
40
+ * _If you need to inject the dependency only once, you must use the `useInject` hook._
41
+ * _It basically acts like a `Transient` scope, ensuring that a new dependency is injected on each re-render._
42
+ *
43
+ * @param provider The {@link ProviderToken}.
44
+ * @param options See {@link UseInjectSharedOptions}.
45
+ * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.
46
+ */
47
+ declare function useInjectOnRender<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
48
+ type UseInjectOptions = UseInjectSharedOptions & {
49
+ /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */
50
+ isOptional?: boolean;
51
+ };
52
+
53
+ /**
54
+ * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.
55
+ *
56
+ * **Note:** _By using this hook, the dependency will be injected only once after the first component mount process._
57
+ * _If you need to re-inject the dependency on each re-render, you must use the `useInjectOnRender` hook._
58
+ * _It basically acts like a `Request` scope, ensuring that even a `Transient` dependency does not mutate during re-renders._
59
+ *
60
+ * @param provider The {@link ProviderToken}.
61
+ * @param options See {@link UseInjectSharedOptions}.
62
+ * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.
63
+ */
64
+ declare function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
65
+
66
+ /**
67
+ * Can be used to retrieve many resolved `dependencies` from the module container at once.
68
+ *
69
+ * **Note:** _By using this hook, the dependencies will be injected only once after the first component mount process._
70
+ * _If you need to re-inject the dependencies on each re-render, you must use the `useInjectManyOnRender` hook._
71
+ *
72
+ * @param options See {@link UseInjectSharedOptions}.
73
+ * @param deps Either one or more {@link ProviderToken}.
74
+ * @returns Tuple containing the {@link D | dependencies}.
75
+ */
76
+ declare function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({ deps, options, }: {
77
+ deps: [...(D | unknown[])];
78
+ options?: UseInjectSharedOptions;
79
+ }): ProviderModuleGetManySignature<D>;
80
+
81
+ /**
82
+ * Can be used to retrieve many resolved `dependencies` from the module container at once.
83
+ *
84
+ * **Note:** _By using this hook, the dependencies will be injected on each re-render process._
85
+ * _If you need to inject the dependencies only once, you must use the `useInjectMany` hook._
86
+ *
87
+ * @param options See {@link UseInjectSharedOptions}.
88
+ * @param deps Either one or more {@link ProviderToken}.
89
+ * @returns Tuple containing the {@link D | dependencies}.
90
+ */
91
+ declare function useInjectManyOnRender<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({ deps, }: {
92
+ deps: [...(D | unknown[])];
93
+ options?: UseInjectSharedOptions;
94
+ }): ProviderModuleGetManySignature<D>;
95
+
96
+ declare function useExposeComponentModuleContext(): void;
97
+
98
+ /**
99
+ * This is an **experimental** hook which can be used to make sure that a component will re-render when a children
100
+ * exposes its internal context module.
101
+ *
102
+ * It works best with the `useInjectOnRender` hook, as it'll re-resolve all the required dependencies
103
+ * of the injected ProviderToken.
104
+ *
105
+ * **Use it carefully as it may lead to unnecessary re-render cycles or it may even not work as expected!**
106
+ * **It's safer to use the `TapIntoComponent` wrapper component with the `contextInstance` to manually inject the**
107
+ * **contextualized dependencies of the children into a parent component service!**
108
+ *
109
+ * @experimental
110
+ */
111
+ declare function useRerenderOnChildrenModuleContextLoaded(): void;
112
+
113
+ /**
114
+ * The `React.Context` value to be provided to a `React.Provider`.
115
+ *
116
+ * Its default value is a reference to the {@link AppModule}.
117
+ */
118
+ declare const REACT_X_INJECTION_CONTEXT: react.Context<{
119
+ ctx: IComponentProviderModule;
120
+ }>;
121
+ declare const REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT: react.Context<Map<string, IComponentProviderModule>>;
122
+ declare const REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE: react.Context<{
123
+ r: number;
124
+ }>;
125
+
126
+ interface ModuleProviderProps {
127
+ children: React.ReactNode;
128
+ /** The {@link IComponentProviderModule | ComponentProviderModule} instance which must be accessible by this component. */
129
+ module: IComponentProviderModule;
130
+ /**
131
+ * Provide an object containing the initialization {@link ProviderModuleConstructor | options} so the {@link ModuleProviderProps.module | module}
132
+ * can be re-initialized when the component re-mounts _**(It'll happen only if it has been previously disposed!)**_.
133
+ *
134
+ * **Note:** _This is an advanced option and should be used only if you fully understand how the {@link ModuleProviderProps.module | module}_
135
+ * _initialization process works!_
136
+ * _For more details refer to the {@link https://adimarianmutu.github.io/x-injection/index.html | xInjection} offical docs._
137
+ */
138
+ tryReInitModuleOnMount?: ProviderModuleOptions;
139
+ /**
140
+ * When set to `true` it'll automatically dispose
141
+ * the provided {@link ModuleProviderProps.module | module} during the
142
+ * component `unmount` process.
143
+ *
144
+ * **Note:** _This is an advanced option and should be used only if you fully understand how the {@link ModuleProviderProps.module | module}_
145
+ * _dispose process works!_
146
+ * _For more details refer to the {@link https://adimarianmutu.github.io/x-injection/index.html | xInjection} offical docs._
147
+ *
148
+ * Defaults to `false`.
149
+ */
150
+ disposeModuleOnUnmount?: boolean;
151
+ }
152
+
153
+ declare function ModuleProvider({ children, module, tryReInitModuleOnMount, disposeModuleOnUnmount, }: ModuleProviderProps): react_jsx_runtime.JSX.Element;
154
+
155
+ /** A superset of the {@link ProviderModule} used to integrate within a `React` component. */
156
+ declare class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {
157
+ protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];
158
+ protected readonly _initialOptions: IComponentProviderModuleNaked['_initialOptions'];
159
+ constructor(options: ProviderModuleOptions);
160
+ toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
161
+ dispose(): void;
162
+ /**
163
+ * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**
164
+ *
165
+ * See {@link IComponentProviderModuleNaked._convertToContextualizedComponentInstance}.
166
+ */
167
+ protected _convertToContextualizedComponentInstance(): IComponentProviderModule;
168
+ }
169
+
170
+ interface TapIntoComponentContextProps {
171
+ children: React.ReactNode;
172
+ /**
173
+ * A callback can be provided to fully get access to the `ProviderModule` of the component instance,
174
+ * as long as the component is exposing it by using the `useExposeComponentModuleContext` hook.
175
+ *
176
+ * @param ctx A context map of modules.
177
+ *
178
+ * @example
179
+ * ```tsx
180
+ * function UserComponent(props: UserComponentProps) {
181
+ * // This is required in order to correctly expose the ctx!
182
+ * useExposeComponentModuleContext();
183
+ *
184
+ * const [userProfileSettings, userSecuritySettings] = useInjectMany({ deps: [UserProfileSettings, UserSecuritySettings] });
185
+ *
186
+ * return null;
187
+ * }
188
+ *
189
+ * function UserPage(props: UserPageProps) {
190
+ * return (
191
+ * <TapIntoComponent
192
+ * contextInstance={(ctx)) => ({
193
+ * tryGet: UserComponentModule,
194
+ * thenDo: (ctx) => {
195
+ * const services = ctx.getMany(...);
196
+ * }
197
+ * })}>
198
+ * <UserComponent {...props.userComponentProps} />
199
+ * </TapIntoComponent>
200
+ * );
201
+ * }
202
+ * ```
203
+ *
204
+ * **Or without the fluid syntax:**
205
+ *
206
+ * ```tsx
207
+ * function UserPage(props: UserPageProps) {
208
+ * return (
209
+ * <TapIntoComponent
210
+ * contextInstance={(ctxMap)) => {
211
+ * const ctx = ctxMap.get(UserComponentModule.toString());
212
+ * if (!ctx) return;
213
+ *
214
+ * const services = ctx.getMany(...);
215
+ * }}>
216
+ * <UserComponent {...props.userComponentProps} />
217
+ * </TapIntoComponent>
218
+ * );
219
+ * }
220
+ * ````
221
+ */
222
+ contextInstance?: (ctx: Map<string, IComponentProviderModule>) => void | WithComponentInstanceCtxFluidSyntax;
223
+ }
224
+ interface WithComponentInstanceCtxFluidSyntax {
225
+ /** The {@link IComponentProviderModule | module} to look for in the `context map`. */
226
+ tryGet: IComponentProviderModule;
227
+ /**
228
+ * Provide a callback which will be invoked when the `context map` has
229
+ * the {@link tryGet | module} requested.
230
+ *
231
+ * @param module The contextualized instance of the {@link IComponentProviderModule} extracted from the children.
232
+ */
233
+ thenDo: (module: IComponentProviderModule) => void | Promise<void>;
234
+ }
235
+
236
+ /**
237
+ * This component is the standard way to "tap into" an instance of the component
238
+ * in order to get access to its scoped module container and its _(exposed)_ dependencies _instances_.
239
+ *
240
+ * @param contextInstance See {@link TapIntoComponentContextProps.contextInstance}.
241
+ * @param exposed See {@link TapIntoComponentContextProps.exposed}.
242
+ */
243
+ declare function TapIntoComponent({ children, contextInstance }: TapIntoComponentContextProps): react_jsx_runtime.JSX.Element;
244
+
245
+ export { ComponentProviderModule, type IComponentProviderModule, type IComponentProviderModuleNaked, ModuleProvider, REACT_X_INJECTION_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE, TapIntoComponent, type TapIntoComponentContextProps, type UseInjectOptions, type UseInjectSharedOptions, type WithComponentInstanceCtxFluidSyntax, useExposeComponentModuleContext, useInject, useInjectMany, useInjectManyOnRender, useInjectOnRender, useRerenderOnChildrenModuleContextLoaded };
@@ -0,0 +1,245 @@
1
+ import { ProviderModuleOptions, IProviderModule, IProviderModuleNaked, ProviderToken, ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderModule } from '@adimm/x-injection';
2
+ import * as react from 'react';
3
+ import * as react_jsx_runtime from 'react/jsx-runtime';
4
+
5
+ interface IComponentProviderModuleNaked extends IComponentProviderModule {
6
+ /** Indicates if this module has been initialized by a React Component or not. */
7
+ _initializedFromComponent: boolean;
8
+ /** The {@link ProviderModuleOptions | options} with which the module has been originally initialized. */
9
+ _initialOptions: ProviderModuleOptions;
10
+ /**
11
+ * Instantiate a new {@link IComponentProviderModule} which will be supplied to the React Component.
12
+ *
13
+ * All the `providers` will be injected into a `singleton` scope.
14
+ */
15
+ _convertToContextualizedComponentInstance(): IComponentProviderModule;
16
+ }
17
+
18
+ interface IComponentProviderModule extends IProviderModule {
19
+ /**
20
+ * Casts the current module type to the {@link IComponentProviderModuleNaked} type.
21
+ *
22
+ * **Internally used and for testing purposes!**
23
+ */
24
+ toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
25
+ /**
26
+ * Should be invoked only when the component is not needed anymore.
27
+ *
28
+ * _eg: When changing page, removable components and so on._
29
+ */
30
+ dispose(): void;
31
+ }
32
+
33
+ interface UseInjectSharedOptions {
34
+ }
35
+
36
+ /**
37
+ * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.
38
+ *
39
+ * **Note:** _By using this hook, the dependency will be injected on each re-render process._
40
+ * _If you need to inject the dependency only once, you must use the `useInject` hook._
41
+ * _It basically acts like a `Transient` scope, ensuring that a new dependency is injected on each re-render._
42
+ *
43
+ * @param provider The {@link ProviderToken}.
44
+ * @param options See {@link UseInjectSharedOptions}.
45
+ * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.
46
+ */
47
+ declare function useInjectOnRender<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
48
+ type UseInjectOptions = UseInjectSharedOptions & {
49
+ /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */
50
+ isOptional?: boolean;
51
+ };
52
+
53
+ /**
54
+ * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.
55
+ *
56
+ * **Note:** _By using this hook, the dependency will be injected only once after the first component mount process._
57
+ * _If you need to re-inject the dependency on each re-render, you must use the `useInjectOnRender` hook._
58
+ * _It basically acts like a `Request` scope, ensuring that even a `Transient` dependency does not mutate during re-renders._
59
+ *
60
+ * @param provider The {@link ProviderToken}.
61
+ * @param options See {@link UseInjectSharedOptions}.
62
+ * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.
63
+ */
64
+ declare function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T;
65
+
66
+ /**
67
+ * Can be used to retrieve many resolved `dependencies` from the module container at once.
68
+ *
69
+ * **Note:** _By using this hook, the dependencies will be injected only once after the first component mount process._
70
+ * _If you need to re-inject the dependencies on each re-render, you must use the `useInjectManyOnRender` hook._
71
+ *
72
+ * @param options See {@link UseInjectSharedOptions}.
73
+ * @param deps Either one or more {@link ProviderToken}.
74
+ * @returns Tuple containing the {@link D | dependencies}.
75
+ */
76
+ declare function useInjectMany<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({ deps, options, }: {
77
+ deps: [...(D | unknown[])];
78
+ options?: UseInjectSharedOptions;
79
+ }): ProviderModuleGetManySignature<D>;
80
+
81
+ /**
82
+ * Can be used to retrieve many resolved `dependencies` from the module container at once.
83
+ *
84
+ * **Note:** _By using this hook, the dependencies will be injected on each re-render process._
85
+ * _If you need to inject the dependencies only once, you must use the `useInjectMany` hook._
86
+ *
87
+ * @param options See {@link UseInjectSharedOptions}.
88
+ * @param deps Either one or more {@link ProviderToken}.
89
+ * @returns Tuple containing the {@link D | dependencies}.
90
+ */
91
+ declare function useInjectManyOnRender<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({ deps, }: {
92
+ deps: [...(D | unknown[])];
93
+ options?: UseInjectSharedOptions;
94
+ }): ProviderModuleGetManySignature<D>;
95
+
96
+ declare function useExposeComponentModuleContext(): void;
97
+
98
+ /**
99
+ * This is an **experimental** hook which can be used to make sure that a component will re-render when a children
100
+ * exposes its internal context module.
101
+ *
102
+ * It works best with the `useInjectOnRender` hook, as it'll re-resolve all the required dependencies
103
+ * of the injected ProviderToken.
104
+ *
105
+ * **Use it carefully as it may lead to unnecessary re-render cycles or it may even not work as expected!**
106
+ * **It's safer to use the `TapIntoComponent` wrapper component with the `contextInstance` to manually inject the**
107
+ * **contextualized dependencies of the children into a parent component service!**
108
+ *
109
+ * @experimental
110
+ */
111
+ declare function useRerenderOnChildrenModuleContextLoaded(): void;
112
+
113
+ /**
114
+ * The `React.Context` value to be provided to a `React.Provider`.
115
+ *
116
+ * Its default value is a reference to the {@link AppModule}.
117
+ */
118
+ declare const REACT_X_INJECTION_CONTEXT: react.Context<{
119
+ ctx: IComponentProviderModule;
120
+ }>;
121
+ declare const REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT: react.Context<Map<string, IComponentProviderModule>>;
122
+ declare const REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE: react.Context<{
123
+ r: number;
124
+ }>;
125
+
126
+ interface ModuleProviderProps {
127
+ children: React.ReactNode;
128
+ /** The {@link IComponentProviderModule | ComponentProviderModule} instance which must be accessible by this component. */
129
+ module: IComponentProviderModule;
130
+ /**
131
+ * Provide an object containing the initialization {@link ProviderModuleConstructor | options} so the {@link ModuleProviderProps.module | module}
132
+ * can be re-initialized when the component re-mounts _**(It'll happen only if it has been previously disposed!)**_.
133
+ *
134
+ * **Note:** _This is an advanced option and should be used only if you fully understand how the {@link ModuleProviderProps.module | module}_
135
+ * _initialization process works!_
136
+ * _For more details refer to the {@link https://adimarianmutu.github.io/x-injection/index.html | xInjection} offical docs._
137
+ */
138
+ tryReInitModuleOnMount?: ProviderModuleOptions;
139
+ /**
140
+ * When set to `true` it'll automatically dispose
141
+ * the provided {@link ModuleProviderProps.module | module} during the
142
+ * component `unmount` process.
143
+ *
144
+ * **Note:** _This is an advanced option and should be used only if you fully understand how the {@link ModuleProviderProps.module | module}_
145
+ * _dispose process works!_
146
+ * _For more details refer to the {@link https://adimarianmutu.github.io/x-injection/index.html | xInjection} offical docs._
147
+ *
148
+ * Defaults to `false`.
149
+ */
150
+ disposeModuleOnUnmount?: boolean;
151
+ }
152
+
153
+ declare function ModuleProvider({ children, module, tryReInitModuleOnMount, disposeModuleOnUnmount, }: ModuleProviderProps): react_jsx_runtime.JSX.Element;
154
+
155
+ /** A superset of the {@link ProviderModule} used to integrate within a `React` component. */
156
+ declare class ComponentProviderModule extends ProviderModule implements IComponentProviderModule {
157
+ protected readonly _initializedFromComponent: IComponentProviderModuleNaked['_initializedFromComponent'];
158
+ protected readonly _initialOptions: IComponentProviderModuleNaked['_initialOptions'];
159
+ constructor(options: ProviderModuleOptions);
160
+ toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked;
161
+ dispose(): void;
162
+ /**
163
+ * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**
164
+ *
165
+ * See {@link IComponentProviderModuleNaked._convertToContextualizedComponentInstance}.
166
+ */
167
+ protected _convertToContextualizedComponentInstance(): IComponentProviderModule;
168
+ }
169
+
170
+ interface TapIntoComponentContextProps {
171
+ children: React.ReactNode;
172
+ /**
173
+ * A callback can be provided to fully get access to the `ProviderModule` of the component instance,
174
+ * as long as the component is exposing it by using the `useExposeComponentModuleContext` hook.
175
+ *
176
+ * @param ctx A context map of modules.
177
+ *
178
+ * @example
179
+ * ```tsx
180
+ * function UserComponent(props: UserComponentProps) {
181
+ * // This is required in order to correctly expose the ctx!
182
+ * useExposeComponentModuleContext();
183
+ *
184
+ * const [userProfileSettings, userSecuritySettings] = useInjectMany({ deps: [UserProfileSettings, UserSecuritySettings] });
185
+ *
186
+ * return null;
187
+ * }
188
+ *
189
+ * function UserPage(props: UserPageProps) {
190
+ * return (
191
+ * <TapIntoComponent
192
+ * contextInstance={(ctx)) => ({
193
+ * tryGet: UserComponentModule,
194
+ * thenDo: (ctx) => {
195
+ * const services = ctx.getMany(...);
196
+ * }
197
+ * })}>
198
+ * <UserComponent {...props.userComponentProps} />
199
+ * </TapIntoComponent>
200
+ * );
201
+ * }
202
+ * ```
203
+ *
204
+ * **Or without the fluid syntax:**
205
+ *
206
+ * ```tsx
207
+ * function UserPage(props: UserPageProps) {
208
+ * return (
209
+ * <TapIntoComponent
210
+ * contextInstance={(ctxMap)) => {
211
+ * const ctx = ctxMap.get(UserComponentModule.toString());
212
+ * if (!ctx) return;
213
+ *
214
+ * const services = ctx.getMany(...);
215
+ * }}>
216
+ * <UserComponent {...props.userComponentProps} />
217
+ * </TapIntoComponent>
218
+ * );
219
+ * }
220
+ * ````
221
+ */
222
+ contextInstance?: (ctx: Map<string, IComponentProviderModule>) => void | WithComponentInstanceCtxFluidSyntax;
223
+ }
224
+ interface WithComponentInstanceCtxFluidSyntax {
225
+ /** The {@link IComponentProviderModule | module} to look for in the `context map`. */
226
+ tryGet: IComponentProviderModule;
227
+ /**
228
+ * Provide a callback which will be invoked when the `context map` has
229
+ * the {@link tryGet | module} requested.
230
+ *
231
+ * @param module The contextualized instance of the {@link IComponentProviderModule} extracted from the children.
232
+ */
233
+ thenDo: (module: IComponentProviderModule) => void | Promise<void>;
234
+ }
235
+
236
+ /**
237
+ * This component is the standard way to "tap into" an instance of the component
238
+ * in order to get access to its scoped module container and its _(exposed)_ dependencies _instances_.
239
+ *
240
+ * @param contextInstance See {@link TapIntoComponentContextProps.contextInstance}.
241
+ * @param exposed See {@link TapIntoComponentContextProps.exposed}.
242
+ */
243
+ declare function TapIntoComponent({ children, contextInstance }: TapIntoComponentContextProps): react_jsx_runtime.JSX.Element;
244
+
245
+ export { ComponentProviderModule, type IComponentProviderModule, type IComponentProviderModuleNaked, ModuleProvider, REACT_X_INJECTION_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE, TapIntoComponent, type TapIntoComponentContextProps, type UseInjectOptions, type UseInjectSharedOptions, type WithComponentInstanceCtxFluidSyntax, useExposeComponentModuleContext, useInject, useInjectMany, useInjectManyOnRender, useInjectOnRender, useRerenderOnChildrenModuleContextLoaded };
package/dist/index.js ADDED
@@ -0,0 +1,186 @@
1
+ var e = Object.defineProperty, t = (t, n) => e(t, "name", {
2
+ value: n,
3
+ configurable: !0
4
+ });
5
+
6
+ import { useRef as n } from "react";
7
+
8
+ function o(e) {
9
+ const t = n(null);
10
+ return null === t.current && (t.current = {
11
+ value: e()
12
+ }), t.current?.value;
13
+ }
14
+
15
+ t(o, "useOnce");
16
+
17
+ import { useEffect as r, useRef as i, useState as s } from "react";
18
+
19
+ function c(e) {
20
+ const t = i(void 0), n = i(!1), o = i(!1), [, c] = s(0);
21
+ n.current && (o.current = !0), r((() => (n.current || (t.current = e(), n.current = !0),
22
+ c((e => e + 1)), () => {
23
+ o.current && t.current?.();
24
+ })), []);
25
+ }
26
+
27
+ t(c, "useEffectOnce");
28
+
29
+ import { useContext as u } from "react";
30
+
31
+ import { AppModule as a } from "@adimm/x-injection";
32
+
33
+ import { createContext as d } from "react";
34
+
35
+ var p = d(a), l = d(new Map), m = d({
36
+ r: 0
37
+ });
38
+
39
+ import { useContext as f, useMemo as x } from "react";
40
+
41
+ function C({children: e, module: t, tryReInitModuleOnMount: n, disposeModuleOnUnmount: o}) {
42
+ const r = t.toNaked().isAppModule, i = {
43
+ ctx: x((() => r ? t : t.toNaked()._convertToContextualizedComponentInstance()), [ e, t, n, o ])
44
+ };
45
+ return React.createElement(p.Provider, {
46
+ value: i
47
+ }, React.createElement(m.Provider, {
48
+ value: {
49
+ r: 0
50
+ }
51
+ }, React.createElement(v, {
52
+ children: e,
53
+ module: i,
54
+ tryReInitModuleOnMount: n,
55
+ disposeModuleOnUnmount: o
56
+ })));
57
+ }
58
+
59
+ function v({children: e, module: t, tryReInitModuleOnMount: n, disposeModuleOnUnmount: o = !1}) {
60
+ const r = f(l), i = f(m);
61
+ return c((() => {
62
+ const e = t.ctx.toNaked();
63
+ if (r) {
64
+ const e = t.ctx.toNaked().imports.map((e => r.get(e.toString())?.toString() === e.toString() ? r.get(e.toString()) : e));
65
+ e.length > 0 && (t.ctx.toNaked()._lazyInit({
66
+ ...t.ctx.toNaked()._initialOptions,
67
+ imports: e
68
+ }), i.r++);
69
+ }
70
+ return e.isDisposed && n && e._lazyInit(n), () => {
71
+ o && !e.isDisposed && e._dispose();
72
+ };
73
+ })), e;
74
+ }
75
+
76
+ function M(e, t) {
77
+ return u(p).ctx.get(e, t?.isOptional);
78
+ }
79
+
80
+ function h(e, t) {
81
+ return o((() => M(e, t)));
82
+ }
83
+
84
+ t(C, "ModuleProvider"), t(v, "XInjectionChildrenRenderer"), t(M, "useInjectOnRender"),
85
+ t(h, "useInject");
86
+
87
+ import { useContext as I } from "react";
88
+
89
+ function O({deps: e}) {
90
+ return I(p).ctx.getMany(...e);
91
+ }
92
+
93
+ function g({deps: e, options: t}) {
94
+ return o((() => O({
95
+ options: t,
96
+ deps: e
97
+ })));
98
+ }
99
+
100
+ t(O, "useInjectManyOnRender"), t(g, "useInjectMany");
101
+
102
+ import { useContext as _ } from "react";
103
+
104
+ function R() {
105
+ const e = _(p);
106
+ _(l).set(e.ctx.toString(), e.ctx);
107
+ }
108
+
109
+ t(R, "useExposeComponentModuleContext");
110
+
111
+ import { useContext as S, useEffect as y, useState as E } from "react";
112
+
113
+ function j() {
114
+ const e = S(m), [, t] = E(0);
115
+ y((() => {
116
+ t((e => e + 1));
117
+ }), [ e.r ]);
118
+ }
119
+
120
+ t(j, "useRerenderOnChildrenModuleContextLoaded");
121
+
122
+ import { InjectionScope as P, isClass as k, isClassOrFunction as z, ProviderModule as N, ProviderModuleHelpers as b } from "@adimm/x-injection";
123
+
124
+ var D = class e extends N {
125
+ static {
126
+ t(this, "ComponentProviderModule");
127
+ }
128
+ _initializedFromComponent;
129
+ _initialOptions;
130
+ constructor(e) {
131
+ super(b.buildInternalConstructorParams({
132
+ ...e,
133
+ defaultScope: e.defaultScope ?? P.Transient,
134
+ identifier: Symbol(`Component${e.identifier.description}`)
135
+ })), this._initializedFromComponent = !1, this._initialOptions = e;
136
+ }
137
+ toNaked() {
138
+ return this;
139
+ }
140
+ dispose() {
141
+ this._dispose();
142
+ }
143
+ _convertToContextualizedComponentInstance() {
144
+ if (this.isAppModule || this.isDisposed) return this;
145
+ const t = this._getProviders().map((e => z(e) ? k(e) ? {
146
+ scope: P.Singleton,
147
+ provide: e,
148
+ useClass: e
149
+ } : {
150
+ provide: e,
151
+ useValue: e
152
+ } : {
153
+ ...e,
154
+ scope: P.Singleton
155
+ })), n = new e({
156
+ ...this._initialOptions,
157
+ providers: t
158
+ });
159
+ return n._initializedFromComponent = !0, n;
160
+ }
161
+ };
162
+
163
+ import { useContext as T, useEffect as w, useMemo as F } from "react";
164
+
165
+ function U({children: e, contextInstance: t}) {
166
+ const n = F((() => new Map), []);
167
+ return React.createElement(l.Provider, {
168
+ value: n
169
+ }, React.createElement(A, {
170
+ contextInstance: t
171
+ }), e);
172
+ }
173
+
174
+ function A({contextInstance: e}) {
175
+ const t = T(l);
176
+ return w((() => {
177
+ const n = e?.(t);
178
+ if (!n) return;
179
+ const o = t.get(n.tryGet.toString());
180
+ o && n.thenDo(o);
181
+ }), [ t ]), null;
182
+ }
183
+
184
+ t(U, "TapIntoComponent"), t(A, "CtxExposer");
185
+
186
+ export { D as ComponentProviderModule, C as ModuleProvider, p as REACT_X_INJECTION_CONTEXT, l as REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT, m as REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE, U as TapIntoComponent, R as useExposeComponentModuleContext, h as useInject, g as useInjectMany, O as useInjectManyOnRender, M as useInjectOnRender, j as useRerenderOnChildrenModuleContextLoaded };//# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/helpers/hooks/use-once.ts","../src/helpers/hooks/use-effect-once.ts","../src/core/hooks/use-inject-on-render.ts","../src/core/providers/module-provider/react-context.ts","../src/core/providers/module-provider/module.provider.tsx","../src/core/hooks/use-inject.ts","../src/core/hooks/use-inject-many-on-render.ts","../src/core/hooks/use-inject-many.ts","../src/core/hooks/use-expose-component-module-context.ts","../src/core/hooks/use-rerender-on-children-module-context-loaded.ts","../src/core/component-provider-module.ts","../src/core/utils/tap-into-component-context/tap-into-component-context.tsx"],"sourcesContent":["import { useRef } from 'react';\n\nexport function useOnce<T>(fn: () => T): T {\n const ref = useRef<OnceValue<T> | null>(null);\n\n if (ref.current === null) {\n ref.current = { value: fn() };\n }\n\n return ref.current?.value;\n}\n\ntype OnceValue<T> = { value: T };\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 type { ProviderToken } from '@adimm/x-injection';\nimport { useContext } from 'react';\n\nimport type { UseInjectSharedOptions } from '../../types';\nimport { REACT_X_INJECTION_CONTEXT } from '../providers';\n\n/**\n * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.\n *\n * **Note:** _By using this hook, the dependency will be injected on each re-render process._\n * _If you need to inject the dependency only once, you must use the `useInject` hook._\n * _It basically acts like a `Transient` scope, ensuring that a new dependency is injected on each re-render._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectSharedOptions}.\n * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.\n */\nexport function useInjectOnRender<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n const componentModule = useContext(REACT_X_INJECTION_CONTEXT);\n\n return componentModule.ctx.get(provider, options?.isOptional);\n}\n\nexport type UseInjectOptions = UseInjectSharedOptions & {\n /** When set to `false` _(default)_ an exception will be thrown when the `providerOrIdentifier` isn't bound. */\n isOptional?: boolean;\n};\n","import { AppModule } from '@adimm/x-injection';\nimport { createContext } from 'react';\n\nimport type { IComponentProviderModule } from '../../../types';\n\n/**\n * The `React.Context` value to be provided to a `React.Provider`.\n *\n * Its default value is a reference to the {@link AppModule}.\n */\nexport const REACT_X_INJECTION_CONTEXT = createContext<{ ctx: IComponentProviderModule }>(AppModule as any);\n\nexport const REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT = createContext<Map<string, IComponentProviderModule>>(\n new Map()\n);\n\nexport const REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE = createContext<{ r: number }>({ r: 0 });\n","import { useContext, useMemo } from 'react';\nimport type { Except } from 'type-fest';\n\nimport { useEffectOnce } from '../../../helpers';\nimport type { IComponentProviderModule, IComponentProviderModuleNaked } from '../../../types';\nimport type { ModuleProviderProps } from './models';\nimport {\n REACT_X_INJECTION_CONTEXT,\n REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT,\n REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE,\n} from './react-context';\n\nexport function ModuleProvider({\n children,\n module,\n tryReInitModuleOnMount,\n disposeModuleOnUnmount,\n}: ModuleProviderProps) {\n const isAppModule = module.toNaked().isAppModule;\n\n const moduleCtxReference = {\n ctx: useMemo(() => {\n return isAppModule ? module : module.toNaked()._convertToContextualizedComponentInstance();\n }, [children, module, tryReInitModuleOnMount, disposeModuleOnUnmount]),\n };\n\n return (\n <REACT_X_INJECTION_CONTEXT.Provider value={moduleCtxReference}>\n <REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE.Provider value={{ r: 0 }}>\n <XInjectionChildrenRenderer\n children={children}\n module={moduleCtxReference}\n tryReInitModuleOnMount={tryReInitModuleOnMount}\n disposeModuleOnUnmount={disposeModuleOnUnmount}\n />\n </REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE.Provider>\n </REACT_X_INJECTION_CONTEXT.Provider>\n );\n}\n\nfunction XInjectionChildrenRenderer({\n children,\n module,\n tryReInitModuleOnMount,\n disposeModuleOnUnmount = false,\n}: Except<ModuleProviderProps, 'module'> & { module: { ctx: IComponentProviderModule } }) {\n const componentModuleInstance = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT);\n const rerenderParentCtx = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE);\n\n // We use the `useEffectOnce` custom hook in order\n // to make sure that if the developer is providing the\n // `tryReInitModuleOnMount` and/or `disposeModuleOnUnmount` options\n // we do not early dispose the module when React double re-renders the\n // component while StrictMode is enabled.\n // This hook guarantees that the same behavior is expected with or without StrictMode.\n //\n // https://react.dev/reference/react/StrictMode\n useEffectOnce(() => {\n // ON MOUNT\n\n const moduleNaked = module.ctx.toNaked();\n\n if (componentModuleInstance) {\n const contextualizedImportedModules = module.ctx.toNaked().imports.map((importedModule) => {\n const shouldReplaceImportedModuleWithContextualized =\n componentModuleInstance.get(importedModule.toString())?.toString() === importedModule.toString();\n\n /* istanbul ignore next */\n if (!shouldReplaceImportedModuleWithContextualized)\n return importedModule as unknown as IComponentProviderModuleNaked;\n\n return componentModuleInstance.get(importedModule.toString()) as IComponentProviderModuleNaked;\n });\n\n if (contextualizedImportedModules.length > 0) {\n module.ctx.toNaked()._lazyInit({\n ...module.ctx.toNaked()._initialOptions,\n imports: contextualizedImportedModules,\n });\n\n // This will force the parent to re-render when using the `useRerenderOnChildrenModuleContextLoaded` hook.\n rerenderParentCtx.r++;\n }\n }\n\n /* istanbul ignore next */\n if (moduleNaked.isDisposed && tryReInitModuleOnMount) {\n /* istanbul ignore next */\n moduleNaked._lazyInit(tryReInitModuleOnMount);\n }\n\n return () => {\n // ON UNMOUNT\n\n if (!disposeModuleOnUnmount || moduleNaked.isDisposed) return;\n\n moduleNaked._dispose();\n };\n });\n\n return children;\n}\n","import type { ProviderToken } from '@adimm/x-injection';\n\nimport { useOnce } from '../../helpers';\nimport { useInjectOnRender, type UseInjectOptions } from './use-inject-on-render';\n\n/**\n * React `hook` which can be used inside a component to inject the required {@link provider | dependency}.\n *\n * **Note:** _By using this hook, the dependency will be injected only once after the first component mount process._\n * _If you need to re-inject the dependency on each re-render, you must use the `useInjectOnRender` hook._\n * _It basically acts like a `Request` scope, ensuring that even a `Transient` dependency does not mutate during re-renders._\n *\n * @param provider The {@link ProviderToken}.\n * @param options See {@link UseInjectSharedOptions}.\n * @returns Either the {@link T | dependency} or `undefined` if {@link isOptional} is set to `true`.\n */\nexport function useInject<T>(provider: ProviderToken<T>, options?: UseInjectOptions): T {\n return useOnce(() => useInjectOnRender(provider, options));\n}\n","import type {\n ProviderModuleGetManyParam,\n ProviderModuleGetManySignature,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n ProviderToken,\n} from '@adimm/x-injection';\nimport { useContext } from 'react';\n\nimport type { UseInjectSharedOptions } from '../../types';\nimport { REACT_X_INJECTION_CONTEXT } from '../providers';\n\n/**\n * Can be used to retrieve many resolved `dependencies` from the module container at once.\n *\n * **Note:** _By using this hook, the dependencies will be injected on each re-render process._\n * _If you need to inject the dependencies only once, you must use the `useInjectMany` hook._\n *\n * @param options See {@link UseInjectSharedOptions}.\n * @param deps Either one or more {@link ProviderToken}.\n * @returns Tuple containing the {@link D | dependencies}.\n */\nexport function useInjectManyOnRender<D extends (ProviderModuleGetManyParam<any> | ProviderToken)[]>({\n deps,\n}: {\n deps: [...(D | unknown[])];\n options?: UseInjectSharedOptions;\n}): ProviderModuleGetManySignature<D> {\n const componentModule = useContext(REACT_X_INJECTION_CONTEXT);\n\n return componentModule.ctx.getMany(...deps);\n}\n","import type { ProviderModuleGetManyParam, ProviderModuleGetManySignature, ProviderToken } from '@adimm/x-injection';\n\nimport { useOnce } from '../../helpers';\nimport type { UseInjectSharedOptions } from '../../types';\nimport { useInjectManyOnRender } from './use-inject-many-on-render';\n\n/**\n * Can be used to retrieve many resolved `dependencies` from the module container at once.\n *\n * **Note:** _By using this hook, the dependencies will be injected only once after the first component mount process._\n * _If you need to re-inject the dependencies on each re-render, you must use the `useInjectManyOnRender` hook._\n *\n * @param options See {@link UseInjectSharedOptions}.\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,\n options,\n}: {\n deps: [...(D | unknown[])];\n options?: UseInjectSharedOptions;\n}): ProviderModuleGetManySignature<D> {\n return useOnce(() => useInjectManyOnRender({ options, deps }));\n}\n","import { useContext } from 'react';\n\nimport { REACT_X_INJECTION_CONTEXT, REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT } from '../providers';\n\nexport function useExposeComponentModuleContext(): void {\n const componentModule = useContext(REACT_X_INJECTION_CONTEXT);\n const exposed = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT);\n\n exposed.set(componentModule.ctx.toString(), componentModule.ctx);\n}\n","import { useContext, useEffect, useState } from 'react';\n\nimport { REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE } from '../providers';\n\n/**\n * This is an **experimental** hook which can be used to make sure that a component will re-render when a children\n * exposes its internal context module.\n *\n * It works best with the `useInjectOnRender` hook, as it'll re-resolve all the required dependencies\n * of the injected ProviderToken.\n *\n * **Use it carefully as it may lead to unnecessary re-render cycles or it may even not work as expected!**\n * **It's safer to use the `TapIntoComponent` wrapper component with the `contextInstance` to manually inject the**\n * **contextualized dependencies of the children into a parent component service!**\n *\n * @experimental\n */\nexport function useRerenderOnChildrenModuleContextLoaded(): void {\n const rerenderParentCtx = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE);\n const [, setRerender] = useState(0);\n\n useEffect(() => {\n setRerender((x) => x + 1);\n }, [rerenderParentCtx.r]);\n}\n","import {\n InjectionScope,\n isClass,\n isClassOrFunction,\n ProviderModule,\n ProviderModuleHelpers,\n type DependencyProvider,\n type IProviderModuleNaked,\n type ProviderClassToken,\n type ProviderModuleOptions,\n type ProviderValueToken,\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 protected readonly _initialOptions: IComponentProviderModuleNaked['_initialOptions'];\n\n constructor(options: ProviderModuleOptions) {\n super(\n ProviderModuleHelpers.buildInternalConstructorParams({\n ...options,\n // By default components should have all their providers\n // defined as transient because a component may have more than one instance of itself.\n defaultScope: options.defaultScope ?? InjectionScope.Transient,\n identifier: Symbol(`Component${options.identifier.description}`),\n })\n );\n\n this._initializedFromComponent = false;\n this._initialOptions = options;\n }\n\n override toNaked(): IComponentProviderModuleNaked & IProviderModuleNaked {\n return this as any;\n }\n\n /* istanbul ignore next */\n dispose(): void {\n this._dispose();\n }\n\n /**\n * **Publicly visible when the instance is casted to {@link IComponentProviderModuleNaked}.**\n *\n * See {@link IComponentProviderModuleNaked._convertToContextualizedComponentInstance}.\n */\n /* istanbul ignore next */\n protected _convertToContextualizedComponentInstance(): IComponentProviderModule {\n if (this.isAppModule || this.isDisposed) return this;\n\n const contextualizedProviders = this._getProviders().map((provider) => {\n if (!isClassOrFunction(provider)) {\n return {\n ...provider,\n scope: InjectionScope.Singleton,\n } as DependencyProvider;\n }\n\n if (isClass(provider)) {\n return {\n scope: InjectionScope.Singleton,\n provide: provider,\n useClass: provider,\n } as ProviderClassToken<any>;\n }\n\n return {\n provide: provider,\n useValue: provider,\n } as ProviderValueToken<any>;\n });\n\n const componentModule = new ComponentProviderModule({\n ...this._initialOptions,\n providers: contextualizedProviders,\n });\n\n //@ts-expect-error Read-only property.\n componentModule._initializedFromComponent = true;\n\n return componentModule;\n }\n}\n","import { useContext, useEffect, useMemo } from 'react';\nimport type { Except } from 'type-fest';\n\nimport { REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT } from '../../providers';\nimport type { TapIntoComponentContextProps } from './interfaces';\n\n/**\n * This component is the standard way to \"tap into\" an instance of the component\n * in order to get access to its scoped module container and its _(exposed)_ dependencies _instances_.\n *\n * @param contextInstance See {@link TapIntoComponentContextProps.contextInstance}.\n * @param exposed See {@link TapIntoComponentContextProps.exposed}.\n */\nexport function TapIntoComponent({ children, contextInstance }: TapIntoComponentContextProps) {\n const moduleContextMap = useMemo(() => new Map(), []);\n\n return (\n <REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT.Provider value={moduleContextMap}>\n <CtxExposer contextInstance={contextInstance} />\n {children}\n </REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT.Provider>\n );\n}\n\nfunction CtxExposer({ contextInstance }: Except<TapIntoComponentContextProps, 'children'>) {\n const ctxMap = useContext(REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT);\n\n useEffect(() => {\n const fluidSyntax = contextInstance?.(ctxMap);\n if (!fluidSyntax) return;\n\n const moduleCtx = ctxMap.get(fluidSyntax.tryGet.toString());\n /* istanbul ignore next */\n if (!moduleCtx) return;\n\n fluidSyntax.thenDo(moduleCtx);\n }, [ctxMap]);\n\n return null;\n}\n"],"mappings":"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","names":["useRef","useOnce","fn","ref","useRef","current","value","useEffect","useRef","useState","useEffectOnce","effect","destroyFunc","useRef","undefined","effectCalled","renderAfterCalled","forceRerender","useState","current","useEffect","x","useContext","AppModule","createContext","REACT_X_INJECTION_CONTEXT","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","Map","REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE","r","useContext","useMemo","ModuleProvider","children","module","tryReInitModuleOnMount","disposeModuleOnUnmount","isAppModule","toNaked","moduleCtxReference","ctx","useMemo","_convertToContextualizedComponentInstance","REACT_X_INJECTION_CONTEXT","Provider","value","REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE","r","XInjectionChildrenRenderer","componentModuleInstance","useContext","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","rerenderParentCtx","useEffectOnce","moduleNaked","contextualizedImportedModules","imports","map","importedModule","shouldReplaceImportedModuleWithContextualized","get","toString","length","_lazyInit","_initialOptions","isDisposed","_dispose","useInjectOnRender","provider","options","componentModule","useContext","REACT_X_INJECTION_CONTEXT","ctx","get","isOptional","useInject","provider","options","useOnce","useInjectOnRender","useContext","useInjectManyOnRender","deps","componentModule","useContext","REACT_X_INJECTION_CONTEXT","ctx","getMany","useInjectMany","deps","options","useOnce","useInjectManyOnRender","useContext","useExposeComponentModuleContext","componentModule","useContext","REACT_X_INJECTION_CONTEXT","exposed","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","set","ctx","toString","useContext","useEffect","useState","useRerenderOnChildrenModuleContextLoaded","rerenderParentCtx","useContext","REACT_X_INJECTION_EXPOSED_COMPONENT_RERENDER_ON_CTX_CHANGE","setRerender","useState","useEffect","x","r","InjectionScope","isClass","isClassOrFunction","ProviderModule","ProviderModuleHelpers","ComponentProviderModule","ProviderModule","_initializedFromComponent","_initialOptions","constructor","options","ProviderModuleHelpers","buildInternalConstructorParams","defaultScope","InjectionScope","Transient","identifier","Symbol","description","toNaked","dispose","_dispose","_convertToContextualizedComponentInstance","isAppModule","isDisposed","contextualizedProviders","_getProviders","map","provider","isClassOrFunction","scope","Singleton","isClass","provide","useClass","useValue","componentModule","providers","useContext","useEffect","useMemo","TapIntoComponent","children","contextInstance","moduleContextMap","useMemo","Map","REACT_X_INJECTION_EXPOSED_COMPONENT_MODULE_CONTEXT","Provider","value","CtxExposer","ctxMap","useContext","useEffect","fluidSyntax","moduleCtx","get","tryGet","toString","thenDo"]}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@adimm/x-injection-reactjs",
3
+ "description": "ReactJS integration of the `xInjection` library.",
4
+ "version": "0.1.0",
5
+ "author": "Adi-Marian Mutu",
6
+ "homepage": "https://github.com/AdiMarianMutu/x-injection-reactjs#readme",
7
+ "bugs": "https://github.com/AdiMarianMutu/x-injection-reactjs/issues",
8
+ "keywords": [
9
+ "inversion of control",
10
+ "ioc",
11
+ "di",
12
+ "dependency injection",
13
+ "reactjs",
14
+ "components",
15
+ "inversify",
16
+ "nest",
17
+ "ts",
18
+ "typescript"
19
+ ],
20
+ "license": "MIT",
21
+ "scripts": {
22
+ "build": "tsup --config ./config/tsup.config.ts",
23
+ "docs:build": "typedoc --options ./config/typedoc.json",
24
+ "docs:serve": "npm run docs:build && http-server ./docs --cors -p 8080 -c-1",
25
+ "lint": "eslint \"src/**/*.{ts,tsx}\" --config ./config/.eslintrc.cjs",
26
+ "lint:fix": "npm run lint -- --fix",
27
+ "prebuild": "rimraf dist",
28
+ "prepare": "husky install",
29
+ "pretest": "rimraf coverage",
30
+ "prettier:format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"config/**/*\" --config config/.prettierrc.cjs",
31
+ "start": "npm run build && node dist/index.js",
32
+ "start:watch": "tsup src/index.ts --config ./config/tsup.config.ts --watch --onSuccess 'node dist/index.js'",
33
+ "test": "jest --config ./config/jest.config.ts",
34
+ "test:coverage": "npm run test && http-server ./coverage/lcov-report --cors -p 8081 -c-1",
35
+ "v:bump-patch": "npm version patch -m \"chore: update `package.json` patch version to %s\"",
36
+ "v:bump-minor": "npm version minor -m \"chore: update `package.json` minor version to %s\"",
37
+ "v:bump-major": "npm version major -m \"chore: update `package.json` major version %s\""
38
+ },
39
+ "dependencies": {
40
+ "@adimm/x-injection": "^0.4.0",
41
+ "react": ">=18.0.0"
42
+ },
43
+ "devDependencies": {
44
+ "@ianvs/prettier-plugin-sort-imports": "^4.4.1",
45
+ "@swc/core": "^1.11.24",
46
+ "@testing-library/jest-dom": "^6.6.3",
47
+ "@testing-library/react": "^16.3.0",
48
+ "@tsconfig/node18": "^18.2.4",
49
+ "@types/jest": "^29.5.14",
50
+ "@types/react": "^19.1.2",
51
+ "@typescript-eslint/eslint-plugin": "^6.21.0",
52
+ "eslint": "^8.57.1",
53
+ "eslint-config-prettier": "^9.1.0",
54
+ "eslint-plugin-import": "^2.31.0",
55
+ "eslint-plugin-prettier": "^5.3.1",
56
+ "http-server": "^14.1.1",
57
+ "husky": "^9.1.7",
58
+ "jest": "^29.7.0",
59
+ "jest-environment-jsdom": "^29.7.0",
60
+ "node-notifier": "^10.0.1",
61
+ "prettier": "3.2.4",
62
+ "rimraf": "^5.0.10",
63
+ "terser": "^5.39.0",
64
+ "ts-jest": "^29.3.2",
65
+ "ts-node": "^10.9.2",
66
+ "tsup": "^8.4.0",
67
+ "type-fest": "^4.40.1",
68
+ "typedoc": "^0.28.4",
69
+ "typedoc-theme-hierarchy": "^6.0.0",
70
+ "typescript": "^5.8.3"
71
+ },
72
+ "optionalDependencies": {
73
+ "@rollup/rollup-linux-x64-gnu": "4.40.2"
74
+ },
75
+ "engines": {
76
+ "node": ">=18.0.0"
77
+ },
78
+ "files": [
79
+ "dist"
80
+ ],
81
+ "type": "module",
82
+ "main": "./dist/index.cjs",
83
+ "module": "./dist/index.js",
84
+ "types": "./dist/index.d.ts",
85
+ "sideEffects": false
86
+ }