react-sprucebot
Version: 
React components for your Sprucebot Skill 💪🏼
205 lines (183 loc) • 3.94 kB
JavaScript
import React, { Component, Fragment } from 'react'
import styled from 'styled-components'
import PropTypes from 'prop-types'
import Loader from '../Loader/Loader'
import SingletonRouter from 'next/router'
import Link from 'next/link'
const ButtonWrapper = styled.div`
	display: flex;
	width: 50%;
	${props => props.left && `padding-right: 1.125em;`};
	${props => props.right && `padding-left: 1.125em;`};
`
const StyledButton = styled.button`
	${props =>
		props.busy ||
		(props.disabled &&
			`
			pointer-events: none;
			cursor: not-allowed;
		`)};
`
const StyledAnchor = styled.a`
	${props =>
		props.busy ||
		(props.disabled &&
			`
		pointer-events: none;
		cursor: not-allowed;
	`)};
`
// TODO refactor into styled component
export default class Button extends Component {
	constructor(props) {
		super(props)
		this.state = {
			busy: !!props.busy
		}
	}
	componentWillReceiveProps(nextProps) {
		if (typeof nextProps.busy !== 'undefined') {
			this.setState({
				busy: nextProps.busy
			})
		}
	}
	onClick = e => {
		const { busy } = this.state
		const { disabled, onClick, href, target, router } = this.props
		if (busy || disabled) {
			return
		}
		if (onClick) {
			onClick(e)
		} else if (href) {
			this.setState({ busy: true })
		}
	}
	renderView = () => {
		const { busy } = this.state
		const { hideLoader, loaderDark, loaderStyle, children } = this.props
		if (busy && !hideLoader) {
			return (
				<Loader
					dark={loaderDark ? true : false}
					fullWidth={false}
					loaderStyle={loaderStyle}
				/>
			)
		}
		return children
	}
	render() {
		const {
			tag,
			disabled,
			primary,
			secondary,
			alt,
			link,
			caution,
			className,
			children,
			submit,
			remove,
			toggle,
			router,
			loaderDark,
			loaderStyle,
			busy: propBusy,
			hideLoader,
			left,
			right,
			href,
			type,
			...props
		} = this.props
		const { busy } = this.state
		if (primary && secondary) {
			return (
				<button className="btn__primary">
					'primary' and 'secondary' are mutually exclusive.
				</button>
			)
		} else if (primary && alt) {
			return (
				<button className="btn__primary">
					'primary' and 'alt' are mutually exclusive.
				</button>
			)
		}
		let btnClass = primary ? 'btn__primary' : ''
		btnClass += secondary ? 'btn__secondary' : ''
		btnClass += alt && btnClass.length > 0 ? '__alt' : ''
		btnClass += alt && btnClass.length === 0 ? 'btn__alt' : ''
		btnClass += disabled ? ' btn__disabled' : ''
		btnClass += caution ? ' btn__caution' : ''
		btnClass += link ? ' btn__link' : ''
		btnClass += toggle ? 'btn__toggle' : ''
		if (remove) {
			btnClass = 'btn__remove'
		}
		// if this button has a href or is a "remove" button, make it an anchor
		let Tag
		let usingLink = false
		if (href || remove) {
			Tag = SingletonRouter.router ? Link : 'a'
			usingLink = SingletonRouter.router
		} else if (tag === 'button') {
			Tag = StyledButton
		} else {
			Tag = tag
		}
		if (usingLink) {
			return (
				<Link href={href} {...props}>
					<a
						onClick={this.onClick}
						className={`btn ${btnClass} ${className || ''}`}
					>
						<span className="wrapper">{this.renderView()}</span>
					</a>
				</Link>
			)
		}
		return (
			<Tag
				className={`btn ${btnClass} ${className || ''}`}
				onClick={this.onClick}
				disabled={disabled}
				busy={busy}
				href={href}
				{...props}
				type={type}
			>
				<span className="wrapper">{this.renderView()}</span>
			</Tag>
		)
	}
}
Button.propTypes = {
	tag: PropTypes.string,
	primary: PropTypes.bool,
	alt: PropTypes.bool,
	secondary: PropTypes.bool,
	busy: PropTypes.bool,
	href: PropTypes.string,
	remove: PropTypes.bool,
	toggle: PropTypes.bool,
	hideLoader: PropTypes.bool,
	left: PropTypes.bool,
	right: PropTypes.bool,
	type: PropTypes.string
}
Button.defaultProps = {
	tag: 'button',
	primary: false,
	alt: false,
	secondary: false,
	busy: false,
	remove: false,
	toggle: false,
	type: 'button'
}