From 7dce43f1797bd44358f66e2646c166bdc8a1afe9 Mon Sep 17 00:00:00 2001 From: im36-123 Date: Tue, 3 Sep 2019 14:20:02 +0900 Subject: [PATCH] feat: add BaseButton component --- src/components/Button/BaseButton.tsx | 127 ++++++++++++++++++++++++ src/components/Button/PrimaryButton.tsx | 110 ++------------------ 2 files changed, 137 insertions(+), 100 deletions(-) create mode 100644 src/components/Button/BaseButton.tsx diff --git a/src/components/Button/BaseButton.tsx b/src/components/Button/BaseButton.tsx new file mode 100644 index 0000000000..5ca5509d7f --- /dev/null +++ b/src/components/Button/BaseButton.tsx @@ -0,0 +1,127 @@ +import * as React from 'react' +import styled, { css } from 'styled-components' + +import { InjectedProps } from '../../hocs/withTheme' + +import { hoverable } from '../../hocs/hoverable' +import { isTouchDevice } from '../../libs/ua' + +type Tag = 'button' | 'a' +type Size = 'default' | 's' + +interface BaseProps { + size?: Size + children?: React.ReactNode + className?: string + prefix?: React.ReactNode + suffix?: React.ReactNode + square?: boolean + wide?: boolean +} + +export const buttonFactory: ( + tag: Tag, +) => React.FC = tag => ({ + size = 'default', + className = '', + square = false, + children = '', + prefix = '', + suffix = '', + theme, + ...props +}) => { + const Tag = hoverable()(Base.withComponent(tag)) + + // prettier-ignore + const classNames = `${size} ${className} ${square ? 'square' : ''} ${prefix ? 'prefix' : ''} ${suffix ? 'suffix' : ''}` + + return ( + + {prefix && {prefix}} + {children} + {suffix && {suffix}} + + ) +} + +const Base: any = styled.div` + ${({ theme }: InjectedProps) => { + const { frame, size, interaction } = theme + + return css` + display: inline-flex; + justify-content: center; + align-items: center; + width: ${({ wide }: any) => (wide ? '100%;' : 'auto')}; + min-width: 2rem; + vertical-align: middle; + border: none; + border-radius: ${frame.border.radius.m}; + color: #fff; + font-family: inherit; + font-weight: bold; + text-align: center; + text-decoration: none; + box-sizing: border-box; + cursor: pointer; + transition: ${isTouchDevice ? 'none' : `all ${interaction.hover.animation}`}; + + &.default { + font-size: ${size.pxToRem(size.font.TALL)}; + height: 40px; + line-height: 40px; + padding: 0 ${size.pxToRem(size.space.XS)}; + } + + &.s { + font-size: ${size.pxToRem(size.font.SHORT)}; + height: 27px; + line-height: 27px; + padding: 0 ${size.pxToRem(size.space.XXS)}; + } + + &.square { + width: 40px; + line-height: 40px; + padding: 0; + + &.s { + width: 27px; + min-width: 27px; + } + } + + &[disabled] { + cursor: not-allowed; + } + + &.suffix { + justify-content: space-between; + } + + &.prefix { + justify-content: left; + } + ` + }} +` + +const Prefix = styled.span` + ${({ theme }: InjectedProps) => { + const { size } = theme + return css` + display: inline-flex; + margin-right: ${size.pxToRem(size.space.XXS)}; + ` + }} +` +const Suffix = styled.span` + ${({ theme }: InjectedProps) => { + const { size } = theme + return css` + display: inline-flex; + margin-left: ${size.pxToRem(size.space.XXS)}; + ` + }} +` diff --git a/src/components/Button/PrimaryButton.tsx b/src/components/Button/PrimaryButton.tsx index c4aaf05daf..31257a978b 100644 --- a/src/components/Button/PrimaryButton.tsx +++ b/src/components/Button/PrimaryButton.tsx @@ -1,12 +1,11 @@ import * as React from 'react' import styled, { css } from 'styled-components' -import { InjectedProps, withTheme } from '../../hocs/withTheme' +import { buttonFactory } from './BaseButton' -import { hoverable } from '../../hocs/hoverable' +import { InjectedProps, withTheme } from '../../hocs/withTheme' import { isTouchDevice } from '../../libs/ua' -type Tag = 'button' | 'a' type Size = 'default' | 's' interface ClickEvent { @@ -34,122 +33,33 @@ interface AnchorProps extends BaseProps { rel?: string } -const buttonFactory: ( - tag: Tag, -) => React.FC = tag => ({ - size = 'default', - className = '', - square = false, - children = '', - prefix = '', - suffix = '', - theme, - ...props -}) => { - const Tag = hoverable()(Base.withComponent(tag)) - - // prettier-ignore - const classNames = `${size} ${className} ${square ? 'square' : ''} ${prefix ? 'prefix' : ''} ${suffix ? 'suffix' : ''}` - - return ( - - {prefix && {prefix}} - {children} - {suffix && {suffix}} - - ) -} - const ButtonComponent: React.FC = buttonFactory('button') const ButtonAnchorComponent: React.FC = buttonFactory('a') -export const PrimaryButton = withTheme(ButtonComponent) -export const PrimaryButtonAnchor = withTheme(ButtonAnchorComponent) - -const Base: any = styled.div` +const injectStyle = ( + component: React.FC | React.FC, +) => styled(component)` ${({ theme }: InjectedProps) => { - const { palette, frame, size, interaction } = theme + const { palette, interaction } = theme return css` - display: inline-flex; - justify-content: center; - align-items: center; - width: ${({ wide }: any) => (wide ? '100%;' : 'auto')}; - min-width: 2rem; - vertical-align: middle; - border: none; - border-radius: ${frame.border.radius.m}; background-color: ${palette.MAIN}; color: #fff; - font-family: inherit; - font-weight: bold; - text-align: center; - text-decoration: none; - box-sizing: border-box; - cursor: pointer; transition: ${isTouchDevice ? 'none' : `all ${interaction.hover.animation}`}; - &.default { - font-size: ${size.pxToRem(size.font.TALL)}; - height: 40px; - line-height: 40px; - padding: 0 ${size.pxToRem(size.space.XS)}; - } - - &.s { - font-size: ${size.pxToRem(size.font.SHORT)}; - height: 27px; - line-height: 27px; - padding: 0 ${size.pxToRem(size.space.XXS)}; - } - &.hover { background-color: ${palette.hoverColor(palette.MAIN)}; } - &.square { - width: 40px; - line-height: 40px; - padding: 0; - - &.s { - width: 27px; - min-width: 27px; - } - } - &[disabled] { background-color: ${palette.disableColor(palette.MAIN)}; color: ${palette.disableColor('#fff')}; - cursor: not-allowed; - } - - &.suffix { - justify-content: space-between; - } - - &.prefix { - justify-content: left; } ` }} ` -const Prefix = styled.span` - ${({ theme }: InjectedProps) => { - const { size } = theme - return css` - display: inline-flex; - margin-right: ${size.pxToRem(size.space.XXS)}; - ` - }} -` -const Suffix = styled.span` - ${({ theme }: InjectedProps) => { - const { size } = theme - return css` - display: inline-flex; - margin-left: ${size.pxToRem(size.space.XXS)}; - ` - }} -` +export const PrimaryButton: React.FC = withTheme(injectStyle(ButtonComponent)) +export const PrimaryButtonAnchor: React.FC = withTheme( + injectStyle(ButtonAnchorComponent), +)