์ƒ‰์ƒ | CoUI
๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
LogoCoUI

์ƒ‰์ƒ

CoUI ์‹œ๋งจํ‹ฑ ์ƒ‰์ƒ ํ† ํฐ โ€” ์—ญํ•  ์„ ํƒ๊ณผ ๋Œ€๋น„ ํŽ˜์–ด๋ง. CoreColors ๊ฐ€ ๋‹จ์ผ ์ถœ์ฒ˜์ž…๋‹ˆ๋‹ค.

๋ชฉ์ฐจ

Figma Foundation ยท 01. Color ยท ๊ฐ’์€ coui_core ๊ฐ€ ์ •๋ณธ์ž…๋‹ˆ๋‹ค. ์ •๋ณธ ํŒŒ์ผ์€ Figma ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ.

์ด ํŽ˜์ด์ง€๋Š” ์—ญํ• ์„ ๊ณ ๋ฅด๊ณ , ์ง€๊ธˆ ํ…Œ๋งˆ์˜ ์‹ค์ œ ๊ฐ’์„ ์Šค์™€์น˜๋กœ ํ™•์ธํ•˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ๊ฐ’์€ coui_core ์˜ CoreColors ๊ฐ€ ์ •ํ•˜๊ณ , Flutter ColorScheme ๊ณผ Web --coui-* ๋ณ€์ˆ˜๊ฐ€ ๊ฐ™์€ ์ด๋ฆ„์„ ์ฝ์Šต๋‹ˆ๋‹ค.

ํŒ”๋ ˆํŠธ hex ๋ฅผ ์•ฑ์— ๋ณต์‚ฌํ•˜์ง€ ๋งˆ์„ธ์š”. ๋ผ์ดํŠธ/๋‹คํฌ์™€ ์„œํŽ˜์ด์Šค ์Šคํƒ€์ผ์ด ํ† ํฐ ๊ฐ’์€ ๋ฐ”๊พธ๊ณ , ์ด๋ฆ„์€ ๊ทธ๋Œ€๋กœ ๋‘ก๋‹ˆ๋‹ค. ํ† ํฐ ์ถ• ์ „์ฒด๋Š” ๋””์ž์ธ ํ† ํฐ ์„ ๋ณด์„ธ์š”.

์–ธ์ œ ์“ฐ๋‚˜#

์‹œ๋งจํ‹ฑ ํ† ํฐ์„ ๊ณ ๋ฅด์„ธ์š”

  • ๋ฐฐ๊ฒฝ ยท ๊ธ€์ž ยท ๋ณด๋” ยท ์ƒํƒœ ์ƒ‰์„ ์ค„ ๋•Œ โ€” primary, onSurface, error ์ฒ˜๋Ÿผ ์—ญํ• ์„ ๊ณ ๋ฆ…๋‹ˆ๋‹ค
  • ์ปดํฌ๋„ŒํŠธ Style (backgroundColor: CoreColor.token(CoreColors.surface)) ์ด๋‚˜ Text('โ€ฆ').onSurface

์“ฐ์ง€ ๋งˆ์„ธ์š”

  • #RRGGBB / Color(0xFFโ€ฆ) ๋ฅผ ์œ„์ ฏ์— ๋ฐ•๊ธฐ โ€” ๋‹คํฌ ๋ชจ๋“œ์™€ ์„œํŽ˜์ด์Šค ์Šคํƒ€์ผ์ด ๋น„๊ปด๊ฐ‘๋‹ˆ๋‹ค
  • "์ด ๋ฒ„ํŠผ์€ ํŒŒ๋ž‘"์ฒ˜๋Ÿผ ์›์‹œ ์ƒ‰์„ ๊ณ ๋ฅด๊ธฐ โ€” ์ฑ„์›€์€ ์—ญํ• (primary, accent)์„ ๊ณ ๋ฆ…๋‹ˆ๋‹ค

primary ์™€ accent#

CoUI ๊ธฐ๋ณธ ํ…Œ๋งˆ์—์„œ primary / onPrimary ๋Š” ๋ผ์ดํŠธ์—์„œ ๋ธ”๋ฃจ๊ทธ๋ ˆ์ด์ž…๋‹ˆ๋‹ค โ€” neutral ๋ณด๋‹ค ์ฑ„๋„๊ฐ€ ๋†’์€ ์ฒญํšŒ์ƒ‰ ๊ณ„์—ด(OKLCH hue 266)์ด๋ผ ์ž๊ธฐ ์ƒ‰์œผ๋กœ ์ฝํžˆ์ง€๋งŒ, ์ฑ„์›€ ๋‹จ๊ณ„๋Š” ์ฝ˜ํ…์ธ ์™€ ๊ฒฝ์Ÿํ•˜์ง€ ์•Š์„ ๋งŒํผ ์–ด๋‘ก์Šต๋‹ˆ๋‹ค. ๋ผ์ดํŠธ๋Š” ์ง„ํ•œ ์ฑ„์›€(primary/800)์— ํฐ ๊ธ€์ž์ž…๋‹ˆ๋‹ค. ๋‹คํฌ๋Š” ๊ฑฐ์˜ ํฐ neutral ์ฑ„์›€(neutral/100)์— ๊ฑฐ์˜ ๊ฒ€์€ ๊ธ€์ž(neutral/1000)์ž…๋‹ˆ๋‹ค โ€” ํŒŒ์Šคํ…” ํŒŒ๋ž‘(primary/200)์€ ํŽธ์ง‘๊ธฐ๊ฐ€ ์„ ํƒ ์˜์—ญ ยท ๋งํฌ ยท ์ •๋ณด์— ์ด๋ฏธ ์“ฐ๋Š” ํŒŒ๋ž‘๊ณผ ์„ž์—ฌ "์„ ํƒ๋œ ๊ฒƒ"์ฒ˜๋Ÿผ ์ฝํ˜”๊ธฐ ๋•Œ๋ฌธ์—, ๋‹คํฌ์˜ ์ฃผ ์•ก์…˜๋งŒ neutral ๋žจํ”„์—์„œ ๊ณ ๋ฆ…๋‹ˆ๋‹ค. ํฌ์ปค์Šค ๋ง ยท hover ยท pressed ๋„ ๊ฐ™์€ neutral ๋‹จ๊ณ„๋ฅผ ๋”ฐ๋ผ๊ฐ€๊ณ , ์ปจํ…Œ์ด๋„ˆ ยท fixed ยท inverse ยท ๊ธ€์ž(primaryText) ์Šฌ๋กฏ์€ ๋‹คํฌ์—์„œ๋„ ๋ธ”๋ฃจ๊ทธ๋ ˆ์ด๋ฅผ ์œ ์ง€ํ•ด ๋ธŒ๋žœ๋“œ ์ƒ‰์กฐ๋Š” ๊ทธ ๋ฉด๊ณผ ๊ธ€์ž์— ๋‚จ์Šต๋‹ˆ๋‹ค. CoUI ๋Š” ๋ชจ๋“  ์„œ๋น„์Šค์˜ ๊ธฐ๋ณธ UI ๋ผ์„œ primary ๊ฐ€ ์ฝ˜ํ…์ธ ์™€ ๊ฒฝ์Ÿํ•˜์ง€ ์•Š๊ฒŒ ๋‘๊ณ , ๋ธŒ๋žœ๋“œ ํ…Œ๋งˆ๊ฐ€ primary ์Šฌ๋กฏ์„ ์ž๊ธฐ ์ƒ‰์œผ๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค โ€” ์ด ๋‹คํฌ ์˜ˆ์™ธ๋Š” CoUI ๊ธฐ๋ณธ ํ…Œ๋งˆ๋งŒ์˜ ๊ฒƒ์ด๊ณ  ๋ธŒ๋žœ๋“œ ๋งคํ•‘์€ ๊ทธ๋Œ€๋กœ "๋ฐ์€ ๋‹จ๊ณ„ + ์–ด๋‘์šด ๊ธ€์ž"์ž…๋‹ˆ๋‹ค.

secondary ๋Š” ์ค‘์„ฑ ๊ฐ•์กฐ์ž…๋‹ˆ๋‹ค โ€” ์ผ๋ฐ˜ ๋ชจ๋“œ์—์„œ primary ์™€ ๊ฐ™์€ ๋‹จ๊ณ„๋ฅผ neutral ๋žจํ”„์—์„œ ๊ณ ๋ฅธ ์ฑ„์›€์ž…๋‹ˆ๋‹ค.

CoreColors.accent / CoreColors.onAccent ๋Š” tertiary / onTertiary ์™€ ๊ฐ™์€ ์Šคํ‚ด ์Šฌ๋กฏ์ž…๋‹ˆ๋‹ค. CoUI ๊ธฐ๋ณธ ํ…Œ๋งˆ์—์„œ tertiary ๊ณ„์—ด์€ primary ์™€ ๊ฐ™์€ ๊ฐ’์ด๋ฏ€๋กœ accent ๋„ primary ์™€ ๊ฐ™์€ ์ƒ‰์ž…๋‹ˆ๋‹ค(๋ผ์ดํŠธ๋Š” ๋ธ”๋ฃจ๊ทธ๋ ˆ์ด, ๋‹คํฌ๋Š” ๊ฑฐ์˜ ํฐ neutral) โ€” CoUI ์—๋Š” ๋‘ ๋ฒˆ์งธ ๊ฐ•์กฐ์ƒ‰์ด ์—†์Šต๋‹ˆ๋‹ค. ์ปจํ…Œ์ด๋„ˆยทfixed ๋‹จ๊ณ„๋Š” ๊ทธ๋Œ€๋กœ tertiaryContainer ์ด๋ฆ„์„ ์”๋‹ˆ๋‹ค.

์ƒ‰์ด ์žˆ๋Š” ๊ฐ•์กฐ ์ฑ„์›€์ด ํ•„์š”ํ•œ ์ œํ’ˆ์€ ์ž๊ธฐ ๋ธŒ๋žœ๋“œ(CoreBrand)์˜ tertiary ๋กœ ๊ทธ ์ƒ‰์„ ์ •ํ•˜๊ณ , ์ฑ„์›€์€ accent ์— ๋ฌถ์Šต๋‹ˆ๋‹ค. Cocode ํ™ˆ ์„ผ๋“œ ๋””์Šคํฌ์˜ ๋ฏผํŠธ๋Š” CoUI ์˜ ๊ฐ’์ด ์•„๋‹ˆ๊ณ , ๋ ˆํฌ ์•ˆ ๋ธŒ๋žœ๋“œ(Unibook h312)์—๋„ ์—†์Šต๋‹ˆ๋‹ค โ€” ์ œํ’ˆ ์บ”๋ฒ„์Šค hex ๋Š” ์—ฌ๊ธฐ ์ •๋ณธ์ด ์•„๋‹ˆ๋ฏ€๋กœ, ํ™ˆ์€ ๊ทธ ๋ฏผํŠธ๋ฅผ CoreBrand ํŒ”๋ ˆํŠธ์˜ tertiaryHSL ์— ์‹ฌ์Šต๋‹ˆ๋‹ค.

