diff --git a/src/components/ui/dropdown/dropdown.stories.tsx b/src/components/ui/dropdown/dropdown.stories.tsx index 47b3e9c..e0c215c 100644 --- a/src/components/ui/dropdown/dropdown.stories.tsx +++ b/src/components/ui/dropdown/dropdown.stories.tsx @@ -12,7 +12,7 @@ const meta: Meta = { tags: ['autodocs'], args: { name: 'status', - areaLabel: '카테고리', + ariaLabel: '카테고리', placeholder: '카테고리를 선택하세요', values: CATEGORY_CODE, // 기본값 }, @@ -44,6 +44,6 @@ export const Small: Story = { export const WithDefaultValue: Story = { args: { - defaultValue: CATEGORY_CODE[1], + selected: CATEGORY_CODE[1], }, }; diff --git a/src/components/ui/dropdown/dropdown.styles.ts b/src/components/ui/dropdown/dropdown.styles.ts index b0fe9be..17537db 100644 --- a/src/components/ui/dropdown/dropdown.styles.ts +++ b/src/components/ui/dropdown/dropdown.styles.ts @@ -1,5 +1,5 @@ export const DROPDOWN_STYLE = { - base: 'flex-1 text-left min-w-[110px] focus-visible:outline-red-300', + base: 'relative flex-1 text-left min-w-[110px] focus-visible:outline-red-300', md: 'base-input !pr-10', sm: 'rounded-md bg-gray-100 py-1.5 pl-3 pr-7 text-body-s font-bold', } as const; diff --git a/src/components/ui/dropdown/dropdown.tsx b/src/components/ui/dropdown/dropdown.tsx index f9345fb..4934f74 100644 --- a/src/components/ui/dropdown/dropdown.tsx +++ b/src/components/ui/dropdown/dropdown.tsx @@ -4,38 +4,40 @@ import useEscapeKey from '@/hooks/useEscapeKey'; import useSafeRef from '@/hooks/useSafeRef'; import useToggle from '@/hooks/useToggle'; import { cn } from '@/lib/utils/cn'; -import { useState } from 'react'; import { DROPDOWN_ICON_STYLE, DROPDOWN_ITEM_STYLE, DROPDOWN_STYLE } from './dropdown.styles'; import useDropdown from './hooks/useDropdown'; interface DropdownProps { name: string; - areaLabel: string; + ariaLabel: string; + selected: T | undefined; // Controlled value values: readonly T[]; size?: 'md' | 'sm'; - defaultValue?: T; placeholder?: string; className?: string; + onChange: (value: T) => void; } -// EX : +// EX : const Dropdown = ({ name, - areaLabel: label, + ariaLabel, values, size = 'md', - defaultValue, + selected, placeholder = '선택해주세요', className, + onChange, }: DropdownProps) => { const { value: isOpen, toggle, setClose } = useToggle(); - const [selected, setSelected] = useState(defaultValue); const [attachDropdownRef, dropdownRef] = useSafeRef(); const [attachTriggerRef, triggerRef] = useSafeRef(); const [attachListRef, listRef] = useSafeRef(); - const handleSelect = (value: T) => { - setSelected(value); + + const handleSelect = (val: T) => { + onChange(val); setClose(); + // triggerRef.current?.focus(); }; const { cursorIndex, position } = useDropdown({ @@ -57,7 +59,7 @@ const Dropdown = ({ ref={attachTriggerRef} type='button' aria-expanded={isOpen} - aria-label={label} + aria-label={ariaLabel} className={cn( DROPDOWN_STYLE['base'], size === 'md' ? DROPDOWN_STYLE['md'] : DROPDOWN_STYLE['sm'] @@ -68,7 +70,7 @@ const Dropdown = ({ ({
({ onSelect, }: UseDropdownProps) => { const position = useDropdownPosition(triggerRef); - const { cursorIndex, setCursorIndex } = useKeyboardNavigation({ isOpen, values, onSelect }); + const { cursorIndex } = useKeyboardNavigation({ isOpen, values, onSelect }); useDropdownScroll(listRef, cursorIndex); return { cursorIndex, position, - setCursorIndex, }; }; diff --git a/src/components/ui/dropdown/hooks/useDropdownPosition.ts b/src/components/ui/dropdown/hooks/useDropdownPosition.ts index 4ce818b..2b927a2 100644 --- a/src/components/ui/dropdown/hooks/useDropdownPosition.ts +++ b/src/components/ui/dropdown/hooks/useDropdownPosition.ts @@ -1,6 +1,6 @@ import { RefObject, useEffect, useState } from 'react'; -const useDropdownPosition = (triggerRef: RefObject) => { +const useDropdownPosition = (triggerRef: RefObject, threshold = 300) => { const [position, setPosition] = useState<'top' | 'bottom'>('bottom'); useEffect(() => { @@ -10,7 +10,7 @@ const useDropdownPosition = (triggerRef: RefObject) => { const updatePosition = () => { const rect = trigger.getBoundingClientRect(); const viewportHeight = window.innerHeight; - setPosition(viewportHeight - rect.bottom < 300 ? 'top' : 'bottom'); + setPosition(viewportHeight - rect.bottom < threshold ? 'top' : 'bottom'); }; updatePosition(); @@ -20,7 +20,7 @@ const useDropdownPosition = (triggerRef: RefObject) => { window.removeEventListener('resize', updatePosition); window.removeEventListener('scroll', updatePosition, true); }; - }, [triggerRef]); + }, [triggerRef, threshold]); return position; }; diff --git a/src/components/ui/icon/icon.tsx b/src/components/ui/icon/icon.tsx index a845e4e..4a2496b 100644 --- a/src/components/ui/icon/icon.tsx +++ b/src/components/ui/icon/icon.tsx @@ -13,7 +13,7 @@ interface IconProps extends React.HTMLAttributes { iconSize?: IconSize; // 모바일 기본 사이즈 bigScreenSize?: IconResponsiveSize; // PC에서 사이즈 다를때 사용 className?: string; - ariaLabel: string; // 접근성 라벨 + ariaLabel?: string; // 접근성 라벨 decorative?: boolean; }