@servicetitan/react-ioc 22.21.0 → 23.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/dist/await.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { FC, ReactNode } from 'react';
2
- export interface AwaitProps {
1
+ import { FC, PropsWithChildren, ReactNode } from 'react';
2
+ export declare type AwaitProps = PropsWithChildren<{
3
3
  promises: Promise<void>[];
4
4
  fallback?: NonNullable<ReactNode> | null;
5
- }
5
+ }>;
6
6
  export declare const Await: FC<AwaitProps>;
7
7
  //# sourceMappingURL=await.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"await.d.ts","sourceRoot":"","sources":["../src/await.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAsB,SAAS,EAAqB,MAAM,OAAO,CAAC;AAE7E,MAAM,WAAW,UAAU;IACvB,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;CAC5C;AAED,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAkBhC,CAAC"}
1
+ {"version":3,"file":"await.d.ts","sourceRoot":"","sources":["../src/await.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAQ,iBAAiB,EAAgB,SAAS,EAAqB,MAAM,OAAO,CAAC;AAGhG,oBAAY,UAAU,GAAG,iBAAiB,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1B,QAAQ,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;CAC5C,CAAC,CAAC;AAEH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAsBhC,CAAC"}
package/dist/await.js CHANGED
@@ -9,7 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  };
10
10
  import { jsx as _jsx } from "react/jsx-runtime";
11
11
  import { lazy, Suspense, useMemo } from 'react';
