import Link, { LinkProps } from "next/link"; import React, { useMemo } from "react"; import cls from "./Button.module.scss"; const Button: React.FC = ({ as = "button", iconAfter, icon, appearance = "primary", children, ...props }) => { const Component = as === "button" && !props.href ? "button" : as === "next" ? Link : "a"; const classList: string = useMemo(() => { const list: string[] = [ cls.button, cls[appearance] ]; // We need these classes to differentiate content in CSS if (icon) list.push(cls.iconBefore); if (iconAfter) list.push(cls.iconAfter); if (children) list.push(cls.content); if (props.className) list.push(props.className); return list.join(" "); }, [appearance, children, icon, iconAfter, props.className]); return ( { icon } { children } { iconAfter } ); }; export default Button; // Since we want to render button as both "a" and "button" (depending on the props) we do a little trick here // Shorthand types type HtmlButtonProps = Omit, "disabled">; type HtmlAnchorProps = Omit, "type">; type NextLinkProps = Omit, keyof LinkProps> & LinkProps & { children?: React.ReactNode; } & React.RefAttributes; type ButtonOrAnchorProps = | ({ as?: "a"; href?: string; } & HtmlAnchorProps) // If href is present, it must be an | ({ as?: "button"; href?: undefined; } & HtmlButtonProps) // If href is absent, it is a