Card | CoUI

Card

슬롯 기반 레이아웃을 제공하는 카드 컨테이너 컴포넌트

Card#

관련 정보를 하나의 단위로 묶어 표시하는 컨테이너 컴포넌트입니다. media/header/body/footer/overlay 슬롯을 제공합니다.

Live Preview#

사용 시기 (When to Use)#

이 컴포넌트를 사용하세요:

  • 관련 정보를 하나의 단위로 묶어 표시할 때 (프로필, 상품, 게시물 등)
  • 시각적으로 콘텐츠를 구분하고 계층을 만들 때
  • 클릭 가능한 콘텐츠 블록이 필요할 때

대신 다른 컴포넌트를 사용하세요:

  • Accordion: 접고 펼 수 있는 콘텐츠 섹션이 필요할 때
  • Table: 구조화된 데이터를 행과 열로 표시할 때
  • Dialog: 임시 콘텐츠를 모달로 표시할 때

기본 사용법 (Basic Usage)#

// 기본 카드 (outlined, no elevation)
CoCard(
  body: Text('카드 내용'),
)

// 슬롯 기반 레이아웃
CoCard(
  header: Text('제목'),
  body: Text('본문 내용입니다.'),
  footer: Text('푸터'),
)

// variant + elevation (chrome / dimensional 은 cardStyle 로 통합)
CoCard(
  variant: CoreComponentVariant.filled,
  cardStyle: CoreCardStyle(
    elevation: CoreCardElevation.medium,
  ),
  body: Text('강조된 카드'),
)

// 클릭 가능
CoCard(
  onTap: () => print('clicked'),
  body: Text('Click me'),
)

