import styled, { css, FlattenInterpolation, ThemeProps, DefaultTheme, } from 'styled-components'; type Intent = 'primary' | 'danger' | 'success' | 'warning' | 'error'; type ThemeVariant = | 'basic' | 'basic-transparent' | 'filled-primary' | 'filled-danger' | 'filled-success' | 'filled-warning' | 'filled-error' | 'outlined-primary' | 'outlined-danger' | 'outlined-success' | 'outlined-warning' | 'outlined-error' | 'text-primary' | 'text-danger' | 'text-success' | 'text-warning' | 'text-error' | 'filled-reversed-primary' | 'filled-reversed-danger' | 'filled-reversed-success' | 'filled-reversed-warning' | 'filled-reversed-error'; const HOVER_COLORS = { primary: 'hoverPrimary', danger: 'hoverDanger', success: 'hoverSuccess', warning: 'hoverWarning', error: 'hoverError', } as const; const ACTIVE_COLORS = { primary: 'activePrimary', danger: 'activeDanger', success: 'activeSuccess', warning: 'activeWarning', error: 'activeError', } as const; const genFilledStyles = ( intent: Intent ): FlattenInterpolation> => css` border: none; color: white; background: ${({ theme }) => theme.colors.button[intent]}; &:hover, &:focus { background: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]}; } &:active { background: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]}; } &:disabled { background: ${({ theme }) => theme.colors.button.disabledBackground}; color: ${({ theme }) => theme.colors.button.disabledText}; cursor: not-allowed; } `; const genOutlinedStyles = ( intent: Intent ): FlattenInterpolation> => css` color: ${({ theme }) => theme.colors.button[intent]}; border-color: ${({ theme }) => theme.colors.button[intent]}; background: transparent; &:hover, &:focus { color: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]}; border-color: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]}; } &:active { color: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]}; border-color: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]}; } &:disabled { color: ${({ theme }) => theme.colors.button.disabledLightText}; border-color: ${({ theme }) => theme.colors.button.defaultBorder}; cursor: not-allowed; } `; const genTextStyles = ( intent: Intent ): FlattenInterpolation> => css` color: ${({ theme }) => theme.colors.button[intent]}; border: none; background: transparent; min-width: unset; &:hover, &:focus { color: ${({ theme }) => theme.colors.button[HOVER_COLORS[intent]]}; } &:active { color: ${({ theme }) => theme.colors.button[ACTIVE_COLORS[intent]]}; } &:disabled { color: ${({ theme }) => theme.colors.button.disabledText}; cursor: not-allowed; } `; const genFilledReversedStyles = ( intent: Intent ): FlattenInterpolation> => css` border: none; background: white; color: ${({ theme }) => theme.colors.button[intent]}; &:hover { opacity: 0.4; } &:focus, &:active { opacity: 0.7; } &:disabled { opacity: 1; background: ${({ theme }) => theme.colors.button.disabledBackground}; color: ${({ theme }) => theme.colors.button.disabledText}; cursor: not-allowed; } `; const genLoadingStyles = (variant: ThemeVariant) => { switch (variant) { case 'basic': return css` color: ${({ theme }) => theme.colors.button.activePrimary}; border-color: ${({ theme }) => theme.colors.button.activePrimary}; `; case 'basic-transparent': case 'filled-reversed-primary': case 'filled-reversed-success': case 'filled-reversed-warning': case 'filled-reversed-danger': case 'filled-reversed-error': return css` opacity: 0.7; `; case 'filled-primary': return css` background: ${({ theme }) => theme.colors.button.loadingPrimary}; `; case 'filled-success': return css` background: ${({ theme }) => theme.colors.button.loadingSuccess}; `; case 'filled-warning': return css` background: ${({ theme }) => theme.colors.button.loadingWarning}; `; case 'filled-danger': return css` background: ${({ theme }) => theme.colors.button.loadingDanger}; `; case 'filled-error': return css` background: ${({ theme }) => theme.colors.button.loadingError}; `; case 'outlined-primary': return css` color: ${({ theme }) => theme.colors.button.loadingPrimary}; border-color: ${({ theme }) => theme.colors.button.loadingPrimary}; `; case 'outlined-success': return css` color: ${({ theme }) => theme.colors.button.loadingSuccess}; border-color: ${({ theme }) => theme.colors.button.loadingSuccess}; `; case 'outlined-warning': return css` color: ${({ theme }) => theme.colors.button.loadingWarning}; border-color: ${({ theme }) => theme.colors.button.loadingWarning}; `; case 'outlined-danger': return css` color: ${({ theme }) => theme.colors.button.loadingDanger}; border-color: ${({ theme }) => theme.colors.button.loadingDanger}; `; case 'outlined-error': return css` color: ${({ theme }) => theme.colors.button.loadingError}; border-color: ${({ theme }) => theme.colors.button.loadingError}; `; case 'text-primary': return css` color: ${({ theme }) => theme.colors.button.loadingPrimary}; border-color: ${({ theme }) => theme.colors.button.loadingPrimary}; `; case 'text-success': return css` color: ${({ theme }) => theme.colors.button.loadingSuccess}; border-color: ${({ theme }) => theme.colors.button.loadingSuccess}; `; case 'text-warning': return css` color: ${({ theme }) => theme.colors.button.loadingWarning}; border-color: ${({ theme }) => theme.colors.button.loadingWarning}; `; case 'text-danger': return css` color: ${({ theme }) => theme.colors.button.loadingDanger}; border-color: ${({ theme }) => theme.colors.button.loadingDanger}; `; case 'text-error': return css` color: ${({ theme }) => theme.colors.button.loadingError}; border-color: ${({ theme }) => theme.colors.button.loadingError}; `; } }; const StyledButton = styled('button').withConfig({ shouldForwardProp: (prop, _defaultValidatorFn) => !['loading', 'themeSize', 'themeVariant'].includes(prop), })<{ loading?: boolean; themeSize: 'small' | 'medium' | 'large'; themeVariant: ThemeVariant; }>` box-sizing: border-box; white-space: nowrap; line-height: 100%; border-style: solid; border-width: ${({ theme }) => theme.borderWidths.button.default}; font-weight: ${({ theme }) => theme.fontWeights.button.text}; margin: 0; cursor: pointer; &:focus { outline: none; } ${({ themeSize, theme }) => { switch (themeSize) { case 'small': return css` height: ${theme.sizes.button.small}; padding: ${theme.space.button.smallPadding}; font-size: ${theme.fontSizes.button.small}; border-radius: ${theme.radii.button.small}; min-width: ${theme.sizes.button.smallMinWidth}; `; case 'medium': return css` height: ${theme.sizes.button.medium}; padding: ${theme.space.button.mediumPadding}; font-size: ${theme.fontSizes.button.medium}; border-radius: ${theme.radii.button.medium}; min-width: ${theme.sizes.button.mediumMinWidth}; `; case 'large': return css` height: ${theme.sizes.button.large}; padding: ${theme.space.button.largePadding}; font-size: ${theme.fontSizes.button.large}; border-radius: ${theme.radii.button.large}; min-width: ${theme.sizes.button.largeMinWidth}; `; } }}; ${({ themeVariant, theme }) => { switch (themeVariant) { case 'basic': return css` color: ${theme.colors.button.defaultText}; border-color: ${theme.colors.button.defaultBorder}; background: ${theme.colors.button.defaultLightBackground}; &:hover, &:focus { color: ${theme.colors.button.hoverPrimary}; border-color: ${theme.colors.button.hoverPrimary}; } &:active { color: ${theme.colors.button.activePrimary}; border-color: ${theme.colors.button.activePrimary}; } &:disabled { background: ${theme.colors.button.defaultBackground}; color: ${theme.colors.button.disabledText}; border-color: ${theme.colors.button.defaultBorder}; cursor: not-allowed; } `; case 'basic-transparent': return css` color: ${theme.colors.button.basicTransparent}; border-color: ${theme.colors.button.basicTransparent}; background: transparent; &:hover { opacity: 0.4; } &:focus, &:active { opacity: 0.7; } &:disabled { opacity: 1; color: ${theme.colors.button.disabledLightText}; border-color: ${theme.colors.button.defaultBorder}; cursor: not-allowed; } `; case 'filled-primary': return genFilledStyles('primary'); case 'filled-danger': return genFilledStyles('danger'); case 'filled-success': return genFilledStyles('success'); case 'filled-warning': return genFilledStyles('warning'); case 'filled-error': return genFilledStyles('error'); case 'outlined-primary': return genOutlinedStyles('primary'); case 'outlined-danger': return genOutlinedStyles('danger'); case 'outlined-success': return genOutlinedStyles('success'); case 'outlined-warning': return genOutlinedStyles('warning'); case 'outlined-error': return genOutlinedStyles('error'); case 'text-primary': return genTextStyles('primary'); case 'text-danger': return genTextStyles('danger'); case 'text-success': return genTextStyles('success'); case 'text-warning': return genTextStyles('warning'); case 'text-error': return genTextStyles('error'); case 'filled-reversed-primary': return genFilledReversedStyles('primary'); case 'filled-reversed-danger': return genFilledReversedStyles('danger'); case 'filled-reversed-success': return genFilledReversedStyles('success'); case 'filled-reversed-warning': return genFilledReversedStyles('warning'); case 'filled-reversed-error': return genFilledReversedStyles('error'); } }}; ${({ loading, themeVariant }) => loading === true ? css` pointer-events: none; ${genLoadingStyles(themeVariant)} ` : ''}; `; const IconWrapper = styled.span<{ themePosition: 'left' | 'right' }>` margin: 0; padding: 0; > * { vertical-align: top; } ${({ themePosition, theme }) => { switch (themePosition) { case 'left': return css` padding-right: ${theme.space.button.iconPadding}; `; case 'right': return css` padding-left: ${theme.space.button.iconPadding}; `; } }}; `; const StyledIconButton = styled.button<{ themeSize: 'small' | 'medium' | 'large'; }>` display: inline-flex; margin: 0; padding: 0; border: none; background: transparent; cursor: pointer; color: inherit; &:focus, &:active { outline: none; } ${({ themeSize, theme }) => { switch (themeSize) { case 'small': return css` font-size: ${theme.fontSizes.button.small}; `; case 'medium': return css` font-size: ${theme.fontSizes.button.medium}; `; case 'large': return css` font-size: ${theme.fontSizes.button.large}; `; } }}; `; export { IconWrapper, StyledButton, StyledIconButton, Intent, ThemeVariant };