Icon#
CoUI 디자인 시스템의 통일된 아이콘 컴포넌트입니다. Iconify 생태계(Lucide, Radix, Bootstrap, HeroIcons) 아이콘을 IconName
참조로 렌더합니다. Flutter와 Web이 동일한 API와 동일한 아이콘 레퍼런스를 사용합니다.
Live Preview#
class IconDefaultExample extends StatelessComponent {
const IconDefaultExample({super.key});
@override
Component build(BuildContext context) {
return const Icon(LucideIcons.house, iconStyle: CoreIconStyle(size: 28));
}
}
class IconDefaultExample extends StatelessWidget {
const IconDefaultExample({super.key});
@override
Widget build(BuildContext context) {
return const Icon(LucideIcons.house, iconStyle: CoreIconStyle(size: 28));
}
}
class IconSearchExample extends StatelessComponent {
const IconSearchExample({super.key});
@override
Component build(BuildContext context) {
return const Icon(LucideIcons.search, iconStyle: CoreIconStyle(size: 28));
}
}
class IconSearchExample extends StatelessWidget {
const IconSearchExample({super.key});
@override
Widget build(BuildContext context) {
return const Icon(LucideIcons.search, iconStyle: CoreIconStyle(size: 28));
}
}
class IconFavoriteExample extends StatelessComponent {
const IconFavoriteExample({super.key});
@override
Component build(BuildContext context) {
return Icon(
LucideIcons.heart,
iconStyle: CoreIconStyle(size: 28, color: context.colorScheme.tertiary),
);
}
}
class IconFavoriteExample extends StatelessWidget {
const IconFavoriteExample({super.key});
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Icon(
LucideIcons.heart,
iconStyle: CoreIconStyle(size: 28, color: scheme.tertiary.toValue()),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 버튼, 메뉴, 네비게이션 항목에 시각적 힌트가 필요할 때
- 텍스트 없이 아이콘만으로 의미를 전달해야 할 때 (접근성 레이블 필수)
- CoUI 디자인 시스템의 통일된 아이콘 세트를 사용할 때
대신 다른 컴포넌트를 사용하세요:
Badge: 아이콘 위에 숫자나 상태 표시가 필요할 때Icon과Badge를 조합Fab: 아이콘 버튼을 강조된 액션 버튼으로 표시할 때
기본 사용법 (Basic Usage)#
Icon의 모든 시각 커스터마이징은 iconStyle: CoreIconStyle(...)로 단일화되어 있습니다 (Epic #1302 — nested Style API).
// 기본 아이콘 (디자인 시스템 default — 24px / onSurface)
const Icon(LucideIcons.house);
// 크기 지정
const Icon(
LucideIcons.house,
iconStyle: CoreIconStyle(size: 28),
);
// 다른 아이콘 세트
const Icon(RadixIcons.chevronLeft, iconStyle: CoreIconStyle(size: 16));
const Icon(BootstrapIcons.gear, iconStyle: CoreIconStyle(size: 20));
// HeroIcons 스타일 선택
const Icon(HeroIcons.arrowLeft.outline, iconStyle: CoreIconStyle(size: 24));
const Icon(HeroIcons.arrowLeft.solid, iconStyle: CoreIconStyle(size: 24));
// 크기 + 색상
Icon(
LucideIcons.heart,
iconStyle: CoreIconStyle(
size: 28,
color: Theme.of(context).colorScheme.tertiary,
),
);
// 같은 스타일을 여러 인스턴스에 재사용
final dangerIcon = CoreIconStyle<Color>(
size: 20,
color: Theme.of(context).colorScheme.error,
);
Icon(LucideIcons.alertTriangle, iconStyle: dangerIcon);
Icon(LucideIcons.x, iconStyle: dangerIcon);
// 기본 아이콘
const Icon(LucideIcons.house);
// 크기 지정
const Icon(
LucideIcons.house,
iconStyle: CoreIconStyle(size: 28),
);
// 다른 아이콘 세트
const Icon(RadixIcons.chevronLeft, iconStyle: CoreIconStyle(size: 16));
const Icon(BootstrapIcons.gear, iconStyle: CoreIconStyle(size: 20));
// HeroIcons 스타일 선택
const Icon(HeroIcons.arrowLeft.outline, iconStyle: CoreIconStyle(size: 24));
const Icon(HeroIcons.arrowLeft.solid, iconStyle: CoreIconStyle(size: 24));
// 크기 + 색상 — Web 의 color 는 Tailwind colour token 문자열
Icon(
LucideIcons.heart,
iconStyle: CoreIconStyle(
size: 28,
color: context.colorScheme.tertiary, // 'tertiary' 토큰
),
);
Props / Parameters#
| 속성 | 타입 (Flutter) | 타입 (Web) | 기본값 | 설명 |
|---|---|---|---|---|
icon |
IconName |
IconName |
필수 (positional) | 표시할 아이콘 (LucideIcons.* 등) |
iconStyle |
CoreIconStyle<Color>? |
CoreIconStyle<String>? |
null |
아이콘 크기/색상 (Style 시스템 참조) |
스타일 시스템 (Style System)#
Icon 의 모든 시각 오버라이드는 단일 iconStyle (CoreIconStyle<C>) 으로 흐릅니다 (Epic #1302 원칙 6/7/8).
IconName 식별자만 위젯 파라미터로 직접 전달합니다.
CoreIconStyle<C> 슬롯#
| Slot | 타입 (Flutter) | 타입 (Web) | 설명 |
|---|---|---|---|
size |
double? |
double? |
아이콘 크기 (logical px). null → 다음 단계 inherit |
color |
Color? |
String? (Tailwind colour token) |
아이콘 색상. null → 다음 단계 inherit |
CoreIconStyle.merge(other) — non-null 필드만 덮어씌우는 비파괴 합성. resolve chain의 핵심.
Resolve chain#
design system default
→ CoreIconTheme.style // 프로젝트 공통
→ parent component slot override // 예: CoreButtonStyle.leadingIconStyle
→ widget.iconStyle // 인스턴스별
각 레이어는 CoreIconStyle 의 어떤 필드든 부분적으로 채울 수 있습니다. null 인 필드는 다음 레이어로 넘겨주고, non-null 인 필드는 해당 레이어에서 확정됩니다.
색상 처리 차이점#
-
Flutter:
Color객체로 받아ColorFilter.mode(color, BlendMode.srcIn)으로 tint -
Web: Tailwind colour token 문자열(
'tertiary'등)로 받아text-${token}class 적용 - 양쪽 모두
currentColor기반 SVG를 tint하는 결과는 동일
테마 연동#
프로젝트 레벨 기본값은 CoreComponentTheme.icon에 CoreIconTheme.style로 지정합니다.
CoUIApp(
theme: CoreComponentTheme(
icon: CoreIconTheme(
style: CoreIconStyle(
size: 20,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
child: ...,
)
이후 iconStyle이 null이거나 size/color가 null인 모든 Icon은 위 default를 따릅니다.
크기 권장값#
| 용도 | 크기 |
|---|---|
| 인라인 텍스트 | 16.0 |
| 버튼 내 아이콘 | 20.0 |
| 기본 아이콘 | 24.0 |
| 강조 아이콘 | 32.0 |
| 히어로 아이콘 | 48.0 |
접근성 (Accessibility)#
- 아이콘은 시각적 요소이므로, 텍스트 레이블이 없는 독립 아이콘에는 tooltip 또는 부모
aria-label을 제공하세요 - Flutter:
Semanticswrapper 사용 -
Web:
<iconify-icon>은 기본적으로aria-hidden상태 — 의미 전달이 필요하면 부모 요소에aria-label지정