final cocode = CoreBrand(
  id: 'cocode',
  displayName: 'Cocode',
  palette: PrimitiveColors.generate(
    primaryHSL: (h: 220.0, s: 0.65, l: 0.535),
    secondaryHSL: (h: 260.0, s: 0.60, l: 0.50),
    // ์˜ˆ์‹œ ์‹œ๋“œ โ€” ํฐ ์•„์ด์ฝ˜(onAccent)์ด accent ์ฑ„์›€ ์œ„์—์„œ 4.5:1 ์„ ๋„˜๋Š”
    // ๋ณด๋ผ๋‹ค. ํ™ˆ ์„ผ๋“œ ๋””์Šคํฌ์—์„œ ์‹ค์ธกํ•œ ๋ฏผํŠธ๋กœ ๋ฐ”๊ฟ€ ๋•Œ๋„ ๋ผ์ดํŠธ์˜
    // onAccent ร— accent ๋Œ€๋น„๊ฐ€ 4.5:1 ์ธ์ง€ ํ™•์ธํ•œ๋‹ค โ€” ๋ฐ์€ ๋ฏผํŠธ๋Š” ํฐ
    // ์•„์ด์ฝ˜๊ณผ ๊ทธ ๋Œ€๋น„์— ๋ชป ๋ฏธ์นœ๋‹ค.
    tertiaryHSL: (h: 272.0, s: 0.75, l: 0.46),
    successHSL: (h: 140.0, s: 0.70, l: 0.30),
    infoHSL: (h: 200.0, s: 0.75, l: 0.38),
    warningHSL: (h: 45.0, s: 0.85, l: 0.50),
    errorHSL: (h: 0.0, s: 0.75, l: 0.50),
    neutralHue: 220,
  ),
);

// ํžˆ์–ด๋กœ ์„ผ๋“œ ๋””์Šคํฌ โ€” ์ฑ„์›€ accent, ์•„์ด์ฝ˜ onAccent.
// primary variant ์˜ ๊ธฐ๋ณธ hover ์ฑ„์›€์€ background ๋ฅผ ๋ฎ์–ด์“ฐ๋ฉด ๋น ์ง„๋‹ค.
Button(
  variant: CoreButtonVariant.primary,
  shape: CoreButtonShape.circle,
  buttonStyle: const CoreButtonStyle(
    backgroundColor: CoreColor.token(CoreColors.accent),
    foregroundColor: CoreColor.token(CoreColors.onAccent),
  ),
  onPressed: send,
  child: Icon(LucideIcons.arrowUp),
)

primary ๋Š” ์ฃผ ์•ก์…˜ ์ฑ„์›€์—, accent ๋Š” ๋ธŒ๋žœ๋“œ๊ฐ€ ๋”ฐ๋กœ ๊ณ ๋ฅธ ๊ฐ•์กฐ ์ฑ„์›€(์„ผ๋“œ ๋””์Šคํฌ ๊ฐ™์€)์— ์”๋‹ˆ๋‹ค. CoUI ๊ธฐ๋ณธ ํ…Œ๋งˆ์—์„œ๋Š” ๋‘˜์ด ๊ฐ™์€ ์ƒ‰์œผ๋กœ ์น ํ•ด์ง€๊ณ , ๋ธŒ๋žœ๋“œ ํ…Œ๋งˆ๊ฐ€ tertiary ๋ฅผ ๋”ฐ๋กœ ๊ณ ๋ฅด๋ฉด ๋‘˜์ด ๊ฐˆ๋ผ์ง‘๋‹ˆ๋‹ค. ์ƒํƒœ ์ƒ‰(success, error)์€ ์•…์„ผํŠธ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

onX ๋Š” ๊ทธ ์œ„ ๊ธ€์ž/์•„์ด์ฝ˜ ์ƒ‰์ž…๋‹ˆ๋‹ค. primary ๋ฐฐ๊ฒฝ์—๋Š” onPrimary, surface ์œ„ ๋ณธ๋ฌธ์—๋Š” onSurface ๋ฅผ ์ง์ง€์œผ์„ธ์š”.

๋งํฌ๋Š” ์ „์šฉ ์Šฌ๋กฏ link ๋กœ ์•Œ์•„๋ด…๋‹ˆ๋‹ค. primary ๋„ info ๋„ ์•„๋‹™๋‹ˆ๋‹ค โ€” CoUI ์—์„œ primary ๋Š” ๋ณธ๋ฌธ ๊ธ€์ž์™€ ๊ฑฐ์˜ ๊ฐ™์€ ํ†ค(๋ผ์ดํŠธ ๋ธ”๋ฃจ๊ทธ๋ ˆ์ด, ๋‹คํฌ ๊ฑฐ์˜ ํฐ neutral)์ด๋ผ ๋งํฌ๋กœ ์ฝํžˆ์ง€ ์•Š๊ณ , info ๋Š” ์ƒํƒœ์ƒ‰์ด๋ผ "์ด๋™ํ•œ๋‹ค"๊ฐ€ ์•„๋‹ˆ๋ผ "์•ˆ๋‚ด"๋ฅผ ๋œปํ•ฉ๋‹ˆ๋‹ค. ์Šฌ๋กฏ์„ ๋”ฐ๋กœ ๋‘๋ฉด ๋ธŒ๋žœ๋“œ๊ฐ€ ๋งํฌ ์ƒ‰๋งŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CoUI ์—์„œ๋Š” ์ƒˆ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ์—†์ด info ๋žจํ”„์˜ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค: ๋ผ์ดํŠธ info/700 ยท ๋‹คํฌ info/400 ยท ๊ณ ๋Œ€๋น„ ๋ผ์ดํŠธ info/800 ยท ๊ณ ๋Œ€๋น„ ๋‹คํฌ info/200. ๋งํฌ๋Š” ๊ธ€์ž๋กœ ์ฝํžˆ๋ฏ€๋กœ surface 8ํ†ค ์ „๋ถ€์—์„œ 4.5:1 ์„ ๋„˜์–ด์•ผ ํ•˜๊ณ , ๊ทธ๋ž˜์„œ ์ƒํƒœ ์ฑ„์›€ ๋‹จ๊ณ„(info/600)๊ฐ€ ์•„๋‹ˆ๋ผ ํ•œ ๋‹จ๊ณ„ ์–ด๋‘์šด 700 ์ž…๋‹ˆ๋‹ค โ€” 600 ์€ ํšŒ์ƒ‰ ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„์—์„œ 4.5:1 ์•„๋ž˜๋กœ ๋–จ์–ด์ง‘๋‹ˆ๋‹ค. ๋ธŒ๋žœ๋“œ๊ฐ€ ๋งํฌ ์ƒ‰์„ ๋ฐ”๊พธ๋ ค๋ฉด surface ~ surfaceContainerHighest ์œ„์—์„œ 4.5:1 ์„ ๋„˜๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋งํฌ์˜ ๋ฐ‘์ค„์€ ์ƒ‰์ด ์•„๋‹ˆ๋ผ Link ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ •ํ•ฉ๋‹ˆ๋‹ค โ€” Link.

์„ธ ๋ฒˆ์งธ ๊ธ€์ž ๋‹จ๊ณ„ โ€” onSurfaceSubtle#

๊ธ€์ž๋Š” ์„ธ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค: ๋ณธ๋ฌธ onSurface, ๋ณด์กฐ onSurfaceVariant, ๋ฉ”ํƒ€ onSurfaceSubtle. ๋ฉ”ํƒ€๋Š” ์ค„ ๋ฒˆํ˜ธ ยท ํƒ€์ž„์Šคํƒฌํ”„ ยท ๋„์›€๋ง์ฒ˜๋Ÿผ ์ฝํ˜€์•ผ ํ•˜์ง€๋งŒ ๋ˆˆ์— ๋œ ๋„์–ด์•ผ ํ•˜๋Š” ๊ธ€์ž์ž…๋‹ˆ๋‹ค.

CoUI ์—์„œ๋Š” ์ƒˆ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ์—†์ด placeholder ์™€ ๊ฐ™์€ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค(๋ผ์ดํŠธ neutral/600 ยท ๋‹คํฌ neutral/500 ยท ๊ณ ๋Œ€๋น„ ๋ผ์ดํŠธ neutral/700 ยท ๊ณ ๋Œ€๋น„ ๋‹คํฌ neutral/400) โ€” neutral ๋žจํ”„์—์„œ onSurfaceVariant ๋ฐ”๋กœ ์•„๋ž˜ ๋‹จ๊ณ„๊ฐ€ ๊ทธ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋Œ€๋น„ ์•ฝ์†๋„ placeholder ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค: ํŽ˜์ด์ง€(surface ยท surfaceContainerLowest) ์œ„์—์„œ 4.5:1 ์„ ๋„˜๊ณ (๋ผ์ดํŠธ 4.65 ยท ๋‹คํฌ 5.96), ํšŒ์ƒ‰ ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„๋Š” ์•ฝ์†ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค(๋ผ์ดํŠธ surfaceContainer ์œ„ 4.26).

placeholder ๋กœ ๋Œ€์‹ ํ•˜์ง€ ๋งˆ์„ธ์š” โ€” ๊ฐ’์ด ๊ฐ™์•„๋„ ๊ทธ๊ฑด "์•„์ง ๊ฐ’์ด ์—†๋‹ค"๋Š” ๋œป์ด๋ผ, ๋ธŒ๋žœ๋“œ๊ฐ€ ๋‘˜์„ ๋”ฐ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. disabledContent ๋„ ์•„๋‹™๋‹ˆ๋‹ค โ€” ๋น„ํ™œ์„ฑ์€ ๋Œ€๋น„ ์˜๋ฌด๊ฐ€ ์—†์–ด์„œ, ๋ฉ”ํƒ€ ๊ธ€์ž๋ฅผ ๊ฑฐ๊ธฐ์— ๋‘๋ฉด 4.5:1 ์„ ๋†“์ณ๋„ ์•„๋ฌด๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค. ํšŒ์ƒ‰ ์ปจํ…Œ์ด๋„ˆ ์œ„๋‚˜ hover ยท pressed ์ƒํƒœ์ธต์ด ๋ฎ์ด๋Š” ํ–‰ ์•ˆ์˜ ๋ณด์กฐ ๊ธ€์ž๋Š” onSurfaceVariant ๋ฅผ ์“ฐ์„ธ์š”.

์†Ÿ์€ ๋ฉด โ€” surfaceRaised#

surfaceRaised ๋Š” ํŠธ๋ž™ ์œ„๋กœ ์†Ÿ์€ ์„ ํƒ ๋ฉด์ž…๋‹ˆ๋‹ค โ€” ๋ถ„ํ•  ์ปจํŠธ๋กค์—์„œ ์„ ํƒ๋œ ์นธ, ์•Œ์•ฝ ํƒญ์—์„œ ์„ ํƒ๋œ ํƒญ. ๋ผ์ดํŠธ๋Š” ํฐ์ƒ‰, ๋‹คํฌ๋Š” ์ปจํ…Œ์ด๋„ˆ ์‚ฌ๋‹ค๋ฆฌ์˜ ๋งจ ์œ„(neutral/800)์ž…๋‹ˆ๋‹ค. ๋‹คํฌ์—์„œ๋Š” surfaceContainerHighest ์™€ ๊ฐ™์€ ๊ฐ’์ด์–ด๋„ ๋œป์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค โ€” ๊ฐ€์žฅ ๋†’์€ ์ปจํ…Œ์ด๋„ˆ ํ†ค์ด ์•„๋‹ˆ๋ผ "์•„๋ž˜ ํŠธ๋ž™์—์„œ ๋– ์˜ค๋ฅธ ๋ฉด"์ด๋ผ์„œ, ๋‘ ๋ชจ๋“œ ๋ชจ๋‘ ํŠธ๋ž™(surfaceContainer)๋ณด๋‹ค ๋ฐ์Šต๋‹ˆ๋‹ค. ๋Œ€๋น„ ๊ฒŒ์ดํŠธ์˜ surface ํ†ค ๋ชฉ๋ก์— ๋“ค์–ด ์žˆ์–ด, ๋ณธ๋ฌธ ยท ๋ณด์กฐ ๊ธ€์ž์™€ ๋งํฌ๊ฐ€ ๊ทธ ์œ„์—์„œ๋„ ๋‹ค๋ฅธ ํ†ค๊ณผ ๊ฐ™์€ ๊ธฐ์ค€์„ ๋„˜๋Š”์ง€ ์žฝ๋‹ˆ๋‹ค.

