Skip to content

Commit

Permalink
Merge pull request #6 from zoopi-palette/feat/text-input
Browse files Browse the repository at this point in the history
Feat/text input
  • Loading branch information
ghtea authored Apr 24, 2022
2 parents e90f4df + 7d1e302 commit 7f0604d
Show file tree
Hide file tree
Showing 18 changed files with 227 additions and 8 deletions.
9 changes: 9 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')

module.exports = {
"stories": [
"../**/*.stories.@(js|jsx|ts|tsx)"
Expand Down Expand Up @@ -48,6 +50,13 @@ module.exports = {
}],
});

config.resolve.plugins = [
...(config.resolve.plugins || []),
new TsconfigPathsPlugin({
extensions: config.resolve.extensions,
}),
];

return config
},
}
2 changes: 1 addition & 1 deletion components/HeaderBar/HeaderBar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {useTheme} from "@emotion/react"
import Link from "next/Link"
import React from "react"
import {Button} from "components/button";
import {Button} from "components/Button";

export const HeaderBar = () => {
const theme = useTheme();
Expand Down
File renamed without changes.
1 change: 1 addition & 0 deletions components/LayoutCenter/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./LayoutCenter"
2 changes: 1 addition & 1 deletion components/button/button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ComponentStory, ComponentMeta} from "@storybook/react";
import React from "react";

import {Button, ButtonAppearance, ButtonColor} from "./button";
import {Button, ButtonAppearance, ButtonColor} from "./Button";

const buttonColors: ButtonColor[] = ["main", "gray"]
const buttonApperances: ButtonAppearance[] = ["filled", "outline"]
Expand Down
2 changes: 1 addition & 1 deletion components/button/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./button"
export * from "./Button"
2 changes: 1 addition & 1 deletion components/icon/icon.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ComponentStory, ComponentMeta} from "@storybook/react";
import React from "react";

import {Icon, IconName} from "./icon";
import {Icon, IconName} from "./Icon";

const iconNames: IconName[] = ["arrow-back", "arrow-right", "check-circle", "circle", "close-circle", "close", "eye", "search"]

Expand Down
2 changes: 1 addition & 1 deletion components/icon/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./icon"
export * from "./Icon"
1 change: 0 additions & 1 deletion components/templates/layout-center/index.ts

This file was deleted.

1 change: 1 addition & 0 deletions components/textInput/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./TextInput"
19 changes: 19 additions & 0 deletions components/textInput/textInput.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {ComponentStory, ComponentMeta} from "@storybook/react";
import React from "react";

import {TextInput} from "./TextInput";

export default {
title: "atoms/TextInput",
component: TextInput,
argTypes: {
},
args: {
label: "label",
placeholder: "placeholder"
},
} as ComponentMeta<typeof TextInput>;

const Template: ComponentStory<typeof TextInput> = (args) => <TextInput {...args} />;

export const Default = Template.bind({});
114 changes: 114 additions & 0 deletions components/textInput/textInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {useTheme} from "@emotion/react"
import {ChangeEvent, ChangeEventHandler, FocusEventHandler, ReactNode, useCallback, useEffect, useMemo, useRef, useState} from "react"
import {Icon} from "components/Icon"
import {Css, CssObject} from "styles/theme"

export type TextInputProps = {
children?: ReactNode
value: string
placeholder?: string
onChange?: (value: string, event?: ChangeEvent<HTMLInputElement>)=>void
onBlur?: FocusEventHandler<HTMLInputElement>
onFocus?: FocusEventHandler<HTMLInputElement>
label?: string | null
type?: "email" | "password" | "text";
clearDisabled?: boolean
right?: ReactNode
}

