All files / button/components button.tsx

100% Statements 6/6
61.29% Branches 19/31
100% Functions 1/1
100% Lines 6/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113                                                                                        2x             2x             2x                                 3x                                     3x               3x                    
import * as React from 'react';
import cx from 'classnames';
 
import { ThemeStyle } from '../../types';
import { IGlyph, Icon } from '../../icon';
 
/**
 * The Button component.
 */
export interface IButtonProps {
  /** Passed down classname. */
  className?: string;
  /** Glyph for svg */
  icon?: IGlyph;
  /** Custom size if needed */
  iconSize?: { height?: number; width?: number };
  /** Space avoiding below */
  includeSpaceBelow?: boolean;
  /** Make it full width */
  isFullWidth?: boolean;
  /** Button is outline themed */
  isOutline?: boolean;
  /** Make the Button small. */
  isSmall?: boolean;
  /** Make the Button rounded. Default is true */
  isRounded?: boolean;
  /** Button has a white outline and text, the background color is dependant on parent */
  isReverse?: boolean;
  /** Text and icon are aligned left */
  isTextAlignedLeft?: boolean;
  /** Make the button disabled */
  disabled?: boolean;
  /** On click action for the button. */
  onClick: () => void;
  /** Content specified as children. */
  children?: React.ReactNode;
  /** Theme style for button colors */
  theme?: ThemeStyle;
  /** Glyph for svg */
  trailingIcon?: IGlyph;
  /** Custom size if needed */
  trailingIconSize?: { height?: number; width?: number };
}
 
const OUTLINE_THEME = {
  [ThemeStyle.black]: '',
  [ThemeStyle.blue]: '',
  [ThemeStyle.white]: 'panda-btn-outline--theme-white',
  [ThemeStyle.red]: '',
};
 
const FILLED_THEME = {
  [ThemeStyle.black]: '',
  [ThemeStyle.blue]: 'panda-btn--filled--theme-blue',
  [ThemeStyle.white]: '',
  [ThemeStyle.red]: '',
};
 
export const Button: React.FC<IButtonProps> = ({
  className,
  children,
  includeSpaceBelow = false,
  isSmall = false,
  isRounded = true,
  isOutline = false,
  isReverse = false,
  icon,
  iconSize,
  isFullWidth = false,
  isTextAlignedLeft = false,
  trailingIcon,
  trailingIconSize,
  theme,
  onClick,
}) => {
  const combinedClass = cx({
    'panda-btn': true,
    'panda-btn--rounded': isRounded,
    'panda-btn--not-rounded': !isRounded,
    'panda-btn--small': isSmall,
    'panda-btn--full-width': isFullWidth,
    'panda-btn--space-below-small': includeSpaceBelow && isSmall,
    'panda-btn--space-below-large': includeSpaceBelow && !isSmall,
    'hover-cursor': true,
    // Normal Button styles
    [FILLED_THEME[theme || ThemeStyle.blue]]: !isOutline && !isReverse,
    // Outline styles
    'panda-btn-outline': isOutline,
    [OUTLINE_THEME[theme || ThemeStyle.white]]: isOutline,
    // Reverse style
    'panda-btn-reverse': isReverse,
    // Custom classname
    [className || '']: true,
  });
  const combinedTextClass = cx({
    'panda-typography--p1': !isSmall,
    'panda-typography--span2': isSmall,
    'panda-btn--text-left': isTextAlignedLeft,
    'space-left-medium': !!icon,
    'space-right-medium': !!trailingIcon,
  });
 
  return (
    <button className={combinedClass} onClick={onClick}>
      {icon && <Icon icon={icon} size={iconSize || { height: isSmall ? 12 : 15 }} />}
      <span className={combinedTextClass}>{children}</span>
      {trailingIcon && (
        <Icon icon={trailingIcon} size={trailingIconSize || { height: isSmall ? 12 : 15 }} />
      )}
    </button>
  );
};