-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
Let me start by saying I do not have an understanding of the object structure of React components under the hood (e.g. fibers).
My detailed component structure
BUTTON
import {
cloneElement,
ComponentProps,
ForwardedRef,
forwardRef,
ReactElement,
ReactNode,
} from "react";
import classNames from "classnames";
import Link from "@/components/Link";
import Tooltip from "@/components/Tooltip";
import classes from "./Button.module.css";
type Base = {
/** icon to show next to text */
icon?: ReactElement;
/** look */
design?: "normal" | "accent" | "critical";
};
type Content =
/** require text and/or tooltip for accessibility */
{ text: string; tooltip?: ReactNode } | { text?: string; tooltip: ReactNode };
/** <a> or <RouterLink> */
type Link = Omit<ComponentProps<typeof Link>, "children">;
/** <button> */
type _Button = Omit<ComponentProps<"button">, "children">;
type Props = Base & Content & (Link | _Button);
/**
* looks like a button and either goes somewhere (<a>) or does something
* (<button>)
*/
const Button = forwardRef(
(
{ text, icon, design = "normal", tooltip, ...props }: Props,
ref: ForwardedRef<unknown>,
) => {
/** contents of main element */
const children = (
<>
{text}
{icon && cloneElement(icon, { className: "icon" })}
</>
);
/** class name string */
const className = classNames(classes.button, classes[design], {
[classes.square!]: !text && !!icon,
});
/** full element to render */
const element =
"to" in props ? (
<Link
ref={ref as ForwardedRef<HTMLAnchorElement>}
className={className}
{...(props as Link)}
>
{children}
</Link>
) : (
<button
ref={ref as ForwardedRef<HTMLButtonElement>}
className={className}
type="button"
{...(props as _Button)}
>
{children}
</button>
);
/** wrap in tooltip */
return <Tooltip content={tooltip}>{element}</Tooltip>;
},
);
export default Button;LINK
import {
ComponentPropsWithoutRef,
ForwardedRef,
forwardRef,
ReactNode,
} from "react";
import { FaArrowUpRightFromSquare } from "react-icons/fa6";
import { Link as RouterLink } from "react-router-dom";
import classNames from "classnames";
import Tooltip from "@/components/Tooltip";
import classes from "./Link.module.css";
type Props = {
/** url to link to, local or external */
to: string;
/** force-disable arrow icon for external links */
noIcon?: boolean;
/** tooltip content */
tooltip?: ReactNode;
/** link content */
children: ReactNode;
} & ComponentPropsWithoutRef<"a">;
/** link to internal route or external url */
const Link = forwardRef(
(
{ to, children, noIcon, tooltip, ...props }: Props,
ref: ForwardedRef<HTMLAnchorElement>,
) => {
/** whether link is external (some other site) or internal (within router) */
const external = to.startsWith("http");
/** full element to render */
const element = external ? (
<a ref={ref} href={to} target={external ? "_blank" : ""} {...props}>
{children}
{!noIcon && (
<FaArrowUpRightFromSquare
className={classNames(classes.icon, "inline-icon")}
/>
)}
</a>
) : (
<RouterLink ref={ref} to={to} {...props}>
{children}
</RouterLink>
);
return <Tooltip content={tooltip}>{element}</Tooltip>;
},
);
export default Link;In short, I try to render <Button text="Test Text" />, and I end up with the following structure:
If I call reactToText regularly, it returns a blank string, but if I call it like this it works:
const button = <Button text="Test Text" />;
reactToText(button.type.render(button.props));
Perhaps this could be added as a case to support?
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels