@iyulab/components 1.44.0 → 1.44.1

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/_virtual/_glob-assets_raw/dark.css.e8ac080d.js +1 -1
  3. package/dist/assets/locales/ar.json.js +6 -2
  4. package/dist/assets/locales/de.json.js +6 -2
  5. package/dist/assets/locales/en.json.js +6 -2
  6. package/dist/assets/locales/es.json.js +6 -2
  7. package/dist/assets/locales/fr.json.js +6 -2
  8. package/dist/assets/locales/id.json.js +6 -2
  9. package/dist/assets/locales/ja.json.js +5 -2
  10. package/dist/assets/locales/ko.json.js +6 -2
  11. package/dist/assets/locales/pt-BR.json.js +6 -2
  12. package/dist/assets/locales/ru.json.js +6 -2
  13. package/dist/assets/locales/th.json.js +6 -2
  14. package/dist/assets/locales/vi.json.js +6 -2
  15. package/dist/assets/locales/zh-CN.json.js +6 -2
  16. package/dist/assets/locales/zh-TW.json.js +6 -2
  17. package/dist/components/UOverlayElement.d.ts +7 -1
  18. package/dist/components/UOverlayElement.js +1 -1
  19. package/dist/components/breadcrumb-item/UBreadcrumbItem.js +1 -0
  20. package/dist/components/date-picker/UDatePicker.js +1 -0
  21. package/dist/components/input/UInput.js +2 -1
  22. package/dist/components/menu-item/UMenuItem.js +5 -1
  23. package/dist/components/popover/UPopover.d.ts +10 -0
  24. package/dist/components/popover/UPopover.js +3 -1
  25. package/dist/components/radio/URadio.js +1 -0
  26. package/dist/components/rating/URating.js +1 -0
  27. package/dist/components/select/USelect.d.ts +8 -0
  28. package/dist/components/select/USelect.js +6 -1
  29. package/dist/components/tab/UTab.d.ts +2 -0
  30. package/dist/components/tab/UTab.js +7 -0
  31. package/dist/components/tree-item/UTreeItem.js +5 -1
  32. package/dist/styles/dark.css +72 -47
  33. package/dist/utilities/Dialog.d.ts +2 -2
  34. package/dist/utilities/Dialog.js +5 -4
  35. package/dist/utilities/Locale.d.ts +1 -1
  36. package/package.json +1 -1
  37. package/skills/iyulab-components/SKILL.md +7 -0
  38. package/skills/iyulab-components/references/components/popover.md +12 -0
  39. package/skills/iyulab-components/references/extensions/overlay.md +3 -1
  40. package/skills/iyulab-components/references/utilities/dialog.md +2 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.44.1] - 2026-09-23
4
+
5
+ ### Fixed
6
+
7
+ - 🔴 **A closed popover no longer consumes `Escape`.** A popover with `escape` in its `dismiss`
8
+ list listens on the document from the moment it connects, and it called `preventDefault()`
9
+ whether or not it was open. Every form control carries a popover, so on any real screen a
10
+ document-level `Escape` always arrived already `defaultPrevented` — and `defaultPrevented` is
11
+ exactly the signal you need to tell whether an inner layer handled the key. Now only an open
12
+ popover consumes it. A popover waiting on `showDelay` still has its pending show cancelled, but
13
+ the key is not consumed because nothing was visible yet. A closed popover also ignores document
14
+ clicks instead of running `hide()` on every click.
15
+ - **`u-input` no longer consumes `Escape` while its suggestion list is closed.**
16
+ - **`u-select` returns focus to the combobox when its list closes with focus inside it.** Closing
17
+ the list with `Escape` or choosing an option with the keyboard left focus inside the hidden
18
+ list, where keyboard users lost their place and the next `Escape` was swallowed again. Closing
19
+ by clicking elsewhere does not move focus.
20
+ - **Dialogs and drawers ignore an `Escape` that something inside them already consumed.** With an
21
+ open list inside a dialog, one press used to close both. Now the first press closes the list and
22
+ the second closes the dialog — one press, one layer.
23
+ - 🔴 **`disabled` is now exposed to assistive technology on controls whose role sits on a
24
+ non-native node.** These controls blocked interaction but never said so: screen readers
25
+ announced nothing, and test tools that check actionability treated the control as enabled,
26
+ clicked it, and had the click silently swallowed. `aria-disabled="true"` is now set on the
27
+ `combobox` of `u-select` and `u-date-picker`, the `radiogroup` of `u-radio` and `u-rating`,
28
+ the host of `u-menu-item`, `u-tab` and `u-tree-item`, and the link of `u-breadcrumb-item`.
29
+
30
+ - 🔴 **In dark mode, a `:root` override of the scale tokens now wins, as it does in light.**
31
+ `dark.css` redeclared radius, spacing, the type scale, motion and fonts — with the same values as
32
+ `light.css` — under `:root[theme="dark"]`, which outranks `:root`. So every layer that sets those
33
+ tokens on `:root` (the `@iyulab/enterprise` preset, a brand sheet) lost in dark mode regardless
34
+ of load order. Colors still switched, so dark mode *looked* fine while the type scale and radius
35
+ quietly fell back to neutral. Those tokens now sit in a `:root:where([theme="dark"])` block, at
36
+ the same specificity as `:root`. `dark.css` still defines every token, so a fixed-dark screen
37
+ that loads only that sheet is unaffected. **No visual change** for anyone not overriding them.
38
+ - 🔴 **`prefers-reduced-motion` is honoured in dark mode.** The durations were among the tokens
39
+ redeclared at the higher specificity, so `light.css`'s reduced-motion rule lost to them and
40
+ animations kept running for users who asked for less motion. `dark.css` now carries the same
41
+ rule for itself.
42
+
43
+ - **`Dialog.confirm` and `Dialog.prompt` label their buttons in the active locale.** The defaults
44
+ were the English literals `Cancel` and `Confirm`, so an app that had switched `Locale` got
45
+ English buttons under a translated message, while every other built-in label in this package
46
+ already followed the locale. `confirm` and `cancel` are now in all fourteen built-in tables;
47
+ labels you pass explicitly still win, and English is unchanged.
48
+
49
+ ⚠ **If you close your own panel on `Escape`**, you can now guard it with `event.defaultPrevented`
50
+ the way the platform intends; you no longer need to inspect which popovers are open. **If a test
51
+ locates a control by tag and expects a click on a disabled one to be attempted**, it will now
52
+ wait instead — locate by role.
53
+
54
+ ### Documentation
55
+
56
+ - The popover and overlay references state the `Escape` contract, with the guard a consumer
57
+ panel should use. The skill index states where `disabled` is exposed for each control.
58
+ - `docs/theming.md` says which tokens a `:root` override reaches in dark mode, and how to
59
+ override a color there too.
60
+
3
61
  ## [1.44.0] - 2026-09-22
