import * as React from 'react'; import classnames from 'classnames'; import styles from './ButtonBase.scss'; import ILocalContainerProps from '../../../../common/structures/ILocalContainerProps'; import { Container } from '../../../modules/Container/Container'; import { FunctionGeneric } from '../../../../common/structures/Generics'; export enum ButtonPropColor { default = 'default', gray = 'gray', green = 'green', orange = 'orange', red = 'red', } export enum ButtonPropPadding { s = 's', m = 'm', l = 'l', none = 'none', } export enum ButtonSvgStyle { fill = 'fill', stroke = 'stroke', background = 'background', none = 'none', } export enum ButtonPropFontSize { xs = 'xs', s = 's', m = 'm', l = 'l', xl = 'xl', xxl = 'xxl', } export enum ButtonPropFontWeight { heavy = 'heavy', medium = 'medium', light = 'light', } export enum ButtonPropForm { fill = 'fill', outline = 'outline', reversed = 'reversed', text = 'text', } enum ButtonPropTextTransform { none = 'none', upper = 'upper', } enum ButtonPropTextDecoration { none = 'none', underline = 'underline', underlineOnHover = 'underlineOnHover', } /** Props common to all button forms */ export interface IButtonCommonProps extends ILocalContainerProps { /** Whether the button is disabled. */ disabled?: boolean; /** Whether the button is active. */ active?: boolean; /** The form name attribute */ name?: string; /** The click handler. */ onClick?: FunctionGeneric; /** The html element tag used for the button. */ tag?: string; /** Props specific to the tag prop tag defined and applied to this component. */ tagProps?: { [prop: string]: any }; /** The default behavior of the button. */ type?: 'button' | 'submit' | 'reset'; /** SVG Icon to be placed left of text */ leftIcon?: any; // has to be any since optional /** SVG Icon to be placed right of text */ rightIcon?: any; // has to be any since optional /** Whether the svg is stroke only, fill only, or whether to not modify either */ svgStyle?: ButtonSvgStyle | keyof typeof ButtonSvgStyle; /** Display inline-flex vs flex */ inline?: boolean; /** Stop propagation - prevents button keydown event from bubbling up to wrapping elements with potential listeners */ stopKeyDownPropagation?: boolean; } /** * Props specific to a button form, surfaced via privateOptions. * A button form should be built by specifying these props, and instances * of that form should sitll be able to modify them via privateOptions. */ export interface IButtonBaseProps extends IButtonCommonProps { /** The main color applied to the button. */ color?: ButtonPropColor | keyof typeof ButtonPropColor; /** The styles applied to the button that forms how colors are applied to styles like background, border, color, etc. */ form?: ButtonPropForm | keyof typeof ButtonPropForm; /** The fontSize of padding applied to the button. */ padding?: ButtonPropPadding | keyof typeof ButtonPropPadding; /** The font-fontSize applied to the button. */ fontSize?: ButtonPropFontSize | keyof typeof ButtonPropFontSize; /** The font-weight applied to the button */ fontWeight?: ButtonPropFontWeight | keyof typeof ButtonPropFontWeight; /** The casing applied to the button */ textTransform?: ButtonPropTextTransform | keyof typeof ButtonPropTextTransform; /** The text decoration applied to the button */ textDecoration?: ButtonPropTextDecoration | keyof typeof ButtonPropTextDecoration; } /** * Base button component, other buttons built on this * Note child text will reflect true case by default */ const ButtonBase = (props: IButtonBaseProps) => { const { children, color, container, className, disabled, active, fontSize, form, id, innerRef, name, onClick, padding, fontWeight, style, textTransform, textDecoration, tag, tagProps, inline, leftIcon, rightIcon, svgStyle, stopKeyDownPropagation, ...otherProps } = props; const Tag: any = tag; const LeftIcon: any = leftIcon; const RightIcon: any = rightIcon; const [isActive, setIsActive] = React.useState(active); const handleKeyDown = (e: React.KeyboardEvent) => { if (stopKeyDownPropagation) { e.stopPropagation(); } if (e.key === 'Enter' && !active) { setIsActive(true); } }; const handleKeyUp = (e: React.KeyboardEvent) => { if (e.key === 'Enter' && !active) { setIsActive(false); } }; const onButtonClick = (e: React.MouseEvent) => { if (disabled) { e.preventDefault(); return; } onClick?.(e); } React.useEffect(() => { setIsActive(active); }, [active]); return ( {leftIcon && } {children} {rightIcon && } ); }; ButtonBase.defaultProps = { color: ButtonPropColor.default, disabled: false, fontSize: ButtonPropFontSize.m, form: ButtonPropForm.fill, padding: ButtonPropPadding.m, tag: 'button', fontWeight: ButtonPropFontWeight.heavy, textTransform: ButtonPropTextTransform.none, textDecoration: ButtonPropTextDecoration.none, svgStyle: ButtonSvgStyle.fill, }; export { ButtonBase };