์ƒํƒœ ํ‘œ์‹œ โ€” errorIcon ยท successIcon ยท warningIcon ยท infoIcon#

๊ธ€์ž๊ฐ€ ์•„๋‹Œ ์ƒํƒœ ํ‘œ์‹œ โ€” ์•„์ด์ฝ˜, ์ƒํƒœ ์ , ์ง„ํ–‰ ๋ง‰๋Œ€, ์ฐจํŠธ ํ‘œ์‹œ โ€” ๋Š” ์ƒํƒœ ์ฑ„์›€(error โ€ฆ)์ด ์•„๋‹ˆ๋ผ ์ด ์Šฌ๋กฏ ๋„ท์„ ์”๋‹ˆ๋‹ค. ๊ธ€์ž๋Š” 4.5:1 ์„ ๋„˜์–ด์•ผ ํ•˜์ง€๋งŒ ๊ธ€์ž๊ฐ€ ์•„๋‹Œ ํ‘œ์‹œ๋Š” 3:1(WCAG 1.4.11)์ด๋ฉด ๋˜์–ด์„œ, ์ฑ„์›€๋ณด๋‹ค ํ•œ ๋‹จ๊ณ„ ๋ฐ๊ฒŒ ๋‘˜ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

CoUI ์—์„œ๋Š” ์ƒˆ ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ ์—†์ด ์ƒํƒœ ๋žจํ”„์˜ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค: ๋ผ์ดํŠธ 500 ยท ๋‹คํฌ 400 ยท ๊ณ ๋Œ€๋น„ ๋ผ์ดํŠธ 700 ยท ๊ณ ๋Œ€๋น„ ๋‹คํฌ 300. ๋Œ€๋น„ ๊ฒŒ์ดํŠธ๊ฐ€ ํŽ˜์ด์ง€ ํ†ค(surface ยท surfaceBright ยท surfaceContainerLowest) ์œ„์—์„œ ์ผ๋ฐ˜ ๋ชจ๋“œ 3:1, ๊ณ ๋Œ€๋น„ 4.5:1 ์„ ์žฝ๋‹ˆ๋‹ค(๋ผ์ดํŠธ 3.06 ~ 3.21 ยท ๋‹คํฌ 8.25 ~ 9.10 ยท ๊ณ ๋Œ€๋น„ ๋ผ์ดํŠธ 6.30 ~ 6.92 ยท ๊ณ ๋Œ€๋น„ ๋‹คํฌ 11.03 ~ 11.76). ๋ผ์ดํŠธ์˜ 500 ์€ ํšŒ์ƒ‰ ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„์—์„œ 3:1 ์•„๋ž˜๋กœ ๋–จ์–ด์ง€๋ฏ€๋กœ(2.45 ~ 3.07), ํšŒ์ƒ‰ ์ปจํ…Œ์ด๋„ˆ ์œ„์˜ ํ‘œ์‹œ๋Š” ์ƒํƒœ ์ฑ„์›€(error โ€ฆ)์„ ์“ฐ์„ธ์š”. ์ƒ์„ฑ ํŒ”๋ ˆํŠธ ๋ธŒ๋žœ๋“œ(ํ‘œ์ค€ ๋งคํ•‘)๋Š” ์ƒํƒœ ์ฑ„์›€๊ณผ ๊ฐ™์€ ๋‹จ๊ณ„์ด๊ณ , ๋ผ์ดํŠธ warning ๋งŒ ์ฑ„์›€์ด ๋ฐ์•„ ํ•œ ๋‹จ๊ณ„ ์–ด๋‘์šด dark ์ž…๋‹ˆ๋‹ค.

๊ธ€์ž์—๋Š” ์“ฐ์ง€ ๋งˆ์„ธ์š” โ€” ์ƒํƒœ ์ƒ‰ ๊ธ€์ž๋Š” onXContainer ์ž…๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ ์ƒ‰ โ€” syntaxKeyword ยท syntaxType ยท syntaxFunction ยท syntaxString#

์ฝ”๋“œ ๊ฐ•์กฐ ์ƒ‰์€ ์Šฌ๋กฏ ๋„ท์ž…๋‹ˆ๋‹ค โ€” ํ‚ค์›Œ๋“œ(keyword ยท storage ยท control), ํƒ€์ž… ยท ํด๋ž˜์Šค ยท ์ˆซ์ž, ํ•จ์ˆ˜ ยท ๋ฉ”์„œ๋“œ, ๋ฌธ์ž์—ด. ํ‰๋ฌธ ยท ๋ณ€์ˆ˜๋Š” onSurface, ๊ตฌ๋‘์  ยท ์—ฐ์‚ฐ์ž๋Š” onSurfaceVariant, ์ฃผ์„์€ onSurfaceSubtle ์„ ์”๋‹ˆ๋‹ค.

๊ตฌ๋ฌธ ์ƒ‰์€ ๋ธŒ๋žœ๋“œ๊ฐ€ ์ •ํ•˜๋Š” ์ƒ‰์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ธŒ๋žœ๋“œ์—์„œ ๊ฐ™์€ ๊ฐ’์ž…๋‹ˆ๋‹ค. ๋ณด๋ผ ยท ๋…ธ๋ž‘ ยท ์—ฐ๋‘์˜ ์–ด๋‘์šด ํŒ์šฉ ๊ฐ’๊ณผ ๋ฐ์€ ํŒ์šฉ ๊ฐ’ ์—ฌ์„ฏ์ด ๋ธŒ๋žœ๋“œ ๋ฐ–์˜ syntax ๊ทธ๋ฃน์— ํ•œ ๋ฒˆ๋งŒ ์žˆ๊ณ , ๋ธŒ๋žœ๋“œ์˜ ์‹œ๋งจํ‹ฑ ๋งคํ•‘์ด ๊ทธ ๊ฐ’์„ ๋ชจ๋“œ์— ๋งž๊ฒŒ ์ด๋ฆ„์œผ๋กœ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค(๋ถ„๋ฅ˜์ƒ‰๊ณผ ๊ฐ™์€ ๋ฐฉ์‹). ํ•จ์ˆ˜ ์ƒ‰๋งŒ ๋ธŒ๋žœ๋“œ info ๋žจํ”„์˜ ๋‹จ๊ณ„์ด๊ณ , CoUI ๋Š” ๋งํฌ์™€ ๊ฐ™์€ ๋‹จ๊ณ„์ž…๋‹ˆ๋‹ค(๋ผ์ดํŠธ info/700 ยท ๋‹คํฌ info/400). ๊ณ ๋Œ€๋น„๋Š” ๊ฐ™์€ ๋ฐ๊ธฐ์˜ ์ผ๋ฐ˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์”๋‹ˆ๋‹ค. ์ฝ”๋“œ๊ฐ€ ๋†“์ด๋Š” ๋ฐ”ํƒ• ์—ฌ๋Ÿ ๊ณณ(surface ยท surfaceContainerLow ยท surfaceContainer ยท surfaceContainerHigh ยท ๋„ค ์ƒํƒœ์˜ XContainer ๋ )์—์„œ 4.5:1 ์„ ๋„˜์–ด์•ผ ํ•˜๊ณ , ๋ ˆํฌ์˜ ๋Œ€๋น„ ๊ฒŒ์ดํŠธ๊ฐ€ CoUI ์—์„œ ๊ทธ๊ฒƒ์„ ์žฝ๋‹ˆ๋‹ค(๊ฐ€์žฅ ๋‚ฎ์€ ๊ณณ์ด ๋ผ์ดํŠธ surfaceContainerHigh ์œ„ 4.55).

coui_core ๋งต#

์“ฐ๋Š” ์ด๋ฆ„์˜๋ฏธ
CoreColors.primary ๋“ฑ ์‹œ๋งจํ‹ฑ ์Šฌ๋กฏ. kebab ์ด๋ฆ„์ด CSS ๋ณ€์ˆ˜ (--coui-primary) ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค
CoreColor.token(CoreColors.primary)Style ํ•„๋“œ์— ๋„ฃ๋Š” ํ”Œ๋žซํผ-์ค‘๋ฆฝ ์ฐธ์กฐ
theme.colorScheme.primaryFlutter โ€” ํ˜„์žฌ ์Šคํ‚ด์ด ํ† ํฐ์„ ํ’€์–ด ์ค€ ๊ฐ’
bg-primary / rgb(var(--coui-on-surface)) Web โ€” Tailwind class ๋˜๋Š” inline ๋ณ€์ˆ˜

์•„๋ž˜ ์Šค์™€์น˜๋Š” --coui-<token> ์„ ๊ทธ๋Œ€๋กœ ์น ํ•˜๋ฏ€๋กœ, ํ—ค๋”์˜ ํ…Œ๋งˆยท์„œํŽ˜์ด์Šค ์Šค์œ„์ฒ˜๋ฅผ ๋ฐ”๊พธ๋ฉด ๊ฐ™์ด ์›€์ง์ž…๋‹ˆ๋‹ค.

์‚ฌ์šฉ๋ฒ•#

// Flutter โ€” colorScheme ๊ฒฝ์œ  ๋˜๋Š” Style ํ† ํฐ
theme.colorScheme.primary
theme.colorScheme.onSurfaceVariant
CoreColor.token(CoreColors.primary)

// Web โ€” ํ† ํฐ class / CSS ๋ณ€์ˆ˜
'bg-primary'                      // Tailwind class
'rgb(var(--coui-on-surface))'     // inline

๋ฌด์—‡์„ ๊ณ ๋ฅด๋‚˜ โ€” ์ž…๋ ฅ์€ 8๊ฐœ๋‹ค#

CoUI ์ž์‹ ์˜ ํŒ”๋ ˆํŠธ๋Š” ๊ณ„์‚ฐํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๋””์ž์ด๋„ˆ๊ฐ€ ์ •ํ•œ ๊ณ ์ • hex ๋ฅผ CouiColorPresets.palette ์— ์ˆซ์ž ๋‹จ๊ณ„๋กœ ์ ์–ด ๋‘ก๋‹ˆ๋‹ค(neutral/50โ€ฆ1050, primaryยท์ƒํƒœ ์ƒ‰ 100โ€ฆ1000, base/whiteยทbase/black). Web ์€ ๊ฐ™์€ ์ด๋ฆ„์„ --coui-neutral-100 ์ฒ˜๋Ÿผ, Figma ๋Š” color/coui/neutral/100 ์ฒ˜๋Ÿผ ์”๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ๋Š” ์ด ํ”„๋ฆฌ๋ฏธํ‹ฐ๋ธŒ๋ฅผ ์ง์ ‘ ์ฝ์ง€ ์•Š๊ณ  ์‹œ๋งจํ‹ฑ ์Šฌ๋กฏ๋งŒ ์ฝ์Šต๋‹ˆ๋‹ค.

