@abdokouta/ts-container-react 1.0.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) 2024 Refine
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/dist/index.cjs ADDED
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var jsxRuntime = require('react/jsx-runtime');
5
+
6
+ // src/contexts/container.context.ts
7
+ var ContainerContext = react.createContext(null);
8
+ ContainerContext.displayName = "ContainerContext";
9
+ function ContainerProvider({ context, children }) {
10
+ return /* @__PURE__ */ jsxRuntime.jsx(ContainerContext.Provider, { value: context, children });
11
+ }
12
+ function useContainer() {
13
+ const context = react.useContext(ContainerContext);
14
+ if (!context) {
15
+ throw new Error(
16
+ "useContainer() must be used within a <ContainerProvider>. Wrap your component tree with <ContainerProvider context={app}>."
17
+ );
18
+ }
19
+ return context;
20
+ }
21
+ function useInject(token) {
22
+ const container = useContainer();
23
+ return react.useMemo(() => container.get(token), [container, token]);
24
+ }
25
+ function useOptionalInject(token) {
26
+ const container = useContainer();
27
+ return react.useMemo(() => container.getOptional(token), [container, token]);
28
+ }
29
+
30
+ exports.ContainerContext = ContainerContext;
31
+ exports.ContainerProvider = ContainerProvider;
32
+ exports.useContainer = useContainer;
33
+ exports.useInject = useInject;
34
+ exports.useOptionalInject = useOptionalInject;
35
+ //# sourceMappingURL=index.cjs.map
36
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/contexts/container.context.ts","../src/providers/container.provider.tsx","../src/hooks/use-container.hook.ts","../src/hooks/use-inject.hook.ts","../src/hooks/use-optional-inject.hook.ts"],"names":["createContext","useContext","useMemo"],"mappings":";;;;;;AAkBO,IAAM,gBAAA,GAAmBA,oBAAwC,IAAI;AAE5E,gBAAA,CAAiB,WAAA,GAAc,kBAAA;ACUxB,SAAS,iBAAA,CAAkB,EAAE,OAAA,EAAS,QAAA,EAAS,EAA2B;AAC/E,EAAA,sCACG,gBAAA,CAAiB,QAAA,EAAjB,EAA0B,KAAA,EAAO,SAC/B,QAAA,EACH,CAAA;AAEJ;ACJO,SAAS,YAAA,GAAkC;AAChD,EAAA,MAAM,OAAA,GAAUC,iBAAW,gBAAgB,CAAA;AAE3C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;ACFO,SAAS,UAAmB,KAAA,EAA6B;AAC9D,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,OAAOC,aAAA,CAAQ,MAAM,SAAA,CAAU,GAAA,CAAO,KAAK,CAAA,EAAG,CAAC,SAAA,EAAW,KAAK,CAAC,CAAA;AAClE;ACNO,SAAS,kBAA2B,KAAA,EAAyC;AAClF,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,OAAOA,aAAAA,CAAQ,MAAM,SAAA,CAAU,WAAA,CAAe,KAAK,CAAA,EAAG,CAAC,SAAA,EAAW,KAAK,CAAC,CAAA;AAC1E","file":"index.cjs","sourcesContent":["/**\n * @fileoverview React context for the DI container.\n *\n * Holds a `ContainerResolver` reference that React hooks use to\n * resolve providers. The resolver is provided by `<ContainerProvider>`.\n *\n * @module contexts/context\n */\n\nimport { createContext } from 'react';\nimport type { ContainerResolver } from '@abdokouta/ts-container';\n\n/**\n * React context that holds the container resolver.\n *\n * `null` by default — must be provided by `ContainerProvider`.\n * Using `useInject()` outside of a `ContainerProvider` will throw.\n */\nexport const ContainerContext = createContext<ContainerResolver | null>(null);\n\nContainerContext.displayName = 'ContainerContext';\n","/**\n * @fileoverview ContainerProvider — React component that provides the DI container.\n *\n * Wrap your application (or a subtree) with `<ContainerProvider>` to make\n * the DI container available to all child components via `useInject()`.\n *\n * @module providers/provider\n */\n\nimport { ContainerContext } from '@/contexts/container.context';\nimport type { ContainerProviderProps } from '@/interfaces/container-provider-props.interface';\n\n/**\n * Provides the DI container to the React component tree.\n *\n * @example\n * ```tsx\n * import { ContainerProvider } from '@abdokouta/ts-container-react';\n * import { ApplicationContext } from '@abdokouta/ts-application';\n * import { AppModule } from './app.module';\n *\n * const app = await ApplicationContext.create(AppModule);\n *\n * ReactDOM.createRoot(document.getElementById('root')!).render(\n * <ContainerProvider context={app}>\n * <App />\n * </ContainerProvider>\n * );\n * ```\n */\nexport function ContainerProvider({ context, children }: ContainerProviderProps) {\n return (\n <ContainerContext.Provider value={context}>\n {children}\n </ContainerContext.Provider>\n );\n}\n","/**\n * @fileoverview useContainer hook — access the raw ContainerResolver.\n *\n * @module hooks/use-container\n */\n\nimport { useContext } from 'react';\nimport type { ContainerResolver } from '@abdokouta/ts-container';\nimport { ContainerContext } from '@/contexts/container.context';\n\n/**\n * Get the container resolver from React context.\n *\n * Returns the `ContainerResolver` provided by `<ContainerProvider>`.\n * Useful when you need direct access to `has()` or other resolver methods.\n *\n * For most cases, prefer `useInject()` instead.\n *\n * @returns The ContainerResolver instance\n * @throws Error if used outside of `<ContainerProvider>`\n *\n * @example\n * ```typescript\n * import { useContainer } from '@pixielity/react';\n *\n * function DebugPanel() {\n * const container = useContainer();\n * const hasCache = container.has(CacheManager);\n * return <div>Cache available: {String(hasCache)}</div>;\n * }\n * ```\n */\nexport function useContainer(): ContainerResolver {\n const context = useContext(ContainerContext);\n\n if (!context) {\n throw new Error(\n 'useContainer() must be used within a <ContainerProvider>. ' +\n 'Wrap your component tree with <ContainerProvider context={app}>.',\n );\n }\n\n return context;\n}\n","/**\n * @fileoverview useInject hook — resolve a provider from the DI container.\n *\n * This is the primary hook for accessing services in React components.\n *\n * @module hooks/use-inject\n */\n\nimport { useMemo } from 'react';\nimport type { InjectionToken } from '@abdokouta/ts-container';\nimport { useContainer } from './use-container.hook';\n\n/**\n * Resolve a provider from the DI container.\n *\n * The resolved instance is memoized — it won't change between renders\n * unless the container or token changes.\n *\n * @typeParam T - The type of the resolved provider\n * @param token - The injection token (class, string, or symbol)\n * @returns The resolved provider instance\n * @throws Error if the provider is not found or if used outside `<ContainerProvider>`\n *\n * @example\n * ```typescript\n * import { useInject } from '@pixielity/react';\n *\n * // Inject by class\n * function UserProfile() {\n * const userService = useInject(UserService);\n * const user = userService.getUser('123');\n * return <div>{user.name}</div>;\n * }\n *\n * // Inject by symbol token\n * function CacheStatus() {\n * const config = useInject<CacheConfig>(CACHE_CONFIG);\n * return <div>Default store: {config.default}</div>;\n * }\n * ```\n */\nexport function useInject<T = any>(token: InjectionToken<T>): T {\n const container = useContainer();\n return useMemo(() => container.get<T>(token), [container, token]);\n}\n","/**\n * @fileoverview useOptionalInject hook — optionally resolve a provider.\n *\n * Like `useInject()`, but returns `undefined` instead of throwing\n * if the provider is not found.\n *\n * @module hooks/use-optional-inject\n */\n\nimport { useMemo } from 'react';\nimport type { InjectionToken } from '@abdokouta/ts-container';\nimport { useContainer } from './use-container.hook';\n\n/**\n * Optionally resolve a provider from the DI container.\n *\n * Returns `undefined` if the provider is not found, instead of throwing.\n * Useful for optional dependencies that may or may not be configured.\n *\n * @typeParam T - The type of the resolved provider\n * @param token - The injection token (class, string, or symbol)\n * @returns The resolved instance or `undefined`\n *\n * @example\n * ```typescript\n * import { useOptionalInject } from '@pixielity/react';\n *\n * function Analytics() {\n * const tracker = useOptionalInject(AnalyticsService);\n *\n * if (!tracker) {\n * return null; // Analytics not configured\n * }\n *\n * return <div>Tracking enabled</div>;\n * }\n * ```\n */\nexport function useOptionalInject<T = any>(token: InjectionToken<T>): T | undefined {\n const container = useContainer();\n return useMemo(() => container.getOptional<T>(token), [container, token]);\n}\n"]}
@@ -0,0 +1,167 @@
1
+ import * as react from 'react';
2
+ import react__default from 'react';
3
+ import { ContainerResolver, InjectionToken } from '@abdokouta/ts-container';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ /**
7
+ * React context that holds the container resolver.
8
+ *
9
+ * `null` by default — must be provided by `ContainerProvider`.
10
+ * Using `useInject()` outside of a `ContainerProvider` will throw.
11
+ */
12
+ declare const ContainerContext: react.Context<ContainerResolver | null>;
13
+
14
+ /**
15
+ * @fileoverview ContainerProviderProps — props for the ContainerProvider component.
16
+ *
17
+ * @module interfaces/container-provider-props
18
+ */
19
+
20
+ /**
21
+ * Props for the `<ContainerProvider>` component.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <ContainerProvider context={app}>
26
+ * <App />
27
+ * </ContainerProvider>
28
+ * ```
29
+ */
30
+ interface ContainerProviderProps {
31
+ /**
32
+ * The container resolver (typically an ApplicationContext from `@pixielity/application`).
33
+ * Must implement `get()`, `getOptional()`, and `has()`.
34
+ */
35
+ context: ContainerResolver;
36
+ /**
37
+ * Child components that will have access to the container.
38
+ */
39
+ children: react__default.ReactNode;
40
+ }
41
+
42
+ /**
43
+ * Provides the DI container to the React component tree.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * import { ContainerProvider } from '@abdokouta/ts-container-react';
48
+ * import { ApplicationContext } from '@abdokouta/ts-application';
49
+ * import { AppModule } from './app.module';
50
+ *
51
+ * const app = await ApplicationContext.create(AppModule);
52
+ *
53
+ * ReactDOM.createRoot(document.getElementById('root')!).render(
54
+ * <ContainerProvider context={app}>
55
+ * <App />
56
+ * </ContainerProvider>
57
+ * );
58
+ * ```
59
+ */
60
+ declare function ContainerProvider({ context, children }: ContainerProviderProps): react_jsx_runtime.JSX.Element;
61
+
62
+ /**
63
+ * @fileoverview useContainer hook — access the raw ContainerResolver.
64
+ *
65
+ * @module hooks/use-container
66
+ */
67
+
68
+ /**
69
+ * Get the container resolver from React context.
70
+ *
71
+ * Returns the `ContainerResolver` provided by `<ContainerProvider>`.
72
+ * Useful when you need direct access to `has()` or other resolver methods.
73
+ *
74
+ * For most cases, prefer `useInject()` instead.
75
+ *
76
+ * @returns The ContainerResolver instance
77
+ * @throws Error if used outside of `<ContainerProvider>`
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * import { useContainer } from '@pixielity/react';
82
+ *
83
+ * function DebugPanel() {
84
+ * const container = useContainer();
85
+ * const hasCache = container.has(CacheManager);
86
+ * return <div>Cache available: {String(hasCache)}</div>;
87
+ * }
88
+ * ```
89
+ */
90
+ declare function useContainer(): ContainerResolver;
91
+
92
+ /**
93
+ * @fileoverview useInject hook — resolve a provider from the DI container.
94
+ *
95
+ * This is the primary hook for accessing services in React components.
96
+ *
97
+ * @module hooks/use-inject
98
+ */
99
+
100
+ /**
101
+ * Resolve a provider from the DI container.
102
+ *
103
+ * The resolved instance is memoized — it won't change between renders
104
+ * unless the container or token changes.
105
+ *
106
+ * @typeParam T - The type of the resolved provider
107
+ * @param token - The injection token (class, string, or symbol)
108
+ * @returns The resolved provider instance
109
+ * @throws Error if the provider is not found or if used outside `<ContainerProvider>`
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import { useInject } from '@pixielity/react';
114
+ *
115
+ * // Inject by class
116
+ * function UserProfile() {
117
+ * const userService = useInject(UserService);
118
+ * const user = userService.getUser('123');
119
+ * return <div>{user.name}</div>;
120
+ * }
121
+ *
122
+ * // Inject by symbol token
123
+ * function CacheStatus() {
124
+ * const config = useInject<CacheConfig>(CACHE_CONFIG);
125
+ * return <div>Default store: {config.default}</div>;
126
+ * }
127
+ * ```
128
+ */
129
+ declare function useInject<T = any>(token: InjectionToken<T>): T;
130
+
131
+ /**
132
+ * @fileoverview useOptionalInject hook — optionally resolve a provider.
133
+ *
134
+ * Like `useInject()`, but returns `undefined` instead of throwing
135
+ * if the provider is not found.
136
+ *
137
+ * @module hooks/use-optional-inject
138
+ */
139
+
140
+ /**
141
+ * Optionally resolve a provider from the DI container.
142
+ *
143
+ * Returns `undefined` if the provider is not found, instead of throwing.
144
+ * Useful for optional dependencies that may or may not be configured.
145
+ *
146
+ * @typeParam T - The type of the resolved provider
147
+ * @param token - The injection token (class, string, or symbol)
148
+ * @returns The resolved instance or `undefined`
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * import { useOptionalInject } from '@pixielity/react';
153
+ *
154
+ * function Analytics() {
155
+ * const tracker = useOptionalInject(AnalyticsService);
156
+ *
157
+ * if (!tracker) {
158
+ * return null; // Analytics not configured
159
+ * }
160
+ *
161
+ * return <div>Tracking enabled</div>;
162
+ * }
163
+ * ```
164
+ */
165
+ declare function useOptionalInject<T = any>(token: InjectionToken<T>): T | undefined;
166
+
167
+ export { ContainerContext, ContainerProvider, type ContainerProviderProps, useContainer, useInject, useOptionalInject };
@@ -0,0 +1,167 @@
1
+ import * as react from 'react';
2
+ import react__default from 'react';
3
+ import { ContainerResolver, InjectionToken } from '@abdokouta/ts-container';
4
+ import * as react_jsx_runtime from 'react/jsx-runtime';
5
+
6
+ /**
7
+ * React context that holds the container resolver.
8
+ *
9
+ * `null` by default — must be provided by `ContainerProvider`.
10
+ * Using `useInject()` outside of a `ContainerProvider` will throw.
11
+ */
12
+ declare const ContainerContext: react.Context<ContainerResolver | null>;
13
+
14
+ /**
15
+ * @fileoverview ContainerProviderProps — props for the ContainerProvider component.
16
+ *
17
+ * @module interfaces/container-provider-props
18
+ */
19
+
20
+ /**
21
+ * Props for the `<ContainerProvider>` component.
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * <ContainerProvider context={app}>
26
+ * <App />
27
+ * </ContainerProvider>
28
+ * ```
29
+ */
30
+ interface ContainerProviderProps {
31
+ /**
32
+ * The container resolver (typically an ApplicationContext from `@pixielity/application`).
33
+ * Must implement `get()`, `getOptional()`, and `has()`.
34
+ */
35
+ context: ContainerResolver;
36
+ /**
37
+ * Child components that will have access to the container.
38
+ */
39
+ children: react__default.ReactNode;
40
+ }
41
+
42
+ /**
43
+ * Provides the DI container to the React component tree.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * import { ContainerProvider } from '@abdokouta/ts-container-react';
48
+ * import { ApplicationContext } from '@abdokouta/ts-application';
49
+ * import { AppModule } from './app.module';
50
+ *
51
+ * const app = await ApplicationContext.create(AppModule);
52
+ *
53
+ * ReactDOM.createRoot(document.getElementById('root')!).render(
54
+ * <ContainerProvider context={app}>
55
+ * <App />
56
+ * </ContainerProvider>
57
+ * );
58
+ * ```
59
+ */
60
+ declare function ContainerProvider({ context, children }: ContainerProviderProps): react_jsx_runtime.JSX.Element;
61
+
62
+ /**
63
+ * @fileoverview useContainer hook — access the raw ContainerResolver.
64
+ *
65
+ * @module hooks/use-container
66
+ */
67
+
68
+ /**
69
+ * Get the container resolver from React context.
70
+ *
71
+ * Returns the `ContainerResolver` provided by `<ContainerProvider>`.
72
+ * Useful when you need direct access to `has()` or other resolver methods.
73
+ *
74
+ * For most cases, prefer `useInject()` instead.
75
+ *
76
+ * @returns The ContainerResolver instance
77
+ * @throws Error if used outside of `<ContainerProvider>`
78
+ *
79
+ * @example
80
+ * ```typescript
81
+ * import { useContainer } from '@pixielity/react';
82
+ *
83
+ * function DebugPanel() {
84
+ * const container = useContainer();
85
+ * const hasCache = container.has(CacheManager);
86
+ * return <div>Cache available: {String(hasCache)}</div>;
87
+ * }
88
+ * ```
89
+ */
90
+ declare function useContainer(): ContainerResolver;
91
+
92
+ /**
93
+ * @fileoverview useInject hook — resolve a provider from the DI container.
94
+ *
95
+ * This is the primary hook for accessing services in React components.
96
+ *
97
+ * @module hooks/use-inject
98
+ */
99
+
100
+ /**
101
+ * Resolve a provider from the DI container.
102
+ *
103
+ * The resolved instance is memoized — it won't change between renders
104
+ * unless the container or token changes.
105
+ *
106
+ * @typeParam T - The type of the resolved provider
107
+ * @param token - The injection token (class, string, or symbol)
108
+ * @returns The resolved provider instance
109
+ * @throws Error if the provider is not found or if used outside `<ContainerProvider>`
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import { useInject } from '@pixielity/react';
114
+ *
115
+ * // Inject by class
116
+ * function UserProfile() {
117
+ * const userService = useInject(UserService);
118
+ * const user = userService.getUser('123');
119
+ * return <div>{user.name}</div>;
120
+ * }
121
+ *
122
+ * // Inject by symbol token
123
+ * function CacheStatus() {
124
+ * const config = useInject<CacheConfig>(CACHE_CONFIG);
125
+ * return <div>Default store: {config.default}</div>;
126
+ * }
127
+ * ```
128
+ */
129
+ declare function useInject<T = any>(token: InjectionToken<T>): T;
130
+
131
+ /**
132
+ * @fileoverview useOptionalInject hook — optionally resolve a provider.
133
+ *
134
+ * Like `useInject()`, but returns `undefined` instead of throwing
135
+ * if the provider is not found.
136
+ *
137
+ * @module hooks/use-optional-inject
138
+ */
139
+
140
+ /**
141
+ * Optionally resolve a provider from the DI container.
142
+ *
143
+ * Returns `undefined` if the provider is not found, instead of throwing.
144
+ * Useful for optional dependencies that may or may not be configured.
145
+ *
146
+ * @typeParam T - The type of the resolved provider
147
+ * @param token - The injection token (class, string, or symbol)
148
+ * @returns The resolved instance or `undefined`
149
+ *
150
+ * @example
151
+ * ```typescript
152
+ * import { useOptionalInject } from '@pixielity/react';
153
+ *
154
+ * function Analytics() {
155
+ * const tracker = useOptionalInject(AnalyticsService);
156
+ *
157
+ * if (!tracker) {
158
+ * return null; // Analytics not configured
159
+ * }
160
+ *
161
+ * return <div>Tracking enabled</div>;
162
+ * }
163
+ * ```
164
+ */
165
+ declare function useOptionalInject<T = any>(token: InjectionToken<T>): T | undefined;
166
+
167
+ export { ContainerContext, ContainerProvider, type ContainerProviderProps, useContainer, useInject, useOptionalInject };
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import { createContext, useContext, useMemo } from 'react';
2
+ import { jsx } from 'react/jsx-runtime';
3
+
4
+ // src/contexts/container.context.ts
5
+ var ContainerContext = createContext(null);
6
+ ContainerContext.displayName = "ContainerContext";
7
+ function ContainerProvider({ context, children }) {
8
+ return /* @__PURE__ */ jsx(ContainerContext.Provider, { value: context, children });
9
+ }
10
+ function useContainer() {
11
+ const context = useContext(ContainerContext);
12
+ if (!context) {
13
+ throw new Error(
14
+ "useContainer() must be used within a <ContainerProvider>. Wrap your component tree with <ContainerProvider context={app}>."
15
+ );
16
+ }
17
+ return context;
18
+ }
19
+ function useInject(token) {
20
+ const container = useContainer();
21
+ return useMemo(() => container.get(token), [container, token]);
22
+ }
23
+ function useOptionalInject(token) {
24
+ const container = useContainer();
25
+ return useMemo(() => container.getOptional(token), [container, token]);
26
+ }
27
+
28
+ export { ContainerContext, ContainerProvider, useContainer, useInject, useOptionalInject };
29
+ //# sourceMappingURL=index.js.map
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/contexts/container.context.ts","../src/providers/container.provider.tsx","../src/hooks/use-container.hook.ts","../src/hooks/use-inject.hook.ts","../src/hooks/use-optional-inject.hook.ts"],"names":["useMemo"],"mappings":";;;;AAkBO,IAAM,gBAAA,GAAmB,cAAwC,IAAI;AAE5E,gBAAA,CAAiB,WAAA,GAAc,kBAAA;ACUxB,SAAS,iBAAA,CAAkB,EAAE,OAAA,EAAS,QAAA,EAAS,EAA2B;AAC/E,EAAA,2BACG,gBAAA,CAAiB,QAAA,EAAjB,EAA0B,KAAA,EAAO,SAC/B,QAAA,EACH,CAAA;AAEJ;ACJO,SAAS,YAAA,GAAkC;AAChD,EAAA,MAAM,OAAA,GAAU,WAAW,gBAAgB,CAAA;AAE3C,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AAEA,EAAA,OAAO,OAAA;AACT;ACFO,SAAS,UAAmB,KAAA,EAA6B;AAC9D,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,OAAO,OAAA,CAAQ,MAAM,SAAA,CAAU,GAAA,CAAO,KAAK,CAAA,EAAG,CAAC,SAAA,EAAW,KAAK,CAAC,CAAA;AAClE;ACNO,SAAS,kBAA2B,KAAA,EAAyC;AAClF,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,OAAOA,OAAAA,CAAQ,MAAM,SAAA,CAAU,WAAA,CAAe,KAAK,CAAA,EAAG,CAAC,SAAA,EAAW,KAAK,CAAC,CAAA;AAC1E","file":"index.js","sourcesContent":["/**\n * @fileoverview React context for the DI container.\n *\n * Holds a `ContainerResolver` reference that React hooks use to\n * resolve providers. The resolver is provided by `<ContainerProvider>`.\n *\n * @module contexts/context\n */\n\nimport { createContext } from 'react';\nimport type { ContainerResolver } from '@abdokouta/ts-container';\n\n/**\n * React context that holds the container resolver.\n *\n * `null` by default — must be provided by `ContainerProvider`.\n * Using `useInject()` outside of a `ContainerProvider` will throw.\n */\nexport const ContainerContext = createContext<ContainerResolver | null>(null);\n\nContainerContext.displayName = 'ContainerContext';\n","/**\n * @fileoverview ContainerProvider — React component that provides the DI container.\n *\n * Wrap your application (or a subtree) with `<ContainerProvider>` to make\n * the DI container available to all child components via `useInject()`.\n *\n * @module providers/provider\n */\n\nimport { ContainerContext } from '@/contexts/container.context';\nimport type { ContainerProviderProps } from '@/interfaces/container-provider-props.interface';\n\n/**\n * Provides the DI container to the React component tree.\n *\n * @example\n * ```tsx\n * import { ContainerProvider } from '@abdokouta/ts-container-react';\n * import { ApplicationContext } from '@abdokouta/ts-application';\n * import { AppModule } from './app.module';\n *\n * const app = await ApplicationContext.create(AppModule);\n *\n * ReactDOM.createRoot(document.getElementById('root')!).render(\n * <ContainerProvider context={app}>\n * <App />\n * </ContainerProvider>\n * );\n * ```\n */\nexport function ContainerProvider({ context, children }: ContainerProviderProps) {\n return (\n <ContainerContext.Provider value={context}>\n {children}\n </ContainerContext.Provider>\n );\n}\n","/**\n * @fileoverview useContainer hook — access the raw ContainerResolver.\n *\n * @module hooks/use-container\n */\n\nimport { useContext } from 'react';\nimport type { ContainerResolver } from '@abdokouta/ts-container';\nimport { ContainerContext } from '@/contexts/container.context';\n\n/**\n * Get the container resolver from React context.\n *\n * Returns the `ContainerResolver` provided by `<ContainerProvider>`.\n * Useful when you need direct access to `has()` or other resolver methods.\n *\n * For most cases, prefer `useInject()` instead.\n *\n * @returns The ContainerResolver instance\n * @throws Error if used outside of `<ContainerProvider>`\n *\n * @example\n * ```typescript\n * import { useContainer } from '@pixielity/react';\n *\n * function DebugPanel() {\n * const container = useContainer();\n * const hasCache = container.has(CacheManager);\n * return <div>Cache available: {String(hasCache)}</div>;\n * }\n * ```\n */\nexport function useContainer(): ContainerResolver {\n const context = useContext(ContainerContext);\n\n if (!context) {\n throw new Error(\n 'useContainer() must be used within a <ContainerProvider>. ' +\n 'Wrap your component tree with <ContainerProvider context={app}>.',\n );\n }\n\n return context;\n}\n","/**\n * @fileoverview useInject hook — resolve a provider from the DI container.\n *\n * This is the primary hook for accessing services in React components.\n *\n * @module hooks/use-inject\n */\n\nimport { useMemo } from 'react';\nimport type { InjectionToken } from '@abdokouta/ts-container';\nimport { useContainer } from './use-container.hook';\n\n/**\n * Resolve a provider from the DI container.\n *\n * The resolved instance is memoized — it won't change between renders\n * unless the container or token changes.\n *\n * @typeParam T - The type of the resolved provider\n * @param token - The injection token (class, string, or symbol)\n * @returns The resolved provider instance\n * @throws Error if the provider is not found or if used outside `<ContainerProvider>`\n *\n * @example\n * ```typescript\n * import { useInject } from '@pixielity/react';\n *\n * // Inject by class\n * function UserProfile() {\n * const userService = useInject(UserService);\n * const user = userService.getUser('123');\n * return <div>{user.name}</div>;\n * }\n *\n * // Inject by symbol token\n * function CacheStatus() {\n * const config = useInject<CacheConfig>(CACHE_CONFIG);\n * return <div>Default store: {config.default}</div>;\n * }\n * ```\n */\nexport function useInject<T = any>(token: InjectionToken<T>): T {\n const container = useContainer();\n return useMemo(() => container.get<T>(token), [container, token]);\n}\n","/**\n * @fileoverview useOptionalInject hook — optionally resolve a provider.\n *\n * Like `useInject()`, but returns `undefined` instead of throwing\n * if the provider is not found.\n *\n * @module hooks/use-optional-inject\n */\n\nimport { useMemo } from 'react';\nimport type { InjectionToken } from '@abdokouta/ts-container';\nimport { useContainer } from './use-container.hook';\n\n/**\n * Optionally resolve a provider from the DI container.\n *\n * Returns `undefined` if the provider is not found, instead of throwing.\n * Useful for optional dependencies that may or may not be configured.\n *\n * @typeParam T - The type of the resolved provider\n * @param token - The injection token (class, string, or symbol)\n * @returns The resolved instance or `undefined`\n *\n * @example\n * ```typescript\n * import { useOptionalInject } from '@pixielity/react';\n *\n * function Analytics() {\n * const tracker = useOptionalInject(AnalyticsService);\n *\n * if (!tracker) {\n * return null; // Analytics not configured\n * }\n *\n * return <div>Tracking enabled</div>;\n * }\n * ```\n */\nexport function useOptionalInject<T = any>(token: InjectionToken<T>): T | undefined {\n const container = useContainer();\n return useMemo(() => container.getOptional<T>(token), [container, token]);\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "@abdokouta/ts-container-react",
3
+ "version": "1.0.0",
4
+ "description": "React bindings for @abdokouta/ts-container. ContainerProvider, useInject, useOptionalInject, useContainer hooks.",
5
+ "keywords": [
6
+ "dependency-injection",
7
+ "di",
8
+ "react",
9
+ "hooks",
10
+ "container",
11
+ "provider",
12
+ "useInject",
13
+ "typescript"
14
+ ],
15
+ "license": "MIT",
16
+ "author": "Pixielity",
17
+ "type": "module",
18
+ "sideEffects": false,
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js",
23
+ "require": "./dist/index.cjs"
24
+ }
25
+ },
26
+ "main": "dist/index.cjs",
27
+ "module": "dist/index.mjs",
28
+ "types": "dist/index.d.ts",
29
+ "files": [
30
+ "dist",
31
+ "README.md",
32
+ "LICENSE"
33
+ ],
34
+ "dependencies": {
35
+ "@abdokouta/ts-container": "1.0.0"
36
+ },
37
+ "peerDependencies": {
38
+ "react": "^18.0.0 || ^19.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^25.5.2",
42
+ "@types/react": "^19.2.14",
43
+ "react": "^19.2.4",
44
+ "tsup": "^8.5.1",
45
+ "@nesvel/typescript-config": "^1.0.4",
46
+ "typescript": "^6.0.2",
47
+ "vitest": "^4.1.2"
48
+ },
49
+ "engines": {
50
+ "node": ">=18"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "scripts": {
56
+ "build": "tsup",
57
+ "dev": "tsup --watch",
58
+ "typecheck": "tsc --noEmit",
59
+ "clean": "rm -rf dist",
60
+ "test": "vitest run --passWithNoTests"
61
+ }
62
+ }