Skip to content

Commit

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

* refactor: Removed ButtonMenuItem styled component
  • Loading branch information
hachiojidev authored Oct 19, 2020
1 parent 855e648 commit 1a85549
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 34 deletions.
30 changes: 15 additions & 15 deletions src/components/Button/StyledButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import styled, { DefaultTheme } from "styled-components";
import { Props, Variants } from "./types.d";
import { ButtonProps, variants } from "./types";

interface ThemedProps extends Props {
interface ThemedProps extends ButtonProps {
theme: DefaultTheme;
}

Expand All @@ -11,12 +11,12 @@ const getBackground = ({ variant, disabled, theme }: ThemedProps) => {
}

switch (variant) {
case Variants.OUTLINE:
case Variants.TEXT:
case variants.OUTLINE:
case variants.TEXT:
return "transparent";
case Variants.SECONDARY:
case variants.SECONDARY:
return theme.colors.tertiary;
case Variants.PRIMARY:
case variants.PRIMARY:
default:
return theme.colors.primary;
}
Expand All @@ -28,11 +28,11 @@ const getBorder = ({ variant, disabled, theme }: ThemedProps) => {
}

switch (variant) {
case Variants.OUTLINE:
case variants.OUTLINE:
return `2px solid ${theme.colors.primary}`;
case Variants.PRIMARY:
case Variants.SECONDARY:
case Variants.TEXT:
case variants.PRIMARY:
case variants.SECONDARY:
case variants.TEXT:
default:
return 0;
}
Expand All @@ -44,12 +44,12 @@ const getColor = ({ variant, disabled, theme }: ThemedProps) => {
}

switch (variant) {
case Variants.PRIMARY:
case variants.PRIMARY:
return "#FFFFFF";
case Variants.TEXT:
case variants.TEXT:
return theme.colors.text;
case Variants.OUTLINE:
case Variants.SECONDARY:
case variants.OUTLINE:
case variants.SECONDARY:
default:
return theme.colors.primary;
}
Expand All @@ -63,7 +63,7 @@ export const EndIcon = styled.span`
margin-left: 0.5em;
`;

const StyledButton = styled.button<Props>`
const StyledButton = styled.button<ButtonProps>`
align-items: center;
background-color: ${getBackground};
border: ${getBorder};
Expand Down
8 changes: 4 additions & 4 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import StyledButton, { StartIcon, EndIcon } from "./StyledButton";
import { Props } from "./types.d";
import { ButtonProps, variants, sizes } from "./types";

const Button: React.FC<Props> = ({ startIcon, endIcon, children, ...props }) => {
const Button: React.FC<ButtonProps> = ({ startIcon, endIcon, children, ...props }) => {
return (
<StyledButton {...props}>
{startIcon && <StartIcon>{startIcon}</StartIcon>}
Expand All @@ -13,8 +13,8 @@ const Button: React.FC<Props> = ({ startIcon, endIcon, children, ...props }) =>
};

Button.defaultProps = {
variant: "primary",
size: "md",
variant: variants.PRIMARY,
size: sizes.MD,
};

export default Button;
15 changes: 0 additions & 15 deletions src/components/Button/types.d.ts

This file was deleted.

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

export const sizes = {
SM: "sm",
MD: "md",
} as const;

export const variants = {
PRIMARY: "primary",
SECONDARY: "secondary",
OUTLINE: "outline",
TEXT: "text",
} as const;

export type Sizes = typeof sizes[keyof typeof sizes];
export type Variants = typeof variants[keyof typeof variants];

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: Variants;
size?: Sizes;
startIcon?: ReactNode;
endIcon?: ReactNode;
}
10 changes: 10 additions & 0 deletions src/components/ButtonMenu/ButtonMenuItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from "react";
import Button from "../Button";
import { sizes } from "../Button/types";
import { ButtonMenuItemProps } from "./types";

const ButtonMenuItem: React.FC<ButtonMenuItemProps> = ({ isActive = false, size = sizes.MD, ...props }) => {
return <Button variant={isActive ? "primary" : "secondary"} size={size} {...props} />;
};

export default ButtonMenuItem;
9 changes: 9 additions & 0 deletions src/components/ButtonMenu/StyledButtonMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import styled from "styled-components";

const StyledButtonMenu = styled.div`
background-color: ${({ theme }) => theme.colors.tertiary};
border-radius: 16px;
display: inline-flex;
`;

export default StyledButtonMenu;
49 changes: 49 additions & 0 deletions src/components/ButtonMenu/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { useState } from "react";
import styled from "styled-components";
/* eslint-disable import/no-unresolved */
import { Meta } from "@storybook/react/types-6-0";
import ButtonMenu from "./index";
import ButtonMenuItem from "./ButtonMenuItem";

const Row = styled.div`
margin-bottom: 32px;
& > button + button {
margin-left: 16px;
}
`;

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

export const Default: React.FC = () => {
const [index, setIndex] = useState(0);
const [index1, setIndex1] = useState(1);

const handleClick = (newIndex) => setIndex(newIndex);
const handleClick1 = (newIndex) => setIndex1(newIndex);

return (
<>
<Row>
<ButtonMenu activeIndex={index} onClick={handleClick}>
<ButtonMenuItem>Button 1</ButtonMenuItem>
<ButtonMenuItem>Button 2</ButtonMenuItem>
<ButtonMenuItem>Button 3</ButtonMenuItem>
<ButtonMenuItem>Button 4</ButtonMenuItem>
</ButtonMenu>
</Row>
<Row>
<ButtonMenu activeIndex={index1} onClick={handleClick1} size="sm">
<ButtonMenuItem>Button 1</ButtonMenuItem>
<ButtonMenuItem>Button 2</ButtonMenuItem>
<ButtonMenuItem>Button 3</ButtonMenuItem>
<ButtonMenuItem>Button 4</ButtonMenuItem>
</ButtonMenu>
</Row>
</>
);
};
17 changes: 17 additions & 0 deletions src/components/ButtonMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { cloneElement, Children, ReactElement } from "react";
import StyledButtonMenu from "./StyledButtonMenu";
import { sizes } from "../Button/types";
import { ButtonMenuProps, ButtonMenuItemProps } from "./types";

const ButtonMenu: React.FC<ButtonMenuProps> = ({ activeIndex = 0, size = sizes.MD, onClick, children }) => {
return (
<StyledButtonMenu>
{Children.map(children, (child: ReactElement<ButtonMenuItemProps>, index) => {
const handleClick = () => onClick && onClick(index);
return cloneElement(child, { isActive: activeIndex === index, onClick: handleClick, size });
})}
</StyledButtonMenu>
);
};

export default ButtonMenu;
13 changes: 13 additions & 0 deletions src/components/ButtonMenu/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ButtonProps, Sizes } from "../Button/types";

export interface ButtonMenuItemProps extends ButtonProps {
isActive?: boolean;
size?: Sizes;
}

export interface ButtonMenuProps {
activeIndex?: number;
onClick?: (index: number) => void;
size?: Sizes;
children: React.ReactElement[];
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// eslint-disable-next-line import/prefer-default-export
export { default as Button } from "./components/Button";
export { default as ButtonMenu } from "./components/ButtonMenu";
export { default as ButtonMenuItem } from "./components/ButtonMenu/ButtonMenuItem";
export { default as ResetCSS } from "./ResetCSS";

export * from "./theme";

0 comments on commit 1a85549

Please sign in to comment.