Skip to content

Get text from render function? #332

@vincerubinetti

Description

@vincerubinetti

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:

Screenshot 2023-11-22 at 9 17 29 PM

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions