Skip to content

Instantly share code, notes, and snippets.

@smashercosmo
Created July 1, 2020 14:26
Show Gist options
  • Save smashercosmo/e669270b61e5b90c4d1fa063b51f1f92 to your computer and use it in GitHub Desktop.
Save smashercosmo/e669270b61e5b90c4d1fa063b51f1f92 to your computer and use it in GitHub Desktop.
import cx from 'classnames'
import React from 'react'
import { Link as ReactRouterLink } from 'react-router-dom'
import type { LinkProps as ReactRouterLinkProps } from 'react-router-dom'
import { ButtonSpinner } from '../ButtonSpinner/ButtonSpinner'
import styles from './Button.css'
type CommonProps = {
theme: 'primary' | 'secondary'
mode: 'light' | 'dark'
block?: boolean
full?: boolean
pending?: boolean
disabled?: boolean
hideContentIfPending?: boolean
}
type ButtonComponentProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
type?: 'button' | 'submit' | 'reset'
} & CommonProps
type AnchorComponentProps = React.AnchorHTMLAttributes<HTMLAnchorElement> &
CommonProps
type LinkComponentProps = ReactRouterLinkProps & CommonProps
type ButtonProps =
| ButtonComponentProps
| AnchorComponentProps
| LinkComponentProps
function isPropsForLinkComponent(
props: ButtonProps,
): props is LinkComponentProps {
return 'to' in props && typeof props.to === 'string'
}
function isPropsForAnchorComponent(
props: ButtonProps,
): props is AnchorComponentProps {
return 'href' in props && typeof props.href === 'string'
}
function Button(props: ButtonProps) {
const {
block,
full,
disabled,
pending,
hideContentIfPending,
theme,
mode,
children,
} = props
const rootClasses = cx(styles.root, {
[styles.block]: block,
[styles.full]: full,
})
const innerClasses = cx(styles.inner, {
[styles[theme]]: theme,
[styles[mode]]: mode,
[styles.disabled]: theme && (disabled || pending),
})
const hideChildren = pending && hideContentIfPending
const content = (
<div className={innerClasses} tabIndex={-1}>
{pending && <ButtonSpinner fill={mode === 'light' ? 'black' : 'white'} />}
{!hideChildren && children}
</div>
)
if (isPropsForLinkComponent(props)) {
const {
block: _block,
full: _full,
pending: _pending,
hideContentIfPending: _hideContentIfPending,
theme: _theme,
mode: _mode,
...linkProps
} = props
return (
<ReactRouterLink {...linkProps} className={rootClasses} tabIndex={0}>
{content}
</ReactRouterLink>
)
}
if (isPropsForAnchorComponent(props)) {
const {
block: _block,
full: _full,
pending: _pending,
hideContentIfPending: _hideContentIfPending,
theme: _theme,
mode: _mode,
...anchorProps
} = props
return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
<a {...anchorProps} className={rootClasses} tabIndex={0}>
{content}
</a>
)
}
const {
block: _block,
full: _full,
pending: _pending,
hideContentIfPending: _hideContentIfPending,
theme: _theme,
mode: _mode,
type = 'button',
...buttonProps
} = props
return (
<button
{...buttonProps}
/* eslint-disable-next-line react/button-has-type */
type={type}
disabled={disabled || pending}
className={rootClasses}
tabIndex={0}>
{content}
</button>
)
}
export { Button }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment