@iyulab/components 1.38.0 → 1.40.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 +194 -0
- package/README.md +24 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorateMetadata.js +1 -1
- 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/assets/locales/ar.json.js +6 -2
- package/dist/assets/locales/de.json.js +6 -2
- package/dist/assets/locales/en.json.js +6 -2
- package/dist/assets/locales/es.json.js +6 -2
- package/dist/assets/locales/fr.json.js +6 -2
- package/dist/assets/locales/id.json.js +6 -2
- package/dist/assets/locales/ja.json.js +6 -2
- package/dist/assets/locales/ko.json.js +6 -2
- package/dist/assets/locales/pt-BR.json.js +6 -2
- package/dist/assets/locales/ru.json.js +6 -2
- package/dist/assets/locales/th.json.js +6 -2
- package/dist/assets/locales/vi.json.js +6 -2
- package/dist/assets/locales/zh-CN.json.js +6 -2
- package/dist/assets/locales/zh-TW.json.js +6 -2
- package/dist/components/UFloatingElement.js +2 -2
- package/dist/components/UFormControlElement.js +2 -2
- package/dist/components/UOverlayElement.js +2 -2
- package/dist/components/alert/UAlert.js +2 -2
- package/dist/components/avatar/UAvatar.js +2 -2
- package/dist/components/badge/UBadge.js +2 -2
- package/dist/components/breadcrumb/UBreadcrumb.js +1 -1
- package/dist/components/breadcrumb/UBreadcrumb.styles.js +1 -1
- package/dist/components/breadcrumb-item/UBreadcrumbItem.js +2 -2
- package/dist/components/breadcrumb-item/UBreadcrumbItem.styles.js +1 -1
- package/dist/components/button/UButton.js +2 -2
- package/dist/components/button-group/UButtonGroup.js +2 -2
- package/dist/components/card/UCard.js +2 -2
- package/dist/components/carousel/UCarousel.js +2 -2
- package/dist/components/checkbox/UCheckbox.js +2 -2
- package/dist/components/checkbox/UCheckbox.styles.js +7 -1
- package/dist/components/chip/UChip.js +2 -2
- package/dist/components/chip/UChip.styles.js +7 -0
- package/dist/components/copy-button/UCopyButton.js +2 -2
- package/dist/components/date-picker/UDatePicker.js +2 -2
- package/dist/components/date-picker/UDatePicker.styles.js +2 -2
- package/dist/components/dialog/UDialog.js +2 -2
- package/dist/components/divider/UDivider.js +2 -2
- package/dist/components/divider/UDivider.styles.js +1 -1
- package/dist/components/drawer/UDrawer.js +2 -2
- package/dist/components/expander/UExpander.js +2 -2
- package/dist/components/expander/UExpander.styles.js +1 -1
- package/dist/components/field/UField.js +2 -2
- package/dist/components/field/UField.styles.js +1 -1
- package/dist/components/file-input/UFileInput.js +2 -2
- package/dist/components/file-input/UFileInput.styles.js +2 -2
- package/dist/components/form/UForm.js +2 -2
- package/dist/components/icon/UIcon.js +3 -3
- package/dist/components/icon-button/UIconButton.js +2 -2
- package/dist/components/input/UInput.d.ts +15 -1
- package/dist/components/input/UInput.js +62 -12
- package/dist/components/input/UInput.styles.js +25 -6
- package/dist/components/menu/UMenu.js +2 -2
- package/dist/components/menu-item/UMenuItem.js +2 -2
- package/dist/components/option/UOption.js +2 -2
- package/dist/components/panel/UPanel.js +2 -2
- package/dist/components/popover/UPopover.js +23 -7
- package/dist/components/progress-bar/UProgressBar.js +2 -2
- package/dist/components/progress-ring/UProgressRing.js +2 -2
- package/dist/components/radio/URadio.js +2 -2
- package/dist/components/rating/URating.js +2 -2
- package/dist/components/rating/URating.styles.js +6 -0
- package/dist/components/select/USelect.d.ts +7 -1
- package/dist/components/select/USelect.js +19 -8
- package/dist/components/select/USelect.styles.js +18 -5
- package/dist/components/skeleton/USkeleton.js +2 -2
- package/dist/components/slider/USlider.d.ts +3 -1
- package/dist/components/slider/USlider.js +2 -2
- package/dist/components/slider/USlider.styles.js +19 -2
- package/dist/components/spinner/USpinner.js +2 -2
- package/dist/components/split-panel/USplitPanel.d.ts +37 -2
- package/dist/components/split-panel/USplitPanel.js +120 -11
- package/dist/components/split-panel/USplitPanel.styles.js +37 -6
- package/dist/components/switch/USwitch.js +2 -2
- package/dist/components/switch/USwitch.styles.js +8 -3
- package/dist/components/tab/UTab.js +2 -2
- package/dist/components/tab/UTab.styles.js +1 -1
- package/dist/components/tab-panel/UTabPanel.js +3 -3
- package/dist/components/tag/UTag.js +2 -2
- package/dist/components/text/UText.js +2 -2
- package/dist/components/text/UText.styles.js +1 -1
- package/dist/components/textarea/UTextarea.d.ts +5 -0
- package/dist/components/textarea/UTextarea.js +2 -2
- package/dist/components/textarea/UTextarea.styles.js +6 -3
- package/dist/components/tooltip/UTooltip.js +2 -2
- package/dist/components/tree/UTree.js +2 -2
- package/dist/components/tree-item/UTreeItem.js +2 -2
- package/dist/components/tree-item/UTreeItem.styles.js +50 -13
- package/dist/styles/dark.css +4 -1
- package/dist/styles/light.css +7 -4
- package/dist/utilities/Locale.d.ts +1 -1
- package/dist/utilities/OverlayManager.d.ts +36 -4
- package/dist/utilities/OverlayManager.js +39 -4
- package/dist/utilities/Toast.d.ts +55 -4
- package/dist/utilities/Toast.js +84 -19
- package/package.json +4 -4
- package/skills/iyulab-components/references/components/dialog.md +19 -0
- package/skills/iyulab-components/references/components/input.md +17 -0
- package/skills/iyulab-components/references/components/panel.md +12 -0
- package/skills/iyulab-components/references/components/select.md +9 -0
- package/skills/iyulab-components/references/components/slider.md +1 -1
- package/skills/iyulab-components/references/components/split-panel.md +41 -3
- package/skills/iyulab-components/references/components/tab-panel.md +18 -0
- package/skills/iyulab-components/references/utilities/overlay-manager.md +16 -2
|
@@ -58,49 +58,86 @@ var styles = css`
|
|
|
58
58
|
white-space: nowrap;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/* ── toggler ──
|
|
61
|
+
/* ── toggler ──
|
|
62
|
+
The box that takes the pointer is 24x24 (WCAG 2.2 SC 2.5.8); the square you see is still
|
|
63
|
+
18x18, drawn by the pseudo-element. The negative margins give the extra 3px on each side
|
|
64
|
+
back, so the glyph, the label and the row height sit exactly where they did — the extra
|
|
65
|
+
area lands on the header's own padding and the gap before the label, never on another
|
|
66
|
+
target. */
|
|
62
67
|
.prefix-toggler {
|
|
68
|
+
position: relative;
|
|
69
|
+
box-sizing: border-box;
|
|
63
70
|
flex-shrink: 0;
|
|
64
|
-
margin
|
|
71
|
+
margin: -3px 1px -3px -3px;
|
|
65
72
|
display: inline-flex;
|
|
66
73
|
align-items: center;
|
|
67
74
|
justify-content: center;
|
|
68
|
-
width:
|
|
69
|
-
height:
|
|
75
|
+
width: 24px;
|
|
76
|
+
height: 24px;
|
|
77
|
+
}
|
|
78
|
+
.prefix-toggler::before {
|
|
79
|
+
content: "";
|
|
80
|
+
position: absolute;
|
|
81
|
+
inset: 3px;
|
|
70
82
|
border-radius: var(--u-radius-sm, 3px);
|
|
83
|
+
transition: background-color var(--u-duration-fast, 140ms) var(--u-ease-standard, cubic-bezier(0.2, 0, 0, 1));
|
|
84
|
+
}
|
|
85
|
+
.prefix-toggler > * {
|
|
86
|
+
position: relative;
|
|
71
87
|
}
|
|
72
88
|
.prefix-toggler u-icon {
|
|
73
89
|
font-size: 12px;
|
|
74
90
|
pointer-events: none;
|
|
75
91
|
}
|
|
76
|
-
:host(:not([disabled])[trigger="icon"]) .prefix-toggler:hover,
|
|
77
|
-
:host(:not([disabled])[trigger="icon"]:focus-visible) .prefix-toggler {
|
|
92
|
+
:host(:not([disabled])[trigger="icon"]) .prefix-toggler:hover::before,
|
|
93
|
+
:host(:not([disabled])[trigger="icon"]:focus-visible) .prefix-toggler::before {
|
|
78
94
|
background-color: var(--u-bg-color-hover, #F5F5F5);
|
|
79
95
|
}
|
|
96
|
+
/* A checkable row puts the checkbox 4px after the toggle. Centred 24px areas for both would
|
|
97
|
+
overlap by 3px, so here the toggle takes its extra width entirely on the left (header
|
|
98
|
+
padding), and the padding keeps the glyph centred on its visible square. */
|
|
99
|
+
:host([checkable]) .prefix-toggler {
|
|
100
|
+
margin: -3px 4px -3px -6px;
|
|
101
|
+
padding-left: 6px;
|
|
102
|
+
}
|
|
103
|
+
:host([checkable]) .prefix-toggler::before {
|
|
104
|
+
inset: 3px 0 3px 6px;
|
|
105
|
+
}
|
|
80
106
|
|
|
81
|
-
/* ── checkbox ──
|
|
107
|
+
/* ── checkbox ──
|
|
108
|
+
Same split as the toggle: a 24x24 box takes the pointer, the 16x16 box you see is the
|
|
109
|
+
pseudo-element, and the negative margins keep every visible edge where it was. */
|
|
82
110
|
.prefix-checkbox {
|
|
111
|
+
position: relative;
|
|
112
|
+
box-sizing: border-box;
|
|
83
113
|
flex-shrink: 0;
|
|
84
|
-
margin
|
|
114
|
+
margin: -4px 0 -4px -4px;
|
|
85
115
|
display: inline-flex;
|
|
86
116
|
align-items: center;
|
|
87
117
|
justify-content: center;
|
|
88
|
-
width:
|
|
89
|
-
height:
|
|
118
|
+
width: 24px;
|
|
119
|
+
height: 24px;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
}
|
|
122
|
+
.prefix-checkbox::before {
|
|
123
|
+
content: "";
|
|
124
|
+
position: absolute;
|
|
125
|
+
inset: 4px;
|
|
126
|
+
box-sizing: border-box;
|
|
90
127
|
border-radius: var(--u-radius-sm, 3px);
|
|
91
128
|
border: 1.5px solid var(--u-input-border-color, #E0E0E0);
|
|
92
129
|
background-color: transparent;
|
|
93
130
|
transition: background-color var(--u-duration-fast, 140ms) var(--u-ease-standard, cubic-bezier(0.2, 0, 0, 1)), border-color var(--u-duration-fast, 140ms) var(--u-ease-standard, cubic-bezier(0.2, 0, 0, 1));
|
|
94
|
-
cursor: pointer;
|
|
95
131
|
}
|
|
96
132
|
.prefix-checkbox u-icon {
|
|
133
|
+
position: relative;
|
|
97
134
|
visibility: hidden;
|
|
98
135
|
font-size: 12px;
|
|
99
136
|
color: #fff;
|
|
100
137
|
pointer-events: none;
|
|
101
138
|
}
|
|
102
|
-
.prefix-checkbox[checked],
|
|
103
|
-
.prefix-checkbox[indeterminate] {
|
|
139
|
+
.prefix-checkbox[checked]::before,
|
|
140
|
+
.prefix-checkbox[indeterminate]::before {
|
|
104
141
|
border-color: var(--tree-item-color);
|
|
105
142
|
background-color: var(--tree-item-color);
|
|
106
143
|
}
|
package/dist/styles/dark.css
CHANGED
|
@@ -242,7 +242,10 @@
|
|
|
242
242
|
--u-txt-color-hover: var(--u-primary-color-strong);
|
|
243
243
|
--u-txt-color-active: var(--u-primary-color-strong);
|
|
244
244
|
--u-txt-color-disabled: var(--u-neutral-500);
|
|
245
|
-
|
|
245
|
+
/* 라이트와 같은 기준 — 놓이는 모든 면에서 AA. neutral-700(#8A8A8A)은 바탕 5.43 ·
|
|
246
|
+
올림면(neutral-300) 4.16 · active 면(neutral-400) 3.15 로 미달이었다.
|
|
247
|
+
neutral-800(#B0B0B0) = 8.64 · 6.62 · 5.01. 본문(neutral-900)과의 대비비 1.46. */
|
|
248
|
+
--u-txt-color-weak: var(--u-neutral-800);
|
|
246
249
|
--u-txt-color-strong: var(--u-neutral-1000);
|
|
247
250
|
|
|
248
251
|
--u-link-txt-color: var(--u-primary-color-strong);
|
package/dist/styles/light.css
CHANGED
|
@@ -252,10 +252,13 @@
|
|
|
252
252
|
--u-txt-color-hover: var(--u-primary-color-strong);
|
|
253
253
|
--u-txt-color-active: var(--u-primary-color-strong);
|
|
254
254
|
--u-txt-color-disabled: var(--u-neutral-400);
|
|
255
|
-
/*
|
|
256
|
-
neutral-600(#757575)
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
/* 보조 텍스트는 «놓이는 모든 면»에서 AA(4.5)를 받쳐야 한다 — 바탕만이 아니다.
|
|
256
|
+
neutral-600(#757575)은 바탕 4.61 에서만 통과하고 올림면(neutral-50) 4.41 ·
|
|
257
|
+
active 면(neutral-200) 3.97 로 미달이었다(표 머리·카드 위 보조 텍스트).
|
|
258
|
+
neutral-700(#616161) = 바탕 6.19 · 올림면 5.93 · active 5.34.
|
|
259
|
+
본문(neutral-900)과의 대비비는 2.60 으로, 보조 텍스트를 모든 표면 위에서
|
|
260
|
+
읽히게 보장하는 흔한 디자인 시스템 기준(본문 대비 약 1.3~1.8)보다 위계가 넓다. */
|
|
261
|
+
--u-txt-color-weak: var(--u-neutral-700);
|
|
259
262
|
--u-txt-color-strong: var(--u-neutral-1000);
|
|
260
263
|
|
|
261
264
|
--u-link-txt-color: var(--u-primary-color-strong);
|
|
@@ -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';
|
|
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' | 'search';
|
|
16
16
|
type LocaleTable = Record<LocaleMessageKey, string>;
|
|
17
17
|
/**
|
|
18
18
|
* 한 패키지(또는 앱 영역)의 문자열 묶음.
|
|
@@ -1,17 +1,49 @@
|
|
|
1
1
|
import { FocusTrap } from 'focus-trap';
|
|
2
2
|
/**
|
|
3
|
-
* OverlayManager는
|
|
3
|
+
* OverlayManager는 **겹치는 표면 전체의 층(layer)을 소유**합니다.
|
|
4
4
|
*
|
|
5
|
-
* - 오버레이 스택 순서 관리 (z-index 자동
|
|
5
|
+
* - 오버레이 스택 순서 관리 (z-index 자동 할당)
|
|
6
|
+
* - **알림 층 z-index 제공** — 알림은 오버레이의 형제가 아니라 그 «위» 채널이다
|
|
6
7
|
* - body scroll lock 참조 카운팅
|
|
7
8
|
* - topmost 판별 (ESC 키 처리용)
|
|
8
9
|
* - focus-trap trapStack 공유
|
|
10
|
+
*
|
|
11
|
+
* ## 층 스케일 — 왜 두 개의 «띠»인가
|
|
12
|
+
*
|
|
13
|
+
* 겹침을 컴포넌트마다 따로 정하면 어긋난다. 실측(2026-09-08)으로 `Toast` 가 자기 컨테이너에
|
|
14
|
+
* `z-index: 9999` 를 박고 있었고 이 매니저가 오버레이에 **9999 «초과»** 를 주고 있어,
|
|
15
|
+
* ***모달 안에서 띄운 오류 토스트가 구조적으로 항상 가려졌다.*** 알림이 도달하지 않는 것은
|
|
16
|
+
* 조용한 실패라 아무도 보지 못했다.
|
|
17
|
+
*
|
|
18
|
+
* ⇒ 층을 **이름 있는 띠**로 고정한다(디자인 시스템의 표준 관용구다 — 겹침은 협상이 아니라
|
|
19
|
+
* 계약이다):
|
|
20
|
+
*
|
|
21
|
+
* | 띠 | 범위 | 소유 |
|
|
22
|
+
* |---|---|---|
|
|
23
|
+
* | 오버레이 | `9999` ~ `9999 + OVERLAY_BAND` | `u-dialog`·`u-drawer` 등 `UOverlayElement` 계열 |
|
|
24
|
+
* | **알림** | `notificationZIndex` | `Toast` — **오버레이 띠보다 항상 위** |
|
|
25
|
+
*
|
|
26
|
+
* ⚠**띠에 상한이 있는 것이 이 계약의 핵심이다.** 종전 `zCounter` 는 «지금까지 열린 총합»이라
|
|
27
|
+
* 단조 증가해 **상한이 없었고**, 상한이 없으면 «알림이 항상 위»를 어떤 상수로도 보장할 수
|
|
28
|
+
* 없다. 이제 **동시에 열린 깊이**(`stack.length`)로 할당하므로 띠 안에 갇힌다.
|
|
29
|
+
* 동시 오버레이가 `OVERLAY_BAND` 를 넘으면 그 이상은 같은 값을 공유한다(서로 간 겹침 순서만
|
|
30
|
+
* 포기하고, **알림이 위**라는 불변식은 유지된다) — 실제 앱이 도달하는 상태가 아니지만,
|
|
31
|
+
* 도달하더라도 무엇이 깨지는지 정해져 있는 편이 낫다.
|
|
9
32
|
*/
|
|
10
33
|
export declare class OverlayManager {
|
|
11
34
|
/** 열린 오버레이 스택 */
|
|
12
35
|
private static readonly stack;
|
|
13
|
-
/**
|
|
14
|
-
private static
|
|
36
|
+
/** 오버레이 띠의 시작 값 */
|
|
37
|
+
private static readonly OVERLAY_BASE;
|
|
38
|
+
/** 오버레이 띠의 폭 — 이 수를 넘는 «동시» 오버레이는 최상단 값을 공유한다 */
|
|
39
|
+
private static readonly OVERLAY_BAND;
|
|
40
|
+
/**
|
|
41
|
+
* 알림 층의 z-index. **오버레이 띠 전체보다 항상 위**임이 보장된다.
|
|
42
|
+
*
|
|
43
|
+
* 토스트·스낵바처럼 «오버레이 위에서도 반드시 보여야 하는» 표면이 쓴다. 직접 상수를
|
|
44
|
+
* 박지 말고 이 값을 읽을 것 — 그래야 띠가 조정돼도 따라온다.
|
|
45
|
+
*/
|
|
46
|
+
static get notificationZIndex(): number;
|
|
15
47
|
/** body scroll lock 참조 카운트 */
|
|
16
48
|
private static lockCount;
|
|
17
49
|
/** scroll lock 이전 body overflow 값 */
|
|
@@ -1,18 +1,53 @@
|
|
|
1
1
|
//#region src/utilities/OverlayManager.ts
|
|
2
2
|
/**
|
|
3
|
-
* OverlayManager는
|
|
3
|
+
* OverlayManager는 **겹치는 표면 전체의 층(layer)을 소유**합니다.
|
|
4
4
|
*
|
|
5
|
-
* - 오버레이 스택 순서 관리 (z-index 자동
|
|
5
|
+
* - 오버레이 스택 순서 관리 (z-index 자동 할당)
|
|
6
|
+
* - **알림 층 z-index 제공** — 알림은 오버레이의 형제가 아니라 그 «위» 채널이다
|
|
6
7
|
* - body scroll lock 참조 카운팅
|
|
7
8
|
* - topmost 판별 (ESC 키 처리용)
|
|
8
9
|
* - focus-trap trapStack 공유
|
|
10
|
+
*
|
|
11
|
+
* ## 층 스케일 — 왜 두 개의 «띠»인가
|
|
12
|
+
*
|
|
13
|
+
* 겹침을 컴포넌트마다 따로 정하면 어긋난다. 실측(2026-09-08)으로 `Toast` 가 자기 컨테이너에
|
|
14
|
+
* `z-index: 9999` 를 박고 있었고 이 매니저가 오버레이에 **9999 «초과»** 를 주고 있어,
|
|
15
|
+
* ***모달 안에서 띄운 오류 토스트가 구조적으로 항상 가려졌다.*** 알림이 도달하지 않는 것은
|
|
16
|
+
* 조용한 실패라 아무도 보지 못했다.
|
|
17
|
+
*
|
|
18
|
+
* ⇒ 층을 **이름 있는 띠**로 고정한다(디자인 시스템의 표준 관용구다 — 겹침은 협상이 아니라
|
|
19
|
+
* 계약이다):
|
|
20
|
+
*
|
|
21
|
+
* | 띠 | 범위 | 소유 |
|
|
22
|
+
* |---|---|---|
|
|
23
|
+
* | 오버레이 | `9999` ~ `9999 + OVERLAY_BAND` | `u-dialog`·`u-drawer` 등 `UOverlayElement` 계열 |
|
|
24
|
+
* | **알림** | `notificationZIndex` | `Toast` — **오버레이 띠보다 항상 위** |
|
|
25
|
+
*
|
|
26
|
+
* ⚠**띠에 상한이 있는 것이 이 계약의 핵심이다.** 종전 `zCounter` 는 «지금까지 열린 총합»이라
|
|
27
|
+
* 단조 증가해 **상한이 없었고**, 상한이 없으면 «알림이 항상 위»를 어떤 상수로도 보장할 수
|
|
28
|
+
* 없다. 이제 **동시에 열린 깊이**(`stack.length`)로 할당하므로 띠 안에 갇힌다.
|
|
29
|
+
* 동시 오버레이가 `OVERLAY_BAND` 를 넘으면 그 이상은 같은 값을 공유한다(서로 간 겹침 순서만
|
|
30
|
+
* 포기하고, **알림이 위**라는 불변식은 유지된다) — 실제 앱이 도달하는 상태가 아니지만,
|
|
31
|
+
* 도달하더라도 무엇이 깨지는지 정해져 있는 편이 낫다.
|
|
9
32
|
*/
|
|
10
33
|
var OverlayManager = class {
|
|
11
34
|
static {
|
|
12
35
|
this.stack = [];
|
|
13
36
|
}
|
|
14
37
|
static {
|
|
15
|
-
this.
|
|
38
|
+
this.OVERLAY_BASE = 9999;
|
|
39
|
+
}
|
|
40
|
+
static {
|
|
41
|
+
this.OVERLAY_BAND = 1e3;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 알림 층의 z-index. **오버레이 띠 전체보다 항상 위**임이 보장된다.
|
|
45
|
+
*
|
|
46
|
+
* 토스트·스낵바처럼 «오버레이 위에서도 반드시 보여야 하는» 표면이 쓴다. 직접 상수를
|
|
47
|
+
* 박지 말고 이 값을 읽을 것 — 그래야 띠가 조정돼도 따라온다.
|
|
48
|
+
*/
|
|
49
|
+
static get notificationZIndex() {
|
|
50
|
+
return this.OVERLAY_BASE + this.OVERLAY_BAND + 1;
|
|
16
51
|
}
|
|
17
52
|
static {
|
|
18
53
|
this.lockCount = 0;
|
|
@@ -38,7 +73,7 @@ var OverlayManager = class {
|
|
|
38
73
|
*/
|
|
39
74
|
static add(overlay, lockBody = true) {
|
|
40
75
|
this.stack.push(overlay);
|
|
41
|
-
overlay.style.zIndex = String(
|
|
76
|
+
overlay.style.zIndex = String(this.OVERLAY_BASE + Math.min(this.stack.length, this.OVERLAY_BAND));
|
|
42
77
|
if (lockBody) {
|
|
43
78
|
if (this.lockCount === 0) {
|
|
44
79
|
this.savedOverflow = document.body.style.overflow;
|
|
@@ -20,8 +20,20 @@ export interface ToastOptions {
|
|
|
20
20
|
* 토스트 알림 유틸리티 클래스입니다.
|
|
21
21
|
*/
|
|
22
22
|
export declare class Toast {
|
|
23
|
+
/**
|
|
24
|
+
* 위치별 컨테이너를 **타깃 엘리먼트 자신에 키잉**한다.
|
|
25
|
+
*
|
|
26
|
+
* 종전에는 `"<position>@<id>"` 문자열이 키였고, 그 파생이 세 가지를 동시에 깨뜨렸다:
|
|
27
|
+
* ⑴같은 `id`를 가진 «다른» 엘리먼트가 같은 키로 충돌한다(SPA 라우트 교체가 화면
|
|
28
|
+
* 엘리먼트를 같은 `id`로 다시 만드는 것은 평범한 패턴이다) ⑵`id`가 없으면 폴백이
|
|
29
|
+
* `el-${Date.now()}` 라 호출마다 키가 달라져 캐시가 성립하지 않고 컨테이너가 쌓인다
|
|
30
|
+
* ⑶그 불안정한 키를 `hide` 정리 경로가 **다시 계산**하므로 `containers.delete()` 가
|
|
31
|
+
* 빗나가 항목이 영구히 남는다.
|
|
32
|
+
*
|
|
33
|
+
* `WeakMap` 은 셋을 전부 구조적으로 없앤다 — 엘리먼트 동일성이 곧 키라 충돌이 불가능하고,
|
|
34
|
+
* `id` 유무에 의존하지 않으며, 타깃이 버려지면 그 항목도 함께 수거된다.
|
|
35
|
+
*/
|
|
23
36
|
private static containers;
|
|
24
|
-
private static elements;
|
|
25
37
|
/**
|
|
26
38
|
* 모든 Toast 호출에 적용될 전역 기본 옵션입니다. 개별 호출의 `options`가 우선합니다.
|
|
27
39
|
*
|
|
@@ -47,8 +59,47 @@ export declare class Toast {
|
|
|
47
59
|
static error(content: string, options?: ToastOptions): Promise<void>;
|
|
48
60
|
/** 토스트 알림을 생성합니다. */
|
|
49
61
|
static show(status?: AlertStatus, content?: string, options?: ToastOptions): Promise<void>;
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
/**
|
|
63
|
+
* 위치에 맞는 컨테이너 엘리먼트를 가져오거나, 생성합니다.
|
|
64
|
+
*
|
|
65
|
+
* ⚠**캐시 적중은 그 컨테이너가 «여전히 쓸 수 있는가»를 확인한 뒤에만 유효하다.** 호스트가
|
|
66
|
+
* 갈아끼워지면(`body.innerHTML = ''`, 셸 재구축) 캐시된 컨테이너는 문서에서 떨어진 채
|
|
67
|
+
* 남는데, 거기에 append 된 엘리먼트는 **연결되지 않아 `updateComplete` 가 영원히 해소되지
|
|
68
|
+
* 않는다**. 낡은 항목은 버리고 새로 만든다.
|
|
69
|
+
*/
|
|
53
70
|
private static getOrCreateContainer;
|
|
71
|
+
/**
|
|
72
|
+
* 알림 컨테이너를 **네이티브 top layer** 로 올린다(`popover="manual"`).
|
|
73
|
+
*
|
|
74
|
+
* ## 왜 — z-index 로는 원리적으로 닿지 않는 자리가 있다
|
|
75
|
+
*
|
|
76
|
+
* `OverlayManager` 의 «이름 있는 띠» 계약은 **우리 오버레이보다 위**를 보장한다(실측:
|
|
77
|
+
* 컨테이너 `z-index: 11000`). 그러나 ***top layer 는 z-index 축 밖에 있다*** — 소비앱이
|
|
78
|
+
* 네이티브 `<dialog>.showModal()` 을 열면 그 다이얼로그는 **어떤 z-index 보다도 위**에
|
|
79
|
+
* 서고, 우리 토스트는 가려진다. 실측(cycle-477, 크로미움 `elementFromPoint`):
|
|
80
|
+
*
|
|
81
|
+
* ```
|
|
82
|
+
* containerZIndex 11000 · notificationZIndex 11000 · hitTag "DIALOG" · toastReachable false
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* 알림 채널의 제1원칙이 ***«지각되지 않는 경보는 경보가 아니다»*** 이므로, 그 채널은 겹침을
|
|
86
|
+
* **다투지 않고** 전용 층을 가져야 한다. `popover="manual"` 은 dismiss 계약도 포커스 트랩도
|
|
87
|
+
* 걸지 않고 **top layer 승격만** 하므로 이 표면에 정확히 맞는다.
|
|
88
|
+
*
|
|
89
|
+
* ## ⚠ 범위 — `document.body` 컨테이너만이다
|
|
90
|
+
*
|
|
91
|
+
* `target` 이 주어진 컨테이너는 `position: absolute` 로 **그 엘리먼트 기준**으로 놓인다.
|
|
92
|
+
* top layer 원소는 조상의 배치 문맥에서 떨어져 나오므로 그 좌표계가 통째로 깨진다 ⇒
|
|
93
|
+
* 타깃 기준 컨테이너는 **종전 z-index 경로를 그대로 쓴다.** 이것이 시범 범위이고,
|
|
94
|
+
* 오버레이 전면 전환(`u-dialog`·`u-drawer` 등)은 별개 결정이다(`ROADMAP.md` §C-B).
|
|
95
|
+
*
|
|
96
|
+
* ## ⚠ z-index 를 지우지 않는다
|
|
97
|
+
*
|
|
98
|
+
* `showPopover` 가 없는 브라우저(또는 호출이 거부되는 상태)에서는 **아무 일도 일어나지
|
|
99
|
+
* 않고 종전 동작이 그대로 남아야** 한다 — 그래서 승격은 순수 «추가»이고, 실패는 조용히
|
|
100
|
+
* 삼킨다(알림을 띄우려다 예외를 던지는 것은 이 표면에서 최악의 실패다).
|
|
101
|
+
*/
|
|
102
|
+
private static preparePopover;
|
|
103
|
+
/** 연결된 뒤에만 부를 수 있다 — 실패하면 종전 동작(z-index 띠)으로 조용히 돌아간다. */
|
|
104
|
+
private static showTopLayer;
|
|
54
105
|
}
|
package/dist/utilities/Toast.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { OverlayManager } from "./OverlayManager.js";
|
|
1
2
|
import { UAlert } from "../components/alert/UAlert.js";
|
|
2
3
|
//#region src/utilities/Toast.ts
|
|
3
4
|
/**
|
|
@@ -5,10 +6,7 @@ import { UAlert } from "../components/alert/UAlert.js";
|
|
|
5
6
|
*/
|
|
6
7
|
var Toast = class {
|
|
7
8
|
static {
|
|
8
|
-
this.containers = /* @__PURE__ */ new
|
|
9
|
-
}
|
|
10
|
-
static {
|
|
11
|
-
this.elements = /* @__PURE__ */ new Set();
|
|
9
|
+
this.containers = /* @__PURE__ */ new WeakMap();
|
|
12
10
|
}
|
|
13
11
|
static {
|
|
14
12
|
this.DefaultOptions = {};
|
|
@@ -52,39 +50,50 @@ var Toast = class {
|
|
|
52
50
|
el.title = merged.title || "";
|
|
53
51
|
el.closable = merged.closable ?? true;
|
|
54
52
|
el.duration = merged.duration ?? 4e3;
|
|
55
|
-
this.elements.add(el);
|
|
56
53
|
const position = merged.position || "top-right";
|
|
57
54
|
const target = merged.target || document.body;
|
|
58
55
|
const container = this.getOrCreateContainer(position, target);
|
|
59
56
|
container.appendChild(el);
|
|
57
|
+
if (!el.isConnected) {
|
|
58
|
+
container.removeChild(el);
|
|
59
|
+
console.warn("[@iyulab/components] Toast was not shown: the target element is not in the document.\n A toast can only render inside a connected element — pass a target that is attached,\n or omit `target` to use document.body.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
60
62
|
await el.updateComplete;
|
|
61
63
|
el.show();
|
|
62
64
|
el.addEventListener("hide", async (e) => {
|
|
63
65
|
if (e.target !== el) return;
|
|
64
66
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
65
67
|
el.remove();
|
|
66
|
-
this.elements.delete(el);
|
|
67
68
|
if (!container.hasChildNodes()) {
|
|
68
|
-
const containerKey = this.getContainerKey(position, target);
|
|
69
69
|
container.remove();
|
|
70
|
-
this.containers.delete(
|
|
70
|
+
this.containers.get(target)?.delete(position);
|
|
71
71
|
}
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
/**
|
|
75
|
+
* 위치에 맞는 컨테이너 엘리먼트를 가져오거나, 생성합니다.
|
|
76
|
+
*
|
|
77
|
+
* ⚠**캐시 적중은 그 컨테이너가 «여전히 쓸 수 있는가»를 확인한 뒤에만 유효하다.** 호스트가
|
|
78
|
+
* 갈아끼워지면(`body.innerHTML = ''`, 셸 재구축) 캐시된 컨테이너는 문서에서 떨어진 채
|
|
79
|
+
* 남는데, 거기에 append 된 엘리먼트는 **연결되지 않아 `updateComplete` 가 영원히 해소되지
|
|
80
|
+
* 않는다**. 낡은 항목은 버리고 새로 만든다.
|
|
81
|
+
*/
|
|
79
82
|
static getOrCreateContainer(position, target) {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
let byPosition = this.containers.get(target);
|
|
84
|
+
if (!byPosition) {
|
|
85
|
+
byPosition = /* @__PURE__ */ new Map();
|
|
86
|
+
this.containers.set(target, byPosition);
|
|
87
|
+
}
|
|
88
|
+
const cached = byPosition.get(position);
|
|
89
|
+
if (cached && cached.isConnected && cached.parentNode === target) return cached;
|
|
90
|
+
if (cached) byPosition.delete(position);
|
|
91
|
+
const container = document.createElement("div");
|
|
92
|
+
container.style.zIndex = String(OverlayManager.notificationZIndex);
|
|
85
93
|
container.style.display = "flex";
|
|
86
94
|
container.style.gap = "10px";
|
|
87
95
|
const isTargeted = target !== document.body;
|
|
96
|
+
const popoverReady = isTargeted ? false : this.preparePopover(container);
|
|
88
97
|
if (isTargeted) {
|
|
89
98
|
container.style.position = "absolute";
|
|
90
99
|
if (getComputedStyle(target).position === "static") target.style.position = "relative";
|
|
@@ -114,9 +123,65 @@ var Toast = class {
|
|
|
114
123
|
}
|
|
115
124
|
container.style.transform = transformParts.length ? transformParts.join(" ") : "";
|
|
116
125
|
target.appendChild(container);
|
|
117
|
-
this.
|
|
126
|
+
if (popoverReady) this.showTopLayer(container);
|
|
127
|
+
byPosition.set(position, container);
|
|
118
128
|
return container;
|
|
119
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* 알림 컨테이너를 **네이티브 top layer** 로 올린다(`popover="manual"`).
|
|
132
|
+
*
|
|
133
|
+
* ## 왜 — z-index 로는 원리적으로 닿지 않는 자리가 있다
|
|
134
|
+
*
|
|
135
|
+
* `OverlayManager` 의 «이름 있는 띠» 계약은 **우리 오버레이보다 위**를 보장한다(실측:
|
|
136
|
+
* 컨테이너 `z-index: 11000`). 그러나 ***top layer 는 z-index 축 밖에 있다*** — 소비앱이
|
|
137
|
+
* 네이티브 `<dialog>.showModal()` 을 열면 그 다이얼로그는 **어떤 z-index 보다도 위**에
|
|
138
|
+
* 서고, 우리 토스트는 가려진다. 실측(cycle-477, 크로미움 `elementFromPoint`):
|
|
139
|
+
*
|
|
140
|
+
* ```
|
|
141
|
+
* containerZIndex 11000 · notificationZIndex 11000 · hitTag "DIALOG" · toastReachable false
|
|
142
|
+
* ```
|
|
143
|
+
*
|
|
144
|
+
* 알림 채널의 제1원칙이 ***«지각되지 않는 경보는 경보가 아니다»*** 이므로, 그 채널은 겹침을
|
|
145
|
+
* **다투지 않고** 전용 층을 가져야 한다. `popover="manual"` 은 dismiss 계약도 포커스 트랩도
|
|
146
|
+
* 걸지 않고 **top layer 승격만** 하므로 이 표면에 정확히 맞는다.
|
|
147
|
+
*
|
|
148
|
+
* ## ⚠ 범위 — `document.body` 컨테이너만이다
|
|
149
|
+
*
|
|
150
|
+
* `target` 이 주어진 컨테이너는 `position: absolute` 로 **그 엘리먼트 기준**으로 놓인다.
|
|
151
|
+
* top layer 원소는 조상의 배치 문맥에서 떨어져 나오므로 그 좌표계가 통째로 깨진다 ⇒
|
|
152
|
+
* 타깃 기준 컨테이너는 **종전 z-index 경로를 그대로 쓴다.** 이것이 시범 범위이고,
|
|
153
|
+
* 오버레이 전면 전환(`u-dialog`·`u-drawer` 등)은 별개 결정이다(`ROADMAP.md` §C-B).
|
|
154
|
+
*
|
|
155
|
+
* ## ⚠ z-index 를 지우지 않는다
|
|
156
|
+
*
|
|
157
|
+
* `showPopover` 가 없는 브라우저(또는 호출이 거부되는 상태)에서는 **아무 일도 일어나지
|
|
158
|
+
* 않고 종전 동작이 그대로 남아야** 한다 — 그래서 승격은 순수 «추가»이고, 실패는 조용히
|
|
159
|
+
* 삼킨다(알림을 띄우려다 예외를 던지는 것은 이 표면에서 최악의 실패다).
|
|
160
|
+
*/
|
|
161
|
+
static preparePopover(container) {
|
|
162
|
+
if (typeof container.showPopover !== "function") return false;
|
|
163
|
+
container.setAttribute("popover", "manual");
|
|
164
|
+
container.style.inset = "auto";
|
|
165
|
+
container.style.margin = "0";
|
|
166
|
+
container.style.border = "none";
|
|
167
|
+
container.style.padding = "0";
|
|
168
|
+
container.style.background = "transparent";
|
|
169
|
+
container.style.color = "inherit";
|
|
170
|
+
container.style.overflow = "visible";
|
|
171
|
+
container.style.width = "auto";
|
|
172
|
+
container.style.height = "auto";
|
|
173
|
+
container.style.maxWidth = "none";
|
|
174
|
+
container.style.maxHeight = "none";
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
/** 연결된 뒤에만 부를 수 있다 — 실패하면 종전 동작(z-index 띠)으로 조용히 돌아간다. */
|
|
178
|
+
static showTopLayer(container) {
|
|
179
|
+
try {
|
|
180
|
+
container.showPopover();
|
|
181
|
+
} catch {
|
|
182
|
+
container.removeAttribute("popover");
|
|
183
|
+
}
|
|
184
|
+
}
|
|
120
185
|
};
|
|
121
186
|
//#endregion
|
|
122
187
|
export { Toast };
|
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.40.0",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"iyulab",
|
|
7
7
|
"components",
|
|
@@ -83,16 +83,16 @@
|
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@eslint/js": "^
|
|
86
|
+
"@eslint/js": "^10.0.1",
|
|
87
87
|
"@types/node": "^26.1.1",
|
|
88
88
|
"@types/react": "^19.2.14",
|
|
89
89
|
"@vitest/browser-playwright": "^4.1.10",
|
|
90
|
-
"eslint": "^
|
|
90
|
+
"eslint": "^10.1.0",
|
|
91
91
|
"eslint-plugin-lit": "^2.3.1",
|
|
92
92
|
"globals": "^17.7.0",
|
|
93
93
|
"happy-dom": "^20.10.6",
|
|
94
94
|
"react": "^19.2.7",
|
|
95
|
-
"typescript": "^
|
|
95
|
+
"typescript": "^6.0.2",
|
|
96
96
|
"typescript-eslint": "^8.64.0",
|
|
97
97
|
"vite": "^8.1.4",
|
|
98
98
|
"vite-plugin-dts": "^5.0.3",
|
|
@@ -25,6 +25,25 @@ For programmatic usage (`Dialog.alert`, `Dialog.confirm`, `Dialog.prompt`), see
|
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
28
|
+
## Sizing
|
|
29
|
+
|
|
30
|
+
The panel is **content-sized, capped at 90%** of the dialog's own box — 90% of the height and of
|
|
31
|
+
the width. Measured in an 896px-tall viewport: a short dialog renders a 235px panel, and the same
|
|
32
|
+
dialog carrying 3,000px of body content stops at 806px.
|
|
33
|
+
|
|
34
|
+
Past that cap the **body is the only scroll region**. The `header` and `footer` slots are
|
|
35
|
+
`flex-shrink: 0`, so the title and the actions stay visible however long the content grows.
|
|
36
|
+
|
|
37
|
+
There is no size property. To make the dialog smaller than 90% of the viewport, give the **host** a
|
|
38
|
+
height — that is what the 90% is measured against:
|
|
39
|
+
|
|
40
|
+
```css
|
|
41
|
+
u-dialog { height: 400px; } /* the panel then caps at 360px */
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
⚠ That lever only shrinks: a height on the host lowers the panel's maximum, it does not reserve a
|
|
45
|
+
panel of that size. A short dialog stays short.
|
|
46
|
+
|
|
28
47
|
## Slots
|
|
29
48
|
|
|
30
49
|
| Name | Description |
|
|
@@ -81,6 +81,23 @@ for a KRW amount) is the consumer's call — the library does not infer one from
|
|
|
81
81
|
| `input` | Fires on every keystroke |
|
|
82
82
|
| `change` | Fires when value is committed |
|
|
83
83
|
|
|
84
|
+
## Form submission
|
|
85
|
+
|
|
86
|
+
Pressing Enter in the field submits its `<form>`, as in a native text field (HTML implicit
|
|
87
|
+
submission): the form's first submit button is activated — `<button type="submit">` or
|
|
88
|
+
`<u-button type="submit">`; a disabled one does nothing — and with no submit button the form is
|
|
89
|
+
submitted only when it has no other single-line field. Enter that confirms an IME composition,
|
|
90
|
+
Enter with a modifier key, and Enter on a highlighted suggestion (`u-option`) do not submit.
|
|
91
|
+
Call `preventDefault()` on the `keydown` to cancel it. Do not also submit on Enter yourself.
|
|
92
|
+
|
|
93
|
+
```html
|
|
94
|
+
<form @submit=${onSubmit}>
|
|
95
|
+
<u-input name="user" required></u-input>
|
|
96
|
+
<u-input name="password" type="password" required></u-input>
|
|
97
|
+
<u-button type="submit">Sign in</u-button>
|
|
98
|
+
</form>
|
|
99
|
+
```
|
|
100
|
+
|
|
84
101
|
## Methods
|
|
85
102
|
|
|
86
103
|
| Method | Description |
|
|
@@ -26,6 +26,18 @@ General-purpose content panel. Matches a tab or tree node when using `value`.
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
+
## Sizing
|
|
30
|
+
|
|
31
|
+
`u-panel` has `overflow: auto` and no height of its own, so it behaves two ways — both intended:
|
|
32
|
+
|
|
33
|
+
- **No height** — it grows with its content. Nothing is clipped and no scrollbar appears.
|
|
34
|
+
- **A height (or a height-bearing parent)** — it becomes the scroll container for its content.
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<u-panel style="height: 240px">…</u-panel> <!-- scrolls its content -->
|
|
38
|
+
<u-panel>…</u-panel> <!-- grows with its content -->
|
|
39
|
+
```
|
|
40
|
+
|
|
29
41
|
## Slots
|
|
30
42
|
|
|
31
43
|
| Name | Description |
|
|
@@ -70,6 +70,15 @@ Dropdown select with single or multiple selection, search, and clear support. Fo
|
|
|
70
70
|
| `focus(options?)` | Focus the trigger |
|
|
71
71
|
| `blur()` | Blur the trigger |
|
|
72
72
|
|
|
73
|
+
## Keyboard & accessibility
|
|
74
|
+
|
|
75
|
+
The trigger is a `role="combobox"`. Without `searchable` the dropdown holds a `role="listbox"`
|
|
76
|
+
and opening it focuses the first option. With `searchable` the dropdown is a `role="dialog"`
|
|
77
|
+
(named by `label`, or "Search") that holds the search field and the listbox; opening it focuses
|
|
78
|
+
the search field, so typing filters at once. From the search field `ArrowDown`/`ArrowUp` move to
|
|
79
|
+
the first/last visible option; on an option, arrows, `Home`/`End`, `Enter`/`Space` (select) and
|
|
80
|
+
`Escape` (close) work as usual.
|
|
81
|
+
|
|
73
82
|
## CSS Parts
|
|
74
83
|
|
|
75
84
|
| Part | Description |
|
|
@@ -84,7 +84,7 @@ Range slider. Single-thumb or dual-thumb (range) mode. Supports marks, value dis
|
|
|
84
84
|
| `--slider-fill-color` | Track fill color |
|
|
85
85
|
| `--slider-track-height` | Track height |
|
|
86
86
|
| `--slider-track-color` | Track background color |
|
|
87
|
-
| `--slider-thumb-size` | Thumb diameter |
|
|
87
|
+
| `--slider-thumb-size` | Thumb diameter (**visible circle only** — the pointer target keeps a 24x24 floor per WCAG 2.2 SC 2.5.8, so lowering this does not shrink it) |
|
|
88
88
|
| `--slider-thumb-color` | Thumb fill color |
|
|
89
89
|
| `--slider-thumb-border-color` | Thumb border color |
|
|
90
90
|
| `--slider-mark-size` | Mark dot size |
|