Skip to content
This repository was archived by the owner on Oct 16, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/atoms/button/button.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export const tertiary = () => (

export const disabled = () => (
<Fragment>
{/** TODO: Box it! */}
<Button onClick={action('clicked')} disabled>
{text('Primary button content', 'primary')}
</Button>
Expand All @@ -34,3 +33,11 @@ export const disabled = () => (
</Button>
</Fragment>
);

export const loading = () => <Button loading />;

export const withIcon = () => (
<Button icon="email" iconColor="primary.8">
{text('Content', 'Send')}
</Button>
);
37 changes: 34 additions & 3 deletions src/atoms/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import {
typography,
TypographyProps,
} from 'styled-system';

import { Theme, theme } from '../../theme';
import { StyleFunction } from '../../utils/types';
import { Flex } from '../flex/flex';
import { Icon, IconOptions } from '../icon/icon';
import { Paragraph } from '../paragraph/paragraph';

const defaultStyle = ({
theme: {
Expand Down Expand Up @@ -130,6 +132,9 @@ type ButtonVariant = 'primary' | 'secondary' | 'tertiary';

interface Props {
variant: ButtonVariant;
loading: boolean;
icon: IconOptions;
iconColor: string;
}

export type ButtonProps = Props &
Expand All @@ -155,8 +160,31 @@ const StyledButton = styled.button<ButtonProps>`
`;

// ts-ignore to fix type inconsistency because of color
// @ts-ignore
export const Button = (props: ButtonProps) => <StyledButton {...props} />;
export const Button = (props: ButtonProps) =>
props.icon ? (
// @ts-ignore
<StyledButton {...props} py={1}>
<Flex alignItems="center">
<Icon option={props.icon} color={props.iconColor} width="25px" />
<Flex flexGrow={1} justifyContent="center">
<Paragraph fontWeight="bold" lineHeight="0" pl={2} pr={1}>
{props.children}
</Paragraph>
</Flex>
</Flex>
</StyledButton>
) : props.loading ? (
// @ts-ignore
<StyledButton {...props} disabled>
<Flex alignItems="center" justifyContent="space-between">
<Icon option="loading" width="20px" color="white" />
Loading
</Flex>
</StyledButton>
) : (
// @ts-ignore
<StyledButton {...props} />
);

Button.defaultProps = {
theme,
Expand All @@ -168,4 +196,7 @@ Button.defaultProps = {
height: '40px',
px: 3,
py: 2,
loading: false,
icon: '',
iconColor: 'primary.8',
};
11 changes: 11 additions & 0 deletions src/atoms/icon/email-svg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { FunctionComponent } from 'react';
import { IconProps, StyledIcon } from './icon';

export const EmailSVG: FunctionComponent<IconProps> = (props) => {
return (
// @ts-ignore
<StyledIcon xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" {...props}>
<path d="M19 4H5a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3zm0 2l-6.5 4.47a1 1 0 0 1-1 0L5 6z" />
</StyledIcon>
);
};
14 changes: 11 additions & 3 deletions src/atoms/icon/icon.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import React from 'react';

import { atom } from '../../utils/structure';
import { EmailIcon } from './icon';
import { Icon } from './icon';
import { Box } from '../box/box';
import { Flex } from '../flex/flex';

export default { title: atom('Icon') };

export const email = () => (
<Box>
<EmailIcon />
<EmailIcon color="#876543" variant="outline" />
<Icon option="email" width="16px" />
<Icon color="accent.5" option="email" width="32px" />
</Box>
);

export const loading = () => (
<Flex alignItems="center">
<Icon option="loading" width="16px" color="#FF0000" />
<Icon option="loading" width="32px" color="#231391" />
</Flex>
);
72 changes: 19 additions & 53 deletions src/atoms/icon/icon.tsx
Original file line number Diff line number Diff line change
@@ -1,71 +1,37 @@
// @ts-ignore
import { themeGet } from '@styled-system/theme-get';
import React, { HTMLProps, ReactNode } from 'react';
import React, { HTMLProps } from 'react';
import styled, { ThemeProps } from 'styled-components';
import { color, ColorProps, compose, layout, LayoutProps, size, SizeProps } from 'styled-system';
import { theme, Theme } from '../../theme';
import { EmailSVG } from './email-svg';
import { LoadingSVG } from './loading-svg';
import { Box } from '../box/box';

export type IconVariant = 'fill' | 'outline';
export interface Props {
variant: IconVariant;
}

export type IconProps = Props & ThemeProps<Theme> & ColorProps & LayoutProps & SizeProps & HTMLProps<SVGElement>;
export type IconOptions = 'email' | 'loading';

interface Icons {
filledIcon: ReactNode;
outlinedIcon: ReactNode;
export interface Props {
option?: IconOptions;
color: string;
}
type IconPropsWithIcons = IconProps & Icons;

const styledProps = compose(
color,
layout,
size,
);
export type IconProps = Props & ThemeProps<Theme> & HTMLProps<SVGElement>;

const StyledIcon = styled.svg<IconProps>`
export const StyledIcon = styled.svg<IconProps>`
fill: ${({ color }: IconProps) => themeGet(`colors.${color}`, color)};
${styledProps};
`;

const Icon = ({ filledIcon, outlinedIcon, ...props }: IconPropsWithIcons) => {
// @ts-ignore
return <StyledIcon {...props}>{props.variant === 'fill' ? filledIcon : outlinedIcon}</StyledIcon>;
export const Icon = ({ option, ...props }: IconProps) => {
return option === 'email' ? (
<EmailSVG {...props} />
) : option === 'loading' ? (
<LoadingSVG {...props} />
) : (
<Box>Icon not found</Box>
);
};

Icon.defaultProps = {
theme,
size: 'iconSmall',
color: 'primary.4',
variant: 'fill',
};

const EmailFill = () => (
<g data-name="Layer 2">
<g data-name="email">
<rect width="24" height="24" opacity="0" />
<path d="M19 4H5a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3zm0 2l-6.5 4.47a1 1 0 0 1-1 0L5 6z" />
</g>
</g>
);

const EmailOutline = () => (
<g data-name="Layer 2">
<g data-name="email">
<rect width="24" height="24" opacity="0" />
<path d="M19 4H5a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h14a3 3 0 0 0 3-3V7a3 3 0 0 0-3-3zm-.67 2L12 10.75 5.67 6zM19 18H5a1 1 0 0 1-1-1V7.25l7.4 5.55a1 1 0 0 0 .6.2 1 1 0 0 0 .6-.2L20 7.25V17a1 1 0 0 1-1 1z" />
</g>
</g>
);

export const EmailIcon = (props: IconProps) => {
return <Icon {...props} filledIcon={<EmailFill />} outlinedIcon={<EmailOutline />} />;
};

EmailIcon.defaultProps = {
theme,
size: 'iconSmall',
color: 'primary.4',
variant: 'fill',
width: '24px',
};
41 changes: 41 additions & 0 deletions src/atoms/icon/loading-svg.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// @ts-ignore
import { themeGet } from '@styled-system/theme-get';
import React, { FunctionComponent } from 'react';
import { IconProps, StyledIcon } from './icon';

export const LoadingSVG: FunctionComponent<IconProps> = (props: IconProps) => {
return (
//@ts-ignore
<StyledIcon {...props} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle
cx="50"
cy="50"
fill="none"
r="40"
strokeWidth="15"
stroke={themeGet(`colors.${props.color}`, props.color)(props)}
strokeDasharray="62.83185307179586 62.83185307179586"
transform="rotate(0 50 50)"
>
<animate
attributeName="r"
begin="0s"
dur="2s"
values={`40;29;40`}
keyTimes="0;0.45;1"
repeatCount="indefinite"
/>
<animateTransform
attributeName="transform"
type="rotate"
calcMode="linear"
values="0 50 50;360 50 50"
keyTimes="0;1"
dur="2s"
begin="0s"
repeatCount="indefinite"
></animateTransform>
</circle>
</StyledIcon>
);
};
19 changes: 12 additions & 7 deletions src/components/text-input/text-input.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { ChangeEvent } from 'react';
import { TextInput } from './text-input';
import { component } from '../../utils/structure';
import { action } from '@storybook/addon-actions';
import { EmailIcon } from '../../atoms/icon/icon';
import { Icon } from '../../atoms/icon/icon';
import { Paragraph, Anchor } from '../../atoms';

export default { title: component('TextInput') };
Expand All @@ -26,18 +26,23 @@ export const withOnChange = () => {
);
};
export const withIcon = () => (
<TextInput label="Best skill with your nose" placeholder="Sorry for being nosy..." icon={<EmailIcon />} />
<TextInput label="Best skill with your nose" placeholder="Sorry for being nosy..." icon={<Icon option="email" />} />
);

export const withIconDisabled = () => (
<TextInput label="Best skill with your nose" placeholder="Sorry for being nosy..." icon={<EmailIcon />} disabled />
<TextInput
label="Best skill with your nose"
placeholder="Sorry for being nosy..."
icon={<Icon option="email" />}
disabled
/>
);

export const withIconError = () => (
<TextInput
label="Best skill with your nose"
placeholder="Sorry for being nosy..."
icon={<EmailIcon />}
icon={<Icon option="email" />}
error="Too short"
/>
);
Expand All @@ -47,7 +52,7 @@ export const withIconAndText = () => (
label="Hand size"
placeholder="Type here..."
help="We handle this information privately"
icon={<EmailIcon />}
icon={<Icon option="email" />}
/>
);

Expand All @@ -63,7 +68,7 @@ export const withIconAndComplexHelp = () => (
</Anchor>
</Paragraph>
}
icon={<EmailIcon />}
icon={<Icon option="email" />}
/>
);

Expand All @@ -80,6 +85,6 @@ export const withIconAndComplexHelpAndError = () => (
</Anchor>
</Paragraph>
}
icon={<EmailIcon />}
icon={<Icon option="email" />}
/>
);
2 changes: 1 addition & 1 deletion src/components/text-input/text-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ const StyledInputContainer = styled(Flex)<StyledInputContainerProps>`
}

& > input:disabled ~ div > svg {
fill: ${({ theme: { colors } }: StyledInputContainerProps) => colors.neutral[5]};
fill: ${({ theme: { colors } }: StyledInputContainerProps) => colors.neutral[2]};
}
`;

Expand Down