4
62
 
5
63
  ### Fixed
@@ -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 /* ==========================================================================\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 /* 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 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-500);\n --u-scrollbar-color-hover: var(--u-neutral-600);\n --u-scrollbar-track-color: transparent;\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', '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}";
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 /* 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', '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 };
@@ -38,6 +38,8 @@ var alertMessage = "رسالة";
38
38
  var remove = "إزالة";
39
39
  var closeTab = "إغلاق علامة التبويب";
40
40
  var breadcrumb = "مسار التنقل";
41
+ var confirm = "تأكيد";
42
+ var cancel = "إلغاء";
41
43
  var ar_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var ar_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, ar_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, ar_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Nachricht";
38
38
  var remove = "Entfernen";
39
39
  var closeTab = "Tab schließen";
40
40
  var breadcrumb = "Navigationspfad";
41
+ var confirm = "Bestätigen";
42
+ var cancel = "Abbrechen";
41
43
  var de_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var de_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, de_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, de_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Message";
38
38
  var remove = "Remove";
39
39
  var closeTab = "Close tab";
40
40
  var breadcrumb = "Breadcrumb";
41
+ var confirm = "Confirm";
42
+ var cancel = "Cancel";
41
43
  var en_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var en_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, en_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, en_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -37,6 +37,8 @@ var alertMessage = "Mensaje";
37
37
  var remove = "Quitar";
38
38
  var closeTab = "Cerrar pestaña";
39
39
  var breadcrumb = "Ruta de navegación";
40
+ var confirm = "Confirmar";
41
+ var cancel = "Cancelar";
40
42
  var es_default = {
41
43
  valueMissing,
42
44
  badInput,
@@ -76,7 +78,9 @@ var es_default = {
76
78
  alertMessage,
77
79
  remove,
78
80
  closeTab,
79
- breadcrumb
81
+ breadcrumb,
82
+ confirm,
83
+ cancel
80
84
  };
81
85
  //#endregion
82
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, es_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, tooLong, tooShort, typeMismatch, valueMissing };
86
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, es_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Message";
38
38
  var remove = "Supprimer";
39
39
  var closeTab = "Fermer l'onglet";
40
40
  var breadcrumb = "Fil d'Ariane";
41
+ var confirm = "Confirmer";
42
+ var cancel = "Annuler";
41
43
  var fr_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var fr_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, fr_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, fr_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Pesan";
38
38
  var remove = "Hapus";
39
39
  var closeTab = "Tutup tab";
40
40
  var breadcrumb = "Navigasi remah roti";
41
+ var confirm = "Konfirmasi";
42
+ var cancel = "Batal";
41
43
  var id_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var id_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, id_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, id_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,7 @@ var alertMessage = "メッセージ";
38
38
  var remove = "削除";
39
39
  var closeTab = "タブを閉じる";
40
40
  var breadcrumb = "パンくずリスト";
41
+ var cancel = "キャンセル";
41
42
  var ja_default = {
42
43
  valueMissing,
43
44
  badInput,
@@ -77,7 +78,9 @@ var ja_default = {
77
78
  alertMessage,
78
79
  remove,
79
80
  closeTab,
80
- breadcrumb
81
+ breadcrumb,
82
+ confirm: "OK",
83
+ cancel
81
84
  };
82
85
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, ja_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
86
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, ja_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "메시지";
38
38
  var remove = "제거";
39
39
  var closeTab = "탭 닫기";
40
40
  var breadcrumb = "탐색 경로";
41
+ var confirm = "확인";
42
+ var cancel = "취소";
41
43
  var ko_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var ko_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, ko_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, ko_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Mensagem";
38
38
  var remove = "Remover";
39
39
  var closeTab = "Fechar aba";
40
40
  var breadcrumb = "Trilha de navegação";
41
+ var confirm = "Confirmar";
42
+ var cancel = "Cancelar";
41
43
  var pt_BR_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var pt_BR_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, pt_BR_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, pt_BR_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Сообщение";
38
38
  var remove = "Удалить";
39
39
  var closeTab = "Закрыть вкладку";
40
40
  var breadcrumb = "Навигационная цепочка";
41
+ var confirm = "Подтвердить";
42
+ var cancel = "Отмена";
41
43
  var ru_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var ru_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, ru_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, ru_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "ข้อความ";
38
38
  var remove = "ลบ";
39
39
  var closeTab = "ปิดแท็บ";
40
40
  var breadcrumb = "เส้นทางการนำทาง";
41
+ var confirm = "ยืนยัน";
42
+ var cancel = "ยกเลิก";
41
43
  var th_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var th_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, th_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, th_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "Thông báo";
38
38
  var remove = "Xóa";
39
39
  var closeTab = "Đóng tab";
40
40
  var breadcrumb = "Đường dẫn điều hướng";
41
+ var confirm = "Xác nhận";
42
+ var cancel = "Hủy";
41
43
  var vi_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var vi_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, vi_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, vi_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "消息";
38
38
  var remove = "移除";
39
39
  var closeTab = "关闭标签页";
40
40
  var breadcrumb = "面包屑导航";
41
+ var confirm = "确定";
42
+ var cancel = "取消";
41
43
  var zh_CN_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var zh_CN_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, zh_CN_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, zh_CN_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -38,6 +38,8 @@ var alertMessage = "訊息";
38
38
  var remove = "移除";
39
39
  var closeTab = "關閉分頁";
40
40
  var breadcrumb = "麵包屑導覽";
41
+ var confirm = "確定";
42
+ var cancel = "取消";
41
43
  var zh_TW_default = {
42
44
  valueMissing,
43
45
  badInput,
@@ -77,7 +79,9 @@ var zh_TW_default = {
77
79
  alertMessage,
78
80
  remove,
79
81
  closeTab,
80
- breadcrumb
82
+ breadcrumb,
83
+ confirm,
84
+ cancel
81
85
  };
82
86
  //#endregion
83
- export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, chooseDate, chooseFile, clear, close, closeTab, copied, copy, decrement, zh_TW_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
87
+ export { alertError, alertInfo, alertMessage, alertNotice, alertSuccess, alertWarning, badInput, breadcrumb, cancel, chooseDate, chooseFile, clear, close, closeTab, confirm, copied, copy, decrement, zh_TW_default as default, filesSelected, goToSlide, hidePassword, increment, nextMonth, nextSlide, noFileChosen, patternMismatch, previousMonth, previousSlide, rangeOverflow, rangeUnderflow, remove, resizePanels, search, showPassword, stepMismatch, time, today, tooLong, tooShort, typeMismatch, valueMissing };
@@ -87,6 +87,12 @@ export declare abstract class UOverlayElement extends UElement {
87
87
  private cleanup;
88
88
  /** host 자체를 클릭한 경우(백드롭)만 닫기 요청 */
