@iyulab/components 1.48.0 → 1.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/_virtual/_glob-assets_raw/dark.css.e8ac080d.js +1 -1
- package/dist/_virtual/_glob-assets_raw/light.css.637cb2f8.js +1 -1
- package/dist/components/UFloatingElement.styles.js +1 -1
- package/dist/components/UOverlayElement.d.ts +0 -8
- package/dist/components/UOverlayElement.js +2 -8
- package/dist/components/UOverlayElement.styles.js +1 -1
- package/dist/components/popover/UPopover.js +9 -2
- package/dist/styles/dark.css +12 -0
- package/dist/styles/light.css +12 -0
- package/dist/utilities/OverlayManager.d.ts +32 -0
- package/dist/utilities/OverlayManager.js +39 -1
- package/package.json +1 -1
- package/skills/iyulab-components/references/utilities/overlay-manager.md +21 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.49.0] - 2026-09-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **A layer stack for Escape: `OverlayManager.openLayer(el, onEscape)`, `closeLayer(el)`,
|
|
8
|
+
`topLayer`.** Every surface that closes on Escape is a layer, layers stack in the order they
|
|
9
|
+
opened, and one Escape closes the topmost one. `u-dialog`, `u-drawer` and an open `u-popover` are
|
|
10
|
+
layers; an app surface that is not an overlay component (a shell panel, a custom sheet) can join
|
|
11
|
+
the same order instead of listening for Escape itself. The manager listens once on `document`: an
|
|
12
|
+
Escape a control already handled closes no layer, and the Escape that closes one is marked
|
|
13
|
+
consumed, so listeners on `window` see `defaultPrevented`. `onEscape` receives the event and may
|
|
14
|
+
return `false` to decline — for a non-modal panel that only closes while focus is inside it —
|
|
15
|
+
which leaves the key unconsumed and closes nothing.
|
|
16
|
+
|
|
17
|
+
- **Stacking tokens for surfaces that overlap across the page: `--u-layer-shell` (1000),
|
|
18
|
+
`--u-layer-floating` (1000) and `--u-layer-overlay` (9999).** Floating elements and overlays now
|
|
19
|
+
read them (same values as before), so an app surface that must sit in the same order reads the
|
|
20
|
+
token instead of repeating a number. Both sheets declare them. See `docs/design-tokens.md`.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **A popover opened inside a popover now closes alone on Escape.** Each open popover listened for
|
|
25
|
+
Escape itself, so one press closed the whole chain (a submenu and its menu). The second press
|
|
26
|
+
closes the outer one.
|
|
27
|
+
|
|
3
28
|
## [1.48.0] - 2026-09-28
|
|
4
29
|
|
|
5
30
|
### Changed
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region \0glob-assets_raw/dark.css.e8ac080d
|
|
2
|
-
var dark_css_default = ":root[theme=\"dark\"] {\n color-scheme: dark;\n\n /* Neutral Colors */\n --u-neutral-0: #000000;\n --u-neutral-50: #0A0A0A;\n --u-neutral-100: #121212;\n --u-neutral-200: #1E1E1E;\n --u-neutral-300: #2A2A2A;\n --u-neutral-400: #3D3D3D;\n --u-neutral-500: #525252;\n --u-neutral-600: #6E6E6E;\n --u-neutral-700: #8A8A8A;\n --u-neutral-800: #B0B0B0;\n --u-neutral-900: #D4D4D4;\n --u-neutral-1000: #FFFFFF;\n\n /* Blue Colors */\n --u-blue-0: #030D1A;\n --u-blue-100: #061629;\n --u-blue-200: #0A223B;\n --u-blue-300: #103150;\n --u-blue-400: #174167;\n --u-blue-500: #205281;\n --u-blue-600: #2A659D;\n --u-blue-700: #3678B8;\n --u-blue-800: #478DCE;\n --u-blue-900: #5DA2DF;\n --u-blue-1000: #79BBEA;\n\n /* Green Colors */\n --u-green-0: #06140C;\n --u-green-100: #0A2114;\n --u-green-200: #10301D;\n --u-green-300: #164228;\n --u-green-400: #1F5535;\n --u-green-500: #2A6942;\n --u-green-600: #367E50;\n --u-green-700: #4A9563;\n --u-green-800: #63AB7A;\n --u-green-900: #80BE97;\n --u-green-1000: #9BCFB1;\n\n /* Yellow Colors */\n --u-yellow-0: #1C1300;\n --u-yellow-100: #2D1E00;\n --u-yellow-200: #402B00;\n --u-yellow-300: #553900;\n --u-yellow-400: #6B4900;\n --u-yellow-500: #825A00;\n --u-yellow-600: #9A6C00;\n --u-yellow-700: #B08012;\n --u-yellow-800: #C69635;\n --u-yellow-900: #D9AD5A;\n --u-yellow-1000: #E8C57F;\n\n /* Red Colors */\n --u-red-0: #1C0707;\n --u-red-100: #2C0B0B;\n --u-red-200: #3E1111;\n --u-red-300: #541818;\n --u-red-400: #6C2020;\n --u-red-500: #852A2A;\n --u-red-600: #A13535;\n --u-red-700: #B94949;\n --u-red-800: #CB6262;\n --u-red-900: #D98383;\n --u-red-1000: #E7A2A2;\n\n /* Orange Colors */\n --u-orange-0: #1D0E00;\n --u-orange-100: #2F1700;\n --u-orange-200: #421F00;\n --u-orange-300: #582A00;\n --u-orange-400: #703600;\n --u-orange-500: #8A4500;\n --u-orange-600: #A55600;\n --u-orange-700: #BD6A18;\n --u-orange-800: #D1823C;\n --u-orange-900: #E19D67;\n --u-orange-1000: #EDB992;\n\n /* Teal Colors */\n --u-teal-0: #041411;\n --u-teal-100: #07201B;\n --u-teal-200: #0B2E28;\n --u-teal-300: #10403A;\n --u-teal-400: #16544D;\n --u-teal-500: #1E6860;\n --u-teal-600: #297D74;\n --u-teal-700: #3A9389;\n --u-teal-800: #54A89F;\n --u-teal-900: #73BBB3;\n --u-teal-1000: #93CBC5;\n\n /* Cyan Colors */\n --u-cyan-0: #041318;\n --u-cyan-100: #071F29;\n --u-cyan-200: #0B2D3A;\n --u-cyan-300: #104050;\n --u-cyan-400: #165469;\n --u-cyan-500: #1E6A82;\n --u-cyan-600: #287F9C;\n --u-cyan-700: #3995B5;\n --u-cyan-800: #53AACC;\n --u-cyan-900: #73BEDD;\n --u-cyan-1000: #95CFE8;\n\n /* Purple Colors */\n --u-purple-0: #150A22;\n --u-purple-100: #220F36;\n --u-purple-200: #31164B;\n --u-purple-300: #432064;\n --u-purple-400: #572B80;\n --u-purple-500: #6C379C;\n --u-purple-600: #8245B7;\n --u-purple-700: #975BCB;\n --u-purple-800: #AB79D9;\n --u-purple-900: #BD99E2;\n --u-purple-1000: #CEB8EA;\n\n /* Pink Colors */\n --u-pink-0: #1F0A14;\n --u-pink-100: #310F20;\n --u-pink-200: #451532;\n --u-pink-300: #5C1D45;\n --u-pink-400: #74285A;\n --u-pink-500: #8F336F;\n --u-pink-600: #AB4187;\n --u-pink-700: #C0569D;\n --u-pink-800: #D174B3;\n --u-pink-900: #E095C7;\n --u-pink-1000: #EBB5D9;\n\n /* ==========================================================================\n Role Colors — 의미 역할 층\n 컴포넌트는 팔레트 프리미티브가 아니라 이 층을 참조한다.\n 브랜드 색 교체는 아래 25개만 재정의하면 시맨틱 층까지 따라온다.\n\n 단은 '강도' 축이다 (weakest -> strong). 용도(배경/테두리/텍스트)는\n 소비처가 정한다 -- 단을 속성에 묶으면 primary 버튼의 배경이 어느\n 단인지 같은 모순이 생긴다.\n\n ★**다만 두 단은 용도가 확정돼 있다** — 대비 요구가 서로 다르기 때문이다.\n `-color` = **면**. `--u-*-txt-color` 가 그 위에 얹히므로 on-color 기준 4.5.\n `-strong` = **글자·아이콘**. `--u-bg-color` 위에 놓이므로 바탕 기준 4.5.\n 라이트에서는 바탕도 on-color 도 흰색이라 두 요구가 한 조건으로 합쳐지지만,\n **다크에서는 정반대 방향**이다(바탕 #121212 · on-color #FFFFFF). 바탕에서 읽히는\n 밝은 단은 흰 글자를 못 받고, 흰 글자를 받는 어두운 단은 바탕에서 안 읽힌다.\n ⇒ 다크에서 `-color` 와 `-strong` 이 두 단 벌어지는 것이 그 결과다.\n `tests/build/token-contrast.test.ts` 가 값을 지킨다.\n ========================================================================== */\n\n /* primary — 브랜드 · 강조 · 포커스 · 링크 */\n --u-primary-color-weakest: var(--u-blue-200);\n --u-primary-color-weaker: var(--u-blue-300);\n --u-primary-color-weak: var(--u-blue-500);\n --u-primary-color: var(--u-blue-600); /* 면: 흰 글자 6.09 ✓ */\n --u-primary-color-strong: var(--u-blue-800); /* 글자: 바탕 5.32 ✓ (700 은 4.05 ✗) */\n\n /* info — 정보 안내 (primary 와 기본값은 같으나 역할이 다르다 — 브랜딩은 primary 만 바꾼다) */\n --u-info-color-weakest: var(--u-blue-200);\n --u-info-color-weaker: var(--u-blue-300);\n --u-info-color-weak: var(--u-blue-500);\n --u-info-color: var(--u-blue-600);\n --u-info-color-strong: var(--u-blue-800);\n\n /* success — 성공 · 완료 */\n --u-success-color-weakest: var(--u-green-200);\n --u-success-color-weaker: var(--u-green-300);\n --u-success-color-weak: var(--u-green-500);\n --u-success-color: var(--u-green-600);\n --u-success-color-strong: var(--u-green-700);\n\n /* warning — 주의 */\n --u-warning-color-weakest: var(--u-yellow-200);\n --u-warning-color-weaker: var(--u-yellow-300);\n --u-warning-color-weak: var(--u-yellow-500);\n --u-warning-color: var(--u-yellow-600);\n --u-warning-color-strong: var(--u-yellow-700);\n\n /* danger — 오류 · 위험 · 유효성 실패 */\n --u-danger-color-weakest: var(--u-red-200);\n --u-danger-color-weaker: var(--u-red-300);\n --u-danger-color-weak: var(--u-red-500);\n --u-danger-color: var(--u-red-600); /* 면: 흰 글자 6.83 ✓ */\n --u-danger-color-strong: var(--u-red-800); /* 글자: 바탕 4.87 ✓ (700 은 3.67 ✗) */\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-100);\n\n /* 유채색 배경 위의 글자 — warning 만 다르다(light.css 참조). */\n --u-primary-txt-color: #FFFFFF;\n --u-info-txt-color: #FFFFFF;\n --u-success-txt-color: #FFFFFF;\n --u-danger-txt-color: #FFFFFF;\n /* ★라이트 시트와 같은 이유로 중립 최상단을 쓴다 — 다크에서는 그 값이 #FFFFFF 라\n 결과가 종전과 같다(4.65 ✓). 리터럴 대신 토큰을 쓰는 이유는 라이트에서 뒤집히기\n 때문이다(#000000). 두 시트가 같은 선언이 되어 어긋날 자리가 없어진다. */\n --u-warning-txt-color: var(--u-neutral-1000);\n --u-txt-color-hover: var(--u-primary-color-strong);\n --u-txt-color-active: var(--u-primary-color-strong);\n --u-txt-color-disabled: var(--u-neutral-500);\n /* 라이트와 같은 기준 — 놓이는 모든 면에서 AA. neutral-700(#8A8A8A)은 바탕 5.43 ·\n 올림면(neutral-300) 4.16 · active 면(neutral-400) 3.15 로 미달이었다.\n neutral-800(#B0B0B0) = 8.64 · 6.62 · 5.01. 본문(neutral-900)과의 대비비 1.46. */\n --u-txt-color-weak: var(--u-neutral-800);\n --u-txt-color-strong: var(--u-neutral-1000);\n\n --u-link-txt-color: var(--u-primary-color-strong);\n --u-tooltip-txt-color: var(--u-neutral-100);\n\n /* Icon Colors */\n --u-icon-color: var(--u-neutral-800);\n --u-icon-color-inverse: var(--u-neutral-100);\n --u-icon-color-hover: var(--u-primary-color-strong);\n --u-icon-color-active: var(--u-primary-color-strong);\n --u-icon-color-disabled: var(--u-neutral-500);\n\n /* Border Colors\n ★`-weak` 는 `neutral-300` 일 수 없다 — `--u-bg-color-raised` 가 같은 단이라, 올림면(사이드바·\n 표 머리/행·마스터-디테일 구분선) 위에 그리는 약한 선이 **면과 같은 색**(대비 1.00)이 되어\n 화면에서 사라진다. 라이트는 200 단이 올림면(50)과 떨어져 있어 보인다. 램프에서 올림면(300)\n 위로 올릴 수 있는 다음 단이 400 뿐이라 `-weak` 는 이 테마에서 `--u-border-color` 와 같은\n 단이다 — 다크에서는 «약함/보통» 두 단이 하나로 합쳐지지만, 종전 `-weak` 는 그것이 쓰이는\n 면 위에서 애초에 구별되지 않았다. */\n --u-border-color: var(--u-neutral-400);\n --u-border-color-weak: var(--u-neutral-400);\n --u-border-color-strong: var(--u-neutral-500);\n --u-border-color-hover: var(--u-neutral-500);\n\n /* ★상태 테두리는 `-strong` 단이다 — light.css 의 같은 자리 주석 참조.\n 이 테마가 실제로 미달이었다: focus 2.74 · invalid 2.44 → 4.74 / 4.34. */\n --u-input-border-color: var(--u-neutral-400);\n --u-input-border-color-hover: var(--u-neutral-500);\n --u-input-border-color-focus: var(--u-primary-color-strong);\n --u-input-border-color-invalid: var(--u-danger-color-strong);\n\n /* Background Colors */\n --u-bg-color: var(--u-neutral-100);\n --u-bg-color-inverse: var(--u-neutral-0);\n --u-bg-color-hover: var(--u-neutral-300);\n --u-bg-color-active: var(--u-neutral-400);\n --u-bg-color-disabled: var(--u-neutral-100);\n\n /* 면 높이 — 상세는 light.css 참조. 다크는 **바탕보다 밝은 쪽**이 위다.\n neutral-300(#2A2A2A)은 바탕(#121212) 대비 1.42 로, 소비 측이 오버라이드로 쓰던\n neutral-200(1.15)보다 실제로 더 잘 구분된다 — 그 오버라이드가 해결하려던 증상이\n *\"툴바·헤더가 배경에 묻힌다\"* 였다. */\n --u-bg-color-raised: var(--u-neutral-300);\n\n /* ★올림면 위의 hover — `--u-bg-color-hover`(전역, 바탕면 전용)와 값이 같아서\n («둘 다 neutral-300») 카드·표 머리 위에 마우스를 올려도 아무 일도 안 일어났다\n (소비자 실측). 전역 토큰 하나로는 \"지금 위에 있는 면\"을\n 알 방법이 없어(참조 지점마다 계산 기준이 다를 수 없다) **전용 토큰**을 신설한다.\n\n ⚠**A안**(`raised`를 neutral-200으로) — 과거에 거부된 값(위 주석). **B안**(전역\n `hover`를 neutral-400으로) — `--u-bg-color-active` 와 충돌해 결함이 다른 쌍으로\n 옮겨간다. ⇒ hover 는 본래 \"현재 면보다 한 단 위\"이지 절대 단이 아니므로\n `color-mix()` 로 raised 자신을 기준 삼아 상대 계산한다.\n\n N=6% 는 raised(L≈0.023)와 active(L≈0.047, neutral-400) 사이 대비 계산으로 골랐다 —\n 결과 L≈0.038, raised 대비 ≈1.21(라이트의 기존 \"약한\" 1.04보다 뚜렷하고, `bg→raised`\n 의 기존 1.31 과 비슷한 체감), active 와는 값이 달라 겹치지 않는다(≈#373737 vs\n active #3D3D3D). N 을 더 올리면(≈10%+) active 를 넘어서 순서가 뒤집힌다 — 확인함. */\n --u-bg-color-raised-hover: color-mix(in srgb, var(--u-bg-color-raised), white 6%);\n\n /* 유채색 표면 — 라이트와 **같은 단이 아니라 같은 세기**로 짝지었다(light.css 참조).\n 팔레트 유채색 틴트가 다크에서 짓눌리므로 한 단 위를 쓴다. green 은 대칭이라 그대로. */\n --u-primary-bg-color: var(--u-blue-100);\n --u-info-bg-color: var(--u-blue-100);\n --u-success-bg-color: var(--u-green-0);\n --u-danger-bg-color: var(--u-red-100);\n /* warning 합류 — 라이트는 yellow-200 이다(단 이름이 다른 이유는 light.css 참조). */\n --u-warning-bg-color: var(--u-yellow-100);\n\n --u-input-bg-color: var(--u-neutral-200);\n --u-panel-bg-color: var(--u-neutral-200);\n --u-overlay-bg-color: rgba(0, 0, 0, 0.7);\n --u-tooltip-bg-color: rgba(255, 255, 255, 0.85);\n\n /* Shadow Colors */\n --u-shadow-color-weaker: rgba(0, 0, 0, 0.15);\n --u-shadow-color-weak: rgba(0, 0, 0, 0.25);\n --u-shadow-color-normal: rgba(0, 0, 0, 0.35);\n --u-shadow-color-strong: rgba(0, 0, 0, 0.45);\n --u-shadow-color-stronger: rgba(0, 0, 0, 0.60);\n\n /* Elevation Scale — 근거는 light.css 의 같은 자리 주석 참조.\n ★다크는 알파가 3배 가까이 진하다 — 리터럴로 흩어져 있던 종전에는 이 차이가\n 적용되지 않아 다크에서 그림자가 사실상 보이지 않았다. */\n --u-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25), 0 1px 1px rgba(0, 0, 0, 0.14); /* = shadow-color-weak */\n --u-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.18); /* = shadow-color-normal */\n --u-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.45), 0 2px 4px rgba(0, 0, 0, 0.22); /* = shadow-color-strong */\n --u-shadow-xl: 0 6px 18px rgba(0, 0, 0, 0.60), 0 2px 6px rgba(0, 0, 0, 0.30); /* = shadow-color-stronger */\n\n\n /* ==========================================================================\n Chart categorical palette — 다크 면(#121212 · 올림면 #2A2A2A)에 대해 **따로 고른** 여덟 칸\n ★램프를 참조하지 않는 이유: 다크 장식 램프는 채도가 낮아(면 위 배지·태그용) 차트 계열로는\n 회색처럼 읽힌다 — 램프의 단 조합 39만 가지 중 검증을 통과한 것이 없었다. 그래서 라이트\n 여덟 칸과 **같은 색상·순서**를 OKLCH 밝기만 다크 대역으로 옮겨 잡았다.\n 검증: 밝기 0.48–0.67 · 채도 ≥ 0.1 · 색각 이상 이웃 ΔE ≥ 9.5 · 정상 시각 이웃 ΔE ≥ 25.1 ·\n 두 면 모두 대비 ≥ 3:1. 순서는 light.css 와 같다.\n ========================================================================== */\n --u-chart-color-1: #247EDB;\n --u-chart-color-2: #D03E73;\n --u-chart-color-3: #0DA1B2;\n --u-chart-color-4: #ED5711;\n --u-chart-color-5: #059183;\n --u-chart-color-6: #D96D04;\n --u-chart-color-7: #AE48CB;\n --u-chart-color-8: #4AA74D;\n\n /* Scrollbar Colors */\n --u-scrollbar-color: var(--u-neutral-500);\n --u-scrollbar-color-hover: var(--u-neutral-600);\n --u-scrollbar-track-color: transparent;\n}\n\n/* ==========================================================================\n ★모드와 무관한 스케일 — 반경·여백·글자 스케일·모션·글꼴.\n 값이 light.css 와 **같다.** 그런데 위 블록(`:root[theme=\"dark\"]`, 특이도 0,1,1)에 두면\n `:root`(0,1,0)로 이 토큰을 덮는 **모든 층**(하우스 프리셋·소비자 브랜드 시트)이 다크\n 모드에서만 **로드 순서와 무관하게** 진다 — 에러도 경고도 없이, 색은 정상으로 바뀌므로\n «다크가 잘 된다» 로 보인다. `:where()` 로 특이도를 `:root` 와 같게 두면 층 모델이 라이트와\n 똑같이 로드 순서로 선다.\n ⚠이 블록을 지우지 말 것 — 이 시트만 쓰는 «고정 다크 디자인» 소비자(docs/theming.md)는\n 이 토큰들을 여기서 받는다. 두 시트를 함께 쓸 때는 값이 같으므로 어느 쪽이 이겨도 같다.\n ========================================================================== */\n:root:where([theme=\"dark\"]) {\n /* ==========================================================================\n Radius Scale — 모서리 반경\n 리터럴을 흩뿌리면 값이 갈린다(실제로 pill 이 999px/9999px 두 표기로 나뉘어 있었다).\n ========================================================================== */\n --u-radius-none: 0;\n --u-radius-sm: 3px;\n --u-radius-md: 4px;\n --u-radius-lg: 6px;\n --u-radius-xl: 8px;\n /* ★상단 2단은 **면(surface)용**이다 — 카드·패널·대화상자처럼 큰 사각형은 컨트롤과\n 같은 반경을 쓰면 각져 보인다. 기존 5단은 **컨트롤용**이고 값을 바꾸지 않는다\n (바꾸면 모든 소비자의 버튼·입력이 동시에 움직인다). */\n --u-radius-2xl: 12px;\n --u-radius-3xl: 16px;\n --u-radius-pill: 9999px;\n --u-radius-circle: 50%;\n\n /* ==========================================================================\n Space Scale — 컨테이너·오버레이의 절대 여백\n ⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이의 **레이아웃 여백**만\n 담당한다. 폼·인라인 요소의 `em` 여백은 상속된 `font-size` 에 비례하는 것이 의도이므로\n **여기로 흡수하지 않는다.** 반경과 마찬가지로 테마와 무관하므로 두 시트가 같다.\n 축 구분과 근거는 docs/design-tokens.md 참조.\n ========================================================================== */\n --u-space-3xs: 2px;\n --u-space-2xs: 4px;\n --u-space-xs: 6px;\n --u-space-sm: 8px;\n --u-space-md: 12px;\n --u-space-lg: 16px;\n /* ★상단 4단은 **화면 리듬**이다 — 카드 안쪽 여백(20~24)·섹션 간격(24~32)·페이지 여백\n (32~40). 종전에는 이 구간이 통째로 비어 있어 소비자가 전부 리터럴로 적었고,\n 그래서 앱마다 화면 밀도가 달라졌다. `lg`(16px) 이하는 **요소 사이**, `xl` 이상은\n **영역 사이**로 나눠 쓴다.\n ⚠`xs: 6px` 는 4px 격자에서 벗어나 있으나 **바꾸지 않는다** — 이미 배선된 컨트롤\n 여백이 전부 움직인다. 신규 단은 전부 4의 배수로 둔다. */\n --u-space-xl: 20px;\n --u-space-2xl: 24px;\n --u-space-3xl: 32px;\n --u-space-4xl: 40px;\n\n /* ==========================================================================\n Type Scale — 글자 크기·굵기·행간·자간의 **한 벌**\n ★**크기만 주면 스케일이 되지 않는다.** 소비자가 크기만 받고 굵기·행간을 각자 정하면\n 결국 화면마다 다른 위계가 생긴다 — 그래서 네 값을 **단 단위로 묶어** 낸다.\n\n 단 이름은 크기가 아니라 **역할**이다(`lg`/`xl` 이 아니라 `title`/`label`). 역할로 두면\n 소비자가 *\"어느 크기를 쓸까\"* 가 아니라 *\"이 글자는 무엇인가\"* 를 묻게 된다.\n\n ★**한글 기준으로 값을 골랐다**:\n ⑴ 행간은 **1.4 이상**. 라틴 관례(1.2)는 한글에서 답답하다 — 받침 때문에 글자 상자가\n 세로로 꽉 차 있어 라틴과 같은 행간이면 줄이 붙어 보인다.\n ⑵ 자간은 **0 이 기본**이고 큰 제목만 **음수**. 한글에 양수 자간(letter-spacing)을 주면\n 가독성이 떨어진다 — 라틴 소문자 조판 관례를 그대로 옮기면 안 되는 자리다.\n ⑶ `overline` 에만 양수 자간을 둔다. 그 단은 **영문·숫자 라벨**을 전제한 자리이고,\n 한글을 넣을 소비자는 자간을 0 으로 덮어야 한다(문서에 명시).\n\n ⚠**`text-transform` 은 토큰으로 내지 않는다.** 한글에는 대문자가 없어 `uppercase` 가\n 아무 효과가 없고, 영문이 섞이면 그것만 커져 오히려 어수선해진다.\n ========================================================================== */\n --u-text-display-size: 26px;\n --u-text-display-weight: 700;\n --u-text-display-leading: 1.4;\n --u-text-display-tracking: -0.02em;\n\n --u-text-title-size: 20px;\n --u-text-title-weight: 700;\n --u-text-title-leading: 1.45;\n --u-text-title-tracking: -0.01em;\n\n --u-text-subtitle-size: 16px;\n --u-text-subtitle-weight: 600;\n --u-text-subtitle-leading: 1.5;\n --u-text-subtitle-tracking: 0;\n\n --u-text-body-size: 14px;\n --u-text-body-weight: 400;\n --u-text-body-leading: 1.6;\n --u-text-body-tracking: 0;\n\n --u-text-label-size: 13px;\n --u-text-label-weight: 600;\n --u-text-label-leading: 1.5;\n --u-text-label-tracking: 0;\n\n --u-text-caption-size: 12px;\n --u-text-caption-weight: 400;\n --u-text-caption-leading: 1.5;\n --u-text-caption-tracking: 0;\n\n --u-text-overline-size: 11px;\n --u-text-overline-weight: 700;\n --u-text-overline-leading: 1.45;\n --u-text-overline-tracking: 0.06em;\n\n /* ==========================================================================\n Motion — 지속시간·이징\n ★값이 없으면 앱마다 다른 속도가 생기고, `prefers-reduced-motion` 은 **반드시**\n 빠뜨리는 앱이 나온다. 축을 여기 두고 존중 규칙은 아래 미디어 쿼리가 진다.\n ========================================================================== */\n --u-duration-instant: 80ms;\n --u-duration-fast: 140ms;\n --u-duration-normal: 220ms;\n --u-duration-slow: 320ms;\n --u-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --u-ease-decelerate: cubic-bezier(0, 0, 0, 1);\n --u-ease-accelerate: cubic-bezier(0.3, 0, 1, 1);\n\n /* ==========================================================================\n Font Styles\n ★**CJK 폴백을 스택에 포함한다 — 국제화이지 취향이 아니다.**\n 종전 스택(`-apple-system, Segoe UI, Noto Sans, Helvetica, Arial`)에는 **한중일 글립을\n 가진 폰트가 하나도 없었다.** Windows 에서 한글은 `Segoe UI` 에 없으므로 UA 가 임의로\n 맑은 고딕을 고르고, macOS 는 `-apple-system` 이 Apple SD Gothic Neo 를 준다 ⇒ **같은 앱이\n OS 마다 다른 글꼴로 렌더**됐다. 폴백을 명시하면 그 선택이 결정적이 된다.\n ⚠**웹폰트를 로드하지 않는다.** 라이브러리가 네트워크 요청을 만들면 소비자의 CSP·\n 오프라인 환경을 깬다. 스택 맨 앞의 `Pretendard` 는 **소비자가 로드했을 때만** 잡히는\n 선택적 이름이다(없으면 조용히 다음으로 넘어간다).\n ========================================================================== */\n --u-font-base: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', 'Hiragino Sans', 'Yu Gothic UI', 'Microsoft YaHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';\n --u-font-mono: ui-monospace, 'Cascadia Code', Consolas, 'Source Code Pro', Menlo, Monaco, 'Courier New', monospace;\n --u-font-serif: 'Georgia', 'Times New Roman', Times, serif;\n --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;\n --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n/* ★`prefers-reduced-motion` — light.css 와 같은 규칙을 이 시트도 진다. 이 시트만 쓰는\n 소비자가 있고, 두 시트를 함께 쓸 때는 어느 시트가 뒤에 오든 **마지막 선언이 이 0ms**\n 가 되도록 각 시트가 자기 블록 뒤에 둔다. 종전에는 지속시간이 위 (0,1,1) 블록에 있어\n 다크 모드에서 «동작 줄이기» 설정이 **무시됐다.** */\n@media (prefers-reduced-motion: reduce) {\n :root:where([theme=\"dark\"]) {\n --u-duration-instant: 0ms;\n --u-duration-fast: 0ms;\n --u-duration-normal: 0ms;\n --u-duration-slow: 0ms;\n }\n}\n";
|
|
2
|
+
var dark_css_default = ":root[theme=\"dark\"] {\n color-scheme: dark;\n\n /* Neutral Colors */\n --u-neutral-0: #000000;\n --u-neutral-50: #0A0A0A;\n --u-neutral-100: #121212;\n --u-neutral-200: #1E1E1E;\n --u-neutral-300: #2A2A2A;\n --u-neutral-400: #3D3D3D;\n --u-neutral-500: #525252;\n --u-neutral-600: #6E6E6E;\n --u-neutral-700: #8A8A8A;\n --u-neutral-800: #B0B0B0;\n --u-neutral-900: #D4D4D4;\n --u-neutral-1000: #FFFFFF;\n\n /* Blue Colors */\n --u-blue-0: #030D1A;\n --u-blue-100: #061629;\n --u-blue-200: #0A223B;\n --u-blue-300: #103150;\n --u-blue-400: #174167;\n --u-blue-500: #205281;\n --u-blue-600: #2A659D;\n --u-blue-700: #3678B8;\n --u-blue-800: #478DCE;\n --u-blue-900: #5DA2DF;\n --u-blue-1000: #79BBEA;\n\n /* Green Colors */\n --u-green-0: #06140C;\n --u-green-100: #0A2114;\n --u-green-200: #10301D;\n --u-green-300: #164228;\n --u-green-400: #1F5535;\n --u-green-500: #2A6942;\n --u-green-600: #367E50;\n --u-green-700: #4A9563;\n --u-green-800: #63AB7A;\n --u-green-900: #80BE97;\n --u-green-1000: #9BCFB1;\n\n /* Yellow Colors */\n --u-yellow-0: #1C1300;\n --u-yellow-100: #2D1E00;\n --u-yellow-200: #402B00;\n --u-yellow-300: #553900;\n --u-yellow-400: #6B4900;\n --u-yellow-500: #825A00;\n --u-yellow-600: #9A6C00;\n --u-yellow-700: #B08012;\n --u-yellow-800: #C69635;\n --u-yellow-900: #D9AD5A;\n --u-yellow-1000: #E8C57F;\n\n /* Red Colors */\n --u-red-0: #1C0707;\n --u-red-100: #2C0B0B;\n --u-red-200: #3E1111;\n --u-red-300: #541818;\n --u-red-400: #6C2020;\n --u-red-500: #852A2A;\n --u-red-600: #A13535;\n --u-red-700: #B94949;\n --u-red-800: #CB6262;\n --u-red-900: #D98383;\n --u-red-1000: #E7A2A2;\n\n /* Orange Colors */\n --u-orange-0: #1D0E00;\n --u-orange-100: #2F1700;\n --u-orange-200: #421F00;\n --u-orange-300: #582A00;\n --u-orange-400: #703600;\n --u-orange-500: #8A4500;\n --u-orange-600: #A55600;\n --u-orange-700: #BD6A18;\n --u-orange-800: #D1823C;\n --u-orange-900: #E19D67;\n --u-orange-1000: #EDB992;\n\n /* Teal Colors */\n --u-teal-0: #041411;\n --u-teal-100: #07201B;\n --u-teal-200: #0B2E28;\n --u-teal-300: #10403A;\n --u-teal-400: #16544D;\n --u-teal-500: #1E6860;\n --u-teal-600: #297D74;\n --u-teal-700: #3A9389;\n --u-teal-800: #54A89F;\n --u-teal-900: #73BBB3;\n --u-teal-1000: #93CBC5;\n\n /* Cyan Colors */\n --u-cyan-0: #041318;\n --u-cyan-100: #071F29;\n --u-cyan-200: #0B2D3A;\n --u-cyan-300: #104050;\n --u-cyan-400: #165469;\n --u-cyan-500: #1E6A82;\n --u-cyan-600: #287F9C;\n --u-cyan-700: #3995B5;\n --u-cyan-800: #53AACC;\n --u-cyan-900: #73BEDD;\n --u-cyan-1000: #95CFE8;\n\n /* Purple Colors */\n --u-purple-0: #150A22;\n --u-purple-100: #220F36;\n --u-purple-200: #31164B;\n --u-purple-300: #432064;\n --u-purple-400: #572B80;\n --u-purple-500: #6C379C;\n --u-purple-600: #8245B7;\n --u-purple-700: #975BCB;\n --u-purple-800: #AB79D9;\n --u-purple-900: #BD99E2;\n --u-purple-1000: #CEB8EA;\n\n /* Pink Colors */\n --u-pink-0: #1F0A14;\n --u-pink-100: #310F20;\n --u-pink-200: #451532;\n --u-pink-300: #5C1D45;\n --u-pink-400: #74285A;\n --u-pink-500: #8F336F;\n --u-pink-600: #AB4187;\n --u-pink-700: #C0569D;\n --u-pink-800: #D174B3;\n --u-pink-900: #E095C7;\n --u-pink-1000: #EBB5D9;\n\n /* ==========================================================================\n Role Colors — 의미 역할 층\n 컴포넌트는 팔레트 프리미티브가 아니라 이 층을 참조한다.\n 브랜드 색 교체는 아래 25개만 재정의하면 시맨틱 층까지 따라온다.\n\n 단은 '강도' 축이다 (weakest -> strong). 용도(배경/테두리/텍스트)는\n 소비처가 정한다 -- 단을 속성에 묶으면 primary 버튼의 배경이 어느\n 단인지 같은 모순이 생긴다.\n\n ★**다만 두 단은 용도가 확정돼 있다** — 대비 요구가 서로 다르기 때문이다.\n `-color` = **면**. `--u-*-txt-color` 가 그 위에 얹히므로 on-color 기준 4.5.\n `-strong` = **글자·아이콘**. `--u-bg-color` 위에 놓이므로 바탕 기준 4.5.\n 라이트에서는 바탕도 on-color 도 흰색이라 두 요구가 한 조건으로 합쳐지지만,\n **다크에서는 정반대 방향**이다(바탕 #121212 · on-color #FFFFFF). 바탕에서 읽히는\n 밝은 단은 흰 글자를 못 받고, 흰 글자를 받는 어두운 단은 바탕에서 안 읽힌다.\n ⇒ 다크에서 `-color` 와 `-strong` 이 두 단 벌어지는 것이 그 결과다.\n `tests/build/token-contrast.test.ts` 가 값을 지킨다.\n ========================================================================== */\n\n /* primary — 브랜드 · 강조 · 포커스 · 링크 */\n --u-primary-color-weakest: var(--u-blue-200);\n --u-primary-color-weaker: var(--u-blue-300);\n --u-primary-color-weak: var(--u-blue-500);\n --u-primary-color: var(--u-blue-600); /* 면: 흰 글자 6.09 ✓ */\n --u-primary-color-strong: var(--u-blue-800); /* 글자: 바탕 5.32 ✓ (700 은 4.05 ✗) */\n\n /* info — 정보 안내 (primary 와 기본값은 같으나 역할이 다르다 — 브랜딩은 primary 만 바꾼다) */\n --u-info-color-weakest: var(--u-blue-200);\n --u-info-color-weaker: var(--u-blue-300);\n --u-info-color-weak: var(--u-blue-500);\n --u-info-color: var(--u-blue-600);\n --u-info-color-strong: var(--u-blue-800);\n\n /* success — 성공 · 완료 */\n --u-success-color-weakest: var(--u-green-200);\n --u-success-color-weaker: var(--u-green-300);\n --u-success-color-weak: var(--u-green-500);\n --u-success-color: var(--u-green-600);\n --u-success-color-strong: var(--u-green-700);\n\n /* warning — 주의 */\n --u-warning-color-weakest: var(--u-yellow-200);\n --u-warning-color-weaker: var(--u-yellow-300);\n --u-warning-color-weak: var(--u-yellow-500);\n --u-warning-color: var(--u-yellow-600);\n --u-warning-color-strong: var(--u-yellow-700);\n\n /* danger — 오류 · 위험 · 유효성 실패 */\n --u-danger-color-weakest: var(--u-red-200);\n --u-danger-color-weaker: var(--u-red-300);\n --u-danger-color-weak: var(--u-red-500);\n --u-danger-color: var(--u-red-600); /* 면: 흰 글자 6.83 ✓ */\n --u-danger-color-strong: var(--u-red-800); /* 글자: 바탕 4.87 ✓ (700 은 3.67 ✗) */\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-100);\n\n /* 유채색 배경 위의 글자 — warning 만 다르다(light.css 참조). */\n --u-primary-txt-color: #FFFFFF;\n --u-info-txt-color: #FFFFFF;\n --u-success-txt-color: #FFFFFF;\n --u-danger-txt-color: #FFFFFF;\n /* ★라이트 시트와 같은 이유로 중립 최상단을 쓴다 — 다크에서는 그 값이 #FFFFFF 라\n 결과가 종전과 같다(4.65 ✓). 리터럴 대신 토큰을 쓰는 이유는 라이트에서 뒤집히기\n 때문이다(#000000). 두 시트가 같은 선언이 되어 어긋날 자리가 없어진다. */\n --u-warning-txt-color: var(--u-neutral-1000);\n --u-txt-color-hover: var(--u-primary-color-strong);\n --u-txt-color-active: var(--u-primary-color-strong);\n --u-txt-color-disabled: var(--u-neutral-500);\n /* 라이트와 같은 기준 — 놓이는 모든 면에서 AA. neutral-700(#8A8A8A)은 바탕 5.43 ·\n 올림면(neutral-300) 4.16 · active 면(neutral-400) 3.15 로 미달이었다.\n neutral-800(#B0B0B0) = 8.64 · 6.62 · 5.01. 본문(neutral-900)과의 대비비 1.46. */\n --u-txt-color-weak: var(--u-neutral-800);\n --u-txt-color-strong: var(--u-neutral-1000);\n\n --u-link-txt-color: var(--u-primary-color-strong);\n --u-tooltip-txt-color: var(--u-neutral-100);\n\n /* Icon Colors */\n --u-icon-color: var(--u-neutral-800);\n --u-icon-color-inverse: var(--u-neutral-100);\n --u-icon-color-hover: var(--u-primary-color-strong);\n --u-icon-color-active: var(--u-primary-color-strong);\n --u-icon-color-disabled: var(--u-neutral-500);\n\n /* Border Colors\n ★`-weak` 는 `neutral-300` 일 수 없다 — `--u-bg-color-raised` 가 같은 단이라, 올림면(사이드바·\n 표 머리/행·마스터-디테일 구분선) 위에 그리는 약한 선이 **면과 같은 색**(대비 1.00)이 되어\n 화면에서 사라진다. 라이트는 200 단이 올림면(50)과 떨어져 있어 보인다. 램프에서 올림면(300)\n 위로 올릴 수 있는 다음 단이 400 뿐이라 `-weak` 는 이 테마에서 `--u-border-color` 와 같은\n 단이다 — 다크에서는 «약함/보통» 두 단이 하나로 합쳐지지만, 종전 `-weak` 는 그것이 쓰이는\n 면 위에서 애초에 구별되지 않았다. */\n --u-border-color: var(--u-neutral-400);\n --u-border-color-weak: var(--u-neutral-400);\n --u-border-color-strong: var(--u-neutral-500);\n --u-border-color-hover: var(--u-neutral-500);\n\n /* ★상태 테두리는 `-strong` 단이다 — light.css 의 같은 자리 주석 참조.\n 이 테마가 실제로 미달이었다: focus 2.74 · invalid 2.44 → 4.74 / 4.34. */\n --u-input-border-color: var(--u-neutral-400);\n --u-input-border-color-hover: var(--u-neutral-500);\n --u-input-border-color-focus: var(--u-primary-color-strong);\n --u-input-border-color-invalid: var(--u-danger-color-strong);\n\n /* Background Colors */\n --u-bg-color: var(--u-neutral-100);\n --u-bg-color-inverse: var(--u-neutral-0);\n --u-bg-color-hover: var(--u-neutral-300);\n --u-bg-color-active: var(--u-neutral-400);\n --u-bg-color-disabled: var(--u-neutral-100);\n\n /* 면 높이 — 상세는 light.css 참조. 다크는 **바탕보다 밝은 쪽**이 위다.\n neutral-300(#2A2A2A)은 바탕(#121212) 대비 1.42 로, 소비 측이 오버라이드로 쓰던\n neutral-200(1.15)보다 실제로 더 잘 구분된다 — 그 오버라이드가 해결하려던 증상이\n *\"툴바·헤더가 배경에 묻힌다\"* 였다. */\n --u-bg-color-raised: var(--u-neutral-300);\n\n /* ★올림면 위의 hover — `--u-bg-color-hover`(전역, 바탕면 전용)와 값이 같아서\n («둘 다 neutral-300») 카드·표 머리 위에 마우스를 올려도 아무 일도 안 일어났다\n (소비자 실측). 전역 토큰 하나로는 \"지금 위에 있는 면\"을\n 알 방법이 없어(참조 지점마다 계산 기준이 다를 수 없다) **전용 토큰**을 신설한다.\n\n ⚠**A안**(`raised`를 neutral-200으로) — 과거에 거부된 값(위 주석). **B안**(전역\n `hover`를 neutral-400으로) — `--u-bg-color-active` 와 충돌해 결함이 다른 쌍으로\n 옮겨간다. ⇒ hover 는 본래 \"현재 면보다 한 단 위\"이지 절대 단이 아니므로\n `color-mix()` 로 raised 자신을 기준 삼아 상대 계산한다.\n\n N=6% 는 raised(L≈0.023)와 active(L≈0.047, neutral-400) 사이 대비 계산으로 골랐다 —\n 결과 L≈0.038, raised 대비 ≈1.21(라이트의 기존 \"약한\" 1.04보다 뚜렷하고, `bg→raised`\n 의 기존 1.31 과 비슷한 체감), active 와는 값이 달라 겹치지 않는다(≈#373737 vs\n active #3D3D3D). N 을 더 올리면(≈10%+) active 를 넘어서 순서가 뒤집힌다 — 확인함. */\n --u-bg-color-raised-hover: color-mix(in srgb, var(--u-bg-color-raised), white 6%);\n\n /* 유채색 표면 — 라이트와 **같은 단이 아니라 같은 세기**로 짝지었다(light.css 참조).\n 팔레트 유채색 틴트가 다크에서 짓눌리므로 한 단 위를 쓴다. green 은 대칭이라 그대로. */\n --u-primary-bg-color: var(--u-blue-100);\n --u-info-bg-color: var(--u-blue-100);\n --u-success-bg-color: var(--u-green-0);\n --u-danger-bg-color: var(--u-red-100);\n /* warning 합류 — 라이트는 yellow-200 이다(단 이름이 다른 이유는 light.css 참조). */\n --u-warning-bg-color: var(--u-yellow-100);\n\n --u-input-bg-color: var(--u-neutral-200);\n --u-panel-bg-color: var(--u-neutral-200);\n --u-overlay-bg-color: rgba(0, 0, 0, 0.7);\n --u-tooltip-bg-color: rgba(255, 255, 255, 0.85);\n\n /* Shadow Colors */\n --u-shadow-color-weaker: rgba(0, 0, 0, 0.15);\n --u-shadow-color-weak: rgba(0, 0, 0, 0.25);\n --u-shadow-color-normal: rgba(0, 0, 0, 0.35);\n --u-shadow-color-strong: rgba(0, 0, 0, 0.45);\n --u-shadow-color-stronger: rgba(0, 0, 0, 0.60);\n\n /* Elevation Scale — 근거는 light.css 의 같은 자리 주석 참조.\n ★다크는 알파가 3배 가까이 진하다 — 리터럴로 흩어져 있던 종전에는 이 차이가\n 적용되지 않아 다크에서 그림자가 사실상 보이지 않았다. */\n --u-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.25), 0 1px 1px rgba(0, 0, 0, 0.14); /* = shadow-color-weak */\n --u-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.35), 0 1px 2px rgba(0, 0, 0, 0.18); /* = shadow-color-normal */\n --u-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.45), 0 2px 4px rgba(0, 0, 0, 0.22); /* = shadow-color-strong */\n --u-shadow-xl: 0 6px 18px rgba(0, 0, 0, 0.60), 0 2px 6px rgba(0, 0, 0, 0.30); /* = shadow-color-stronger */\n\n\n /* ==========================================================================\n Chart categorical palette — 다크 면(#121212 · 올림면 #2A2A2A)에 대해 **따로 고른** 여덟 칸\n ★램프를 참조하지 않는 이유: 다크 장식 램프는 채도가 낮아(면 위 배지·태그용) 차트 계열로는\n 회색처럼 읽힌다 — 램프의 단 조합 39만 가지 중 검증을 통과한 것이 없었다. 그래서 라이트\n 여덟 칸과 **같은 색상·순서**를 OKLCH 밝기만 다크 대역으로 옮겨 잡았다.\n 검증: 밝기 0.48–0.67 · 채도 ≥ 0.1 · 색각 이상 이웃 ΔE ≥ 9.5 · 정상 시각 이웃 ΔE ≥ 25.1 ·\n 두 면 모두 대비 ≥ 3:1. 순서는 light.css 와 같다.\n ========================================================================== */\n --u-chart-color-1: #247EDB;\n --u-chart-color-2: #D03E73;\n --u-chart-color-3: #0DA1B2;\n --u-chart-color-4: #ED5711;\n --u-chart-color-5: #059183;\n --u-chart-color-6: #D96D04;\n --u-chart-color-7: #AE48CB;\n --u-chart-color-8: #4AA74D;\n\n /* Scrollbar Colors */\n --u-scrollbar-color: var(--u-neutral-500);\n --u-scrollbar-color-hover: var(--u-neutral-600);\n --u-scrollbar-track-color: transparent;\n}\n\n/* ==========================================================================\n ★모드와 무관한 스케일 — 반경·여백·글자 스케일·모션·글꼴.\n 값이 light.css 와 **같다.** 그런데 위 블록(`:root[theme=\"dark\"]`, 특이도 0,1,1)에 두면\n `:root`(0,1,0)로 이 토큰을 덮는 **모든 층**(하우스 프리셋·소비자 브랜드 시트)이 다크\n 모드에서만 **로드 순서와 무관하게** 진다 — 에러도 경고도 없이, 색은 정상으로 바뀌므로\n «다크가 잘 된다» 로 보인다. `:where()` 로 특이도를 `:root` 와 같게 두면 층 모델이 라이트와\n 똑같이 로드 순서로 선다.\n ⚠이 블록을 지우지 말 것 — 이 시트만 쓰는 «고정 다크 디자인» 소비자(docs/theming.md)는\n 이 토큰들을 여기서 받는다. 두 시트를 함께 쓸 때는 값이 같으므로 어느 쪽이 이겨도 같다.\n ========================================================================== */\n:root:where([theme=\"dark\"]) {\n /* ==========================================================================\n Radius Scale — 모서리 반경\n 리터럴을 흩뿌리면 값이 갈린다(실제로 pill 이 999px/9999px 두 표기로 나뉘어 있었다).\n ========================================================================== */\n --u-radius-none: 0;\n --u-radius-sm: 3px;\n --u-radius-md: 4px;\n --u-radius-lg: 6px;\n --u-radius-xl: 8px;\n /* ★상단 2단은 **면(surface)용**이다 — 카드·패널·대화상자처럼 큰 사각형은 컨트롤과\n 같은 반경을 쓰면 각져 보인다. 기존 5단은 **컨트롤용**이고 값을 바꾸지 않는다\n (바꾸면 모든 소비자의 버튼·입력이 동시에 움직인다). */\n --u-radius-2xl: 12px;\n --u-radius-3xl: 16px;\n --u-radius-pill: 9999px;\n --u-radius-circle: 50%;\n\n /* ==========================================================================\n Layer Scale — 페이지 전역에서 겹치는 표면의 쌓임 순서\n 컴포넌트 «안» 의 국소 순서(1~100)는 그 컴포넌트의 쌓임 맥락 안에서만 뜻이 있어 여기 두지 않는다.\n 여기는 서로 다른 패키지의 표면이 페이지에서 다투는 층이다 — 값을 흩뿌리면 층이 갈린다\n (셸 1000 · 플로팅 1000 · 오버레이 9999 · 라이트박스 9999 가 각자 숫자였다).\n 오버레이 띠의 실제 값은 OverlayManager 가 «동시에 열린 깊이» 로 인라인에 쓴다 — 이 토큰은\n 그 띠의 시작값(열리기 전 기본값)이고 OverlayManager.OVERLAY_BASE 와 같아야 한다.\n ========================================================================== */\n --u-layer-shell: 1000; /* 앱 셸의 사이드바·모바일 머리 */\n --u-layer-floating: 1000; /* 팝오버·목록·메뉴 — 앵커를 따라 뜨는 표면 */\n --u-layer-overlay: 9999; /* 대화상자·서랍·라이트박스 — 화면을 덮는 표면 */\n\n /* ==========================================================================\n Space Scale — 컨테이너·오버레이의 절대 여백\n ⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이의 **레이아웃 여백**만\n 담당한다. 폼·인라인 요소의 `em` 여백은 상속된 `font-size` 에 비례하는 것이 의도이므로\n **여기로 흡수하지 않는다.** 반경과 마찬가지로 테마와 무관하므로 두 시트가 같다.\n 축 구분과 근거는 docs/design-tokens.md 참조.\n ========================================================================== */\n --u-space-3xs: 2px;\n --u-space-2xs: 4px;\n --u-space-xs: 6px;\n --u-space-sm: 8px;\n --u-space-md: 12px;\n --u-space-lg: 16px;\n /* ★상단 4단은 **화면 리듬**이다 — 카드 안쪽 여백(20~24)·섹션 간격(24~32)·페이지 여백\n (32~40). 종전에는 이 구간이 통째로 비어 있어 소비자가 전부 리터럴로 적었고,\n 그래서 앱마다 화면 밀도가 달라졌다. `lg`(16px) 이하는 **요소 사이**, `xl` 이상은\n **영역 사이**로 나눠 쓴다.\n ⚠`xs: 6px` 는 4px 격자에서 벗어나 있으나 **바꾸지 않는다** — 이미 배선된 컨트롤\n 여백이 전부 움직인다. 신규 단은 전부 4의 배수로 둔다. */\n --u-space-xl: 20px;\n --u-space-2xl: 24px;\n --u-space-3xl: 32px;\n --u-space-4xl: 40px;\n\n /* ==========================================================================\n Type Scale — 글자 크기·굵기·행간·자간의 **한 벌**\n ★**크기만 주면 스케일이 되지 않는다.** 소비자가 크기만 받고 굵기·행간을 각자 정하면\n 결국 화면마다 다른 위계가 생긴다 — 그래서 네 값을 **단 단위로 묶어** 낸다.\n\n 단 이름은 크기가 아니라 **역할**이다(`lg`/`xl` 이 아니라 `title`/`label`). 역할로 두면\n 소비자가 *\"어느 크기를 쓸까\"* 가 아니라 *\"이 글자는 무엇인가\"* 를 묻게 된다.\n\n ★**한글 기준으로 값을 골랐다**:\n ⑴ 행간은 **1.4 이상**. 라틴 관례(1.2)는 한글에서 답답하다 — 받침 때문에 글자 상자가\n 세로로 꽉 차 있어 라틴과 같은 행간이면 줄이 붙어 보인다.\n ⑵ 자간은 **0 이 기본**이고 큰 제목만 **음수**. 한글에 양수 자간(letter-spacing)을 주면\n 가독성이 떨어진다 — 라틴 소문자 조판 관례를 그대로 옮기면 안 되는 자리다.\n ⑶ `overline` 에만 양수 자간을 둔다. 그 단은 **영문·숫자 라벨**을 전제한 자리이고,\n 한글을 넣을 소비자는 자간을 0 으로 덮어야 한다(문서에 명시).\n\n ⚠**`text-transform` 은 토큰으로 내지 않는다.** 한글에는 대문자가 없어 `uppercase` 가\n 아무 효과가 없고, 영문이 섞이면 그것만 커져 오히려 어수선해진다.\n ========================================================================== */\n --u-text-display-size: 26px;\n --u-text-display-weight: 700;\n --u-text-display-leading: 1.4;\n --u-text-display-tracking: -0.02em;\n\n --u-text-title-size: 20px;\n --u-text-title-weight: 700;\n --u-text-title-leading: 1.45;\n --u-text-title-tracking: -0.01em;\n\n --u-text-subtitle-size: 16px;\n --u-text-subtitle-weight: 600;\n --u-text-subtitle-leading: 1.5;\n --u-text-subtitle-tracking: 0;\n\n --u-text-body-size: 14px;\n --u-text-body-weight: 400;\n --u-text-body-leading: 1.6;\n --u-text-body-tracking: 0;\n\n --u-text-label-size: 13px;\n --u-text-label-weight: 600;\n --u-text-label-leading: 1.5;\n --u-text-label-tracking: 0;\n\n --u-text-caption-size: 12px;\n --u-text-caption-weight: 400;\n --u-text-caption-leading: 1.5;\n --u-text-caption-tracking: 0;\n\n --u-text-overline-size: 11px;\n --u-text-overline-weight: 700;\n --u-text-overline-leading: 1.45;\n --u-text-overline-tracking: 0.06em;\n\n /* ==========================================================================\n Motion — 지속시간·이징\n ★값이 없으면 앱마다 다른 속도가 생기고, `prefers-reduced-motion` 은 **반드시**\n 빠뜨리는 앱이 나온다. 축을 여기 두고 존중 규칙은 아래 미디어 쿼리가 진다.\n ========================================================================== */\n --u-duration-instant: 80ms;\n --u-duration-fast: 140ms;\n --u-duration-normal: 220ms;\n --u-duration-slow: 320ms;\n --u-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --u-ease-decelerate: cubic-bezier(0, 0, 0, 1);\n --u-ease-accelerate: cubic-bezier(0.3, 0, 1, 1);\n\n /* ==========================================================================\n Font Styles\n ★**CJK 폴백을 스택에 포함한다 — 국제화이지 취향이 아니다.**\n 종전 스택(`-apple-system, Segoe UI, Noto Sans, Helvetica, Arial`)에는 **한중일 글립을\n 가진 폰트가 하나도 없었다.** Windows 에서 한글은 `Segoe UI` 에 없으므로 UA 가 임의로\n 맑은 고딕을 고르고, macOS 는 `-apple-system` 이 Apple SD Gothic Neo 를 준다 ⇒ **같은 앱이\n OS 마다 다른 글꼴로 렌더**됐다. 폴백을 명시하면 그 선택이 결정적이 된다.\n ⚠**웹폰트를 로드하지 않는다.** 라이브러리가 네트워크 요청을 만들면 소비자의 CSP·\n 오프라인 환경을 깬다. 스택 맨 앞의 `Pretendard` 는 **소비자가 로드했을 때만** 잡히는\n 선택적 이름이다(없으면 조용히 다음으로 넘어간다).\n ========================================================================== */\n --u-font-base: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', 'Hiragino Sans', 'Yu Gothic UI', 'Microsoft YaHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';\n --u-font-mono: ui-monospace, 'Cascadia Code', Consolas, 'Source Code Pro', Menlo, Monaco, 'Courier New', monospace;\n --u-font-serif: 'Georgia', 'Times New Roman', Times, serif;\n --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;\n --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n/* ★`prefers-reduced-motion` — light.css 와 같은 규칙을 이 시트도 진다. 이 시트만 쓰는\n 소비자가 있고, 두 시트를 함께 쓸 때는 어느 시트가 뒤에 오든 **마지막 선언이 이 0ms**\n 가 되도록 각 시트가 자기 블록 뒤에 둔다. 종전에는 지속시간이 위 (0,1,1) 블록에 있어\n 다크 모드에서 «동작 줄이기» 설정이 **무시됐다.** */\n@media (prefers-reduced-motion: reduce) {\n :root:where([theme=\"dark\"]) {\n --u-duration-instant: 0ms;\n --u-duration-fast: 0ms;\n --u-duration-normal: 0ms;\n --u-duration-slow: 0ms;\n }\n}\n";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { dark_css_default as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
//#region \0glob-assets_raw/light.css.637cb2f8
|
|
2
|
-
var light_css_default = ":root {\n color-scheme: light;\n\n /* Neutral Colors */\n --u-neutral-0: #FFFFFF;\n --u-neutral-50: #FAFAFA;\n --u-neutral-100: #F5F5F5;\n --u-neutral-200: #EEEEEE;\n --u-neutral-300: #E0E0E0;\n --u-neutral-400: #BDBDBD;\n --u-neutral-500: #9E9E9E;\n --u-neutral-600: #757575;\n --u-neutral-700: #616161;\n --u-neutral-800: #424242;\n --u-neutral-900: #212121;\n --u-neutral-1000: #000000;\n\n /* Blue Colors */\n --u-blue-0: #E3F2FD;\n --u-blue-100: #BBDEFB;\n --u-blue-200: #90CAF9;\n --u-blue-300: #64B5F6;\n --u-blue-400: #42A5F5;\n --u-blue-500: #2196F3;\n --u-blue-600: #1E88E5;\n --u-blue-700: #1976D2;\n --u-blue-800: #1565C0;\n --u-blue-900: #0D47A1;\n --u-blue-1000: #062A5E;\n\n /* Green Colors */\n --u-green-0: #E8F5E9;\n --u-green-100: #C8E6C9;\n --u-green-200: #A5D6A7;\n --u-green-300: #81C784;\n --u-green-400: #66BB6A;\n --u-green-500: #4CAF50;\n --u-green-600: #43A047;\n --u-green-700: #388E3C;\n --u-green-800: #2E7D32;\n --u-green-900: #1B5E20;\n --u-green-1000: #0F3A12;\n\n /* Yellow Colors */\n --u-yellow-0: #FFFDE7;\n --u-yellow-100: #FFF9C4;\n --u-yellow-200: #FFF59D;\n --u-yellow-300: #FFF176;\n --u-yellow-400: #FFEE58;\n --u-yellow-500: #FFEB3B;\n --u-yellow-600: #FDD835;\n --u-yellow-700: #FBC02D;\n --u-yellow-800: #F9A825;\n --u-yellow-900: #F57F17;\n --u-yellow-1000: #8A4A00;\n\n /* Red Colors */\n --u-red-0: #FFEBEE;\n --u-red-100: #FFCDD2;\n --u-red-200: #EF9A9A;\n --u-red-300: #E57373;\n --u-red-400: #EF5350;\n --u-red-500: #F44336;\n --u-red-600: #E53935;\n --u-red-700: #D32F2F;\n --u-red-800: #C62828;\n --u-red-900: #B71C1C;\n --u-red-1000: #6B0F0F;\n\n /* Orange Colors */\n --u-orange-0: #FFF3E0;\n --u-orange-100: #FFE0B2;\n --u-orange-200: #FFCC80;\n --u-orange-300: #FFB74D;\n --u-orange-400: #FFA726;\n --u-orange-500: #FF9800;\n --u-orange-600: #FB8C00;\n --u-orange-700: #F57C00;\n --u-orange-800: #EF6C00;\n --u-orange-900: #E65100;\n --u-orange-1000: #8C3100;\n\n /* Teal Colors */\n --u-teal-0: #E0F2F1;\n --u-teal-100: #B2DFDB;\n --u-teal-200: #80CBC4;\n --u-teal-300: #4DB6AC;\n --u-teal-400: #26A69A;\n --u-teal-500: #009688;\n --u-teal-600: #00897B;\n --u-teal-700: #00796B;\n --u-teal-800: #00695C;\n --u-teal-900: #004D40;\n --u-teal-1000: #002E26;\n\n /* Cyan Colors */\n --u-cyan-0: #E0F7FA;\n --u-cyan-100: #B2EBF2;\n --u-cyan-200: #80DEEA;\n --u-cyan-300: #4DD0E1;\n --u-cyan-400: #26C6DA;\n --u-cyan-500: #00BCD4;\n --u-cyan-600: #00ACC1;\n --u-cyan-700: #0097A7;\n --u-cyan-800: #00838F;\n --u-cyan-900: #006064;\n --u-cyan-1000: #003A3D;\n\n /* Purple Colors */\n --u-purple-0: #F3E5F5;\n --u-purple-100: #E1BEE7;\n --u-purple-200: #CE93D8;\n --u-purple-300: #BA68C8;\n --u-purple-400: #AB47BC;\n --u-purple-500: #9C27B0;\n --u-purple-600: #8E24AA;\n --u-purple-700: #7B1FA2;\n --u-purple-800: #6A1B9A;\n --u-purple-900: #4A148C;\n --u-purple-1000: #2C0B54;\n\n /* Pink Colors */\n --u-pink-0: #FCE4EC;\n --u-pink-100: #F8BBD0;\n --u-pink-200: #F48FB1;\n --u-pink-300: #F06292;\n --u-pink-400: #EC407A;\n --u-pink-500: #E91E63;\n --u-pink-600: #D81B60;\n --u-pink-700: #C2185B;\n --u-pink-800: #AD1457;\n --u-pink-900: #880E4F;\n --u-pink-1000: #520830;\n\n /* ==========================================================================\n Role Colors — 의미 역할 층\n 컴포넌트는 팔레트 프리미티브가 아니라 이 층을 참조한다.\n 브랜드 색 교체는 아래 25개만 재정의하면 시맨틱 층까지 따라온다.\n\n 단은 '강도' 축이다 (weakest -> strong). 용도(배경/테두리/텍스트)는\n 소비처가 정한다 -- 단을 속성에 묶으면 primary 버튼의 배경이 어느\n 단인지 같은 모순이 생긴다.\n ========================================================================== */\n\n /* ★단이 팔레트 shade 와 1:1 이 아니다 — **대비로 고른다.**\n `-color` 는 `--u-*-txt-color` 를 받는 면이고 `-strong` 은 바탕 위의 글자다.\n 라이트에서는 바탕도 on-color 도 흰색이라 두 요구가 `contrast(shade, #FFF) ≥ 4.5`\n 하나로 합쳐지고, 그 단이 계열마다 다르다(blue 700 · red 700 · green 800).\n Material 램프는 휘도가 아니라 색상 기준으로 만들어져 있어서 단 번호가 세기를\n 보장하지 않는다 — 값은 `tests/build/token-contrast.test.ts` 가 지킨다. */\n\n /* primary — 브랜드 · 강조 · 포커스 · 링크 */\n --u-primary-color-weakest: var(--u-blue-200);\n --u-primary-color-weaker: var(--u-blue-300);\n --u-primary-color-weak: var(--u-blue-500);\n --u-primary-color: var(--u-blue-700); /* 4.60 ✓ (600 은 3.68 ✗) */\n --u-primary-color-strong: var(--u-blue-800); /* 5.75 ✓ */\n\n /* info — 정보 안내 (primary 와 기본값은 같으나 역할이 다르다 — 브랜딩은 primary 만 바꾼다) */\n --u-info-color-weakest: var(--u-blue-200);\n --u-info-color-weaker: var(--u-blue-300);\n --u-info-color-weak: var(--u-blue-500);\n --u-info-color: var(--u-blue-700);\n --u-info-color-strong: var(--u-blue-800);\n\n /* success — 성공 · 완료\n ⚠green 은 700 도 4.12 로 미달이라 두 단을 건너뛴다. 계열마다 통과 단이 다른 것이\n 이 층의 정상 상태다(단 번호를 맞추면 대비가 어긋난다). */\n --u-success-color-weakest: var(--u-green-200);\n --u-success-color-weaker: var(--u-green-300);\n --u-success-color-weak: var(--u-green-500);\n --u-success-color: var(--u-green-800); /* 5.13 ✓ (600=3.30 · 700=4.12 ✗) */\n --u-success-color-strong: var(--u-green-900); /* 7.87 ✓ */\n\n /* warning — 주의 */\n --u-warning-color-weakest: var(--u-yellow-200);\n --u-warning-color-weaker: var(--u-yellow-300);\n --u-warning-color-weak: var(--u-yellow-500);\n --u-warning-color: var(--u-yellow-600);\n /* ★다른 계열은 -strong 이 shade-800~900 인데 warning 만 1000 이다 — 노랑 램프는\n 900 까지도 흰 바탕 2.65 로 미달이고, 1000(#8A4A00)에서 처음 6.86 이 된다.\n 그 값은 갈색에 가깝지만, 이 단의 용도는 **면이 아니라 글자·아이콘**이므로 색상보다\n 가독성이 먼저다(경고 문구를 어두운 호박색으로 쓰는 것은 보편 관행이다). */\n --u-warning-color-strong: var(--u-yellow-1000);\n\n /* danger — 오류 · 위험 · 유효성 실패 */\n --u-danger-color-weakest: var(--u-red-200);\n --u-danger-color-weaker: var(--u-red-300);\n --u-danger-color-weak: var(--u-red-500);\n --u-danger-color: var(--u-red-700); /* 4.98 ✓ (600 은 4.23 ✗ — 오류 문구가 이 단이었다) */\n --u-danger-color-strong: var(--u-red-800); /* 5.62 ✓ */\n /* ==========================================================================\n Radius Scale — 모서리 반경\n 리터럴을 흩뿌리면 값이 갈린다(실제로 pill 이 999px/9999px 두 표기로 나뉘어 있었다).\n ========================================================================== */\n --u-radius-none: 0;\n --u-radius-sm: 3px;\n --u-radius-md: 4px;\n --u-radius-lg: 6px;\n --u-radius-xl: 8px;\n /* ★상단 2단은 **면(surface)용**이다 — 카드·패널·대화상자처럼 큰 사각형은 컨트롤과\n 같은 반경을 쓰면 각져 보인다. 기존 5단은 **컨트롤용**이고 값을 바꾸지 않는다\n (바꾸면 모든 소비자의 버튼·입력이 동시에 움직인다). */\n --u-radius-2xl: 12px;\n --u-radius-3xl: 16px;\n --u-radius-pill: 9999px;\n --u-radius-circle: 50%;\n\n /* ==========================================================================\n Space Scale — 컨테이너·오버레이의 절대 여백\n ⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이(카드·대화상자·드로어·\n 알림·메뉴·툴팁 등)의 **레이아웃 여백**만 담당한다. 폼·인라인 요소의 `em` 여백은\n 상속된 `font-size` 에 비례하는 것이 의도이므로 **여기로 흡수하지 않는다** —\n 흡수하면 타이포를 키운 소비자의 여백이 따라 커지지 않는다.\n 축 구분과 근거는 docs/design-tokens.md 참조.\n ========================================================================== */\n --u-space-3xs: 2px;\n --u-space-2xs: 4px;\n --u-space-xs: 6px;\n --u-space-sm: 8px;\n --u-space-md: 12px;\n --u-space-lg: 16px;\n /* ★상단 4단은 **화면 리듬**이다 — 카드 안쪽 여백(20~24)·섹션 간격(24~32)·페이지 여백\n (32~40). 종전에는 이 구간이 통째로 비어 있어 소비자가 전부 리터럴로 적었고,\n 그래서 앱마다 화면 밀도가 달라졌다. `lg`(16px) 이하는 **요소 사이**, `xl` 이상은\n **영역 사이**로 나눠 쓴다.\n ⚠`xs: 6px` 는 4px 격자에서 벗어나 있으나 **바꾸지 않는다** — 이미 배선된 컨트롤\n 여백이 전부 움직인다. 신규 단은 전부 4의 배수로 둔다. */\n --u-space-xl: 20px;\n --u-space-2xl: 24px;\n --u-space-3xl: 32px;\n --u-space-4xl: 40px;\n\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-0);\n /* 유채색 배경 위의 글자. --u-txt-color-inverse 는 다크에서 neutral-100(#121212)이라\n 유채색 버튼 위에서 읽히지 않는다. 브랜드 색을 바꾸는 소비자가 전경색도 함께\n 조절할 수 있도록 별도 이름을 준다.\n ⚠이 토큰이 흰색이라는 것과 그 위의 배경이 AA 를 받친다는 것은 별개다 —\n 라이트 팔레트의 shade-600 은 8색 중 6색이 흰 글자로 AA 에 미달한다(미해결). */\n --u-primary-txt-color: #FFFFFF;\n --u-info-txt-color: #FFFFFF;\n --u-success-txt-color: #FFFFFF;\n --u-danger-txt-color: #FFFFFF;\n /* ★warning 만 어둡다 — 취향이 아니라 측정이다. 노랑은 **어떤 단도** 흰 글자로 AA 를\n 받치지 못한다(라이트 최대 2.65 @900, 그마저 갈색). 다른 넷처럼 단을 옮기는 수단이\n 없으므로 전경을 뒤집는다. `--u-neutral-1000` 은 라이트 #000000 / 다크 #FFFFFF 이라\n 한 줄로 양 테마를 만족한다(라이트 15.05 · 다크 4.65). */\n --u-warning-txt-color: var(--u-neutral-1000);\n\n --u-txt-color-hover: var(--u-primary-color-strong);\n --u-txt-color-active: var(--u-primary-color-strong);\n --u-txt-color-disabled: var(--u-neutral-400);\n /* 보조 텍스트는 «놓이는 모든 면»에서 AA(4.5)를 받쳐야 한다 — 바탕만이 아니다.\n neutral-600(#757575)은 바탕 4.61 에서만 통과하고 올림면(neutral-50) 4.41 ·\n active 면(neutral-200) 3.97 로 미달이었다(표 머리·카드 위 보조 텍스트).\n neutral-700(#616161) = 바탕 6.19 · 올림면 5.93 · active 5.34.\n 본문(neutral-900)과의 대비비는 2.60 으로, 보조 텍스트를 모든 표면 위에서\n 읽히게 보장하는 흔한 디자인 시스템 기준(본문 대비 약 1.3~1.8)보다 위계가 넓다. */\n --u-txt-color-weak: var(--u-neutral-700);\n --u-txt-color-strong: var(--u-neutral-1000);\n\n --u-link-txt-color: var(--u-primary-color-strong);\n --u-tooltip-txt-color: var(--u-neutral-0);\n\n /* Icon Colors */\n --u-icon-color: var(--u-neutral-700);\n --u-icon-color-inverse: var(--u-neutral-0);\n --u-icon-color-hover: var(--u-primary-color-strong);\n --u-icon-color-active: var(--u-primary-color-strong);\n --u-icon-color-disabled: var(--u-neutral-400);\n\n /* Border Colors */\n --u-border-color: var(--u-neutral-300);\n --u-border-color-weak: var(--u-neutral-200);\n --u-border-color-strong: var(--u-neutral-400);\n --u-border-color-hover: var(--u-neutral-400);\n\n /* ★상태 테두리는 `-strong` 단이다 — 면이 아니라 **면 위에 그리는 선**이기 때문이다.\n 1.16.0 이 가른 용도(`-color` = 면 / `-strong` = 면·바탕 위)에 이 자리가 맞춰지지\n 않아 다크에서 미달이었다: focus 2.74 · invalid 2.44 (WCAG 1.4.11 기준 3.0).\n `-strong` 으로 옮기면 다크 4.74 / 4.34, 라이트 5.75 / 5.62 — 두 테마 모두 단조 상승. */\n --u-input-border-color: var(--u-neutral-300);\n --u-input-border-color-hover: var(--u-neutral-400);\n --u-input-border-color-focus: var(--u-primary-color-strong);\n --u-input-border-color-invalid: var(--u-danger-color-strong);\n\n /* Background Colors */\n --u-bg-color: var(--u-neutral-0);\n --u-bg-color-inverse: var(--u-neutral-900);\n --u-bg-color-hover: var(--u-neutral-100);\n --u-bg-color-active: var(--u-neutral-200);\n --u-bg-color-disabled: var(--u-neutral-50);\n\n /* ★면 높이 — 바탕에 인접해 있으면서 한 단 구분되는 크롬 면(툴바·표 헤더·푸터).\n 상호작용 상태(-hover/-active/-disabled)와 **다른 축**이다. 상태 이름에 높이를\n 얹으면 의미가 어긋난다.\n `--u-panel-bg-color` 와도 다르다 — 그쪽은 **떠 있는 패널**(카드·대화상자·메뉴)이라\n 라이트에서 페이지와 같은 흰색이고 그림자가 높이를 나른다. 크롬 면은 그림자가 없어\n 라이트에서도 틴트가 필요하다.\n ⚠한 단만 정의한다. 두 단째의 실측 수요는 라이트 한쪽뿐이었다(다크에서는 소비 측\n 오버라이드가 두 값을 같은 단으로 합치고 있었다). */\n --u-bg-color-raised: var(--u-neutral-50);\n\n /* ⚠**라이트는 전역 hover 에 그대로 별칭한다 — 결손이 아니라 실측 결론이다**\n (dark.css 의 같은 자리 참조). 두 시트는 각각 완결적이어야 한다는\n 불변식(`token-fallbacks.test.ts` 「키 패리티」)이 있어 다크에만 선언할 수 없다.\n 라이트 팔레트는 raised(250)·hover(245)·active(238) 가 12단 안에 몰려 있어\n (L≈0.956/0.913/0.855) 셋과 겹치지 않는 네 번째 단을 넣을 여유가 없다 — 대비를\n 조금만 올려도(≈1.10) active 와 거의 붙고(≈1단 차), 더 올리면 순서가 뒤집힌다.\n 다크와 달리 raised(250)≠hover(245) 라 «완전히 안 움직이는» 결함이 아니었으므로\n (약한 대비 1.04 로 이미 알려진 채로 남는다 — 같은 초안이 지적한 곁가지),\n 새 단을 억지로 만들지 않고 기존 hover 를 그대로 쓴다. */\n --u-bg-color-raised-hover: var(--u-bg-color-hover);\n \n /* 유채색 표면 — 정보/성공/위험 상태의 '면'.\n 역할 층의 유채색은 전경 5단뿐이라, 상태 배경이 필요한 컴포넌트는 팔레트를 직접\n 읽고 다크를 손으로 보정해야 했다. 팔레트의 유채색 틴트는 다크에서 짓눌리므로\n (바탕 대비 델타의 다크/라이트 비 — 청색 0.38~0.54) 두 테마가 **같은 단이 아니라\n 같은 세기**가 되도록 짝지었다. 실측 비: blue 1.09 · red 1.12 · green 0.91.\n\n ★**warning 이 합류했다(1.16.0 → 1.17.0).** 종전에는 *\"세기를 맞출 단 짝이 없다\"* 며\n 빠져 있었는데, 그 판정은 **shade-0 짝만** 재고 있었다. 노랑만 한 단 내려 잡으면\n 라이트 쪽 세기가 맞는다 — 바탕 대비 휘도 델타 실측:\n blue-0 0.131 · red-0 0.132 · green-0 0.117 · **yellow-200 0.110** (yellow-0 은 0.027)\n ⚠단 이름이 계열마다 다른 것(yellow 만 200)은 이 층의 정상 상태다. 라이트 팔레트는\n 휘도 순이 아니므로 같은 단 번호가 같은 세기를 뜻하지 않는다. */\n --u-primary-bg-color: var(--u-blue-0);\n --u-info-bg-color: var(--u-blue-0);\n --u-success-bg-color: var(--u-green-0);\n --u-danger-bg-color: var(--u-red-0);\n --u-warning-bg-color: var(--u-yellow-200);\n\n --u-input-bg-color: var(--u-neutral-0);\n --u-panel-bg-color: var(--u-neutral-0);\n --u-overlay-bg-color: rgba(0, 0, 0, 0.5);\n --u-tooltip-bg-color: rgba(0, 0, 0, 0.75);\n\n /* Shadow Colors */\n --u-shadow-color-weaker: rgba(0, 0, 0, 0.04);\n --u-shadow-color-weak: rgba(0, 0, 0, 0.08);\n --u-shadow-color-normal: rgba(0, 0, 0, 0.12);\n --u-shadow-color-strong: rgba(0, 0, 0, 0.16);\n --u-shadow-color-stronger: rgba(0, 0, 0, 0.24);\n\n /* ==========================================================================\n Elevation Scale — 높이(그림자)\n\n ★색 축은 있었지만 **높이 축이 없었다.** 그 결과 컴포넌트가 그림자를 리터럴로\n 썼고, 같은 리듬을 의도한 자리에 서로 다른 값 11가지가 생겼다(카드 .1 vs 캐러셀\n .15 — 둘 다 \"표면에 얹힌 카드\"인데 알파가 다르다).\n\n ⚠**그리고 그 리터럴들은 테마를 몰랐다** — `rgba(0,0,0,.1)` 은 다크 바탕에서\n 거의 보이지 않는다. 이 축을 경유하면 다크의 진한 알파(.25~.60)를 자동으로 받는다.\n\n ⚠**알파를 `--u-shadow-color-*` 로 중첩하지 않고 인라인한다.** use-site 폴백\n 생성기는 합성 값을 리터럴로 다루므로, 중첩하면 `var(--u-shadow-md, 0 2px 8px\n var(--u-shadow-color-normal))` 처럼 **폴백 안에 또 토큰이 들어간다** — 시트가\n 없을 때 그 폴백도 함께 무효가 되어 그림자가 통째로 사라진다.\n 두 축의 알파가 어긋나지 않는지는 `tests/build/elevation-scale.test.ts` 가 지킨다.\n ========================================================================== */\n --u-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 1px rgba(0, 0, 0, 0.04); /* = shadow-color-weak — 표면에 얹힌 작은 컨트롤(탭·손잡이) */\n --u-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.05); /* = shadow-color-normal — 카드·표면 */\n --u-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.16), 0 2px 4px rgba(0, 0, 0, 0.06); /* = shadow-color-strong — 떠 있는 레이어(드롭다운·알림) */\n --u-shadow-xl: 0 6px 18px rgba(0, 0, 0, 0.24), 0 2px 6px rgba(0, 0, 0, 0.08); /* = shadow-color-stronger — 모달·최상위(대화상자·툴팁) */\n\n\n /* ==========================================================================\n Type Scale — 글자 크기·굵기·행간·자간의 **한 벌**\n ★**크기만 주면 스케일이 되지 않는다.** 소비자가 크기만 받고 굵기·행간을 각자 정하면\n 결국 화면마다 다른 위계가 생긴다 — 그래서 네 값을 **단 단위로 묶어** 낸다.\n\n 단 이름은 크기가 아니라 **역할**이다(`lg`/`xl` 이 아니라 `title`/`label`). 역할로 두면\n 소비자가 *\"어느 크기를 쓸까\"* 가 아니라 *\"이 글자는 무엇인가\"* 를 묻게 된다.\n\n ★**한글 기준으로 값을 골랐다**:\n ⑴ 행간은 **1.4 이상**. 라틴 관례(1.2)는 한글에서 답답하다 — 받침 때문에 글자 상자가\n 세로로 꽉 차 있어 라틴과 같은 행간이면 줄이 붙어 보인다.\n ⑵ 자간은 **0 이 기본**이고 큰 제목만 **음수**. 한글에 양수 자간(letter-spacing)을 주면\n 가독성이 떨어진다 — 라틴 소문자 조판 관례를 그대로 옮기면 안 되는 자리다.\n ⑶ `overline` 에만 양수 자간을 둔다. 그 단은 **영문·숫자 라벨**을 전제한 자리이고,\n 한글을 넣을 소비자는 자간을 0 으로 덮어야 한다(문서에 명시).\n\n ⚠**`text-transform` 은 토큰으로 내지 않는다.** 한글에는 대문자가 없어 `uppercase` 가\n 아무 효과가 없고, 영문이 섞이면 그것만 커져 오히려 어수선해진다.\n ========================================================================== */\n --u-text-display-size: 26px;\n --u-text-display-weight: 700;\n --u-text-display-leading: 1.4;\n --u-text-display-tracking: -0.02em;\n\n --u-text-title-size: 20px;\n --u-text-title-weight: 700;\n --u-text-title-leading: 1.45;\n --u-text-title-tracking: -0.01em;\n\n --u-text-subtitle-size: 16px;\n --u-text-subtitle-weight: 600;\n --u-text-subtitle-leading: 1.5;\n --u-text-subtitle-tracking: 0;\n\n --u-text-body-size: 14px;\n --u-text-body-weight: 400;\n --u-text-body-leading: 1.6;\n --u-text-body-tracking: 0;\n\n --u-text-label-size: 13px;\n --u-text-label-weight: 600;\n --u-text-label-leading: 1.5;\n --u-text-label-tracking: 0;\n\n --u-text-caption-size: 12px;\n --u-text-caption-weight: 400;\n --u-text-caption-leading: 1.5;\n --u-text-caption-tracking: 0;\n\n --u-text-overline-size: 11px;\n --u-text-overline-weight: 700;\n --u-text-overline-leading: 1.45;\n --u-text-overline-tracking: 0.06em;\n\n /* ==========================================================================\n Motion — 지속시간·이징\n ★값이 없으면 앱마다 다른 속도가 생기고, `prefers-reduced-motion` 은 **반드시**\n 빠뜨리는 앱이 나온다. 축을 여기 두고 존중 규칙은 아래 미디어 쿼리가 진다.\n ========================================================================== */\n --u-duration-instant: 80ms;\n --u-duration-fast: 140ms;\n --u-duration-normal: 220ms;\n --u-duration-slow: 320ms;\n --u-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --u-ease-decelerate: cubic-bezier(0, 0, 0, 1);\n --u-ease-accelerate: cubic-bezier(0.3, 0, 1, 1);\n\n /* Scrollbar Colors */\n --u-scrollbar-color: var(--u-neutral-400);\n --u-scrollbar-color-hover: var(--u-neutral-500);\n --u-scrollbar-track-color: transparent;\n\n /* ==========================================================================\n Chart categorical palette — 차트 «계열» 색(범주형), 순서가 곧 계약이다\n ★여덟 칸이 **한 벌로** 검증됐다(dataviz 검증기, 흰 면 · 올림면): OKLCH 밝기 대역 0.43–0.77 ·\n 채도 하한 0.1 · 색각 이상(적·녹) 이웃 ΔE ≥ 12.7 · 정상 시각 이웃 ΔE ≥ 28.1. 순서를 바꾸거나\n 한 칸만 갈아 끼우면 그 검증이 깨진다 — 리브랜딩은 여덟 칸을 함께 다시 고른다.\n ★1번이 브랜드 파랑과 같은 단(blue-700)이라 계열 하나짜리 차트는 제품 색으로 그려진다.\n 그러나 역할 토큰(--u-primary-color)을 참조하지 **않는다** — 브랜드를 바꿨을 때 1번만 움직이면\n 나머지 일곱과의 구별이 검증 밖으로 나간다(장식 축과 같은 면역).\n ⚠상태색(success·danger 등)과 겹치지 않는 단을 골랐다(green-600 ≠ success green-800 · 빨강 없음).\n ⚠6번(yellow-900)은 흰 면 대비 2.65:1 — 범례·직접 레이블·표 보기가 함께 있어야 한다.\n ========================================================================== */\n --u-chart-color-1: var(--u-blue-700);\n --u-chart-color-2: var(--u-pink-800);\n --u-chart-color-3: var(--u-cyan-700);\n --u-chart-color-4: var(--u-orange-900);\n --u-chart-color-5: var(--u-teal-500);\n --u-chart-color-6: var(--u-yellow-900);\n --u-chart-color-7: var(--u-purple-600);\n --u-chart-color-8: var(--u-green-600);\n\n /* ==========================================================================\n Font Styles\n ★**CJK 폴백을 스택에 포함한다 — 국제화이지 취향이 아니다.**\n 종전 스택(`-apple-system, Segoe UI, Noto Sans, Helvetica, Arial`)에는 **한중일 글립을\n 가진 폰트가 하나도 없었다.** Windows 에서 한글은 `Segoe UI` 에 없으므로 UA 가 임의로\n 맑은 고딕을 고르고, macOS 는 `-apple-system` 이 Apple SD Gothic Neo 를 준다 ⇒ **같은 앱이\n OS 마다 다른 글꼴로 렌더**됐다. 폴백을 명시하면 그 선택이 결정적이 된다.\n ⚠**웹폰트를 로드하지 않는다.** 라이브러리가 네트워크 요청을 만들면 소비자의 CSP·\n 오프라인 환경을 깬다. 스택 맨 앞의 `Pretendard` 는 **소비자가 로드했을 때만** 잡히는\n 선택적 이름이다(없으면 조용히 다음으로 넘어간다).\n ========================================================================== */\n --u-font-base: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', 'Hiragino Sans', 'Yu Gothic UI', 'Microsoft YaHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';\n --u-font-mono: ui-monospace, 'Cascadia Code', Consolas, 'Source Code Pro', Menlo, Monaco, 'Courier New', monospace;\n --u-font-serif: 'Georgia', 'Times New Roman', Times, serif;\n --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;\n --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n/* ==========================================================================\n ★`prefers-reduced-motion` 존중 — **라이브러리가 진다.**\n 소비자마다 각자 처리하게 두면 반드시 빠뜨리는 앱이 나온다(그리고 그 앱은\n 접근성 감사 전까지 아무도 모른다). 지속시간 축을 0 으로 눌러 두면 이 축을\n 경유하는 모든 애니메이션이 함께 멈춘다.\n ⚠`animation: none` 으로 강제하지 않는다 — 로딩 스피너처럼 **의미를 나르는**\n 움직임까지 죽이면 사용자가 진행 중인지 알 수 없게 된다.\n ========================================================================== */\n@media (prefers-reduced-motion: reduce) {\n :root {\n --u-duration-instant: 0ms;\n --u-duration-fast: 0ms;\n --u-duration-normal: 0ms;\n --u-duration-slow: 0ms;\n }\n}\n";
|
|
2
|
+
var light_css_default = ":root {\n color-scheme: light;\n\n /* Neutral Colors */\n --u-neutral-0: #FFFFFF;\n --u-neutral-50: #FAFAFA;\n --u-neutral-100: #F5F5F5;\n --u-neutral-200: #EEEEEE;\n --u-neutral-300: #E0E0E0;\n --u-neutral-400: #BDBDBD;\n --u-neutral-500: #9E9E9E;\n --u-neutral-600: #757575;\n --u-neutral-700: #616161;\n --u-neutral-800: #424242;\n --u-neutral-900: #212121;\n --u-neutral-1000: #000000;\n\n /* Blue Colors */\n --u-blue-0: #E3F2FD;\n --u-blue-100: #BBDEFB;\n --u-blue-200: #90CAF9;\n --u-blue-300: #64B5F6;\n --u-blue-400: #42A5F5;\n --u-blue-500: #2196F3;\n --u-blue-600: #1E88E5;\n --u-blue-700: #1976D2;\n --u-blue-800: #1565C0;\n --u-blue-900: #0D47A1;\n --u-blue-1000: #062A5E;\n\n /* Green Colors */\n --u-green-0: #E8F5E9;\n --u-green-100: #C8E6C9;\n --u-green-200: #A5D6A7;\n --u-green-300: #81C784;\n --u-green-400: #66BB6A;\n --u-green-500: #4CAF50;\n --u-green-600: #43A047;\n --u-green-700: #388E3C;\n --u-green-800: #2E7D32;\n --u-green-900: #1B5E20;\n --u-green-1000: #0F3A12;\n\n /* Yellow Colors */\n --u-yellow-0: #FFFDE7;\n --u-yellow-100: #FFF9C4;\n --u-yellow-200: #FFF59D;\n --u-yellow-300: #FFF176;\n --u-yellow-400: #FFEE58;\n --u-yellow-500: #FFEB3B;\n --u-yellow-600: #FDD835;\n --u-yellow-700: #FBC02D;\n --u-yellow-800: #F9A825;\n --u-yellow-900: #F57F17;\n --u-yellow-1000: #8A4A00;\n\n /* Red Colors */\n --u-red-0: #FFEBEE;\n --u-red-100: #FFCDD2;\n --u-red-200: #EF9A9A;\n --u-red-300: #E57373;\n --u-red-400: #EF5350;\n --u-red-500: #F44336;\n --u-red-600: #E53935;\n --u-red-700: #D32F2F;\n --u-red-800: #C62828;\n --u-red-900: #B71C1C;\n --u-red-1000: #6B0F0F;\n\n /* Orange Colors */\n --u-orange-0: #FFF3E0;\n --u-orange-100: #FFE0B2;\n --u-orange-200: #FFCC80;\n --u-orange-300: #FFB74D;\n --u-orange-400: #FFA726;\n --u-orange-500: #FF9800;\n --u-orange-600: #FB8C00;\n --u-orange-700: #F57C00;\n --u-orange-800: #EF6C00;\n --u-orange-900: #E65100;\n --u-orange-1000: #8C3100;\n\n /* Teal Colors */\n --u-teal-0: #E0F2F1;\n --u-teal-100: #B2DFDB;\n --u-teal-200: #80CBC4;\n --u-teal-300: #4DB6AC;\n --u-teal-400: #26A69A;\n --u-teal-500: #009688;\n --u-teal-600: #00897B;\n --u-teal-700: #00796B;\n --u-teal-800: #00695C;\n --u-teal-900: #004D40;\n --u-teal-1000: #002E26;\n\n /* Cyan Colors */\n --u-cyan-0: #E0F7FA;\n --u-cyan-100: #B2EBF2;\n --u-cyan-200: #80DEEA;\n --u-cyan-300: #4DD0E1;\n --u-cyan-400: #26C6DA;\n --u-cyan-500: #00BCD4;\n --u-cyan-600: #00ACC1;\n --u-cyan-700: #0097A7;\n --u-cyan-800: #00838F;\n --u-cyan-900: #006064;\n --u-cyan-1000: #003A3D;\n\n /* Purple Colors */\n --u-purple-0: #F3E5F5;\n --u-purple-100: #E1BEE7;\n --u-purple-200: #CE93D8;\n --u-purple-300: #BA68C8;\n --u-purple-400: #AB47BC;\n --u-purple-500: #9C27B0;\n --u-purple-600: #8E24AA;\n --u-purple-700: #7B1FA2;\n --u-purple-800: #6A1B9A;\n --u-purple-900: #4A148C;\n --u-purple-1000: #2C0B54;\n\n /* Pink Colors */\n --u-pink-0: #FCE4EC;\n --u-pink-100: #F8BBD0;\n --u-pink-200: #F48FB1;\n --u-pink-300: #F06292;\n --u-pink-400: #EC407A;\n --u-pink-500: #E91E63;\n --u-pink-600: #D81B60;\n --u-pink-700: #C2185B;\n --u-pink-800: #AD1457;\n --u-pink-900: #880E4F;\n --u-pink-1000: #520830;\n\n /* ==========================================================================\n Role Colors — 의미 역할 층\n 컴포넌트는 팔레트 프리미티브가 아니라 이 층을 참조한다.\n 브랜드 색 교체는 아래 25개만 재정의하면 시맨틱 층까지 따라온다.\n\n 단은 '강도' 축이다 (weakest -> strong). 용도(배경/테두리/텍스트)는\n 소비처가 정한다 -- 단을 속성에 묶으면 primary 버튼의 배경이 어느\n 단인지 같은 모순이 생긴다.\n ========================================================================== */\n\n /* ★단이 팔레트 shade 와 1:1 이 아니다 — **대비로 고른다.**\n `-color` 는 `--u-*-txt-color` 를 받는 면이고 `-strong` 은 바탕 위의 글자다.\n 라이트에서는 바탕도 on-color 도 흰색이라 두 요구가 `contrast(shade, #FFF) ≥ 4.5`\n 하나로 합쳐지고, 그 단이 계열마다 다르다(blue 700 · red 700 · green 800).\n Material 램프는 휘도가 아니라 색상 기준으로 만들어져 있어서 단 번호가 세기를\n 보장하지 않는다 — 값은 `tests/build/token-contrast.test.ts` 가 지킨다. */\n\n /* primary — 브랜드 · 강조 · 포커스 · 링크 */\n --u-primary-color-weakest: var(--u-blue-200);\n --u-primary-color-weaker: var(--u-blue-300);\n --u-primary-color-weak: var(--u-blue-500);\n --u-primary-color: var(--u-blue-700); /* 4.60 ✓ (600 은 3.68 ✗) */\n --u-primary-color-strong: var(--u-blue-800); /* 5.75 ✓ */\n\n /* info — 정보 안내 (primary 와 기본값은 같으나 역할이 다르다 — 브랜딩은 primary 만 바꾼다) */\n --u-info-color-weakest: var(--u-blue-200);\n --u-info-color-weaker: var(--u-blue-300);\n --u-info-color-weak: var(--u-blue-500);\n --u-info-color: var(--u-blue-700);\n --u-info-color-strong: var(--u-blue-800);\n\n /* success — 성공 · 완료\n ⚠green 은 700 도 4.12 로 미달이라 두 단을 건너뛴다. 계열마다 통과 단이 다른 것이\n 이 층의 정상 상태다(단 번호를 맞추면 대비가 어긋난다). */\n --u-success-color-weakest: var(--u-green-200);\n --u-success-color-weaker: var(--u-green-300);\n --u-success-color-weak: var(--u-green-500);\n --u-success-color: var(--u-green-800); /* 5.13 ✓ (600=3.30 · 700=4.12 ✗) */\n --u-success-color-strong: var(--u-green-900); /* 7.87 ✓ */\n\n /* warning — 주의 */\n --u-warning-color-weakest: var(--u-yellow-200);\n --u-warning-color-weaker: var(--u-yellow-300);\n --u-warning-color-weak: var(--u-yellow-500);\n --u-warning-color: var(--u-yellow-600);\n /* ★다른 계열은 -strong 이 shade-800~900 인데 warning 만 1000 이다 — 노랑 램프는\n 900 까지도 흰 바탕 2.65 로 미달이고, 1000(#8A4A00)에서 처음 6.86 이 된다.\n 그 값은 갈색에 가깝지만, 이 단의 용도는 **면이 아니라 글자·아이콘**이므로 색상보다\n 가독성이 먼저다(경고 문구를 어두운 호박색으로 쓰는 것은 보편 관행이다). */\n --u-warning-color-strong: var(--u-yellow-1000);\n\n /* danger — 오류 · 위험 · 유효성 실패 */\n --u-danger-color-weakest: var(--u-red-200);\n --u-danger-color-weaker: var(--u-red-300);\n --u-danger-color-weak: var(--u-red-500);\n --u-danger-color: var(--u-red-700); /* 4.98 ✓ (600 은 4.23 ✗ — 오류 문구가 이 단이었다) */\n --u-danger-color-strong: var(--u-red-800); /* 5.62 ✓ */\n /* ==========================================================================\n Radius Scale — 모서리 반경\n 리터럴을 흩뿌리면 값이 갈린다(실제로 pill 이 999px/9999px 두 표기로 나뉘어 있었다).\n ========================================================================== */\n --u-radius-none: 0;\n --u-radius-sm: 3px;\n --u-radius-md: 4px;\n --u-radius-lg: 6px;\n --u-radius-xl: 8px;\n /* ★상단 2단은 **면(surface)용**이다 — 카드·패널·대화상자처럼 큰 사각형은 컨트롤과\n 같은 반경을 쓰면 각져 보인다. 기존 5단은 **컨트롤용**이고 값을 바꾸지 않는다\n (바꾸면 모든 소비자의 버튼·입력이 동시에 움직인다). */\n --u-radius-2xl: 12px;\n --u-radius-3xl: 16px;\n --u-radius-pill: 9999px;\n --u-radius-circle: 50%;\n\n /* ==========================================================================\n Layer Scale — 페이지 전역에서 겹치는 표면의 쌓임 순서\n 컴포넌트 «안» 의 국소 순서(1~100)는 그 컴포넌트의 쌓임 맥락 안에서만 뜻이 있어 여기 두지 않는다.\n 여기는 서로 다른 패키지의 표면이 페이지에서 다투는 층이다 — 값을 흩뿌리면 층이 갈린다\n (셸 1000 · 플로팅 1000 · 오버레이 9999 · 라이트박스 9999 가 각자 숫자였다).\n 오버레이 띠의 실제 값은 OverlayManager 가 «동시에 열린 깊이» 로 인라인에 쓴다 — 이 토큰은\n 그 띠의 시작값(열리기 전 기본값)이고 OverlayManager.OVERLAY_BASE 와 같아야 한다.\n ========================================================================== */\n --u-layer-shell: 1000; /* 앱 셸의 사이드바·모바일 머리 */\n --u-layer-floating: 1000; /* 팝오버·목록·메뉴 — 앵커를 따라 뜨는 표면 */\n --u-layer-overlay: 9999; /* 대화상자·서랍·라이트박스 — 화면을 덮는 표면 */\n\n /* ==========================================================================\n Space Scale — 컨테이너·오버레이의 절대 여백\n ⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이(카드·대화상자·드로어·\n 알림·메뉴·툴팁 등)의 **레이아웃 여백**만 담당한다. 폼·인라인 요소의 `em` 여백은\n 상속된 `font-size` 에 비례하는 것이 의도이므로 **여기로 흡수하지 않는다** —\n 흡수하면 타이포를 키운 소비자의 여백이 따라 커지지 않는다.\n 축 구분과 근거는 docs/design-tokens.md 참조.\n ========================================================================== */\n --u-space-3xs: 2px;\n --u-space-2xs: 4px;\n --u-space-xs: 6px;\n --u-space-sm: 8px;\n --u-space-md: 12px;\n --u-space-lg: 16px;\n /* ★상단 4단은 **화면 리듬**이다 — 카드 안쪽 여백(20~24)·섹션 간격(24~32)·페이지 여백\n (32~40). 종전에는 이 구간이 통째로 비어 있어 소비자가 전부 리터럴로 적었고,\n 그래서 앱마다 화면 밀도가 달라졌다. `lg`(16px) 이하는 **요소 사이**, `xl` 이상은\n **영역 사이**로 나눠 쓴다.\n ⚠`xs: 6px` 는 4px 격자에서 벗어나 있으나 **바꾸지 않는다** — 이미 배선된 컨트롤\n 여백이 전부 움직인다. 신규 단은 전부 4의 배수로 둔다. */\n --u-space-xl: 20px;\n --u-space-2xl: 24px;\n --u-space-3xl: 32px;\n --u-space-4xl: 40px;\n\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-0);\n /* 유채색 배경 위의 글자. --u-txt-color-inverse 는 다크에서 neutral-100(#121212)이라\n 유채색 버튼 위에서 읽히지 않는다. 브랜드 색을 바꾸는 소비자가 전경색도 함께\n 조절할 수 있도록 별도 이름을 준다.\n ⚠이 토큰이 흰색이라는 것과 그 위의 배경이 AA 를 받친다는 것은 별개다 —\n 라이트 팔레트의 shade-600 은 8색 중 6색이 흰 글자로 AA 에 미달한다(미해결). */\n --u-primary-txt-color: #FFFFFF;\n --u-info-txt-color: #FFFFFF;\n --u-success-txt-color: #FFFFFF;\n --u-danger-txt-color: #FFFFFF;\n /* ★warning 만 어둡다 — 취향이 아니라 측정이다. 노랑은 **어떤 단도** 흰 글자로 AA 를\n 받치지 못한다(라이트 최대 2.65 @900, 그마저 갈색). 다른 넷처럼 단을 옮기는 수단이\n 없으므로 전경을 뒤집는다. `--u-neutral-1000` 은 라이트 #000000 / 다크 #FFFFFF 이라\n 한 줄로 양 테마를 만족한다(라이트 15.05 · 다크 4.65). */\n --u-warning-txt-color: var(--u-neutral-1000);\n\n --u-txt-color-hover: var(--u-primary-color-strong);\n --u-txt-color-active: var(--u-primary-color-strong);\n --u-txt-color-disabled: var(--u-neutral-400);\n /* 보조 텍스트는 «놓이는 모든 면»에서 AA(4.5)를 받쳐야 한다 — 바탕만이 아니다.\n neutral-600(#757575)은 바탕 4.61 에서만 통과하고 올림면(neutral-50) 4.41 ·\n active 면(neutral-200) 3.97 로 미달이었다(표 머리·카드 위 보조 텍스트).\n neutral-700(#616161) = 바탕 6.19 · 올림면 5.93 · active 5.34.\n 본문(neutral-900)과의 대비비는 2.60 으로, 보조 텍스트를 모든 표면 위에서\n 읽히게 보장하는 흔한 디자인 시스템 기준(본문 대비 약 1.3~1.8)보다 위계가 넓다. */\n --u-txt-color-weak: var(--u-neutral-700);\n --u-txt-color-strong: var(--u-neutral-1000);\n\n --u-link-txt-color: var(--u-primary-color-strong);\n --u-tooltip-txt-color: var(--u-neutral-0);\n\n /* Icon Colors */\n --u-icon-color: var(--u-neutral-700);\n --u-icon-color-inverse: var(--u-neutral-0);\n --u-icon-color-hover: var(--u-primary-color-strong);\n --u-icon-color-active: var(--u-primary-color-strong);\n --u-icon-color-disabled: var(--u-neutral-400);\n\n /* Border Colors */\n --u-border-color: var(--u-neutral-300);\n --u-border-color-weak: var(--u-neutral-200);\n --u-border-color-strong: var(--u-neutral-400);\n --u-border-color-hover: var(--u-neutral-400);\n\n /* ★상태 테두리는 `-strong` 단이다 — 면이 아니라 **면 위에 그리는 선**이기 때문이다.\n 1.16.0 이 가른 용도(`-color` = 면 / `-strong` = 면·바탕 위)에 이 자리가 맞춰지지\n 않아 다크에서 미달이었다: focus 2.74 · invalid 2.44 (WCAG 1.4.11 기준 3.0).\n `-strong` 으로 옮기면 다크 4.74 / 4.34, 라이트 5.75 / 5.62 — 두 테마 모두 단조 상승. */\n --u-input-border-color: var(--u-neutral-300);\n --u-input-border-color-hover: var(--u-neutral-400);\n --u-input-border-color-focus: var(--u-primary-color-strong);\n --u-input-border-color-invalid: var(--u-danger-color-strong);\n\n /* Background Colors */\n --u-bg-color: var(--u-neutral-0);\n --u-bg-color-inverse: var(--u-neutral-900);\n --u-bg-color-hover: var(--u-neutral-100);\n --u-bg-color-active: var(--u-neutral-200);\n --u-bg-color-disabled: var(--u-neutral-50);\n\n /* ★면 높이 — 바탕에 인접해 있으면서 한 단 구분되는 크롬 면(툴바·표 헤더·푸터).\n 상호작용 상태(-hover/-active/-disabled)와 **다른 축**이다. 상태 이름에 높이를\n 얹으면 의미가 어긋난다.\n `--u-panel-bg-color` 와도 다르다 — 그쪽은 **떠 있는 패널**(카드·대화상자·메뉴)이라\n 라이트에서 페이지와 같은 흰색이고 그림자가 높이를 나른다. 크롬 면은 그림자가 없어\n 라이트에서도 틴트가 필요하다.\n ⚠한 단만 정의한다. 두 단째의 실측 수요는 라이트 한쪽뿐이었다(다크에서는 소비 측\n 오버라이드가 두 값을 같은 단으로 합치고 있었다). */\n --u-bg-color-raised: var(--u-neutral-50);\n\n /* ⚠**라이트는 전역 hover 에 그대로 별칭한다 — 결손이 아니라 실측 결론이다**\n (dark.css 의 같은 자리 참조). 두 시트는 각각 완결적이어야 한다는\n 불변식(`token-fallbacks.test.ts` 「키 패리티」)이 있어 다크에만 선언할 수 없다.\n 라이트 팔레트는 raised(250)·hover(245)·active(238) 가 12단 안에 몰려 있어\n (L≈0.956/0.913/0.855) 셋과 겹치지 않는 네 번째 단을 넣을 여유가 없다 — 대비를\n 조금만 올려도(≈1.10) active 와 거의 붙고(≈1단 차), 더 올리면 순서가 뒤집힌다.\n 다크와 달리 raised(250)≠hover(245) 라 «완전히 안 움직이는» 결함이 아니었으므로\n (약한 대비 1.04 로 이미 알려진 채로 남는다 — 같은 초안이 지적한 곁가지),\n 새 단을 억지로 만들지 않고 기존 hover 를 그대로 쓴다. */\n --u-bg-color-raised-hover: var(--u-bg-color-hover);\n \n /* 유채색 표면 — 정보/성공/위험 상태의 '면'.\n 역할 층의 유채색은 전경 5단뿐이라, 상태 배경이 필요한 컴포넌트는 팔레트를 직접\n 읽고 다크를 손으로 보정해야 했다. 팔레트의 유채색 틴트는 다크에서 짓눌리므로\n (바탕 대비 델타의 다크/라이트 비 — 청색 0.38~0.54) 두 테마가 **같은 단이 아니라\n 같은 세기**가 되도록 짝지었다. 실측 비: blue 1.09 · red 1.12 · green 0.91.\n\n ★**warning 이 합류했다(1.16.0 → 1.17.0).** 종전에는 *\"세기를 맞출 단 짝이 없다\"* 며\n 빠져 있었는데, 그 판정은 **shade-0 짝만** 재고 있었다. 노랑만 한 단 내려 잡으면\n 라이트 쪽 세기가 맞는다 — 바탕 대비 휘도 델타 실측:\n blue-0 0.131 · red-0 0.132 · green-0 0.117 · **yellow-200 0.110** (yellow-0 은 0.027)\n ⚠단 이름이 계열마다 다른 것(yellow 만 200)은 이 층의 정상 상태다. 라이트 팔레트는\n 휘도 순이 아니므로 같은 단 번호가 같은 세기를 뜻하지 않는다. */\n --u-primary-bg-color: var(--u-blue-0);\n --u-info-bg-color: var(--u-blue-0);\n --u-success-bg-color: var(--u-green-0);\n --u-danger-bg-color: var(--u-red-0);\n --u-warning-bg-color: var(--u-yellow-200);\n\n --u-input-bg-color: var(--u-neutral-0);\n --u-panel-bg-color: var(--u-neutral-0);\n --u-overlay-bg-color: rgba(0, 0, 0, 0.5);\n --u-tooltip-bg-color: rgba(0, 0, 0, 0.75);\n\n /* Shadow Colors */\n --u-shadow-color-weaker: rgba(0, 0, 0, 0.04);\n --u-shadow-color-weak: rgba(0, 0, 0, 0.08);\n --u-shadow-color-normal: rgba(0, 0, 0, 0.12);\n --u-shadow-color-strong: rgba(0, 0, 0, 0.16);\n --u-shadow-color-stronger: rgba(0, 0, 0, 0.24);\n\n /* ==========================================================================\n Elevation Scale — 높이(그림자)\n\n ★색 축은 있었지만 **높이 축이 없었다.** 그 결과 컴포넌트가 그림자를 리터럴로\n 썼고, 같은 리듬을 의도한 자리에 서로 다른 값 11가지가 생겼다(카드 .1 vs 캐러셀\n .15 — 둘 다 \"표면에 얹힌 카드\"인데 알파가 다르다).\n\n ⚠**그리고 그 리터럴들은 테마를 몰랐다** — `rgba(0,0,0,.1)` 은 다크 바탕에서\n 거의 보이지 않는다. 이 축을 경유하면 다크의 진한 알파(.25~.60)를 자동으로 받는다.\n\n ⚠**알파를 `--u-shadow-color-*` 로 중첩하지 않고 인라인한다.** use-site 폴백\n 생성기는 합성 값을 리터럴로 다루므로, 중첩하면 `var(--u-shadow-md, 0 2px 8px\n var(--u-shadow-color-normal))` 처럼 **폴백 안에 또 토큰이 들어간다** — 시트가\n 없을 때 그 폴백도 함께 무효가 되어 그림자가 통째로 사라진다.\n 두 축의 알파가 어긋나지 않는지는 `tests/build/elevation-scale.test.ts` 가 지킨다.\n ========================================================================== */\n --u-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 1px rgba(0, 0, 0, 0.04); /* = shadow-color-weak — 표면에 얹힌 작은 컨트롤(탭·손잡이) */\n --u-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.05); /* = shadow-color-normal — 카드·표면 */\n --u-shadow-lg: 0 4px 12px rgba(0, 0, 0, 0.16), 0 2px 4px rgba(0, 0, 0, 0.06); /* = shadow-color-strong — 떠 있는 레이어(드롭다운·알림) */\n --u-shadow-xl: 0 6px 18px rgba(0, 0, 0, 0.24), 0 2px 6px rgba(0, 0, 0, 0.08); /* = shadow-color-stronger — 모달·최상위(대화상자·툴팁) */\n\n\n /* ==========================================================================\n Type Scale — 글자 크기·굵기·행간·자간의 **한 벌**\n ★**크기만 주면 스케일이 되지 않는다.** 소비자가 크기만 받고 굵기·행간을 각자 정하면\n 결국 화면마다 다른 위계가 생긴다 — 그래서 네 값을 **단 단위로 묶어** 낸다.\n\n 단 이름은 크기가 아니라 **역할**이다(`lg`/`xl` 이 아니라 `title`/`label`). 역할로 두면\n 소비자가 *\"어느 크기를 쓸까\"* 가 아니라 *\"이 글자는 무엇인가\"* 를 묻게 된다.\n\n ★**한글 기준으로 값을 골랐다**:\n ⑴ 행간은 **1.4 이상**. 라틴 관례(1.2)는 한글에서 답답하다 — 받침 때문에 글자 상자가\n 세로로 꽉 차 있어 라틴과 같은 행간이면 줄이 붙어 보인다.\n ⑵ 자간은 **0 이 기본**이고 큰 제목만 **음수**. 한글에 양수 자간(letter-spacing)을 주면\n 가독성이 떨어진다 — 라틴 소문자 조판 관례를 그대로 옮기면 안 되는 자리다.\n ⑶ `overline` 에만 양수 자간을 둔다. 그 단은 **영문·숫자 라벨**을 전제한 자리이고,\n 한글을 넣을 소비자는 자간을 0 으로 덮어야 한다(문서에 명시).\n\n ⚠**`text-transform` 은 토큰으로 내지 않는다.** 한글에는 대문자가 없어 `uppercase` 가\n 아무 효과가 없고, 영문이 섞이면 그것만 커져 오히려 어수선해진다.\n ========================================================================== */\n --u-text-display-size: 26px;\n --u-text-display-weight: 700;\n --u-text-display-leading: 1.4;\n --u-text-display-tracking: -0.02em;\n\n --u-text-title-size: 20px;\n --u-text-title-weight: 700;\n --u-text-title-leading: 1.45;\n --u-text-title-tracking: -0.01em;\n\n --u-text-subtitle-size: 16px;\n --u-text-subtitle-weight: 600;\n --u-text-subtitle-leading: 1.5;\n --u-text-subtitle-tracking: 0;\n\n --u-text-body-size: 14px;\n --u-text-body-weight: 400;\n --u-text-body-leading: 1.6;\n --u-text-body-tracking: 0;\n\n --u-text-label-size: 13px;\n --u-text-label-weight: 600;\n --u-text-label-leading: 1.5;\n --u-text-label-tracking: 0;\n\n --u-text-caption-size: 12px;\n --u-text-caption-weight: 400;\n --u-text-caption-leading: 1.5;\n --u-text-caption-tracking: 0;\n\n --u-text-overline-size: 11px;\n --u-text-overline-weight: 700;\n --u-text-overline-leading: 1.45;\n --u-text-overline-tracking: 0.06em;\n\n /* ==========================================================================\n Motion — 지속시간·이징\n ★값이 없으면 앱마다 다른 속도가 생기고, `prefers-reduced-motion` 은 **반드시**\n 빠뜨리는 앱이 나온다. 축을 여기 두고 존중 규칙은 아래 미디어 쿼리가 진다.\n ========================================================================== */\n --u-duration-instant: 80ms;\n --u-duration-fast: 140ms;\n --u-duration-normal: 220ms;\n --u-duration-slow: 320ms;\n --u-ease-standard: cubic-bezier(0.2, 0, 0, 1);\n --u-ease-decelerate: cubic-bezier(0, 0, 0, 1);\n --u-ease-accelerate: cubic-bezier(0.3, 0, 1, 1);\n\n /* Scrollbar Colors */\n --u-scrollbar-color: var(--u-neutral-400);\n --u-scrollbar-color-hover: var(--u-neutral-500);\n --u-scrollbar-track-color: transparent;\n\n /* ==========================================================================\n Chart categorical palette — 차트 «계열» 색(범주형), 순서가 곧 계약이다\n ★여덟 칸이 **한 벌로** 검증됐다(dataviz 검증기, 흰 면 · 올림면): OKLCH 밝기 대역 0.43–0.77 ·\n 채도 하한 0.1 · 색각 이상(적·녹) 이웃 ΔE ≥ 12.7 · 정상 시각 이웃 ΔE ≥ 28.1. 순서를 바꾸거나\n 한 칸만 갈아 끼우면 그 검증이 깨진다 — 리브랜딩은 여덟 칸을 함께 다시 고른다.\n ★1번이 브랜드 파랑과 같은 단(blue-700)이라 계열 하나짜리 차트는 제품 색으로 그려진다.\n 그러나 역할 토큰(--u-primary-color)을 참조하지 **않는다** — 브랜드를 바꿨을 때 1번만 움직이면\n 나머지 일곱과의 구별이 검증 밖으로 나간다(장식 축과 같은 면역).\n ⚠상태색(success·danger 등)과 겹치지 않는 단을 골랐다(green-600 ≠ success green-800 · 빨강 없음).\n ⚠6번(yellow-900)은 흰 면 대비 2.65:1 — 범례·직접 레이블·표 보기가 함께 있어야 한다.\n ========================================================================== */\n --u-chart-color-1: var(--u-blue-700);\n --u-chart-color-2: var(--u-pink-800);\n --u-chart-color-3: var(--u-cyan-700);\n --u-chart-color-4: var(--u-orange-900);\n --u-chart-color-5: var(--u-teal-500);\n --u-chart-color-6: var(--u-yellow-900);\n --u-chart-color-7: var(--u-purple-600);\n --u-chart-color-8: var(--u-green-600);\n\n /* ==========================================================================\n Font Styles\n ★**CJK 폴백을 스택에 포함한다 — 국제화이지 취향이 아니다.**\n 종전 스택(`-apple-system, Segoe UI, Noto Sans, Helvetica, Arial`)에는 **한중일 글립을\n 가진 폰트가 하나도 없었다.** Windows 에서 한글은 `Segoe UI` 에 없으므로 UA 가 임의로\n 맑은 고딕을 고르고, macOS 는 `-apple-system` 이 Apple SD Gothic Neo 를 준다 ⇒ **같은 앱이\n OS 마다 다른 글꼴로 렌더**됐다. 폴백을 명시하면 그 선택이 결정적이 된다.\n ⚠**웹폰트를 로드하지 않는다.** 라이브러리가 네트워크 요청을 만들면 소비자의 CSP·\n 오프라인 환경을 깬다. 스택 맨 앞의 `Pretendard` 는 **소비자가 로드했을 때만** 잡히는\n 선택적 이름이다(없으면 조용히 다음으로 넘어간다).\n ========================================================================== */\n --u-font-base: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 'Apple SD Gothic Neo', 'Malgun Gothic', 'Noto Sans KR', 'Hiragino Sans', 'Yu Gothic UI', 'Microsoft YaHei', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';\n --u-font-mono: ui-monospace, 'Cascadia Code', Consolas, 'Source Code Pro', Menlo, Monaco, 'Courier New', monospace;\n --u-font-serif: 'Georgia', 'Times New Roman', Times, serif;\n --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;\n --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n}\n\n/* ==========================================================================\n ★`prefers-reduced-motion` 존중 — **라이브러리가 진다.**\n 소비자마다 각자 처리하게 두면 반드시 빠뜨리는 앱이 나온다(그리고 그 앱은\n 접근성 감사 전까지 아무도 모른다). 지속시간 축을 0 으로 눌러 두면 이 축을\n 경유하는 모든 애니메이션이 함께 멈춘다.\n ⚠`animation: none` 으로 강제하지 않는다 — 로딩 스피너처럼 **의미를 나르는**\n 움직임까지 죽이면 사용자가 진행 중인지 알 수 없게 된다.\n ========================================================================== */\n@media (prefers-reduced-motion: reduce) {\n :root {\n --u-duration-instant: 0ms;\n --u-duration-fast: 0ms;\n --u-duration-normal: 0ms;\n --u-duration-slow: 0ms;\n }\n}\n";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { light_css_default as default };
|
|
@@ -87,12 +87,4 @@ export declare abstract class UOverlayElement extends UElement {
|
|
|
87
87
|
private cleanup;
|
|
88
88
|
/** host 자체를 클릭한 경우(백드롭)만 닫기 요청 */
|
|
89
89
|
private handlePointerdown;
|
|
90
|
-
/**
|
|
91
|
-
* ESC 키 입력 시 닫기 요청 (최상위 오버레이에 대해서만).
|
|
92
|
-
*
|
|
93
|
-
* 이미 소비된 Escape(`defaultPrevented`)는 받지 않는다 — 오버레이 안에서 열린 목록·팝오버가
|
|
94
|
-
* 자기 층을 닫으며 먹은 키다. 한 번의 Escape 는 한 층만 닫는다. 이 리스너는 window 버블에
|
|
95
|
-
* 있으므로 안쪽 컨트롤과 document 리스너가 모두 돈 «뒤» 에 판단한다.
|
|
96
|
-
*/
|
|
97
|
-
private handleWindowKeydown;
|
|
98
90
|
}
|
|
@@ -28,12 +28,6 @@ var UOverlayElement = class extends UElement {
|
|
|
28
28
|
this.handlePointerdown = (e) => {
|
|
29
29
|
if (e.composedPath()[0] === this) this.requestClose("backdrop");
|
|
30
30
|
};
|
|
31
|
-
this.handleWindowKeydown = (e) => {
|
|
32
|
-
if (!this.open || e.key !== "Escape" || e.defaultPrevented) return;
|
|
33
|
-
if (!OverlayManager.isTopmost(this)) return;
|
|
34
|
-
e.preventDefault();
|
|
35
|
-
this.requestClose("escape");
|
|
36
|
-
};
|
|
37
31
|
}
|
|
38
32
|
static {
|
|
39
33
|
this.styles = [super.styles, styles];
|
|
@@ -97,7 +91,7 @@ var UOverlayElement = class extends UElement {
|
|
|
97
91
|
/** 오버레이가 열릴 때 설정을 적용합니다. */
|
|
98
92
|
setup() {
|
|
99
93
|
OverlayManager.add(this, this.shouldLockBody);
|
|
100
|
-
|
|
94
|
+
OverlayManager.openLayer(this, () => this.requestClose("escape"));
|
|
101
95
|
this.addEventListener("pointerdown", this.handlePointerdown);
|
|
102
96
|
if (this.mode === "modal") {
|
|
103
97
|
if (!this.focusTrap) this.focusTrap = createFocusTrap(this, {
|
|
@@ -141,8 +135,8 @@ var UOverlayElement = class extends UElement {
|
|
|
141
135
|
/** 오버레이가 닫힐 때 설정을 해제합니다. */
|
|
142
136
|
cleanup() {
|
|
143
137
|
this.focusTrap?.deactivate();
|
|
144
|
-
window.removeEventListener("keydown", this.handleWindowKeydown);
|
|
145
138
|
this.removeEventListener("pointerdown", this.handlePointerdown);
|
|
139
|
+
OverlayManager.closeLayer(this);
|
|
146
140
|
OverlayManager.remove(this, this.shouldLockBody);
|
|
147
141
|
}
|
|
148
142
|
};
|
|
@@ -2,6 +2,7 @@ import { isCoarsePointer } from "../../utilities/elements.js";
|
|
|
2
2
|
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorateMetadata.js";
|
|
3
3
|
import __decorate from "../../_virtual/_@oxc-project_runtime@0.151.0/helpers/esm/decorate.js";
|
|
4
4
|
import { UFloatingElement } from "../UFloatingElement.js";
|
|
5
|
+
import { OverlayManager } from "../../utilities/OverlayManager.js";
|
|
5
6
|
import { arrayAttrConverter } from "../../utilities/converters.js";
|
|
6
7
|
import { styles } from "./UPopover.styles.js";
|
|
7
8
|
import { html } from "lit";
|
|
@@ -111,8 +112,7 @@ var UPopover = class UPopover extends UFloatingElement {
|
|
|
111
112
|
};
|
|
112
113
|
this.handleDocumentKeydown = (e) => {
|
|
113
114
|
if (e.key !== "Escape") return;
|
|
114
|
-
if (
|
|
115
|
-
if (this.open) e.preventDefault();
|
|
115
|
+
if (this.open || !this.targetEl) return;
|
|
116
116
|
this.hide();
|
|
117
117
|
};
|
|
118
118
|
this.handleDocumentScroll = () => {
|
|
@@ -139,12 +139,19 @@ var UPopover = class UPopover extends UFloatingElement {
|
|
|
139
139
|
}
|
|
140
140
|
disconnectedCallback() {
|
|
141
141
|
clearTimeout(this.safeTimer);
|
|
142
|
+
OverlayManager.closeLayer(this);
|
|
142
143
|
if (this.anchors) this.unbind(this.anchors);
|
|
143
144
|
super.disconnectedCallback();
|
|
144
145
|
}
|
|
145
146
|
updated(changedProperties) {
|
|
146
147
|
super.updated(changedProperties);
|
|
147
148
|
if (changedProperties.has("open") && this.open && this.autofocus) this.focusTo(0);
|
|
149
|
+
if (changedProperties.has("open") || changedProperties.has("dismiss")) {
|
|
150
|
+
if (this.open && this.dismiss.includes("escape")) OverlayManager.openLayer(this, () => {
|
|
151
|
+
this.hide();
|
|
152
|
+
});
|
|
153
|
+
else OverlayManager.closeLayer(this);
|
|
154
|
+
}
|
|
148
155
|
if ([
|
|
149
156
|
"anchors",
|
|
150
157
|
"trigger",
|
package/dist/styles/dark.css
CHANGED
|
@@ -346,6 +346,18 @@
|
|
|
346
346
|
--u-radius-pill: 9999px;
|
|
347
347
|
--u-radius-circle: 50%;
|
|
348
348
|
|
|
349
|
+
/* ==========================================================================
|
|
350
|
+
Layer Scale — 페이지 전역에서 겹치는 표면의 쌓임 순서
|
|
351
|
+
컴포넌트 «안» 의 국소 순서(1~100)는 그 컴포넌트의 쌓임 맥락 안에서만 뜻이 있어 여기 두지 않는다.
|
|
352
|
+
여기는 서로 다른 패키지의 표면이 페이지에서 다투는 층이다 — 값을 흩뿌리면 층이 갈린다
|
|
353
|
+
(셸 1000 · 플로팅 1000 · 오버레이 9999 · 라이트박스 9999 가 각자 숫자였다).
|
|
354
|
+
오버레이 띠의 실제 값은 OverlayManager 가 «동시에 열린 깊이» 로 인라인에 쓴다 — 이 토큰은
|
|
355
|
+
그 띠의 시작값(열리기 전 기본값)이고 OverlayManager.OVERLAY_BASE 와 같아야 한다.
|
|
356
|
+
========================================================================== */
|
|
357
|
+
--u-layer-shell: 1000; /* 앱 셸의 사이드바·모바일 머리 */
|
|
358
|
+
--u-layer-floating: 1000; /* 팝오버·목록·메뉴 — 앵커를 따라 뜨는 표면 */
|
|
359
|
+
--u-layer-overlay: 9999; /* 대화상자·서랍·라이트박스 — 화면을 덮는 표면 */
|
|
360
|
+
|
|
349
361
|
/* ==========================================================================
|
|
350
362
|
Space Scale — 컨테이너·오버레이의 절대 여백
|
|
351
363
|
⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이의 **레이아웃 여백**만
|
package/dist/styles/light.css
CHANGED
|
@@ -206,6 +206,18 @@
|
|
|
206
206
|
--u-radius-pill: 9999px;
|
|
207
207
|
--u-radius-circle: 50%;
|
|
208
208
|
|
|
209
|
+
/* ==========================================================================
|
|
210
|
+
Layer Scale — 페이지 전역에서 겹치는 표면의 쌓임 순서
|
|
211
|
+
컴포넌트 «안» 의 국소 순서(1~100)는 그 컴포넌트의 쌓임 맥락 안에서만 뜻이 있어 여기 두지 않는다.
|
|
212
|
+
여기는 서로 다른 패키지의 표면이 페이지에서 다투는 층이다 — 값을 흩뿌리면 층이 갈린다
|
|
213
|
+
(셸 1000 · 플로팅 1000 · 오버레이 9999 · 라이트박스 9999 가 각자 숫자였다).
|
|
214
|
+
오버레이 띠의 실제 값은 OverlayManager 가 «동시에 열린 깊이» 로 인라인에 쓴다 — 이 토큰은
|
|
215
|
+
그 띠의 시작값(열리기 전 기본값)이고 OverlayManager.OVERLAY_BASE 와 같아야 한다.
|
|
216
|
+
========================================================================== */
|
|
217
|
+
--u-layer-shell: 1000; /* 앱 셸의 사이드바·모바일 머리 */
|
|
218
|
+
--u-layer-floating: 1000; /* 팝오버·목록·메뉴 — 앵커를 따라 뜨는 표면 */
|
|
219
|
+
--u-layer-overlay: 9999; /* 대화상자·서랍·라이트박스 — 화면을 덮는 표면 */
|
|
220
|
+
|
|
209
221
|
/* ==========================================================================
|
|
210
222
|
Space Scale — 컨테이너·오버레이의 절대 여백
|
|
211
223
|
⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이(카드·대화상자·드로어·
|
|
@@ -50,6 +50,38 @@ export declare class OverlayManager {
|
|
|
50
50
|
private static savedOverflow;
|
|
51
51
|
/** focus-trap 공유 trapStack */
|
|
52
52
|
static readonly trapStack: FocusTrap[];
|
|
53
|
+
/**
|
|
54
|
+
* 닫을 수 있는 층 — **여는 순서대로** 쌓인다. 대화상자·서랍(`UOverlayElement`)만이 아니라
|
|
55
|
+
* 팝오버·앱 셸의 패널처럼 z-index 띠를 쓰지 않는 층도 여기 선다.
|
|
56
|
+
*
|
|
57
|
+
* ## 왜 한 곳인가 — «한 번의 Escape 는 가장 위 층 하나만 닫는다»
|
|
58
|
+
*
|
|
59
|
+
* 층마다 제 리스너로 Escape 를 받으면 순서가 «리스너를 등록한 순서» 가 된다. 그것은 층이 쌓인
|
|
60
|
+
* 순서와 다르다 — 앱 셸은 패널을 열 때 등록하므로 패널 «안» 에서 나중에 연 서랍보다 먼저 돌아
|
|
61
|
+
* 바깥을 닫았고, 닫힌 팝오버가 document 에서 Escape 를 먹어 셸의 닫기를 막았고, 팝오버 안에서 연
|
|
62
|
+
* 하위 팝오버는 Escape 한 번에 둘 다 닫혔다. 순서를 «여는 순서» 로 한 곳에 두면 셋이 같은 규칙이
|
|
63
|
+
* 된다.
|
|
64
|
+
*
|
|
65
|
+
* 리스너는 **document 버블 하나이고, 모듈을 읽을 때 한 번 붙는다** — 안쪽 컨트롤(목록·입력)이
|
|
66
|
+
* 요소 수준에서 먹은 Escape(`defaultPrevented`)는 층을 닫지 않고, 앱이 window 에 건 리스너보다는
|
|
67
|
+
* 항상 먼저 돈다(층이 열린 «뒤» 에 붙이면 먼저 등록된 앱 리스너가 소비 전의 키를 본다 — 팝오버가
|
|
68
|
+
* 층이 되기 전 document 에서 먹던 순서를 지킨다). 층이 없으면 곧바로 돌아간다. 층을 닫은 Escape 는 `preventDefault` 로 소비됐음을
|
|
69
|
+
* 알린다(뒤에 듣는 앱 리스너가 «누가 먹었나» 를 가릴 수 있게). IME 조합 중인 Escape 는 조합을
|
|
70
|
+
* 끝내는 키라 받지 않는다.
|
|
71
|
+
*/
|
|
72
|
+
private static readonly layers;
|
|
73
|
+
/**
|
|
74
|
+
* 층을 연다 — 이미 열려 있으면 맨 위로 옮긴다. `onEscape` 는 이 층이 가장 위일 때 Escape 가 부른다.
|
|
75
|
+
*
|
|
76
|
+
* `onEscape` 가 `false` 를 돌려주면 **거절**이다 — 키를 소비하지 않고 어떤 층도 닫지 않는다.
|
|
77
|
+
* 비모달 패널이 «포커스가 자기 안에 있을 때만» Escape 로 닫히는 경우에 쓴다(WAI-ARIA 비모달 대화상자).
|
|
78
|
+
*/
|
|
79
|
+
static openLayer(el: HTMLElement, onEscape: (e: KeyboardEvent) => boolean | void): void;
|
|
80
|
+
/** 층을 닫는다(스택에서 뺀다). 열려 있지 않으면 아무것도 하지 않는다. */
|
|
81
|
+
static closeLayer(el: HTMLElement): void;
|
|
82
|
+
/** 가장 위의 층(없으면 `undefined`). */
|
|
83
|
+
static get topLayer(): HTMLElement | undefined;
|
|
84
|
+
private static handleLayerKeydown;
|
|
53
85
|
/** 현재 열린 오버레이 수 */
|
|
54
86
|
static get size(): number;
|
|
55
87
|
/** 가장 위에 있는 오버레이인지 확인 */
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* 포기하고, **알림이 위**라는 불변식은 유지된다) — 실제 앱이 도달하는 상태가 아니지만,
|
|
31
31
|
* 도달하더라도 무엇이 깨지는지 정해져 있는 편이 낫다.
|
|
32
32
|
*/
|
|
33
|
-
var OverlayManager = class {
|
|
33
|
+
var OverlayManager = class OverlayManager {
|
|
34
34
|
static {
|
|
35
35
|
this.stack = [];
|
|
36
36
|
}
|
|
@@ -58,6 +58,44 @@ var OverlayManager = class {
|
|
|
58
58
|
static {
|
|
59
59
|
this.trapStack = [];
|
|
60
60
|
}
|
|
61
|
+
static {
|
|
62
|
+
this.layers = [];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 층을 연다 — 이미 열려 있으면 맨 위로 옮긴다. `onEscape` 는 이 층이 가장 위일 때 Escape 가 부른다.
|
|
66
|
+
*
|
|
67
|
+
* `onEscape` 가 `false` 를 돌려주면 **거절**이다 — 키를 소비하지 않고 어떤 층도 닫지 않는다.
|
|
68
|
+
* 비모달 패널이 «포커스가 자기 안에 있을 때만» Escape 로 닫히는 경우에 쓴다(WAI-ARIA 비모달 대화상자).
|
|
69
|
+
*/
|
|
70
|
+
static openLayer(el, onEscape) {
|
|
71
|
+
this.closeLayer(el);
|
|
72
|
+
this.layers.push({
|
|
73
|
+
el,
|
|
74
|
+
onEscape
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** 층을 닫는다(스택에서 뺀다). 열려 있지 않으면 아무것도 하지 않는다. */
|
|
78
|
+
static closeLayer(el) {
|
|
79
|
+
const idx = this.layers.findIndex((l) => l.el === el);
|
|
80
|
+
if (idx === -1) return;
|
|
81
|
+
this.layers.splice(idx, 1);
|
|
82
|
+
}
|
|
83
|
+
/** 가장 위의 층(없으면 `undefined`). */
|
|
84
|
+
static get topLayer() {
|
|
85
|
+
return this.layers[this.layers.length - 1]?.el;
|
|
86
|
+
}
|
|
87
|
+
static {
|
|
88
|
+
this.handleLayerKeydown = (e) => {
|
|
89
|
+
if (e.key !== "Escape" || e.isComposing || e.defaultPrevented) return;
|
|
90
|
+
const top = OverlayManager.layers[OverlayManager.layers.length - 1];
|
|
91
|
+
if (!top) return;
|
|
92
|
+
if (top.onEscape(e) === false) return;
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
static {
|
|
97
|
+
if (typeof document !== "undefined") document.addEventListener("keydown", OverlayManager.handleLayerKeydown);
|
|
98
|
+
}
|
|
61
99
|
/** 현재 열린 오버레이 수 */
|
|
62
100
|
static get size() {
|
|
63
101
|
return this.stack.length;
|
package/package.json
CHANGED
|
@@ -19,6 +19,23 @@ Overlay z-index comes from **how many overlays are open at once** (stack depth),
|
|
|
19
19
|
|
|
20
20
|
> **Do not hardcode a z-index for a surface that must appear above overlays.** Read `OverlayManager.notificationZIndex` so the value follows the scale.
|
|
21
21
|
|
|
22
|
+
## Layer stack — one Escape closes the topmost layer
|
|
23
|
+
|
|
24
|
+
Every surface that closes on Escape is a **layer**, and layers stack in **the order they opened**: `u-dialog` and `u-drawer`, an open `u-popover` (unless its `dismiss` leaves out `escape`), and any app surface that registers itself. One Escape closes the topmost layer only — a popover opened inside a popover closes alone, a drawer opened inside an app panel closes before the panel.
|
|
25
|
+
|
|
26
|
+
The manager listens once, on `document` in the bubble phase:
|
|
27
|
+
|
|
28
|
+
- an Escape a control already handled (`defaultPrevented` — a list closing, an input clearing) closes no layer;
|
|
29
|
+
- the Escape that closes a layer is marked consumed (`preventDefault`), so a listener an app put on `window` sees `defaultPrevented === true`;
|
|
30
|
+
- an Escape during IME composition is left alone.
|
|
31
|
+
|
|
32
|
+
An app surface that is not a `UOverlayElement` (a shell panel, a custom sheet) joins the same order:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
OverlayManager.openLayer(panel, () => closePanel()); // when it opens
|
|
36
|
+
OverlayManager.closeLayer(panel); // when it closes, by any path
|
|
37
|
+
```
|
|
38
|
+
|
|
22
39
|
> **Note:** You generally do not need to use `OverlayManager` directly. It is called automatically by overlay components. Only use it if you are building a custom overlay component that extends `UOverlayElement`.
|
|
23
40
|
|
|
24
41
|
## API
|
|
@@ -27,7 +44,10 @@ Overlay z-index comes from **how many overlays are open at once** (stack depth),
|
|
|
27
44
|
|--------|----------------|-------------|
|
|
28
45
|
| `OverlayManager.add(overlay, lockBody?)` | `void` | Register an overlay; assigns a z-index from the overlay band by stack depth; optionally locks body scroll |
|
|
29
46
|
| `OverlayManager.remove(overlay, lockBody?)` | `void` | Unregister an overlay; releases scroll lock if no overlays remain |
|
|
30
|
-
| `OverlayManager.isTopmost(overlay)` | `boolean` | Returns `true` if the overlay is the topmost in the
|
|
47
|
+
| `OverlayManager.isTopmost(overlay)` | `boolean` | Returns `true` if the overlay is the topmost in the overlay (z-index) stack |
|
|
48
|
+
| `OverlayManager.openLayer(el, onEscape)` | `void` | Put `el` on top of the layer stack; `onEscape` runs when it is topmost and an unhandled Escape arrives. Opening an open layer moves it to the top |
|
|
49
|
+
| `OverlayManager.closeLayer(el)` | `void` | Take `el` off the layer stack (no-op if it is not on it) |
|
|
50
|
+
| `OverlayManager.topLayer` | `HTMLElement \| undefined` | The topmost layer |
|
|
31
51
|
| `OverlayManager.size` | `number` | Number of currently open overlays |
|
|
32
52
|
| `OverlayManager.notificationZIndex` | `number` | z-index of the notification layer — guaranteed above the whole overlay band. Use this for toasts, snackbars, and anything else that must remain visible over an open modal |
|
|
33
53
|
| `OverlayManager.trapStack` | `FocusTrap[]` | Shared focus-trap stack (used internally by focus-trap library) |
|