react-fast-hoc
Advanced tools
Comparing version
# react-fast-hoc | ||
## 0.1.0 | ||
### Minor Changes | ||
- ca39ecc: Added mimic to new component functionality. And changed `createHoc` options object api | ||
- b5e5c89: Fixed types naming | ||
### Patch Changes | ||
- 9966412: Added wrap into proxy function | ||
## 0.0.3 | ||
@@ -4,0 +15,0 @@ |
@@ -5,37 +5,84 @@ import type { Booleans, Fn, Pipe } from "hotscript"; | ||
type PropsBase = Record<string | number | symbol, unknown>; | ||
/** | ||
* Returns new comonent types after wrapping into hoc | ||
*/ | ||
type ChangeComponentProps<TComponent extends ComponentType<any>, TNewProps> = TComponent extends MemoExoticComponent<infer TNested> ? MemoExoticComponent<TNested extends React.ComponentClass<any, any> ? ForwardRefExoticComponent<TNewProps> : FunctionComponent<TNewProps>> : TComponent extends ForwardRefExoticComponent<any> ? ForwardRefExoticComponent<TNewProps> : TComponent extends React.ComponentClass<any, any> ? ForwardRefExoticComponent<TNewProps> : TComponent extends FunctionComponent<any> ? FunctionComponent<TNewProps> : never; | ||
export type FastHocComponentWrapperReturn<TPipeTransform extends Fn[], TComponentPropsExtends extends object, TComponent extends ComponentType<any>, TComputedProps extends TComponentPropsExtends = TComponent extends ElementType<any> ? ComponentPropsWithRef<TComponent> : never> = ChangeComponentProps<TComponent, Pipe<TComputedProps, TPipeTransform>>; | ||
export type FastHocComponentWrapper<TPipeTransform extends Fn[], TComponentPropsExtends extends object> = <TComponent extends ComponentType<any> = React.FC<any>>(component: TComponent) => FastHocComponentWrapperReturn<TPipeTransform, TComponentPropsExtends, TComponent>; | ||
export type FastHocReturn<TPipeTransform extends Fn[], TComponentPropsExtends extends PropsBase = PropsBase> = FastHocComponentWrapper<TPipeTransform, TComponentPropsExtends>; | ||
export type FastHocPropsTransformer = (props: Record<string | symbol | number, unknown>) => Record<string | symbol | number, unknown>; | ||
export type FastHocArg = { | ||
propsTransformer: null | FastHocPropsTransformer; | ||
resultTransformer: null | ((jsx: ReactNode) => ReactNode); | ||
} & ({ | ||
/** | ||
* Returns a wrapped component with transformed props | ||
*/ | ||
export type WrappedComponent<TPipeTransform extends Fn[], TComponentPropsExtends extends object, TComponent extends ComponentType<any>, TComputedProps extends TComponentPropsExtends = TComponent extends ElementType<any> ? ComponentPropsWithRef<TComponent> : never> = ChangeComponentProps<TComponent, Pipe<TComputedProps, TPipeTransform>>; | ||
/** | ||
* Higher-order component that wraps the input component | ||
* with the provided transformation pipeline and new component props. | ||
*/ | ||
export type WrappedComponentCreator<TPipeTransform extends Fn[], TComponentPropsExtends extends object> = <TComponent extends ComponentType<any> = React.FC<any>>(component: TComponent) => WrappedComponent<TPipeTransform, TComponentPropsExtends, TComponent>; | ||
export type CreateHocReturn<TPipeTransform extends Fn[], TComponentPropsExtends extends PropsBase = PropsBase> = WrappedComponentCreator<TPipeTransform, TComponentPropsExtends>; | ||
export type PropsTransformer = (props: Record<string | symbol | number, unknown>) => Record<string | symbol | number, unknown>; | ||
export type CreateHocComponentOptions = ({ | ||
namePrefix: string; | ||
nameRewrite: null; | ||
} | { | ||
namePrefix: null; | ||
nameRewrite: string; | ||
}); | ||
}) & { | ||
/** | ||
* @description This feature has overhead in terms of using another proxy | ||
* to you can easilty mutate and define new properties, and not change inital component | ||
*/ | ||
mimicToNewComponent?: boolean; | ||
}; | ||
/** | ||
* | ||
* @param propsTransformer props transformer not typesafe for now | ||
* represents the argument object for the createHoc function. It contains | ||
* the props and result transformers, and options for name prefix or rewrite. | ||
*/ | ||
export type CreateHocOptions = { | ||
/** | ||
* @description you can mutate props object | ||
*/ | ||
propsTransformer: null | PropsTransformer; | ||
resultTransformer: null | ((jsx: ReactNode) => ReactNode); | ||
} & CreateHocComponentOptions; | ||
/** | ||
* allows to wrap component into the proxy as functional component | ||
*/ | ||
export declare const wrapIntoProxy: (proxy: ProxyHandler<Function>) => <T extends ComponentType<{}>>(Component: T) => ChangeComponentProps<T, T extends ElementType<any> ? ComponentPropsWithRef<T> : never>; | ||
/** | ||
* @description *Transformations is not typesafe, you should [hotscript](https://github.com/gvergnaud/HOTScript) for type transformation* | ||
* @param propsTransformer You can use react hooks in the transformer function. | ||
* @param displayNamePrefix | ||
* @returns | ||
*/ | ||
export declare const createHoc: <TPipeTransform extends Fn[], ComponentPropsExtends extends PropsBase = PropsBase>(params: FastHocArg) => FastHocReturn<TPipeTransform, ComponentPropsExtends>; | ||
export declare const createHoc: <TPipeTransform extends Fn[], ComponentPropsExtends extends PropsBase = PropsBase>(params: CreateHocOptions) => CreateHocReturn<TPipeTransform, ComponentPropsExtends>; | ||
/** | ||
* | ||
* @param propsTransformer props transformer not typesafe for now | ||
* @param displayNamePrefix | ||
* @description create a hoc that automagically applies proxy to component. *Transformations is not typesafe, you should [hotscript](https://github.com/gvergnaud/HOTScript) for type transformation* | ||
* @example | ||
* ```tsx | ||
* const withProps = createTransformProps<[], { newProp: string }>((props) => ({ | ||
* ...props, | ||
* newProp: props?.newProp ?? "newProp", | ||
* })); | ||
* ``` | ||
* @param propsTransformer You can use react hooks in the transformer function | ||
* @param options | ||
* @returns | ||
*/ | ||
export declare const createTransformProps: <TPipeTransform extends Fn[] = [], ComponentPropsExtends extends PropsBase = PropsBase>(propsTransformer: FastHocPropsTransformer, displayNamePrefix?: string) => FastHocReturn<TPipeTransform, ComponentPropsExtends>; | ||
export type TransformPropsReturn<T extends React.ComponentType<any>, TNewProps extends PropsBase> = FastHocComponentWrapperReturn<[ | ||
export declare const createTransformProps: <TPipeTransform extends Fn[] = [], ComponentPropsExtends extends PropsBase = PropsBase>(propsTransformer: PropsTransformer, options?: CreateHocComponentOptions) => CreateHocReturn<TPipeTransform, ComponentPropsExtends>; | ||
/** | ||
* type alias for the result of the transformProps function. | ||
*/ | ||
export type TransformPropsReturn<TComponent extends React.ComponentType<any>, TNewProps extends PropsBase> = WrappedComponent<[ | ||
HotscriptObjects.OmitBy<Booleans.Not<never>>, | ||
HotscriptObjects.Assign<TNewProps> | ||
], any, T>; | ||
export declare const transformProps: <T extends ComponentType<any>, TNewProps extends PropsBase, TPreviousProps extends ComponentPropsWithRef<T> = ComponentPropsWithRef<T>>(Component: T, transformer: (props: TNewProps) => TPreviousProps, displayNamePrefix?: string) => ChangeComponentProps<T, (import("hotscript/dist/internals/helpers").IsNever<import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps> extends true ? [import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps, HotscriptObjects.OmitByImpl<T extends ElementType<any> ? ComponentPropsWithRef<T> : never, Booleans.Not<never>>] : [import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps] extends ["@hotscript/placeholder"] ? [HotscriptObjects.OmitByImpl<T extends ElementType<any> ? ComponentPropsWithRef<T> : never, Booleans.Not<never>>] : [import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps, HotscriptObjects.OmitByImpl<T extends ElementType<any> ? ComponentPropsWithRef<T> : never, Booleans.Not<never>>]) extends infer args extends unknown[] ? import("hotscript/dist/internals/helpers").UnionToIntersection<(args extends infer args_1 extends unknown[] ? args_1 : never)[number]> extends infer T_1 ? { [K in keyof T_1]: import("hotscript/dist/internals/helpers").UnionToIntersection<(args extends infer args_1 extends unknown[] ? args_1 : never)[number]>[K]; } : never : never>; | ||
], any, TComponent>; | ||
/** | ||
* transformProps is a function that takes a component, a props transformer function, and an | ||
* optional display name prefix, and returns a higher-order component that wraps the input | ||
* component with the specified props transformations. | ||
* | ||
* @param Component The input component to be wrapped with the props transformations. | ||
* @param transformer A function that takes the new props and returns the previous props for the input component. | ||
* @param options Optional string to prefix the display name of the resulting component. | ||
* @returns A higher-order component that wraps the input component with the specified props transformations. | ||
*/ | ||
export declare const transformProps: <TComponent extends ComponentType<any>, TNewProps extends PropsBase = ComponentPropsWithRef<TComponent>, TPreviousProps extends ComponentPropsWithRef<TComponent> = ComponentPropsWithRef<TComponent>>(Component: TComponent, transformer: (props: TNewProps) => TPreviousProps, options?: CreateHocComponentOptions) => ChangeComponentProps<TComponent, (import("hotscript/dist/internals/helpers").IsNever<import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps> extends true ? [import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps, HotscriptObjects.OmitByImpl<TComponent extends ElementType<any> ? ComponentPropsWithRef<TComponent> : never, Booleans.Not<never>>] : [import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps] extends ["@hotscript/placeholder"] ? [HotscriptObjects.OmitByImpl<TComponent extends ElementType<any> ? ComponentPropsWithRef<TComponent> : never, Booleans.Not<never>>] : [import("hotscript/dist/internals/helpers").IsNever<TNewProps> extends true ? never : [TNewProps] extends ["@hotscript/unset"] ? "@hotscript/placeholder" : TNewProps, HotscriptObjects.OmitByImpl<TComponent extends ElementType<any> ? ComponentPropsWithRef<TComponent> : never, Booleans.Not<never>>]) extends infer args extends unknown[] ? import("hotscript/dist/internals/helpers").UnionToIntersection<(args extends infer args_1 extends unknown[] ? args_1 : never)[number]> extends infer T ? { [K in keyof T]: import("hotscript/dist/internals/helpers").UnionToIntersection<(args extends infer args_1 extends unknown[] ? args_1 : never)[number]>[K]; } : never : never>; | ||
export {}; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -26,3 +26,4 @@ "use strict"; | ||
createTransformProps: () => createTransformProps, | ||
transformProps: () => transformProps | ||
transformProps: () => transformProps, | ||
wrapIntoProxy: () => wrapIntoProxy | ||
}); | ||
@@ -107,3 +108,49 @@ module.exports = __toCommonJS(src_exports); | ||
}, "wrapFunctionalFROrDefault"); | ||
var wrapComponentIntoHoc = /* @__PURE__ */ __name((Component, handler) => { | ||
var MimicToNewComponentHandler = class { | ||
constructor() { | ||
this._componentProps = /* @__PURE__ */ new WeakMap(); | ||
} | ||
get(target, p, receiver) { | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps && overridenProps.has(p)) { | ||
return overridenProps.get(p); | ||
} | ||
return Reflect.get(target, p, receiver); | ||
} | ||
set(target, p, value) { | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps) { | ||
overridenProps.set(p, value); | ||
return true; | ||
} | ||
this._componentProps.set(target, /* @__PURE__ */ new Map([[p, value]])); | ||
return true; | ||
} | ||
defineProperty(target, property, attributes) { | ||
if (!("value" in attributes)) { | ||
console.error("Only value property is supported"); | ||
return false; | ||
} | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps) { | ||
overridenProps.set(property, attributes.value); | ||
return true; | ||
} | ||
this._componentProps.set(target, /* @__PURE__ */ new Map([[property, attributes.value]])); | ||
return true; | ||
} | ||
deleteProperty(target, p) { | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps) { | ||
overridenProps.delete(p); | ||
return true; | ||
} | ||
return Reflect.deleteProperty(target, p); | ||
} | ||
has(target, prop) { | ||
return this._componentProps.get(target)?.has(prop) || Reflect.has(target, prop); | ||
} | ||
}; | ||
__name(MimicToNewComponentHandler, "MimicToNewComponentHandler"); | ||
var wrapComponentIntoHoc = /* @__PURE__ */ __name((Component, handler, mimicToNewComponentHandler) => { | ||
if (isClassComponent(Component)) { | ||
@@ -130,7 +177,14 @@ return wrapFunctionalFROrDefault( | ||
} | ||
return new Proxy(Component, handler); | ||
const proxied = new Proxy(Component, handler); | ||
return mimicToNewComponentHandler ? new Proxy(proxied, mimicToNewComponentHandler) : proxied; | ||
}, "wrapComponentIntoHoc"); | ||
// src/index.ts | ||
var wrapIntoProxy = /* @__PURE__ */ __name((proxy) => (Component) => wrapComponentIntoHoc( | ||
Component, | ||
proxy, | ||
null | ||
), "wrapIntoProxy"); | ||
var createHoc = /* @__PURE__ */ __name((params) => { | ||
const { mimicToNewComponent = true } = params; | ||
const proxyObject = new HocTransformer( | ||
@@ -143,16 +197,21 @@ // @ts-expect-error | ||
); | ||
return (component) => wrapComponentIntoHoc(component, proxyObject); | ||
const mimicToHandler = mimicToNewComponent ? new MimicToNewComponentHandler() : null; | ||
return (component) => wrapComponentIntoHoc( | ||
component, | ||
proxyObject, | ||
mimicToHandler | ||
); | ||
}, "createHoc"); | ||
var createTransformProps = /* @__PURE__ */ __name((propsTransformer, displayNamePrefix) => createHoc({ | ||
namePrefix: displayNamePrefix ?? "Transformed", | ||
var DEFAULT_TRANSFORM_OPTIONS = { namePrefix: "Transformed" }; | ||
var createTransformProps = /* @__PURE__ */ __name((propsTransformer, options) => createHoc({ | ||
propsTransformer, | ||
resultTransformer: null, | ||
nameRewrite: null | ||
...options ?? DEFAULT_TRANSFORM_OPTIONS | ||
}), "createTransformProps"); | ||
var transformProps = /* @__PURE__ */ __name((Component, transformer, displayNamePrefix) => createTransformProps( | ||
var transformProps = /* @__PURE__ */ __name((Component, transformer, options) => createTransformProps( | ||
// @ts-expect-error | ||
transformer, | ||
displayNamePrefix | ||
options | ||
)(Component), "transformProps"); | ||
/*! For license information please see index.js.LEGAL.txt */ | ||
//# sourceMappingURL=index.js.map |
import type { ReactNode, Ref } from "react"; | ||
import { Get } from "./toFunctional"; | ||
import { type Get } from "./toFunctional"; | ||
export declare class HocTransformer implements ProxyHandler<Function> { | ||
@@ -23,3 +23,11 @@ private transformer; | ||
} | React.ComponentClass<TProps> | React.FC<TProps>; | ||
export declare const wrapComponentIntoHoc: <TProps extends object>(Component: RealComponentType<TProps, unknown>, handler: HocTransformer) => Function | { | ||
export declare class MimicToNewComponentHandler implements ProxyHandler<Function> { | ||
private _componentProps; | ||
get(target: Function, p: PropertyKey, receiver: any): any; | ||
set(target: Function, p: PropertyKey, value: any): boolean; | ||
defineProperty(target: Function, property: PropertyKey, attributes: PropertyDescriptor): boolean; | ||
deleteProperty(target: Function, p: PropertyKey): boolean; | ||
has(target: Function, prop: PropertyKey): boolean; | ||
} | ||
export declare const wrapComponentIntoHoc: <TProps extends object>(Component: RealComponentType<TProps, unknown>, handler: HocTransformer, mimicToNewComponentHandler: null | MimicToNewComponentHandler) => Function | { | ||
$$typeof: symbol; | ||
@@ -26,0 +34,0 @@ render: Function; |
{ | ||
"name": "react-fast-hoc", | ||
"license": "MIT", | ||
"version": "0.0.3", | ||
"version": "0.1.0", | ||
"sideEffects": false, | ||
@@ -31,2 +31,3 @@ "publishConfig": { | ||
"@types/react-dom": "^18.2.0", | ||
"cpx": "^1.5.0", | ||
"jsdom": "^21.1.1", | ||
@@ -53,4 +54,5 @@ "nanobundle": "^1.6.0", | ||
"lint": "pnpm typecheck", | ||
"build": "nanobundle build --clean --verbose" | ||
"build:collect-readme": "cpx ../../README.md .", | ||
"build": "pnpm build:collect-readme & nanobundle build --clean --verbose" | ||
} | ||
} |
@@ -9,5 +9,5 @@ # React Fast HOC | ||
- [Usage](#usage) | ||
- [transformProps](#transformProps) | ||
- [createHoc](#createHoc) | ||
- [createTransformProps](#createTransformProps) | ||
- [transformProps](#transformProps) | ||
- [API Reference](#api-reference) | ||
@@ -39,2 +39,19 @@ - [Examples](#examples) | ||
### transformProps | ||
Directly create a new component with transformed props. | ||
```typescript | ||
import { transformProps } from "react-fast-hoc"; | ||
const EnhancedComponent = transformProps( | ||
MyComponent, | ||
(props) => { | ||
// Transform props here | ||
return { ...props, transformedProp: "Transformed Value" }; | ||
}, | ||
"WithTransformedProps" | ||
); | ||
``` | ||
### createHoc | ||
@@ -75,19 +92,4 @@ | ||
### transformProps | ||
> You can use `wrapIntoProxy` to create more customizable hocs | ||
Directly create a new component with transformed props. | ||
```typescript | ||
import { transformProps } from "react-fast-hoc"; | ||
const EnhancedComponent = transformProps( | ||
MyComponent, | ||
(props) => { | ||
// Transform props here | ||
return { ...props, transformedProp: "Transformed Value" }; | ||
}, | ||
"WithTransformedProps" | ||
); | ||
``` | ||
## API Reference | ||
@@ -94,0 +96,0 @@ |
@@ -24,10 +24,12 @@ import { cleanup, render } from "@testing-library/react"; | ||
test("works correct with FC", () => { | ||
expect(createTransformProps(identityProps)(() => null)).toBeTypeOf("function"); | ||
expect(createTransformProps(identityProps)(() => null)).toBeTypeOf( | ||
"function" | ||
); | ||
}); | ||
test("transforms class component to function component", () => { | ||
console.log(createTransformProps(identityProps)(ClassComponent)); | ||
// @ts-expect-error internal property | ||
expect(createTransformProps(identityProps)(ClassComponent).render).toBeTypeOf( | ||
"function" | ||
); | ||
expect( | ||
// @ts-expect-error internal property | ||
createTransformProps(identityProps)(ClassComponent).render | ||
).toBeTypeOf("function"); | ||
}); | ||
@@ -44,3 +46,5 @@ }); | ||
); | ||
const addBebeHoc = createTransformProps<[Objects.Omit<"bebe">]>(addBebeProp as any); | ||
const addBebeHoc = createTransformProps<[Objects.Omit<"bebe">]>( | ||
addBebeProp as any | ||
); | ||
const Component = vi.fn(() => null); | ||
@@ -47,0 +51,0 @@ const propsDetector = vi.fn((props: unknown) => null); |
138
src/index.ts
@@ -15,2 +15,3 @@ import type { Booleans, Fn, Pipe } from "hotscript"; | ||
HocTransformer, | ||
MimicToNewComponentHandler, | ||
wrapComponentIntoHoc, | ||
@@ -22,2 +23,5 @@ wrapPropsTransformer, | ||
/** | ||
* Returns new comonent types after wrapping into hoc | ||
*/ | ||
type ChangeComponentProps< | ||
@@ -40,3 +44,6 @@ TComponent extends ComponentType<any>, | ||
export type FastHocComponentWrapperReturn< | ||
/** | ||
* Returns a wrapped component with transformed props | ||
*/ | ||
export type WrappedComponent< | ||
TPipeTransform extends Fn[], | ||
@@ -50,3 +57,7 @@ TComponentPropsExtends extends object, | ||
export type FastHocComponentWrapper< | ||
/** | ||
* Higher-order component that wraps the input component | ||
* with the provided transformation pipeline and new component props. | ||
*/ | ||
export type WrappedComponentCreator< | ||
TPipeTransform extends Fn[], | ||
@@ -56,34 +67,54 @@ TComponentPropsExtends extends object | ||
component: TComponent | ||
) => FastHocComponentWrapperReturn< | ||
TPipeTransform, | ||
TComponentPropsExtends, | ||
TComponent | ||
>; | ||
) => WrappedComponent<TPipeTransform, TComponentPropsExtends, TComponent>; | ||
export type FastHocReturn< | ||
export type CreateHocReturn< | ||
TPipeTransform extends Fn[], | ||
TComponentPropsExtends extends PropsBase = PropsBase | ||
> = FastHocComponentWrapper<TPipeTransform, TComponentPropsExtends>; | ||
> = WrappedComponentCreator<TPipeTransform, TComponentPropsExtends>; | ||
export type FastHocPropsTransformer = ( | ||
export type PropsTransformer = ( | ||
props: Record<string | symbol | number, unknown> | ||
) => Record<string | symbol | number, unknown>; | ||
export type FastHocArg = { | ||
propsTransformer: null | FastHocPropsTransformer; | ||
resultTransformer: null | ((jsx: ReactNode) => ReactNode); | ||
} & ( | ||
export type CreateHocComponentOptions = ( | ||
| { | ||
namePrefix: string; | ||
nameRewrite: null; | ||
} | ||
| { | ||
namePrefix: null; | ||
nameRewrite: string; | ||
} | ||
); | ||
) & { | ||
/** | ||
* @description This feature has overhead in terms of using another proxy | ||
* to you can easilty mutate and define new properties, and not change inital component | ||
*/ | ||
mimicToNewComponent?: boolean; | ||
}; | ||
/** | ||
* represents the argument object for the createHoc function. It contains | ||
* the props and result transformers, and options for name prefix or rewrite. | ||
*/ | ||
export type CreateHocOptions = { | ||
/** | ||
* @description you can mutate props object | ||
*/ | ||
propsTransformer: null | PropsTransformer; | ||
resultTransformer: null | ((jsx: ReactNode) => ReactNode); | ||
} & CreateHocComponentOptions; | ||
/** | ||
* | ||
* @param propsTransformer props transformer not typesafe for now | ||
* allows to wrap component into the proxy as functional component | ||
*/ | ||
export const wrapIntoProxy = | ||
(proxy: ProxyHandler<Function>) => | ||
<T extends React.ComponentType>(Component: T) => | ||
wrapComponentIntoHoc( | ||
Component, | ||
proxy as HocTransformer, | ||
null | ||
) as WrappedComponent<[], PropsBase, T>; | ||
/** | ||
* @description *Transformations is not typesafe, you should [hotscript](https://github.com/gvergnaud/HOTScript) for type transformation* | ||
* @param propsTransformer You can use react hooks in the transformer function. | ||
* @param displayNamePrefix | ||
@@ -96,4 +127,5 @@ * @returns | ||
>( | ||
params: FastHocArg | ||
params: CreateHocOptions | ||
) => { | ||
const { mimicToNewComponent = true } = params; | ||
const proxyObject = new HocTransformer( | ||
@@ -108,14 +140,27 @@ // @ts-expect-error | ||
); | ||
const mimicToHandler = mimicToNewComponent | ||
? new MimicToNewComponentHandler() | ||
: null; | ||
return ((component: ComponentType<unknown>) => | ||
wrapComponentIntoHoc(component, proxyObject)) as FastHocReturn< | ||
TPipeTransform, | ||
ComponentPropsExtends | ||
>; | ||
wrapComponentIntoHoc( | ||
component, | ||
proxyObject, | ||
mimicToHandler | ||
)) as CreateHocReturn<TPipeTransform, ComponentPropsExtends>; | ||
}; | ||
const DEFAULT_TRANSFORM_OPTIONS = { namePrefix: "Transformed" } as const; | ||
/** | ||
* | ||
* @param propsTransformer props transformer not typesafe for now | ||
* @param displayNamePrefix | ||
* @description create a hoc that automagically applies proxy to component. *Transformations is not typesafe, you should [hotscript](https://github.com/gvergnaud/HOTScript) for type transformation* | ||
* @example | ||
* ```tsx | ||
* const withProps = createTransformProps<[], { newProp: string }>((props) => ({ | ||
* ...props, | ||
* newProp: props?.newProp ?? "newProp", | ||
* })); | ||
* ``` | ||
* @param propsTransformer You can use react hooks in the transformer function | ||
* @param options | ||
* @returns | ||
@@ -127,17 +172,18 @@ */ | ||
>( | ||
propsTransformer: FastHocPropsTransformer, | ||
displayNamePrefix?: string | ||
propsTransformer: PropsTransformer, | ||
options?: CreateHocComponentOptions | ||
) => | ||
createHoc<TPipeTransform, ComponentPropsExtends>({ | ||
namePrefix: displayNamePrefix ?? "Transformed", | ||
propsTransformer, | ||
resultTransformer: null, | ||
nameRewrite: null, | ||
...(options ?? DEFAULT_TRANSFORM_OPTIONS), | ||
}); | ||
// type ObjectsAssign<T extends object> = Objects.Pick<T>; | ||
/** | ||
* type alias for the result of the transformProps function. | ||
*/ | ||
export type TransformPropsReturn< | ||
T extends React.ComponentType<any>, | ||
TComponent extends React.ComponentType<any>, | ||
TNewProps extends PropsBase | ||
> = FastHocComponentWrapperReturn< | ||
> = WrappedComponent< | ||
[ | ||
@@ -148,13 +194,23 @@ HotscriptObjects.OmitBy<Booleans.Not<never>>, | ||
any, | ||
T | ||
TComponent | ||
>; | ||
/** | ||
* transformProps is a function that takes a component, a props transformer function, and an | ||
* optional display name prefix, and returns a higher-order component that wraps the input | ||
* component with the specified props transformations. | ||
* | ||
* @param Component The input component to be wrapped with the props transformations. | ||
* @param transformer A function that takes the new props and returns the previous props for the input component. | ||
* @param options Optional string to prefix the display name of the resulting component. | ||
* @returns A higher-order component that wraps the input component with the specified props transformations. | ||
*/ | ||
export const transformProps = < | ||
T extends React.ComponentType<any>, | ||
TNewProps extends PropsBase, | ||
TPreviousProps extends ComponentPropsWithRef<T> = ComponentPropsWithRef<T> | ||
TComponent extends React.ComponentType<any>, | ||
TNewProps extends PropsBase = ComponentPropsWithRef<TComponent>, | ||
TPreviousProps extends ComponentPropsWithRef<TComponent> = ComponentPropsWithRef<TComponent> | ||
>( | ||
Component: T, | ||
Component: TComponent, | ||
transformer: (props: TNewProps) => TPreviousProps, | ||
displayNamePrefix?: string | ||
options?: CreateHocComponentOptions | ||
) => | ||
@@ -164,3 +220,3 @@ createTransformProps( | ||
transformer, | ||
displayNamePrefix | ||
)(Component) as unknown as TransformPropsReturn<T, TNewProps>; | ||
options | ||
)(Component) as unknown as TransformPropsReturn<TComponent, TNewProps>; |
import type { ReactNode, Ref } from "react"; | ||
import { Get, isClassComponent, toFunctional } from "./toFunctional"; | ||
import { type Get, isClassComponent, toFunctional } from "./toFunctional"; | ||
@@ -111,2 +111,55 @@ // Using classes to save memory | ||
export class MimicToNewComponentHandler implements ProxyHandler<Function> { | ||
private _componentProps = new WeakMap<Function, Map<PropertyKey, unknown>>(); | ||
get(target: Function, p: PropertyKey, receiver: any) { | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps && overridenProps.has(p)) { | ||
return overridenProps.get(p); | ||
} | ||
return Reflect.get(target, p, receiver); | ||
} | ||
set(target: Function, p: PropertyKey, value: any) { | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps) { | ||
overridenProps.set(p, value); | ||
return true; | ||
} | ||
this._componentProps.set(target, new Map([[p, value]])); | ||
return true; | ||
} | ||
defineProperty( | ||
target: Function, | ||
property: PropertyKey, | ||
attributes: PropertyDescriptor | ||
) { | ||
if (!("value" in attributes)) { | ||
console.error("Only value property is supported"); | ||
return false; | ||
} | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps) { | ||
overridenProps.set(property, attributes.value); | ||
return true; | ||
} | ||
this._componentProps.set(target, new Map([[property, attributes.value]])); | ||
return true; | ||
} | ||
deleteProperty(target: Function, p: PropertyKey) { | ||
// TODO: IMPROVE | ||
const overridenProps = this._componentProps.get(target); | ||
if (overridenProps) { | ||
overridenProps.delete(p); | ||
return true; | ||
} | ||
return Reflect.deleteProperty(target, p); | ||
} | ||
has(target: Function, prop: PropertyKey) { | ||
return ( | ||
this._componentProps.get(target)?.has(prop) || Reflect.has(target, prop) | ||
); | ||
} | ||
} | ||
// I don't know why but typescript is not helpful at all | ||
@@ -117,3 +170,4 @@ | ||
Component: RealComponentType<TProps>, | ||
handler: HocTransformer | ||
handler: HocTransformer, | ||
mimicToNewComponentHandler: null | MimicToNewComponentHandler | ||
) => { | ||
@@ -148,3 +202,6 @@ // this case assumes that it's ClassComponent | ||
return new Proxy(Component, handler); | ||
const proxied = new Proxy(Component, handler); | ||
return mimicToNewComponentHandler | ||
? new Proxy(proxied, mimicToNewComponentHandler) | ||
: proxied; | ||
}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
97838
33.56%24
4.35%1218
34.44%103
1.98%12
9.09%