DotTheme
토큰, reset과 overlay가 적용되는 안전한 제품 경계를 만듭니다.
목적
DotTheme는 Dot의 semantic token, 최소 reset과 overlay portal이 적용되는 제품 경계를 만든다. 소비 앱의 body, router, shell을 소유하지 않으면서도 Dot 컴포넌트가 같은 색, 간격, focus와 surface 언어를 공유하게 한다.
Dot의 정체성은 단순한 색상 묶음이 아니다.
- Flexible: 화면 크기, 작업 밀도, 사용자 상태에 맞게 같은 의미가 적절한 형태로 적응한다.
- Link: 페이지와 overlay, 목록과 상세, 입력과 피드백 사이에서 토큰과 상호작용 맥락이 끊기지 않는다.
- Glow: 불확실한 순간의 방향을 제한적으로 밝히며 일반 UI를 장식하지 않는다.
선택 기준
- Dot 컴포넌트를 사용하는 제품 영역의 가장 가까운 공통 조상에 한 번 배치한다.
- 전체 앱이 Dot을 사용하면 app shell 안에서 route 콘텐츠와 overlay를 함께 감싼다.
- 다른 디자인 시스템과 공존하면 Dot 영역만 경계로 묶는다.
- 각 컴포넌트나 각 페이지마다 중복해서 감싸지 않는다.
구조
DotTheme는 다음을 렌더한다.
.dot-themeclass가 있는div- 전달된 children
- layout을 차지하지 않는 전용 portal container
Dot의 Radix 기반 overlay는 이 portal container를 사용해 document body로 theme 경계를 벗어나지 않는다. Dialog, Select, Popover, Tooltip 같은 layer도 같은 semantic token과 scoped reset을 유지한다.
변형과 크기
DotTheme는 색상 theme나 크기 variant를 제공하지 않는다. 하나의 semantic 계약을 제품 환경에 맞게 적용하며, root의 크기는 children과 소비 앱 layout이 결정한다.
- 밝고 어두운 임의 variant를 class 조합으로 만들어 DotTheme API처럼 취급하지 않는다.
- 전체 viewport를 감쌀 수도 있고 다른 시스템과 공존하는 부분 영역만 감쌀 수도 있다.
- 영역이 작아져도 semantic token의 의미를 바꾸지 않고 내부 component와 layout이 반응형으로 적응하게 한다.
상태와 동작
- mount되면 theme root와 portal container가 같은 경계 안에 준비된다.
- portal container가 준비되기 전에는 context를 사용하는 overlay portal을 렌더하지 않는다.
- hydration 전후에 다른 theme class를 임의로 교체하지 않는다.
- DotTheme는 route, 인증, 데이터와 focus 상태를 소유하지 않는다.
서버 렌더링과 hydration
DotTheme는 client component다.- 앱의 SSR 구조에서 DotTheme를 렌더할 수 있는 client boundary를 둔다.
- portal container가 준비되기 전에는 context를 사용하는 overlay portal이 렌더되지 않아 theme 밖으로 잠깐 나타나는 현상을 막는다.
- hydration 전후에 다른 theme class를 임의로 교체하지 않는다.
토큰 사용 원칙
- 제품 코드는 raw 색보다
surface-*,ink-*,line-*, 상태 semantic token을 사용한다. - 기본 본문, table, form에는 중립 surface와 ink를 우선한다.
- Glow gradient는 AI 안내, 의미 있는 전환, 브랜드 소개처럼 방향을 밝히는 드문 순간에만 사용한다.
- 상태는 색만으로 전달하지 않고 레이블, 아이콘, 설명을 함께 제공한다.
- 소비 앱의 전역 스타일이
.dot-theme내부 semantic 의미를 무효화하지 않게 한다.
콘텐츠
- DotTheme 자체는 사용자에게 보이는 문구를 만들지 않는다.
- theme 경계 안의 콘텐츠는 semantic surface, ink와 상태 token으로 정보 위계를 표현한다.
- Glow와 brand color가 제목, 상태 문구 또는 행동 레이블의 의미를 대신하지 않게 한다.
- overlay 콘텐츠도 trigger가 있던 페이지의 용어와 대상 이름을 이어서 사용한다.
Overlay와 맥락 연결
- overlay가 열린 위치와 닫힌 뒤 돌아갈 초점을 보존한다.
- 목록의 특정 행에서 열린 메뉴나 dialog는 닫힌 뒤 같은 행 또는 안전한 다음 위치로 돌아간다.
- overlay 내부에서 시작한 작업의 성공·실패가 바깥 페이지에 반영되었는지 명확히 알린다.
- 제품이 별도 portal primitive를 만들면 DotTheme 내부 container를 명시적으로 사용한다.
접근성
- DotTheme는 focus를 직접 이동하지 않는다. route와 개별 overlay가 focus lifecycle을 소유한다.
.dot-theme경계 안에서도 semantic HTML과 heading 순서를 유지한다.- focus indicator, contrast, reduced motion을 소비 앱 전역 override로 제거하지 않는다.
- theme 경계를 DOM landmark로 오해하지 않는다.
main,nav,aside는 별도로 구성한다.
좁은 화면과 긴 콘텐츠
- DotTheme는 반응형 layout을 강제하지 않는다.
PageScaffold, section과 각 component가 좁은 화면에 맞게 재배치되도록 충분한 root 폭을 제공한다. - viewport 높이를 고정해 긴 콘텐츠나 keyboard focus 대상을 잘라내지 않는다.
- overlay portal이 mobile viewport, safe area와 확대된 텍스트에서도 theme root 바깥으로 잘리지 않는지 확인한다.
- 다른 디자인 시스템과 나란히 배치될 때 경계용 wrapper가 불필요한 horizontal scroll을 만들지 않게 한다.
공개 API
DotThemeProps는 React.HTMLAttributes<HTMLDivElement>다.
| 속성 | 타입 | 설명 |
|---|---|---|
children | ReactNode | theme 안에서 렌더할 제품 UI |
className | string | theme root의 추가 class |
ref | Ref<HTMLDivElement> | theme root ref |
| 기타 | HTMLAttributes<HTMLDivElement> | id, data-*, aria-* 등 표준 div 속성 |
예제
import { DotTheme, PageScaffold } from '@classum/dot-design-system/ui';
export function AppSurface() {
return (
<DotTheme className="min-h-dvh bg-surface-canvas text-ink-default">
<PageScaffold>{/* routes */}</PageScaffold>
</DotTheme>
);
}피해야 할 사용
body스타일, router 또는 인증 상태를 DotTheme가 소유한다고 가정- 컴포넌트마다 DotTheme를 중첩
- overlay를 임의로 document body에 보내 token 경계를 끊는 구현
- raw 색상으로 semantic token을 반복해서 덮어쓰기
- Glow를 기본 primary, navigation 배경, table row에 광범위하게 사용
- theme root를 문서의 main landmark로 대신 사용