-
Notifications
You must be signed in to change notification settings - Fork 3
[feature] 지원서 상태에 따라 분류하고 이름, 제출 순으로 정렬 할 수 있다. #754
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2f29c2a
a137afb
e2f589c
f17ebbe
7954ef8
6462c46
8433910
a698eb9
875de8d
228bde8
a96c1ef
19dbdba
69f0f7b
5165a86
9b6c2e5
f63681d
1cd6e7f
b24b4cb
9bc9af1
e3711ec
65c6fc9
bdc96ac
d8843ca
ac9ab83
a1c0351
e476c11
972d708
3af21b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,50 +1,119 @@ | ||
| import { useState } from 'react'; | ||
| import React, { createContext, useContext, ReactNode } from 'react'; | ||
| import * as Styled from './CustomDropDown.styles'; | ||
| import dropdown_icon from '@/assets/images/icons/drop_button_icon.svg'; | ||
|
|
||
| interface DropdownOption { | ||
| interface DropdownOption<TValue> { | ||
| label: string; | ||
| value: string; | ||
| value: TValue; | ||
| } | ||
|
|
||
| interface DropdownProps { | ||
| options: DropdownOption[]; | ||
| selected: string; | ||
| onSelect: (value: string) => void; | ||
| interface CustomDropDownContextProps<TValue> { | ||
| open: boolean; | ||
| selected?: TValue; | ||
| options: readonly DropdownOption<TValue>[]; | ||
| onToggle: (isOpen: boolean) => void; | ||
| handleSelect: (value: TValue) => void; | ||
| } | ||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const CustomDropdown = ({ options, selected, onSelect }: DropdownProps) => { | ||
| const [open, setOpen] = useState(false); | ||
| interface CustomDropDownProps<TValue> { | ||
| children: ReactNode; | ||
| options: readonly DropdownOption<TValue>[]; | ||
| selected?: TValue; | ||
| onSelect: (value: TValue) => void; | ||
| open: boolean; | ||
| onToggle: (isOpen: boolean) => void; | ||
| style?: React.CSSProperties; | ||
| } | ||
|
|
||
| interface ItemProps<TValue> { | ||
| value: TValue; | ||
| children: ReactNode; | ||
| style?: React.CSSProperties; | ||
| } | ||
|
|
||
| const CustomDropDownContext = createContext< | ||
| CustomDropDownContextProps<any> | undefined | ||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| >(undefined); | ||
|
Comment on lines
+33
to
+35
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. context 쓰신 이유가 각각의 드롭다운 상태를 독립적으로 유지하기 위해서인가요?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 컴포넌트안 공통된 상태들을 공유하기 위해서입니다!
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 그럼 각각 다른 드롭다운 컴포넌트 두개를 생성하면 서로 상태를 공유하나요?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 서로 상태를 공유하지않고 각자 상태를 가지게됩니다 |
||
|
|
||
| const useDropDownContext = () => { | ||
| const context = useContext(CustomDropDownContext); | ||
| if (!context) { | ||
| throw new Error( | ||
| 'useDropDownContext는 CustomDropDownContextProvider 내부에서 사용할 수 있습니다.', | ||
| ); | ||
| } | ||
| return context; | ||
| }; | ||
oesnuj marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const Trigger = ({ children }: { children: ReactNode }) => { | ||
| const { onToggle, open } = useDropDownContext(); | ||
| return ( | ||
| <div | ||
| onClick={() => { | ||
| onToggle(open); | ||
| }} | ||
| > | ||
| {children} | ||
| </div> | ||
| ); | ||
| }; | ||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const handleSelect = (value: string) => { | ||
| interface MenuProps { | ||
| children: ReactNode; | ||
| top?: string; | ||
| width?: string; | ||
| right?: string; | ||
| } | ||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| const Menu = ({ children, top, width, right }: MenuProps) => { | ||
| const { open } = useDropDownContext(); | ||
| return open ? ( | ||
| <Styled.OptionList role='listbox' $top={top} $width={width} $right={right}> | ||
| {children} | ||
| </Styled.OptionList> | ||
| ) : null; | ||
| }; | ||
|
|
||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const Item = <TValue extends string | number = string>({ | ||
| value, | ||
| children, | ||
| style, | ||
| }: ItemProps<TValue>) => { | ||
| const { selected, handleSelect } = useDropDownContext(); | ||
| return ( | ||
| <Styled.OptionItem | ||
| role='option' | ||
| $isSelected={value === selected} | ||
| onClick={() => handleSelect(value)} | ||
| style={style} | ||
| > | ||
| {children} | ||
| </Styled.OptionItem> | ||
| ); | ||
| }; | ||
|
|
||
| export function CustomDropDown<T extends string | number = string>({ | ||
| children, | ||
| options, | ||
| selected, | ||
| onSelect, | ||
| open, | ||
| onToggle, | ||
| style, | ||
| }: CustomDropDownProps<T>) { | ||
| const handleSelect = (value: T) => { | ||
| onSelect(value); | ||
| setOpen(false); | ||
| onToggle(open); | ||
| }; | ||
|
|
||
| const selectedLabel = | ||
| options.find((option) => option.value === selected)?.label || '선택하세요'; | ||
| const value = { open, selected, options, onToggle, handleSelect }; | ||
|
|
||
| return ( | ||
| <Styled.DropDownWrapper> | ||
| <Styled.Selected onClick={() => setOpen((prev) => !prev)} open={open}> | ||
| <span>{selectedLabel}</span> | ||
| <Styled.Icon src={dropdown_icon} alt='드롭다운 버튼' /> | ||
| </Styled.Selected> | ||
| {open && ( | ||
| <Styled.OptionList> | ||
| {options.map(({ label, value }) => ( | ||
| <Styled.OptionItem | ||
| key={value} | ||
| isSelected={value === selected} | ||
| onClick={() => handleSelect(value)} | ||
| > | ||
| {label} | ||
| </Styled.OptionItem> | ||
| ))} | ||
| </Styled.OptionList> | ||
| )} | ||
| </Styled.DropDownWrapper> | ||
| <CustomDropDownContext.Provider value={value}> | ||
| <Styled.DropDownWrapper style={style}>{children}</Styled.DropDownWrapper> | ||
| </CustomDropDownContext.Provider> | ||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ); | ||
| }; | ||
| } | ||
|
|
||
| export default CustomDropdown; | ||
| CustomDropDown.Trigger = Trigger; | ||
| CustomDropDown.Menu = Menu; | ||
| CustomDropDown.Item = Item; | ||
lepitaaar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Uh oh!
There was an error while loading. Please reload this page.