Skip to content

Instantly share code, notes, and snippets.

@lifeiscontent
Last active July 26, 2022 17:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lifeiscontent/84bbce3bd14d04b5140382378dafc35e to your computer and use it in GitHub Desktop.
Save lifeiscontent/84bbce3bd14d04b5140382378dafc35e to your computer and use it in GitHub Desktop.
import React from "react";
import clsx from "clsx";
import * as Polymorphic from "./Polymorphic";
export type ButtonProps = {
Disabled?: boolean;
Variant: "primary" | "secondary" | "tertiary" | "success" | "destructive";
Width: "fill" | "hug";
IconLeft?: React.ReactNode;
IconRight?: React.ReactNode;
children?: React.ReactNode;
};
type ButtonTag = "button" | "a" | React.ForwardRefExoticComponent<any>;
const ButtonDefaultTag = "button";
export const Button = Polymorphic.forwardRef<
typeof ButtonDefaultTag,
ButtonProps,
ButtonTag
>(function Button(
{
className: _,
style: __,
Disabled,
Width,
Tag,
Variant,
IconLeft,
IconRight,
children,
...hostProps
},
ref
) {
const Component = Tag ?? ButtonDefaultTag;
return (
<Component
ref={ref}
className={clsx("Button", {
"Button-width--fill": Width === "fill",
"Button-width--hug": Width === "hug",
"Button-variant--primary": Variant === "primary",
"Button-variant--success": Variant === "success",
"Button-variant--destructive": Variant === "destructive",
"Button-variant--secondary": Variant === "secondary",
"Button-variant--teriary": Variant === "tertiary",
"Button-disabled": Disabled,
})}
{...hostProps}
>
{IconLeft && <span className="ButtonIcon-left">{IconLeft}</span>}
{children && <span className="ButtonText">{children}</span>}
{IconRight && <span className="ButtonIcon-right">{IconRight}</span>}
</Component>
);
});
import * as React from "react";
// Props for Polymorphic Tag property
export type TagProps<TTag extends React.ElementType> = {
Tag?: TTag;
};
// React.ComponentProps but for use with Polymorphic `Tag` property
export type ComponentPropsWithoutRef<
TTag extends React.ElementType,
TProps
> = TProps &
TagProps<TTag> &
Omit<React.ComponentPropsWithoutRef<TTag>, keyof (TProps & TagProps<TTag>)>;
// React.ComponentPropsWithRef but for use with Polymorphic `Tag` property
export type ComponentPropsWithRef<
TTag extends React.ElementType,
TProps
> = ComponentPropsWithoutRef<TTag, TProps> & {
ref?: ForwardedRef<TTag>;
};
// Helper function to lookup the ref type of a component
export type ForwardedRef<TTag extends React.ElementType> = React.ForwardedRef<
React.ElementRef<TTag>
>;
export const forwardRef = React.forwardRef as <
TDefaultTag extends TElementType,
TProps,
TElementType extends React.ElementType = React.ElementType
>(
renderFn: (
props: ComponentPropsWithoutRef<TElementType, TProps>,
ref: ForwardedRef<TElementType>
) => React.ReactElement | null
) => <TTag extends TElementType = TDefaultTag>(
props: ComponentPropsWithRef<TTag, TProps>
) => React.ReactElement | null;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment