Skip to content

Commit

Permalink
feat: TextField, DatePicker 컴포넌트 추가 (#26)
Browse files Browse the repository at this point in the history
* feat: TextField 컴포넌트 기본 스타일 추가

* feat: cursor 스타일 추가

* feat: type이 date일때 캘린더 아이콘 보이도록 추가

* feat: file 타입 대응

* feat: DatePicker 추가, never로 추론되는 것 수정
  • Loading branch information
alstn2468 authored Feb 3, 2024
1 parent f5e4788 commit 0d0dabd
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 4 deletions.
73 changes: 72 additions & 1 deletion apps/preview/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import './index.css';
import 'the-new-css-reset/css/reset.css';
import { Badge, Button, TextButton, BooltiUIProvider, Footer } from '@boolti/ui';
import {
Badge,
Button,
TextButton,
BooltiUIProvider,
Footer,
TextField,
DatePicker,
} from '@boolti/ui';
import {
AppleIcon,
ArrowLeftIcon,
Expand All @@ -21,8 +29,10 @@ import {
UsersIcon,
WalletIcon,
} from '@boolti/icon';
import { useState } from 'react';

const App = () => {
const [date, setDate] = useState<string>('');
return (
<BooltiUIProvider>
<h1>
Expand Down Expand Up @@ -231,6 +241,67 @@ const App = () => {
<CloseIcon size={20} /> <CloseIcon size={24} />
</div>
</h1>
<br />
<TextField placeholder="aaa" size="small" inputType="text" />
<br />
<TextField
value="abc"
onChange={() => {
/** noop */
}}
size="big"
inputType="text"
/>

<br />
<TextField
value="abc"
onChange={() => {
/** noop */
}}
size="big"
inputType="text"
buttonProps={{ children: 'BUTTON' }}
/>

<br />
<TextField
disabled
value="abc"
onChange={() => {
/** noop */
}}
size="big"
inputType="text"
buttonProps={{ children: 'BUTTON' }}
/>

<br />
<TextField
placeholder="YYYY.MM.DD"
size="big"
inputType="date"
value={date}
onChange={(event) => {
setDate(event.target.value);
}}
buttonProps={{ children: 'BUTTON' }}
/>

<br />
<TextField
placeholder="abc"
size="big"
inputType="file"
buttonProps={{ children: 'BUTTON' }}
/>

<br />
<DatePicker size="small" />

<br />
<DatePicker size="big" />

<Footer />
</BooltiUIProvider>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/ui/src/components/Button/Button.styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ const Container = styled.button<ButtonProps>`
background-color 0.2s ease-in-out,
border-color 0.2s ease-in-out,
color 0.2s ease-in-out;
cursor: pointer;
&:disabled {
cursor: unset;
}
${({ size, theme }) => {
switch (size) {
case 'bold':
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Styled, { ButtonProps } from './Button.styles';

type Props = React.HTMLAttributes<HTMLButtonElement> & ButtonProps;
type Props = React.ComponentProps<'button'> & ButtonProps;

const Button = ({ children, colorTheme, size, icon, ...rest }: Props) => {
return (
Expand Down
37 changes: 37 additions & 0 deletions packages/ui/src/components/DatePicker/DatePicker.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import styled from '@emotion/styled';

export interface DatePickerProps {
fromInputProps?: Omit<React.ComponentProps<'input'>, 'type'>;
toInputProps?: Omit<React.ComponentProps<'input'>, 'type'>;
size: 'small' | 'big';
}

const Container = styled.div<DatePickerProps>`
display: flex;
justify-content: center;
align-items: center;
${({ size }) => {
switch (size) {
case 'small':
return `
width: 386px;
`;
case 'big':
return `
width: 600px;
`;
}
}}
& > div {
width: auto;
flex: 1;
}
`;

export const Seperator = styled.span`
margin: 0 4px;
${({ theme }) => theme.typo.b4};
color: ${({ theme }) => theme.palette.grey.g80};
`;

export default { Container, Seperator };
14 changes: 14 additions & 0 deletions packages/ui/src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import TextField from '../TextField';
import Styled, { DatePickerProps } from './DatePicker.styles';

const DatePicker = ({ fromInputProps, toInputProps, size }: DatePickerProps) => {
return (
<Styled.Container size={size}>
<TextField {...fromInputProps} size={size} inputType="date" placeholder="YYYY.MM.DD" />
<Styled.Seperator>~</Styled.Seperator>
<TextField {...toInputProps} size={size} inputType="date" placeholder="YYYY.MM.DD" />
</Styled.Container>
);
};

export default DatePicker;
2 changes: 1 addition & 1 deletion packages/ui/src/components/TextButton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Styled from './TextButton.styles';

interface Props extends React.HTMLAttributes<HTMLButtonElement> {
interface Props extends React.ComponentProps<'button'> {
icon?: React.ReactNode;
disabled?: boolean;
}
Expand Down
102 changes: 102 additions & 0 deletions packages/ui/src/components/TextField/TextField.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import styled from '@emotion/styled';

export interface TextFieldProps {
size: 'small' | 'big';
inputType: 'text' | 'date' | 'file';
disabled?: boolean;
buttonProps?: React.ComponentProps<'button'>;
}

const Container = styled.div<TextFieldProps>`
display: flex;
${({ size }) => {
switch (size) {
case 'small':
return `
width: 386px;
`;
case 'big':
return `
width: 600px;
`;
}
}}
`;

const InputContainer = styled.div`
position: relative;
flex: 1;
& > svg {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
}
`;

const InputLabel = styled.label`
display: block;
width: 100%;
height: 48px;
border-radius: 4px;
padding: 12px 13px;
color: ${({ theme }) => theme.palette.grey.g90};
border: 1px solid ${({ theme }) => theme.palette.grey.g90};
background: ${({ theme }) => theme.palette.grey.w};
${({ theme }) => theme.typo.b3};
`;

const Input = styled.input`
width: 100%;
border-radius: 4px;
padding: 12px 13px;
color: ${({ theme }) => theme.palette.grey.g90};
border: 1px solid ${({ theme }) => theme.palette.grey.g90};
background: ${({ theme }) => theme.palette.grey.w};
${({ theme }) => theme.typo.b3};
&:placeholder-shown {
border: 1px solid ${({ theme }) => theme.palette.grey.g20};
color: ${({ theme }) => theme.palette.grey.g30};
}
&:disabled {
background: ${({ theme }) => theme.palette.grey.g10};
border: 1px solid ${({ theme }) => theme.palette.grey.g20};
color: ${({ theme }) => theme.palette.grey.g40};
}
&[type='date'] {
opacity: 0;
position: absolute;
top: 0;
left: 0;
}
&[type='date']::before {
content: attr(data-placeholder);
width: 100%;
}
&[type='date']::-webkit-inner-spin-button,
&[type='date']::-webkit-calendar-picker-indicator {
position: absolute;
right: -10px;
top: 0;
transform: translateX(-10px);
padding-left: 600px;
height: 100%;
opacity: 0;
}
&[type='file'] {
display: none;
}
`;

const ButtonContainer = styled.div`
margin-left: 8px;
`;

export default {
Container,
Input,
InputLabel,
InputContainer,
ButtonContainer,
};
40 changes: 40 additions & 0 deletions packages/ui/src/components/TextField/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { CalendarIcon } from '@boolti/icon';
import { nanoid } from 'nanoid';
import Button from '../Button';
import Styled, { TextFieldProps } from './TextField.styles';
import { useRef } from 'react';

type Props = Omit<React.ComponentProps<'input'>, 'size' | 'type'> & TextFieldProps;

const TextField = ({ disabled, size, inputType, buttonProps, placeholder, id, ...rest }: Props) => {
const uuid = useRef<string>(id ?? nanoid(6));
return (
<Styled.Container disabled={disabled} size={size} inputType={inputType}>
<Styled.InputContainer>
{(inputType === 'file' || inputType === 'date') && (
<Styled.InputLabel htmlFor={uuid.current}>
{rest.value ? rest.value : placeholder}
</Styled.InputLabel>
)}
<Styled.Input
id={uuid.current}
data-placeholder={placeholder}
placeholder={placeholder}
disabled={disabled}
type={inputType}
{...rest}
/>
{inputType === 'date' && <CalendarIcon size={20} />}
</Styled.InputContainer>
{buttonProps && (
<Styled.ButtonContainer>
<Button {...buttonProps} disabled={disabled} size="bold" colorTheme="netural">
{buttonProps.children}
</Button>
</Styled.ButtonContainer>
)}
</Styled.Container>
);
};

export default TextField;
4 changes: 3 additions & 1 deletion packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,7 @@ import TextButton from './TextButton';
import Badge from './Badge';
import Dialog from './Dialog';
import Footer from './Footer';
import TextField from './TextField';
import DatePicker from './DatePicker';

export { BooltiUIProvider, Button, TextButton, Badge, Dialog, Footer };
export { BooltiUIProvider, Button, TextButton, Badge, Dialog, Footer, TextField, DatePicker };

0 comments on commit 0d0dabd

Please sign in to comment.