reactrators
Version:
A React library for composing and enhancing components with flexible and chainable functions. Simplify the process of injecting functionality and props into React components by providing a composable utility for building component enhancers.
44 lines (39 loc) • 1.8 kB
text/typescript
import {ComponentType, createElement } from "react";
import {ComposableOptions, EnhancedProps, InjectableEntry, InjectableFunction} from "./types";
const _composeFns = (props: Record<string, any>, toCompose: (InjectableFunction | InjectableEntry)[], opts?: ComposableOptions): Record<string, any> => {
return toCompose.reduce((acc, fn) => {
if(!Array.isArray(fn) && typeof fn !== "function") {
throw new Error("Hook must be a function or an array");
}
if(Array.isArray(fn) && fn.length !== 2) {
throw new Error("Hook must be an array with 2 elements");
}
let fnToCall = fn;
let params = undefined;
if(Array.isArray(fn)) {
if(typeof fn[0] !== "function" && typeof fn[1] !== "object") {
throw new Error("Hook must be an array with first element as a function and second element as an object");
}
const [ fnArray , paramsArray ] = fn as InjectableEntry;
fnToCall = fnArray;
params = paramsArray;
}
let fnInstanceParams = { ...params, ...props };
if(opts?.chainable) {
fnInstanceParams = { ...acc, ...params, ...props };
}
const fnInstance = (fnToCall as InjectableFunction)(fnInstanceParams);
acc = { ...acc, ...fnInstance };
return acc
}, {});
}
const composable = (fn: (props?: Record<any, any>) => (InjectableFunction | InjectableEntry)[], opts: ComposableOptions ) => <P extends EnhancedProps>(
Component: ComponentType<P>
) => {
return (props: P) => {
const injectable = fn();
const toInject = _composeFns(props, injectable, opts);
return createElement(Component, { ...toInject, ...props });
}
}
export default composable;