89
89
  private handlePointerdown;
90
- /** ESC 키 입력 시 닫기 요청 (최상위 오버레이에 대해서만) */
90
+ /**
91
+ * ESC 키 입력 시 닫기 요청 (최상위 오버레이에 대해서만).
92
+ *
93
+ * 이미 소비된 Escape(`defaultPrevented`)는 받지 않는다 — 오버레이 안에서 열린 목록·팝오버가
94
+ * 자기 층을 닫으며 먹은 키다. 한 번의 Escape 는 한 층만 닫는다. 이 리스너는 window 버블에
95
+ * 있으므로 안쪽 컨트롤과 document 리스너가 모두 돈 «뒤» 에 판단한다.
96
+ */
91
97
  private handleWindowKeydown;
92
98
  }
@@ -28,7 +28,7 @@ var UOverlayElement = class extends UElement {
28
28
  if (e.composedPath()[0] === this) this.requestClose("backdrop");
29
29
  };
30
30
  this.handleWindowKeydown = (e) => {
31
- if (!this.open || e.key !== "Escape") return;
31
+ if (!this.open || e.key !== "Escape" || e.defaultPrevented) return;
32
32
  if (!OverlayManager.isTopmost(this)) return;
33
33
  e.preventDefault();
34
34
  this.requestClose("escape");
@@ -25,6 +25,7 @@ var UBreadcrumbItem = class UBreadcrumbItem extends UElement {
25
25
  if (this.href) return html`
26
26
  <a part="link"
27
27
  href=${this.href}
28
+ aria-disabled=${ifDefined(this.disabled ? "true" : void 0)}
28
29
  target=${ifDefined(this.target)}
29
30
  rel=${ifDefined(this.rel)}
30
31
  @click=${this.handleAnchorClick}
@@ -201,6 +201,7 @@ var UDatePicker = class UDatePicker extends UFormControlElement {
201
201
  <div class="container" part="container"
202
202
  tabindex=${this.disabled ? "-1" : "0"}
203
203
  role="combobox"
204
+ aria-disabled=${ifDefined(this.disabled ? "true" : void 0)}
204
205
  aria-haspopup="dialog"
205
206
  aria-expanded=${this.open}
206
207
  aria-label=${ifDefined(this.resolvedAriaLabel)}
@@ -72,8 +72,9 @@ var UInput = class UInput extends UFormControlElement {
72
72
  this.options.find((o) => !o.hidden && !o.disabled)?.focus();
73
73
  break;
74
74
  case "Escape":
75
+ if (!this.popoverEl?.open) break;
75
76
  e.preventDefault();
76
- this.popoverEl?.hide();
77
+ this.popoverEl.hide();
77
78
  }
78
79
  };
79
80
  this.handleSuffixIconKeydown = (action) => (e) => {
@@ -74,7 +74,11 @@ var UMenuItem = class UMenuItem extends UElement {
74
74
  }
75
75
  updated(changedProperties) {
76
76
  super.updated(changedProperties);
77
- if (changedProperties.has("disabled")) this.setAttribute("tabindex", this.disabled ? "-1" : "0");
77
+ if (changedProperties.has("disabled")) {
78
+ this.setAttribute("tabindex", this.disabled ? "-1" : "0");
79
+ if (this.disabled) this.setAttribute("aria-disabled", "true");
80
+ else this.removeAttribute("aria-disabled");
81
+ }
78
82
  if (changedProperties.has("expanded") && !this.expanded) this._childItems.forEach((c) => c.expanded = false);
79
83
  if (changedProperties.has("depth") || changedProperties.has("inline")) this.style.setProperty("--menu-item-depth", String(this.inline ? this.depth : 0));
80
84
  }
@@ -59,6 +59,16 @@ export declare class UPopover extends UFloatingElement {
59
59
  private startSafeTimer;
60
60
  private cancelSafeTimer;
61
61
  private handleDocumentClick;
62
+ /**
63
+ * 이 리스너는 `dismiss` 에 `escape` 가 있으면 **연결 시점에** document 에 붙으므로, 닫힌
64
+ * 인스턴스도 모든 Escape 를 받는다. 닫힌 팝오버는 Escape 로 할 일이 없다 — 여기서
65
+ * `preventDefault()` 하면 화면에 팝오버가 «존재하기만» 해도 document 버블 시점의 Escape 가
66
+ * 항상 소비된 것으로 보여, 소비자(그리고 우리 오버레이)가 `defaultPrevented` 로 «위에서 누가
67
+ * 먹었나» 를 가릴 수 없게 된다.
68
+ *
69
+ * 표시 대기 중(`showDelay`)이면 `targetEl` 이 이미 서 있으므로 그 대기는 취소한다 — 다만
70
+ * 아직 보이지 않았으니 소비하지는 않는다.
71
+ */
62
72
  private handleDocumentKeydown;
63
73
  /**
64
74
  * 현재 표시 중이며 앵커가 **좌표 기반 가상 엘리먼트**인지 여부.
@@ -99,6 +99,7 @@ var UPopover = class UPopover extends UFloatingElement {
99
99
  this.startSafeTimer();
100
100
  };
101
101
  this.handleDocumentClick = (e) => {
102
+ if (!this.open && !this.targetEl) return;
102
103
  if (this.trigger === "contextmenu") {
103
104
  this.hide();
104
105
  return;
@@ -110,7 +111,8 @@ var UPopover = class UPopover extends UFloatingElement {
110
111
  };
111
112
  this.handleDocumentKeydown = (e) => {
112
113
  if (e.key !== "Escape") return;
113
- e.preventDefault();
114
+ if (!this.open && !this.targetEl) return;
115
+ if (this.open) e.preventDefault();
114
116
  this.hide();
115
117
  };
116
118
  this.handleDocumentScroll = () => {
@@ -93,6 +93,7 @@ var URadio = class URadio extends UFormControlElement {
93
93
  >
94
94
  <div class="container" part="container"
95
95
  role="radiogroup"
96
+ aria-disabled=${ifDefined(this.disabled ? "true" : void 0)}
96
97
  aria-label=${ifDefined(this.resolvedAriaLabel)}
97
98
  aria-description=${ifDefined(this.resolvedAriaDescription)}>
98
99
  <slot @slotchange=${this.handleSlotChange}></slot>
@@ -112,6 +112,7 @@ var URating = class URating extends UFormControlElement {
112
112
  .validationMessage=${this.validationMessage}
113
113
  >
114
114
  <div class="symbols" part="container" role="radiogroup"
115
+ aria-disabled=${ifDefined(this.disabled ? "true" : void 0)}
115
116
  aria-label=${ifDefined(this.resolvedAriaLabel)}
116
117
  aria-description=${ifDefined(this.resolvedAriaDescription)}>
117
118
  ${Array.from({ length: this.max }, (_, i) => {
@@ -89,6 +89,14 @@ export declare class USelect extends UFormControlElement<string | string[]> {
89
89
  * updated() 경로는 base의 silent setValidity()만 수행해 Lit 중복 업데이트를 피한다). */
90
90
  private emitChange;
91
91
  private handleSlotChange;
92
+ /**
93
+ * 목록이 닫힐 때 포커스가 그 «안»(옵션·검색 입력)에 있었으면 콤보박스로 되돌린다.
94
+ *
95
+ * 되돌리지 않으면 포커스가 숨은 목록 안에 남는다 — 키보드 사용자는 자기 위치를 잃고,
96
+ * 그 옵션은 다음 Escape 까지 받아 소비해 바깥 층(오버레이·소비자 패널)이 닫히지 않는다.
97
+ * 바깥 클릭으로 닫힐 때는 포커스가 이미 다른 곳에 있으므로 건드리지 않는다.
98
+ */
99
+ private handlePopoverHide;
92
100
  private handleOptionClick;
93
101
  private handleOptionKeydown;
94
102
  private handleSearchInput;
@@ -31,6 +31,10 @@ var USelect = class USelect extends UFormControlElement {
31
31
  this.options = slot.assignedElements({ flatten: true }).filter((el) => el instanceof UOption);
32
32
  this.setup(this.options);
33
33
  };
34
+ this.handlePopoverHide = () => {
35
+ this.open = false;
36
+ if (this.popoverEl?.matches(":focus-within")) this.containerEl?.focus();
37
+ };
34
38
  this.handleOptionClick = (e) => {
35
39
  const option = e.currentTarget;
36
40
  if (option.disabled) return;
@@ -173,6 +177,7 @@ var USelect = class USelect extends UFormControlElement {
173
177
 
174
178
  <div class="container" part="container" tabindex=${this.disabled ? "-1" : "0"}
175
179
  role="combobox"
180
+ aria-disabled=${ifDefined(this.disabled ? "true" : void 0)}
176
181
  aria-label=${ifDefined(this.resolvedAriaLabel)}
177
182
  aria-description=${ifDefined(this.resolvedAriaDescription)}
178
183
  aria-haspopup=${this.searchable ? "dialog" : "listbox"}
@@ -215,7 +220,7 @@ var USelect = class USelect extends UFormControlElement {
215
220
  for=".container"
216
221
  trigger="click"
217
222
  @show=${() => this.open = true}
218
- @hide=${() => this.open = false}
223
+ @hide=${this.handlePopoverHide}
219
224
  strategy="fixed"
220
225
  placement="bottom-start"
221
226
  offset="1"
@@ -1,3 +1,4 @@
1
+ import { PropertyValues } from 'lit';
1
2
  import { UElement } from '../UElement.js';
2
3
  /**
3
4
  * 탭 패널에서 사용하는 탭 아이템(탭 버튼) 컴포넌트입니다.
@@ -24,6 +25,7 @@ export declare class UTab extends UElement {
24
25
  /** 탭 드래그 여부 */
25
26
  draggable: boolean;
26
27
  connectedCallback(): void;
28
+ protected updated(changedProperties: PropertyValues): void;
27
29
  render(): import('lit-html').TemplateResult<1>;
28
30
  private handleRemoveClick;
29
31
  }
@@ -33,6 +33,13 @@ var UTab = class UTab extends UElement {
33
33
  this.setAttribute("tabindex", "0");
34
34
  if (!this.hasAttribute("slot")) this.setAttribute("slot", "tab");
35
35
  }
36
+ updated(changedProperties) {
37
+ super.updated(changedProperties);
38
+ if (changedProperties.has("disabled")) {
39
+ if (this.disabled) this.setAttribute("aria-disabled", "true");
40
+ else this.removeAttribute("aria-disabled");
41
+ }
42
+ }
36
43
  render() {
37
44
  return html`
38
45
  <div class="base" part="base">
@@ -83,7 +83,11 @@ var UTreeItem = class UTreeItem extends UElement {
83
83
  }
84
84
  updated(changedProperties) {
85
85
  super.updated(changedProperties);
86
- if (changedProperties.has("disabled")) this.setAttribute("tabindex", this.disabled ? "-1" : "0");
86
+ if (changedProperties.has("disabled")) {
87
+ this.setAttribute("tabindex", this.disabled ? "-1" : "0");
88
+ if (this.disabled) this.setAttribute("aria-disabled", "true");
89
+ else this.removeAttribute("aria-disabled");
90
+ }
87
91
  if (changedProperties.has("depth")) this.style.setProperty("--tree-item-depth", String(this.depth));
88
92
  }
89
93
  render() {
@@ -185,47 +185,6 @@
185
185
  --u-danger-color-weak: var(--u-red-500);
186
186
  --u-danger-color: var(--u-red-600); /* 면: 흰 글자 6.83 ✓ */
187
187
  --u-danger-color-strong: var(--u-red-800); /* 글자: 바탕 4.87 ✓ (700 은 3.67 ✗) */
188
- /* ==========================================================================
189
- Radius Scale — 모서리 반경
190
- 리터럴을 흩뿌리면 값이 갈린다(실제로 pill 이 999px/9999px 두 표기로 나뉘어 있었다).
191
- ========================================================================== */
192
- --u-radius-none: 0;
193
- --u-radius-sm: 3px;
194
- --u-radius-md: 4px;
195
- --u-radius-lg: 6px;
196
- --u-radius-xl: 8px;
197
- /* ★상단 2단은 **면(surface)용**이다 — 카드·패널·대화상자처럼 큰 사각형은 컨트롤과
198
- 같은 반경을 쓰면 각져 보인다. 기존 5단은 **컨트롤용**이고 값을 바꾸지 않는다
199
- (바꾸면 모든 소비자의 버튼·입력이 동시에 움직인다). */
200
- --u-radius-2xl: 12px;
201
- --u-radius-3xl: 16px;
202
- --u-radius-pill: 9999px;
203
- --u-radius-circle: 50%;
204
-
205
- /* ==========================================================================
206
- Space Scale — 컨테이너·오버레이의 절대 여백
207
- ⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이의 **레이아웃 여백**만
208
- 담당한다. 폼·인라인 요소의 `em` 여백은 상속된 `font-size` 에 비례하는 것이 의도이므로
209
- **여기로 흡수하지 않는다.** 반경과 마찬가지로 테마와 무관하므로 두 시트가 같다.
210
- 축 구분과 근거는 docs/design-tokens.md 참조.
211
- ========================================================================== */
212
- --u-space-3xs: 2px;
213
- --u-space-2xs: 4px;
214
- --u-space-xs: 6px;
215
- --u-space-sm: 8px;
216
- --u-space-md: 12px;
217
- --u-space-lg: 16px;
218
- /* ★상단 4단은 **화면 리듬**이다 — 카드 안쪽 여백(20~24)·섹션 간격(24~32)·페이지 여백
219
- (32~40). 종전에는 이 구간이 통째로 비어 있어 소비자가 전부 리터럴로 적었고,
220
- 그래서 앱마다 화면 밀도가 달라졌다. `lg`(16px) 이하는 **요소 사이**, `xl` 이상은
221
- **영역 사이**로 나눠 쓴다.
222
- ⚠`xs: 6px` 는 4px 격자에서 벗어나 있으나 **바꾸지 않는다** — 이미 배선된 컨트롤
223
- 여백이 전부 움직인다. 신규 단은 전부 4의 배수로 둔다. */
224
- --u-space-xl: 20px;
225
- --u-space-2xl: 24px;
226
- --u-space-3xl: 32px;
227
- --u-space-4xl: 40px;
228
-
229
188
  /* Text Colors */
230
189
  --u-txt-color: var(--u-neutral-900);
231
190
  --u-txt-color-inverse: var(--u-neutral-100);
@@ -336,6 +295,64 @@
336
295
  --u-shadow-xl: 0 6px 18px rgba(0, 0, 0, 0.60), 0 2px 6px rgba(0, 0, 0, 0.30); /* = shadow-color-stronger */
337
296
 
338
297
 
298
+ /* Scrollbar Colors */
299
+ --u-scrollbar-color: var(--u-neutral-500);
300
+ --u-scrollbar-color-hover: var(--u-neutral-600);
301
+ --u-scrollbar-track-color: transparent;
302
+ }
303
+
304
+ /* ==========================================================================
305
+ ★모드와 무관한 스케일 — 반경·여백·글자 스케일·모션·글꼴.
306
+ 값이 light.css 와 **같다.** 그런데 위 블록(`:root[theme="dark"]`, 특이도 0,1,1)에 두면
307
+ `:root`(0,1,0)로 이 토큰을 덮는 **모든 층**(하우스 프리셋·소비자 브랜드 시트)이 다크
308
+ 모드에서만 **로드 순서와 무관하게** 진다 — 에러도 경고도 없이, 색은 정상으로 바뀌므로
309
+ «다크가 잘 된다» 로 보인다. `:where()` 로 특이도를 `:root` 와 같게 두면 층 모델이 라이트와
310
+ 똑같이 로드 순서로 선다.
311
+ ⚠이 블록을 지우지 말 것 — 이 시트만 쓰는 «고정 다크 디자인» 소비자(docs/theming.md)는
312
+ 이 토큰들을 여기서 받는다. 두 시트를 함께 쓸 때는 값이 같으므로 어느 쪽이 이겨도 같다.
313
+ ========================================================================== */
314
+ :root:where([theme="dark"]) {
315
+ /* ==========================================================================
316
+ Radius Scale — 모서리 반경
317
+ 리터럴을 흩뿌리면 값이 갈린다(실제로 pill 이 999px/9999px 두 표기로 나뉘어 있었다).
318
+ ========================================================================== */
319
+ --u-radius-none: 0;
320
+ --u-radius-sm: 3px;
321
+ --u-radius-md: 4px;
322
+ --u-radius-lg: 6px;
323
+ --u-radius-xl: 8px;
324
+ /* ★상단 2단은 **면(surface)용**이다 — 카드·패널·대화상자처럼 큰 사각형은 컨트롤과
325
+ 같은 반경을 쓰면 각져 보인다. 기존 5단은 **컨트롤용**이고 값을 바꾸지 않는다
326
+ (바꾸면 모든 소비자의 버튼·입력이 동시에 움직인다). */
327
+ --u-radius-2xl: 12px;
328
+ --u-radius-3xl: 16px;
329
+ --u-radius-pill: 9999px;
330
+ --u-radius-circle: 50%;
331
+
332
+ /* ==========================================================================
333
+ Space Scale — 컨테이너·오버레이의 절대 여백
334
+ ⚠**여백은 하나의 축이 아니다.** 이 스케일은 컨테이너/오버레이의 **레이아웃 여백**만
335
+ 담당한다. 폼·인라인 요소의 `em` 여백은 상속된 `font-size` 에 비례하는 것이 의도이므로
336
+ **여기로 흡수하지 않는다.** 반경과 마찬가지로 테마와 무관하므로 두 시트가 같다.
337
+ 축 구분과 근거는 docs/design-tokens.md 참조.
338
+ ========================================================================== */
339
+ --u-space-3xs: 2px;
340
+ --u-space-2xs: 4px;
341
+ --u-space-xs: 6px;
342
+ --u-space-sm: 8px;
343
+ --u-space-md: 12px;
344
+ --u-space-lg: 16px;
345
+ /* ★상단 4단은 **화면 리듬**이다 — 카드 안쪽 여백(20~24)·섹션 간격(24~32)·페이지 여백
346
+ (32~40). 종전에는 이 구간이 통째로 비어 있어 소비자가 전부 리터럴로 적었고,
347
+ 그래서 앱마다 화면 밀도가 달라졌다. `lg`(16px) 이하는 **요소 사이**, `xl` 이상은
348
+ **영역 사이**로 나눠 쓴다.
349
+ ⚠`xs: 6px` 는 4px 격자에서 벗어나 있으나 **바꾸지 않는다** — 이미 배선된 컨트롤
350
+ 여백이 전부 움직인다. 신규 단은 전부 4의 배수로 둔다. */
351
+ --u-space-xl: 20px;
352
+ --u-space-2xl: 24px;
353
+ --u-space-3xl: 32px;
354
+ --u-space-4xl: 40px;
355
+
339
356
  /* ==========================================================================
340
357
  Type Scale — 글자 크기·굵기·행간·자간의 **한 벌**
341
358
  ★**크기만 주면 스케일이 되지 않는다.** 소비자가 크기만 받고 굵기·행간을 각자 정하면
@@ -403,11 +420,6 @@
403
420
  --u-ease-decelerate: cubic-bezier(0, 0, 0, 1);
404
421
  --u-ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
405
422
 
406
- /* Scrollbar Colors */
407
- --u-scrollbar-color: var(--u-neutral-500);
408
- --u-scrollbar-color-hover: var(--u-neutral-600);
409
- --u-scrollbar-track-color: transparent;
410
-
411
423
  /* ==========================================================================
412
424
  Font Styles
413
425
  ★**CJK 폴백을 스택에 포함한다 — 국제화이지 취향이 아니다.**
@@ -425,4 +437,17 @@
425
437
  --u-font-display: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
426
438
  --u-font-modern: 'Inter', 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
427
439
  --u-font-rounded: 'Nunito', 'Quicksand', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
428
- }
440
+ }
441
+
442
+ /* ★`prefers-reduced-motion` — light.css 와 같은 규칙을 이 시트도 진다. 이 시트만 쓰는
443
+ 소비자가 있고, 두 시트를 함께 쓸 때는 어느 시트가 뒤에 오든 **마지막 선언이 이 0ms**
444
+ 가 되도록 각 시트가 자기 블록 뒤에 둔다. 종전에는 지속시간이 위 (0,1,1) 블록에 있어
445
+ 다크 모드에서 «동작 줄이기» 설정이 **무시됐다.** */
446
+ @media (prefers-reduced-motion: reduce) {
447
+ :root:where([theme="dark"]) {
448
+ --u-duration-instant: 0ms;
449
+ --u-duration-fast: 0ms;
450
+ --u-duration-normal: 0ms;
451
+ --u-duration-slow: 0ms;
452
+ }
453
+ }
@@ -22,9 +22,9 @@ export interface DialogOptions {
22
22
  }
23
23
  /** Confirm Dialog 옵션 */
24
24
  export interface ConfirmDialogOptions extends DialogOptions {
25
- /** 확인 버튼 텍스트 (기본: 'Confirm') */
25
+ /** 확인 버튼 텍스트 (기본: 현재 로케일의 `confirm` — 영어는 'Confirm') */
26
26
  confirmLabel?: string;
27
- /** 취소 버튼 텍스트 (기본: 'Cancel') */
27
+ /** 취소 버튼 텍스트 (기본: 현재 로케일의 `cancel` — 영어는 'Cancel') */
28
28
  cancelLabel?: string;
29
29
  }
30
30
  /** Prompt Dialog 옵션 */
@@ -1,4 +1,5 @@
1
1
  import "../components/button/UButton.js";
2
+ import { Locale } from "./Locale.js";
2
3
  import { UDialog } from "../components/dialog/UDialog.js";
3
4
  import "../components/input/UInput.js";
4
5
  import { html, nothing, render } from "lit";
@@ -29,11 +30,11 @@ var Dialog = class {
29
30
  ...options,
30
31
  content: message,
31
32
  actions: [{
32
- label: options?.cancelLabel || "Cancel",
33
+ label: options?.cancelLabel || Locale.getValue("cancel"),
33
34
  value: "cancel",
34
35
  variant: "outlined"
35
36
  }, {
36
- label: options?.confirmLabel || "Confirm",
37
+ label: options?.confirmLabel || Locale.getValue("confirm"),
37
38
  value: "confirm"
38
39
  }]
39
40
  }) === "confirm";
@@ -68,11 +69,11 @@ var Dialog = class {
68
69
  </div>
69
70
  `,
70
71
  actions: [{
71
- label: options?.cancelLabel || "Cancel",
72
+ label: options?.cancelLabel || Locale.getValue("cancel"),
72
73
  value: "cancel",
73
74
  variant: "outlined"
74
75
  }, {
75
- label: options?.confirmLabel || "Confirm",
76
+ label: options?.confirmLabel || Locale.getValue("confirm"),
76
77
  value: "confirm"
77
78
  }]
78
79
  }) === "confirm" ? inputValue : null;
@@ -12,7 +12,7 @@ export type SupportedLocale = 'en' | 'ko' | 'ja' | 'zh-CN' | 'zh-TW' | 'es' | 'f
12
12
  /** 내장 로케일은 자동완성되지만, 임의의 BCP47 태그도 그대로 받는다. */
13
13
  export type LocaleTag = SupportedLocale | (string & {});
14
14
  /** 라이브러리가 제공하는 chrome 문자열 키. 지금은 검증 메시지뿐이지만 이후 다른 UI 문구도 추가될 수 있다. */
15
- export type LocaleMessageKey = 'valueMissing' | 'badInput' | 'typeMismatch' | 'patternMismatch' | 'rangeUnderflow' | 'rangeOverflow' | 'stepMismatch' | 'tooShort' | 'tooLong' | 'increment' | 'decrement' | 'clear' | 'today' | 'time' | 'showPassword' | 'hidePassword' | 'previousSlide' | 'nextSlide' | 'goToSlide' | 'chooseDate' | 'previousMonth' | 'nextMonth' | 'close' | 'copy' | 'copied' | 'chooseFile' | 'noFileChosen' | 'filesSelected' | 'resizePanels' | 'breadcrumb' | 'search' | 'alertError' | 'alertWarning' | 'alertSuccess' | 'alertInfo' | 'alertNotice' | 'alertMessage' | 'remove' | 'closeTab';
15
+ export type LocaleMessageKey = 'valueMissing' | 'badInput' | 'typeMismatch' | 'patternMismatch' | 'rangeUnderflow' | 'rangeOverflow' | 'stepMismatch' | 'tooShort' | 'tooLong' | 'increment' | 'decrement' | 'clear' | 'today' | 'time' | 'showPassword' | 'hidePassword' | 'previousSlide' | 'nextSlide' | 'goToSlide' | 'chooseDate' | 'previousMonth' | 'nextMonth' | 'close' | 'copy' | 'copied' | 'chooseFile' | 'noFileChosen' | 'filesSelected' | 'resizePanels' | 'breadcrumb' | 'search' | 'alertError' | 'alertWarning' | 'alertSuccess' | 'alertInfo' | 'alertNotice' | 'alertMessage' | 'remove' | 'closeTab' | 'confirm' | 'cancel';
16
16
  type LocaleTable = Record<LocaleMessageKey, string>;
17
17
  /**
18
18
  * 한 패키지(또는 앱 영역)의 문자열 묶음.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iyulab/components",
3
3
  "description": "web-components library based on lit-element made by iyulab",
4
- "version": "1.44.0",
4
+ "version": "1.44.1",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "components",
@@ -78,6 +78,13 @@ import { UButton, UInput } from '@iyulab/components/react';
78
78
  - [`u-form`](./references/components/form.md) — Form group with two-way model binding and validation
79
79
  - [`u-option`](./references/components/option.md) — Selectable option item for `u-select`, `u-radio`, `u-input`
80
80
 
81
+ **`disabled` is exposed where assistive technology and test tools look for it** — on the node that
82
+ carries the control's role, not on the host element. Native nodes use native `disabled`
83
+ (`u-input`, `u-textarea`, `u-checkbox`, `u-switch`, `u-file-input`); role nodes get
84
+ `aria-disabled="true"` (the `combobox` of `u-select`/`u-date-picker`, the `radiogroup` of
85
+ `u-radio`/`u-rating`, the `slider` thumbs). In end-to-end tests, locate controls by role
86
+ (`getByRole('combobox')`) rather than by tag, so actionability checks see the disabled state.
87
+
81
88
  ### Overlay & Floating
82
89
 
83
90
  - [`u-dialog`](./references/components/dialog.md) — Modal/non-modal dialog with configurable placement
@@ -62,6 +62,18 @@ Inherits all `UFloatingElement` properties (see [floating.md](../extensions/floa
62
62
 
63
63
  `click` and `escape` express user intent and always close the popover.
64
64
 
65
+ **Only an open popover consumes `Escape`.** When it closes on `Escape` it calls `preventDefault()`;
66
+ a closed popover leaves the event alone. So `event.defaultPrevented` at the document or window
67
+ level reliably means *something above already handled this key* — use it to decide whether your
68
+ own panel should close:
69
+
70
+ ```ts
71
+ document.addEventListener('keydown', (e) => {
72
+ if (e.key !== 'Escape' || e.defaultPrevented) return; // an open list or popover took it
73
+ closeMyPanel();
74
+ });
75
+ ```
76
+
65
77
  `scroll` and `resize` are viewport-geometry changes and **only close the popover when it is
66
78
  anchored to a coordinate** — i.e. the virtual anchor created by `trigger="contextmenu"`, whose
67
79
  `clientX`/`clientY` stop matching whatever they pointed at once the page reflows.
@@ -8,7 +8,9 @@ Abstract base class for full-screen or contained overlays (dialogs, drawers, sid
8
8
 
9
9
  - **Focus-trap** via `focus-trap` library
10
10
  - **Body scroll lock** while open
11
- - **ESC key** and **backdrop click** close
11
+ - **ESC key** and **backdrop click** close — an `Escape` that something inside the overlay
12
+ already consumed (`defaultPrevented`, e.g. an open select list closing itself) does not close
13
+ the overlay, so one press closes one layer
12
14
  - **OverlayManager** z-index stacking
13
15
 
14
16
  ## When to extend
@@ -55,8 +55,8 @@ interface DialogOptions {
55
55
  }
56
56
 
57
57
  interface ConfirmDialogOptions extends DialogOptions {
58
- confirmLabel?: string; // default: 'Confirm'
59
- cancelLabel?: string; // default: 'Cancel'
58
+ confirmLabel?: string; // default: the active locale's `confirm` (en: 'Confirm')
59
+ cancelLabel?: string; // default: the active locale's `cancel` (en: 'Cancel')
60
60
  }
61
61
 
62
62
  interface PromptDialogOptions extends ConfirmDialogOptions {