설치 | CoUI
본문으로 건너뛰기
LogoCoUI

설치

CoUI 패키지 설치 가이드

목차

CoUI는 아직 pub.dev에 배포되지 않았습니다(coui_flutter/coui_web 모두 publish_to: none) — flutter pub add / dart pub add 대신 git 태그를 참조해 설치합니다.

패키지 선택#

패키지용도
coui_flutterFlutter 앱 (Mobile, Desktop, Web)
coui_webJaspr Web 앱
coui_core 공유 유틸리티 (coui_flutter/coui_web가 자동 포함, 별도 설치 불필요)

저장소 접근 안내

CoUI 저장소는 공개 준비 중이며 현재는 비공개입니다. 아래 설치 방법은 공개 이후 그대로 동작하며, 그전까지는 저장소 접근 권한이 필요합니다.

  • 계약 고객에게는 프로젝트에 사용한 버전의 소스 사본을 프로젝트 저장소에 함께 인도합니다.
  • 그 외 접근이 필요하시면 cody@cocode.im 으로 연락 주세요.

컴포넌트 카탈로그와 문서는 이 사이트에서 계정 없이 그대로 보실 수 있습니다.

Flutter#

pubspec.yaml#

dependencies:
  coui_flutter:
    git:
      url: https://github.com/coco-de/coui.git
      path: packages/coui_flutter

최소 요구사항#

  • Flutter 3.47.0+
  • Dart 3.11.0+
  • Material Design (uses-material-design: true)

글꼴#

본문 서체 Pretendard 는 앱이 제공합니다. 코드 서체 Geist Mono 는 coui_flutter 가 GeistMono 로 함께 싣고 있어서, 코드 역할(code*)은 앱이 아무것도 넣지 않아도 그 서체로 그려집니다 — Geist Mono 에 없는 한글은 Pretendard 로 그려집니다. 함께 싣는 GeistSans 는 본문 서체 뒤의 fallback 이라, 앱이 Pretendard 를 제공하지 않아도(테스트, 글꼴 없는 앱) 같은 메트릭으로 그려지게 합니다.

Flutter web 은 패키지가 선언한 글꼴을 첫 프레임 전에 전부 내려받습니다. 그래서 Geist 는 컴포넌트 토큰이 쓰는 굵기 400 · 500 · 600 · 700 만 선언되어 있습니다. 앱이 서체를 제공하지 않으면서 그 밖의 굵기(100 · 200 · 300 · 800 · 900)를 Geist 로 그려야 한다면, 필요한 굵기만 앱 pubspec.yaml 에서 직접 선언합니다. 선언하지 않은 굵기는 가장 가까운 선언된 굵기로 그려집니다(예: 900 → 700).

flutter:
  fonts:
    # family 이름을 패키지와 같게 두어야 CoUI 의 fallback 체인이 집어 간다.
    - family: packages/coui_flutter/GeistSans
      fonts:
        - asset: packages/coui_flutter/fonts/Geist-UltraBlack.otf
          weight: 900
굵기GeistSans 파일GeistMono 파일
100Geist-Thin.otfGeistMono-Thin.otf
200Geist-UltraLight.otfGeistMono-UltraLight.otf
300Geist-Light.otfGeistMono-Light.otf
800Geist-Black.otfGeistMono-Black.otf
900Geist-UltraBlack.otfGeistMono-UltraBlack.otf

GeistMono 는 family 를 packages/coui_flutter/GeistMono 로 둡니다.

아이콘 글꼴

CoUI 의 Icon 은 LucideIcons 같은 IconName 을 SVG 로 그리므로 아이콘 글꼴이 필요 없고, coui_flutter 는 아이콘 글꼴을 선언하지 않습니다. 글꼴 파일(LucideIcons.ttf · BootstrapIcons.otf · RadixIcons.otf)은 패키지에 그대로 있어, 앱이 Flutter IconData 로 그 글꼴을 직접 그린다면 앱 pubspec.yaml 에서 선언합니다. 앱 코드의 IconData 가 const 이면 릴리스 빌드의 아이콘 트리 셰이커가 실제로 쓰는 글리프만 남깁니다.

flutter:
  fonts:
    # IconData(fontFamily: 'LucideIcons', fontPackage: 'coui_flutter') 가 찾는 이름.
    - family: packages/coui_flutter/LucideIcons
      fonts:
        - asset: packages/coui_flutter/icons/LucideIcons.ttf

테마 설정#

CoUI Flutter는 CoreComponentTheme를 ThemeData.fromCore에 넘겨 테마를 관리합니다(상세: 테마 가이드):

CoUIApp(
  theme: ThemeData.fromCore(
    CoreThemePresets.light,
    coreComponentTheme: const CoreComponentTheme(
      // 개별 컴포넌트 테마 커스터마이징
      button: CoreButtonTheme(
        style: CoreButtonStyle(
          borderRadius: CoreBorderRadius.all(CoreRadius.radius12),
        ),
      ),
    ),
  ),
  home: MyHomePage(),
)

Jaspr Web#

pubspec.yaml#

dependencies:
  coui_web:
    git:
      url: https://github.com/coco-de/coui.git
      path: packages/coui_web

최소 요구사항#

  • Dart 3.11.0+
  • Jaspr 0.23.2+

Tailwind CSS + 디자인 토큰 (<head>)#

CoUI Web은 Tailwind 유틸리티 클래스로 렌더하고, 그 클래스가 참조하는 값은 --coui-* CSS 변수에서 옵니다. 그래서 <head>에 Tailwind 자체와 CoUI가 만든 config·변수를 함께 넣어야 합니다.

import 'package:coui_web/coui_web.dart';

final config = ThemeConfig.defaults();