๋ธŒ๋žœ๋“œ ํŒ”๋ ˆํŠธ์˜ ์ถœ๋ฐœ์ ์€ 8๊ฐœ ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค โ€” 7๊ฐœ ์—ญํ• ์˜ HSL (primary ยท secondary ยท tertiary ยท success ยท info ยท warning ยท error)๊ณผ ์ค‘๋ฆฝ hue ํ•˜๋‚˜๋ฅผ PrimitiveColors.generate ์— ๋„˜๊น๋‹ˆ๋‹ค. ์Šฌ๋กฏ์„ ํ•˜๋‚˜์”ฉ ๊ณ ๋ฅด๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์ด ์ž…๋ ฅ๊ณผ ์‹œ๋งจํ‹ฑ ๋งคํ•‘์„ ์ •ํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆยท์ „๊ฒฝยท์ƒํƒœ ์Šฌ๋กฏ์ด ๋”ฐ๋ผ์˜ต๋‹ˆ๋‹ค. ๋ชจ๋“œ์™€ ์„œํŽ˜์ด์Šค ์Šคํƒ€์ผ๋„ ์ตœ์ข… ๊ฐ’์— ์ฐธ์—ฌํ•˜๋ฏ€๋กœ, ํŠน์ • ํŒ”๋ ˆํŠธ์˜ hex ๋‚˜ ์Šฌ๋กฏ ๊ฐœ์ˆ˜๋ฅผ ๊ณ ์ •๋œ ๋ณด์žฅ์œผ๋กœ ์“ฐ์ง€ ๋งˆ์„ธ์š”.

์ปค์Šคํ…€ ํŒ”๋ ˆํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฒ•๊ณผ ๊ทธ๊ฒƒ์ด Tailwind configยทCSS ๋ณ€์ˆ˜๋กœ ๊ตฌ์›Œ์ง€๋Š” ๊ฒฝ๋กœ๋Š” ํ…Œ๋งˆ ๊ฐ€์ด๋“œ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์—ญํ•  โ€” primary ๊ฐ€ ๊ธฐ๋ณธ์ด๊ณ , ๋‚˜๋จธ์ง€ ๋‘˜์€ ๊ฐˆ๋ž˜๋‹ค#

์…‹์€ ํŒŒ์ƒ ์œ„๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฐ๊ฐ ๋”ฐ๋กœ ๊ณ ๋ฅด๋Š” ์ž…๋ ฅ์ž…๋‹ˆ๋‹ค. tertiary ๊ฐ€ secondary ์—์„œ ๋‚˜์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

primary ๋Š” ๊ธฐ๋ณธ ์ธํ„ฐ๋ž™์…˜ ์—ญํ• ์ด๊ณ , secondaryยทtertiary ๋Š” ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ‰์œผ๋กœ ๊ฐˆ๋ž˜๋‚ด์•ผ ํ•  ๋•Œ ๊ณ ๋ฅด๋Š” ๋‹ค๋ฅธ ์—ญํ• ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ์ฑ„์›€์€ ์‹œ๋งจํ‹ฑ ๋งคํ•‘์ด ์ •ํ•ฉ๋‹ˆ๋‹ค โ€” CoUI ๊ธฐ๋ณธ ํ…Œ๋งˆ์—์„œ๋Š” primary ๊ฐ€ ๋ผ์ดํŠธ์—์„œ ๋ธ”๋ฃจ๊ทธ๋ ˆ์ด(๋‹คํฌ์—์„œ๋Š” ๊ฑฐ์˜ ํฐ neutral), secondary ๊ฐ€ ์ค‘์„ฑ ๊ฐ•์กฐ์ด๊ณ , tertiary(= accent)๋Š” primary ์™€ ๊ฐ™์€ ๊ฐ’์ด๋ผ ๊ฐˆ๋ž˜๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ฐˆ๋ž˜๋Š” ๋ธŒ๋žœ๋“œ ํŒ”๋ ˆํŠธ๊ฐ€ tertiary ๋ฅผ ๋”ฐ๋กœ ๊ณ ๋ฅผ ๋•Œ ์ƒ๊น๋‹ˆ๋‹ค.

๊ทธ ์ด์ƒ์˜ ์˜๋ฏธ๋ก ("secondary ๋Š” ๋ณด์กฐ ๋™์ž‘")์€ ์ด ํ‚ท์ด ์ฃผ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์•ฑ์ด ์ •ํ•˜์„ธ์š”.

์ฑ„์›€์˜ ๋ฐ๊ธฐ๋Š” ์ „๊ฒฝ๊ณผ ํ•จ๊ป˜ ๊ฒฐ์ •ํ•˜์„ธ์š”. onX ๊ฐ€ ํฐ์ƒ‰์ธ์ง€ ๊ฒ€์ •์ธ์ง€๋Š” ๋งคํ•‘์ด ์ •ํ•ฉ๋‹ˆ๋‹ค. ์ฑ„์›€๋งŒ ๋ฐํžˆ๊ฑฐ๋‚˜ ์–ด๋‘ก๊ฒŒ ํ•˜๋ฉด ๊ทธ ์œ„ ์ „๊ฒฝ๊ณผ์˜ ๋Œ€๋น„๊ฐ€ ๊นจ์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ปค์Šคํ…€ ํŒ”๋ ˆํŠธ๋„ ์‹ค์ œ ์Šคํ‚ด์—์„œ X / onX ๋ฅผ ํ•œ ์Œ์œผ๋กœ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

surface ๊ณ„์ธต โ€” ์ด๋ฆ„์€ ๋ฐ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ "ํŽ˜์ด์ง€์—์„œ ๋–จ์–ด์ง„ ๊ฑฐ๋ฆฌ"๋‹ค#

์ด๊ฑด ์ด๋ฆ„๋งŒ์œผ๋กœ ๋งžํž ์ˆ˜ ์—†์–ด์„œ ๋ฐ˜๋“œ์‹œ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

surfaceContainerLowest โ†’ surfaceContainerLow โ†’ surfaceContainer โ†’ surfaceContainerHigh โ†’ surfaceContainerHighest ๊ฐ€ ์ปจํ…Œ์ด๋„ˆ ํ†ค ์‚ฌ๋‹ค๋ฆฌ์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๊ฐ’์€ ์•„๋ž˜ ์Šค์™€์น˜์—์„œ ํ˜„์žฌ ํ…Œ๋งˆ๋กœ ํ™•์ธํ•˜์„ธ์š”.

๋ผ์ดํŠธ์—์„œ๋Š” level ์ด ์˜ค๋ฅผ์ˆ˜๋ก ์–ด๋‘์›Œ์ง€๊ณ , ๋‹คํฌ์—์„œ๋Š” ๋ฐ์•„์ง‘๋‹ˆ๋‹ค. ๋ฐฉํ–ฅ์ด ๋’ค์ง‘ํžˆ์ง€๋งŒ ๋œป์€ ๊ฐ™์Šต๋‹ˆ๋‹ค โ€” "ํŽ˜์ด์ง€์—์„œ ๋ฉ€์–ด์ง„๋‹ค". ๋” ๋ฐ์€ ์ƒ‰์ด๋ผ๋Š” ์ด์œ ๋กœ ์—ญํ• ์„ ๊ณ ๋ฅด์ง€ ๋งˆ์„ธ์š”. ์นด๋“œยทํŒ์˜ค๋ฒ„์˜ ํ‘œ๋ฉด์€ ๊ฐ ์ปดํฌ๋„ŒํŠธ ๊ธฐ๋ณธ๊ฐ’์ด ์ •ํ•˜๊ณ , ๋ณ„๋„ ์œ„๊ณ„๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋งŒ ์ปจํ…Œ์ด๋„ˆ level ์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์Šฌ๋กฏ์ด ๊ฐ™์€ ๊ฐ’์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งคํ•‘ยท๋ชจ๋“œ์— ๋”ฐ๋ผ surface ์™€ ์ผ๋ถ€ ์ปจํ…Œ์ด๋„ˆ ํ†ค์ด ๊ฒน์นฉ๋‹ˆ๋‹ค. ์ด๋ฆ„์ด ๋‹ค๋ฅด๋‹ค๋Š” ์ด์œ ๋งŒ์œผ๋กœ ์‹œ๊ฐ ์ฐจ์ด๊ฐ€ ๋ณด์žฅ๋˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

onSurface ์™€ onSurfaceVariant ๋Š” ๊ธฐ๋ณธ ์Šคํ‚ด์—์„œ surface 8ํ†ค ๋ชจ๋‘์— ๋Œ€ํ•ด 4.5:1 ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ฆ๋ฉ๋‹ˆ๋‹ค. ์•ฑ์ด ๊ฐ’์„ ๋ฎ์œผ๋ฉด ๊ทธ ์•ฑ์˜ ์ตœ์ข… ์กฐํ•ฉ๋„ ๋‹ค์‹œ ์žฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

on* ํŽ˜์–ด๋ง โ€” ์ด ํ‘œ๋Š” CI ๊ฐ€ ๋งค PR ๊ฒ€์ฆํ•œ๋‹ค#

์ถ”์ธก์ด ์•„๋‹™๋‹ˆ๋‹ค. check_contrast.dart ๊ฐ€ ์‹ค์ œ ์Šคํ‚ด์„ ๋นŒ๋“œํ•ด ์žฌ๊ณ , CI ๊ฐ€ ๊ทธ๊ฒƒ์„ ๋Œ๋ฆฝ๋‹ˆ๋‹ค. ๊ฒ€์‚ฌ ๋ฒ”์œ„์™€ ๊ฒฐ๊ณผ์˜ ์ •๋ณธ์€ packages/coui_core/tool/check_contrast.dart ์™€ ๊ทธ ์‹คํ–‰ ์ถœ๋ ฅ์ž…๋‹ˆ๋‹ค. ์Šฌ๋กฏ์ด ํ™•์žฅ๋˜์–ด๋„ ์˜ค๋ž˜๋œ ์Œ ๊ฐœ์ˆ˜๋ฅผ ๋ณด์žฅ์œผ๋กœ ๋‚จ๊ธฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฌด์—‡๊ธฐ์ค€
onSurface ยท onSurfaceVariant ร— surface 8ํ†ค4.5:1
onX on X โ€” 7์—ญํ• 4.5:1
onXContainer on XContainer โ€” 7์—ญํ• 4.5:1
onXFixed ๊ณ„์—ด ร— XFixed/XFixedDim4.5:1
inverseOnSurfaceยทinversePrimary on inverseSurface 4.5:1
onXContainer ๋ฅผ ๋ณธ๋ฌธ ํ…์ŠคํŠธ๋กœ surface ์œ„์—4.5:1
primaryText ร— surface 8ํ†ค4.5:1
primaryTextLarge ร— surface 8ํ†ค3:1 (ํฐ ๊ธ€์ž ์ „์šฉ)
link ร— surface 8ํ†ค4.5:1
placeholder ร— ์ž…๋ ฅ ํ•„๋“œ๊ฐ€ ๋†“์ด๋Š” ๋ฐ”ํƒ•(surface ยท surfaceContainerLowest) 4.5:1
onSurfaceSubtle ร— ๊ฐ™์€ ๋ฐ”ํƒ•(surface ยท surfaceContainerLowest) 4.5:1
syntaxKeyword ยท syntaxType ยท syntaxFunction ยท syntaxString ร— ์ฝ”๋“œ ๋ฐ”ํƒ• ์—ฌ๋Ÿ โ€” CoUI 4.5:1
์ฑ„์›Œ์ง„ ์ปจํŠธ๋กค์˜ hover / pressed ๋ฐฐ๊ฒฝ๊ณผ ์ „๊ฒฝ4.5:1
outline ร— surface 8ํ†ค3:1
outlineSubtle ร— surface ยท surfaceBright โ€” CoUI ๊ณ ๋Œ€๋น„ ๋‘ ๋ชจ๋“œ๋งŒ 4.5:1
onCategoryX on categoryX โ€” ๋ถ„๋ฅ˜์ƒ‰ 9๊ฐ€์ง€ 4.5:1 ยท ๋ผ์ดํŠธ 3.5:1(์ข์€ ์˜ˆ์™ธ) ยท ๊ณ ๋Œ€๋น„ 7:1
onCategoryXContainer on categoryXContainer 4.5:1 ยท ๊ณ ๋Œ€๋น„ 7:1
onCategoryXContainer ๋ฅผ ์ƒ‰ ๊ธ€์ž๋กœ surface ์œ„์— 4.5:1 ยท ๊ณ ๋Œ€๋น„ 7:1
categoryXOutline ร— surface โ€” ๊ณ ๋Œ€๋น„ ๋‘ ๋ชจ๋“œ๋งŒ(CoUI ยท ํ‘œ์ค€ ๋งคํ•‘) 4.5:1

