import React, { useRef, useState, MouseEvent, useMemo } from 'react' import withDefaults from '../utils/with-defaults' import useTheme from '../styles/use-theme' import { ButtonTypes, NormalSizes } from '../utils/prop-types' import ButtonDrip from './button.drip' import ButtonLoading from '../loading' import ButtonIcon from './button-icon' import { getButtonColors, getButtonCursor, getButtonHoverColors, getButtonSize } from './styles' interface Props { type?: ButtonTypes size?: NormalSizes ghost?: boolean loading?: boolean shadow?: boolean auto?: boolean effect?: boolean disabled?: boolean icon?: React.ReactNode iconRight?: React.ReactNode onClick?: React.MouseEventHandler className?: string } const defaultProps = { type: 'default' as ButtonTypes, size: 'medium' as NormalSizes, ghost: false, loading: false, shadow: false, auto: false, effect: true, disabled: false, className: '', } type NativeAttrs = Omit, keyof Props> export type ButtonProps = Props & typeof defaultProps & NativeAttrs const Button: React.FC> = ({ children, disabled, type, loading, shadow, ghost, effect, onClick, auto, size, icon, iconRight, className, ...props }) => { const theme = useTheme() const buttonRef = useRef(null) const [dripShow, setDripShow] = useState(false) const [dripX, setDripX] = useState(0) const [dripY, setDripY] = useState(0) const { bg, border, color } = useMemo(() => getButtonColors(theme, type, disabled, ghost), [ theme, type, disabled, ghost, ]) const hover = useMemo(() => getButtonHoverColors(theme, type, disabled, loading, shadow, ghost), [ theme, type, disabled, loading, shadow, ghost, ]) const { cursor, events } = useMemo(() => getButtonCursor(disabled, loading), [disabled, loading]) const { height, minWidth, padding, width, fontSize } = useMemo(() => getButtonSize(size, auto), [ size, auto, ]) /* istanbul ignore next */ const dripCompletedHandle = () => { setDripShow(false) setDripX(0) setDripY(0) } const clickHandler = (event: MouseEvent) => { if (disabled || loading) return const showDrip = !shadow && !ghost && effect /* istanbul ignore next */ if (showDrip && buttonRef.current) { const rect = buttonRef.current.getBoundingClientRect() setDripShow(true) setDripX(event.clientX - rect.left) setDripY(event.clientY - rect.top) } onClick && onClick(event) } const childrenWithIcon = useMemo(() => { const hasIcon = icon || iconRight const isRight = Boolean(iconRight) const paddingForAutoMode = auto || size === 'mini' ? `calc(var(--zeit-ui-button-height) / 2 + var(--zeit-ui-button-padding) * .5)` : 0 if (!hasIcon) return
{children}
return ( <> {hasIcon}
{children}
) }, [children, icon, auto, size]) return ( ) } const MemoButton = React.memo>(Button) export default withDefaults(MemoButton, defaultProps)