final head = <Component>[
  // Tailwind가 먼저 — 아래 config가 이 CDN이 정의한 전역에 할당합니다.
  Component.element(
    tag: 'script',
    attributes: {'src': 'https://cdn.tailwindcss.com/3.4.17'},
  ),
  Component.element(tag: 'script', children: [RawText(config.tailwindConfig)]),
  // 라이트 `:root { --coui-* }`
  Component.element(tag: 'style', children: [RawText(config.cssVariables)]),
];

이 단계를 빠뜨리면 색·여백·반경·글자 크기가 통째로 죽고 flex·grid 같은 구조 유틸리티만 남습니다.

다크 변수는 <style>로 넣지 마세요. Tailwind CDN의 JIT 스캐너가 그 안의 다크 값을 스캔해 라이트 모드를 덮습니다. 런타임에 <style> 요소를 만들어 붙이는 <script>로 우회합니다 — 내용은 config.darkVariableBlock + config.surfaceStyleVariableBlocks입니다.

Tailwind 는 정확한 v3 릴리스로 고정하세요. 버전 없는 cdn.tailwindcss.com 은 CDN 이 그날 내주는 릴리스를 따라갑니다. CoUI 의 색 강제 모드 포커스 교정은 v3 의 outline-none 이 투명 outline 을 남긴다는 데 기대므로, 그 의미를 바꾸는 릴리스 하나로 코드 변경 없이 교정이 무효가 됩니다.

CDN 을 쓸 수 없는 환경(엄격한 CSP · 오프라인 빌드). coui_web 이 스스로 외부에서 받는 자산은 둘입니다. 아이콘 폴백 스크립트는 iconScript(src: …) 로 자체 호스팅 경로를 주고, PhoneInput 의 국기 SVG 는 flag-icons 4:3 세트를 미러한 뒤 페이지를 CouiAssetSourceScope(flagIconsBaseUrl: …) 로 감쌉니다. 둘 다 지정하지 않으면 기본 CDN 을 그대로 씁니다.

Tailwind reset(preflight)이 꺼져 있습니다. tailwindConfig는 corePlugins: {preflight: false}이므로 브라우저 기본 스타일 초기화가 필요하면 앱이 직접 넣어야 합니다.

서버 엔트리포인트에서 package:jaspr/server.dart를 함께 import 하면 runApp· Document·Text가 두 배럴에 모두 있어 이름이 충돌합니다. 한쪽에 show/hide를 거세요.

글꼴 (<head>)#

Web 의 글꼴 스택은 --coui-font-family-sans("Pretendard", system-ui, sans-serif)와 --coui-font-family-mono("Geist Mono", "Pretendard", monospace)입니다. coui_web 은 서체 파일을 싣지 않으므로 앱이 둘 다 불러옵니다. Geist Mono 를 빠뜨리면 코드 역할이 Pretendard 로 떨어져 고정폭이 아니게 됩니다 — 줄 번호와 코드가 맞춰 앉던 글자 격자가 무너집니다.

Flutter 와 글리프까지 같게 그리려면 coui_flutter 가 번들한 것과 같은 정적 OTF(GeistMono-Regular · -Medium · -SemiBold · -Bold, 저장소의 packages/coui_flutter/lib/fonts/)를 앱이 서빙하고 @font-face 로 잇습니다.

// 앱이 /fonts/ 에 서빙하는 경우. 굵기마다 한 규칙 — 코드 역할은 400 이고,
// 서페이스 스타일의 굵기 하한이 600 까지 올릴 수 있습니다.
const monoFaces = {400: 'Regular', 500: 'Medium', 600: 'SemiBold', 700: 'Bold'};
final monoFontFaceCss = [
  for (final MapEntry(key: weight, value: name) in monoFaces.entries)
    "@font-face{font-family:'Geist Mono';font-weight:$weight;"
    "font-display:swap;src:url('/fonts/GeistMono-$name.otf') format('opentype')}",
].join();

final fontHead = <Component>[
  Component.element(
    tag: 'link',
    attributes: {
      'rel': 'stylesheet',
      'href': 'https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/static/pretendard.min.css',
    },
  ),
  Component.element(tag: 'style', children: [RawText(monoFontFaceCss)]),
];

글꼴 CDN 의 Geist Mono 도 같은 이름이라 스택이 집어 가지만, Flutter 가 번들한 판보다 새로운 판이라 글자 모양과 폭이 조금 다를 수 있습니다.

앱 루트#

컴포넌트를 쓰기 전에 트리 최상단을 CoUIWeb으로 감쌉니다 — Flutter CoUIApp의 대응입니다.

import 'package:coui_web/coui_web.dart';

class MyApp extends StatelessComponent {
  const MyApp({super.key});

  @override
  Component build(BuildContext context) {
    return CoUIWeb(
      theme: ThemeData.coui,
      child: MyHomePage(),
    );
  }
}

감싸지 않으면 테마를 읽는 첫 컴포넌트에서 No Theme found in context로 실패합니다. CoUIWeb은 테마 외에 오버레이 호스트·아이콘 기본 크기·루트 캐스케이드도 함께 설치합니다 — 시작하기 참고.

개발 환경#

Git 클론 (로컬 개발)#

# 모노레포 로컬 개발 시
dependencies:
  coui_flutter:
    path: ../coui/packages/coui_flutter
  coui_web:
    path: ../coui/packages/coui_web

버전 고정#

위 git: 의존성은 기본적으로 main의 최신 커밋을 따라갑니다. 특정 릴리스에 고정하려면 ref:에 그 패키지의 태그를 지정하세요 — 정확한 현재 버전과 태그 값, 릴리스 노트는 Changelog 페이지에서 확인할 수 있습니다(빌드 시점에 pubspec.yaml을 직접 읽으므로 항상 최신입니다).