๊ทœ์น™ ์„ธ ์ค„#

  1. onX ๋Š” X ์œ„์—์„œ๋งŒ ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค. onPrimary ๋ฅผ surface ์œ„์— ๋†“๋Š” ์กฐํ•ฉ์€ ๊ฒ€์ฆ ๋Œ€์ƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.
  2. ์—ญํ• ์ƒ‰ ํ…์ŠคํŠธ๊ฐ€ ํ•„์š”ํ•˜๋ฉด fill ์ด ์•„๋‹ˆ๋ผ onXContainer ๋˜๋Š” ํ…์ŠคํŠธ ์ „์šฉ primaryText ๋ฅผ ์“ฐ์„ธ์š”. fill ์€ ๊ทธ ์œ„์˜ onX ์™€ ์ง์ง€์€ ์ฑ„์›€์ด๊ณ  ๋ณธ๋ฌธ ์ƒ‰์ด ์•„๋‹™๋‹ˆ๋‹ค. primaryTextLarge ๋Š” ํฐ ๊ธ€์ž ๊ธฐ์ค€์ด๋ฏ€๋กœ ์ผ๋ฐ˜ ๋ณธ๋ฌธ์— ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  3. outline ์€ ํ…์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ฒฝ๊ณ„๋ผ 3:1 ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค.

์ผ๋ถ€๋Ÿฌ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š” ๊ฒƒ#

์ ์–ด๋‘์ง€ ์•Š์œผ๋ฉด ์—†๋Š” ๋ณด์žฅ์„ ๋ฏฟ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • outlineVariant โ€” ์žฅ์‹ ๊ตฌ๋ถ„์„ ์ด๋ผ 3:1 ์„ ์š”๊ตฌํ•˜๋ฉด hairline ์ด ์•„๋‹ˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ปจํŠธ๋กค์„ ๊ตฌํšํ•˜๋Š” ๊ฒฝ๊ณ„๋ฅผ ์ด๊ฒƒ๋งŒ์œผ๋กœ ๊ทธ๋ฆฌ์ง€ ๋งˆ์„ธ์š” โ€” ๊ทธ ์šฉ๋„๋Š” outline ์ž…๋‹ˆ๋‹ค.
  • outlineSubtle โ€” ๋–  ์žˆ๋Š” ํŒจ๋„์˜ ํ…Œ๋‘๋ฆฌ ์Šฌ๋กฏ์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜ ๋ชจ๋“œ์—์„œ๋Š” outlineVariant ๋ณด๋‹ค๋„ ์˜…๊ฒŒ ๋‘๋Š” ๊ฐ’(๋ผ์ดํŠธ neutral/150 ยท ๋‹คํฌ neutral/900)์ด๋ผ ๊ฐ™์€ ์ด์œ ๋กœ ๋น„์œจ์„ ์š”๊ตฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹คํฌ์˜ neutral/900 ์€ ํŒจ๋„ ์ฑ„์›€ (surfaceBright)๊ณผ ๊ฐ™์€ ํ†ค์ด๋ผ ์„ ์ด ๋ณด์ด์ง€ ์•Š๊ณ , ๊ฐ€์žฅ์ž๋ฆฌ๋Š” ์ฑ„์›€์˜ ๋ช…๋„ ์ฐจ๋กœ ์ฝํž™๋‹ˆ๋‹ค. ๊ทธ๋ฆผ์ž๋ฅผ ๋ฏฟ์„ ์ˆ˜ ์—†๋Š” CoUI ๊ณ ๋Œ€๋น„ ๋‘ ๋ชจ๋“œ๋งŒ surface ยท surfaceBright ์œ„์—์„œ 4.5:1 ๋กœ ์žฝ๋‹ˆ๋‹ค. ๋ธŒ๋žœ๋“œ๊ฐ€ ๋”ฐ๋กœ ์ •ํ•˜์ง€ ์•Š์€ ํ‘œ์ค€ ๋งคํ•‘์—์„œ๋Š” ์ด ์Šฌ๋กฏ์ด outlineVariant ์™€ ๊ฐ™์€ ๊ฐ’์ด๋ผ ๊ทธ ๊ธฐ์ค€์„ ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • disabled ์Šฌ๋กฏ โ€” WCAG ๊ฐ€ ๋น„ํ™œ์„ฑ ์ปจํŠธ๋กค์„ ๋ฉด์ œํ•ฉ๋‹ˆ๋‹ค. ๋Œ€์‹  ๋ณ„๋„ ํ…Œ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฅธ ๊ธฐ์ค€์œผ๋กœ ๊ฐ’์„ ๊ณ ์ •ํ•ฉ๋‹ˆ๋‹ค(surface ๋Œ€๋น„ 3:1 ์ด์ƒ์ด๋ฉด์„œ onSurface ๋ณด๋‹ค๋Š” ๋‚ฎ์„ ๊ฒƒ โ€” ์ฝํžˆ๋˜ ๋ช…๋ฐฑํžˆ ๋น„ํ™œ์„ฑ).
  • ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„์˜ placeholder โ€” ์ž…๋ ฅ ํ•„๋“œ๋Š” surface ๋ฐ”ํƒ•์ด๋ผ ์ด ์กฐํ•ฉ์€ ๊ทธ๋ ค์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. CoUI ๊ธฐ๋ณธ ํ…Œ๋งˆ์—์„œ placeholder ๋Š” ๋ผ์ดํŠธ์˜ surfaceContainerLow ๋ถ€ํ„ฐ ์œ„ ์ปจํ…Œ์ด๋„ˆ ํ†ค๊ณผ surfaceDim, ๋‹คํฌ์˜ surfaceContainerHighยทsurfaceContainerHighestยทsurfaceBright ์œ„์—์„œ 4.5:1 ์— ๋ชป ๋ฏธ์นฉ๋‹ˆ๋‹ค. ์ปจํ…Œ์ด๋„ˆ ํ†ค์œผ๋กœ ์ฑ„์šด ์ž…๋ ฅ์„ ๋งŒ๋“ค๋ฉด ๊ทธ ํ†ค์„ ๊ฒ€์‚ฌ ๋Œ€์ƒ์— ๋„ฃ๊ณ  ๋‹ค์‹œ ์žฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ž„์˜ ์ „๊ฒฝยท๋ฐฐ๊ฒฝ ์กฐํ•ฉ โ€” onX ๊ฐ€ ์žˆ๋‹ค๋Š” ์‚ฌ์‹ค๋งŒ์œผ๋กœ ๋ชจ๋“  ๋ฐฐ๊ฒฝ๊ณผ์˜ ๋Œ€๋น„๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. primaryTextLarge ์˜ 3:1 ๊ฒ€์‚ฌ๋„ ์ผ๋ฐ˜ ๋ณธ๋ฌธ ๋ณด์žฅ์ด ์•„๋‹™๋‹ˆ๋‹ค.
  • ํŽ˜์ด์ง€ ์œ„์˜ ๋ถ„๋ฅ˜์ƒ‰ ์ฑ„์›€ โ€” ์นฉ ยท ์ฐจํŠธ ยท ๋ฒ”๋ก€ ์ ์ด ํŽ˜์ด์ง€์—์„œ ๋ณด์ด๋Š” ์ •๋„ (categoryX ร— surface)์ž…๋‹ˆ๋‹ค. ๋””์ž์ธ์€ UI ๊ธฐ์ค€ 3:1 ์„ ์ฐธ๊ณ ๋กœ๋งŒ ์ ์Šต๋‹ˆ๋‹ค โ€” ๋ถ„๋ฅ˜์˜ ์ด๋ฆ„์€ ์นฉ์ด๋‚˜ ๋ฒ”๋ก€์˜ ๋ผ๋ฒจ์ด ๋งํ•˜๊ณ , ๊ทธ ๋ผ๋ฒจ ์ง์€ ์œ„ ํ‘œ์—์„œ ์žฝ๋‹ˆ๋‹ค.
  • ๋ผ์ดํŠธ ยท ๋‹คํฌ์˜ ๋ถ„๋ฅ˜์ƒ‰ outline โ€” ๋ผ์ดํŠธ์—์„œ๋Š” ์ปจํ…Œ์ด๋„ˆ ํ†ค์„ ์ฝ์–ด ์˜…์€ ์นฉ์— ์ผ๋ถ€๋Ÿฌ ํ…Œ๋‘๋ฆฌ๊ฐ€ ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‹คํฌ์˜ outline ์€ ์นฉ ๊ฐ€์žฅ์ž๋ฆฌ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ์ƒ‰์กฐ์ด์ง€ ์ปจํŠธ๋กค์„ ๊ตฌํšํ•˜๋Š” ๊ฒฝ๊ณ„๊ฐ€ ์•„๋‹ˆ๋ผ ์•ฝ 2:1 ์ž…๋‹ˆ๋‹ค. ๋ณด์ด๋Š” ๊ฒฝ๊ณ„๋ฅผ ์•ฝ์†ํ•˜๋Š” ๊ณ ๋Œ€๋น„ ๋‘ ๋ชจ๋“œ์—์„œ๋งŒ ์žฝ๋‹ˆ๋‹ค.
  • ์นด๋“œ ยท ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„์˜ ๋ถ„๋ฅ˜์ƒ‰ ์ง โ€” ๊ธฐ์ค€์€ ์นฉ์ด ๊ธฐ๋ณธ์œผ๋กœ ๋†“์ด๋Š” ํŽ˜์ด์ง€์—์„œ ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ณ ๋Œ€๋น„ ๋‹คํฌ์˜ outline ์€ surfaceContainer ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„์—์„œ 4.5:1 ์— ๋ชป ๋ฏธ์นฉ๋‹ˆ๋‹ค. ๊ทธ ๋ชจ๋“œ์—์„œ ์ปจํ…Œ์ด๋„ˆ ํ†ค ์œ„์— ์นฉ์„ ๊ทธ๋ฆฌ๋ฉด ๊ทธ ํ†ค์„ ๊ฒ€์‚ฌ ๋Œ€์ƒ์— ๋„ฃ๊ณ  ๋‹ค์‹œ ์žฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ค‘๋ฆฝ ํ†ค์ด ๋‹ค๋ฅธ ๋ธŒ๋žœ๋“œ์˜ ๊ณ ๋Œ€๋น„ ๋‹คํฌ ํŽ˜์ด์ง€ โ€” ๋ถ„๋ฅ˜์ƒ‰ ๊ฐ’์€ ๋ชจ๋“  ๋ธŒ๋žœ๋“œ์—์„œ ๊ฐ™์ง€๋งŒ ํŽ˜์ด์ง€(surface)๋Š” ๋ธŒ๋žœ๋“œ์˜ ์ค‘๋ฆฝ ํ†ค์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ๊ฒŒ์ดํŠธ๋Š” ํ‘œ์ค€ ๋งคํ•‘์„ ๋Œ€ํ‘œ ํŒ”๋ ˆํŠธ ํ•œ ๋ฒŒ์˜ ํŽ˜์ด์ง€์—์„œ๋งŒ ์žฌ๊ณ , ๊ณ ๋Œ€๋น„ ๋‹คํฌ์˜ outline ์€ ๊ทธ ํŽ˜์ด์ง€์—์„œ 4.5:1 ์— ๊ฒจ์šฐ ๋‹ฟ์Šต๋‹ˆ๋‹ค(yellow ๊ฐ€ ๊ฐ€์žฅ ๋น ๋“ฏํ•ฉ๋‹ˆ๋‹ค). ๊ทธ๋ž˜์„œ ์ค‘๋ฆฝ ํ†ค์ด ๋” ๋ฐ๊ฑฐ๋‚˜ ์ƒ‰์กฐ๊ฐ€ ๋‹ค๋ฅธ ๋ธŒ๋žœ๋“œ์˜ ๊ณ ๋Œ€๋น„ ๋‹คํฌ ํŽ˜์ด์ง€์—์„œ๋Š” outline ์ด 4.5:1 ์— ๋ชป ๋ฏธ์น  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” ๊ทธ๋Ÿฐ ๋ธŒ๋žœ๋“œ๋Š” ์ž๊ธฐ ํŽ˜์ด์ง€์—์„œ outline ์„ ์ง์ ‘ ์žฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ธ€์ž ์ง์€ ์—ฌ์œ ๊ฐ€ ์ปค์„œ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ณ ๋Œ€๋น„ ๋ชจ๋“œ์—์„œ๋„ ๊ฐ™์€ ์—ญํ•  ์Œ์„ ๊ฐ™์€ ๊ธฐ์ค€์œผ๋กœ ๊ฒ€์ฆํ•˜๊ณ , ๊ทธ ์œ„์— ๊ณ ๋Œ€๋น„์—์„œ๋งŒ ๋”ํ•˜๋Š” ๊ธฐ์ค€์ด ์žˆ์Šต๋‹ˆ๋‹ค โ€” ์œ„ ํ‘œ์—์„œ ๊ณ ๋Œ€๋น„๋ฅผ ๋”ฐ๋กœ ์ ์€ ํ–‰์ž…๋‹ˆ๋‹ค. ๊ณ ๋Œ€๋น„๊ฐ€ ๋ฌด์—‡์„ ๋ฐ”๊พธ๊ณ  ๋ฌด์—‡์„ ์ผ๋ถ€๋Ÿฌ ํ•˜์ง€ ์•Š๋Š”์ง€๋Š” ์ ‘๊ทผ์„ฑ ํŽ˜์ด์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถ„๋ฅ˜์ƒ‰ (category) โ€” ์˜๋ฏธ ์—†์ด ๊ตฌ๋ถ„๋งŒ ํ•˜๋Š” ์ƒ‰#

ํƒœ๊ทธ ยท ์•„๋ฐ”ํƒ€ ยท ๋ผ๋ฒจ ยท ์ผ์ • ยท ์ฐจํŠธ ๋ฒ”๋ก€์ฒ˜๋Ÿผ ์ด๊ฒƒ๊ณผ ์ €๊ฒƒ์ด ๋‹ค๋ฅด๋‹ค๋งŒ ๋งํ•˜๋Š” ๊ณณ์— ์”๋‹ˆ๋‹ค. ๋ถ„๋ฅ˜์ƒ‰์€ ์„ฑ๊ณต ยท ์˜ค๋ฅ˜ ยท ๊ฒฝ๊ณ  ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ๋‚˜๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ์˜๋ฏธ๋Š” ์ƒํƒœ ์ƒ‰์ด ๋งก์Šต๋‹ˆ๋‹ค.

์ƒ‰์€ 9๊ฐ€์ง€์ž…๋‹ˆ๋‹ค: red ยท orange ยท yellow ยท green ยท blue ยท purple ยท pink ยท brown ยท gray. ์ฝ”๋“œ์—์„œ๋Š” CoreCategoryColor ์˜ ๊ฐ’์ด๊ณ , CSS ๋ณ€์ˆ˜ ยท Figma ๋ณ€์ˆ˜ ยท ์•„๋ž˜ ์Šค์™€์น˜๊ฐ€ ๋ชจ๋‘ ์ด ์ˆœ์„œ๋กœ ๋‚˜์—ด๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋“œ๋งˆ๋‹ค ์นฉ์ด ๋‹ค๋ฅด๊ฒŒ ๋ณด์ธ๋‹ค#

๋ชจ๋“œ์ง„ํ•œ ์นฉ์˜…์€ ์นฉ
๋ผ์ดํŠธ์ฑ„์›€ + ํฐ ๊ธ€์ž์˜…์€ ์ƒ‰์กฐ ๋ฐ”ํƒ• + ์ง„ํ•œ ์ƒ‰ ๊ธ€์ž, ํ…Œ๋‘๋ฆฌ ์—†์Œ
๋‹คํฌ์–ด๋‘์šด ์ฑ„์›€ + ํฐ ๊ธ€์ž์–ด๋‘์šด ์ƒ‰์กฐ ๋ฐ”ํƒ• + ์ƒ‰ ํ…Œ๋‘๋ฆฌ + ์„ ๋ช…ํ•œ ์ƒ‰ ๊ธ€์ž
๊ณ ๋Œ€๋น„ ๋ผ์ดํŠธ์ง„ํ•œ ์ฑ„์›€ + ํฐ ๊ธ€์ž๋ผ์ดํŠธ ๋ฐ”ํƒ• + ๋” ์ง„ํ•œ ๊ธ€์ž + ์ง„ํ•œ ์ฑ„์›€์ƒ‰ ํ…Œ๋‘๋ฆฌ
๊ณ ๋Œ€๋น„ ๋‹คํฌ๋ฐ์€ ์ฑ„์›€ + ๊ฒ€์ • ๊ธ€์ž์–ด๋‘์šด ์ƒ‰์กฐ ๋ฐ”ํƒ• + ๋ฐ์€ ๊ธ€์ž + ์ƒ‰ ํ…Œ๋‘๋ฆฌ

์Šฌ๋กฏ ์ด๋ฆ„์€ ๋„ค ๋ชจ๋“œ๊ฐ€ ๊ฐ™๊ณ  ๊ฐ’๋งŒ ๋‹ค๋ฆ…๋‹ˆ๋‹ค โ€” ์ปดํฌ๋„ŒํŠธ๋Š” ์Šฌ๋กฏ๋งŒ ๊ณ ๋ฆ…๋‹ˆ๋‹ค.

์Šฌ๋กฏ โ€” ์ƒ‰๋งˆ๋‹ค ๋‹ค์„ฏ ๊ฐœ#

์Šฌ๋กฏ (X = Red โ€ฆ Gray)์“ฐ์ž„
categoryX์ง„ํ•œ ์นฉ ์ฑ„์›€ ยท ์ฐจํŠธ ๊ณ„์—ด ยท ๋ฒ”๋ก€ ์ 
onCategoryX์ง„ํ•œ ์นฉ ๊ธ€์ž
categoryXContainer์˜…์€ ์นฉ ยท ์•„๋ฐ”ํƒ€ ยท ์ผ์ • ๋ธ”๋ก ๋ฐ”ํƒ•
onCategoryXContainer์˜…์€ ์นฉ ๊ธ€์ž, ๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ์ƒ‰ ๊ธ€์ž
categoryXOutline์˜…์€ ์นฉ ยท ์•„๋ฐ”ํƒ€ ยท ์ผ์ • ๋ธ”๋ก ํ…Œ๋‘๋ฆฌ โ€” ๋ผ์ดํŠธ์—์„œ๋Š” ๋ณด์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค
// ์ •ํ•ด ๋‘” ์ƒ‰
CoreColor.token(CoreColors.categoryRedContainer)

// ์‹คํ–‰ ์ค‘์— ๊ณ ๋ฅธ ์ƒ‰ โ€” hue ๋Š” CoreCategoryColor
CoreColor.token(hue.container)

// Web โ€” ๊ฐ™์€ ์ด๋ฆ„์˜ class / CSS ๋ณ€์ˆ˜
'bg-category-red-container'
'rgb(var(--coui-on-category-red-container))'

์“ฐ๋Š” ๊ทœ์น™#

  • ์˜๋ฏธ๋ฅผ ๋‚˜๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์„ฑ๊ณต ยท ์˜ค๋ฅ˜ ยท ๊ฒฝ๊ณ  ยท ์ •๋ณด์—๋Š” ์ƒํƒœ ์ƒ‰์„ ์”๋‹ˆ๋‹ค.
  • 9๊ฐ€์ง€ ์ค‘์—์„œ ๊ณ ๋ฆ…๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๊ณ ๋ฅธ ์ž„์˜์˜ hex ๋Š” ๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ƒ‰ ๊ธ€์ž๋Š” ๋ชจ๋“  ๋ชจ๋“œ์—์„œ onCategoryXContainer ์ž…๋‹ˆ๋‹ค โ€” ๋ถ„๋ฅ˜๋ช…์„ ์ƒ‰์œผ๋กœ ์“ฐ๋Š” ๊ธ€์ž, ๋ฒ”๋ก€ ๊ธ€์ž ๋ชจ๋‘. categoryX ๋Š” ๊ธ€์ž์ƒ‰์ด ์•„๋‹™๋‹ˆ๋‹ค. ํฐ ๋ฐ”ํƒ• ์œ„์—์„œ 3.5:1 ์–ธ์ €๋ฆฌ๊นŒ์ง€ ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ์€ ์˜…์€ ์นฉ์ž…๋‹ˆ๋‹ค. ์ง„ํ•œ ์นฉ์€ ๊ฐ•์กฐ๋‚˜ ์‹œ๊ฐ„ ๋ฐฐ์ง€ ๊ฐ™์€ ์งง์€ ๋ผ๋ฒจ์—๋งŒ ์”๋‹ˆ๋‹ค.

๋Œ€๋น„ ์˜ˆ์™ธ โ€” ๋ผ์ดํŠธ์˜ ์ง„ํ•œ ์นฉ ๋ผ๋ฒจ ํ•˜๋‚˜#

