CoUI MockupWindow#
Quick Reference#
- Widget:
MockupWindow -
Variant: 없음 (variant 파라미터 없음) — "no semantic enums (no
variant, nosize)" - Size: 없음 (size 파라미터 없음)
-
Style slot:
mockupWindowStyle: CoreMockupWindowStyle(...)— the single per-instance style slot covering every chrome/colour/dimensional knob - Canonical snippet:
MockupWindow(
child: const Padding(
padding: EdgeInsets.all(16),
child: Text('Window content'),
),
)
한마디로#
MockupWindow는 화면 안에 "맥(macOS) 컴퓨터 창 모양의 액자"를 그려주는 부품입니다. 왼쪽 위에 빨강·노랑·초록 점 3개(신호등 버튼)가 달린 창 테두리를 만들고, 그 안에 원하는 내용(스크린샷, 데모 화면, 설명 등)을 넣어 보여줍니다. 진짜 창이 아니라 "창처럼 보이게 하는 장식 프레임"이라서, 점들을 눌러도 아무 일도 일어나지 않습니다. 랜딩 페이지에서 제품 화면을 그럴듯하게 연출할 때 쓰는 사진 액자라고 생각하면 됩니다.
무엇을·언제#
- 무엇을 해주나요: 내용물 위에 "제목 표시줄 + 신호등 점 3개"가 붙은 데스크톱 창 프레임을 씌워 줍니다. 테두리·둥근 모서리·배경색까지 알아서 통일된 모양으로 나옵니다.
- 언제 쓰이나요: 랜딩/소개 페이지에서 앱 화면을 창 안에 담아 보여줄 때, 문서·포트폴리오에서 데모 화면을 연출할 때, 디자인 시안에서 "이건 데스크톱 앱 화면이다"라고 표현하고 싶을 때 사용됩니다.
- 눌리는 건가요: 아니요. 빨강·노랑·초록 점은 순수한 장식이라 클릭/탭해도 동작하지 않습니다.
- 꾸밀 수 있나요: 배경색, 테두리색, 모서리 둥글기, 제목 표시줄 높이, 점 크기·색까지 세부 설정 한 곳(mockupWindowStyle)에서 바꿀 수 있습니다.
- 한 번 정해두면 통일됩니다: 앱(Flutter)과 웹 양쪽에서 같은 방식으로 만들어지고, 프로젝트 전체의 기본 모양을 한곳(테마)에서 정해둘 수도 있습니다.
- 형제 부품도 있습니다: 브라우저 창(MockupBrowser), 휴대폰 프레임(MockupPhone), 코드 화면(MockupCode)도 같은 계열의 "연출용 액자"입니다.
핵심 용어#
| 용어 | 쉬운 설명 |
|---|---|
| MockupWindow | 맥 스타일 창 모양을 흉내 내는 장식용 액자 부품 |
| title bar (제목 표시줄) | 창 맨 위의 가로 띠 — 신호등 점 3개가 들어가는 자리 |
| traffic light (신호등 점) | 왼쪽 위 빨강(닫기)·노랑(최소화)·초록(최대화) 장식 점 3개 |
| child | 창 안에 넣는 내용물 (스크린샷, 텍스트, 데모 화면 등) |
| mockupWindowStyle | 이 창 하나만 다르게(색·크기·모서리 등) 꾸미는 세부 설정 칸 |
| theme / theming | 프로젝트 전체 창 액자에 공통 적용되는 기본 모양 설정 |
| Flutter | 모바일/앱 화면을 만드는 기술 |
| Web | 웹 브라우저용 화면을 만드는 기술 |
| Legacy / Deprecated | 옛날 방식이라 새 코드에서는 쓰지 말아야 하는, 곧 사라질 항목 |
Overview#
MockupWindow is the unified cross-platform OS-window mockup: an outer frame with a title bar carrying three macOS-style traffic-light dots (close/minimize/maximize) above a content slot. It is a pure display component — the dots are decorative, there are no callbacks, and there are
no semantic enums (no variant, no size). The entire surface is:
-
child— optional window content (Widget?on Flutter,Component?on Web). -
mockupWindowStyle— the single per-instance style slot (CoreMockupWindowStyle), covering every chrome/colour/dimensional knob.
It implements the shared CoreMockupWindowContract<W> from coui_core, so Flutter and Web take the same style type and resolve through the same chain. Sibling mockups in the same family:
MockupBrowser, MockupPhone, MockupCode — all recolourable at once via the shared
CoreMockupTheme.
Rendered structure (both platforms):
frame (background, border, borderRadius, clipped)
├─ title bar (height, horizontal padding, bottom border)
│ ├─ dot: close (red #FF5F57)
│ ├─ dot: minimize (amber #FFBD2E)
│ └─ dot: maximize (green #28C840)
└─ content (child)
Flutter (coui_flutter)#
Import#
import 'package:coui_flutter/coui_flutter.dart';
Single barrel only — never import src/ paths.
Basic Usage#
MockupWindow(
child: const Padding(
padding: EdgeInsets.all(16),
child: Text('Window content'),
),
)
child is optional — omit it to render just the empty frame with its title bar:
const MockupWindow()
The frame clips its content (clipBehavior: antiAlias), so images or colored children are trimmed to the rounded corners automatically. The column is
mainAxisSize: min / crossAxisAlignment: stretch — the window hugs its content height and stretches content to the frame width.
Screenshot / demo frame pattern#
MockupWindow(
child: SizedBox(
height: 300,
child: Center(child: Text('App preview')),
),
)
Per-instance Style (mockupWindowStyle)#
mockupWindowStyle takes a CoreMockupWindowStyle. All fields are optional; anything unset falls back through the theme chain to the design-system defaults.
MockupWindow(
mockupWindowStyle: const CoreMockupWindowStyle(
borderRadius: CoreBorderRadius.all(CoreRadius.radius8),
titleBarHeight: 32,
trafficLightSize: 10,
),
child: const Text('Compact window'),
)
Recolour example (token-bound frame + custom dots):
MockupWindow(
mockupWindowStyle: const CoreMockupWindowStyle(
backgroundColor: CoreColor.token(CoreColors.surface),
borderColor: CoreColor.token(CoreColors.outline),
trafficLightCloseColor: CoreColor(0xFF888888),
trafficLightMinimizeColor: CoreColor(0xFF888888),
trafficLightMaximizeColor: CoreColor(0xFF888888),
),
child: const Text('Monochrome chrome'),
)
Flutter-specific behavior notes#
-
All dimensional values (radius, title-bar spacing/padding/height, dot size/radius) are pre-multiplied by
theme.scalingin the resolver — the widget paints them as-is. -
Colours resolve through
theme.colorSchemeto paint-readyColors; the title bar's bottom divider uses the same resolvedborderColoras the outer frame. -
Dot spacing flows into
Row.spacing(titleBarSpacingis a scalar, logical px).
Web (coui_web / Jaspr)#
Import#
import 'package:coui_web/coui_web.dart';
Basic Usage#
child is a Jaspr Component:
MockupWindow(
child: div([text('Window content')], classes: 'p-4'),
)
Multiple content blocks (children)#
Web additionally accepts a children: List<Component>? — rendered before child
inside the frame:
MockupWindow(
children: [
div([text('Toolbar')], classes: 'p-2'),
div([text('Body')], classes: 'p-4'),
],
)
Per-instance Style (same CoreMockupWindowStyle)#
MockupWindow(
mockupWindowStyle: const CoreMockupWindowStyle(
borderRadius: CoreBorderRadius.all(CoreRadius.radius8),
),
child: div([text('Custom radius')]),
)
Colour channels are class-XOR-inline: a token colour (default or token override, e.g. the surface
background / outline border) emits a Tailwind bg-*/border-* class and stays dark-mode reactive; a raw
CoreColor(0xFF...) override goes inline. The traffic-light defaults are raw macOS palette values, so they render as inline
background-color. All dimensional values (radius, gap, padding, height, dot size) are always inline rem — never utility classes.
Web-only constructor extras#
The Web constructor also accepts tag (root element tag, default 'div'), id,
classes, css (Jaspr Styles), attributes, and eventHandlers. User
classes are merged after the resolved class string; user css is combined after the resolved inline styles. The component also provides
copyWith(...).
MockupWindow(
classes: 'max-w-3xl mx-auto',
child: div([text('Hero demo')]),
)
Note: the Web root carries w-full — it fills its container's width (constrain it with a wrapper or
classes as above), whereas the Flutter frame just follows its parent constraints.
Parameters#
| Parameter | Type (Flutter) | Type (Web) | Default | Notes |
|---|---|---|---|---|
child |
Widget? |
Component? |
null |
Window content (optional — empty frame is valid) |
mockupWindowStyle |
CoreMockupWindowStyle? |
CoreMockupWindowStyle? |
null |
Single per-instance chrome/colour/dimension slot |
Web-only: children (List<Component>?, rendered before child),
tag (default 'div'), id, classes, css
(Jaspr Styles), attributes, eventHandlers, plus copyWith(...).
There are no variant / size enums on this component — MockupWindow
is a single-form display frame; every visual knob lives on the style slot below.
Style slot — CoreMockupWindowStyle (full field set + defaults)#
Constructor fields (all optional) and their design-system defaults (statics on CoreMockupWindowStyle, shared by Flutter and Web):
| Field | Type | Default (static) | Value |
|---|---|---|---|
backgroundColor |
CoreColor? |
defaultBackgroundColor |
token surface |
borderColor |
CoreColor? |
defaultBorderColor |
token outline (frame + title-bar divider) |
borderRadius |
CoreBorderRadius? |
defaultBorderRadius |
CoreBorderRadius.all(CoreRadius.radius16) |
titleBarSpacing |
double? |
defaultTitleBarSpacing |
CoreSpace.space8 (gap between dots, logical px) |
titleBarPadding |
CoreEdgeInsets? |
defaultTitleBarPadding |
CoreEdgeInsets.symmetric(horizontal: CoreSpace.space12) |
titleBarHeight |
double? |
defaultTitleBarHeight |
CoreSpace.space40 (logical px) |
trafficLightSize |
double? |
defaultTrafficLightSize |
CoreSpace.space12 (logical px) |
trafficLightBorderRadius |
CoreBorderRadius? |
defaultTrafficLightBorderRadius |
CoreBorderRadius.all(CoreRadius.radius9999) (perfect circle) |
trafficLightCloseColor |
CoreColor? |
defaultTrafficLightCloseColor |
raw CoreColor(0xFFFF5F57) (macOS red) |
trafficLightMinimizeColor |
CoreColor? |
defaultTrafficLightMinimizeColor |
raw CoreColor(0xFFFFBD2E) (macOS yellow) |
trafficLightMaximizeColor |
CoreColor? |
defaultTrafficLightMaximizeColor |
raw CoreColor(0xFF28C840) (macOS green) |
CoreMockupWindowStyle also exposes merge(other) and copyWith(...).
Project-level theming#
Two theme slots participate, both { style }-shaped:
-
CoreMockupWindowTheme(coreComponentTheme.mockupWindow) — window-specific project defaults, carries a fullCoreMockupWindowStyle. -
CoreMockupTheme(coreComponentTheme.mockup) — shared across all mockup variants (Browser/Code/Phone/Window). ItsCoreMockupStyleexposes onlybackgroundColor/borderColor/frameColor/borderRadius; the Window resolver consumes the first three minusframeColor(phone-only) — i.e. background, border, and radius can be recoloured for every mockup frame at once.
Resolve chain (lowest → highest priority; identical on both platforms):
CoreMockupWindowStyle design-system defaults
→ CoreMockupTheme.style // shared cross-variant (bg/border/radius only)
→ CoreMockupWindowTheme.style // 프로젝트 공통
→ widget.mockupWindowStyle // 인스턴스별
const CoreMockupWindowTheme(
style: CoreMockupWindowStyle(
borderRadius: CoreBorderRadius.all(CoreRadius.radius8),
titleBarHeight: 32,
),
)
Register it on the app theme's coreComponentTheme.mockupWindow slot; the shared recolour goes on
coreComponentTheme.mockup (CoreMockupTheme(style: CoreMockupStyle(...))). Both platform resolvers read the same two slots.
Flutter ↔ Web Differences#
| Aspect | Flutter | Web |
|---|---|---|
| Widget class | MockupWindow (StatelessWidget, CoreMockupWindowContract<Widget>) |
MockupWindow (UiComponent, CoreMockupWindowContract<Component>) |
| Child type | Widget? |
Component? + extra children: List<Component>? |
| Content order | title bar → child |
title bar → ...children → child |
| Render | Container + Column, clipBehavior: antiAlias |
element (default
<div>
, configurable
tag
) with Tailwind className + inline styles,
overflow-hidden relative
|
| Width behavior | follows parent constraints | root gets w-full (fills container) |
| Dimensions | pre-multiplied by theme.scaling, painted as logical px |
emitted as inline rem CSS |
| Colours | resolved via theme.colorScheme to paint-ready Color |
token → Tailwind class (dark-mode reactive); raw ARGB → inline CSS |
| Extra ctor params | — |
tag
,
id
,
classes
,
css
,
attributes
,
eventHandlers
; also
copyWith(...)
|
Shared on both: mockupWindowStyle: CoreMockupWindowStyle, CoreMockupWindowTheme
/ shared CoreMockupTheme resolve chain, decorative-only traffic lights (no callbacks anywhere).
Pitfalls#
- The traffic-light dots (close/minimize/maximize) are purely decorative — "the dots are decorative, there are no callbacks" — clicking/tapping them does nothing.
-
On Web the root element carries
w-fulland fills its container by default, unlike Flutter which just follows parent constraints — constrain it with a wrapper or your ownclassesif you don't want full width. -
The shared
CoreMockupTheme'sCoreMockupStylealso exposes aframeColorfield, but the Window resolver only consumesbackgroundColor/borderColor/borderRadiusfrom it —frameColoris phone-only and has no effect onMockupWindow. -
v0.127 is a de-prefix hard break: the old
Co-prefixed class (CoMockupWindow) has no alias — it was removed outright, not just deprecated, while app-shell exceptions likeCoUIApp,CoUILocalizations,CoUIScrollBehaviorkeep their prefix. -
On Web, colour channels are class-XOR-inline: token colours (defaults/overrides) emit Tailwind
bg-*/border-*classes and stay dark-mode reactive, but a rawCoreColor(0xFF...)override (e.g. custom traffic-light colours) renders as inline CSS instead.
v0.127 Migration (Legacy)#
v0.127 is a de-prefix hard break: the widget class was renamed and no Co-prefixed alias remains.
Core* contract names (CoreMockupWindowStyle, CoreMockupWindowTheme,
CoreMockupTheme, CoreMockupWindowContract) are unchanged.
| ❌ Legacy (pre-0.127, removed) | ✅ v0.127 |
|---|---|
❌ CoMockupWindow(child: …) | MockupWindow(child: …) |
❌ CoMockupBrowser(…) (sibling) | MockupBrowser(…) |
❌ CoMockupPhone(…) (sibling) | MockupPhone(…) |
❌ CoMockupCode(…) (sibling) | MockupCode(…) |
Additional migration notes:
-
Migration is rename-only for this component: ❌
CoMockupWindow(...)→MockupWindow(...)with identical parameters (child,mockupWindowStyle). -
App-shell exceptions that keep the prefix:
CoUIApp,CoUILocalizations,CoUIScrollBehavior. -
Import stays the single barrel:
package:coui_flutter/coui_flutter.dart/package:coui_web/coui_web.dart— neversrc/paths.