@iyulab/components 1.39.0 → 1.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +173 -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 +13 -6
- 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 +43 -2
- package/dist/components/split-panel/USplitPanel.js +127 -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/Toast.d.ts +34 -0
- package/dist/utilities/Toast.js +57 -0
- package/dist/utilities/devWarning.d.ts +17 -0
- package/dist/utilities/devWarning.js +5 -0
- 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
|
@@ -6,14 +6,22 @@ import { UElement } from '../UElement.js';
|
|
|
6
6
|
* @slot - 분할된 패널 요소들
|
|
7
7
|
* @slot splitter - 핸들(스플리터) UI
|
|
8
8
|
*
|
|
9
|
-
* @cssprop --splitter-size -
|
|
9
|
+
* @cssprop --splitter-size - 보이는 구분선 두께 (default: 4px)
|
|
10
|
+
* @cssprop --splitter-hit-size - 포인터를 받는 핸들 영역의 두께 — 레이아웃 공간을 차지하므로 패널을
|
|
11
|
+
* 가리지 않는다. 실제 핸들 두께는 이 값과 `--splitter-size` 중 큰 쪽 (default: 24px — WCAG 2.5.8)
|
|
10
12
|
* @cssprop --splitter-color - 스플리터 색상
|
|
11
13
|
* @cssprop --splitter-color-hover - 스플리터 호버 색상
|
|
12
14
|
* @cssprop --splitter-color-active - 스플리터 활성 색상
|
|
13
15
|
*
|
|
14
16
|
* @event shift-start - 구분선 이동 시작 시 발생
|
|
15
17
|
* @event shift - 구분선 이동 중 발생
|
|
16
|
-
* @event shift-end - 구분선 이동 완료 시 발생
|
|
18
|
+
* @event shift-end - 구분선 이동 완료 시 발생 (포인터·키보드 공통)
|
|
19
|
+
*
|
|
20
|
+
* 키보드(WAI-ARIA APG «Window Splitter»): 분할 핸들은 `role="separator"` 로 포커스를 받는다.
|
|
21
|
+
* 방향키(가로 배치는 ←/→, 세로 배치는 ↑/↓)로 앞 패널을 줄이거나 늘리고, Home/End 는 앞 패널을
|
|
22
|
+
* 최소/최대로, Enter 는 앞 패널을 접거나 접기 전 크기로 되돌린다. 키 입력 한 번은 하나의 완결된
|
|
23
|
+
* 이동이라 `shift-start`·`shift`·`shift-end` 를 연달아 낸다 — 비율을 저장하는 소비자는 포인터든
|
|
24
|
+
* 키보드든 `shift-end` 하나만 들으면 된다.
|
|
17
25
|
*/
|
|
18
26
|
export declare class USplitPanel extends UElement {
|
|
19
27
|
static styles: import('lit').CSSResultGroup[];
|
|
@@ -30,21 +38,54 @@ export declare class USplitPanel extends UElement {
|
|
|
30
38
|
private ghost?;
|
|
31
39
|
private panels;
|
|
32
40
|
private splitter?;
|
|
41
|
+
/** Enter 로 접은 핸들별 «접기 전 앞 패널 비율» — 다시 Enter 를 누르면 여기로 돌아간다. */
|
|
42
|
+
private collapsedFrom;
|
|
33
43
|
private dragState;
|
|
34
44
|
private get percentages();
|
|
45
|
+
/**
|
|
46
|
+
* 핸들 하나가 레이아웃에서 차지하는 두께(px). 렌더된 핸들을 재는 것이 정본이다 — CSS 가
|
|
47
|
+
* `max(--splitter-size, --splitter-hit-size)` 로 정하고 `rem` 등 어떤 단위든 올 수 있다.
|
|
48
|
+
* 아직 렌더되지 않았거나 숨겨져 0 이면 두 변수를 읽어 같은 규칙을 흉내 낸다.
|
|
49
|
+
*/
|
|
35
50
|
private get splitterSize();
|
|
36
51
|
private get splitterCount();
|
|
37
52
|
protected willUpdate(changedProperties: PropertyValues): void;
|
|
38
53
|
render(): import('lit-html').TemplateResult<1>;
|
|
39
54
|
private handleSlotChange;
|
|
55
|
+
/**
|
|
56
|
+
* 호스트에 높이(또는 세로 분할이면 폭) 제약이 없으면 이 컴포넌트는 손잡이 두께로 붕괴한다 —
|
|
57
|
+
* 실측 18px(cycle-565). 호스트가 `overflow: hidden` 이라 패널 내용에 닿을 방법이 없고,
|
|
58
|
+
* 오류도 없다. 첫 배치 뒤 한 번 재서 개발 모드에서 알린다(HD-61 ⒝).
|
|
59
|
+
*/
|
|
60
|
+
private warnIfCollapsed;
|
|
40
61
|
private handleSplitterSlotChange;
|
|
41
62
|
private appendSplitters;
|
|
42
63
|
private createSplitter;
|
|
64
|
+
/**
|
|
65
|
+
* 분할 핸들의 접근성 상태 — APG «Window Splitter». 핸들은 명령형으로 만들어 Lit 템플릿 밖에
|
|
66
|
+
* 있으므로, 비율·방향·비활성이 바뀔 때마다 여기서 다시 쓴다.
|
|
67
|
+
*
|
|
68
|
+
* 값은 **앞 패널(primary pane)의 몫**이다. 패널이 셋 이상이면 한 핸들은 이웃한 두 패널 사이만
|
|
69
|
+
* 옮기므로 최대값은 100 이 아니라 그 두 패널의 몫의 합이다.
|
|
70
|
+
*/
|
|
71
|
+
private syncSplitterAria;
|
|
72
|
+
/** 방향키 한 번이 옮기는 앞 패널의 몫(나머지 공간 기준 %). */
|
|
73
|
+
private static readonly KEY_STEP;
|
|
74
|
+
private handleKeyDown;
|
|
43
75
|
private updatePanelLayout;
|
|
44
76
|
private handleDblClick;
|
|
45
77
|
private handlePointerDown;
|
|
46
78
|
private handlePointerMove;
|
|
47
79
|
private handlePointerUp;
|
|
80
|
+
/**
|
|
81
|
+
* 패널 하나의 크기 — 비율은 «핸들을 뺀 나머지 공간»에 대한 몫이다.
|
|
82
|
+
*
|
|
83
|
+
* 🔴각 패널은 핸들 전체 두께 중 **자기 비율만큼**을 뺀다. 종전에는 핸들 몫을 패널 수로 똑같이
|
|
84
|
+
* 나눠 뺐는데(`p% - 핸들합/n`), 그 식은 비율이 균등할 때만 «나머지 공간의 p%» 와 같다. 드래그는
|
|
85
|
+
* 이동량을 나머지 공간 기준 비율로 바꾸므로(`availableSize`), 비율이 균등에서 멀어질수록 패널이
|
|
86
|
+
* 포인터보다 더 움직였다 — 핸들이 굵을수록 크게(24px 핸들이면 이동량의 약 9%).
|
|
87
|
+
*/
|
|
88
|
+
private panelSize;
|
|
48
89
|
private clampPair;
|
|
49
90
|
}
|
|
50
91
|
declare global {
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import { arrayAttrConverter } from "../../utilities/converters.js";
|
|
5
|
+
import { Locale } from "../../utilities/Locale.js";
|
|
5
6
|
import { styles } from "./USplitPanel.styles.js";
|
|
6
7
|
import { html } from "lit";
|
|
7
8
|
import { customElement, property, query } from "lit/decorators.js";
|
|
8
9
|
//#region src/components/split-panel/USplitPanel.ts
|
|
10
|
+
var _USplitPanel;
|
|
9
11
|
var USplitPanel = class USplitPanel extends UElement {
|
|
12
|
+
static {
|
|
13
|
+
_USplitPanel = this;
|
|
14
|
+
}
|
|
10
15
|
constructor(..._args) {
|
|
11
16
|
super(..._args);
|
|
12
17
|
this.disabled = false;
|
|
@@ -15,6 +20,7 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
15
20
|
this.defaultRatio = [];
|
|
16
21
|
this.ratio = [];
|
|
17
22
|
this.panels = [];
|
|
23
|
+
this.collapsedFrom = /* @__PURE__ */ new Map();
|
|
18
24
|
this.dragState = {
|
|
19
25
|
index: -1,
|
|
20
26
|
startPoint: 0,
|
|
@@ -27,12 +33,59 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
27
33
|
this.panels = slot.assignedElements({ flatten: true }).filter((el) => el instanceof HTMLElement);
|
|
28
34
|
this.appendSplitters();
|
|
29
35
|
this.updatePanelLayout();
|
|
36
|
+
this.warnIfCollapsed();
|
|
30
37
|
};
|
|
31
38
|
this.handleSplitterSlotChange = (e) => {
|
|
32
39
|
const slot = e.target;
|
|
33
40
|
this.splitter = slot.assignedNodes({ flatten: true }).at(0);
|
|
34
41
|
this.appendSplitters();
|
|
35
42
|
};
|
|
43
|
+
this.handleKeyDown = (e) => {
|
|
44
|
+
if (this.disabled) return;
|
|
45
|
+
const i = Number(e.currentTarget.dataset.index);
|
|
46
|
+
const p = this.percentages;
|
|
47
|
+
if (p[i] === void 0 || p[i + 1] === void 0) return;
|
|
48
|
+
const pair = p[i] + p[i + 1];
|
|
49
|
+
const horizontal = this.orientation === "horizontal";
|
|
50
|
+
const rtl = horizontal && getComputedStyle(this).direction === "rtl";
|
|
51
|
+
const shrink = horizontal ? rtl ? "ArrowRight" : "ArrowLeft" : "ArrowUp";
|
|
52
|
+
const grow = horizontal ? rtl ? "ArrowLeft" : "ArrowRight" : "ArrowDown";
|
|
53
|
+
let a;
|
|
54
|
+
if (e.key === shrink) a = p[i] - _USplitPanel.KEY_STEP;
|
|
55
|
+
else if (e.key === grow) a = p[i] + _USplitPanel.KEY_STEP;
|
|
56
|
+
else if (e.key === "Home") a = 0;
|
|
57
|
+
else if (e.key === "End") a = pair;
|
|
58
|
+
else if (e.key === "Enter") {
|
|
59
|
+
const restore = this.collapsedFrom.get(i);
|
|
60
|
+
if (p[i] > 0) {
|
|
61
|
+
this.collapsedFrom.set(i, p[i]);
|
|
62
|
+
a = 0;
|
|
63
|
+
} else {
|
|
64
|
+
a = restore ?? pair / 2;
|
|
65
|
+
this.collapsedFrom.delete(i);
|
|
66
|
+
}
|
|
67
|
+
} else return;
|
|
68
|
+
e.preventDefault();
|
|
69
|
+
a = Math.round(Math.min(pair, Math.max(0, a)) * 1e6) / 1e6;
|
|
70
|
+
if (Math.abs(a - p[i]) < 1e-6) return;
|
|
71
|
+
if (e.key !== "Enter") this.collapsedFrom.delete(i);
|
|
72
|
+
const next = [...p];
|
|
73
|
+
next[i] = a;
|
|
74
|
+
next[i + 1] = pair - a;
|
|
75
|
+
const init = (ratio) => ({
|
|
76
|
+
bubbles: false,
|
|
77
|
+
composed: false,
|
|
78
|
+
detail: {
|
|
79
|
+
index: i,
|
|
80
|
+
ratio: [...ratio]
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
this.fire("shift-start", init(p));
|
|
84
|
+
this.ratio = next;
|
|
85
|
+
this.updatePanelLayout();
|
|
86
|
+
this.fire("shift", init(next));
|
|
87
|
+
this.fire("shift-end", init(next));
|
|
88
|
+
};
|
|
36
89
|
this.handleDblClick = () => {
|
|
37
90
|
if (this.disabled) return;
|
|
38
91
|
this.ratio = this.defaultRatio.length === this.panels.length ? [...this.defaultRatio] : [];
|
|
@@ -91,9 +144,8 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
91
144
|
} else {
|
|
92
145
|
const [aPercent, bPercent] = this.clampPair(this.dragState.percentages[aIdx] + deltaPercent, this.dragState.percentages[bIdx] - deltaPercent);
|
|
93
146
|
const dim = this.orientation === "horizontal" ? "width" : "height";
|
|
94
|
-
|
|
95
|
-
this.panels[
|
|
96
|
-
this.panels[bIdx].style[dim] = `calc(${bPercent}% - ${offset}px)`;
|
|
147
|
+
this.panels[aIdx].style[dim] = this.panelSize(aPercent);
|
|
148
|
+
this.panels[bIdx].style[dim] = this.panelSize(bPercent);
|
|
97
149
|
const newRatio = [...this.dragState.percentages];
|
|
98
150
|
newRatio[aIdx] = aPercent;
|
|
99
151
|
newRatio[bIdx] = bPercent;
|
|
@@ -143,7 +195,8 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
143
195
|
this.styles = [super.styles, styles];
|
|
144
196
|
}
|
|
145
197
|
get percentages() {
|
|
146
|
-
const
|
|
198
|
+
const usable = (r) => r.length === this.panels.length && r.every((v) => Number.isFinite(v) && v >= 0) && r.some((v) => v > 0);
|
|
199
|
+
const source = usable(this.ratio) ? this.ratio : usable(this.defaultRatio) ? this.defaultRatio : [];
|
|
147
200
|
if (source.length === this.panels.length) {
|
|
148
201
|
const total = source.reduce((sum, s) => sum + s, 0);
|
|
149
202
|
return source.map((s) => s / total * 100);
|
|
@@ -151,9 +204,21 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
151
204
|
const equals = 100 / this.panels.length;
|
|
152
205
|
return this.panels.map(() => equals);
|
|
153
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* 핸들 하나가 레이아웃에서 차지하는 두께(px). 렌더된 핸들을 재는 것이 정본이다 — CSS 가
|
|
209
|
+
* `max(--splitter-size, --splitter-hit-size)` 로 정하고 `rem` 등 어떤 단위든 올 수 있다.
|
|
210
|
+
* 아직 렌더되지 않았거나 숨겨져 0 이면 두 변수를 읽어 같은 규칙을 흉내 낸다.
|
|
211
|
+
*/
|
|
154
212
|
get splitterSize() {
|
|
155
|
-
const
|
|
156
|
-
|
|
213
|
+
const el = this.renderRoot?.querySelector(".splitter");
|
|
214
|
+
if (el) {
|
|
215
|
+
const r = el.getBoundingClientRect();
|
|
216
|
+
const measured = this.orientation === "horizontal" ? r.width : r.height;
|
|
217
|
+
if (measured > 0) return measured;
|
|
218
|
+
}
|
|
219
|
+
const style = getComputedStyle(this);
|
|
220
|
+
const read = (name, fallback) => parseFloat(style.getPropertyValue(name).trim()) || fallback;
|
|
221
|
+
return Math.max(read("--splitter-size", 4), read("--splitter-hit-size", 24));
|
|
157
222
|
}
|
|
158
223
|
get splitterCount() {
|
|
159
224
|
return Math.max(0, this.panels.length - 1);
|
|
@@ -165,6 +230,7 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
165
230
|
"defaultRatio",
|
|
166
231
|
"ratio"
|
|
167
232
|
].some((k) => changedProperties.has(k))) this.updatePanelLayout();
|
|
233
|
+
else if (changedProperties.has("disabled")) this.syncSplitterAria();
|
|
168
234
|
}
|
|
169
235
|
render() {
|
|
170
236
|
return html`
|
|
@@ -176,6 +242,12 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
176
242
|
</div>
|
|
177
243
|
`;
|
|
178
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* 호스트에 높이(또는 세로 분할이면 폭) 제약이 없으면 이 컴포넌트는 손잡이 두께로 붕괴한다 —
|
|
247
|
+
* 실측 18px(cycle-565). 호스트가 `overflow: hidden` 이라 패널 내용에 닿을 방법이 없고,
|
|
248
|
+
* 오류도 없다. 첫 배치 뒤 한 번 재서 개발 모드에서 알린다(HD-61 ⒝).
|
|
249
|
+
*/
|
|
250
|
+
warnIfCollapsed() {}
|
|
179
251
|
appendSplitters() {
|
|
180
252
|
const root = this.renderRoot;
|
|
181
253
|
if (!root) return;
|
|
@@ -185,6 +257,7 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
185
257
|
const splitter = this.createSplitter(i);
|
|
186
258
|
root.insertBefore(splitter, ref);
|
|
187
259
|
}
|
|
260
|
+
this.syncSplitterAria();
|
|
188
261
|
}
|
|
189
262
|
createSplitter(index) {
|
|
190
263
|
const el = document.createElement("div");
|
|
@@ -193,24 +266,67 @@ var USplitPanel = class USplitPanel extends UElement {
|
|
|
193
266
|
el.style.order = String(index * 2 + 1);
|
|
194
267
|
el.dataset.index = String(index);
|
|
195
268
|
if (this.splitter) el.appendChild(this.splitter.cloneNode(true));
|
|
269
|
+
el.setAttribute("role", "separator");
|
|
196
270
|
el.addEventListener("pointerdown", this.handlePointerDown);
|
|
197
271
|
el.addEventListener("dblclick", this.handleDblClick);
|
|
272
|
+
el.addEventListener("keydown", this.handleKeyDown);
|
|
198
273
|
return el;
|
|
199
274
|
}
|
|
275
|
+
/**
|
|
276
|
+
* 분할 핸들의 접근성 상태 — APG «Window Splitter». 핸들은 명령형으로 만들어 Lit 템플릿 밖에
|
|
277
|
+
* 있으므로, 비율·방향·비활성이 바뀔 때마다 여기서 다시 쓴다.
|
|
278
|
+
*
|
|
279
|
+
* 값은 **앞 패널(primary pane)의 몫**이다. 패널이 셋 이상이면 한 핸들은 이웃한 두 패널 사이만
|
|
280
|
+
* 옮기므로 최대값은 100 이 아니라 그 두 패널의 몫의 합이다.
|
|
281
|
+
*/
|
|
282
|
+
syncSplitterAria() {
|
|
283
|
+
const root = this.renderRoot;
|
|
284
|
+
if (!root) return;
|
|
285
|
+
const p = this.percentages;
|
|
286
|
+
const round = (v) => String(Math.round(v * 10) / 10);
|
|
287
|
+
const label = Locale.getValue("resizePanels");
|
|
288
|
+
root.querySelectorAll(".splitter").forEach((el) => {
|
|
289
|
+
const i = Number(el.dataset.index);
|
|
290
|
+
el.setAttribute("aria-valuenow", round(p[i] ?? 0));
|
|
291
|
+
el.setAttribute("aria-valuemin", "0");
|
|
292
|
+
el.setAttribute("aria-valuemax", round((p[i] ?? 0) + (p[i + 1] ?? 0)));
|
|
293
|
+
el.setAttribute("aria-orientation", this.orientation === "horizontal" ? "vertical" : "horizontal");
|
|
294
|
+
el.setAttribute("aria-label", label);
|
|
295
|
+
el.tabIndex = this.disabled ? -1 : 0;
|
|
296
|
+
if (this.disabled) el.setAttribute("aria-disabled", "true");
|
|
297
|
+
else el.removeAttribute("aria-disabled");
|
|
298
|
+
const reflect = el;
|
|
299
|
+
if ("ariaControlsElements" in reflect && this.panels[i]) reflect.ariaControlsElements = [this.panels[i]];
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
static {
|
|
303
|
+
this.KEY_STEP = 5;
|
|
304
|
+
}
|
|
200
305
|
updatePanelLayout() {
|
|
201
306
|
if (this.panels.length === 0) return;
|
|
202
307
|
const dim = this.orientation === "horizontal" ? "width" : "height";
|
|
203
308
|
const otherDim = this.orientation === "horizontal" ? "height" : "width";
|
|
204
309
|
const percentages = this.percentages;
|
|
205
|
-
const splitterOffset = this.splitterSize * (this.splitterCount / this.panels.length);
|
|
206
310
|
this.panels.forEach((panel, index) => {
|
|
207
|
-
panel.style[dim] =
|
|
311
|
+
panel.style[dim] = this.panelSize(percentages[index]);
|
|
208
312
|
panel.style[otherDim] = "";
|
|
209
313
|
panel.style.order = String(index * 2);
|
|
210
314
|
panel.style.boxSizing = "border-box";
|
|
211
315
|
panel.style.flexShrink = "0";
|
|
212
316
|
panel.style.overflow = "auto";
|
|
213
317
|
});
|
|
318
|
+
this.syncSplitterAria();
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* 패널 하나의 크기 — 비율은 «핸들을 뺀 나머지 공간»에 대한 몫이다.
|
|
322
|
+
*
|
|
323
|
+
* 🔴각 패널은 핸들 전체 두께 중 **자기 비율만큼**을 뺀다. 종전에는 핸들 몫을 패널 수로 똑같이
|
|
324
|
+
* 나눠 뺐는데(`p% - 핸들합/n`), 그 식은 비율이 균등할 때만 «나머지 공간의 p%» 와 같다. 드래그는
|
|
325
|
+
* 이동량을 나머지 공간 기준 비율로 바꾸므로(`availableSize`), 비율이 균등에서 멀어질수록 패널이
|
|
326
|
+
* 포인터보다 더 움직였다 — 핸들이 굵을수록 크게(24px 핸들이면 이동량의 약 9%).
|
|
327
|
+
*/
|
|
328
|
+
panelSize(percent) {
|
|
329
|
+
return `calc(${percent}% - ${this.splitterSize * this.splitterCount * percent / 100}px)`;
|
|
214
330
|
}
|
|
215
331
|
clampPair(aRaw, bRaw) {
|
|
216
332
|
const sum = aRaw + bRaw;
|
|
@@ -249,6 +365,6 @@ __decorate([property({
|
|
|
249
365
|
converter: arrayAttrConverter(parseFloat)
|
|
250
366
|
}), __decorateMetadata("design:type", Array)], USplitPanel.prototype, "ratio", void 0);
|
|
251
367
|
__decorate([query(".splitter-ghost"), __decorateMetadata("design:type", typeof HTMLElement === "undefined" ? Object : HTMLElement)], USplitPanel.prototype, "ghost", void 0);
|
|
252
|
-
USplitPanel = __decorate([customElement("u-split-panel")], USplitPanel);
|
|
368
|
+
USplitPanel = _USplitPanel = __decorate([customElement("u-split-panel")], USplitPanel);
|
|
253
369
|
//#endregion
|
|
254
370
|
export { USplitPanel };
|
|
@@ -3,9 +3,15 @@ import { css } from "lit";
|
|
|
3
3
|
var styles = css`
|
|
4
4
|
:host {
|
|
5
5
|
--splitter-size: 4px;
|
|
6
|
+
--splitter-hit-size: 24px;
|
|
6
7
|
--splitter-color: var(--u-neutral-200, #EEEEEE);
|
|
7
8
|
--splitter-color-hover: var(--u-primary-color-weaker, #64B5F6);
|
|
8
9
|
--splitter-color-active: var(--u-primary-color-strong, #1565C0);
|
|
10
|
+
|
|
11
|
+
/* The handle's box: the larger of the visible line and the pointer area. It takes real
|
|
12
|
+
layout space, so it never overlaps a panel — each panel is a scroll container and its
|
|
13
|
+
scrollbar sits right against the handle. */
|
|
14
|
+
--_splitter-box: max(var(--splitter-size), var(--splitter-hit-size));
|
|
9
15
|
}
|
|
10
16
|
|
|
11
17
|
:host {
|
|
@@ -27,7 +33,7 @@ var styles = css`
|
|
|
27
33
|
opacity: 0.4;
|
|
28
34
|
}
|
|
29
35
|
|
|
30
|
-
/* Splitter */
|
|
36
|
+
/* Splitter — the box receives the pointer; the line inside it is what you see */
|
|
31
37
|
.splitter {
|
|
32
38
|
position: relative;
|
|
33
39
|
z-index: 1;
|
|
@@ -35,24 +41,46 @@ var styles = css`
|
|
|
35
41
|
display: flex;
|
|
36
42
|
align-items: center;
|
|
37
43
|
justify-content: center;
|
|
44
|
+
touch-action: none;
|
|
45
|
+
}
|
|
46
|
+
.splitter::before {
|
|
47
|
+
content: "";
|
|
48
|
+
position: absolute;
|
|
49
|
+
z-index: -1;
|
|
38
50
|
background-color: var(--splitter-color);
|
|
39
51
|
transition: background-color var(--u-duration-fast, 140ms) var(--u-ease-standard, cubic-bezier(0.2, 0, 0, 1));
|
|
40
|
-
|
|
52
|
+
pointer-events: none;
|
|
41
53
|
}
|
|
42
|
-
.splitter:hover {
|
|
54
|
+
.splitter:hover::before {
|
|
43
55
|
background-color: var(--splitter-color-hover);
|
|
44
56
|
}
|
|
45
|
-
.splitter:active
|
|
57
|
+
.splitter:active::before,
|
|
58
|
+
.splitter:focus-visible::before {
|
|
46
59
|
background-color: var(--splitter-color-active);
|
|
47
60
|
}
|
|
61
|
+
/* The handle spans the host's full cross axis and the host clips overflow, so the base
|
|
62
|
+
focus ring (drawn 2px outside) would lose two of its sides. Draw it inside the box. */
|
|
63
|
+
.splitter:focus-visible {
|
|
64
|
+
outline-offset: -2px;
|
|
65
|
+
}
|
|
48
66
|
:host([orientation="horizontal"]) .splitter {
|
|
49
|
-
width: var(--
|
|
67
|
+
width: var(--_splitter-box);
|
|
50
68
|
cursor: col-resize;
|
|
51
69
|
}
|
|
70
|
+
:host([orientation="horizontal"]) .splitter::before {
|
|
71
|
+
inset-block: 0;
|
|
72
|
+
left: calc(50% - var(--splitter-size) / 2);
|
|
73
|
+
width: var(--splitter-size);
|
|
74
|
+
}
|
|
52
75
|
:host([orientation="vertical"]) .splitter {
|
|
53
|
-
height: var(--
|
|
76
|
+
height: var(--_splitter-box);
|
|
54
77
|
cursor: row-resize;
|
|
55
78
|
}
|
|
79
|
+
:host([orientation="vertical"]) .splitter::before {
|
|
80
|
+
inset-inline: 0;
|
|
81
|
+
top: calc(50% - var(--splitter-size) / 2);
|
|
82
|
+
height: var(--splitter-size);
|
|
83
|
+
}
|
|
56
84
|
|
|
57
85
|
/* Ghost Splitter (lazy) */
|
|
58
86
|
.splitter-ghost {
|
|
@@ -66,15 +94,18 @@ var styles = css`
|
|
|
66
94
|
.splitter-ghost[active] {
|
|
67
95
|
display: block;
|
|
68
96
|
}
|
|
97
|
+
/* The ghost is placed at the box's leading edge; the margin centres it on the line. */
|
|
69
98
|
:host([orientation="horizontal"]) .splitter-ghost {
|
|
70
99
|
top: 0;
|
|
71
100
|
width: var(--splitter-size);
|
|
72
101
|
height: 100%;
|
|
102
|
+
margin-left: calc((var(--_splitter-box) - var(--splitter-size)) / 2);
|
|
73
103
|
}
|
|
74
104
|
:host([orientation="vertical"]) .splitter-ghost {
|
|
75
105
|
left: 0;
|
|
76
106
|
width: 100%;
|
|
77
107
|
height: var(--splitter-size);
|
|
108
|
+
margin-top: calc((var(--_splitter-box) - var(--splitter-size)) / 2);
|
|
78
109
|
}
|
|
79
110
|
`;
|
|
80
111
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UFormControlElement } from "../UFormControlElement.js";
|
|
4
4
|
import { Locale } from "../../utilities/Locale.js";
|
|
5
5
|
import { styles } from "./USwitch.styles.js";
|
|
@@ -21,6 +21,11 @@ var styles = css`
|
|
|
21
21
|
:host {
|
|
22
22
|
display: inline-flex;
|
|
23
23
|
flex-direction: column;
|
|
24
|
+
/* WCAG 2.2 SC 2.5.8 — 트랙(--switch-track-height)의 시각 치수는 그대로 두고
|
|
25
|
+
포인터 타깃만 24px 하한을 갖는다. UCheckbox 와 같은 처방이다.
|
|
26
|
+
⚠이 주석에 백틱을 쓰면 css 템플릿이 그 자리에서 끝난다(sweep 의 「css 백틱」). */
|
|
27
|
+
min-block-size: 24px;
|
|
28
|
+
justify-content: center;
|
|
24
29
|
color: var(--u-txt-color, #212121);
|
|
25
30
|
font-size: inherit;
|
|
26
31
|
font-family: var(--u-font-base);
|
|
@@ -108,7 +113,7 @@ var styles = css`
|
|
|
108
113
|
.track-unchecked {
|
|
109
114
|
opacity: 1;
|
|
110
115
|
right: var(--switch-thumb-offset);
|
|
111
|
-
color: var(--u-txt-color-weak, #
|
|
116
|
+
color: var(--u-txt-color-weak, #616161);
|
|
112
117
|
}
|
|
113
118
|
:host([checked]) .track-unchecked {
|
|
114
119
|
opacity: 0;
|
|
@@ -166,7 +171,7 @@ var styles = css`
|
|
|
166
171
|
.thumb-unchecked {
|
|
167
172
|
opacity: 1;
|
|
168
173
|
transform: scale(1) rotate(0deg);
|
|
169
|
-
color: var(--u-txt-color-weak, #
|
|
174
|
+
color: var(--u-txt-color-weak, #616161);
|
|
170
175
|
}
|
|
171
176
|
:host([checked]) .thumb-unchecked {
|
|
172
177
|
opacity: 0;
|
|
@@ -185,7 +190,7 @@ var styles = css`
|
|
|
185
190
|
|
|
186
191
|
.description {
|
|
187
192
|
margin-top: 0.5em;
|
|
188
|
-
color: var(--u-txt-color-weak, #
|
|
193
|
+
color: var(--u-txt-color-weak, #616161);
|
|
189
194
|
font-size: 0.75em;
|
|
190
195
|
line-height: 1.3;
|
|
191
196
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
6
6
|
import { styles } from "./UTab.styles.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import { UPanel } from "../panel/UPanel.js";
|
|
5
5
|
import { UTab } from "../tab/UTab.js";
|
|
6
6
|
import { styles } from "./UTabPanel.styles.js";
|
|
@@ -45,7 +45,7 @@ var UTabPanel = class UTabPanel extends UElement {
|
|
|
45
45
|
const enabledTabs = this.tabs.filter((t) => !t.disabled);
|
|
46
46
|
const currentIndex = enabledTabs.indexOf(e.currentTarget);
|
|
47
47
|
if (currentIndex === -1) return;
|
|
48
|
-
let targetIndex
|
|
48
|
+
let targetIndex;
|
|
49
49
|
switch (e.key) {
|
|
50
50
|
case this.isVertical ? "ArrowDown" : "ArrowRight":
|
|
51
51
|
targetIndex = (currentIndex + 1) % enabledTabs.length;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../icon/UIcon.js";
|
|
5
5
|
import { statusIcon } from "../../utilities/statusIcon.js";
|
|
6
6
|
import { styles } from "./UTag.styles.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import { styles } from "./UText.styles.js";
|
|
5
5
|
import { customElement, property } from "lit/decorators.js";
|
|
6
6
|
import { html, literal } from "lit/static-html.js";
|
|
@@ -11,6 +11,11 @@ type TextareaResize = 'none' | 'vertical' | 'horizontal' | 'both' | 'auto';
|
|
|
11
11
|
* @csspart textarea - 실제 텍스트에어리어 요소
|
|
12
12
|
* @csspart counter - 글자 수 표시 영역
|
|
13
13
|
*
|
|
14
|
+
* @cssprop --u-textarea-display - 호스트의 display (기본값: inline-block). 폼/그리드 셀에서
|
|
15
|
+
* 컨테이너 폭을 채우려면 `block`으로 지정한다.
|
|
16
|
+
* @cssprop --u-textarea-width - 호스트의 width (기본값: auto). flex 컨테이너처럼 block만으로는
|
|
17
|
+
* 늘어나지 않는 맥락에서 `100%`로 지정한다.
|
|
18
|
+
*
|
|
14
19
|
* @event input - 입력값이 변경될 때 발생
|
|
15
20
|
* @event change - 값이 확정됐을 때 발생
|
|
16
21
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UFormControlElement } from "../UFormControlElement.js";
|
|
4
4
|
import { Locale } from "../../utilities/Locale.js";
|
|
5
5
|
import "../field/UField.js";
|
|
@@ -2,7 +2,10 @@ import { css } from "lit";
|
|
|
2
2
|
//#region src/components/textarea/UTextarea.styles.ts
|
|
3
3
|
var styles = css`
|
|
4
4
|
:host {
|
|
5
|
-
display:
|
|
5
|
+
/* 폼/그리드 셀에서 컨테이너 폭을 채우려면 소비자가 --u-textarea-display: block 을 준다.
|
|
6
|
+
flex 컨테이너처럼 block 만으로 늘어나지 않는 맥락을 위해 width 경로도 함께 연다. */
|
|
7
|
+
display: var(--u-textarea-display, inline-block);
|
|
8
|
+
width: var(--u-textarea-width, auto);
|
|
6
9
|
color: var(--u-txt-color, #212121);
|
|
7
10
|
font-size: inherit;
|
|
8
11
|
font-family: var(--u-font-base);
|
|
@@ -117,7 +120,7 @@ var styles = css`
|
|
|
117
120
|
word-wrap: break-word;
|
|
118
121
|
}
|
|
119
122
|
textarea::placeholder {
|
|
120
|
-
color: var(--u-txt-color-weak, #
|
|
123
|
+
color: var(--u-txt-color-weak, #616161);
|
|
121
124
|
}
|
|
122
125
|
textarea:disabled {
|
|
123
126
|
cursor: not-allowed;
|
|
@@ -155,7 +158,7 @@ var styles = css`
|
|
|
155
158
|
.counter {
|
|
156
159
|
margin-top: 0.25em;
|
|
157
160
|
text-align: right;
|
|
158
|
-
color: var(--u-txt-color-weak, #
|
|
161
|
+
color: var(--u-txt-color-weak, #616161);
|
|
159
162
|
font-size: 0.75em;
|
|
160
163
|
line-height: 1.2;
|
|
161
164
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
1
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UFloatingElement } from "../UFloatingElement.js";
|
|
4
4
|
import { styles } from "./UTooltip.styles.js";
|
|
5
5
|
import { html } from "lit";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import { UTreeItem } from "../tree-item/UTreeItem.js";
|
|
5
5
|
import { styles } from "./UTree.styles.js";
|
|
6
6
|
import { html } from "lit";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.
|
|
3
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.149.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../spinner/USpinner.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
6
6
|
import { styles } from "./UTreeItem.styles.js";
|