๋ผ์ดํŠธ ๋ชจ๋“œ์˜ ์ง„ํ•œ ์นฉ ๋ผ๋ฒจ(onCategoryX on categoryX)์— ํ•œํ•ด 3.5:1 ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ์กฐ๊ฑด: SemiBold ์ด์ƒ ยท 12px ์ด์ƒ ยท ๋‹จ์–ด ํ•˜๋‚˜๋‚˜ ์‹œ๊ฐ„ ๊ฐ™์€ ์งง์€ ๋ผ๋ฒจ. ๋ฌธ์žฅ์—๋Š” ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํฐ ๊ธ€์ž๋กœ 4.5:1 ์„ ์ง€ํ‚ค๋ฉด ๋ผ์ดํŠธ์˜ ์ฑ„์›€์ด ์–ด๋‘ก๊ณ  ํƒํ•ด์ง‘๋‹ˆ๋‹ค. ์งง์€ ๋ผ๋ฒจ์€ 3.5:1 ์—์„œ๋„ ์ฝํž™๋‹ˆ๋‹ค. ๋‹คํฌ๋Š” 4.5:1, ๊ณ ๋Œ€๋น„ ๋‘ ๋ชจ๋“œ๋Š” 7:1 ์„ ์˜ˆ์™ธ ์—†์ด ์ง€ํ‚ต๋‹ˆ๋‹ค. ๋Œ€๋น„ ๊ฒŒ์ดํŠธ๋Š” ์ด ์˜ˆ์™ธ๋ฅผ 3:1 ํฐ ๊ธ€์ž ๊ธฐ์ค€์ด ์•„๋‹Œ 3.5:1 ๊ทธ๋Œ€๋กœ ์žฌ๋ฏ€๋กœ, ์ฑ„์›€์ด 3.5:1 ์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐ€๋ฉด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

๊ฐ’์€ ๋ธŒ๋žœ๋“œ์™€ ๋ฌด๊ด€ํ•˜๋‹ค#

๋ถ„๋ฅ˜์ƒ‰์€ ๋ธŒ๋žœ๋“œ ์ƒ‰์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ธŒ๋žœ๋“œ์—์„œ ๊ฐ™์€ ๊ฐ’์ž…๋‹ˆ๋‹ค. ๋ธŒ๋žœ๋“œ ํŒ”๋ ˆํŠธ (CoreBrand)๊ฐ€ ๋ฐ”๊พธ์ง€ ์•Š๊ณ , PrimitiveColors.generate ์˜ ์ž…๋ ฅ๋„ ์•„๋‹™๋‹ˆ๋‹ค. ๊ฐ’์€ coui_core ์˜ CoreCategoryPalette ํ•œ ๊ณณ์— ์žˆ๊ณ , ๊ฐ ๋งคํ•‘์ด ์ผ๋ฐ˜ ์Šคํ‚ด๊ณผ ๊ณ ๋Œ€๋น„ ์Šคํ‚ด์— ๊ทธ ํ‘œ๋ฅผ ๊ทธ๋Œ€๋กœ ์”๋‹ˆ๋‹ค. ์ง„ํ•œ ์นฉ ๊ธ€์ž(onCategoryX)๋งŒ ํ‘œ์˜ ์ƒ‰์ด ์•„๋‹ˆ๋ผ ๋งคํ•‘์˜ ํฐ์ƒ‰์ด๊ณ , ๊ณ ๋Œ€๋น„ ๋‹คํฌ์—์„œ๋งŒ ๊ฒ€์ •์ž…๋‹ˆ๋‹ค. Figma ์—์„œ๋Š” ์›์‹œ๊ฐ’์ด ๋ธŒ๋žœ๋“œ ๋ฐ–์˜ color/category/<์ƒ‰>/<์—ญํ• > ๊ทธ๋ฃน์— ํ•œ ๋ฒˆ ์žˆ๊ณ , ๋ธŒ๋žœ๋“œ๋งˆ๋‹ค ์‹œ๋งจํ‹ฑ ์Šฌ๋กฏ์ด ๊ทธ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

CoreSchemeSource ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด ๋„ค ๋นŒ๋”(light ยท dark ยท highContrastLight ยท highContrastDark)์™€ raiseContrast ์•ˆ์—์„œ CoreCategoryPalette.applyTo ๋ฅผ ๋ถ€๋ฅด์„ธ์š”. ๊ณ ๋Œ€๋น„ ์ชฝ์—์„œ ๋น ๋œจ๋ฆฌ๋ฉด ๊ณ ๋Œ€๋น„ ๋ชจ๋“œ๊ฐ€ ๋ถ„๋ฅ˜์ƒ‰์˜ ์ผ๋ฐ˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค โ€” ๋น„์–ด ์žˆ๋Š” ์Šฌ๋กฏ์€ CoUI ์˜ ์ผ๋ฐ˜ ๊ฐ’์œผ๋กœ ์ฑ„์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๋Œ€๋น„๋Š” ๋ ˆํฌ ๊ฒŒ์ดํŠธ๊ฐ€ ์žฐ๋‹ค#

๋ ˆํฌ์˜ ๋Œ€๋น„ ๊ฒŒ์ดํŠธ(check_contrast.dart)๊ฐ€ ์œ„ on* ํ‘œ์˜ ๋ถ„๋ฅ˜์ƒ‰ ์ง์„ 9์ƒ‰ ร— 4๋ชจ๋“œ, CoUI ยท ํ‘œ์ค€ ๋งคํ•‘์—์„œ ์žฝ๋‹ˆ๋‹ค. ํ‘œ์ค€ ๋งคํ•‘์€ ๋Œ€ํ‘œ ํŒ”๋ ˆํŠธ ํ•œ ๋ฒŒ์˜ ํŽ˜์ด์ง€์—์„œ ์žฌ๋ฏ€๋กœ, ์ค‘๋ฆฝ ํ†ค์ด ๋‹ค๋ฅธ ๋ธŒ๋žœ๋“œ์˜ ๊ณ ๋Œ€๋น„ ๋‹คํฌ outline ์€ ์ผ๋ถ€๋Ÿฌ ๊ฒ€์ฆํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ์— ์ ์—ˆ์Šต๋‹ˆ๋‹ค. CoreContrast.auditScheme ์€ ๋ถ„๋ฅ˜์ƒ‰์„ ๋ณด์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๊ธฐ์ค€์ด ๋ชจ๋“œ๋งˆ๋‹ค ๋‹ค๋ฅด๊ณ  ๋ผ์ดํŠธ์˜ 3.5:1 ์€ ์–ด๋–ค CoreContrastLevel ์—๋„ ์—†์–ด์„œ, ๋Œ€ํ‘œ ์Œ ํ•œ ๋ฒŒ๋กœ ์ ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์•ฑ์ด ์ง์ ‘ ๊ทธ๋ฆฌ๋Š” ๋ถ„๋ฅ˜์ƒ‰ ์ง์€ CoreContrast.ratio ๋กœ ๊ณ ์ •ํ•˜์„ธ์š”.

์Šค์™€์น˜๋Š” ์•„๋ž˜ ์ „์ฒด ํ† ํฐ ์˜ Category ๋ฌถ์Œ์— ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒํƒœ์ƒ‰์„ ์žฅ์‹์œผ๋กœ ์จ๋„ ๋˜๋‚˜ โ€” ๋Œ€๊ฐ€๊ฐ€ ๋‘˜ ์žˆ๋‹ค#

์‹œ์Šคํ…œ์€ ์ด ์ƒ‰๋“ค์„ ์žฅ์‹ variant ๋กœ ์‹ค์ œ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ:

warning fill ์€ ํ…์ŠคํŠธ ์ƒ‰์œผ๋กœ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค#

warning fill ์„ ๋ณธ๋ฌธ ์ƒ‰์œผ๋กœ ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฐ์€ ํŒ”๋ ˆํŠธ์—์„œ ๋Œ€๋น„๊ฐ€ ๋‚ฎ์•„์ง€๋Š” ๊ฒƒ์€ ํŠœ๋‹ ๋ฏธ์Šค๊ฐ€ ์•„๋‹ˆ๋ผ ๊ตฌ์กฐ์ ์ž…๋‹ˆ๋‹ค โ€” warning ์€ onWarning ์ด ํฐ์ƒ‰์ด ์•„๋‹ˆ๋ผ ๊ฒ€์ •์ธ ์œ ์ผํ•œ ์—ญํ• ์ด๊ณ , ๊ทธ๊ฑด fill ์ด ์„ค๊ณ„์ƒ ๋ฐ๋‹ค๋Š” ๋œป์ž…๋‹ˆ๋‹ค(๊ฒฝ๊ณ ๋Š” ๋…ธ๋ž‘์ด๋‹ˆ๊นŒ). ํ…์ŠคํŠธ๋กœ ์ฝํžˆ๊ฒŒ ์–ด๋‘ก๊ฒŒ ํ•˜๋ฉด ๊ทธ ๊ฒ€์ • ์ „๊ฒฝ์ด ๊นจ์ง‘๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ํ…์ŠคํŠธ ์ฒด์ธ์˜ fill getter ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” Web ์—์„œ๋Š” ์ผ๊ณฑ ์—ญํ• ์˜ fill getter ๊ฐ€ ์‚ญ์ œ๋˜์—ˆ๊ณ  Flutter ์—์„œ๋Š” deprecated ์ž…๋‹ˆ๋‹ค. ๊ฐ€๋“œ๊ฐ€ ๊ทธ ๊ฒฝ๋กœ์˜ ์žฌ๋„์ž…์„ ๋ง‰์Šต๋‹ˆ๋‹ค. ๊ฒฝ๊ณ ์ƒ‰ ํ…์ŠคํŠธ์˜ ๋Œ€์ฒด๋Š” **onWarningContainer**์ž…๋‹ˆ๋‹ค.

ํ†ค์€ ์Šคํฌ๋ฆฐ ๋ฆฌ๋”๊ฐ€ ๋ผ์–ด๋“œ๋Š” ์ •๋„๋ฅผ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค#

Alert ์˜ ํ†ต๋ณด ๋ฐฉ์‹์€ variant ๊ฐ€ ๊ฒฐ์ •ํ•˜๊ณ , ์–‘ ํ”Œ๋žซํผ์ด ๊ฐ™์€ ๊ฒฐ์ •์„ ์ฝ์Šต๋‹ˆ๋‹ค:

ํ†คWebFlutter
destructive role="alert" โ€” ์ฝ๋˜ ๋ฌธ์žฅ์„ ๋Š์Šต๋‹ˆ๋‹ค live region
warning ยท success ยท inforole="status" โ€” ์ฐจ๋ก€๋ฅผ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹คlive region
ํ†ค ์—†์Œ์—ญํ•  ์—†์Œlive region ์•„๋‹˜

Flutter ์—๋Š” ํ†ต๋ณด ์ถ•์ด ํ•˜๋‚˜๋ฟ์ด๋ผ polite/assertive ๊ตฌ๋ถ„์ด ์—†์Šต๋‹ˆ๋‹ค โ€” ๊ทธ ๊ตฌ๋ถ„๋งŒ Web ์ „์šฉ์ด๊ณ , ๋งคํ•‘ ์ž์ฒด๋Š” ๊ณต์œ ๋ฉ๋‹ˆ๋‹ค.

์ƒ‰์„ ์žฅ์‹์œผ๋กœ ๊ณ ๋ฅด๋ฉด ํŽ˜์ด์ง€๊ฐ€ ๋ง์„ ๋Š์Šต๋‹ˆ๋‹ค. ๋ฐฐ๋„ˆ ์„ธ ๊ฐœ๋ฅผ destructive ๋กœ ๋‘๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ ์•„๋ฌด๊ฒƒ๋„ ํ•˜๊ธฐ ์ „์— ์„ธ ๋ฒˆ ๋ง์ด ๋Š๊น๋‹ˆ๋‹ค.

