fix: forwarding refs of styled components

This commit is contained in:
Mark Lawlor
2022-05-29 20:25:54 +10:00
parent 93ab9271df
commit c89e3146ae
2 changed files with 46 additions and 17 deletions

View File

@@ -6,10 +6,20 @@ export type StyledComponentProps<P> = StyledProps<P> & {
component: React.ComponentType<P>;
};
export function StyledComponent<P>({
component,
...options
}: StyledComponentProps<P>) {
const Component = styled<P>(component);
return <Component {...(options as P)} />;
declare module "react" {
// eslint-disable-next-line @typescript-eslint/ban-types
function forwardRef<T, P = {}>(
render: (props: P, ref: React.Ref<T>) => React.ReactElement | null
): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
}
function StyledComponentFunction<P>(
{ component, ...options }: StyledComponentProps<P>,
ref: React.ForwardedRef<unknown>
) {
const Component = styled(component);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return <Component {...(options as any)} ref={ref} />;
}
export const StyledComponent = React.forwardRef(StyledComponentFunction);

View File

@@ -1,9 +1,14 @@
import {
ComponentProps,
createElement,
FC,
ReactNode,
ComponentType,
forwardRef,
RefAttributes,
ForwardedRef,
ClassAttributes,
ForwardRefExoticComponent,
PropsWithoutRef,
} from "react";
import { StyledProps, StyledPropsWithKeys } from "./utils/styled";
import { ComponentContext } from "./context/component";
@@ -22,20 +27,30 @@ export interface StyledOptions<P> {
supportsClassName?: boolean;
}
type ForwardRef<T, P> = ForwardRefExoticComponent<
PropsWithoutRef<P> & RefAttributes<T>
>;
type InferRef<T> = T extends RefAttributes<infer R> | ClassAttributes<infer R>
? R
: unknown;
/**
* Normal usage
*/
export function styled<T>(
Component: ComponentType<T>,
options?: { props?: undefined; spreadProps?: undefined }
): FC<StyledProps<T>>;
): ForwardRef<InferRef<T>, StyledProps<T>>;
/**
* With either props or valueProps
*/
export function styled<T, K extends keyof T & string>(
Component: ComponentType<T>,
options: { props?: Array<K>; spreadProps?: Array<K>; classProps?: Array<K> }
): FC<StyledPropsWithKeys<T, K>>;
): ForwardRef<InferRef<T>, StyledPropsWithKeys<T, K>>;
/**
* Actual implementation
*/
@@ -50,13 +65,16 @@ export function styled<
supportsClassName = false,
}: StyledOptions<T> = {}
) {
function Styled({
className,
tw: twClassName,
style: styleProp,
children: componentChildren,
...componentProps
}: StyledProps<T>) {
function Styled(
{
className,
tw: twClassName,
style: styleProp,
children: componentChildren,
...componentProps
}: StyledProps<T>,
ref: ForwardedRef<unknown>
) {
const { platform, preview } = usePlatform();
const { classes, allClasses, isComponent } = withClassNames({
@@ -105,6 +123,7 @@ export function styled<
...handlers,
...styledProps,
children,
ref,
} as unknown as T);
return !isComponent
@@ -124,5 +143,5 @@ export function styled<
}`;
}
return Styled;
return forwardRef(Styled);
}