libs/modulify-ui/src/lib/Inversify.tsx (73 lines of code) (raw):

/* eslint-disable @typescript-eslint/no-explicit-any */ import { FC, PropsWithChildren } from 'react'; export type PropsFrom<Component> = Component extends FC<infer Props> ? Props : never; type ComponentProps<P> = P extends FC<infer Props> ? PropsWithChildren<Props> : never; // TODO: replace any, use narrow typings type OriginalComponent<P extends NonNullable<any> = NonNullable<any>> = FC< PropsWithChildren<P> >; type ComponentImplementation<OC extends OriginalComponent> = FC< ComponentProps<OC> >; interface ComponentResolve<OC extends OriginalComponent> { instance: () => ComponentImplementation<OC> | undefined; bind: ( componentFactory: (component: OC) => ComponentImplementation<OC>, ) => ComponentImplementation<OC>; unbind: () => void; render: () => ComponentImplementation<OC> & { original: OC }; } export class Inversify { private static container = new WeakMap< OriginalComponent, ComponentImplementation<OriginalComponent> >(); public static register<OC extends OriginalComponent>( name: string, component: OC, ): ComponentImplementation<OC> & { original: OC } { try { if (!component.name) { Object.defineProperty(component, 'name', { value: name, writable: false, configurable: true, enumerable: false, }); } return Inversify.resolve(component).render(); } catch { return component as unknown as ComponentImplementation<OC> & { original: OC; }; } } public static resolve<OC extends OriginalComponent>( component: OC, ): ComponentResolve<OC> { if (component && !Inversify.container.has(component)) { Inversify.container.set(component, component); } return { instance: () => Inversify.container.get(component), bind: ( componentFactory: (component: OC) => ComponentImplementation<OC>, ) => Inversify.bindImplementation(component, componentFactory), unbind: () => Inversify.container.set(component, component), render: () => Inversify.renderImplementation(component), }; } private static bindImplementation<OC extends OriginalComponent>( component: OC, componentFactory: (component: OC) => ComponentImplementation<OC>, ): ComponentImplementation<OC> { const newComponent = componentFactory(component); Inversify.container.set(component, newComponent as OC); return newComponent; } private static renderImplementation<OC extends OriginalComponent>( component: OC, ): ComponentImplementation<OC> & { original: OC } { const renderedComponent = (props: ComponentProps<OC>) => { const ResolvedComponent = Inversify.container.get(component) ?? component; return <ResolvedComponent {...props} />; }; Object.defineProperties(renderedComponent, { name: { value: component.name, writable: false, configurable: true, enumerable: false, }, original: { value: component, writable: false, configurable: true, enumerable: false, }, }); return renderedComponent as ComponentImplementation<OC> & { original: OC }; } } export default Inversify;