diff --git a/src/shared/ui/Accordion/Accordion.context.tsx b/src/shared/ui/Accordion/Accordion.context.tsx index bf465b7..45376bb 100644 --- a/src/shared/ui/Accordion/Accordion.context.tsx +++ b/src/shared/ui/Accordion/Accordion.context.tsx @@ -4,6 +4,7 @@ type AccordionContextType = { type: 'single' | 'multiple'; openItems: string[]; toggleItem: (value: string) => void; + iconSize?: number; }; export const AccordionContext = createContext(null); diff --git a/src/shared/ui/Accordion/Accordion.stories.tsx b/src/shared/ui/Accordion/Accordion.stories.tsx index 1defd07..e52d874 100644 --- a/src/shared/ui/Accordion/Accordion.stories.tsx +++ b/src/shared/ui/Accordion/Accordion.stories.tsx @@ -90,3 +90,59 @@ export const DefaultValueAccordion: Story = { ); }, }; +export const IconSizeAccordion: Story = { + render: () => { + return ( + + 사용자 입력값에 따라}> +
아이콘의 크기를 조절합니다.
+
+
+ ); + }, +}; + +export const IconAlignAccordion: Story = { + render: () => { + return ( + + +
질문 1
+
아이콘은 요소의 상단에 위치합니다
+ + } + iconAlign="start" + > +
아이콘 정렬 top
+
+ +
질문 2
+
아이콘은 요소의 가운데 위치합니다
+ + } + iconAlign="center" + > +
아이콘 정렬 center
+
+ +
아이콘 정렬 bottom
+
아이콘은 요소의 하단에 위치합니다
+ + } + iconAlign="end" + > +
아이콘 정렬 bottom
+
+
+ ); + }, +}; diff --git a/src/shared/ui/Accordion/Accordion.tsx b/src/shared/ui/Accordion/Accordion.tsx index b68011c..ac21025 100644 --- a/src/shared/ui/Accordion/Accordion.tsx +++ b/src/shared/ui/Accordion/Accordion.tsx @@ -26,6 +26,10 @@ type AccordionRootProps = { * Additional class names to apply to the AccordionRoot. */ className?: string; + /** + * Default icon size for all AccordionItems. + */ + iconSize?: number; }; export function AccordionRoot({ @@ -33,6 +37,7 @@ export function AccordionRoot({ className = '', children, defaultValue, + iconSize, ...props }: AccordionRootProps) { const defaultOpenItem = defaultValue ? defaultValue : []; @@ -49,7 +54,7 @@ export function AccordionRoot({ }; return ( - +
{children}
@@ -83,6 +88,24 @@ type AccordionItemProps = { * The class name for the content container. */ contentClassName?: string; + /** + * Additional class names for the arrow icon wrapper. + */ + iconWrapperClassName?: string; + /** + * Additional class names for the SVG arrow icon itself. + */ + iconClassName?: string; + /** + * icon size + * @default 20 + */ + iconSize?: number; + /** + * icon vertical alignment position. + * @default 'center' + */ + iconAlign?: 'start' | 'center' | 'end'; }; const ACCORDION_MOTION = { @@ -95,6 +118,12 @@ const ACCORDION_MOTION = { }, }; +const ALIGN_ICON = { + start: 'self-start', + center: 'self-center', + end: 'self-end', +}; + const isInteractiveElement = (element: HTMLElement) => { const INTERACTIVE_TAGS = ['INPUT', 'TEXTAREA', 'A']; return INTERACTIVE_TAGS.includes(element.tagName); @@ -106,10 +135,16 @@ export function AccordionItem({ value, btnClassName, contentClassName, + iconWrapperClassName, + iconClassName, + iconSize, + iconAlign = 'center', children, ...props }: AccordionItemProps) { const context = useAccordion(); + const rawIconSize = iconSize ?? context.iconSize ?? 13.5; + const normalizedIconSize = Number.isFinite(rawIconSize) && rawIconSize > 0 ? rawIconSize : 13.5; const uid = useId(); const triggerId = `accordion-trigger-${uid}`; const contentId = `accordion-content-${uid}`; @@ -145,9 +180,9 @@ export function AccordionItem({ - + )}