Created
June 24, 2024 12:06
-
-
Save jackrobertscott/a8e41968181dbe61cb36893c8ba17bc4 to your computer and use it in GitHub Desktop.
Create callable react components.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {css, CSSInterpolation} from "@emotion/css" | |
import { | |
Attributes, | |
ComponentClass, | |
createElement, | |
FC, | |
HTMLProps, | |
RefAttributes, | |
SVGProps, | |
} from "react" | |
import {toKebabCase} from "./changeCase" | |
import {MergeObjects} from "./sharedTypes" | |
export type ClassNameProp = string | undefined | null | false | ClassNameProp[] | |
export type ComponentProps<T> = T extends keyof HTMLElementTagNameMap | |
? MergeObjects< | |
HTMLProps<HTMLElementTagNameMap[T]> & | |
RefAttributes<HTMLElementTagNameMap[T]>, | |
{ | |
data?: Record<string, any> | |
className?: ClassNameProp | ClassNameProp[] | |
css?: CSSInterpolation | |
} | |
> | |
: T extends keyof SVGElementTagNameMap | |
? SVGProps<SVGElementTagNameMap[T]> & RefAttributes<SVGElementTagNameMap[T]> | |
: T extends FC<infer P> | |
? P & Attributes | |
: T extends ComponentClass<infer P> | |
? P & Attributes | |
: unknown | |
function _createElement<T extends string | FC<any> | ComponentClass<any, any>>( | |
tag: T, | |
props?: ComponentProps<T>, | |
...children: any[] | |
) { | |
if (props?.children) { | |
children = children.concat(props?.children) | |
delete props.children | |
} | |
if (typeof tag === "string") { | |
if (props?.data) { | |
for (const [key, value] of Object.entries(props.data)) { | |
props["data-" + toKebabCase(key)] = value | |
} | |
delete props.data | |
} | |
if (props?.className) { | |
props.className = [props.className] | |
.flat(Infinity) | |
.filter(Boolean) | |
.join(" ") | |
} | |
if (props?.css) { | |
props.className = [props.className, css(props.css)] | |
.filter(Boolean) | |
.join(" ") | |
delete props.css | |
} | |
} | |
return createElement(tag, props, ...children) | |
} | |
export function createComponent<T extends {}>(tag: FC<T>): FC<T> | |
export function createComponent<T extends string>(tag: T): FC<ComponentProps<T>> | |
export function createComponent(tag: any): FC<any> { | |
return (props) => _createElement(tag, props) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment