Skip to content

Commit

Permalink
feat: Button (#8)
Browse files Browse the repository at this point in the history
* feat: Button

* docs: Added storybook instructions

* chore: Fixed linting error

* refactor: Moved styled components and types to separate files

* feat: Added types to build

* feat(button): Added start, end icon support

* build: Removed unused package

* feat(button): Text variant

* chore: Added enum for variants
  • Loading branch information
hachiojidev authored Oct 19, 2020
1 parent 229a95a commit e5ab247
Show file tree
Hide file tree
Showing 18 changed files with 502 additions and 35 deletions.
2 changes: 2 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
"@typescript-eslint/no-unused-vars": "error",
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": ["error"],
"no-shadow": "off",
"@typescript-eslint/no-shadow": ["error"],
// React
"react/jsx-filename-extension": ["error", { "extensions": [".tsx"] }],
"react/prop-types": 0,
Expand Down
12 changes: 3 additions & 9 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.@(js|jsx|ts|tsx)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials"
]
}
stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
addons: ["@storybook/addon-links", "@storybook/addon-essentials", "themeprovider-storybook/register"],
};
1 change: 1 addition & 0 deletions .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<link href="https://fonts.googleapis.com/css2?family=Kanit:wght@300;400;600&display=swap" rel="stylesheet">
42 changes: 41 additions & 1 deletion .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,44 @@
import React from "react";
import { withThemesProvider } from "themeprovider-storybook";
import { createGlobalStyle } from "styled-components";
import light from "../src/theme/light";
import dark from "../src/theme/dark";

const Global = createGlobalStyle`
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
body {
font-family: 'Kanit', sans-serif;
}
`;

const globalDecorator = (StoryFn) => (
<>
<Global />
<StoryFn />
</>
);

export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
}
};

const themes = [
{
name: "Light",
backgroundColor: light.colors.background,
...light,
},
{
name: "Dark",
backgroundColor: dark.colors.background,
...dark,
},
];

export const decorators = [globalDecorator, withThemesProvider(themes)];
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# 🥞 Pancake UI Kit

## Developing

This project uses [Storybook](https://storybook.js.org/). To start development run

```shell
$ yarn storybook
```

## Committing

Commit messages follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) using [commitlint](https://commitlint.js.org/#/).
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"repository": "https://github.com/pancakeswap/pancake-uikit",
"license": "MIT",
"scripts": {
"build": "rollup -c",
"build": "rollup -c && tsc -d --emitDeclarationOnly --declarationDir dist",
"lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
"format": "prettier --write 'src/**/*.{js,jsx,ts,tsx}'",
"storybook": "start-storybook -p 6006",
Expand Down Expand Up @@ -54,6 +54,7 @@
"react-is": "^16.13.1",
"rollup": "^2.31.0",
"styled-components": "^5.2.0",
"themeprovider-storybook": "^1.6.4",
"ts-jest": "^26.4.1",
"tslib": "^2.0.3",
"typescript": "^4.0.3"
Expand Down
10 changes: 5 additions & 5 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import typescript from '@rollup/plugin-typescript';
import pkg from './package.json';
import typescript from "@rollup/plugin-typescript";
import pkg from "./package.json";

export default {
input: 'src/index.ts',
input: "src/index.ts",
output: [
{ file: pkg.main, format: 'cjs' },
{ file: pkg.module, format: 'es' },
{ file: pkg.main, format: "cjs" },
{ file: pkg.module, format: "es" },
],
plugins: [typescript()],
};
92 changes: 92 additions & 0 deletions src/components/Button/StyledButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import styled, { DefaultTheme } from "styled-components";
import { Props, Variants } from "./types.d";

interface ThemedProps extends Props {
theme: DefaultTheme;
}

const getBackground = ({ variant, disabled, theme }: ThemedProps) => {
if (disabled) {
return "#ddd";
}

switch (variant) {
case Variants.OUTLINE:
case Variants.TEXT:
return "transparent";
case Variants.SECONDARY:
return theme.colors.tertiary;
case Variants.PRIMARY:
default:
return theme.colors.primary;
}
};

const getBorder = ({ variant, disabled, theme }: ThemedProps) => {
if (disabled) {
return 0;
}

switch (variant) {
case Variants.OUTLINE:
return `2px solid ${theme.colors.primary}`;
case Variants.PRIMARY:
case Variants.SECONDARY:
case Variants.TEXT:
default:
return 0;
}
};

const getColor = ({ variant, disabled, theme }: ThemedProps) => {
if (disabled) {
return "#acaaaf";
}

switch (variant) {
case Variants.PRIMARY:
return "#FFFFFF";
case Variants.TEXT:
return theme.colors.text;
case Variants.OUTLINE:
case Variants.SECONDARY:
default:
return theme.colors.primary;
}
};

export const StartIcon = styled.span`
margin-right: 0.5em;
`;

export const EndIcon = styled.span`
margin-left: 0.5em;
`;

const StyledButton = styled.button<Props>`
align-items: center;
background-color: ${getBackground};
border: ${getBorder};
border-radius: 16px;
color: ${getColor};
cursor: pointer;
display: inline-flex;
font-family: inherit;
font-size: 16px;
font-weight: 600;
height: ${({ size }) => (size === "sm" ? "32px" : "48px")};
letter-spacing: 0.03em;
justify-content: center;
outline: 0;
padding: ${({ size }) => (size === "sm" ? "0 16px" : "0 24px")};
&:hover:not(:disabled) {
opacity: 0.9;
}
&:disabled {
cursor: not-allowed;
}
`;

export default StyledButton;
81 changes: 71 additions & 10 deletions src/components/Button/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,82 @@
import React from "react";
// also exported from '@storybook/react' if you can deal with breaking changes in 6.1
// eslint-disable-next-line import/no-unresolved
import { Story, Meta } from "@storybook/react/types-6-0";
import styled from "styled-components";
/* eslint-disable import/no-unresolved */
import { Meta } from "@storybook/react/types-6-0";
import Button from "./index";

import Button, { Props } from "./index";
const Row = styled.div`
margin-bottom: 32px;
& > button + button {
margin-left: 16px;
}
`;

export default {
title: "Button",
component: Button,
argTypes: {},
} as Meta;

const Template: Story<Props> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
export const Default: React.FC = () => {
return (
<>
<Row>
<Button>Primary</Button>
<Button disabled>Disabled</Button>
<Button size="sm">Small</Button>
</Row>
<Row>
<Button variant="secondary">Secondary</Button>
<Button variant="secondary" disabled>
Disabled
</Button>
<Button variant="secondary" size="sm">
Small
</Button>
</Row>
<Row>
<Button variant="outline">Outline</Button>
<Button variant="outline" disabled>
Disabled
</Button>
<Button variant="outline" size="sm">
Small
</Button>
</Row>
<Row>
<Button variant="text">Text</Button>
<Button variant="text" disabled>
Disabled
</Button>
<Button variant="text" size="sm">
Small
</Button>
</Row>
</>
);
};

Primary.args = {
variant: "primary",
children: "Primary",
const StartIcon = () => (
<span role="img" aria-label="cake" style={{ display: "inline-block", width: "100%", textAlign: "center" }}>
🥞
</span>
);
const EndIcon = () => (
<span role="img" aria-label="cake" style={{ display: "inline-block", width: "100%", textAlign: "center" }}>
🍳
</span>
);
export const WithIcon: React.FC = () => {
return (
<>
<Row>
<Button startIcon={<StartIcon />}>Start Icon</Button>
<Button endIcon={<EndIcon />}>End Icon</Button>
<Button startIcon={<StartIcon />} endIcon={<EndIcon />}>
Start & End Icon
</Button>
</Row>
</>
);
};
19 changes: 13 additions & 6 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import styled from "styled-components";
import React from "react";
import StyledButton, { StartIcon, EndIcon } from "./StyledButton";
import { Props } from "./types.d";

export interface Props {
variant?: "primary";
}

const Button = styled.button<Props>``;
const Button: React.FC<Props> = ({ startIcon, endIcon, children, ...props }) => {
return (
<StyledButton {...props}>
{startIcon && <StartIcon>{startIcon}</StartIcon>}
{children}
{endIcon && <EndIcon>{endIcon}</EndIcon>}
</StyledButton>
);
};

Button.defaultProps = {
variant: "primary",
size: "md",
};

export default Button;
15 changes: 15 additions & 0 deletions src/components/Button/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ButtonHTMLAttributes, ReactNode } from "react";

export enum Variants {
OUTLINE = "outline",
TEXT = "text",
SECONDARY = "secondary",
PRIMARY = "primary",
}

export interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: Variants;
size?: "md" | "sm";
startIcon?: ReactNode;
endIcon?: ReactNode;
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
// eslint-disable-next-line import/prefer-default-export
export { default as Button } from "./components/Button";

export * from "./theme";
32 changes: 32 additions & 0 deletions src/styled.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import "styled-components";

export type Pallete = {
iris: string;
peach: string;
onyx: string;
fuschia: string;
evergreen: string;
slate: string;
lightSlate: string;
dorian: string;
cloud: string;
white: string;
};

declare module "styled-components" {
export interface DefaultTheme {
colors: {
primary: string;
secondary: string;
tertiary: string;
background: string;
text: string;
textSubtle: string;
dark: string;
failure: string;
success: string;
accent: string;
light: string;
} & Pallete;
}
}
Loading

0 comments on commit e5ab247

Please sign in to comment.