@iyulab/components 1.14.0 → 1.15.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 +78 -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/breadcrumb/UBreadcrumb.styles.js +1 -1
- package/dist/components/breadcrumb-item/UBreadcrumbItem.styles.js +1 -1
- package/dist/components/checkbox/UCheckbox.styles.js +1 -1
- package/dist/components/divider/UDivider.styles.js +1 -1
- package/dist/components/field/UField.styles.js +1 -1
- package/dist/components/input/UInput.styles.js +1 -1
- package/dist/components/select/USelect.styles.js +4 -4
- package/dist/components/slider/USlider.styles.js +1 -1
- package/dist/components/switch/USwitch.styles.js +3 -3
- package/dist/components/tab/UTab.styles.js +1 -1
- package/dist/components/textarea/UTextarea.styles.js +2 -2
- package/dist/plugins/vite-plugin-glob-resolve.d.ts +12 -0
- package/dist/plugins/vite-plugin-glob-resolve.js +66 -0
- package/dist/plugins/vite-plugin-react-wrapper.d.ts +54 -0
- package/dist/plugins/vite-plugin-react-wrapper.js +294 -0
- package/dist/styles/dark.css +14 -0
- package/dist/styles/light.css +27 -1
- package/package.json +5 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,83 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.15.0] - 2026-08-02
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- ★**`--u-txt-color-weak` 가 라이트 테마에서 WCAG AA 에 미달하던 문제.**
|
|
8
|
+
흰 배경 대비 **2.68** (AA 기준 4.5) 이었다. neutral-500 → **neutral-600** 으로 한 단
|
|
9
|
+
내려 **4.61** 로 통과한다. 다크 매핑(neutral-700 = 5.43)은 원래 정상이었으므로 그대로
|
|
10
|
+
둔다 — **라이트 한쪽만의 결함**이었다.
|
|
11
|
+
|
|
12
|
+
이 토큰은 컴포넌트 전반의 보조 텍스트가 쓴다. **보조 텍스트가 한 단 진해진다** —
|
|
13
|
+
방향이 단조로워(가독성만 상승) 레이아웃·위계에는 영향이 없다. 배선된 폴백 리터럴
|
|
14
|
+
17곳(11파일)도 함께 맞췄다.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **유채색 표면 토큰 4종** — `--u-primary-bg-color` · `--u-info-bg-color` ·
|
|
19
|
+
`--u-success-bg-color` · `--u-danger-bg-color`.
|
|
20
|
+
|
|
21
|
+
종전에는 역할 층의 유채색이 **전경 5단뿐**이라, 상태 배경(선택된 행, 정보 패널,
|
|
22
|
+
오류 줄 …)이 필요한 컴포넌트는 팔레트를 직접 읽고 다크를 손으로 보정해야 했다.
|
|
23
|
+
|
|
24
|
+
⚠**두 테마가 같은 단이 아니라 같은 세기가 되도록 짝지었다.** 팔레트의 유채색 틴트는
|
|
25
|
+
다크에서 짓눌린다 — 바탕 대비 델타의 다크/라이트 비가 중립은 1.34~1.62배인 반면
|
|
26
|
+
청색은 **0.38~0.54배**다. 그래서 라이트 shade-0 ↔ 다크 shade-100 으로 맞췄고,
|
|
27
|
+
실측 세기 비는 blue 1.09 · red 1.12 · green 0.91 이다.
|
|
28
|
+
|
|
29
|
+
⚠**경고(yellow)는 빠져 있다.** 라이트 황색 틴트가 Δ0.071 로 거의 보이지 않아 어떤
|
|
30
|
+
단 짝을 골라도 비가 2배 밑으로 내려가지 않는다(최선 1.99). 팔레트 리터럴 재설계가
|
|
31
|
+
선행돼야 한다.
|
|
32
|
+
|
|
33
|
+
- **유채색 배경 위의 글자 토큰 5종** — `--u-primary-txt-color` 외.
|
|
34
|
+
`--u-txt-color-inverse` 는 다크에서 neutral-100(`#121212`)이라 유채색 버튼 위에서
|
|
35
|
+
읽히지 않는다. 브랜드 색을 바꾸는 소비자가 전경색도 함께 조절할 수 있도록 분리했다.
|
|
36
|
+
값은 두 테마 모두 `#FFFFFF` 이며 **현재 렌더는 바뀌지 않는다**(컴포넌트가 이미
|
|
37
|
+
리터럴 흰색을 쓰고 있었다).
|
|
38
|
+
|
|
39
|
+
### Known issues
|
|
40
|
+
|
|
41
|
+
- ★**라이트 팔레트의 shade-600 위에서 흰 글자가 AA 에 미달한다 — 8색 중 6색.**
|
|
42
|
+
`u-button[variant="solid"]` 이 그 조합이다. 실측(흰 글자 기준):
|
|
43
|
+
|
|
44
|
+
| 계열 | 라이트 shade-600 | 라이트 shade-700 | 다크 shade-600 |
|
|
45
|
+
|---|---|---|---|
|
|
46
|
+
| blue | 3.68 ✗ | 4.60 ✓ | 6.09 ✓ |
|
|
47
|
+
| green | 3.30 ✗ | 4.12 ✗ | 4.93 ✓ |
|
|
48
|
+
| red | 4.23 ✗ | 4.98 ✓ | 6.83 ✓ |
|
|
49
|
+
| orange | 2.37 ✗ | 2.70 ✗ | 5.34 ✓ |
|
|
50
|
+
| teal | 4.32 ✗ | 5.32 ✓ | 4.91 ✓ |
|
|
51
|
+
| cyan | 2.74 ✗ | 3.51 ✗ | 4.56 ✓ |
|
|
52
|
+
| purple | 7.04 ✓ | 8.20 ✓ | 6.03 ✓ |
|
|
53
|
+
| pink | 4.95 ✓ | 5.87 ✓ | 5.47 ✓ |
|
|
54
|
+
|
|
55
|
+
**다크는 8/8 통과**한다. 한 단 내리는 것(shade-700)으로는 3색만 해결되고 green·
|
|
56
|
+
orange·cyan 은 여전히 미달이라, **라이트 유채색 램프의 리터럴 재설계**가 필요하다.
|
|
57
|
+
위 `--u-txt-color-weak` 와 같은 성격이며 — 다크는 대비를 검증하며 만들어졌고 라이트는
|
|
58
|
+
그렇지 않다 — 범위가 훨씬 크다. 이번 릴리스에서는 고치지 않았다.
|
|
59
|
+
|
|
60
|
+
## [1.14.1] - 2026-08-01
|
|
61
|
+
|
|
62
|
+
### Fixed
|
|
63
|
+
|
|
64
|
+
- ★**Vite 플러그인 진입점이 게시본에 실려 있지 않던 문제 수정** —
|
|
65
|
+
`@iyulab/components/plugins/vite-plugin-react-wrapper.js` 를 임포트하는 소비 패키지의
|
|
66
|
+
**빌드가 실패**했다(`ERR_MODULE_NOT_FOUND`).
|
|
67
|
+
|
|
68
|
+
플러그인을 타입 검사 전용(`noEmit`)으로 바꾸면서 `.js` 산출물이 사라졌는데
|
|
69
|
+
`exports`·`files` 선언은 그대로 남아 있었다. **이 패키지 안에서는 아무 증상이 없다** —
|
|
70
|
+
로컬 빌드는 상대 경로로 `.ts` 소스를 직접 읽기 때문이다. 깨지는 곳은 게시본을 설치한
|
|
71
|
+
다른 패키지이고, 그것도 버전 범위가 새 버전을 잡을 때까지 잠복한다.
|
|
72
|
+
|
|
73
|
+
산출물을 **`dist/plugins/`** 로 내보내고 `exports` 가 그곳을 가리키게 했다.
|
|
74
|
+
**임포트 경로는 종전과 같다** — 소비 패키지는 변경할 것이 없다.
|
|
75
|
+
(산출물을 소스 옆이 아니라 `dist/` 밑에 두는 것은 의도적이다. 옆에 두면 확장자 없는
|
|
76
|
+
임포트가 컴파일본을 소스보다 먼저 잡아 로컬만 낡은 산출물을 쓰게 된다.)
|
|
77
|
+
|
|
78
|
+
`exports` 대상이 실재하는지 검사하는 테스트를 추가했다 — 게시 계약은 게시하는 쪽에서
|
|
79
|
+
확인해야 한다. 소비하는 쪽은 너무 늦게 안다.
|
|
80
|
+
|
|
3
81
|
## [1.14.0] - 2026-08-01
|
|
4
82
|
|
|
5
83
|
### Added
|
|
@@ -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 /* 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);\n --u-primary-color-strong: var(--u-blue-700);\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-700);\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);\n --u-danger-color-strong: var(--u-red-700);\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 --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\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-100);\n --u-txt-color-hover: var(--u-primary-color);\n --u-txt-color-active: var(--u-primary-color);\n --u-txt-color-disabled: var(--u-neutral-500);\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-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);\n --u-icon-color-active: var(--u-primary-color);\n --u-icon-color-disabled: var(--u-neutral-500);\n\n /* Border Colors */\n --u-border-color: var(--u-neutral-400);\n --u-border-color-weak: var(--u-neutral-300);\n --u-border-color-strong: var(--u-neutral-500);\n --u-border-color-hover: var(--u-neutral-500);\n\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);\n --u-input-border-color-invalid: var(--u-danger-color);\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 --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 /* 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 /* Font Styles */\n --u-font-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 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 /* 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);\n --u-primary-color-strong: var(--u-blue-700);\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-700);\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);\n --u-danger-color-strong: var(--u-red-700);\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 --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\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-100);\n\n /* 유채색 배경 위의 글자 — 두 테마 모두 흰색이다(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 --u-warning-txt-color: #FFFFFF;\n --u-txt-color-hover: var(--u-primary-color);\n --u-txt-color-active: var(--u-primary-color);\n --u-txt-color-disabled: var(--u-neutral-500);\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-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);\n --u-icon-color-active: var(--u-primary-color);\n --u-icon-color-disabled: var(--u-neutral-500);\n\n /* Border Colors */\n --u-border-color: var(--u-neutral-400);\n --u-border-color-weak: var(--u-neutral-300);\n --u-border-color-strong: var(--u-neutral-500);\n --u-border-color-hover: var(--u-neutral-500);\n\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);\n --u-input-border-color-invalid: var(--u-danger-color);\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 팔레트 유채색 틴트가 다크에서 짓눌리므로 한 단 위를 쓴다. 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\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 /* 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 /* Font Styles */\n --u-font-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 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}";
|
|
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 /* 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);\n --u-primary-color-strong: var(--u-blue-700);\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-700);\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);\n --u-danger-color-strong: var(--u-red-700);\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 --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\n /* Text Colors */\n --u-txt-color: var(--u-neutral-900);\n --u-txt-color-inverse: var(--u-neutral-0);\n --u-txt-color-hover: var(--u-primary-color);\n --u-txt-color-active: var(--u-primary-color);\n --u-txt-color-disabled: var(--u-neutral-400);\n --u-txt-color-weak: var(--u-neutral-500);\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);\n --u-icon-color-active: var(--u-primary-color);\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 --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);\n --u-input-border-color-invalid: var(--u-danger-color);\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 --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 /* 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 /* Font Styles */\n --u-font-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 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 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 /* 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);\n --u-primary-color-strong: var(--u-blue-700);\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-700);\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);\n --u-danger-color-strong: var(--u-red-700);\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 --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\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 --u-warning-txt-color: #FFFFFF;\n\n --u-txt-color-hover: var(--u-primary-color);\n --u-txt-color-active: var(--u-primary-color);\n --u-txt-color-disabled: var(--u-neutral-400);\n /* neutral-500(#9E9E9E)은 흰 배경 대비 2.68 로 WCAG AA(4.5) 미달이었다.\n neutral-600(#757575) = 4.61 로 통과한다. 다크 매핑(neutral-700 = 5.43)은\n 원래 정상이라 손대지 않는다 — 라이트 한쪽만의 결함이었다. */\n --u-txt-color-weak: var(--u-neutral-600);\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);\n --u-icon-color-active: var(--u-primary-color);\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 --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);\n --u-input-border-color-invalid: var(--u-danger-color);\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 역할 층의 유채색은 전경 5단뿐이라, 상태 배경이 필요한 컴포넌트는 팔레트를 직접\n 읽고 다크를 손으로 보정해야 했다. 팔레트의 유채색 틴트는 다크에서 짓눌리므로\n (바탕 대비 델타의 다크/라이트 비 — 청색 0.38~0.54) 두 테마가 **같은 단이 아니라\n 같은 세기**가 되도록 짝지었다. 실측 비: blue 1.09 · red 1.12 · green 0.91.\n ⚠yellow(경고)는 빠져 있다 — 라이트 황색 틴트가 Δ0.071 로 거의 보이지 않아\n 어떤 짝을 골라도 비가 2배 밑으로 내려가지 않는다. 리터럴 재설계가 선행돼야 한다. */\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\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 /* 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 /* Font Styles */\n --u-font-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, 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}";
|
|
3
3
|
//#endregion
|
|
4
4
|
export { light_css_default as default };
|
|
@@ -118,7 +118,7 @@ var styles = css`
|
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
.count {
|
|
121
|
-
color: var(--u-txt-color-weak, #
|
|
121
|
+
color: var(--u-txt-color-weak, #757575);
|
|
122
122
|
line-height: 1.25;
|
|
123
123
|
}
|
|
124
124
|
|
|
@@ -131,7 +131,7 @@ var styles = css`
|
|
|
131
131
|
text-overflow: ellipsis;
|
|
132
132
|
}
|
|
133
133
|
.text-content.placeholder {
|
|
134
|
-
color: var(--u-txt-color-weak, #
|
|
134
|
+
color: var(--u-txt-color-weak, #757575);
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
.chips-content {
|
|
@@ -183,7 +183,7 @@ var styles = css`
|
|
|
183
183
|
align-items: center;
|
|
184
184
|
gap: 0.4em;
|
|
185
185
|
padding: 0.3em 0.6em;
|
|
186
|
-
color: var(--u-txt-color-weak, #
|
|
186
|
+
color: var(--u-txt-color-weak, #757575);
|
|
187
187
|
border-bottom: 1px solid var(--u-border-color, #E0E0E0);
|
|
188
188
|
}
|
|
189
189
|
.search-input input {
|
|
@@ -193,7 +193,7 @@ var styles = css`
|
|
|
193
193
|
line-height: 1.5;
|
|
194
194
|
}
|
|
195
195
|
.search-input input::placeholder {
|
|
196
|
-
color: var(--u-txt-color-weak, #
|
|
196
|
+
color: var(--u-txt-color-weak, #757575);
|
|
197
197
|
}
|
|
198
198
|
`;
|
|
199
199
|
//#endregion
|
|
@@ -105,7 +105,7 @@ var styles = css`
|
|
|
105
105
|
.track-unchecked {
|
|
106
106
|
opacity: 1;
|
|
107
107
|
right: var(--switch-thumb-offset);
|
|
108
|
-
color: var(--u-txt-color-weak, #
|
|
108
|
+
color: var(--u-txt-color-weak, #757575);
|
|
109
109
|
}
|
|
110
110
|
:host([checked]) .track-unchecked {
|
|
111
111
|
opacity: 0;
|
|
@@ -163,7 +163,7 @@ var styles = css`
|
|
|
163
163
|
.thumb-unchecked {
|
|
164
164
|
opacity: 1;
|
|
165
165
|
transform: scale(1) rotate(0deg);
|
|
166
|
-
color: var(--u-txt-color-weak, #
|
|
166
|
+
color: var(--u-txt-color-weak, #757575);
|
|
167
167
|
}
|
|
168
168
|
:host([checked]) .thumb-unchecked {
|
|
169
169
|
opacity: 0;
|
|
@@ -182,7 +182,7 @@ var styles = css`
|
|
|
182
182
|
|
|
183
183
|
.description {
|
|
184
184
|
margin-top: 0.5em;
|
|
185
|
-
color: var(--u-txt-color-weak, #
|
|
185
|
+
color: var(--u-txt-color-weak, #757575);
|
|
186
186
|
font-size: 0.75em;
|
|
187
187
|
line-height: 1.3;
|
|
188
188
|
}
|
|
@@ -117,7 +117,7 @@ var styles = css`
|
|
|
117
117
|
word-wrap: break-word;
|
|
118
118
|
}
|
|
119
119
|
textarea::placeholder {
|
|
120
|
-
color: var(--u-txt-color-weak, #
|
|
120
|
+
color: var(--u-txt-color-weak, #757575);
|
|
121
121
|
}
|
|
122
122
|
textarea:disabled {
|
|
123
123
|
cursor: not-allowed;
|
|
@@ -155,7 +155,7 @@ var styles = css`
|
|
|
155
155
|
.counter {
|
|
156
156
|
margin-top: 0.25em;
|
|
157
157
|
text-align: right;
|
|
158
|
-
color: var(--u-txt-color-weak, #
|
|
158
|
+
color: var(--u-txt-color-weak, #757575);
|
|
159
159
|
font-size: 0.75em;
|
|
160
160
|
line-height: 1.2;
|
|
161
161
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Rolldown의 preserveModules 모드에서 import.meta.glob의 query 옵션 사용 시
|
|
4
|
+
* 빈 export가 생성되는 문제를 해결하는 플러그인.
|
|
5
|
+
*
|
|
6
|
+
* - `?raw`: 파일 내용을 문자열로 반환
|
|
7
|
+
* - `?inline`: 파일 내용을 문자열로 반환
|
|
8
|
+
* - `?url`: 파일을 asset으로 emit하고 URL을 반환
|
|
9
|
+
*
|
|
10
|
+
* 가상 모듈(\0 prefix)로 변환하여 파일명에 `?`가 포함되는 것을 방지합니다.
|
|
11
|
+
*/
|
|
12
|
+
export default function globResolve(): Plugin;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { resolve, dirname, basename } from 'path';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
|
+
const VIRTUAL_PREFIX = '\0glob-assets';
|
|
5
|
+
const SUPPORTED_QUERIES = ['?raw', '?inline', '?url'];
|
|
6
|
+
function shortHash(input) {
|
|
7
|
+
return createHash('md5').update(input).digest('hex').slice(0, 8);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Rolldown의 preserveModules 모드에서 import.meta.glob의 query 옵션 사용 시
|
|
11
|
+
* 빈 export가 생성되는 문제를 해결하는 플러그인.
|
|
12
|
+
*
|
|
13
|
+
* - `?raw`: 파일 내용을 문자열로 반환
|
|
14
|
+
* - `?inline`: 파일 내용을 문자열로 반환
|
|
15
|
+
* - `?url`: 파일을 asset으로 emit하고 URL을 반환
|
|
16
|
+
*
|
|
17
|
+
* 가상 모듈(\0 prefix)로 변환하여 파일명에 `?`가 포함되는 것을 방지합니다.
|
|
18
|
+
*/
|
|
19
|
+
export default function globResolve() {
|
|
20
|
+
const idToAbsPath = new Map();
|
|
21
|
+
return {
|
|
22
|
+
name: 'vite:glob-resolve',
|
|
23
|
+
enforce: 'pre',
|
|
24
|
+
resolveId(source, importer) {
|
|
25
|
+
for (const query of SUPPORTED_QUERIES) {
|
|
26
|
+
if (source.endsWith(query)) {
|
|
27
|
+
const rawPath = source.slice(0, -query.length);
|
|
28
|
+
const absPath = importer
|
|
29
|
+
? resolve(dirname(importer), rawPath)
|
|
30
|
+
: rawPath;
|
|
31
|
+
const name = basename(absPath);
|
|
32
|
+
const hash = shortHash(absPath);
|
|
33
|
+
const queryName = query.slice(1);
|
|
34
|
+
const virtualId = `${VIRTUAL_PREFIX}_${queryName}/${name}.${hash}`;
|
|
35
|
+
idToAbsPath.set(virtualId, absPath);
|
|
36
|
+
return virtualId;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
},
|
|
41
|
+
load(id) {
|
|
42
|
+
if (!id.startsWith(VIRTUAL_PREFIX))
|
|
43
|
+
return null;
|
|
44
|
+
const absPath = idToAbsPath.get(id);
|
|
45
|
+
if (!absPath)
|
|
46
|
+
return null;
|
|
47
|
+
// virtualId에서 queryName 추출: "\0glob-assets_{queryName}/..."
|
|
48
|
+
const queryName = id.slice(VIRTUAL_PREFIX.length + 1).split('/')[0];
|
|
49
|
+
if (queryName === 'raw' || queryName === 'inline') {
|
|
50
|
+
const content = readFileSync(absPath, 'utf-8');
|
|
51
|
+
return `export default ${JSON.stringify(content)};`;
|
|
52
|
+
}
|
|
53
|
+
if (queryName === 'url') {
|
|
54
|
+
const source = readFileSync(absPath);
|
|
55
|
+
const fileName = basename(absPath);
|
|
56
|
+
const ref = this.emitFile({
|
|
57
|
+
type: 'asset',
|
|
58
|
+
name: fileName,
|
|
59
|
+
source,
|
|
60
|
+
});
|
|
61
|
+
return `export default import.meta.ROLLUP_FILE_URL_${ref};`;
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { Plugin } from 'vite';
|
|
2
|
+
interface ComponentEvent {
|
|
3
|
+
name: string;
|
|
4
|
+
reactName: string;
|
|
5
|
+
detailType: string;
|
|
6
|
+
/**
|
|
7
|
+
* detail 타입 모듈의 **절대 소스 경로** (없으면 '').
|
|
8
|
+
*
|
|
9
|
+
* 상대 경로가 아니라 절대 경로인 이유: 이벤트는 상속 체인의 어느 파일에서든 선언될 수
|
|
10
|
+
* 있고, 그 파일의 import 경로는 **선언한 파일 기준**이다. 예를 들어
|
|
11
|
+
* `src/components/UOverlayElement.ts` 는 `../events/ShowEvent.js`(= `src/events/`)를
|
|
12
|
+
* 가리키는데, 이것을 상속받는 `src/components/dialog/UDialog.ts` 기준으로 풀면
|
|
13
|
+
* `src/components/events/`(존재하지 않음)가 된다. 수집 시점에 선언 파일 기준으로
|
|
14
|
+
* 절대화해 이 어긋남을 원천 차단한다.
|
|
15
|
+
*/
|
|
16
|
+
detailSource: string;
|
|
17
|
+
}
|
|
18
|
+
interface PluginOptions {
|
|
19
|
+
/** 컴포넌트 소스 디렉토리 경로 (기본값: 'src/components') */
|
|
20
|
+
input?: string;
|
|
21
|
+
/** React 래퍼 출력 폴더 - 빌드 outDir 기준 상대 경로 (기본값: 'react') */
|
|
22
|
+
output?: string;
|
|
23
|
+
/** 래퍼 생성에서 제외할 glob 패턴 목록 (cwd: 프로젝트 루트) */
|
|
24
|
+
exclude?: string[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Lit Element 컴포넌트를 React 래퍼로 자동 생성하는 Vite 플러그인
|
|
28
|
+
*/
|
|
29
|
+
export default function reactWrapperPlugin(options: PluginOptions): Plugin;
|
|
30
|
+
/**
|
|
31
|
+
* 이벤트가 **정적으로 수집되지 않는 형태**로 발화되는지 검사한다. 반환값이 비어 있지 않으면
|
|
32
|
+
* 빌드를 실패시킨다 — 누락된 이벤트는 React 소비자 쪽에서 에러도 경고도 없이 죽으므로
|
|
33
|
+
* 경고로 두면 아무도 알아채지 못한다.
|
|
34
|
+
*
|
|
35
|
+
* `content` 는 **leaf 파일 본문만**이다 — 베이스까지 훑으면 `UElement` 의 `fire`/`relay`
|
|
36
|
+
* 구현 자체가 걸려 전 컴포넌트가 위반이 된다. 베이스에서 발화하는 이벤트는 상속 수집
|
|
37
|
+
* ({@link collectComponentEvents})이 이미 채우므로 여기서 볼 필요가 없다.
|
|
38
|
+
*/
|
|
39
|
+
export declare function findEventDeclarationViolations(content: string, className: string, tagName: string, eventCount: number): string[];
|
|
40
|
+
/**
|
|
41
|
+
* 컴포넌트가 노출하는 이벤트를 **상속 체인 전체**에서 수집한다.
|
|
42
|
+
*
|
|
43
|
+
* leaf 파일만 읽으면 베이스 클래스가 발화하는 이벤트를 놓친다 — 예를 들어 `UDialog`·
|
|
44
|
+
* `UDrawer` 는 `show`/`hide` 를 **`UOverlayElement` 가** 발화하므로, leaf 만 보면
|
|
45
|
+
* `events: {}` 가 생성되고 React 소비자는 그 이벤트를 **구독할 방법이 없다**(에러도 경고도
|
|
46
|
+
* 없이 조용히 실패한다).
|
|
47
|
+
*
|
|
48
|
+
* 수집 순서는 **베이스 → leaf**다. `@event` 는 이름만 주고(detail=unknown) 기존 항목을
|
|
49
|
+
* 덮지 않는 반면 `this.fire<T>('name')` 은 타입까지 주며 덮으므로, 이 순서에서
|
|
50
|
+
* ⑴베이스의 타입 정보가 leaf 의 `@event` 재선언에 지워지지 않고
|
|
51
|
+
* ⑵leaf 가 같은 이벤트를 더 구체적 타입으로 발화하면 그것이 이긴다.
|
|
52
|
+
*/
|
|
53
|
+
export declare function collectComponentEvents(filePath: string): ComponentEvent[];
|
|
54
|
+
export {};
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { resolve, join, relative, dirname, basename } from 'path';
|
|
2
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
|
|
3
|
+
import { gzipSync } from 'zlib';
|
|
4
|
+
import { globSync } from 'glob';
|
|
5
|
+
/**
|
|
6
|
+
* Lit Element 컴포넌트를 React 래퍼로 자동 생성하는 Vite 플러그인
|
|
7
|
+
*/
|
|
8
|
+
export default function reactWrapperPlugin(options) {
|
|
9
|
+
let rootDir;
|
|
10
|
+
let buildOutDir;
|
|
11
|
+
let outDir;
|
|
12
|
+
return {
|
|
13
|
+
name: 'vite-plugin-react-wrapper',
|
|
14
|
+
configResolved(config) {
|
|
15
|
+
rootDir = config.root;
|
|
16
|
+
buildOutDir = resolve(rootDir, config.build.outDir);
|
|
17
|
+
outDir = resolve(buildOutDir, options.output || 'react');
|
|
18
|
+
},
|
|
19
|
+
closeBundle() {
|
|
20
|
+
const log = (msg) => console.log(`\x1b[36m[react-wrapper]\x1b[0m ${msg}`);
|
|
21
|
+
log('Generating React wrappers...');
|
|
22
|
+
// 컴포넌트 수집
|
|
23
|
+
const inputPattern = (options.input || 'src/components') + '/**/*.ts';
|
|
24
|
+
let files = globSync(inputPattern, { cwd: rootDir, absolute: true });
|
|
25
|
+
if (options.exclude?.length) {
|
|
26
|
+
const excluded = new Set(options.exclude.flatMap(p => globSync(p, { cwd: rootDir, absolute: true })));
|
|
27
|
+
files = files.filter((f) => !excluded.has(f));
|
|
28
|
+
}
|
|
29
|
+
// 이벤트 선언 누락은 **빌드를 실패**시킨다. 경고로 두면 사람 기억에 의존하게 되고,
|
|
30
|
+
// 누락된 이벤트는 React 소비자 쪽에서 에러 없이 조용히 죽는다 — 알아채기 가장 어려운
|
|
31
|
+
// 실패 형태다. 전 컴포넌트를 훑은 뒤 위반을 한 번에 보고한다.
|
|
32
|
+
const violations = [];
|
|
33
|
+
const components = files.flatMap((f) => parseComponent(f, violations));
|
|
34
|
+
if (violations.length > 0) {
|
|
35
|
+
throw new Error(`[react-wrapper] 이벤트 선언 누락 ${violations.length}건:\n` +
|
|
36
|
+
violations.map(v => ` - ${v}`).join('\n'));
|
|
37
|
+
}
|
|
38
|
+
if (components.length === 0) {
|
|
39
|
+
log('No components found.');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// 출력 디렉토리 생성
|
|
43
|
+
mkdirSync(outDir, { recursive: true });
|
|
44
|
+
// 래퍼 생성
|
|
45
|
+
const generated = [];
|
|
46
|
+
for (const comp of components) {
|
|
47
|
+
generated.push(...writeWrapper(comp, outDir, buildOutDir));
|
|
48
|
+
}
|
|
49
|
+
generated.push(...writeIndex(components, outDir, buildOutDir));
|
|
50
|
+
// 결과 출력
|
|
51
|
+
generated.sort((a, b) => a.size - b.size);
|
|
52
|
+
for (const f of generated) {
|
|
53
|
+
const kb = (f.size / 1024).toFixed(2);
|
|
54
|
+
const gzKb = (f.gzipSize / 1024).toFixed(2);
|
|
55
|
+
const pad = ' '.repeat(Math.max(0, 50 - f.path.length));
|
|
56
|
+
console.log(`${f.path}${pad}${kb.padStart(6)} kB │ gzip: ${gzKb.padStart(6)} kB`);
|
|
57
|
+
}
|
|
58
|
+
log(`Generated ${components.length} React wrappers.`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// --- 컴포넌트 파싱 ---
|
|
63
|
+
function parseComponent(filePath, violations = []) {
|
|
64
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
65
|
+
// @customElement('tag-name') 데코레이터 확인
|
|
66
|
+
const tagMatch = content.match(/@customElement\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
67
|
+
if (!tagMatch)
|
|
68
|
+
return [];
|
|
69
|
+
// export class ClassName 추출
|
|
70
|
+
const classMatch = content.match(/export\s+(?:abstract\s+)?class\s+(\w+)/);
|
|
71
|
+
if (!classMatch)
|
|
72
|
+
return [];
|
|
73
|
+
const events = collectComponentEvents(filePath);
|
|
74
|
+
violations.push(...findEventDeclarationViolations(content, classMatch[1], tagMatch[1], events.length));
|
|
75
|
+
return [{
|
|
76
|
+
className: classMatch[1],
|
|
77
|
+
tagName: tagMatch[1],
|
|
78
|
+
filePath,
|
|
79
|
+
events,
|
|
80
|
+
}];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 이벤트가 **정적으로 수집되지 않는 형태**로 발화되는지 검사한다. 반환값이 비어 있지 않으면
|
|
84
|
+
* 빌드를 실패시킨다 — 누락된 이벤트는 React 소비자 쪽에서 에러도 경고도 없이 죽으므로
|
|
85
|
+
* 경고로 두면 아무도 알아채지 못한다.
|
|
86
|
+
*
|
|
87
|
+
* `content` 는 **leaf 파일 본문만**이다 — 베이스까지 훑으면 `UElement` 의 `fire`/`relay`
|
|
88
|
+
* 구현 자체가 걸려 전 컴포넌트가 위반이 된다. 베이스에서 발화하는 이벤트는 상속 수집
|
|
89
|
+
* ({@link collectComponentEvents})이 이미 채우므로 여기서 볼 필요가 없다.
|
|
90
|
+
*/
|
|
91
|
+
export function findEventDeclarationViolations(content, className, tagName, eventCount) {
|
|
92
|
+
const violations = [];
|
|
93
|
+
// relay/dispatchEvent 는 이름을 정적으로 도출할 수 없다. @event 태그도 없으면
|
|
94
|
+
// events 맵이 빈 채로 생성되어 React 소비자가 구독할 방법이 사라진다.
|
|
95
|
+
if (eventCount === 0 && /this\.(relay|dispatchEvent)\s*\(/.test(content)) {
|
|
96
|
+
violations.push(`${className} (${tagName}): 이벤트를 발생시키지만(relay/dispatchEvent) @event 태그가 없어 ` +
|
|
97
|
+
`React 래퍼에 이벤트 prop이 노출되지 않습니다. 클래스 JSDoc에 '@event <name>'을 추가하세요.`);
|
|
98
|
+
}
|
|
99
|
+
// this.fire(변수) 처럼 이름이 리터럴이 아니면 역시 수집되지 않는다.
|
|
100
|
+
for (const m of content.matchAll(/this\.fire\s*(?:<[^>]+>)?\s*\(\s*([^'"\s)])/g)) {
|
|
101
|
+
violations.push(`${className} (${tagName}): this.fire(${m[1]}…) 의 이벤트명이 문자열 리터럴이 아니라 ` +
|
|
102
|
+
`정적으로 수집할 수 없습니다. 클래스 JSDoc에 '@event <name>'을 추가하세요.`);
|
|
103
|
+
}
|
|
104
|
+
return violations;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 컴포넌트가 노출하는 이벤트를 **상속 체인 전체**에서 수집한다.
|
|
108
|
+
*
|
|
109
|
+
* leaf 파일만 읽으면 베이스 클래스가 발화하는 이벤트를 놓친다 — 예를 들어 `UDialog`·
|
|
110
|
+
* `UDrawer` 는 `show`/`hide` 를 **`UOverlayElement` 가** 발화하므로, leaf 만 보면
|
|
111
|
+
* `events: {}` 가 생성되고 React 소비자는 그 이벤트를 **구독할 방법이 없다**(에러도 경고도
|
|
112
|
+
* 없이 조용히 실패한다).
|
|
113
|
+
*
|
|
114
|
+
* 수집 순서는 **베이스 → leaf**다. `@event` 는 이름만 주고(detail=unknown) 기존 항목을
|
|
115
|
+
* 덮지 않는 반면 `this.fire<T>('name')` 은 타입까지 주며 덮으므로, 이 순서에서
|
|
116
|
+
* ⑴베이스의 타입 정보가 leaf 의 `@event` 재선언에 지워지지 않고
|
|
117
|
+
* ⑵leaf 가 같은 이벤트를 더 구체적 타입으로 발화하면 그것이 이긴다.
|
|
118
|
+
*/
|
|
119
|
+
export function collectComponentEvents(filePath) {
|
|
120
|
+
const eventMap = new Map();
|
|
121
|
+
collectInto(eventMap, filePath, new Set());
|
|
122
|
+
return Array.from(eventMap, ([name, { detailType, detailSource }]) => ({
|
|
123
|
+
name,
|
|
124
|
+
reactName: toCamelEvent(name),
|
|
125
|
+
detailType,
|
|
126
|
+
detailSource,
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
function collectInto(eventMap, filePath, visited) {
|
|
130
|
+
if (visited.has(filePath) || !existsSync(filePath))
|
|
131
|
+
return; // 순환 상속/누락 파일 방어
|
|
132
|
+
visited.add(filePath);
|
|
133
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
134
|
+
// import 구문에서 식별자 → 소스 경로 매핑 수집 (detail 타입과 베이스 클래스 양쪽에 쓴다)
|
|
135
|
+
// 예: import { ShowEventDetail } from '../events/ShowEvent.js';
|
|
136
|
+
const importMap = new Map();
|
|
137
|
+
for (const m of content.matchAll(/import\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g)) {
|
|
138
|
+
const importPath = m[2];
|
|
139
|
+
for (const name of m[1].split(',')) {
|
|
140
|
+
const typeName = name.replace(/type\s+/, '').trim();
|
|
141
|
+
if (typeName)
|
|
142
|
+
importMap.set(typeName, importPath);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// 베이스 클래스를 먼저 수집한다 (제네릭 베이스 `extends UFormControlElement<T>` 포함)
|
|
146
|
+
const extendsMatch = content.match(/export\s+(?:abstract\s+)?class\s+\w+(?:<[^>]*>)?\s+extends\s+(\w+)/);
|
|
147
|
+
if (extendsMatch) {
|
|
148
|
+
const basePath = resolveLocalModule(filePath, importMap.get(extendsMatch[1]));
|
|
149
|
+
if (basePath)
|
|
150
|
+
collectInto(eventMap, basePath, visited);
|
|
151
|
+
}
|
|
152
|
+
// JSDoc @event 패턴: @event eventName — 이름만 제공하므로 기존 항목을 덮지 않는다
|
|
153
|
+
for (const m of content.matchAll(/@event\s+([\w-]+)/g)) {
|
|
154
|
+
if (!eventMap.has(m[1]))
|
|
155
|
+
eventMap.set(m[1], { detailType: 'unknown', detailSource: '' });
|
|
156
|
+
}
|
|
157
|
+
// this.fire<DetailType>('eventName') 패턴 - 제네릭 타입 추출
|
|
158
|
+
for (const m of content.matchAll(/this\.fire\s*(?:<([^>]+)>)?\s*\(\s*['"]([\w-]+)['"]/g)) {
|
|
159
|
+
const detailType = m[1] || 'unknown';
|
|
160
|
+
const detailSource = resolveLocalModule(filePath, importMap.get(detailType)) || '';
|
|
161
|
+
eventMap.set(m[2], { detailType, detailSource });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/** 같은 패키지 소스 안의 상대 import 를 절대 `.ts` 경로로 해석한다 (외부 모듈이면 null) */
|
|
165
|
+
function resolveLocalModule(fromFile, importPath) {
|
|
166
|
+
if (!importPath || !importPath.startsWith('.'))
|
|
167
|
+
return null;
|
|
168
|
+
const abs = resolve(dirname(fromFile), importPath.replace(/\.js$/, '.ts'));
|
|
169
|
+
return existsSync(abs) ? abs : null;
|
|
170
|
+
}
|
|
171
|
+
/** kebab-case 이벤트명을 onCamelCase로 변환 (예: shift-start → onShiftStart) */
|
|
172
|
+
function toCamelEvent(name) {
|
|
173
|
+
return 'on' + name.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join('');
|
|
174
|
+
}
|
|
175
|
+
function writeFile(filePath, content, buildOutDir) {
|
|
176
|
+
writeFileSync(filePath, content, 'utf-8');
|
|
177
|
+
return {
|
|
178
|
+
path: relative(buildOutDir, filePath).replace(/\\/g, '/'),
|
|
179
|
+
size: Buffer.byteLength(content, 'utf-8'),
|
|
180
|
+
gzipSize: gzipSync(content).length,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
function computeImportPath(from, to) {
|
|
184
|
+
let rel = relative(dirname(from), to).replace(/\\/g, '/').replace(/\.ts$/, '');
|
|
185
|
+
if (!rel.startsWith('.'))
|
|
186
|
+
rel = './' + rel;
|
|
187
|
+
return rel;
|
|
188
|
+
}
|
|
189
|
+
function writeWrapper(comp, outDir, buildOutDir) {
|
|
190
|
+
const { className, tagName, events } = comp;
|
|
191
|
+
const jsPath = join(outDir, `${className}.js`);
|
|
192
|
+
const dtsPath = join(outDir, `${className}.d.ts`);
|
|
193
|
+
// 소스 파일의 빌드 출력 경로 추정 (src/ → 빌드 outDir 매핑)
|
|
194
|
+
const srcIndex = comp.filePath.replace(/\\/g, '/').indexOf('/src/');
|
|
195
|
+
const relFromSrc = srcIndex >= 0
|
|
196
|
+
? comp.filePath.substring(srcIndex + 5).replace(/\\/g, '/').replace(/\.ts$/, '')
|
|
197
|
+
: basename(comp.filePath, '.ts');
|
|
198
|
+
const builtModulePath = resolve(buildOutDir, relFromSrc + '.js');
|
|
199
|
+
const importPath = computeImportPath(jsPath, builtModulePath);
|
|
200
|
+
// events 객체 생성
|
|
201
|
+
const eventsObj = events.length > 0
|
|
202
|
+
? `{\n${events.map(e => ` ${e.reactName}: '${e.name}',`).join('\n')}\n }`
|
|
203
|
+
: '{}';
|
|
204
|
+
// .js
|
|
205
|
+
const js = `import React from 'react';
|
|
206
|
+
import { createComponent } from '@lit/react';
|
|
207
|
+
import { ${className} as ${className}Element } from '${importPath}';
|
|
208
|
+
|
|
209
|
+
export const ${className} = createComponent({
|
|
210
|
+
react: React,
|
|
211
|
+
tagName: '${tagName}',
|
|
212
|
+
elementClass: ${className}Element,
|
|
213
|
+
events: ${eventsObj},
|
|
214
|
+
});
|
|
215
|
+
`;
|
|
216
|
+
// .d.ts - import 구문 생성
|
|
217
|
+
const dtsImportPath = importPath.replace(/\.js$/, '');
|
|
218
|
+
const dtsImports = [
|
|
219
|
+
`import React from 'react';`,
|
|
220
|
+
`import { ${className} as ${className}Element } from '${dtsImportPath}';`,
|
|
221
|
+
];
|
|
222
|
+
// 이벤트 detail 타입별 import - 소스 원본 경로 기준으로 빌드 경로 계산.
|
|
223
|
+
// detailSource 는 **선언한 파일 기준으로 이미 절대화**돼 있다(상속받은 이벤트의 경로가
|
|
224
|
+
// leaf 기준으로 잘못 풀리는 것을 막기 위함 — ComponentEvent.detailSource 주석 참조).
|
|
225
|
+
const detailImportMap = new Map(); // 빌드경로 → [타입명]
|
|
226
|
+
for (const e of events) {
|
|
227
|
+
if (e.detailType === 'unknown' || !e.detailSource)
|
|
228
|
+
continue;
|
|
229
|
+
const absEventSrc = e.detailSource.replace(/\\/g, '/');
|
|
230
|
+
const eventSrcIndex = absEventSrc.indexOf('/src/');
|
|
231
|
+
const relFromSrc = eventSrcIndex >= 0
|
|
232
|
+
? absEventSrc.substring(eventSrcIndex + 5).replace(/\.ts$/, '')
|
|
233
|
+
: '';
|
|
234
|
+
if (!relFromSrc)
|
|
235
|
+
continue;
|
|
236
|
+
const absEventBuilt = resolve(buildOutDir, relFromSrc);
|
|
237
|
+
const eventImportPath = computeImportPath(dtsPath, absEventBuilt + '.js').replace(/\.js$/, '');
|
|
238
|
+
const types = detailImportMap.get(eventImportPath) || [];
|
|
239
|
+
if (!types.includes(e.detailType))
|
|
240
|
+
types.push(e.detailType);
|
|
241
|
+
detailImportMap.set(eventImportPath, types);
|
|
242
|
+
}
|
|
243
|
+
for (const [path, types] of detailImportMap) {
|
|
244
|
+
dtsImports.push(`import { type ${types.join(', type ')} } from '${path}';`);
|
|
245
|
+
}
|
|
246
|
+
const eventTypes = events.length > 0
|
|
247
|
+
? events.map(e => {
|
|
248
|
+
const type = e.detailType !== 'unknown' ? `CustomEvent<${e.detailType}>` : 'CustomEvent';
|
|
249
|
+
return ` ${e.reactName}?: (event: ${type}) => void;`;
|
|
250
|
+
}).join('\n') + '\n'
|
|
251
|
+
: '';
|
|
252
|
+
// 래퍼 이벤트 prop(onChange 등)은 React.HTMLAttributes 의 동명 핸들러와 교집합되면
|
|
253
|
+
// 어떤 시그니처도 대입 불가가 된다. HTMLAttributes 쪽에서 해당 키를 제거해 CustomEvent
|
|
254
|
+
// 시그니처만 남긴다. 이벤트가 없으면 Omit<…, never> 로 HTMLAttributes 원형 유지.
|
|
255
|
+
const eventKeyUnion = events.length > 0
|
|
256
|
+
? events.map(e => `'${e.reactName}'`).join(' | ')
|
|
257
|
+
: 'never';
|
|
258
|
+
// Partial<Element> 은 DOM 프로퍼티(children: HTMLCollection 등)를 포함해 React 의 JSX
|
|
259
|
+
// children/이벤트/className 등과 충돌한다. keyof React.HTMLAttributes 를 제거해 컴포넌트
|
|
260
|
+
// 고유 prop만 남기고, React 친화 타입(children: ReactNode 포함)은 HTMLAttributes 가 제공한다.
|
|
261
|
+
//
|
|
262
|
+
// `React.RefAttributes` 를 반드시 교집합에 넣는다 — `ForwardRefExoticComponent<P>` 는 P 에
|
|
263
|
+
// ref 를 자동으로 더해 주지 않는다. @lit/react 의 `ReactWebComponent` 자신이
|
|
264
|
+
// `PropsWithoutRef<…> & React.RefAttributes<I>` 로 선언돼 있으므로(런타임은 ref 를 전달한다),
|
|
265
|
+
// 이것을 빠뜨리면 **런타임은 되는데 타입만 거부하는** 괴리가 생긴다.
|
|
266
|
+
const dts = `${dtsImports.join('\n')}
|
|
267
|
+
|
|
268
|
+
export declare const ${className}: React.ForwardRefExoticComponent<
|
|
269
|
+
Omit<Partial<${className}Element>, keyof React.HTMLAttributes<${className}Element>>
|
|
270
|
+
& Omit<React.HTMLAttributes<${className}Element>, ${eventKeyUnion}>
|
|
271
|
+
& React.RefAttributes<${className}Element>
|
|
272
|
+
& {
|
|
273
|
+
${eventTypes} }
|
|
274
|
+
>;
|
|
275
|
+
|
|
276
|
+
export type ${className}Props = React.ComponentProps<typeof ${className}>;
|
|
277
|
+
`;
|
|
278
|
+
return [
|
|
279
|
+
writeFile(jsPath, js, buildOutDir),
|
|
280
|
+
writeFile(dtsPath, dts, buildOutDir),
|
|
281
|
+
];
|
|
282
|
+
}
|
|
283
|
+
function writeIndex(components, outDir, buildOutDir) {
|
|
284
|
+
const jsExports = components
|
|
285
|
+
.map(c => `export { ${c.className} } from './${c.className}.js';`)
|
|
286
|
+
.join('\n');
|
|
287
|
+
const dtsExports = components
|
|
288
|
+
.map(c => `export { ${c.className}, ${c.className}Props } from './${c.className}';`)
|
|
289
|
+
.join('\n');
|
|
290
|
+
return [
|
|
291
|
+
writeFile(join(outDir, 'index.js'), jsExports + '\n', buildOutDir),
|
|
292
|
+
writeFile(join(outDir, 'index.d.ts'), dtsExports + '\n', buildOutDir),
|
|
293
|
+
];
|
|
294
|
+
}
|
package/dist/styles/dark.css
CHANGED
|
@@ -205,6 +205,13 @@
|
|
|
205
205
|
/* Text Colors */
|
|
206
206
|
--u-txt-color: var(--u-neutral-900);
|
|
207
207
|
--u-txt-color-inverse: var(--u-neutral-100);
|
|
208
|
+
|
|
209
|
+
/* 유채색 배경 위의 글자 — 두 테마 모두 흰색이다(light.css 참조). */
|
|
210
|
+
--u-primary-txt-color: #FFFFFF;
|
|
211
|
+
--u-info-txt-color: #FFFFFF;
|
|
212
|
+
--u-success-txt-color: #FFFFFF;
|
|
213
|
+
--u-danger-txt-color: #FFFFFF;
|
|
214
|
+
--u-warning-txt-color: #FFFFFF;
|
|
208
215
|
--u-txt-color-hover: var(--u-primary-color);
|
|
209
216
|
--u-txt-color-active: var(--u-primary-color);
|
|
210
217
|
--u-txt-color-disabled: var(--u-neutral-500);
|
|
@@ -239,6 +246,13 @@
|
|
|
239
246
|
--u-bg-color-active: var(--u-neutral-400);
|
|
240
247
|
--u-bg-color-disabled: var(--u-neutral-100);
|
|
241
248
|
|
|
249
|
+
/* 유채색 표면 — 라이트와 **같은 단이 아니라 같은 세기**로 짝지었다(light.css 참조).
|
|
250
|
+
팔레트 유채색 틴트가 다크에서 짓눌리므로 한 단 위를 쓴다. green 은 대칭이라 그대로. */
|
|
251
|
+
--u-primary-bg-color: var(--u-blue-100);
|
|
252
|
+
--u-info-bg-color: var(--u-blue-100);
|
|
253
|
+
--u-success-bg-color: var(--u-green-0);
|
|
254
|
+
--u-danger-bg-color: var(--u-red-100);
|
|
255
|
+
|
|
242
256
|
--u-input-bg-color: var(--u-neutral-200);
|
|
243
257
|
--u-panel-bg-color: var(--u-neutral-200);
|
|
244
258
|
--u-overlay-bg-color: rgba(0, 0, 0, 0.7);
|
package/dist/styles/light.css
CHANGED
|
@@ -206,10 +206,24 @@
|
|
|
206
206
|
/* Text Colors */
|
|
207
207
|
--u-txt-color: var(--u-neutral-900);
|
|
208
208
|
--u-txt-color-inverse: var(--u-neutral-0);
|
|
209
|
+
/* 유채색 배경 위의 글자. --u-txt-color-inverse 는 다크에서 neutral-100(#121212)이라
|
|
210
|
+
유채색 버튼 위에서 읽히지 않는다. 브랜드 색을 바꾸는 소비자가 전경색도 함께
|
|
211
|
+
조절할 수 있도록 별도 이름을 준다.
|
|
212
|
+
⚠이 토큰이 흰색이라는 것과 그 위의 배경이 AA 를 받친다는 것은 별개다 —
|
|
213
|
+
라이트 팔레트의 shade-600 은 8색 중 6색이 흰 글자로 AA 에 미달한다(미해결). */
|
|
214
|
+
--u-primary-txt-color: #FFFFFF;
|
|
215
|
+
--u-info-txt-color: #FFFFFF;
|
|
216
|
+
--u-success-txt-color: #FFFFFF;
|
|
217
|
+
--u-danger-txt-color: #FFFFFF;
|
|
218
|
+
--u-warning-txt-color: #FFFFFF;
|
|
219
|
+
|
|
209
220
|
--u-txt-color-hover: var(--u-primary-color);
|
|
210
221
|
--u-txt-color-active: var(--u-primary-color);
|
|
211
222
|
--u-txt-color-disabled: var(--u-neutral-400);
|
|
212
|
-
|
|
223
|
+
/* neutral-500(#9E9E9E)은 흰 배경 대비 2.68 로 WCAG AA(4.5) 미달이었다.
|
|
224
|
+
neutral-600(#757575) = 4.61 로 통과한다. 다크 매핑(neutral-700 = 5.43)은
|
|
225
|
+
원래 정상이라 손대지 않는다 — 라이트 한쪽만의 결함이었다. */
|
|
226
|
+
--u-txt-color-weak: var(--u-neutral-600);
|
|
213
227
|
--u-txt-color-strong: var(--u-neutral-1000);
|
|
214
228
|
|
|
215
229
|
--u-link-txt-color: var(--u-primary-color-strong);
|
|
@@ -240,6 +254,18 @@
|
|
|
240
254
|
--u-bg-color-active: var(--u-neutral-200);
|
|
241
255
|
--u-bg-color-disabled: var(--u-neutral-50);
|
|
242
256
|
|
|
257
|
+
/* 유채색 표면 — 정보/성공/위험 상태의 '면'.
|
|
258
|
+
역할 층의 유채색은 전경 5단뿐이라, 상태 배경이 필요한 컴포넌트는 팔레트를 직접
|
|
259
|
+
읽고 다크를 손으로 보정해야 했다. 팔레트의 유채색 틴트는 다크에서 짓눌리므로
|
|
260
|
+
(바탕 대비 델타의 다크/라이트 비 — 청색 0.38~0.54) 두 테마가 **같은 단이 아니라
|
|
261
|
+
같은 세기**가 되도록 짝지었다. 실측 비: blue 1.09 · red 1.12 · green 0.91.
|
|
262
|
+
⚠yellow(경고)는 빠져 있다 — 라이트 황색 틴트가 Δ0.071 로 거의 보이지 않아
|
|
263
|
+
어떤 짝을 골라도 비가 2배 밑으로 내려가지 않는다. 리터럴 재설계가 선행돼야 한다. */
|
|
264
|
+
--u-primary-bg-color: var(--u-blue-0);
|
|
265
|
+
--u-info-bg-color: var(--u-blue-0);
|
|
266
|
+
--u-success-bg-color: var(--u-green-0);
|
|
267
|
+
--u-danger-bg-color: var(--u-red-0);
|
|
268
|
+
|
|
243
269
|
--u-input-bg-color: var(--u-neutral-0);
|
|
244
270
|
--u-panel-bg-color: var(--u-neutral-0);
|
|
245
271
|
--u-overlay-bg-color: rgba(0, 0, 0, 0.5);
|
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.
|
|
4
|
+
"version": "1.15.0",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iyulab",
|
|
7
7
|
"components",
|
|
@@ -18,8 +18,6 @@
|
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
20
|
"skills",
|
|
21
|
-
"plugins/**/*.js",
|
|
22
|
-
"plugins/**/*.d.ts",
|
|
23
21
|
"package.json",
|
|
24
22
|
"README.md",
|
|
25
23
|
"CHANGELOG.md",
|
|
@@ -36,7 +34,7 @@
|
|
|
36
34
|
"./react": "./dist/react/index.js",
|
|
37
35
|
"./react/*": "./dist/react/*",
|
|
38
36
|
"./styles/*": "./dist/styles/*",
|
|
39
|
-
"./plugins/*": "./plugins/*"
|
|
37
|
+
"./plugins/*": "./dist/plugins/*"
|
|
40
38
|
},
|
|
41
39
|
"scripts": {
|
|
42
40
|
"start": "vite --force",
|
|
@@ -44,12 +42,13 @@
|
|
|
44
42
|
"test:browser": "vitest run --project=browser",
|
|
45
43
|
"lint": "eslint src/",
|
|
46
44
|
"lint:fix": "eslint src/ --fix",
|
|
47
|
-
"build": "eslint && npm run typecheck:plugins && vite build && npm run test:react-types",
|
|
45
|
+
"build": "eslint && npm run typecheck:plugins && vite build && npm run build:plugins && npm run test:react-types",
|
|
48
46
|
"test:react-types": "tsc -p tsconfig.react-smoke.json",
|
|
49
47
|
"typecheck:plugins": "tsc -p plugins/tsconfig.json",
|
|
50
48
|
"docs:cssprops": "node scripts/cssprops-doc.mjs --write",
|
|
51
49
|
"docs:react-events": "node scripts/react-events-doc.mjs --write",
|
|
52
|
-
"docs:tokens": "node scripts/design-tokens-doc.mjs --write"
|
|
50
|
+
"docs:tokens": "node scripts/design-tokens-doc.mjs --write",
|
|
51
|
+
"build:plugins": "tsc -p plugins/tsconfig.build.json"
|
|
53
52
|
},
|
|
54
53
|
"dependencies": {
|
|
55
54
|
"@floating-ui/dom": "^1.8.0",
|