-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* chore: select-icon 수정 * feat: calendar-picker-indicator 속성 정의 * feat: select 아이콘 추가 * feat: date util함수 추가 * feat: DatePicker 컴포넌트 작성 * feat: DatePicker 스토리북 작성
- Loading branch information
Showing
6 changed files
with
228 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import { getTodayDate } from '@/utils/date'; | ||
import Button from '@/v1/base/Button'; | ||
import DatePicker from '@/v1/base/DatePicker'; | ||
import ErrorMessage from '@/v1/base/ErrorMessage'; | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
import { SubmitHandler, useForm } from 'react-hook-form'; | ||
|
||
const meta: Meta<typeof DatePicker> = { | ||
title: 'Base/DatePicker', | ||
component: DatePicker, | ||
tags: ['autodocs'], | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof DatePicker>; | ||
|
||
export const Default: Story = { | ||
args: { | ||
defaultValue: '2023-06-16', | ||
}, | ||
render: args => <DatePicker {...args} />, | ||
}; | ||
|
||
export const Disabled: Story = { | ||
args: { | ||
disabled: true, | ||
defaultValue: '2023-06-16', | ||
}, | ||
render: args => <DatePicker {...args} />, | ||
}; | ||
|
||
export const UseWithForm: Story = { | ||
render: () => <DatePickerWithForm />, | ||
}; | ||
|
||
type DefaultValues = { | ||
startDate: string; | ||
endDate: string; | ||
hello: number; | ||
hi: string; | ||
}; | ||
|
||
const DatePickerWithForm = () => { | ||
const { | ||
register, | ||
handleSubmit, | ||
formState: { errors }, | ||
} = useForm<DefaultValues>({ | ||
mode: 'all', | ||
defaultValues: { | ||
startDate: getTodayDate(), | ||
endDate: '2030-12-25', | ||
}, | ||
}); | ||
|
||
const handleSubmitForm: SubmitHandler<DefaultValues> = ({ | ||
startDate, | ||
endDate, | ||
}) => { | ||
alert(`startDate: ${startDate} endDate: ${endDate}`); | ||
}; | ||
|
||
return ( | ||
<form | ||
onSubmit={handleSubmit(handleSubmitForm)} | ||
className="flex flex-col gap-[3.2rem]" | ||
> | ||
<div className="flex flex-col gap-[0.5rem]"> | ||
<DatePicker | ||
disabled={true} | ||
min={getTodayDate()} | ||
{...register('startDate', { | ||
required: { value: true, message: '종료일을 입력해주세요' }, | ||
min: { | ||
value: getTodayDate(), | ||
message: '종료일은 시작일보다 늦어야 해요', | ||
}, | ||
})} | ||
/> | ||
{errors.startDate && ( | ||
<ErrorMessage>{errors.startDate.message}</ErrorMessage> | ||
)} | ||
</div> | ||
<div className="flex flex-col gap-[0.5rem]"> | ||
<DatePicker | ||
min={getTodayDate()} | ||
{...register('endDate', { | ||
required: { value: true, message: '종료일을 입력해주세요.' }, | ||
min: { | ||
value: getTodayDate(), | ||
message: '종료일은 시작일보다 늦어야 해요.', | ||
}, | ||
})} | ||
/> | ||
{errors.endDate && ( | ||
<ErrorMessage>{errors.endDate.message}</ErrorMessage> | ||
)} | ||
</div> | ||
<Button | ||
size="full" | ||
type="submit" | ||
onClick={handleSubmit(handleSubmitForm)} | ||
> | ||
Submit | ||
</Button> | ||
</form> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { | ||
ChangeEventHandler, | ||
forwardRef, | ||
InputHTMLAttributes, | ||
Ref, | ||
useEffect, | ||
useState, | ||
} from 'react'; | ||
|
||
import { formatDateInputValue } from '@/utils/date'; | ||
|
||
import { IconSelect } from '@public/icons'; | ||
|
||
interface DatePickerProps | ||
extends Omit< | ||
InputHTMLAttributes<HTMLInputElement>, | ||
'value' | 'id' | 'className' | ||
> { | ||
defaultValue?: string; | ||
} | ||
|
||
const DatePicker = ( | ||
{ | ||
name, | ||
onChange, | ||
disabled = false, | ||
defaultValue = '', | ||
...props | ||
}: DatePickerProps, | ||
ref: Ref<HTMLInputElement> | ||
) => { | ||
const [currentDate, setCurrentDate] = useState(defaultValue); | ||
|
||
const disabledClasses = disabled | ||
? 'text-black-500 cursor-not-allowed [&_svg]:fill-black-500' | ||
: 'text-black-900 cursor-pointer [&_svg]:fill-black-900'; | ||
|
||
const handleInputChange: ChangeEventHandler<HTMLInputElement> = event => { | ||
setCurrentDate(event.target.value); | ||
onChange && onChange(event); | ||
}; | ||
|
||
useEffect(() => { | ||
if (defaultValue) return; | ||
|
||
const $date = document.querySelector(`input#${name}`) as HTMLInputElement; | ||
|
||
if (!$date) return; | ||
setCurrentDate($date.value); | ||
}, [defaultValue, name]); | ||
|
||
return ( | ||
<label | ||
className={`relative flex h-[3rem] max-w-[14rem] items-center justify-between bg-transparent ${disabledClasses}`} | ||
htmlFor={name} | ||
> | ||
<div className="flex h-full min-w-0 flex-grow items-center"> | ||
<input | ||
id={name} | ||
name={name} | ||
ref={ref} | ||
type="date" | ||
className="h-full w-0" | ||
disabled={disabled} | ||
defaultValue={currentDate} | ||
onChange={handleInputChange} | ||
{...props} | ||
/> | ||
<p | ||
className={`truncate text-sm ${ | ||
currentDate ? 'text-inherit' : 'text-placeholder' | ||
}`} | ||
> | ||
{currentDate | ||
? formatDateInputValue(currentDate) | ||
: '날짜를 선택해주세요'} | ||
</p> | ||
</div> | ||
<IconSelect className={`h-[1.2rem] w-[1.2rem] flex-shrink-0`} /> | ||
</label> | ||
); | ||
}; | ||
|
||
export default forwardRef(DatePicker); |