설치
CoUI 패키지 설치 가이드
목차
CoUI는 아직 pub.dev에 배포되지 않았습니다(coui_flutter/coui_web 모두
publish_to: none) — flutter pub add / dart pub add
대신 git 태그를
참조해 설치합니다.
패키지 선택#
| 패키지 | 용도 |
|---|---|
coui_flutter | Flutter 앱 (Mobile, Desktop, Web) |
coui_web | Jaspr 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 파일 |
|---|---|---|
| 100 | Geist-Thin.otf | GeistMono-Thin.otf |
| 200 | Geist-UltraLight.otf | GeistMono-UltraLight.otf |
| 300 | Geist-Light.otf | GeistMono-Light.otf |
| 800 | Geist-Black.otf | GeistMono-Black.otf |
| 900 | Geist-UltraBlack.otf | GeistMono-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-icons4: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을 직접 읽으므로 항상 최신입니다).