스타일 시스템 — cardStyle (Epic #1302)#

CoCard 의 모든 chrome / dimensional 오버라이드는 단일 cardStyle 필드(CoreCardStyle) 하나로 흐릅니다. 이전 버전의 flat 필드(width, padding, boxShadow, elevation 등)는 모두 CoreCardStyle 안의 nullable 필드로 옮겨졌습니다.

CoCard(
  variant: CoreComponentVariant.outlined,
  cardStyle: CoreCardStyle(
    padding: EdgeInsets.all(CoreSpace.space24),
    borderRadius: BorderRadius.circular(12),
    backgroundColor: theme.colorScheme.surfaceContainer,
    elevation: CoreCardElevation.soft,
    sizing: CoreCardSizing.fixed,
    width: 320,
  ),
  header: Text('제목'),
  body: Text('본문'),
)

머지 체인 (Merge Chain)#

cardStyle 은 다음 체인을 거쳐 최종 값으로 해석됩니다 (오른쪽이 이김):

design system default
  → CoreCardTheme.style                        // 프로젝트 공통
  → CoreCardTheme.variantStyles[variant]       // variant 별 오버라이드
  → 부모 컴포넌트 슬롯 오버라이드              // 예: TimePicker.popoverPanelStyle
  → widget.cardStyle                           // 인스턴스별 오버라이드

각 레이어는 CoreCardStyle 의 어떤 필드든 부분적으로 채울 수 있습니다. null 인 필드는 다음 레이어로 넘겨주고, non-null 인 필드는 해당 레이어에서 확정됩니다.

테마 적용#

ThemeData.fromCore(
  coreComponentTheme: CoreComponentTheme(
    card: CoreCardTheme(
      style: CoreCardStyle(
        // 모든 카드에 적용되는 기본
        borderRadius: BorderRadius.circular(16),
        padding: EdgeInsets.all(CoreSpace.space20),
      ),
      variantStyles: {
        CoreComponentVariant.filled: CoreCardStyle(
          backgroundColor: theme.colorScheme.primaryContainer,
        ),
      },
    ),
  ),
)

Props / Parameters#

속성타입기본값설명
variant CoreComponentVariant .outlined 시각적 variant (filled / outlined)
media Widget? / Component? null 상단 미디어 영역 (이미지 등)
header Widget? / Component? null 헤더 영역
body Widget? / Component? null 본문 영역
footer Widget? / Component? null 푸터 영역
overlay Widget? / Component? null media 위에 오버레이
child Widget? / Component? null 커스텀 자식 (slot 대신)
onTap VoidCallback? null 탭/클릭 핸들러
cardStyle CoreCardStyle? null chrome + dimensional 오버라이드 묶음 (아래 표 참고)

CoreCardStyle 필드#

필드타입설명
padding EdgeInsetsGeometry? / double? 내부 패딩
borderRadius BorderRadiusGeometry? / double? 보더 반경
borderWidth double? 보더 두께 (logical px, pre-scaling)
backgroundColorColor? / String?배경색
borderColorColor? / String?보더 색상
boxShadow List<BoxShadow>? / String? 커스텀 그림자 (elevation 보다 우선)
headerBodyGapdouble?헤더-바디 간격 (logical px)
bodyFooterGapdouble?바디-푸터 간격 (logical px)
durationDuration?전환 애니메이션 지속 시간
width double? 고정 너비 (sizing이 .fixed 일 때)
height double? 고정 높이 (sizing이 .fixed 일 때)
sizing CoreCardSizing? 크기 결정 방식 (intrinsic / expand / fixed)
elevation CoreCardElevation? 그림자 수준 (none / soft / medium / strong)
clipBehaviorClip? / bool?클리핑 동작

변형 (Variants)#

Outlined (기본)#

CoCard(
  variant: CoreComponentVariant.outlined,
  body: Text('외곽선만'),
)

Filled#

CoCard(
  variant: CoreComponentVariant.filled,
  body: Text('배경색 채움'),
)

Elevation 단계#

CoCard(
  cardStyle: CoreCardStyle(elevation: CoreCardElevation.none),
  body: Text('평면'),
)
CoCard(
  cardStyle: CoreCardStyle(elevation: CoreCardElevation.soft),
  body: Text('약한 그림자'),
)
CoCard(
  cardStyle: CoreCardStyle(elevation: CoreCardElevation.medium),
  body: Text('중간 그림자'),
)
CoCard(
  cardStyle: CoreCardStyle(elevation: CoreCardElevation.strong),
  body: Text('강한 그림자'),
)

미디어 카드 (이미지 + 콘텐츠)#

CoCard(
  media: Image.network('https://example.com/photo.jpg'),
  header: Text('상품명'),
  body: Text('상품 설명'),
  footer: Text('가격'),
)

동작 스펙 (Behavior)#

인터랙션#

  • 탭/클릭: onTap 설정 시 전체 카드 영역 클릭 가능
  • 호버 (onTap 있을 때): 커서가 pointer 로 변경 + hover shadow 애니메이션

애니메이션#

  • elevation 전환: 200ms (CoreDuration.normal)
  • hover shadow: cardStyle.duration (기본 200ms)

접근성 (Accessibility)#

시맨틱#

  • Flutter: 기본 Container (onTap 있을 때 MouseRegion + GestureDetector)
  • Web: <div> (onTap 있을 때 role="button", tabindex="0")

키보드#

  • onTap 설정 시 Enter / Space 로 활성화 가능

크로스 플랫폼 차이점 (Platform Differences)#

항목FlutterWeb
클래스명CoCardCoCard
구조slot 기반 (media / header / body / footer / overlay)slot 기반 (동일)
스타일 제네릭 CoreCardStyle<Color, EdgeInsetsGeometry, BorderRadiusGeometry, List<BoxShadow>, Clip> CoreCardStyle<String, double, double, String, bool>
그림자 CoreCardElevation.* (BoxShadow) CoreCardElevation.* (CSS shadow class)
테마 CoreCardTheme (Flutter 형) CoreCardTheme (Web 형)

마이그레이션 (Epic #1302)#

이전 버전에서는 chrome / dimensional 필드가 위젯의 flat 파라미터였습니다. 이제 모두 cardStyle: CoreCardStyle(...) 안으로 이동했습니다.

// Before — flat 필드
CoCard(
  width: 240,
  padding: EdgeInsets.all(16),
  elevation: CoreCardElevation.soft,
  borderRadius: BorderRadius.circular(12),
  body: Text('...'),
)

// After — cardStyle 묶음
CoCard(
  cardStyle: CoreCardStyle(
    sizing: CoreCardSizing.fixed,
    width: 240,
    padding: EdgeInsets.all(16),
    elevation: CoreCardElevation.soft,
    borderRadius: BorderRadius.circular(12),
  ),
  body: Text('...'),
)

기존 외부 프로젝트 호환을 위해 마이그레이션 도우미는 제공하지 않으며, 각 사용처를 직접 새 API 로 옮겨주세요. CoCard 자신과 모든 co_*.dart 사용처는 sweep 완료된 상태입니다.

  • Accordion: 접고 펼 수 있는 섹션
  • Badge: Card 안에 상태 표시