@laura.broder/learnstorybook-design-system-template
Version:
Storybook design systems tutorial
206 lines (176 loc) • 3.94 kB
JavaScript
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import styled, { css } from 'styled-components';
import { darken } from 'polished';
import { Icon } from './Icon';
import { color } from './shared/styles';
const linkStyles = css`
display: inline-block;
transition: transform 150ms ease-out, color 150ms ease-out;
text-decoration: none;
color: ${color.secondary};
&:hover,
&:focus {
cursor: pointer;
transform: translateY(-1px);
color: ${darken(0.07, color.secondary)};
}
&:active {
transform: translateY(0);
color: ${darken(0.1, color.secondary)};
}
svg {
display: inline-block;
height: 1em;
width: 1em;
vertical-align: text-top;
position: relative;
bottom: -0.125em;
margin-right: 0.4em;
}
${props =>
props.containsIcon &&
css`
svg {
height: 1em;
width: 1em;
vertical-align: middle;
position: relative;
bottom: 0;
margin-right: 0;
}
`};
${props =>
props.secondary &&
css`
color: ${color.mediumdark};
&:hover {
color: ${color.dark};
}
&:active {
color: ${color.darker};
}
`};
${props =>
props.tertiary &&
css`
color: ${color.dark};
&:hover {
color: ${color.darkest};
}
&:active {
color: ${color.mediumdark};
}
`};
${props =>
props.nochrome &&
css`
color: inherit;
&:hover,
&:active {
color: inherit;
text-decoration: underline;
}
`};
${props =>
props.inverse &&
css`
color: ${color.lightest};
&:hover {
color: ${color.lighter};
}
&:active {
color: ${color.light};
}
`};
${props =>
props.isButton &&
css`
border: 0;
border-radius: 0;
background: none;
padding: 0;
font-size: inherit;
`};
`;
const LinkInner = styled.span`
${props =>
props.withArrow &&
css`
> svg:last-of-type {
height: 0.7em;
width: 0.7em;
margin-right: 0;
margin-left: 0.25em;
bottom: auto;
vertical-align: inherit;
}
`};
`;
const LinkA = styled.a`
${linkStyles};
`;
const LinkButton = styled.button`
/* reset button styles */
background: none;
color: inherit;
border: none;
padding: 0;
font: inherit;
cursor: pointer;
outline: inherit;
${linkStyles};
`;
const applyStyle = LinkWrapper => {
return (
LinkWrapper &&
styled(({ containsIcon, inverse, nochrome, secondary, tertiary, ...linkWrapperRest }) => (
<LinkWrapper {...linkWrapperRest} />
))`
${linkStyles};
`
);
};
/**
* Links can contains text and/or icons. Be careful using only icons, you must provide a text alternative via aria-label for accessibility.
*/
export function Link({ isButton, withArrow, LinkWrapper, children, ...rest }) {
const content = (
<Fragment>
<LinkInner withArrow={withArrow}>
{children}
{withArrow && <Icon icon="arrowright" />}
</LinkInner>
</Fragment>
);
const StyledLinkWrapper = applyStyle(LinkWrapper);
let SelectedLink = LinkA;
if (LinkWrapper) {
SelectedLink = StyledLinkWrapper;
} else if (isButton) {
SelectedLink = LinkButton;
}
return <SelectedLink {...rest}>{content}</SelectedLink>;
}
Link.propTypes = {
isButton: PropTypes.bool,
children: PropTypes.node,
withArrow: PropTypes.bool,
containsIcon: PropTypes.bool,
LinkWrapper: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
inverse: PropTypes.bool,
nochrome: PropTypes.bool,
secondary: PropTypes.bool,
tertiary: PropTypes.bool,
};
Link.defaultProps = {
isButton: false,
children: null,
withArrow: false,
containsIcon: false,
LinkWrapper: undefined,
inverse: false,
nochrome: false,
secondary: false,
tertiary: false,
};