UNPKG

@kiwicom/orbit-components

Version:

<div align="center"> <a href="https://orbit.kiwi" target="_blank"> <img alt="orbit-components" src="https://orbit.kiwi/wp-content/uploads/2018/08/orbit-components.png" srcset="https://orbit.kiwi/wp-content/uploads/2018/08/orbit-components@2x.png 2x"

433 lines (412 loc) 17.4 kB
// @flow import * as React from "react"; import styled from "styled-components"; import defaultTokens from "../defaultTokens"; import { ICON_SIZES } from "../Icon/consts"; import { TYPE_OPTIONS, SIZE_OPTIONS, TOKENS } from "./consts"; import Loading, { StyledSpinner } from "../Loading"; import { getSize } from "../Icon"; import type { Props } from "./index"; const getSizeToken = name => ({ theme, size }) => { const tokens = { [TOKENS.heightButton]: { [SIZE_OPTIONS.LARGE]: theme.orbit.heightButtonLarge, [SIZE_OPTIONS.NORMAL]: theme.orbit.heightButtonNormal, [SIZE_OPTIONS.SMALL]: theme.orbit.heightButtonSmall, }, [TOKENS.loadingWidth]: { [SIZE_OPTIONS.LARGE]: theme.orbit.widthIconMedium, [SIZE_OPTIONS.NORMAL]: theme.orbit.widthIconMedium, [SIZE_OPTIONS.SMALL]: theme.orbit.widthIconSmall, }, [TOKENS.loadingHeight]: { [SIZE_OPTIONS.LARGE]: theme.orbit.heightIconMedium, [SIZE_OPTIONS.NORMAL]: theme.orbit.heightIconMedium, [SIZE_OPTIONS.SMALL]: theme.orbit.heightIconSmall, }, [TOKENS.fontSizeButton]: { [SIZE_OPTIONS.LARGE]: theme.orbit.fontSizeButtonLarge, [SIZE_OPTIONS.NORMAL]: theme.orbit.fontSizeButtonNormal, [SIZE_OPTIONS.SMALL]: theme.orbit.fontSizeButtonSmall, }, [TOKENS.paddingButton]: { [SIZE_OPTIONS.LARGE]: theme.orbit.paddingButtonLarge, [SIZE_OPTIONS.NORMAL]: theme.orbit.paddingButtonNormal, [SIZE_OPTIONS.SMALL]: theme.orbit.paddingButtonSmall, }, [TOKENS.paddingButtonWithIcon]: { [SIZE_OPTIONS.LARGE]: theme.orbit.paddingButtonLargeWithIcon, [SIZE_OPTIONS.NORMAL]: theme.orbit.paddingButtonNormalWithIcon, [SIZE_OPTIONS.SMALL]: theme.orbit.paddingButtonSmallWithIcon, }, [TOKENS.marginRightIcon]: { [SIZE_OPTIONS.LARGE]: theme.orbit.marginButtonIconLarge, [SIZE_OPTIONS.NORMAL]: theme.orbit.marginButtonIconNormal, [SIZE_OPTIONS.SMALL]: theme.orbit.marginButtonIconSmall, }, }; return tokens[name][size]; }; const getTypeToken = name => ({ theme, type }) => { const tokens = { [TOKENS.backgroundButton]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.backgroundButtonPrimary, [TYPE_OPTIONS.SECONDARY]: theme.orbit.backgroundButtonSecondary, [TYPE_OPTIONS.INFO]: theme.orbit.backgroundButtonInfo, [TYPE_OPTIONS.SUCCESS]: theme.orbit.backgroundButtonSuccess, [TYPE_OPTIONS.WARNING]: theme.orbit.backgroundButtonWarning, [TYPE_OPTIONS.CRITICAL]: theme.orbit.backgroundButtonCritical, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.backgroundButtonFacebook, [TYPE_OPTIONS.GOOGLE]: theme.orbit.backgroundButtonGoogle, }, [TOKENS.backgroundButtonHover]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.backgroundButtonPrimaryHover, [TYPE_OPTIONS.SECONDARY]: theme.orbit.backgroundButtonSecondaryHover, [TYPE_OPTIONS.INFO]: theme.orbit.backgroundButtonInfoHover, [TYPE_OPTIONS.SUCCESS]: theme.orbit.backgroundButtonSuccessHover, [TYPE_OPTIONS.WARNING]: theme.orbit.backgroundButtonWarningHover, [TYPE_OPTIONS.CRITICAL]: theme.orbit.backgroundButtonCriticalHover, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.backgroundButtonFacebookHover, [TYPE_OPTIONS.GOOGLE]: theme.orbit.backgroundButtonGoogleHover, }, [TOKENS.backgroundButtonActive]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.backgroundButtonPrimaryActive, [TYPE_OPTIONS.SECONDARY]: theme.orbit.backgroundButtonSecondaryActive, [TYPE_OPTIONS.INFO]: theme.orbit.backgroundButtonInfoActive, [TYPE_OPTIONS.SUCCESS]: theme.orbit.backgroundButtonSuccessActive, [TYPE_OPTIONS.WARNING]: theme.orbit.backgroundButtonWarningActive, [TYPE_OPTIONS.CRITICAL]: theme.orbit.backgroundButtonCriticalActive, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.backgroundButtonFacebookActive, [TYPE_OPTIONS.GOOGLE]: theme.orbit.backgroundButtonGoogleActive, }, [TOKENS.colorTextButton]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.colorTextButtonPrimary, [TYPE_OPTIONS.SECONDARY]: theme.orbit.colorTextButtonSecondary, [TYPE_OPTIONS.INFO]: theme.orbit.colorTextButtonInfo, [TYPE_OPTIONS.SUCCESS]: theme.orbit.colorTextButtonSuccess, [TYPE_OPTIONS.WARNING]: theme.orbit.colorTextButtonWarning, [TYPE_OPTIONS.CRITICAL]: theme.orbit.colorTextButtonCritical, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.colorTextButtonFacebook, [TYPE_OPTIONS.GOOGLE]: theme.orbit.colorTextButtonGoogle, }, [TOKENS.colorTextButtonBordered]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.colorTextButtonPrimaryBordered, [TYPE_OPTIONS.SECONDARY]: theme.orbit.colorTextButtonSecondaryBordered, [TYPE_OPTIONS.INFO]: theme.orbit.colorTextButtonInfoBordered, [TYPE_OPTIONS.SUCCESS]: theme.orbit.colorTextButtonSuccessBordered, [TYPE_OPTIONS.WARNING]: theme.orbit.colorTextButtonWarningBordered, [TYPE_OPTIONS.CRITICAL]: theme.orbit.colorTextButtonCriticalBordered, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.colorTextButtonFacebookBordered, [TYPE_OPTIONS.GOOGLE]: theme.orbit.colorTextButtonGoogleBordered, }, [TOKENS.colorTextButtonHover]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.colorTextButtonPrimaryHover, [TYPE_OPTIONS.SECONDARY]: theme.orbit.colorTextButtonSecondaryHover, [TYPE_OPTIONS.INFO]: theme.orbit.colorTextButtonInfoHover, [TYPE_OPTIONS.SUCCESS]: theme.orbit.colorTextButtonSuccessHover, [TYPE_OPTIONS.WARNING]: theme.orbit.colorTextButtonWarningHover, [TYPE_OPTIONS.CRITICAL]: theme.orbit.colorTextButtonCriticalHover, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.colorTextButtonFacebookHover, [TYPE_OPTIONS.GOOGLE]: theme.orbit.colorTextButtonGoogleHover, }, [TOKENS.colorTextButtonBorderedHover]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.colorTextButtonPrimaryBorderedHover, [TYPE_OPTIONS.SECONDARY]: theme.orbit.colorTextButtonSecondaryBorderedHover, [TYPE_OPTIONS.INFO]: theme.orbit.colorTextButtonInfoBorderedHover, [TYPE_OPTIONS.SUCCESS]: theme.orbit.colorTextButtonSuccessBorderedHover, [TYPE_OPTIONS.WARNING]: theme.orbit.colorTextButtonWarningBorderedHover, [TYPE_OPTIONS.CRITICAL]: theme.orbit.colorTextButtonCriticalBorderedHover, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.colorTextButtonFacebookBorderedHover, [TYPE_OPTIONS.GOOGLE]: theme.orbit.colorTextButtonGoogleBorderedHover, }, [TOKENS.colorTextButtonActive]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.colorTextButtonPrimaryActive, [TYPE_OPTIONS.SECONDARY]: theme.orbit.colorTextButtonSecondaryActive, [TYPE_OPTIONS.INFO]: theme.orbit.colorTextButtonInfoActive, [TYPE_OPTIONS.SUCCESS]: theme.orbit.colorTextButtonSuccessActive, [TYPE_OPTIONS.WARNING]: theme.orbit.colorTextButtonWarningActive, [TYPE_OPTIONS.CRITICAL]: theme.orbit.colorTextButtonCriticalActive, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.colorTextButtonFacebookActive, [TYPE_OPTIONS.GOOGLE]: theme.orbit.colorTextButtonGoogleActive, }, [TOKENS.colorTextButtonBorderedActive]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.colorTextButtonPrimaryBorderedActive, [TYPE_OPTIONS.SECONDARY]: theme.orbit.colorTextButtonSecondaryBorderedActive, [TYPE_OPTIONS.INFO]: theme.orbit.colorTextButtonInfoBorderedActive, [TYPE_OPTIONS.SUCCESS]: theme.orbit.colorTextButtonSuccessBorderedActive, [TYPE_OPTIONS.WARNING]: theme.orbit.colorTextButtonWarningBorderedActive, [TYPE_OPTIONS.CRITICAL]: theme.orbit.colorTextButtonCriticalBorderedActive, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.colorTextButtonFacebookBorderedActive, [TYPE_OPTIONS.GOOGLE]: theme.orbit.colorTextButtonGoogleBorderedActive, }, [TOKENS.borderColorButton]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.borderColorButtonPrimaryBordered, [TYPE_OPTIONS.SECONDARY]: theme.orbit.borderColorButtonSecondaryBordered, [TYPE_OPTIONS.INFO]: theme.orbit.borderColorButtonInfoBordered, [TYPE_OPTIONS.SUCCESS]: theme.orbit.borderColorButtonSuccessBordered, [TYPE_OPTIONS.WARNING]: theme.orbit.borderColorButtonWarningBordered, [TYPE_OPTIONS.CRITICAL]: theme.orbit.borderColorButtonCriticalBordered, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.borderColorButtonFacebookBordered, [TYPE_OPTIONS.GOOGLE]: theme.orbit.borderColorButtonGoogleBordered, }, [TOKENS.borderColorButtonHover]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.borderColorButtonPrimaryBorderedHover, [TYPE_OPTIONS.SECONDARY]: theme.orbit.borderColorButtonSecondaryBorderedHover, [TYPE_OPTIONS.INFO]: theme.orbit.borderColorButtonInfoBorderedHover, [TYPE_OPTIONS.SUCCESS]: theme.orbit.borderColorButtonSuccessBorderedHover, [TYPE_OPTIONS.WARNING]: theme.orbit.borderColorButtonWarningBorderedHover, [TYPE_OPTIONS.CRITICAL]: theme.orbit.borderColorButtonCriticalBorderedHover, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.borderColorButtonFacebookBorderedHover, [TYPE_OPTIONS.GOOGLE]: theme.orbit.borderColorButtonGoogleBorderedHover, }, [TOKENS.borderColorButtonActive]: { [TYPE_OPTIONS.PRIMARY]: theme.orbit.borderColorButtonPrimaryBorderedActive, [TYPE_OPTIONS.SECONDARY]: theme.orbit.borderColorButtonSecondaryBorderedActive, [TYPE_OPTIONS.INFO]: theme.orbit.borderColorButtonInfoBorderedActive, [TYPE_OPTIONS.SUCCESS]: theme.orbit.borderColorButtonSuccessBorderedActive, [TYPE_OPTIONS.WARNING]: theme.orbit.borderColorButtonWarningBorderedActive, [TYPE_OPTIONS.CRITICAL]: theme.orbit.borderColorButtonCriticalBorderedActive, [TYPE_OPTIONS.FACEBOOK]: theme.orbit.borderColorButtonFacebookBorderedActive, [TYPE_OPTIONS.GOOGLE]: theme.orbit.borderColorButtonGoogleBorderedActive, }, }; return tokens[name][type]; }; const IconContainer = styled(({ className, children }) => ( <div className={className}>{children}</div> ))` display: flex; flex-direction: row; align-items: center; justify-content: center; margin-right: ${({ onlyIcon }) => (onlyIcon ? "0" : getSizeToken(TOKENS.marginRightIcon))}; color: ${({ bordered }) => bordered ? getTypeToken(TOKENS.colorTextButtonBordered) : getTypeToken(TOKENS.colorTextButton)}; transition: background ${({ theme }) => theme.orbit.durationFast} ease-in-out, box-shadow ${({ theme }) => theme.orbit.durationFast} ease-in-out; > * { width: ${getSize()}; height: ${getSize()}; } `; IconContainer.defaultProps = { theme: defaultTokens, }; const IconContainerRight = styled(IconContainer)` margin-right: 0; margin-left: ${({ onlyIcon }) => (onlyIcon ? "0" : getSizeToken(TOKENS.marginRightIcon))}; `; IconContainerRight.defaultProps = { theme: defaultTokens, }; export const StyledButton = styled( ({ theme, component, circled, external, type, icon, iconLeft, iconRight, sizeIcon, width, bordered, loading, onlyIcon, block, style, dataTest, submit, ...props }) => { const isButtonWithHref = component === "button" && props.href; const Component = isButtonWithHref ? "a" : component; const buttonType = submit ? "submit" : "button"; return ( <Component data-test={dataTest} type={!isButtonWithHref ? buttonType : undefined} {...props}> {props.children} </Component> ); }, )` position: relative; display: ${({ href, component }) => (href || component === "a" ? "inline-flex" : "flex")}; justify-content: center; align-items: center; box-sizing: border-box; appearance: none; text-decoration: none; width: ${({ block, width, onlyIcon }) => block ? "100%" : (width && `${width}px`) || (onlyIcon && getSizeToken(TOKENS.heightButton)) || "auto"}; flex: ${({ block }) => (block ? "1 1 100%" : "0 0 auto")}; height: ${getSizeToken(TOKENS.heightButton)}; background: ${({ bordered, theme }) => bordered ? theme.orbit.backgroundButtonBordered : getTypeToken(TOKENS.backgroundButton)}; color: ${({ bordered }) => bordered ? getTypeToken(TOKENS.colorTextButtonBordered) : getTypeToken(TOKENS.colorTextButton)} !important; border: 0; border-radius: ${({ theme, circled }) => circled ? getSizeToken(TOKENS.heightButton) : theme.orbit.borderRadiusNormal}; padding: 0; padding-right: ${({ onlyIcon, iconRight }) => (onlyIcon && "0") || (iconRight ? getSizeToken(TOKENS.paddingButtonWithIcon) : getSizeToken(TOKENS.paddingButton))}; padding-left: ${({ onlyIcon, icon, iconLeft }) => (onlyIcon && "0") || (iconLeft || icon ? getSizeToken(TOKENS.paddingButtonWithIcon) : getSizeToken(TOKENS.paddingButton))}; font-weight: ${({ theme }) => theme.orbit.fontWeightBold}!important; font-size: ${getSizeToken(TOKENS.fontSizeButton)}; cursor: ${({ disabled }) => (disabled ? "default" : "pointer")}; transition: all 0.15s ease-in-out !important; outline: 0; opacity: ${({ disabled, theme }) => disabled && theme.orbit.opacityButtonDisabled}; pointer-events: ${({ disabled }) => disabled && "none"}; box-shadow: ${({ bordered, theme, type }) => bordered && `inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButton)({ theme, type, })}`}; // Cannot resolve with 0 0 0 1px getTypeToken(TOKENS.borderColorButton) &:hover { background: ${({ disabled, bordered, theme }) => !disabled && (bordered ? theme.orbit.backgroundButtonBorderedHover : getTypeToken(TOKENS.backgroundButtonHover))}; box-shadow: ${({ disabled, bordered, theme, type }) => !disabled && bordered && `inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButtonHover)({ theme, type })}`}; color: ${({ disabled, bordered }) => !disabled && (bordered ? getTypeToken(TOKENS.colorTextButtonBorderedHover) : getTypeToken(TOKENS.colorTextButtonHover))}!important; ${IconContainer} { color: ${({ disabled, bordered }) => !disabled && (bordered ? getTypeToken(TOKENS.colorTextButtonBorderedHover) : getTypeToken(TOKENS.colorTextButtonHover))}; } } &:active { ${({ disabled, theme }) => !disabled && `transform: scale(${theme.orbit.modifierScaleButtonActive})`}; background: ${({ disabled, bordered, theme }) => !disabled && (bordered ? theme.orbit.backgroundButtonBorderedActive : getTypeToken(TOKENS.backgroundButtonActive))}; box-shadow: ${({ disabled, bordered, theme, type }) => !disabled && (bordered && `inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButtonActive)({ theme, type })}`)}; color: ${({ disabled, bordered }) => !disabled && (bordered ? getTypeToken(TOKENS.colorTextButtonBorderedActive) : getTypeToken(TOKENS.colorTextButtonActive))}!important; & ${IconContainer} { color: ${({ disabled, bordered }) => !disabled && (bordered ? getTypeToken(TOKENS.colorTextButtonBorderedActive) : getTypeToken(TOKENS.colorTextButtonActive))}; } } &:enabled:focus { box-shadow: ${({ bordered, theme, type }) => bordered && `inset 0 0 0 1px ${getTypeToken(TOKENS.borderColorButton)({ theme, type })},`} ${({ theme }) => theme.orbit.boxShadowButtonFocus}; } ${StyledSpinner} { width: ${getSizeToken(TOKENS.loadingWidth)}; height: ${getSizeToken(TOKENS.loadingHeight)}; } `; StyledButton.defaultProps = { theme: defaultTokens, }; const StyledButtonContent = styled.div` visibility: ${({ loading }) => loading && "hidden"}; height: 100%; display: flex; justify-content: center; align-items: center; `; StyledButtonContent.defaultProps = { theme: defaultTokens, }; const Button = (props: Props) => { const { component = "button", children, bordered, disabled, href, size = SIZE_OPTIONS.NORMAL, icon, iconRight, external, type = TYPE_OPTIONS.PRIMARY, block, loading = false, width = 0, } = props; const iconLeft = props.iconLeft || icon; const sizeIcon = size === ICON_SIZES.SMALL ? ICON_SIZES.SMALL : ICON_SIZES.MEDIUM; const onlyIcon = iconLeft && !children; const isDisabled = loading || disabled; return ( <StyledButton bordered={bordered} block={block} component={component} disabled={isDisabled} loading={loading} onlyIcon={onlyIcon} size={size} sizeIcon={sizeIcon} target={href && external ? "_blank" : undefined} type={type} width={width} {...props} > {loading && <Loading type="buttonLoader" />} <StyledButtonContent loading={loading}> {iconLeft && ( <IconContainer bordered={bordered} onlyIcon={onlyIcon} size={size} sizeIcon={sizeIcon} type={type} > {iconLeft} </IconContainer> )} {children} {iconRight && ( <IconContainerRight bordered={bordered} onlyIcon={onlyIcon} size={size} sizeIcon={sizeIcon} type={type} > {iconRight} </IconContainerRight> )} </StyledButtonContent> </StyledButton> ); }; export default Button;