๋Œ€๋น„ ๊ฒ€์ฆ#

๋ธŒ๋žœ๋“œ ํŒ”๋ ˆํŠธ๋ฅผ ์„ธ์› ๋‹ค๋ฉด ๋ผ์ดํŠธยท๋‹คํฌ ์‹œ๋งจํ‹ฑ ์Œ์˜ ๋Œ€๋น„๋ฅผ ํ…Œ์ŠคํŠธ๋กœ ๊ณ ์ •ํ•˜์„ธ์š”. coui_core ์˜ CoreContrast ๊ฐ€ WCAG 2.x ์ƒ๋Œ€ ํœ˜๋„์™€ ๋Œ€๋น„ ๋น„์œจ์„ ์ˆœ์ˆ˜ Dart ๋กœ ๊ณ„์‚ฐํ•˜๋ฏ€๋กœ, Flutter ์•ฑยทWeb ์•ฑยท๊ณจ๋“  ํ…Œ์ŠคํŠธ๊ฐ€ ๊ฐ™์€ ์ˆซ์ž๋ฅผ ๋ด…๋‹ˆ๋‹ค. ์•ฑ์—์„œ ํœ˜๋„ ๊ณต์‹์„ ๋‹ค์‹œ ์งœ์ง€ ๋งˆ์„ธ์š”.

์“ฐ๋Š” ์ด๋ฆ„์˜๋ฏธ
CoreContrast.relativeLuminance(color)์ƒ๋Œ€ ํœ˜๋„ (0 = ๊ฒ€์ •, 1 = ํฐ์ƒ‰)
CoreContrast.ratio(foreground, background)๋Œ€๋น„ ๋น„์œจ (1 ~ 21)
CoreContrast.meets(foreground, background, level) level ์„ ํ†ต๊ณผํ•˜๋Š”์ง€
CoreContrastLevel aaNormalText 4.5 ยท aaLargeText 3 ยท aaaNormalText 7 ยท aaaLargeText 4.5 ยท nonText 3
CoreContrast.auditScheme(scheme) ์Šคํ‚ด์˜ ๋Œ€ํ‘œ ์Œ์„ ํ•œ ๋ฒˆ์— ์ ๊ฒ€ํ•œ CoreContrastReport
final brand = PrimitiveColors.generate(/* ๋ธŒ๋žœ๋“œ ์‹œ๋“œ */);
final light = CoreSemanticMapping.light(brand).resolved(.light);
final dark = CoreSemanticMapping.dark(brand).resolved(.dark);

// ๋Œ€ํ‘œ ์Œ ํ•œ ๋ฒˆ์— โ€” ์‹คํŒจํ•œ ์Œ์ด reason ๋งจ ์œ„์— ์ฐํž™๋‹ˆ๋‹ค
for (final scheme in [light, dark]) {
  final report = CoreContrast.auditScheme(scheme);
  expect(report.failures, isEmpty, reason: report.toString());
}

// ์•ฑ์ด ์ง์ ‘ ์น ํ•˜๋Š” ์Œ
expect(
  CoreContrast.meets(light.onPrimaryContainer, light.surface, .aaNormalText),
  isTrue,
);
CoreContrast.ratio(const CoreColor(0xFF777777), const CoreColor(0xFFFFFFFF)); // 4.48

auditScheme ์˜ ๋Œ€ํ‘œ ์Œ์€ ์Šคํ‚ด์ด ๊ทธ๋ฆฌ๋ผ๊ณ  ๋งŒ๋“  ์กฐํ•ฉ์ž…๋‹ˆ๋‹ค โ€” ์—ญํ• ๋งˆ๋‹ค onX / X ์™€ onXContainer / XContainer, ํŽ˜์ด์ง€ ์œ„ onSurface ยท onSurfaceVariant ยท onSurfaceSubtle ยท placeholder ยท error, ์ด๋ฆ„์ด ๊ธฐ์ค€์„ ๋งํ•˜๋Š” primaryText(4.5:1) ยท primaryTextLarge(3:1), inverseOnSurface / inverseSurface, ์ปดํฌ๋„ŒํŠธ ๊ฒฝ๊ณ„ outline(3:1). ๋ชจ๋“  ์ปจํ…Œ์ด๋„ˆ ํ†คยทhover ์ฑ„์›€ยท์ปดํฌ๋„ŒํŠธ ๋ณ€ํ˜•๊นŒ์ง€ ํ›‘์ง€๋Š” ์•Š์œผ๋‹ˆ, ์•ฑ์ด ๋”ฐ๋กœ ์น ํ•˜๋Š” ์Œ์€ ratio / meets ๋กœ ์ง์ ‘ ๊ณ ์ •ํ•˜์„ธ์š”. ์žฅ์‹์šฉ outlineVariant ยท outlineSubtle ๊ณผ ๋น„ํ™œ์„ฑ ํ†ค์€ WCAG ๊ฐ€ ๋น„์œจ์„ ์š”๊ตฌํ•˜์ง€ ์•Š์•„ ๋„ฃ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ถ„๋ฅ˜์ƒ‰๋„ ๋„ฃ์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๊ธฐ์ค€์ด ๋ชจ๋“œ๋งˆ๋‹ค ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(๋ถ„๋ฅ˜์ƒ‰).

  • ์ž…๋ ฅ์€ ํ•ด์„๋œ ์ƒ‰์ž…๋‹ˆ๋‹ค โ€” ResolvedColorScheme ์˜ ์Šฌ๋กฏ์ด๋‚˜ Flutter scheme.resolve(token) ๊ฒฐ๊ณผ. ํ•ด์„ ์ „ CoreColor.token(...) ์€ ์ฑ„๋„์ด ์—†์–ด StateError ๋ฅผ ๋˜์ง‘๋‹ˆ๋‹ค.
  • ๋ฐ˜ํˆฌ๋ช… โ€” ๋Œ€๋น„๋Š” ๋ถˆํˆฌ๋ช…ํ•œ ๋‘ ์ƒ‰ ์‚ฌ์ด์—์„œ๋งŒ ์ •์˜๋ฉ๋‹ˆ๋‹ค. ๋ฐ˜ํˆฌ๋ช…ํ•œ ์ „๊ฒฝ์€ ๋ฐฐ๊ฒฝ ์œ„์— ํ•ฉ์„ฑ(source-over)ํ•œ ์ƒ‰์œผ๋กœ ์žฝ๋‹ˆ๋‹ค. ๋ฐ˜ํˆฌ๋ช…ํ•œ ๋ฐฐ๊ฒฝ์€ ๊ทธ ๋’ค์— ๋ฌด์—‡์ด ์žˆ๋А๋ƒ์— ๋‹ฌ๋ ค ํŒ์ •ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ArgumentError ์ž…๋‹ˆ๋‹ค โ€” ํ™”๋ฉด์— ์‹ค์ œ๋กœ ๋ณด์ด๋Š” ๋ถˆํˆฌ๋ช… ์ƒ‰์„ ๋„˜๊ธฐ์„ธ์š”(CoreContrast.compositeOver).
  • ๋ฐ˜์˜ฌ๋ฆผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” 4.48:1 ์€ ํ™”๋ฉด์— "4.5" ๋กœ ๋ณด์—ฌ๋„ aaNormalText ๋ฅผ ํ†ต๊ณผํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค.

CoUI ๊ธฐ๋ณธ ์ƒ‰(CouiColorPresets.source)์˜ ๋ผ์ดํŠธยท๋‹คํฌยท๊ณ ๋Œ€๋น„ ์Šคํ‚ด์€ ๋Œ€ํ‘œ ์Œ์„ ๋ชจ๋‘ ํ†ต๊ณผํ•˜๊ณ , ๊ทธ ์‚ฌ์‹ค์€ coui_core ํ…Œ์ŠคํŠธ๊ฐ€ ๊ณ ์ •ํ•ฉ๋‹ˆ๋‹ค.

์ „์ฒด ํ† ํฐ#

Surface

surface
surfaceDim
surfaceBright
surfaceContainerLowest
surfaceContainerLow
surfaceContainer
surfaceContainerHigh
surfaceContainerHighest
surfaceRaised
onSurface
onSurfaceVariant
onSurfaceSubtle
surfaceTint

Primary

primary
onPrimary
primaryContainer
onPrimaryContainer
primaryFixed
primaryFixedDim
onPrimaryFixed
onPrimaryFixedVariant

Secondary

secondary
onSecondary
secondaryContainer
onSecondaryContainer
secondaryFixed
secondaryFixedDim
onSecondaryFixed
onSecondaryFixedVariant

Accent

accent
onAccent

Tertiary

tertiary
onTertiary
tertiaryContainer
onTertiaryContainer
tertiaryFixed
tertiaryFixedDim
onTertiaryFixed
onTertiaryFixedVariant

Status

error
onError
errorContainer
onErrorContainer
success
onSuccess
successContainer
onSuccessContainer
warning
onWarning
warningContainer
onWarningContainer
info
onInfo
infoContainer
onInfoContainer

Status indicators

errorIcon
successIcon
warningIcon
infoIcon

Utility

outline
outlineVariant
inverseSurface
inverseOnSurface
inversePrimary
shadow
scrim

Syntax

syntaxKeyword
syntaxType
syntaxFunction
syntaxString

Category

categoryRed
onCategoryRed
categoryRedContainer
onCategoryRedContainer
categoryRedOutline
categoryOrange
onCategoryOrange
categoryOrangeContainer
onCategoryOrangeContainer
categoryOrangeOutline
categoryYellow
onCategoryYellow
categoryYellowContainer
onCategoryYellowContainer
categoryYellowOutline
categoryGreen
onCategoryGreen
categoryGreenContainer
onCategoryGreenContainer
categoryGreenOutline
categoryBlue
onCategoryBlue
categoryBlueContainer
onCategoryBlueContainer
categoryBlueOutline
categoryPurple
onCategoryPurple
categoryPurpleContainer
onCategoryPurpleContainer
categoryPurpleOutline
categoryPink
onCategoryPink
categoryPinkContainer
onCategoryPinkContainer
categoryPinkOutline
categoryBrown
onCategoryBrown
categoryBrownContainer
onCategoryBrownContainer
categoryBrownOutline
categoryGray
onCategoryGray
categoryGrayContainer
onCategoryGrayContainer
categoryGrayOutline

์ด ํ‘œ๋Š” glass* ๋„ค ์Šฌ๋กฏ์„ ๋ณด์—ฌ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๊ธฐ๋ณธ ํŒ”๋ ˆํŠธ๊ฐ€ ๊ทธ ์Šฌ๋กฏ์„ ์ฑ„์šฐ์ง€ ์•Š์•„ --coui-glass-* CSS ๋ณ€์ˆ˜๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ฐ’์„ ๋ช…์‹œํ•˜๋ฉด Liquid Glass ๋””์ž์ธ ์‹œ์Šคํ…œ ์–ด๋Œ‘ํ„ฐ(Flutter)๊ฐ€ ๊ทธ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ณ , ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด surfaceยทprimary ์—์„œ ํŒŒ์ƒํ•ฉ๋‹ˆ๋‹ค.