Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
baegofda committed Sep 24, 2024
1 parent e61d147 commit 1cbcb74
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 16 deletions.
31 changes: 31 additions & 0 deletions src/core/components/Dropdown/DropdownBase/Dropdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,34 @@ export const DropdownBaseWithIcon = () => {
/>
);
};

export const DropdownBaseWithSearch = () => {
const [currentValue, setCurrentValue] = useState('');

const data = ['A반', 'B반', 'C반', 'D반', 'E반'];

const items = data.map((item, idx) => (
<DropdownBase.Item key={idx} onClick={() => setCurrentValue(item)}>
{item}
</DropdownBase.Item>
));

return (
<DropdownBase
trigger={
<DropdownBase.Trigger>
{({ isToggle }) => (
<div className='flex items-center'>
{currentValue || '옵션을 선택해주세요'}
<CaretDown
size='16'
className={isToggle ? 'rotate-180' : 'rotate-0'}
/>
</div>
)}
</DropdownBase.Trigger>
}
content={<DropdownBase.Items useSearch items={items} />}
/>
);
};
44 changes: 36 additions & 8 deletions src/core/components/Dropdown/DropdownBase/DropdownItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,52 @@ import clsx from 'clsx';
import { forwardRef } from 'react';

import { DropdownItemsProps } from './types';
import InputSearch from '@/core/components/Input/InputSearch';

const DropdownItems = forwardRef(
(
{ className, items, ...props }: DropdownItemsProps,
{
rootClassName,
className,
items,
useSearch,
inputProps,
...props
}: DropdownItemsProps,
ref: React.Ref<HTMLUListElement>,
) => {
const {
rounded,
rootClassName: inputRootClassName,
placeholder,
...restInputProps
} = inputProps ?? {};

return (
<ul
ref={ref}
<div
className={clsx(
'absolute z-10 mt-2 whitespace-nowrap bg-white',
className,
'border-gary-02 absolute z-10 mt-2 min-w-full overflow-hidden whitespace-nowrap rounded-xl border bg-white ',
useSearch && 'flex-v-stack',
rootClassName,
)}
role='listbox'
{...props}
>
{items}
</ul>
{useSearch && (
<InputSearch
rounded={rounded ?? 'rounded-8'}
rootElement={'div'}
placeholder={placeholder ?? '검색어를 입력하세요'}
rootClassName={clsx(
'border-b border-b-gray-02 px-3 py-2',
inputRootClassName,
)}
{...restInputProps}
/>
)}
<ul ref={ref} className={clsx('flex-v-stack', className)} {...props}>
{items}
</ul>
</div>
);
},
);
Expand Down
5 changes: 5 additions & 0 deletions src/core/components/Dropdown/DropdownBase/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DropdownItem from '../DropdownItem';
import DropdownItems from '../DropdownItems';
import DropdownTrigger from '../DropdownTrigger';
import { FormLabelProps } from '@/core/components/FormLabel/types';
import { InputSearchProps } from '@/core/components/Input/InputSearch/types';

export interface DropdownProps extends Partial<FormLabelProps> {
className?: string;
Expand All @@ -33,7 +34,11 @@ export interface DropdownContextValue
export interface DropdownItemProps extends HTMLAttributes<HTMLLIElement> {}

export interface DropdownItemsProps extends HTMLAttributes<HTMLUListElement> {
rootClassName?: string;
items: ReactNode[];
useSearch?: boolean;
inputProps?: Omit<InputSearchProps<'div'>, 'rootElement' | 'rounded'> &
Partial<Pick<InputSearchProps<'div'>, 'rounded'>>;
}

export interface DropdownTriggerProps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ const DropdownFilterItems = forwardRef(
return (
<DropdownBase.Items
ref={ref}
className={clsx(
'flex-v-stack gap-y-6 overflow-hidden rounded-xl border border-gray-03 px-3 py-4',
className,
)}
className={clsx('gap-y-6 px-3 py-4', className)}
{...props}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,78 @@ export const Default = () => {
/>
);
};

export const DropdownMultipleWithSearch = () => {
const [searchValue, setSearchValue] = useState('');
const [currentValues, setCurrentValues] = useState<ValueWithLabel<number>[]>(
[],
);
const data = [
{ value: 0, label: '2024년 5월 선정산' },
{ value: 1, label: '5월 BIZ 본정산' },
{ value: 2, label: '5월 비즈 선정산 진짜' },
{ value: 3, label: '5월 비즈 선정산 진짜 진짜' },
];

const handleDelete = (value: ValueWithLabelType) => {
setCurrentValues((prev) => prev.filter(({ value: v }) => v !== value));
};

const onSearchChange = (e: ChangeEvent<HTMLInputElement>) => {
setSearchValue(e.target.value);
};

const filteredData = data.filter((item) =>
item['label'].includes(searchValue),
);

const items = filteredData.map((item, idx) => {
const { value, label } = item;
const isChecked = currentValues.some(({ value: v }) => v === value);

return (
<DropdownMultiple.Item
key={idx}
checked={isChecked}
onChange={(e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation();

const { checked } = e.target;

if (checked) {
setCurrentValues((prev) => [...prev, item]);
} else {
setCurrentValues((prev) =>
prev.filter((prevItem) => prevItem.value !== item.value),
);
}
}}
>
{label}
</DropdownMultiple.Item>
);
});

return (
<DropdownMultiple
label={'정산 선택'}
trigger={
<DropdownMultiple.Trigger
variant={'chip'}
currentValues={currentValues}
placeholder='선택해주세요'
onDelete={handleDelete}
/>
}
content={
<DropdownMultiple.Items
useSearch
inputProps={{ value: searchValue, onChange: onSearchChange }}
items={items}
/>
}
className={'w-[500px]'}
required
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ const DropdownSelectItems = forwardRef(
return (
<DropdownBase.Items
ref={ref}
className={clsx(
'flex-v-stack min-w-full gap-y-6 overflow-hidden rounded-xl border border-gray-03 px-3 py-4',
className,
)}
className={clsx('min-w-full gap-y-6 px-3 py-4', className)}
{...props}
/>
);
Expand Down

0 comments on commit 1cbcb74

Please sign in to comment.