From 08a302ca670be25bbd7026d72fb9c88a39578000 Mon Sep 17 00:00:00 2001 From: Daniel Cortes Date: Wed, 4 Dec 2024 16:50:34 -0700 Subject: [PATCH] Add Polymorphic component, update Box to use it --- .../tackle-box/lib/components/Box/Box.tsx | 50 ++++++++++++++++--- .../components/Polymorphic/Polymorphic.tsx | 48 ++++++++++++++++++ 2 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 packages/tackle-box/lib/components/Polymorphic/Polymorphic.tsx diff --git a/packages/tackle-box/lib/components/Box/Box.tsx b/packages/tackle-box/lib/components/Box/Box.tsx index d7424ce..0d25ac6 100644 --- a/packages/tackle-box/lib/components/Box/Box.tsx +++ b/packages/tackle-box/lib/components/Box/Box.tsx @@ -1,5 +1,5 @@ import { ReactNode, useMemo } from "react"; -import { css, html } from "react-strict-dom"; +import { css } from "react-strict-dom"; import { type Colors, getColorValue } from "@/vars/colors.stylex"; import { StyleObj, UnitValue } from "@/utils/types"; import { @@ -13,6 +13,12 @@ import { type BorderRadiusArgs, type BorderWidthArgs, } from "./utils"; +import { + Polymorphic, + PolymorphicComponentProps, + RSDElementTypes, +} from "../Polymorphic/Polymorphic"; + const styles = css.create({ base: { boxSizing: "border-box", @@ -82,7 +88,7 @@ export type BoxProps = BorderRadiusArgs & style?: StyleObj; } & MarginPadding; -export function Box({ +export function Box({ children, height = "auto", width = "100%", @@ -100,9 +106,38 @@ export function Box({ borderLeftWidth, flexGrow, style, - ...marginPadding -}: BoxProps) { - const { margin, padding } = useMarginPaddingValues(marginPadding); + m, + mx, + my, + mt, + mr, + mb, + ml, + p, + px, + py, + pt, + pr, + pb, + pl, + ...rest +}: PolymorphicComponentProps) { + const { margin, padding } = useMarginPaddingValues({ + m, + mx, + my, + mt, + mr, + mb, + ml, + p, + px, + py, + pt, + pr, + pb, + pl, + }); const borderRadiusValues = useMemo(() => { return computeBorderRadius({ @@ -137,7 +172,7 @@ export function Box({ ]); return ( - {children} - + ); } diff --git a/packages/tackle-box/lib/components/Polymorphic/Polymorphic.tsx b/packages/tackle-box/lib/components/Polymorphic/Polymorphic.tsx new file mode 100644 index 0000000..2cce11f --- /dev/null +++ b/packages/tackle-box/lib/components/Polymorphic/Polymorphic.tsx @@ -0,0 +1,48 @@ +import { ComponentPropsWithoutRef, PropsWithChildren } from "react"; +import { html } from "react-strict-dom"; + +/** + * Union of possible react-strict-dom elements. E.g. html.div, html.p would equal "div" | "p" + */ +export type RSDElementTypes = keyof typeof html; + +/** + * Gets the React.ElementType for a given react-strict-dom element. + */ +type RSDElement = (typeof html)[T]; + +/** + * Gets the props for a given react-strict-dom element. + */ +type RSDElementProps = ComponentPropsWithoutRef< + RSDElement +>; + +/** + * Props for the `as` prop that can be used to change the returned element type. + */ +type AsProp = { + as?: TAsProp; +}; + +/** + * Utility to create props for polymorphic components. + */ +export type PolymorphicComponentProps< + TAsProp extends RSDElementTypes, + // eslint-disable-next-line @typescript-eslint/no-empty-object-type + TProps extends Record = {}, +> = PropsWithChildren< + AsProp & TProps & Omit, keyof TProps> +>; + +export function Polymorphic({ + as, + children, + ...rest +}: PolymorphicComponentProps) { + const elementType: RSDElementTypes = as ?? "div"; + const Component = html[elementType]; + + return {children}; +}