12
- export const Await = ({ promises, fallback = _jsx("h2", { children: "Loading..." }), children }) => {
12
+ import { defaultLoadingFallback } from './fallbacks';
13
+ export const Await = ({ promises, fallback = defaultLoadingFallback, children, }) => {
13
14
  const Lazy = useMemo(() => lazy(() => __awaiter(void 0, void 0, void 0, function* () {
14
15
  yield Promise.all(promises);
15
16
  return {
package/dist/await.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"await.js","sourceRoot":"","sources":["../src/await.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAM,IAAI,EAA2B,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAO7E,MAAM,CAAC,MAAM,KAAK,GAAmB,CAAC,EAAE,QAAQ,EAAE,QAAQ,GAAG,sCAAmB,EAAE,QAAQ,EAAE,EAAE,EAAE;IAC5F,MAAM,IAAI,GAAG,OAAO,CAChB,GAAG,EAAE,CACD,IAAI,CAAK,GAAS,EAAE;QAChB,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE5B,OAAO;YACH,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAwB;SACtD,CAAC;IACN,CAAC,CAAA,CAAC,EACN,CAAC,QAAQ,CAAC,CACb,CAAC;IAEF,OAAO,CACH,KAAC,QAAQ,kBAAC,QAAQ,EAAE,QAAQ,gBACxB,KAAC,IAAI,cAAE,QAAQ,GAAQ,IAChB,CACd,CAAC;AACN,CAAC,CAAC"}
1
+ {"version":3,"file":"await.js","sourceRoot":"","sources":["../src/await.tsx"],"names":[],"mappings":";;;;;;;;;;AAAA,OAAO,EAAM,IAAI,EAA8C,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChG,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAOrD,MAAM,CAAC,MAAM,KAAK,GAAmB,CAAC,EAClC,QAAQ,EACR,QAAQ,GAAG,sBAAsB,EACjC,QAAQ,GACX,EAAE,EAAE;IACD,MAAM,IAAI,GAAG,OAAO,CAChB,GAAG,EAAE,CACD,IAAI,CAA4B,GAAS,EAAE;QACvC,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE5B,OAAO;YACH,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAwB;SACtD,CAAC;IACN,CAAC,CAAA,CAAC,EACN,CAAC,QAAQ,CAAC,CACb,CAAC;IAEF,OAAO,CACH,KAAC,QAAQ,kBAAC,QAAQ,EAAE,QAAQ,gBACxB,KAAC,IAAI,cAAE,QAAQ,GAAQ,IAChB,CACd,CAAC;AACN,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const defaultLoadingFallback: import("react/jsx-runtime").JSX.Element;
2
+ export declare const defaultErrorFallback: import("react/jsx-runtime").JSX.Element;
3
+ //# sourceMappingURL=fallbacks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallbacks.d.ts","sourceRoot":"","sources":["../src/fallbacks.tsx"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,yCAAsB,CAAC;AAC1D,eAAO,MAAM,oBAAoB,yCAAuC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export const defaultLoadingFallback = _jsx("h2", { children: "Loading..." });
3
+ export const defaultErrorFallback = _jsx("h2", Object.assign({ className: "c-red-500" }, { children: "Error" }));
4
+ //# sourceMappingURL=fallbacks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fallbacks.js","sourceRoot":"","sources":["../src/fallbacks.tsx"],"names":[],"mappings":";AAAA,MAAM,CAAC,MAAM,sBAAsB,GAAG,sCAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,oBAAoB,GAAG,2BAAI,SAAS,EAAC,WAAW,2BAAW,CAAC"}
package/dist/provide.d.ts CHANGED
@@ -1,14 +1,15 @@
1
- import { ReactInstance, StatelessComponent, ComponentClass, ClassicComponentClass } from 'react';
2
- import { ProviderConfigEntry } from './provider';
1
+ import { ComponentType, ReactInstance } from 'react';
2
+ import { ProviderConfigEntrySingletons, ProviderConfigEntryInstances } from './provider';
3
3
  export interface WrappedComponent<P> {
4
- wrappedComponent: ReactComponent<P>;
4
+ wrappedComponent: ComponentType<P>;
5
5
  wrappedInstance: ReactInstance | undefined;
6
6
  }
7
- declare type ReactComponent<P = any> = StatelessComponent<P> | ComponentClass<P> | ClassicComponentClass<P>;
8
- declare type ProvideDecorator = (stores: {
9
- singletons?: ProviderConfigEntry<any>[];
10
- instances?: ProviderConfigEntry<any>[];
11
- }, fallback?: JSX.Element) => <T extends ReactComponent>(target: T) => T & WrappedComponent<T>;
7
+ export declare type ProvideDecorator = (stores: {
8
+ singletons?: ProviderConfigEntrySingletons<any>[];
9
+ instances?: ProviderConfigEntryInstances<any>[];
10
+ }, options?: {
11
+ loadingFallback?: JSX.Element;
12
+ errorFallback?: JSX.Element;
13
+ }) => <T extends ComponentType>(target: T) => T & WrappedComponent<T>;
12
14
  export declare const provide: ProvideDecorator;
13
- export {};
14
15
  //# sourceMappingURL=provide.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provide.d.ts","sourceRoot":"","sources":["../src/provide.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,OAAO,CAAC;AAEjG,OAAO,EAAY,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAC/B,gBAAgB,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACpC,eAAe,EAAE,aAAa,GAAG,SAAS,CAAC;CAC9C;AAED,aAAK,cAAc,CAAC,CAAC,GAAG,GAAG,IAAI,kBAAkB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,CAAC,CAAC;AAEpG,aAAK,gBAAgB,GAAG,CACpB,MAAM,EAAE;IACJ,UAAU,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;IACxC,SAAS,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;CAC1C,EACD,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,KACrB,CAAC,CAAC,SAAS,cAAc,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAEtE,eAAO,MAAM,OAAO,kBAKM,CAAC"}
1
+ {"version":3,"file":"provide.d.ts","sourceRoot":"","sources":["../src/provide.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,EAAY,6BAA6B,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAC;AAEnG,MAAM,WAAW,gBAAgB,CAAC,CAAC;IAC/B,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACnC,eAAe,EAAE,aAAa,GAAG,SAAS,CAAC;CAC9C;AAED,oBAAY,gBAAgB,GAAG,CAC3B,MAAM,EAAE;IACJ,UAAU,CAAC,EAAE,6BAA6B,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,SAAS,CAAC,EAAE,4BAA4B,CAAC,GAAG,CAAC,EAAE,CAAC;CACnD,EACD,OAAO,CAAC,EAAE;IACN,eAAe,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IAC9B,aAAa,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CAC/B,KACA,CAAC,CAAC,SAAS,aAAa,EAAE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;AAErE,eAAO,MAAM,OAAO,kBASM,CAAC"}
package/dist/provide.js CHANGED
@@ -1,4 +1,4 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Provider } from './provider';
3
- export const provide = ((stores, fallback) => (Component) => props => (_jsx(Provider, Object.assign({}, stores, { fallback: fallback }, { children: _jsx(Component, Object.assign({}, props)) }))));
3
+ export const provide = ((stores, options) => (Component) => props => (_jsx(Provider, Object.assign({}, stores, { loadingFallback: options === null || options === void 0 ? void 0 : options.loadingFallback, errorFallback: options === null || options === void 0 ? void 0 : options.errorFallback }, { children: _jsx(Component, Object.assign({}, props)) }))));
4
4
  //# sourceMappingURL=provide.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provide.js","sourceRoot":"","sources":["../src/provide.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAAuB,MAAM,YAAY,CAAC;AAiB3D,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,SAAyB,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CACjF,CACI,KAAC,QAAQ,oBAAK,MAAM,IAAE,QAAQ,EAAE,QAAQ,gBACpC,KAAC,SAAS,oBAAK,KAAK,EAAI,IACjB,CACd,CAAqB,CAAC"}
1
+ {"version":3,"file":"provide.js","sourceRoot":"","sources":["../src/provide.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,QAAQ,EAA+D,MAAM,YAAY,CAAC;AAkBnG,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,SAAwB,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAC/E,CACI,KAAC,QAAQ,oBACD,MAAM,IACV,eAAe,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,eAAe,EACzC,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa,gBAErC,KAAC,SAAS,oBAAK,KAAK,EAAI,IACjB,CACd,CAAqB,CAAC"}
@@ -1,20 +1,31 @@
1
- import { FC } from 'react';
1
+ import { FC, PropsWithChildren, ReactElement } from 'react';
2
2
  import { interfaces } from 'inversify';
3
3
  import { Token, SymbolToken } from './common';
4
- export declare type ProviderConfigEntry<T> = interfaces.Newable<T> | ClassProviderConfigEntry<T> | ValueProviderConfigEntry<T>;
5
- interface ClassProviderConfigEntry<T> {
4
+ export declare type ProviderConfigEntrySingletons<T> = ClassProviderConfigEntry<T> | ValueProviderConfigEntry<T>;
5
+ export declare type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;
6
+ export declare type ProviderConfigEntry<T> = ProviderConfigEntrySingletons<T> | ProviderConfigEntryInstances<T>;
7
+ declare type ClassProviderConfigEntry<T> = interfaces.Newable<T> | ClassProviderConfigEntryUseClass<T> | ClassProviderConfigEntryToken<T>;
8
+ declare type ClassProviderConfigEntryNoInherit<T> = interfaces.Newable<T> | Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
9
+ interface ClassProviderConfigEntryUseClass<T> {
6
10
  provide: Token<T>;
7
11
  useClass: interfaces.Newable<T>;
12
+ inherit?: true;
13
+ }
14
+ interface ClassProviderConfigEntryToken<T> {
15
+ provide: interfaces.Newable<T>;
16
+ inherit?: true;
8
17
  }
9
18
  interface ValueProviderConfigEntry<T> {
10
19
  provide: SymbolToken<T> | interfaces.Abstract<T>;
11
20
  useValue: T;
21
+ inherit?: true;
12
22
  }
13
- export interface ProviderProps {
14
- singletons?: ProviderConfigEntry<any>[];
15
- instances?: ProviderConfigEntry<any>[];
16
- fallback?: JSX.Element;
17
- }
23
+ export declare type ProviderProps = PropsWithChildren<{
24
+ singletons?: ProviderConfigEntrySingletons<any>[];
25
+ instances?: ProviderConfigEntryInstances<any>[];
26
+ loadingFallback?: ReactElement;
27
+ errorFallback?: ReactElement;
28
+ }>;
18
29
  export declare const Provider: FC<ProviderProps>;
19
30
  export {};
20
31
  //# sourceMappingURL=provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAyC,MAAM,OAAO,CAAC;AAElE,OAAO,EAAa,UAAU,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAoB,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAGhE,oBAAY,mBAAmB,CAAC,CAAC,IAC3B,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACrB,wBAAwB,CAAC,CAAC,CAAC,GAC3B,wBAAwB,CAAC,CAAC,CAAC,CAAC;AAElC,UAAU,wBAAwB,CAAC,CAAC;IAChC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CACnC;AAED,UAAU,wBAAwB,CAAC,CAAC;IAChC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjD,QAAQ,EAAE,CAAC,CAAC;CACf;AAoBD,MAAM,WAAW,aAAa;IAC1B,UAAU,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;IACxC,SAAS,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;CAC1B;AAED,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CA2FtC,CAAC"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,YAAY,EAAyC,MAAM,OAAO,CAAC;AAEnG,OAAO,EAAa,UAAU,EAAE,MAAM,WAAW,CAAC;AAGlD,OAAO,EAAoB,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAIhE,oBAAY,6BAA6B,CAAC,CAAC,IACrC,wBAAwB,CAAC,CAAC,CAAC,GAC3B,wBAAwB,CAAC,CAAC,CAAC,CAAC;AAClC,oBAAY,4BAA4B,CAAC,CAAC,IAAI,iCAAiC,CAAC,CAAC,CAAC,CAAC;AACnF,oBAAY,mBAAmB,CAAC,CAAC,IAC3B,6BAA6B,CAAC,CAAC,CAAC,GAChC,4BAA4B,CAAC,CAAC,CAAC,CAAC;AAEtC,aAAK,wBAAwB,CAAC,CAAC,IACzB,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACrB,gCAAgC,CAAC,CAAC,CAAC,GACnC,6BAA6B,CAAC,CAAC,CAAC,CAAC;AAEvC,aAAK,iCAAiC,CAAC,CAAC,IAClC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACrB,IAAI,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AAE3D,UAAU,gCAAgC,CAAC,CAAC;IACxC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,UAAU,6BAA6B,CAAC,CAAC;IACrC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,IAAI,CAAC;CAClB;AAED,UAAU,wBAAwB,CAAC,CAAC;IAChC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjD,QAAQ,EAAE,CAAC,CAAC;IACZ,OAAO,CAAC,EAAE,IAAI,CAAC;CAClB;AA8GD,oBAAY,aAAa,GAAG,iBAAiB,CAAC;IAC1C,UAAU,CAAC,EAAE,6BAA6B,CAAC,GAAG,CAAC,EAAE,CAAC;IAClD,SAAS,CAAC,EAAE,4BAA4B,CAAC,GAAG,CAAC,EAAE,CAAC;IAChD,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,aAAa,CAAC,EAAE,YAAY,CAAC;CAChC,CAAC,CAAC;AAEH,eAAO,MAAM,QAAQ,EAAE,EAAE,CAAC,aAAa,CAmFtC,CAAC"}
package/dist/provider.js CHANGED
@@ -3,65 +3,106 @@ import { useState, useContext, useLayoutEffect } from 'react';
3
3
  import { Container } from 'inversify';
4
4
  import { Await } from './await';
5
5
  import { ContainerContext } from './common';
6
+ import { defaultErrorFallback, defaultLoadingFallback } from './fallbacks';
6
7
  import { isStore } from './store';
7
- function isClassProviderConfigEntry(entry) {
8
- return (Object.prototype.hasOwnProperty.call(entry, 'provide') &&
9
- Object.prototype.hasOwnProperty.call(entry, 'useClass'));
8
+ function isClassProviderConfigEntryUseClass(entry) {
9
+ return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');
10
10
  }
11
11
  function isValueProviderConfigEntry(entry) {
12
- return (Object.prototype.hasOwnProperty.call(entry, 'provide') &&
13
- Object.prototype.hasOwnProperty.call(entry, 'useValue'));
12
+ return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');
14
13
  }
15
- export const Provider = ({ singletons, instances, fallback, children }) => {
14
+ function isClassProviderConfigEntryToken(entry) {
15
+ return (Object.hasOwn(entry, 'provide') &&
16
+ !Object.hasOwn(entry, 'useClass') &&
17
+ !Object.hasOwn(entry, 'useValue'));
18
+ }
19
+ function isProviderConfigEntryInheritable(entry) {
20
+ return (isClassProviderConfigEntryUseClass(entry) ||
21
+ isClassProviderConfigEntryToken(entry) ||
22
+ isValueProviderConfigEntry(entry));
23
+ }
24
+ function getProvideTokenWithClass(entry) {
25
+ if (isClassProviderConfigEntryUseClass(entry)) {
26
+ return [entry.provide, entry.useClass];
27
+ }
28
+ if (isClassProviderConfigEntryToken(entry)) {
29
+ return [entry.provide, entry.provide];
30
+ }
31
+ if (isValueProviderConfigEntry(entry)) {
32
+ return [undefined, undefined];
33
+ }
34
+ return [entry, entry];
35
+ }
36
+ function getStoreInstances(container, singletons = [], instances = []) {
37
+ return [...singletons, ...instances].reduce((out, entry) => {
38
+ const [provide, useClass] = getProvideTokenWithClass(entry);
39
+ if (provide && useClass && container.isCurrentBound(provide) && isStore(useClass)) {
40
+ out.push(container.get(provide));
41
+ }
42
+ return out;
43
+ }, []);
44
+ }
45
+ const bindEntry = (container, checkInherit) => (entry) => {
46
+ if (checkInherit &&
47
+ isProviderConfigEntryInheritable(entry) &&
48
+ entry.inherit &&
49
+ container.isBound(entry.provide)) {
50
+ return undefined;
51
+ }
52
+ if (isClassProviderConfigEntryUseClass(entry)) {
53
+ return container.bind(entry.provide).to(entry.useClass);
54
+ }
55
+ if (isClassProviderConfigEntryToken(entry)) {
56
+ return container.bind(entry.provide).to(entry.provide);
57
+ }
58
+ if (isValueProviderConfigEntry(entry)) {
59
+ // using toDynamicValue to return BindingInSyntax
60
+ return container.bind(entry.provide).toDynamicValue(() => entry.useValue);
61
+ }
62
+ return container.bind(entry).to(entry);
63
+ };
64
+ const unbindEntry = (container) => (entry) => {
65
+ if (isClassProviderConfigEntryUseClass(entry) ||
66
+ isValueProviderConfigEntry(entry) ||
67
+ isClassProviderConfigEntryToken(entry)) {
68
+ return container.unbind(entry.provide);
69
+ }
70
+ return container.unbind(entry);
71
+ };
72
+ export const Provider = ({ singletons, instances, loadingFallback = defaultLoadingFallback, errorFallback = defaultErrorFallback, children, }) => {
16
73
  const parentContainer = useContext(ContainerContext);
17
74
  const [container, setContainer] = useState();
18
- const [promises, setPromises] = useState();
75
+ const [promises, setPromises] = useState([]);
76
+ const [error, setError] = useState(false);
19
77
  useLayoutEffect(() => {
20
78
  const container = new Container();
21
79
  container.parent = parentContainer;
22
- const bind = (entry) => {
23
- if (isClassProviderConfigEntry(entry)) {
24
- return container.bind(entry.provide).to(entry.useClass);
25
- }
26
- if (isValueProviderConfigEntry(entry)) {
27
- // using toDynamicValue to return BindingInSyntax
28
- return container.bind(entry.provide).toDynamicValue(() => entry.useValue);
29
- }
30
- return container.bind(entry).to(entry);
31
- };
32
- singletons === null || singletons === void 0 ? void 0 : singletons.map(bind).forEach(binding => {
33
- binding.inSingletonScope();
80
+ singletons === null || singletons === void 0 ? void 0 : singletons.map(bindEntry(container, true)).forEach(binding => {
81
+ binding === null || binding === void 0 ? void 0 : binding.inSingletonScope();
34
82
  });
35
- instances === null || instances === void 0 ? void 0 : instances.forEach(bind);
36
- const storeInstances = [...(singletons !== null && singletons !== void 0 ? singletons : []), ...(instances !== null && instances !== void 0 ? instances : [])]
37
- .map(entry => {
38
- if (isValueProviderConfigEntry(entry)) {
39
- return undefined;
40
- }
41
- const { provide, useClass } = isClassProviderConfigEntry(entry)
42
- ? entry
43
- : { provide: entry, useClass: entry };
44
- if (isStore(useClass)) {
45
- return container.get(provide);
46
- }
47
- return undefined;
48
- })
49
- .filter(Boolean);
83
+ instances === null || instances === void 0 ? void 0 : instances.forEach(bindEntry(container, false));
84
+ const storeInstances = getStoreInstances(container, singletons, instances);
50
85
  const promises = [];
51
86
  for (const instance of storeInstances) {
52
87
  if (instance.initialize) {
53
- promises.push(instance.initialize());
88
+ let promise;
89
+ try {
90
+ promise = instance.initialize();
91
+ }
92
+ catch (_a) {
93
+ setError(true);
94
+ }
95
+ if (promise && typeof promise.catch === 'function') {
96
+ promises.push(promise.catch(() => {
97
+ setError(true);
98
+ }));
99
+ }
54
100
  }
55
101
  }
56
102
  setContainer(container);
57
103
  setPromises(promises);
58
104
  return () => {
59
- const unbind = (entry) => {
60
- if (isClassProviderConfigEntry(entry) || isValueProviderConfigEntry(entry)) {
61
- return container.unbind(entry.provide);
62
- }
63
- return container.unbind(entry);
64
- };
105
+ const unbind = unbindEntry(container);
65
106
  singletons === null || singletons === void 0 ? void 0 : singletons.forEach(unbind);
66
107
  instances === null || instances === void 0 ? void 0 : instances.forEach(unbind);
67
108
  for (const instance of storeInstances) {
@@ -74,6 +115,15 @@ export const Provider = ({ singletons, instances, fallback, children }) => {
74
115
  if (!container) {
75
116
  return null;
76
117
  }
77
- return (_jsx(ContainerContext.Provider, Object.assign({ value: container }, { children: (promises === null || promises === void 0 ? void 0 : promises.length) ? (_jsx(Await, Object.assign({ promises: promises, fallback: fallback }, { children: children }))) : (children) })));
118
+ const getContent = () => {
119
+ if (error) {
120
+ return errorFallback;
121
+ }
122
+ if (promises.length) {
123
+ return (_jsx(Await, Object.assign({ promises: promises, fallback: loadingFallback }, { children: children })));
124
+ }
125
+ return children;
126
+ };
127
+ return _jsx(ContainerContext.Provider, Object.assign({ value: container }, { children: getContent() }));
78
128
  };
79
129
  //# sourceMappingURL=provider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAuC,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAEnG,OAAO,EAAE,SAAS,EAAc,MAAM,WAAW,CAAC;AAElD,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAsB,MAAM,UAAU,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAS,MAAM,SAAS,CAAC;AAoCzC,SAAS,kCAAkC,CACvC,KAA6B;IAE7B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,0BAA0B,CAC/B,KAA6B;IAE7B,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,+BAA+B,CACpC,KAA6B;IAE7B,OAAO,CACH,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC;QAC/B,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC;QACjC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,CACpC,CAAC;AACN,CAAC;AAED,SAAS,gCAAgC,CACrC,KAA6B;IAK7B,OAAO,CACH,kCAAkC,CAAC,KAAK,CAAC;QACzC,+BAA+B,CAAC,KAAK,CAAC;QACtC,0BAA0B,CAAC,KAAK,CAAC,CACpC,CAAC;AACN,CAAC;AAED,SAAS,wBAAwB,CAC7B,KAA6B;IAE7B,IAAI,kCAAkC,CAAC,KAAK,CAAC,EAAE;QAC3C,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;KAC1C;IAED,IAAI,+BAA+B,CAAC,KAAK,CAAC,EAAE;QACxC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;KACzC;IAED,IAAI,0BAA0B,CAAC,KAAK,CAAC,EAAE;QACnC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;KACjC;IAED,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,iBAAiB,CACtB,SAAoB,EACpB,aAAmD,EAAE,EACrD,YAAiD,EAAE;IAEnD,OAAO,CAAC,GAAG,UAAU,EAAE,GAAG,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACvD,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,wBAAwB,CAAC,KAAK,CAAC,CAAC;QAE5D,IAAI,OAAO,IAAI,QAAQ,IAAI,SAAS,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/E,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;SACpC;QAED,OAAO,GAAG,CAAC;IACf,CAAC,EAAE,EAAa,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,SAAS,GACX,CAAC,SAAoB,EAAE,YAAqB,EAAE,EAAE,CAAC,CAAC,KAA+B,EAAE,EAAE;IACjF,IACI,YAAY;QACZ,gCAAgC,CAAC,KAAK,CAAC;QACvC,KAAK,CAAC,OAAO;QACb,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAClC;QACE,OAAO,SAAS,CAAC;KACpB;IAED,IAAI,kCAAkC,CAAC,KAAK,CAAC,EAAE;QAC3C,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;KAC3D;IAED,IAAI,+BAA+B,CAAC,KAAK,CAAC,EAAE;QACxC,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;KAC1D;IAED,IAAI,0BAA0B,CAAC,KAAK,CAAC,EAAE;QACnC,iDAAiD;QACjD,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;KAC7E;IAED,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEN,MAAM,WAAW,GAAG,CAAC,SAAoB,EAAE,EAAE,CAAC,CAAC,KAA+B,EAAE,EAAE;IAC9E,IACI,kCAAkC,CAAC,KAAK,CAAC;QACzC,0BAA0B,CAAC,KAAK,CAAC;QACjC,+BAA+B,CAAC,KAAK,CAAC,EACxC;QACE,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;KAC1C;IAED,OAAO,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC,CAAC;AASF,MAAM,CAAC,MAAM,QAAQ,GAAsB,CAAC,EACxC,UAAU,EACV,SAAS,EACT,eAAe,GAAG,sBAAsB,EACxC,aAAa,GAAG,oBAAoB,EACpC,QAAQ,GACX,EAAE,EAAE;IACD,MAAM,eAAe,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAErD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,EAAa,CAAC;IACxD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAkB,EAAE,CAAC,CAAC;IAC9D,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE1C,eAAe,CAAC,GAAG,EAAE;QACjB,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC;QAClC,SAAS,CAAC,MAAM,GAAG,eAAe,CAAC;QAEnC,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,GAAG,CAAC,SAAS,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC1D,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,gBAAgB,EAAE,CAAC;QAChC,CAAC,CAAC,CAAC;QACH,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;QAEhD,MAAM,cAAc,GAAG,iBAAiB,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAE3E,MAAM,QAAQ,GAAoB,EAAE,CAAC;QACrC,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE;YACnC,IAAI,QAAQ,CAAC,UAAU,EAAE;gBACrB,IAAI,OAAO,CAAC;gBAEZ,IAAI;oBACA,OAAO,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAC;iBACnC;gBAAC,WAAM;oBACJ,QAAQ,CAAC,IAAI,CAAC,CAAC;iBAClB;gBAED,IAAI,OAAO,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,UAAU,EAAE;oBAChD,QAAQ,CAAC,IAAI,CACT,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE;wBACf,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACnB,CAAC,CAAC,CACL,CAAC;iBACL;aACJ;SACJ;QAED,YAAY,CAAC,SAAS,CAAC,CAAC;QACxB,WAAW,CAAC,QAAQ,CAAC,CAAC;QAEtB,OAAO,GAAG,EAAE;YACR,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YAEtC,UAAU,aAAV,UAAU,uBAAV,UAAU,CAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5B,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAE3B,KAAK,MAAM,QAAQ,IAAI,cAAc,EAAE;gBACnC,IAAI,QAAQ,CAAC,OAAO,EAAE;oBAClB,QAAQ,CAAC,OAAO,EAAE,CAAC;iBACtB;aACJ;QACL,CAAC,CAAC;IACN,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kDAAkD;IAE1D,IAAI,CAAC,SAAS,EAAE;QACZ,OAAO,IAAI,CAAC;KACf;IAED,MAAM,UAAU,GAAG,GAAG,EAAE;QACpB,IAAI,KAAK,EAAE;YACP,OAAO,aAAa,CAAC;SACxB;QAED,IAAI,QAAQ,CAAC,MAAM,EAAE;YACjB,OAAO,CACH,KAAC,KAAK,kBAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,eAAe,gBAC/C,QAAQ,IACL,CACX,CAAC;SACL;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC,CAAC;IAEF,OAAO,KAAC,gBAAgB,CAAC,QAAQ,kBAAC,KAAK,EAAE,SAAS,gBAAG,UAAU,EAAE,IAA6B,CAAC;AACnG,CAAC,CAAC"}
package/dist/store.d.ts CHANGED
@@ -6,9 +6,7 @@ interface Identifier<T> extends interfaces.Newable<T> {
6
6
  export declare function isStore<T>(identifier: Identifier<T>): boolean | undefined;
7
7
  export declare abstract class Store {
8
8
  static [symbol]: boolean;
9
- }
10
- export interface Store {
11
- initialize?(): Promise<void>;
9
+ initialize?(): Promise<void> | void;
12
10
  dispose?(): void;
13
11
  }
14
12
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAC;AAEnD,QAAA,MAAM,MAAM,eAAmC,CAAC;AAEhD,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,uBAEnD;AAED,8BACsB,KAAK;IACvB,MAAM,CAAC,CAAC,MAAM,CAAC,UAAQ;CAC1B;AAED,MAAM,WAAW,KAAK;IAClB,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,IAAI,CAAC;CACpB"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,UAAU,EAAE,MAAM,WAAW,CAAC;AAEnD,QAAA,MAAM,MAAM,eAAmC,CAAC;AAEhD,UAAU,UAAU,CAAC,CAAC,CAAE,SAAQ,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,uBAEnD;AAED,8BACsB,KAAK;IACvB,MAAM,CAAC,CAAC,MAAM,CAAC,UAAQ;IAEvB,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IACnC,OAAO,CAAC,IAAI,IAAI;CACnB"}
package/dist/store.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,UAAU,EAAc,MAAM,WAAW,CAAC;AAEnD,MAAM,MAAM,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAMhD,MAAM,UAAU,OAAO,CAAI,UAAyB;IAChD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC;AAGD,IAAsB,KAAK,GAA3B,MAAsB,KAAK;CAE1B,CAAA;KADW,MAAM;AAAP;;;;WAAW,IAAI;GAAC;AADL,KAAK;IAD1B,UAAU,EAAE;GACS,KAAK,CAE1B;SAFqB,KAAK"}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":";;;;;;;AAAA,OAAO,EAAE,UAAU,EAAc,MAAM,WAAW,CAAC;AAEnD,MAAM,MAAM,GAAG,MAAM,CAAC,wBAAwB,CAAC,CAAC;AAMhD,MAAM,UAAU,OAAO,CAAI,UAAyB;IAChD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC;AAGD,IAAsB,KAAK,GAA3B,MAAsB,KAAK;CAK1B,CAAA;KAJW,MAAM;AAAP;;;;WAAW,IAAI;GAAC;AADL,KAAK;IAD1B,UAAU,EAAE;GACS,KAAK,CAK1B;SALqB,KAAK"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/react-ioc",
3
- "version": "22.21.0",
3
+ "version": "23.1.0",
4
4
  "description": "",
5
5
  "homepage": "https://docs.st.dev/docs/frontend/react-ioc",
6
6
  "repository": {
@@ -19,11 +19,15 @@
19
19
  "reflect-metadata": "~0.1.13"
20
20
  },
21
21
  "devDependencies": {
22
- "@types/react": "~17.0.38",
23
- "react": "~17.0.2"
22
+ "@servicetitan/startup-jest": "^1.1.0",
23
+ "@testing-library/react": "^14.2.1",
24
+ "@types/react": "~18.2.55",
25
+ "@types/react-test-renderer": "~18.0.7",
26
+ "react": "~18.2.0",
27
+ "react-test-renderer": "~18.2.0"
24
28
  },
25
29
  "peerDependencies": {
26
- "react": "~17.0.2"
30
+ "react": ">=17.0.2"
27
31
  },
28
32
  "publishConfig": {
29
33
  "access": "public"
@@ -31,5 +35,5 @@
31
35
  "cli": {
32
36
  "webpack": false
33
37
  },
34
- "gitHead": "729b7ca4eb38c323ac538a73573cadd54a4ff839"
38
+ "gitHead": "7267270e54cdb3a2926f61feb4939d057e82adb3"
35
39
  }
@@ -0,0 +1,21 @@
1
+ import TestRenderer from 'react-test-renderer';
2
+ import { Await } from '../await';
3
+ import { waitFor } from '@testing-library/react';
4
+
5
+ const TestContent = () => <div role="content">hello</div>;
6
+
7
+ describe(`[react-ioc] ${Await.displayName}`, () => {
8
+ test('should render content when no promises are passed', async () => {
9
+ const { root } = TestRenderer.create(
10
+ <Await promises={[]}>
11
+ <TestContent />
12
+ </Await>
13
+ );
14
+
15
+ await TestRenderer.act(async () => {
16
+ await waitFor(() => {
17
+ expect(root.findByType(TestContent)).toBeTruthy();
18
+ });
19
+ });
20
+ });
21
+ });
@@ -0,0 +1,343 @@
1
+ import { PropsWithChildren, ReactElement, ReactNode, useEffect } from 'react';
2
+ import { provide, inject, injectable, useDependencies, Store, symbolToken, Provider } from '..';
3
+ import TestRenderer from 'react-test-renderer';
4
+ import { waitFor } from '@testing-library/react';
5
+
6
+ @injectable()
7
+ class StatStore {
8
+ readonly id = 'stat';
9
+ counters: Record<string, number> = {};
10
+ queueCreate: string[] = [];
11
+ queueRender: string[] = [];
12
+
13
+ testInitialize: (id: string) => void = jest.fn();
14
+ testRender = (id: string) => {
15
+ this.queueRender.push(id);
16
+ };
17
+
18
+ register(name: string) {
19
+ if (!this.counters[name]) {
20
+ this.counters[name] = 0;
21
+ }
22
+
23
+ this.counters[name]++;
24
+
25
+ const id = `${name}-${this.counters[name]}`;
26
+ this.queueCreate.push(id);
27
+
28
+ return id;
29
+ }
30
+ }
31
+
32
+ @injectable()
33
+ class StoreSimple {
34
+ readonly id;
35
+
36
+ constructor(@inject(StatStore) stat: StatStore) {
37
+ this.id = stat.register('StoreSimple');
38
+ }
39
+ }
40
+
41
+ @injectable()
42
+ class StoreWithInitialize extends Store {
43
+ readonly id;
44
+
45
+ constructor(@inject(StatStore) private stat: StatStore) {
46
+ super();
47
+ this.id = stat.register('StoreWithInitialize');
48
+ }
49
+
50
+ initialize() {
51
+ this.stat.testInitialize(this.id);
52
+ }
53
+ }
54
+
55
+ type TestStore = typeof StoreSimple | typeof StoreWithInitialize | ReturnType<typeof symbolToken>;
56
+
57
+ const getTestComponent = (inst: TestStore) => {
58
+ return ({ children }: PropsWithChildren<{}>) => {
59
+ const [{ id }, { testRender }] = useDependencies<[any, StatStore]>(inst, StatStore);
60
+ useEffect(() => {
61
+ testRender(id);
62
+ }, [testRender, id]);
63
+ return <div>{children}</div>;
64
+ };
65
+ };
66
+
67
+ type ProviderStoreProps = Parameters<typeof provide>[0];
68
+
69
+ function TestProvider(props: PropsWithChildren<ProviderStoreProps & { store: TestStore }>) {
70
+ const { singletons, instances, children, store = StoreSimple } = props;
71
+ const Component = provide({ singletons, instances })(getTestComponent(store));
72
+ return <Component>{children}</Component>;
73
+ }
74
+
75
+ describe(`[react-ioc] ${provide.name}`, () => {
76
+ let stat!: StatStore;
77
+
78
+ const Stat = provide({ singletons: [StatStore] })(({ children }: PropsWithChildren<{}>) => {
79
+ const [statStore] = useDependencies(StatStore);
80
+ stat = statStore;
81
+ return <div>{children}</div>;
82
+ });
83
+
84
+ const subject = (children: ReactNode) => TestRenderer.create(<Stat>{children}</Stat>);
85
+
86
+ const expectQueueRenderToBe = (queueRender: string[]) =>
87
+ TestRenderer.act(async () => {
88
+ await waitFor(() => {
89
+ expect(stat.queueRender).toEqual(queueRender);
90
+ });
91
+ });
92
+
93
+ describe('check nested stores', () => {
94
+ describe('singletons', () => {
95
+ test('should reuse singletons for each container.get', async () => {
96
+ subject(
97
+ <TestProvider store={StoreSimple} singletons={[StoreSimple]}>
98
+ <TestProvider store={StoreSimple} />
99
+ </TestProvider>
100
+ );
101
+
102
+ expect(stat.queueCreate).toEqual(['StoreSimple-1']);
103
+
104
+ await expectQueueRenderToBe(['StoreSimple-1', 'StoreSimple-1']);
105
+ });
106
+
107
+ test('should create separate singletons for nested tokens', async () => {
108
+ subject(
109
+ <TestProvider store={StoreSimple} singletons={[StoreSimple]}>
110
+ <TestProvider store={StoreSimple} singletons={[StoreSimple]} />
111
+ </TestProvider>
112
+ );
113
+
114
+ expect(stat.queueCreate).toEqual(['StoreSimple-1', 'StoreSimple-2']);
115
+
116
+ await expectQueueRenderToBe(['StoreSimple-1', 'StoreSimple-2']);
117
+ });
118
+
119
+ test('should reuse singleton when using provide inheritance and instance exists', async () => {
120
+ subject(
121
+ <TestProvider store={StoreSimple} singletons={[StoreSimple]}>
122
+ <TestProvider
123
+ store={StoreSimple}
124
+ singletons={[{ provide: StoreSimple, inherit: true }]}
125
+ />
126
+ </TestProvider>
127
+ );
128
+
129
+ expect(stat.queueCreate).toEqual(['StoreSimple-1']);
130
+
131
+ await expectQueueRenderToBe(['StoreSimple-1', 'StoreSimple-1']);
132
+ });
133
+
134
+ test('should create singletons when using provide inheritance and instance not exists', () => {
135
+ subject(
136
+ <TestProvider
137
+ store={StoreSimple}
138
+ singletons={[{ provide: StoreSimple, inherit: true }]}
139
+ >
140
+ <TestProvider store={StoreSimple} singletons={[StoreSimple]} />
141
+ </TestProvider>
142
+ );
143
+
144
+ expect(stat.queueCreate).toEqual(['StoreSimple-1', 'StoreSimple-2']);
145
+ });
146
+ });
147
+
148
+ describe('instances', () => {
149
+ test('should create separate instances for each container.get', async () => {
150
+ subject(
151
+ <TestProvider store={StoreSimple} instances={[StoreSimple]}>
152
+ <TestProvider store={StoreSimple} />
153
+ </TestProvider>
154
+ );
155
+
156
+ expect(stat.queueCreate).toEqual(['StoreSimple-1', 'StoreSimple-2']);
157
+
158
+ await expectQueueRenderToBe(['StoreSimple-1', 'StoreSimple-2']);
159
+ });
160
+
161
+ test('should create separate instances for nested tokens', async () => {
162
+ subject(
163
+ <TestProvider store={StoreSimple} instances={[StoreSimple]}>
164
+ <TestProvider store={StoreSimple} instances={[StoreSimple]} />
165
+ </TestProvider>
166
+ );
167
+
168
+ expect(stat.queueCreate).toEqual(['StoreSimple-1', 'StoreSimple-2']);
169
+
170
+ await expectQueueRenderToBe(['StoreSimple-1', 'StoreSimple-2']);
171
+ });
172
+ });
173
+
174
+ describe('useValue', () => {
175
+ const valueToken = symbolToken('valueToken');
176
+
177
+ test('create new values', async () => {
178
+ subject(
179
+ <TestProvider
180
+ store={valueToken}
181
+ singletons={[{ provide: valueToken, useValue: { id: 'value1' } }]}
182
+ >
183
+ <TestProvider
184
+ store={valueToken}
185
+ singletons={[{ provide: valueToken, useValue: { id: 'value2' } }]}
186
+ />
187
+ </TestProvider>
188
+ );
189
+
190
+ await expectQueueRenderToBe(['value1', 'value2']);
191
+ });
192
+
193
+ test('reuse nested values', async () => {
194
+ subject(
195
+ <TestProvider
196
+ store={valueToken}
197
+ singletons={[{ provide: valueToken, useValue: { id: 'value1' } }]}
198
+ >
199
+ <TestProvider
200
+ store={valueToken}
201
+ singletons={[
202
+ { provide: valueToken, useValue: { id: 'value2' }, inherit: true },
203
+ ]}
204
+ />
205
+ </TestProvider>
206
+ );
207
+
208
+ await expectQueueRenderToBe(['value1', 'value1']);
209
+ });
210
+
211
+ test('no reuse nested values for instances', async () => {
212
+ subject(
213
+ <TestProvider
214
+ store={valueToken}
215
+ singletons={[{ provide: valueToken, useValue: { id: 'value1' } }]}
216
+ >
217
+ <TestProvider
218
+ store={valueToken}
219
+ instances={[
220
+ {
221
+ provide: valueToken,
222
+ useValue: { id: 'value2' },
223
+ inherit: true,
224
+ } as any,
225
+ ]}
226
+ />
227
+ </TestProvider>
228
+ );
229
+
230
+ await expectQueueRenderToBe(['value1', 'value2']);
231
+ });
232
+ });
233
+ });
234
+
235
+ describe('check store initialization', () => {
236
+ test('should wait for store initialization', async () => {
237
+ subject(
238
+ <TestProvider store={StoreWithInitialize} singletons={[StoreWithInitialize]} />
239
+ );
240
+
241
+ expect(stat.queueRender).toEqual([]);
242
+
243
+ await TestRenderer.act(async () => {
244
+ await waitFor(() => {
245
+ expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
246
+ });
247
+ });
248
+
249
+ await expectQueueRenderToBe(['StoreWithInitialize-1']);
250
+ });
251
+ test('should wait for for nested initialization', async () => {
252
+ subject(
253
+ <TestProvider store={StoreWithInitialize} singletons={[StoreWithInitialize]}>
254
+ <TestProvider store={StoreWithInitialize} singletons={[StoreWithInitialize]} />
255
+ </TestProvider>
256
+ );
257
+
258
+ await TestRenderer.act(async () => {
259
+ await waitFor(() => {
260
+ expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
261
+ });
262
+
263
+ await waitFor(() => {
264
+ expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-2');
265
+ });
266
+ });
267
+
268
+ expect(stat.queueCreate).toEqual(['StoreWithInitialize-1', 'StoreWithInitialize-2']);
269
+
270
+ await expectQueueRenderToBe(['StoreWithInitialize-1', 'StoreWithInitialize-2']);
271
+ });
272
+ test('should initialize only once when store is reused', async () => {
273
+ subject(
274
+ <TestProvider store={StoreWithInitialize} singletons={[StoreWithInitialize]}>
275
+ <TestProvider
276
+ store={StoreWithInitialize}
277
+ singletons={[{ provide: StoreWithInitialize, inherit: true }]}
278
+ />
279
+ </TestProvider>
280
+ );
281
+
282
+ await TestRenderer.act(async () => {
283
+ await waitFor(() => {
284
+ expect(stat.testInitialize).toHaveBeenCalledWith('StoreWithInitialize-1');
285
+ });
286
+ });
287
+
288
+ expect(stat.queueCreate).toEqual(['StoreWithInitialize-1']);
289
+ await expectQueueRenderToBe(['StoreWithInitialize-1', 'StoreWithInitialize-1']);
290
+ expect(stat.testInitialize).toHaveBeenCalledTimes(1);
291
+ });
292
+
293
+ describe('error initialization', () => {
294
+ @injectable()
295
+ class StoreWithErrorInitialize extends Store {
296
+ initialize() {
297
+ throw new Error('error');
298
+ }
299
+ }
300
+ @injectable()
301
+ class StoreWithAsyncErrorInitialize extends Store {
302
+ async initialize() {
303
+ await new Promise<void>(resolve => resolve());
304
+ throw new Error('error');
305
+ }
306
+ }
307
+
308
+ const subject = async (
309
+ children: ReactElement
310
+ ): Promise<ReturnType<typeof TestRenderer.create>> => {
311
+ let result: ReturnType<typeof TestRenderer.create> | undefined = undefined;
312
+
313
+ await TestRenderer.act(async () => {
314
+ // we need this function to be async because of TestRenderer warnings
315
+ await new Promise<void>(resolve => resolve());
316
+ result = TestRenderer.create(children);
317
+ });
318
+
319
+ if (!result) {
320
+ throw new Error();
321
+ }
322
+
323
+ return result;
324
+ };
325
+
326
+ test('async error initialization should show error', async () => {
327
+ const { root } = await subject(
328
+ <Provider singletons={[StoreWithAsyncErrorInitialize]}>hello</Provider>
329
+ );
330
+
331
+ expect(root.findByType('h2')).toBeTruthy();
332
+ });
333
+
334
+ test('sync error initialization should show error', async () => {
335
+ const { root } = await subject(
336
+ <Provider singletons={[StoreWithErrorInitialize]}>hello</Provider>
337
+ );
338
+
339
+ expect(root.findByType('h2')).toBeTruthy();
340
+ });
341
+ });
342
+ });
343
+ });
@@ -1,4 +1,4 @@
1
- import { Component, createContext, useRef, FC } from 'react';
1
+ import { Component, createContext, useRef, FC, PropsWithChildren } from 'react';
2
2
  import {
3
3
  provide,
4
4
  injectDependency,
@@ -33,9 +33,9 @@ abstract class SampleConfig {
33
33
  title!: string;
34
34
  }
35
35
 
36
- const SampleConsumer: FC<{
37
- setContainer(container: Container): void;
38
- }> = props => (
36
+ const SampleConsumer: FC<
37
+ PropsWithChildren<{ setContainer(container: Container): void }>
38
+ > = props => (
39
39
  <ContainerContext.Consumer>
40
40
  {container => {
41
41
  props.setContainer(container);
package/src/await.tsx CHANGED
@@ -1,14 +1,19 @@
1
- import { FC, lazy, ReactElement, ReactNode, Suspense, useMemo } from 'react';
1
+ import { FC, lazy, PropsWithChildren, ReactElement, ReactNode, Suspense, useMemo } from 'react';
2
+ import { defaultLoadingFallback } from './fallbacks';
2
3
 
3
- export interface AwaitProps {
4
+ export type AwaitProps = PropsWithChildren<{
4
5
  promises: Promise<void>[];
5
6
  fallback?: NonNullable<ReactNode> | null;
6
- }
7
+ }>;
7
8
 
8
- export const Await: FC<AwaitProps> = ({ promises, fallback = <h2>Loading...</h2>, children }) => {
9
+ export const Await: FC<AwaitProps> = ({
10
+ promises,
11
+ fallback = defaultLoadingFallback,
12
+ children,
13
+ }) => {
9
14
  const Lazy = useMemo(
10
15
  () =>
11
- lazy<FC>(async () => {
16
+ lazy<FC<PropsWithChildren<{}>>>(async () => {
12
17
  await Promise.all(promises);
13
18
 
14
19
  return {
@@ -0,0 +1,2 @@
1
+ export const defaultLoadingFallback = <h2>Loading...</h2>;
2
+ export const defaultErrorFallback = <h2 className="c-red-500">Error</h2>;
package/src/provide.tsx CHANGED
@@ -1,25 +1,30 @@
1
- import { ReactInstance, StatelessComponent, ComponentClass, ClassicComponentClass } from 'react';
1
+ import { ComponentType, ReactInstance } from 'react';
2
2
 
3
- import { Provider, ProviderConfigEntry } from './provider';
3
+ import { Provider, ProviderConfigEntrySingletons, ProviderConfigEntryInstances } from './provider';
4
4
 
5
5
  export interface WrappedComponent<P> {
6
- wrappedComponent: ReactComponent<P>;
6
+ wrappedComponent: ComponentType<P>;
7
7
  wrappedInstance: ReactInstance | undefined;
8
8
  }
9
9
 
10
- type ReactComponent<P = any> = StatelessComponent<P> | ComponentClass<P> | ClassicComponentClass<P>;
11
-
12
- type ProvideDecorator = (
10
+ export type ProvideDecorator = (
13
11
  stores: {
14
- singletons?: ProviderConfigEntry<any>[];
15
- instances?: ProviderConfigEntry<any>[];
12
+ singletons?: ProviderConfigEntrySingletons<any>[];
13
+ instances?: ProviderConfigEntryInstances<any>[];
16
14
  },
17
- fallback?: JSX.Element
18
- ) => <T extends ReactComponent>(target: T) => T & WrappedComponent<T>;
15
+ options?: {
16
+ loadingFallback?: JSX.Element;
17
+ errorFallback?: JSX.Element;
18
+ }
19
+ ) => <T extends ComponentType>(target: T) => T & WrappedComponent<T>;
19
20
 
20
- export const provide = ((stores, fallback) => (Component: ReactComponent) => props =>
21
+ export const provide = ((stores, options) => (Component: ComponentType) => props =>
21
22
  (
22
- <Provider {...stores} fallback={fallback}>
23
+ <Provider
24
+ {...stores}
25
+ loadingFallback={options?.loadingFallback}
26
+ errorFallback={options?.errorFallback}
27
+ >
23
28
  <Component {...props} />
24
29
  </Provider>
25
30
  )) as ProvideDecorator;
package/src/provider.tsx CHANGED
@@ -1,100 +1,203 @@
1
- import { FC, useState, useContext, useLayoutEffect } from 'react';
1
+ import { FC, PropsWithChildren, ReactElement, useState, useContext, useLayoutEffect } from 'react';
2
2
 
3
3
  import { Container, interfaces } from 'inversify';
4
4
 
5
5
  import { Await } from './await';
6
6
  import { ContainerContext, Token, SymbolToken } from './common';
7
- import { isStore } from './store';
7
+ import { defaultErrorFallback, defaultLoadingFallback } from './fallbacks';
8
+ import { isStore, Store } from './store';
8
9
 
9
- export type ProviderConfigEntry<T> =
10
- | interfaces.Newable<T>
10
+ export type ProviderConfigEntrySingletons<T> =
11
11
  | ClassProviderConfigEntry<T>
12
12
  | ValueProviderConfigEntry<T>;
13
+ export type ProviderConfigEntryInstances<T> = ClassProviderConfigEntryNoInherit<T>;
14
+ export type ProviderConfigEntry<T> =
15
+ | ProviderConfigEntrySingletons<T>
16
+ | ProviderConfigEntryInstances<T>;
17
+
18
+ type ClassProviderConfigEntry<T> =
19
+ | interfaces.Newable<T>
20
+ | ClassProviderConfigEntryUseClass<T>
21
+ | ClassProviderConfigEntryToken<T>;
13
22
 
14
- interface ClassProviderConfigEntry<T> {
23
+ type ClassProviderConfigEntryNoInherit<T> =
24
+ | interfaces.Newable<T>
25
+ | Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'>;
26
+
27
+ interface ClassProviderConfigEntryUseClass<T> {
15
28
  provide: Token<T>;
16
29
  useClass: interfaces.Newable<T>;
30
+ inherit?: true;
31
+ }
32
+
33
+ interface ClassProviderConfigEntryToken<T> {
34
+ provide: interfaces.Newable<T>;
35
+ inherit?: true;
17
36
  }
18
37
 
19
38
  interface ValueProviderConfigEntry<T> {
20
39
  provide: SymbolToken<T> | interfaces.Abstract<T>;
21
40
  useValue: T;
41
+ inherit?: true;
22
42
  }
23
43
 
24
- function isClassProviderConfigEntry<T>(
44
+ function isClassProviderConfigEntryUseClass<T>(
25
45
  entry: ProviderConfigEntry<T>
26
- ): entry is ClassProviderConfigEntry<T> {
46
+ ): entry is Omit<ClassProviderConfigEntryUseClass<T>, 'inherit'> {
47
+ return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useClass');
48
+ }
49
+
50
+ function isValueProviderConfigEntry<T>(
51
+ entry: ProviderConfigEntry<T>
52
+ ): entry is Omit<ValueProviderConfigEntry<T>, 'inherit'> {
53
+ return Object.hasOwn(entry, 'provide') && Object.hasOwn(entry, 'useValue');
54
+ }
55
+
56
+ function isClassProviderConfigEntryToken<T>(
57
+ entry: ProviderConfigEntry<T>
58
+ ): entry is Omit<ClassProviderConfigEntryToken<T>, 'inherit'> {
27
59
  return (
28
- Object.prototype.hasOwnProperty.call(entry, 'provide') &&
29
- Object.prototype.hasOwnProperty.call(entry, 'useClass')
60
+ Object.hasOwn(entry, 'provide') &&
61
+ !Object.hasOwn(entry, 'useClass') &&
62
+ !Object.hasOwn(entry, 'useValue')
30
63
  );
31
64
  }
32
65
 
33
- function isValueProviderConfigEntry<T>(
66
+ function isProviderConfigEntryInheritable<T>(
34
67
  entry: ProviderConfigEntry<T>
35
- ): entry is ValueProviderConfigEntry<T> {
68
+ ): entry is
69
+ | ClassProviderConfigEntryUseClass<T>
70
+ | ClassProviderConfigEntryToken<T>
71
+ | ValueProviderConfigEntry<T> {
36
72
  return (
37
- Object.prototype.hasOwnProperty.call(entry, 'provide') &&
38
- Object.prototype.hasOwnProperty.call(entry, 'useValue')
73
+ isClassProviderConfigEntryUseClass(entry) ||
74
+ isClassProviderConfigEntryToken(entry) ||
75
+ isValueProviderConfigEntry(entry)
39
76
  );
40
77
  }
41
78
 
42
- export interface ProviderProps {
43
- singletons?: ProviderConfigEntry<any>[];
44
- instances?: ProviderConfigEntry<any>[];
45
- fallback?: JSX.Element;
79
+ function getProvideTokenWithClass<T>(
80
+ entry: ProviderConfigEntry<T>
81
+ ): [Token<T>, interfaces.Newable<T>] | [undefined, undefined] {
82
+ if (isClassProviderConfigEntryUseClass(entry)) {
83
+ return [entry.provide, entry.useClass];
84
+ }
85
+
86
+ if (isClassProviderConfigEntryToken(entry)) {
87
+ return [entry.provide, entry.provide];
88
+ }
89
+
90
+ if (isValueProviderConfigEntry(entry)) {
91
+ return [undefined, undefined];
92
+ }
93
+
94
+ return [entry, entry];
46
95
  }
47
96
 
48
- export const Provider: FC<ProviderProps> = ({ singletons, instances, fallback, children }) => {
49
- const parentContainer = useContext(ContainerContext);
97
+ function getStoreInstances(
98
+ container: Container,
99
+ singletons: ProviderConfigEntrySingletons<any>[] = [],
100
+ instances: ProviderConfigEntryInstances<any>[] = []
101
+ ): Store[] {
102
+ return [...singletons, ...instances].reduce((out, entry) => {
103
+ const [provide, useClass] = getProvideTokenWithClass(entry);
50
104
 
51
- const [container, setContainer] = useState<Container>();
52
- const [promises, setPromises] = useState<Promise<void>[]>();
105
+ if (provide && useClass && container.isCurrentBound(provide) && isStore(useClass)) {
106
+ out.push(container.get(provide));
107
+ }
53
108
 
54
- useLayoutEffect(() => {
55
- const container = new Container();
56
- container.parent = parentContainer;
109
+ return out;
110
+ }, [] as Store[]);
111
+ }
57
112
 
58
- const bind = (entry: ProviderConfigEntry<any>) => {
59
- if (isClassProviderConfigEntry(entry)) {
60
- return container.bind(entry.provide).to(entry.useClass);
61
- }
113
+ const bindEntry =
114
+ (container: Container, checkInherit: boolean) => (entry: ProviderConfigEntry<any>) => {
115
+ if (
116
+ checkInherit &&
117
+ isProviderConfigEntryInheritable(entry) &&
118
+ entry.inherit &&
119
+ container.isBound(entry.provide)
120
+ ) {
121
+ return undefined;
122
+ }
62
123
 
63
- if (isValueProviderConfigEntry(entry)) {
64
- // using toDynamicValue to return BindingInSyntax
65
- return container.bind(entry.provide).toDynamicValue(() => entry.useValue);
66
- }
124
+ if (isClassProviderConfigEntryUseClass(entry)) {
125
+ return container.bind(entry.provide).to(entry.useClass);
126
+ }
67
127
 
68
- return container.bind(entry).to(entry);
69
- };
128
+ if (isClassProviderConfigEntryToken(entry)) {
129
+ return container.bind(entry.provide).to(entry.provide);
130
+ }
70
131
 
71
- singletons?.map(bind).forEach(binding => {
72
- binding.inSingletonScope();
73
- });
74
- instances?.forEach(bind);
132
+ if (isValueProviderConfigEntry(entry)) {
133
+ // using toDynamicValue to return BindingInSyntax
134
+ return container.bind(entry.provide).toDynamicValue(() => entry.useValue);
135
+ }
75
136
 
76
- const storeInstances = [...(singletons ?? []), ...(instances ?? [])]
77
- .map(entry => {
78
- if (isValueProviderConfigEntry(entry)) {
79
- return undefined;
80
- }
137
+ return container.bind(entry).to(entry);
138
+ };
81
139
 
82
- const { provide, useClass } = isClassProviderConfigEntry(entry)
83
- ? entry
84
- : { provide: entry, useClass: entry };
140
+ const unbindEntry = (container: Container) => (entry: ProviderConfigEntry<any>) => {
141
+ if (
142
+ isClassProviderConfigEntryUseClass(entry) ||
143
+ isValueProviderConfigEntry(entry) ||
144
+ isClassProviderConfigEntryToken(entry)
145
+ ) {
146
+ return container.unbind(entry.provide);
147
+ }
85
148
 
86
- if (isStore(useClass)) {
87
- return container.get(provide);
88
- }
149
+ return container.unbind(entry);
150
+ };
151
+
152
+ export type ProviderProps = PropsWithChildren<{
153
+ singletons?: ProviderConfigEntrySingletons<any>[];
154
+ instances?: ProviderConfigEntryInstances<any>[];
155
+ loadingFallback?: ReactElement;
156
+ errorFallback?: ReactElement;
157
+ }>;
158
+
159
+ export const Provider: FC<ProviderProps> = ({
160
+ singletons,
161
+ instances,
162
+ loadingFallback = defaultLoadingFallback,
163
+ errorFallback = defaultErrorFallback,
164
+ children,
165
+ }) => {
166
+ const parentContainer = useContext(ContainerContext);
167
+
168
+ const [container, setContainer] = useState<Container>();
169
+ const [promises, setPromises] = useState<Promise<void>[]>([]);
170
+ const [error, setError] = useState(false);
89
171
 
90
- return undefined;
91
- })
92
- .filter(Boolean);
172
+ useLayoutEffect(() => {
173
+ const container = new Container();
174
+ container.parent = parentContainer;
175
+
176
+ singletons?.map(bindEntry(container, true)).forEach(binding => {
177
+ binding?.inSingletonScope();
178
+ });
179
+ instances?.forEach(bindEntry(container, false));
180
+
181
+ const storeInstances = getStoreInstances(container, singletons, instances);
93
182
 
94
183
  const promises: Promise<void>[] = [];
95
184
  for (const instance of storeInstances) {
96
185
  if (instance.initialize) {
97
- promises.push(instance.initialize());
186
+ let promise;
187
+
188
+ try {
189
+ promise = instance.initialize();
190
+ } catch {
191
+ setError(true);
192
+ }
193
+
194
+ if (promise && typeof promise.catch === 'function') {
195
+ promises.push(
196
+ promise.catch(() => {
197
+ setError(true);
198
+ })
199
+ );
200
+ }
98
201
  }
99
202
  }
100
203
 
@@ -102,13 +205,7 @@ export const Provider: FC<ProviderProps> = ({ singletons, instances, fallback, c
102
205
  setPromises(promises);
103
206
 
104
207
  return () => {
105
- const unbind = (entry: ProviderConfigEntry<any>) => {
106
- if (isClassProviderConfigEntry(entry) || isValueProviderConfigEntry(entry)) {
107
- return container.unbind(entry.provide);
108
- }
109
-
110
- return container.unbind(entry);
111
- };
208
+ const unbind = unbindEntry(container);
112
209
 
113
210
  singletons?.forEach(unbind);
114
211
  instances?.forEach(unbind);
@@ -125,15 +222,21 @@ export const Provider: FC<ProviderProps> = ({ singletons, instances, fallback, c
125
222
  return null;
126
223
  }
127
224
 
128
- return (
129
- <ContainerContext.Provider value={container}>
130
- {promises?.length ? (
131
- <Await promises={promises} fallback={fallback}>
225
+ const getContent = () => {
226
+ if (error) {
227
+ return errorFallback;
228
+ }
229
+
230
+ if (promises.length) {
231
+ return (
232
+ <Await promises={promises} fallback={loadingFallback}>
132
233
  {children}
133
234
  </Await>
134
- ) : (
135
- children
136
- )}
137
- </ContainerContext.Provider>
138
- );
235
+ );
236
+ }
237
+
238
+ return children;
239
+ };
240
+
241
+ return <ContainerContext.Provider value={container}>{getContent()}</ContainerContext.Provider>;
139
242
  };
package/src/store.ts CHANGED
@@ -13,9 +13,7 @@ export function isStore<T>(identifier: Identifier<T>) {
13
13
  @injectable()
14
14
  export abstract class Store {
15
15
  static [symbol] = true;
16
- }
17
16
 
18
- export interface Store {
19
- initialize?(): Promise<void>;
17
+ initialize?(): Promise<void> | void;
20
18
  dispose?(): void;
21
19
  }