export const TextInput = ({
children,
onChange,
onBlur,
onFocus,
value,
label,
clearDisabled = false,
right,
type = "text",
...rest
}: TextInputProps) => {
const theme = useTheme()

const [localValue, setLocalValue] = useState("")

const css: Css = useMemo(()=>{
return ({
fontSize: "1rem",
color: theme.colors["grey-90"],
borderWidth: 1,
borderBottomStyle: "solid",
borderColor: theme.colors["grey-40"],
paddingBottom: "6px",
"::placeholder": {
padding: 0,
color: theme.colors["grey-40"],
},
":focus": {
borderColor: theme.colors["grey-90"],
},
} as CssObject)
},[theme])

const handleChange: ChangeEventHandler<HTMLInputElement> = useCallback((event)=>{
setLocalValue(event.currentTarget.value)
onChange?.(event.currentTarget.value, event)
},[onChange])

const handleBlur: FocusEventHandler<HTMLInputElement> = useCallback((event)=>{
onBlur?.(event)
},[onBlur])

const handleFocus: FocusEventHandler<HTMLInputElement> = useCallback((event)=>{
onFocus?.(event)
},[onFocus])

const handleClearClick = useCallback(()=>{
setLocalValue("")
onChange?.("")
},[onChange])

return (
<label css={{
display: "inline-flex",
flexDirection: "column",
width: "100%",
position: "relative"
}}>
{label && (
<span css={theme => ({
fontSize: "0.875rem",
color: theme.colors["grey-50"],
marginBottom: "7px"
})}>
{label}
</span>
)}
<input
type={type}
{...rest}
value={value || localValue}
onChange={handleChange}
onBlur={handleBlur}
onFocus={handleFocus}
css={css}
/>
<div css={{position: "absolute", right: 0, bottom: 6}}>
{right}
{clearDisabled ? null : (
<button
onClick={handleClearClick}
css={{
display: (value || localValue) ? "inline-flex" : "none",
cursor: "pointer",
paddingRight: 2,
paddingLeft: 2
}}
>
<Icon name={"close-circle"} color={theme.colors["grey-50"]}/>
</button>
)}
</div>
</label>
)
}
1 change: 1 addition & 0 deletions components/textInputPassword/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./TextInputPassword"
17 changes: 17 additions & 0 deletions components/textInputPassword/textInputPassword.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {ComponentStory, ComponentMeta} from "@storybook/react";
import React from "react";

import {TextInputPassword} from "./TextInputPassword";

export default {
title: "atoms/TextInputPassword",
component: TextInputPassword,
argTypes: {
},
args: {
},
} as ComponentMeta<typeof TextInputPassword>;

const Template: ComponentStory<typeof TextInputPassword> = (args) => <TextInputPassword {...args} />;

export const Default = Template.bind({});
35 changes: 35 additions & 0 deletions components/textInputPassword/textInputPassword.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {useTheme} from "@emotion/react"
import {useState} from "react"
import {Icon} from "components/Icon"
import {TextInput} from "components/TextInput"
import {TextInputProps} from "components/TextInput/TextInput"

export type TextInputPasswordProps = TextInputProps & {
}

export const TextInputPassword = ({
...rest
}: TextInputPasswordProps) => {
const theme = useTheme()

const [type, setType] = useState<TextInputProps["type"]>("password")

const handleEyeClick = ()=>{
setType(prev => prev === "password" ? "text" : "password")
}

const label = rest.label === null ? undefined : (rest.label || "비밀번호")

return (
<TextInput
label={label}
type={type}
right={(
<button css={{paddingRight: 2, paddingLeft: 2, cursor: "pointer"}} onClick={handleEyeClick}>
<Icon name={"eye"} color={theme.colors["grey-60"]}/>
</button>
)}
{...rest}
/>
)
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"eslint-config-next": "12.1.4",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-storybook": "^0.5.10",
"tsconfig-paths-webpack-plugin": "^3.5.2",
"typescript": "4.6.3"
},
"resolutions": {
Expand Down
4 changes: 2 additions & 2 deletions pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import {useTheme} from "@emotion/react";
import type {NextPage} from "next"
import Link from "next/Link"
import Image from "next/image"
import {Button} from "components/button"
import {LayoutCenter} from "components/templates/layout-center"
import {Button} from "components/Button"
import {LayoutCenter} from "components/LayoutCenter"

const BUTTON_WIDTH = 400;

Expand Down
22 changes: 22 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5011,6 +5011,14 @@ enhanced-resolve@^4.5.0:
memory-fs "^0.5.0"
tapable "^1.0.0"

enhanced-resolve@^5.7.0:
version "5.9.3"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88"
integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==
dependencies:
graceful-fs "^4.2.4"
tapable "^2.2.0"

entities@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
Expand Down Expand Up @@ -9876,6 +9884,11 @@ tapable@^1.0.0, tapable@^1.1.3:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==

tapable@^2.2.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==

tar@^6.0.2:
version "6.1.11"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621"
Expand Down Expand Up @@ -10072,6 +10085,15 @@ ts-pnp@^1.1.6:
resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92"
integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==

tsconfig-paths-webpack-plugin@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz#01aafff59130c04a8c4ebc96a3045c43c376449a"
integrity sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==
dependencies:
chalk "^4.1.0"
enhanced-resolve "^5.7.0"
tsconfig-paths "^3.9.0"

tsconfig-paths@^3.11.0, tsconfig-paths@^3.14.1, tsconfig-paths@^3.9.0:
version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
Expand Down

0 comments on commit 7f0604d

Please sign in to comment.