import React from "react"; import classnames from "classnames"; import Spinner from "components/Spinner"; const baseClass = "button"; export type ButtonVariant = | "default" | "alert" | "pill" | "grey-pill" | "link" // Looks like CustomLink with animated underline on hover | "brand-inverse-icon" // Green icon with text, no underline on hover | "text-icon" | "icon" // Buttons without text | "inverse" | "inverse-alert" | "unstyled" // Avoid as much as possible (used in registration breadcrumbs, 404/500, an old button dropdown) | "unstyled-modal-query" | "oversized"; export interface IButtonProps { autofocus?: boolean; children: React.ReactNode; className?: string; disabled?: boolean; tabIndex?: number; type?: "button" | "submit" | "reset"; /** Text shown on tooltip when hovering over a button */ title?: string; /** Default: "default" */ variant?: ButtonVariant; onClick?: | ((value?: any) => void) | (( evt: | React.MouseEvent | React.KeyboardEvent ) => void); isLoading?: boolean; customOnKeyDown?: (e: React.KeyboardEvent) => void; /** Required for buttons that contain SVG icons using`stroke` instead of`fill` for proper hover styling */ iconStroke?: boolean; ariaHasPopup?: | boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog"; ariaExpanded?: boolean; ariaLabel?: string; /** Small: 1/2 the padding, Wide: 200px */ size?: "small" | "wide" | "default"; } // eslint-disable-next-line @typescript-eslint/no-empty-interface interface IButtonState {} interface Inputs { button?: HTMLButtonElement; } class Button extends React.Component { static defaultProps = { type: "button", variant: "default", }; componentDidMount(): void { const { autofocus } = this.props; const { inputs: { button }, } = this; if (autofocus && button) { button.focus(); } } setRef = (button: HTMLButtonElement): boolean => { this.inputs.button = button; return false; }; inputs: Inputs = {}; handleClick = (evt: React.MouseEvent): void => { const { disabled, onClick } = this.props; if (disabled) { return; } if (onClick) { onClick(evt); } }; handleKeyDown = (evt: React.KeyboardEvent): void => { const { disabled, onClick } = this.props; if (disabled || evt.key !== "Enter") { return; } if (onClick) { onClick(evt as any); } }; render(): JSX.Element { const { handleClick, handleKeyDown, setRef } = this; const { children, className, disabled, tabIndex, type, title, variant, isLoading, customOnKeyDown, iconStroke, ariaHasPopup, ariaExpanded, ariaLabel, size, } = this.props; const fullClassName = classnames( baseClass, `${baseClass}--${variant}`, className, { [`${baseClass}--${variant}__small`]: size === "small", [`${baseClass}__wide`]: size === "wide", [`${baseClass}--disabled`]: disabled, [`${baseClass}--icon-stroke`]: iconStroke, } ); const onWhite = variant === "link" || variant === "inverse" || variant === "brand-inverse-icon" || variant === "text-icon" || variant === "pill" || variant === "grey-pill"; return ( ); } } export default Button;