Skip to content

Commit

Permalink
inject component with registered graphs
Browse files Browse the repository at this point in the history
  • Loading branch information
guyca committed Oct 29, 2024
1 parent 7ef16fa commit 99f16b7
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ import { useInjectionToken } from './useInjectionToken';
export default class ComponentInjector {
inject<P>(
Target: React.FunctionComponent<P>,
Graph: Constructable<ObjectGraph>,
keyOrGraph: string | Constructable<ObjectGraph>,
): React.FunctionComponent<Partial<P>> {
const Wrapped = this.wrapComponent(Target, Graph);
const Wrapped = this.wrapComponent(Target, keyOrGraph);
hoistNonReactStatics(Wrapped, Target);
return Wrapped;
}

private wrapComponent<P>(
InjectionCandidate: React.FunctionComponent<P>,
Graph: Constructable<ObjectGraph>,
keyOrGraph: string | Constructable<ObjectGraph>,
): React.FunctionComponent<Partial<P>> {
const isMemoized = isMemoizedComponent(InjectionCandidate);
const Target = isMemoized ? InjectionCandidate.type : InjectionCandidate;
const compare = isMemoized ? InjectionCandidate.compare : undefined;

return genericMemo((passedProps: P) => {
const injectionToken = useInjectionToken(Graph);
const graph = useGraph<P>(Graph, Target, passedProps, injectionToken);
const injectionToken = useInjectionToken(keyOrGraph);
const graph = useGraph<P>(keyOrGraph, Target, passedProps, injectionToken);
const proxiedProps = new PropsInjector(graph).inject(passedProps);

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render } from '@testing-library/react';
import React from 'react';
import type { Constructable, ObjectGraph } from 'src';
import { Obsidian, type Constructable, type ObjectGraph } from '../..';
import MainGraph, { Dependencies } from '../../../test/fixtures/MainGraph';
import { injectComponent } from './InjectComponent';

Expand Down Expand Up @@ -35,7 +35,6 @@ describe('injectComponent', () => {
expect(container.textContent).toBe('error: own prop not provided - Fear kills progress');
});

// it throws an error if the Graph is undefined
it('Throws an error if the Graph is undefined', () => {
const Graph = undefined as unknown as Constructable<ObjectGraph>;
expect(() => injectComponent(component, Graph)).toThrowError(
Expand All @@ -45,4 +44,11 @@ describe('injectComponent', () => {
+ ` Check the implementation of component.`,
);
});

it('Injects component by registered graph key', () => {
Obsidian.registerGraph('MainGraph', () => MainGraph);
const InjectedComponent = injectComponent(component, 'MainGraph');
const { container } = render(<InjectedComponent />);
expect(container.textContent).toBe('error: own prop not provided - Fear kills progress');
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ObjectGraph } from '../../graph/ObjectGraph';
import { Constructable } from '../../types';
import { isString } from '../../utils/isString';
import ComponentInjector from './ComponentInjector';

interface Discriminator {
Expand All @@ -13,18 +14,18 @@ export const injectComponent = <OwnProps = Discriminator, InjectedProps = Discri
(OwnProps extends infer P ? OwnProps extends Discriminator ? P : OwnProps : never) &
(InjectedProps extends Discriminator ? any : InjectedProps)
>,
Graph: Constructable<ObjectGraph>,
keyOrGraph: string | Constructable<ObjectGraph>,
) => {
assertGraph(Graph, Target);
assertGraph(keyOrGraph, Target);

return componentInjector.inject(Target, Graph) as React.FunctionComponent<
return componentInjector.inject(Target, keyOrGraph) as React.FunctionComponent<
InjectedProps extends Discriminator ?
OwnProps extends Discriminator ? Partial<OwnProps> : OwnProps :
OwnProps extends InjectedProps ? Partial<OwnProps> : OwnProps & Partial<InjectedProps>
>;
};
function assertGraph(Graph: Constructable<ObjectGraph<unknown>>, Target: any) {
if (!Graph) {
function assertGraph(keyOrGraph: string | Constructable<ObjectGraph>, Target: any) {
if (!isString(keyOrGraph) && !keyOrGraph) {
throw new Error(
`injectComponent was called with an undefined Graph.`
+ `This is probably not an issue with Obsidian.`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { useContext, useState } from 'react';
import { GraphContext } from './graphContext';
import type { Constructable, ObjectGraph } from '../..';
import { uniqueId } from '../../utils/uniqueId';
import { isString } from '../../utils/isString';

export const useInjectionToken = (Graph: Constructable<ObjectGraph>) => {
export const useInjectionToken = (keyOrGraph: string | Constructable<ObjectGraph>) => {
const ctx = useContext(GraphContext);
const [injectionToken] = useState(() => ctx?.injectionToken ?? uniqueId(Graph.name));
const [injectionToken] = useState(() => {
return ctx?.injectionToken ?? uniqueId(isString(keyOrGraph)? keyOrGraph : keyOrGraph.name);
});
return injectionToken;
};

0 comments on commit 99f16b7

Please sign in to comment.