sh-ui-cli 0.59.2 → 0.59.4
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/data/changelog/versions.json +28 -0
- package/data/registry/react/components/card/styles.css +16 -0
- package/data/registry/react/components/card/styles.module.css +14 -0
- package/data/registry/react/components/checkbox/styles.css +20 -0
- package/data/registry/react/components/checkbox/styles.module.css +20 -0
- package/data/registry/react/components/radio/styles.css +22 -0
- package/data/registry/react/components/radio/styles.module.css +22 -0
- package/data/registry/react/components/switch/styles.css +27 -0
- package/data/registry/react/components/switch/styles.module.css +27 -0
- package/data/registry/react/components/tabs/styles.css +24 -0
- package/data/registry/react/components/tabs/styles.module.css +24 -0
- package/data/registry/react/components/toggle/styles.css +16 -0
- package/data/registry/react/components/toggle/styles.module.css +16 -0
- package/package.json +1 -1
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$description": "sh-ui 릴리즈 노트 단일 소스. docs(React)와 showcase(Flutter)가 함께 읽는다. 새 릴리즈마다 맨 앞에 추가.",
|
|
4
4
|
"versions": [
|
|
5
|
+
{
|
|
6
|
+
"version": "0.59.4",
|
|
7
|
+
"date": "2026-05-06",
|
|
8
|
+
"title": "접근성 라운드 4 — forced-colors 모드 (Windows High Contrast)",
|
|
9
|
+
"type": "patch",
|
|
10
|
+
"highlights": [
|
|
11
|
+
"**`@media (forced-colors: active)` 블록 추가** — Windows 고대비 / Edge 강제 색 모드에서 시스템 컬러 (Highlight, ButtonBorder, ButtonText, GrayText) 로 폴백. 사용자가 색 토큰을 OS 색상에 강제 매핑해도 컴포넌트 상태 (checked/pressed/active) 가 시각적으로 구별됨.",
|
|
12
|
+
"**대상 컴포넌트** — `Checkbox` / `Radio` (checked indicator) / `Switch` (on/off thumb + track) / `Tabs` (active indicator + selected color) / `Toggle` (pressed background+border).",
|
|
13
|
+
"**문제 원인** — 기존 디자인이 `background: var(--primary)` 만으로 active 상태를 표현. 강제 색 모드에서 `--primary` 가 시스템 `Canvas`/`ButtonFace` 로 덮이면 unchecked 와 동일하게 보여 구별 불가. 이제 `Highlight` (selection color) 로 명시 폴백.",
|
|
14
|
+
"**3 variant 동기화** — registry/react plain CSS + CSS Modules + apps/docs. Tailwind variant 는 별도 라운드 (forced-colors: 모디파이어 필요).",
|
|
15
|
+
"**일반 사용자 영향 0** — forced-colors 미활성 시 룰 무시. 활성 시에만 시스템 색이 우선되며 디자인 토큰을 덮어씀."
|
|
16
|
+
],
|
|
17
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.59.4"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"version": "0.59.3",
|
|
21
|
+
"date": "2026-05-06",
|
|
22
|
+
"title": "접근성 라운드 3 — Card container queries (자기 너비 기준 반응형)",
|
|
23
|
+
"type": "patch",
|
|
24
|
+
"highlights": [
|
|
25
|
+
"**`Card` 가 `container-type: inline-size` 로 컨테이너 컨텍스트 생성** — 자신의 width 기준으로 sub-element padding 조정 가능.",
|
|
26
|
+
"**`@container (max-width: 20rem)` 블록 추가** — Card 자체 너비가 320px 이하일 때 gap/padding 자동 축소 (`--space-6 → --space-4`). viewport 가 아닌 **부모 컨테이너** 기준이라 좁은 사이드바·column 안에 Card 가 들어가도 자연스럽게.",
|
|
27
|
+
"**기존 `max-sm:` viewport 룰과 별개로 동작** — 둘 다 fire 해도 같은 값이라 충돌 없음. 모바일 viewport + 어떤 width 든 / 데스크탑 viewport + 좁은 column 등 모두 커버.",
|
|
28
|
+
"**3 variant 동기화** — plain CSS / CSS Modules / apps/docs. Tailwind variant 는 `container-type` 이 inline class 로 표현 어려워 plain CSS 위주.",
|
|
29
|
+
"**Sidebar 등 다른 컴포넌트로 확장**: 사용자 요청 시 추가 라운드 가능. Card 가 가장 명확한 win 이라 우선 적용."
|
|
30
|
+
],
|
|
31
|
+
"url": "https://github.com/sanghyeonKim0201/sh-ui/releases/tag/v0.59.3"
|
|
32
|
+
},
|
|
5
33
|
{
|
|
6
34
|
"version": "0.59.2",
|
|
7
35
|
"date": "2026-05-06",
|
|
@@ -8,6 +8,22 @@
|
|
|
8
8
|
border: 1px solid var(--border);
|
|
9
9
|
border-radius: var(--radius);
|
|
10
10
|
box-shadow: var(--shadow-sm);
|
|
11
|
+
/* 자기 너비 기준으로 sub-element padding 조정. */
|
|
12
|
+
container-type: inline-size;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Card 자체 너비가 좁을 때 padding 자동 축소.
|
|
16
|
+
* viewport 기반 max-sm 과 별개로 — 어떤 viewport 든 Card 자체가 좁으면 적용. */
|
|
17
|
+
@container (max-width: 20rem) {
|
|
18
|
+
.sh-ui-card {
|
|
19
|
+
gap: var(--space-4);
|
|
20
|
+
padding: var(--space-4) 0;
|
|
21
|
+
}
|
|
22
|
+
.sh-ui-card__header,
|
|
23
|
+
.sh-ui-card__content,
|
|
24
|
+
.sh-ui-card__footer {
|
|
25
|
+
padding-inline: var(--space-4);
|
|
26
|
+
}
|
|
11
27
|
}
|
|
12
28
|
|
|
13
29
|
/* 헤더: 기본은 타이틀/설명 세로 스택. action 있으면 2열 그리드로 전환. */
|
|
@@ -8,6 +8,20 @@
|
|
|
8
8
|
border: 1px solid var(--border);
|
|
9
9
|
border-radius: var(--radius);
|
|
10
10
|
box-shadow: var(--shadow-sm);
|
|
11
|
+
container-type: inline-size;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* Card 자체 너비가 좁을 때 padding 자동 축소. */
|
|
15
|
+
@container (max-width: 20rem) {
|
|
16
|
+
.card {
|
|
17
|
+
gap: var(--space-4);
|
|
18
|
+
padding: var(--space-4) 0;
|
|
19
|
+
}
|
|
20
|
+
.header,
|
|
21
|
+
.content,
|
|
22
|
+
.footer {
|
|
23
|
+
padding-inline: var(--space-4);
|
|
24
|
+
}
|
|
11
25
|
}
|
|
12
26
|
|
|
13
27
|
/* 헤더: 기본은 타이틀/설명 세로 스택. action 있으면 2열 그리드로 전환. */
|
|
@@ -73,3 +73,23 @@
|
|
|
73
73
|
transition: none;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
/* Windows 고대비 모드: 색만으로 표시되는 checked 상태가 시스템 색에 덮여 사라지는 걸 방지. */
|
|
78
|
+
@media (forced-colors: active) {
|
|
79
|
+
.sh-ui-checkbox {
|
|
80
|
+
border-color: ButtonBorder;
|
|
81
|
+
}
|
|
82
|
+
.sh-ui-checkbox[data-checked],
|
|
83
|
+
.sh-ui-checkbox[data-indeterminate] {
|
|
84
|
+
background: Highlight;
|
|
85
|
+
border-color: Highlight;
|
|
86
|
+
color: HighlightText;
|
|
87
|
+
}
|
|
88
|
+
.sh-ui-checkbox:focus-visible {
|
|
89
|
+
outline-color: Highlight;
|
|
90
|
+
}
|
|
91
|
+
.sh-ui-checkbox[data-disabled] {
|
|
92
|
+
border-color: GrayText;
|
|
93
|
+
color: GrayText;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -73,3 +73,23 @@
|
|
|
73
73
|
transition: none;
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
/* Windows 고대비 모드: 색만으로 표시되는 checked 상태가 시스템 색에 덮여 사라지는 걸 방지. */
|
|
78
|
+
@media (forced-colors: active) {
|
|
79
|
+
.checkbox {
|
|
80
|
+
border-color: ButtonBorder;
|
|
81
|
+
}
|
|
82
|
+
.checkbox[data-checked],
|
|
83
|
+
.checkbox[data-indeterminate] {
|
|
84
|
+
background: Highlight;
|
|
85
|
+
border-color: Highlight;
|
|
86
|
+
color: HighlightText;
|
|
87
|
+
}
|
|
88
|
+
.checkbox:focus-visible {
|
|
89
|
+
outline-color: Highlight;
|
|
90
|
+
}
|
|
91
|
+
.checkbox[data-disabled] {
|
|
92
|
+
border-color: GrayText;
|
|
93
|
+
color: GrayText;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -78,3 +78,25 @@
|
|
|
78
78
|
transition: none;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
/* Windows 고대비 모드. */
|
|
83
|
+
@media (forced-colors: active) {
|
|
84
|
+
.sh-ui-radio {
|
|
85
|
+
border-color: ButtonBorder;
|
|
86
|
+
}
|
|
87
|
+
.sh-ui-radio[data-checked] {
|
|
88
|
+
border-color: Highlight;
|
|
89
|
+
}
|
|
90
|
+
.sh-ui-radio__indicator {
|
|
91
|
+
background: Highlight;
|
|
92
|
+
}
|
|
93
|
+
.sh-ui-radio:focus-visible {
|
|
94
|
+
outline-color: Highlight;
|
|
95
|
+
}
|
|
96
|
+
.sh-ui-radio[data-disabled] {
|
|
97
|
+
border-color: GrayText;
|
|
98
|
+
}
|
|
99
|
+
.sh-ui-radio[data-disabled] .sh-ui-radio__indicator {
|
|
100
|
+
background: GrayText;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -78,3 +78,25 @@
|
|
|
78
78
|
transition: none;
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
|
|
82
|
+
/* Windows 고대비 모드. */
|
|
83
|
+
@media (forced-colors: active) {
|
|
84
|
+
.radio {
|
|
85
|
+
border-color: ButtonBorder;
|
|
86
|
+
}
|
|
87
|
+
.radio[data-checked] {
|
|
88
|
+
border-color: Highlight;
|
|
89
|
+
}
|
|
90
|
+
.radio__indicator {
|
|
91
|
+
background: Highlight;
|
|
92
|
+
}
|
|
93
|
+
.radio:focus-visible {
|
|
94
|
+
outline-color: Highlight;
|
|
95
|
+
}
|
|
96
|
+
.radio[data-disabled] {
|
|
97
|
+
border-color: GrayText;
|
|
98
|
+
}
|
|
99
|
+
.radio[data-disabled] .radio__indicator {
|
|
100
|
+
background: GrayText;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -81,3 +81,30 @@
|
|
|
81
81
|
transition-duration: 0.01ms !important;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/* Windows 고대비 모드: on/off 가 background-color 만으로 표시되므로 시스템 색에 덮이면 구별 불가. */
|
|
86
|
+
@media (forced-colors: active) {
|
|
87
|
+
.sh-ui-switch {
|
|
88
|
+
border: 1px solid ButtonBorder;
|
|
89
|
+
background: ButtonFace;
|
|
90
|
+
}
|
|
91
|
+
.sh-ui-switch[data-checked] {
|
|
92
|
+
background: Highlight;
|
|
93
|
+
border-color: Highlight;
|
|
94
|
+
}
|
|
95
|
+
.sh-ui-switch__thumb {
|
|
96
|
+
background: ButtonText;
|
|
97
|
+
}
|
|
98
|
+
.sh-ui-switch[data-checked] .sh-ui-switch__thumb {
|
|
99
|
+
background: HighlightText;
|
|
100
|
+
}
|
|
101
|
+
.sh-ui-switch:focus-visible {
|
|
102
|
+
outline-color: Highlight;
|
|
103
|
+
}
|
|
104
|
+
.sh-ui-switch[data-disabled] {
|
|
105
|
+
border-color: GrayText;
|
|
106
|
+
}
|
|
107
|
+
.sh-ui-switch[data-disabled] .sh-ui-switch__thumb {
|
|
108
|
+
background: GrayText;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -81,3 +81,30 @@
|
|
|
81
81
|
transition-duration: 0.01ms !important;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
+
|
|
85
|
+
/* Windows 고대비 모드: on/off 가 background-color 만으로 표시되므로 시스템 색에 덮이면 구별 불가. */
|
|
86
|
+
@media (forced-colors: active) {
|
|
87
|
+
.switch {
|
|
88
|
+
border: 1px solid ButtonBorder;
|
|
89
|
+
background: ButtonFace;
|
|
90
|
+
}
|
|
91
|
+
.switch[data-checked] {
|
|
92
|
+
background: Highlight;
|
|
93
|
+
border-color: Highlight;
|
|
94
|
+
}
|
|
95
|
+
.switch__thumb {
|
|
96
|
+
background: ButtonText;
|
|
97
|
+
}
|
|
98
|
+
.switch[data-checked] .switch__thumb {
|
|
99
|
+
background: HighlightText;
|
|
100
|
+
}
|
|
101
|
+
.switch:focus-visible {
|
|
102
|
+
outline-color: Highlight;
|
|
103
|
+
}
|
|
104
|
+
.switch[data-disabled] {
|
|
105
|
+
border-color: GrayText;
|
|
106
|
+
}
|
|
107
|
+
.switch[data-disabled] .switch__thumb {
|
|
108
|
+
background: GrayText;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -146,3 +146,27 @@
|
|
|
146
146
|
.sh-ui-tabs[data-variant="plain"] .sh-ui-tabs__indicator {
|
|
147
147
|
display: none;
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
/* Windows 고대비 모드: indicator 색이 시스템 색에 덮이면 active 탭 구별 불가. */
|
|
151
|
+
@media (forced-colors: active) {
|
|
152
|
+
.sh-ui-tabs__trigger[data-selected] {
|
|
153
|
+
color: Highlight;
|
|
154
|
+
}
|
|
155
|
+
.sh-ui-tabs[data-variant="underline"] .sh-ui-tabs__indicator {
|
|
156
|
+
box-shadow: inset 0 -2px 0 Highlight;
|
|
157
|
+
}
|
|
158
|
+
.sh-ui-tabs[data-variant="underline"][data-orientation="vertical"] .sh-ui-tabs__indicator {
|
|
159
|
+
box-shadow: inset -2px 0 0 Highlight;
|
|
160
|
+
}
|
|
161
|
+
.sh-ui-tabs[data-variant="pill"] .sh-ui-tabs__indicator {
|
|
162
|
+
border: 1px solid Highlight;
|
|
163
|
+
background: ButtonFace;
|
|
164
|
+
}
|
|
165
|
+
.sh-ui-tabs[data-variant="plain"] .sh-ui-tabs__trigger[data-selected] {
|
|
166
|
+
outline: 1px solid Highlight;
|
|
167
|
+
}
|
|
168
|
+
.sh-ui-tabs__trigger:focus-visible,
|
|
169
|
+
.sh-ui-tabs__content:focus-visible {
|
|
170
|
+
outline-color: Highlight;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -146,3 +146,27 @@
|
|
|
146
146
|
.tabs[data-variant="plain"] .tabs__indicator {
|
|
147
147
|
display: none;
|
|
148
148
|
}
|
|
149
|
+
|
|
150
|
+
/* Windows 고대비 모드: indicator 색이 시스템 색에 덮이면 active 탭 구별 불가. */
|
|
151
|
+
@media (forced-colors: active) {
|
|
152
|
+
.tabs__trigger[data-selected] {
|
|
153
|
+
color: Highlight;
|
|
154
|
+
}
|
|
155
|
+
.tabs[data-variant="underline"] .tabs__indicator {
|
|
156
|
+
box-shadow: inset 0 -2px 0 Highlight;
|
|
157
|
+
}
|
|
158
|
+
.tabs[data-variant="underline"][data-orientation="vertical"] .tabs__indicator {
|
|
159
|
+
box-shadow: inset -2px 0 0 Highlight;
|
|
160
|
+
}
|
|
161
|
+
.tabs[data-variant="pill"] .tabs__indicator {
|
|
162
|
+
border: 1px solid Highlight;
|
|
163
|
+
background: ButtonFace;
|
|
164
|
+
}
|
|
165
|
+
.tabs[data-variant="plain"] .tabs__trigger[data-selected] {
|
|
166
|
+
outline: 1px solid Highlight;
|
|
167
|
+
}
|
|
168
|
+
.tabs__trigger:focus-visible,
|
|
169
|
+
.tabs__content:focus-visible {
|
|
170
|
+
outline-color: Highlight;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
@@ -83,3 +83,19 @@
|
|
|
83
83
|
transition: none;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/* Windows 고대비 모드: pressed 가 background-color 만으로 표시되므로 시스템 색에 덮이면 구별 불가. */
|
|
88
|
+
@media (forced-colors: active) {
|
|
89
|
+
.sh-ui-toggle[data-pressed] {
|
|
90
|
+
background: Highlight;
|
|
91
|
+
color: HighlightText;
|
|
92
|
+
border-color: Highlight;
|
|
93
|
+
}
|
|
94
|
+
.sh-ui-toggle:focus-visible {
|
|
95
|
+
outline-color: Highlight;
|
|
96
|
+
}
|
|
97
|
+
.sh-ui-toggle:disabled {
|
|
98
|
+
color: GrayText;
|
|
99
|
+
border-color: GrayText;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -83,3 +83,19 @@
|
|
|
83
83
|
transition: none;
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/* Windows 고대비 모드: pressed 가 background-color 만으로 표시되므로 시스템 색에 덮이면 구별 불가. */
|
|
88
|
+
@media (forced-colors: active) {
|
|
89
|
+
.toggle[data-pressed] {
|
|
90
|
+
background: Highlight;
|
|
91
|
+
color: HighlightText;
|
|
92
|
+
border-color: Highlight;
|
|
93
|
+
}
|
|
94
|
+
.toggle:focus-visible {
|
|
95
|
+
outline-color: Highlight;
|
|
96
|
+
}
|
|
97
|
+
.toggle:disabled {
|
|
98
|
+
color: GrayText;
|
|
99
|
+
border-color: GrayText;
|
|
100
|
+
}
|
|
101
|
+
}
|