Skip to content

Instantly share code, notes, and snippets.

@hipstersmoothie
Last active December 23, 2020 21:31
Show Gist options
  • Save hipstersmoothie/d06fd5960269df69a416a582949a4a6a to your computer and use it in GitHub Desktop.
Save hipstersmoothie/d06fd5960269df69a416a582949a4a6a to your computer and use it in GitHub Desktop.
import { Box as BoxComponent } from "react-polymorphic-box";
declare type PropsOf<
E extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<E, React.ComponentPropsWithoutRef<E>>;
export declare type RefOf<
E extends keyof JSX.IntrinsicElements | React.JSXElementConstructor<any>
> = JSX.LibraryManagedAttributes<E, React.ComponentPropsWithRef<E>>["ref"];
/** Props for a Box component that supports the "innerRef" and "as" props. */
export type BoxProps<E extends React.ElementType, P = any> = P &
Omit<PropsOf<E>, keyof P> & {
/** Render the component as another component */
as?: E;
/** A ref to attach to the component root DOM element */
innerRef?: RefOf<E>;
};
/** The actual React component used to render BoxProps */
export const Box = BoxComponent;
/**
* Restrict the "as" prop to a subset of JSX.IntrinsicElements or a React component.
*/
export type StrictBoxElement<
Allowed extends keyof JSX.IntrinsicElements,
P = any
> =
| {
[K in Allowed]: P extends JSX.IntrinsicElements[K] ? K : never;
}[Allowed]
| React.ComponentType<P>;
import { Box, BoxProps } from "./box";
const defaultElement = "div" as const;
interface ExampleProps {
foo: string;
bar: number;
}
const Example = <E extends React.ElementType = typeof defaultElement>(
props: BoxProps<E, ExampleProps>
) => {
// If we don't cast all props are 'any'
const { foo, bar, innerRef, ...html } = props as BoxProps<
typeof defaultElement,
ExampleProps
>;
return <Box ref={innerRef} as={defaultElement} {...html} />;
};
Example.defaultProps = {
as: defaultElement,
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment