2017-05-18 21:21:33 +03:00
|
|
|
import React from 'react';
|
|
|
|
import remcalc from 'remcalc';
|
|
|
|
import PropTypes from 'prop-types';
|
2017-10-12 21:55:05 +03:00
|
|
|
import is, { isOr } from 'styled-is';
|
2017-11-23 14:18:38 +02:00
|
|
|
import styled from 'styled-components';
|
|
|
|
import { Button as NButton } from 'normalized-styled-components';
|
|
|
|
|
|
|
|
import BaseAnchor from '../anchor';
|
2017-05-18 21:21:33 +03:00
|
|
|
import Baseline from '../baseline';
|
2017-08-08 13:07:18 +03:00
|
|
|
import StatusLoader from '../status-loader';
|
2017-05-18 21:21:33 +03:00
|
|
|
|
2017-11-23 14:18:38 +02:00
|
|
|
const StyledButton = NButton.extend`
|
|
|
|
min-width: ${remcalc(120)};
|
|
|
|
|
2018-02-15 16:37:59 +02:00
|
|
|
& + button,
|
|
|
|
& + a {
|
2017-11-23 14:18:38 +02:00
|
|
|
margin-left: ${remcalc(6)};
|
|
|
|
}
|
|
|
|
`;
|
|
|
|
|
|
|
|
const InlineAnchor = styled(({ component, children, ...rest }) =>
|
|
|
|
React.createElement(component, rest, children)
|
|
|
|
)`
|
|
|
|
display: inline-block;
|
2018-02-15 16:37:59 +02:00
|
|
|
|
|
|
|
& + button,
|
|
|
|
& + a {
|
|
|
|
margin-left: ${remcalc(6)};
|
|
|
|
}
|
2017-11-23 14:18:38 +02:00
|
|
|
`;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @example ./usage.md
|
|
|
|
*/
|
|
|
|
const BaseButton = props => {
|
|
|
|
const { href = '', component, loading = false, secondary } = props;
|
|
|
|
|
|
|
|
const Views = [
|
|
|
|
() => {
|
|
|
|
return (
|
|
|
|
component &&
|
|
|
|
(({ children, ...props }) =>
|
|
|
|
React.createElement(InlineAnchor, props, children))
|
|
|
|
);
|
|
|
|
},
|
|
|
|
() => {
|
|
|
|
return (
|
|
|
|
href &&
|
|
|
|
(({ children, ...props }) =>
|
|
|
|
React.createElement(
|
|
|
|
InlineAnchor,
|
|
|
|
{ ...props, component: BaseAnchor },
|
|
|
|
children
|
|
|
|
))
|
|
|
|
);
|
|
|
|
},
|
|
|
|
() => ({ children, ...props }) => {
|
|
|
|
return React.createElement(
|
|
|
|
InlineAnchor,
|
|
|
|
{ ...props, component: StyledButton },
|
|
|
|
children
|
|
|
|
);
|
|
|
|
}
|
|
|
|
];
|
|
|
|
|
|
|
|
const View = Views.reduce((sel, view) => (sel ? sel : view()), null);
|
|
|
|
|
|
|
|
const children = loading ? (
|
|
|
|
<StatusLoader secondary={!secondary} small />
|
|
|
|
) : (
|
|
|
|
props.children
|
|
|
|
);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<View {...props} href={href}>
|
|
|
|
{children}
|
|
|
|
</View>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Buttons are the core of any UI kit, and we are no exception. Here we have documented to most basic variations of the button states, which include but are limited to; Default, Hover, Clicked, and Disabled.
|
|
|
|
*/
|
|
|
|
const Button = styled(BaseButton)`
|
2017-05-18 21:21:33 +03:00
|
|
|
box-sizing: border-box;
|
|
|
|
display: inline-block;
|
|
|
|
justify-content: center;
|
|
|
|
align-items: center;
|
|
|
|
|
2017-11-23 14:18:38 +02:00
|
|
|
min-height: ${remcalc(48)};
|
|
|
|
height: ${remcalc(48)};
|
|
|
|
min-width: ${remcalc(120)};
|
2017-12-06 17:03:40 +02:00
|
|
|
padding: ${remcalc(15)} ${remcalc(18)};
|
2017-05-18 21:21:33 +03:00
|
|
|
position: relative;
|
|
|
|
|
2018-01-19 19:37:31 +02:00
|
|
|
font-family: ${props => props.theme.font.families};
|
2017-05-18 21:21:33 +03:00
|
|
|
font-size: ${remcalc(15)};
|
|
|
|
text-align: center;
|
|
|
|
font-style: normal;
|
|
|
|
font-stretch: normal;
|
|
|
|
line-height: normal;
|
|
|
|
letter-spacing: normal;
|
|
|
|
text-decoration: none;
|
|
|
|
|
|
|
|
white-space: nowrap;
|
|
|
|
vertical-align: middle;
|
|
|
|
touch-action: manipulation;
|
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
color: ${props => props.theme.white};
|
2017-12-18 17:40:31 +02:00
|
|
|
-webkit-text-fill-color: currentcolor;
|
2017-05-18 21:21:33 +03:00
|
|
|
background-image: none;
|
|
|
|
background-color: ${props => props.theme.primary};
|
2017-12-22 03:08:27 +02:00
|
|
|
border-radius: ${props => props.theme.borderRadius};
|
2017-10-17 13:01:57 +03:00
|
|
|
border: solid ${remcalc(1)} ${props => props.theme.primaryActive};
|
2017-05-18 21:21:33 +03:00
|
|
|
|
|
|
|
&:focus {
|
|
|
|
outline: 0;
|
|
|
|
text-decoration: none;
|
|
|
|
background-color: ${props => props.theme.primary};
|
2017-10-17 13:01:57 +03:00
|
|
|
border-color: ${props => props.theme.primaryActive};
|
2017-05-18 21:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
background-color: ${props => props.theme.primaryHover};
|
2017-07-11 17:11:52 +03:00
|
|
|
border: solid ${remcalc(1)} ${props => props.theme.primaryActive};
|
2017-05-18 21:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
&:active,
|
|
|
|
&:active:hover,
|
|
|
|
&:active:focus {
|
|
|
|
background-image: none;
|
|
|
|
outline: 0;
|
|
|
|
background-color: ${props => props.theme.primaryActive};
|
2017-07-11 17:11:52 +03:00
|
|
|
border-color: ${props => props.theme.primaryActive};
|
2017-05-18 21:21:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
&[disabled] {
|
|
|
|
cursor: not-allowed;
|
|
|
|
pointer-events: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
${is('secondary')`
|
|
|
|
color: ${props => props.theme.secondary};
|
2017-12-18 17:40:31 +02:00
|
|
|
-webkit-text-fill-color: currentcolor;
|
2017-05-18 21:21:33 +03:00
|
|
|
background-color: ${props => props.theme.white};
|
|
|
|
border-color: ${props => props.theme.grey};
|
|
|
|
|
|
|
|
&:focus {
|
|
|
|
background-color: ${props => props.theme.white};
|
|
|
|
border-color: ${props => props.theme.grey};
|
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
background-color: ${props => props.theme.whiteHover};
|
|
|
|
border-color: ${props => props.theme.grey};
|
|
|
|
}
|
|
|
|
|
|
|
|
&:active,
|
|
|
|
&:active:hover,
|
|
|
|
&:active:focus {
|
|
|
|
background-color: ${props => props.theme.whiteActive};
|
|
|
|
border-color: ${props => props.theme.grey};
|
|
|
|
}
|
2017-09-27 17:44:57 +03:00
|
|
|
`};
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2017-11-28 16:50:55 +02:00
|
|
|
${is('error')`
|
|
|
|
color: ${props => props.theme.red};
|
2017-12-18 17:40:31 +02:00
|
|
|
-webkit-text-fill-color: currentcolor;
|
2017-11-28 16:50:55 +02:00
|
|
|
background-color: ${props => props.theme.white};
|
|
|
|
border-color: ${props => props.theme.red};
|
|
|
|
|
|
|
|
&:focus {
|
2018-01-23 16:16:28 +02:00
|
|
|
color: ${props => props.theme.redDark};
|
2017-11-28 16:50:55 +02:00
|
|
|
background-color: ${props => props.theme.white};
|
2018-01-23 16:16:28 +02:00
|
|
|
border-color: ${props => props.theme.redDark};
|
2017-11-28 16:50:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
2018-01-23 16:16:28 +02:00
|
|
|
color: ${props => props.theme.redDark};
|
|
|
|
background-color: ${props => props.theme.white};
|
|
|
|
border-color: ${props => props.theme.redDark};
|
2017-11-28 16:50:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
&:active,
|
|
|
|
&:active:hover,
|
|
|
|
&:active:focus {
|
2018-01-23 16:16:28 +02:00
|
|
|
background-color: rgba(210, 67, 58, 0.1);
|
|
|
|
border-color: ${props => props.theme.redDark};
|
2017-11-28 16:50:55 +02:00
|
|
|
}
|
|
|
|
`};
|
|
|
|
|
2017-10-12 21:55:05 +03:00
|
|
|
${isOr('disabled', 'loading')`
|
|
|
|
cursor: not-allowed;
|
|
|
|
pointer-events: none;
|
2017-05-18 21:21:33 +03:00
|
|
|
color: ${props => props.theme.grey};
|
|
|
|
background-color: ${props => props.theme.disabled};
|
|
|
|
border-color: ${props => props.theme.grey};
|
|
|
|
|
|
|
|
&:focus {
|
|
|
|
background-color: ${props => props.theme.disabled};
|
|
|
|
border-color: ${props => props.theme.grey};
|
|
|
|
}
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
background-color: ${props => props.theme.disabled};
|
|
|
|
border-color: ${props => props.theme.disabled};
|
|
|
|
}
|
|
|
|
|
|
|
|
&:active,
|
|
|
|
&:active:hover,
|
|
|
|
&:active:focus {
|
|
|
|
background-color: ${props => props.theme.disabled};
|
|
|
|
border-color: ${props => props.theme.disabled};
|
|
|
|
}
|
2017-09-27 17:44:57 +03:00
|
|
|
`};
|
2017-09-20 12:30:53 +03:00
|
|
|
|
|
|
|
${is('rect')`
|
2017-05-18 21:21:33 +03:00
|
|
|
border-radius: 0;
|
2017-09-08 15:01:37 +03:00
|
|
|
`};
|
2017-09-20 12:30:53 +03:00
|
|
|
|
2018-02-26 14:07:30 +02:00
|
|
|
${is('actions')`
|
|
|
|
border-radius: 0;
|
|
|
|
width: ${remcalc(48)};
|
|
|
|
min-width: ${remcalc(0)};
|
|
|
|
min-height: ${remcalc(0)};
|
|
|
|
height: ${remcalc(48)};
|
|
|
|
`};
|
|
|
|
|
2017-09-14 19:50:22 +03:00
|
|
|
${is('small')`
|
2018-02-26 15:47:52 +02:00
|
|
|
padding: ${remcalc(10)} ${remcalc(18)};
|
2017-12-06 17:03:40 +02:00
|
|
|
font-size: ${remcalc(13)};
|
|
|
|
min-width: ${remcalc(0)};
|
2018-02-26 14:07:30 +02:00
|
|
|
min-height: ${remcalc(0)};
|
|
|
|
height: auto;
|
2017-09-20 12:30:53 +03:00
|
|
|
`};
|
|
|
|
|
|
|
|
${is('icon')`
|
2017-11-23 14:18:38 +02:00
|
|
|
display: inline-flex;
|
2017-11-28 16:50:55 +02:00
|
|
|
align-items: center;
|
2017-11-23 14:18:38 +02:00
|
|
|
|
|
|
|
& svg + span {
|
|
|
|
margin-left: ${remcalc(12)};
|
|
|
|
}
|
|
|
|
|
|
|
|
& svg {
|
|
|
|
max-height: ${remcalc(18)};
|
|
|
|
}
|
2017-09-20 12:30:53 +03:00
|
|
|
`};
|
|
|
|
|
|
|
|
${is('fluid')`
|
|
|
|
width: 100%;
|
|
|
|
max-width: 100%;
|
2017-09-14 19:50:22 +03:00
|
|
|
`};
|
2017-10-13 22:56:08 +03:00
|
|
|
|
|
|
|
${is('marginless')`
|
|
|
|
margin: 0;
|
|
|
|
`};
|
2017-11-16 12:47:32 +02:00
|
|
|
|
|
|
|
${is('bold')`
|
2017-11-20 13:33:50 +02:00
|
|
|
font-weight: 500;
|
2017-11-16 12:47:32 +02:00
|
|
|
`};
|
2017-11-23 14:18:38 +02:00
|
|
|
|
|
|
|
${is('right')`
|
|
|
|
float: right;
|
|
|
|
`};
|
2017-05-18 21:21:33 +03:00
|
|
|
`;
|
|
|
|
|
|
|
|
Button.propTypes = {
|
|
|
|
/**
|
|
|
|
* The `<button>`/`<a>`/`<Link>` text
|
|
|
|
*/
|
|
|
|
children: PropTypes.node,
|
|
|
|
/**
|
2017-10-23 17:09:49 +03:00
|
|
|
* When used, it will render an `<a>` with the given href
|
2017-05-18 21:21:33 +03:00
|
|
|
*/
|
|
|
|
href: PropTypes.string,
|
|
|
|
/**
|
2017-10-23 17:09:49 +03:00
|
|
|
* When used, it will render a `<Link>` with the given to
|
2017-05-18 21:21:33 +03:00
|
|
|
*/
|
|
|
|
to: PropTypes.string,
|
2017-10-23 17:09:49 +03:00
|
|
|
/**
|
|
|
|
* Is it primary ?
|
|
|
|
*/
|
2017-05-18 21:21:33 +03:00
|
|
|
primary: PropTypes.bool,
|
2017-10-23 17:09:49 +03:00
|
|
|
/**
|
|
|
|
* Is it secondary ?
|
|
|
|
*/
|
2017-05-18 21:21:33 +03:00
|
|
|
secondary: PropTypes.bool,
|
2017-10-23 17:09:49 +03:00
|
|
|
/**
|
|
|
|
* When set to true a smaller version of the button will show
|
|
|
|
*/
|
2017-09-14 19:50:22 +03:00
|
|
|
small: PropTypes.bool,
|
2017-10-23 17:09:49 +03:00
|
|
|
/**
|
|
|
|
* Set to true to show loading animation
|
|
|
|
*/
|
2017-12-15 16:53:59 +02:00
|
|
|
loading: PropTypes.bool
|
2017-05-18 21:21:33 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
Button.defaultProps = {
|
2017-10-23 17:09:49 +03:00
|
|
|
primary: true,
|
|
|
|
secondary: false,
|
|
|
|
small: false,
|
2017-12-15 16:09:09 +02:00
|
|
|
loading: false
|
2017-05-18 21:21:33 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
export default Baseline(Button);
|