UNPKG

@shopify/polaris

Version:

Shopify’s product component library

61 lines (60 loc) 3.75 kB
import React from 'react'; import { CaretDownMinor } from '@shopify/polaris-icons'; import { classNames, variationName } from '../../utilities/css'; import { handleMouseUpByBlurring } from '../../utilities/focus'; import { useI18n } from '../../utilities/i18n'; import { UnstyledLink } from '../UnstyledLink'; import { Icon } from '../Icon'; import { Spinner } from '../Spinner'; import styles from './Button.scss'; const DEFAULT_SIZE = 'medium'; export function Button({ id, url, disabled, loading, children, accessibilityLabel, ariaControls, ariaExpanded, ariaPressed, onClick, onFocus, onBlur, onKeyDown, onKeyPress, onKeyUp, external, download, icon, primary, outline, destructive, disclosure, plain, monochrome, submit, size = DEFAULT_SIZE, textAlign, fullWidth, }) { const i18n = useI18n(); const isDisabled = disabled || loading; const className = classNames(styles.Button, primary && styles.primary, outline && styles.outline, destructive && styles.destructive, isDisabled && styles.disabled, loading && styles.loading, plain && styles.plain, monochrome && styles.monochrome, size && size !== DEFAULT_SIZE && styles[variationName('size', size)], textAlign && styles[variationName('textAlign', textAlign)], fullWidth && styles.fullWidth, icon && children == null && styles.iconOnly); const disclosureIconMarkup = disclosure ? (<IconWrapper> <Icon source={loading ? 'placeholder' : CaretDownMinor}/> </IconWrapper>) : null; let iconMarkup; if (icon) { const iconInner = isIconSource(icon) ? (<Icon source={loading ? 'placeholder' : icon}/>) : (icon); iconMarkup = <IconWrapper>{iconInner}</IconWrapper>; } const childMarkup = children ? (<span className={styles.Text}>{children}</span>) : null; const spinnerColor = primary || destructive ? 'white' : 'inkLightest'; const spinnerSVGMarkup = loading ? (<span className={styles.Spinner}> <Spinner size="small" color={spinnerColor} accessibilityLabel={i18n.translate('Polaris.Button.spinnerAccessibilityLabel')}/> </span>) : null; const content = iconMarkup || disclosureIconMarkup ? (<span className={styles.Content}> {spinnerSVGMarkup} {iconMarkup} {childMarkup} {disclosureIconMarkup} </span>) : (<span className={styles.Content}> {spinnerSVGMarkup} {childMarkup} </span>); const type = submit ? 'submit' : 'button'; if (url) { return isDisabled ? ( // Render an `<a>` so toggling disabled/enabled state changes only the // `href` attribute instead of replacing the whole element. // eslint-disable-next-line jsx-a11y/anchor-is-valid <a id={id} className={className} aria-label={accessibilityLabel}> {content} </a>) : (<UnstyledLink id={id} url={url} external={external} download={download} onClick={onClick} onFocus={onFocus} onBlur={onBlur} onMouseUp={handleMouseUpByBlurring} className={className} aria-label={accessibilityLabel}> {content} </UnstyledLink>); } return (<button id={id} type={type} onClick={onClick} onFocus={onFocus} onBlur={onBlur} onKeyDown={onKeyDown} onKeyUp={onKeyUp} onKeyPress={onKeyPress} onMouseUp={handleMouseUpByBlurring} className={className} disabled={isDisabled} aria-label={accessibilityLabel} aria-controls={ariaControls} aria-expanded={ariaExpanded} aria-pressed={ariaPressed} role={loading ? 'alert' : undefined} aria-busy={loading ? true : undefined}> {content} </button>); } export function IconWrapper({ children }) { return <span className={styles.Icon}>{children}</span>; } function isIconSource(x) { return (typeof x === 'string' || (typeof x === 'object' && x.body) || typeof x === 'function'); }