@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.
Files changed (108) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/README.md +24 -0
  3. package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorate.js +1 -1
  4. package/dist/_virtual/{_@oxc-project_runtime@0.148.0 → _@oxc-project_runtime@0.149.0}/helpers/esm/decorateMetadata.js +1 -1
  5. package/dist/_virtual/_glob-assets_raw/dark.css.e8ac080d.js +1 -1
  6. package/dist/_virtual/_glob-assets_raw/light.css.637cb2f8.js +1 -1
  7. package/dist/assets/locales/ar.json.js +6 -2
  8. package/dist/assets/locales/de.json.js +6 -2
  9. package/dist/assets/locales/en.json.js +6 -2
  10. package/dist/assets/locales/es.json.js +6 -2
  11. package/dist/assets/locales/fr.json.js +6 -2
  12. package/dist/assets/locales/id.json.js +6 -2
  13. package/dist/assets/locales/ja.json.js +6 -2
  14. package/dist/assets/locales/ko.json.js +6 -2
  15. package/dist/assets/locales/pt-BR.json.js +6 -2
  16. package/dist/assets/locales/ru.json.js +6 -2
  17. package/dist/assets/locales/th.json.js +6 -2
  18. package/dist/assets/locales/vi.json.js +6 -2
  19. package/dist/assets/locales/zh-CN.json.js +6 -2
  20. package/dist/assets/locales/zh-TW.json.js +6 -2
  21. package/dist/components/UFloatingElement.js +2 -2
  22. package/dist/components/UFormControlElement.js +2 -2
  23. package/dist/components/UOverlayElement.js +2 -2
  24. package/dist/components/alert/UAlert.js +2 -2
  25. package/dist/components/avatar/UAvatar.js +2 -2
  26. package/dist/components/badge/UBadge.js +2 -2
  27. package/dist/components/breadcrumb/UBreadcrumb.js +1 -1
  28. package/dist/components/breadcrumb/UBreadcrumb.styles.js +1 -1
  29. package/dist/components/breadcrumb-item/UBreadcrumbItem.js +2 -2
  30. package/dist/components/breadcrumb-item/UBreadcrumbItem.styles.js +1 -1
  31. package/dist/components/button/UButton.js +2 -2
  32. package/dist/components/button-group/UButtonGroup.js +2 -2
  33. package/dist/components/card/UCard.js +2 -2
  34. package/dist/components/carousel/UCarousel.js +2 -2
  35. package/dist/components/checkbox/UCheckbox.js +2 -2
  36. package/dist/components/checkbox/UCheckbox.styles.js +7 -1
  37. package/dist/components/chip/UChip.js +2 -2
  38. package/dist/components/chip/UChip.styles.js +7 -0
  39. package/dist/components/copy-button/UCopyButton.js +2 -2
  40. package/dist/components/date-picker/UDatePicker.js +2 -2
  41. package/dist/components/date-picker/UDatePicker.styles.js +2 -2
  42. package/dist/components/dialog/UDialog.js +2 -2
  43. package/dist/components/divider/UDivider.js +2 -2
  44. package/dist/components/divider/UDivider.styles.js +1 -1
  45. package/dist/components/drawer/UDrawer.js +2 -2
  46. package/dist/components/expander/UExpander.js +2 -2
  47. package/dist/components/expander/UExpander.styles.js +1 -1
  48. package/dist/components/field/UField.js +2 -2
  49. package/dist/components/field/UField.styles.js +1 -1
  50. package/dist/components/file-input/UFileInput.js +2 -2
  51. package/dist/components/file-input/UFileInput.styles.js +2 -2
  52. package/dist/components/form/UForm.js +2 -2
  53. package/dist/components/icon/UIcon.js +13 -6
  54. package/dist/components/icon-button/UIconButton.js +2 -2
  55. package/dist/components/input/UInput.d.ts +15 -1
  56. package/dist/components/input/UInput.js +62 -12
  57. package/dist/components/input/UInput.styles.js +25 -6
  58. package/dist/components/menu/UMenu.js +2 -2
  59. package/dist/components/menu-item/UMenuItem.js +2 -2
  60. package/dist/components/option/UOption.js +2 -2
  61. package/dist/components/panel/UPanel.js +2 -2
  62. package/dist/components/popover/UPopover.js +23 -7
  63. package/dist/components/progress-bar/UProgressBar.js +2 -2
  64. package/dist/components/progress-ring/UProgressRing.js +2 -2
  65. package/dist/components/radio/URadio.js +2 -2
  66. package/dist/components/rating/URating.js +2 -2
  67. package/dist/components/rating/URating.styles.js +6 -0
  68. package/dist/components/select/USelect.d.ts +7 -1
  69. package/dist/components/select/USelect.js +19 -8
  70. package/dist/components/select/USelect.styles.js +18 -5
  71. package/dist/components/skeleton/USkeleton.js +2 -2
  72. package/dist/components/slider/USlider.d.ts +3 -1
  73. package/dist/components/slider/USlider.js +2 -2
  74. package/dist/components/slider/USlider.styles.js +19 -2
  75. package/dist/components/spinner/USpinner.js +2 -2
  76. package/dist/components/split-panel/USplitPanel.d.ts +43 -2
  77. package/dist/components/split-panel/USplitPanel.js +127 -11
  78. package/dist/components/split-panel/USplitPanel.styles.js +37 -6
  79. package/dist/components/switch/USwitch.js +2 -2
  80. package/dist/components/switch/USwitch.styles.js +8 -3
  81. package/dist/components/tab/UTab.js +2 -2
  82. package/dist/components/tab/UTab.styles.js +1 -1
  83. package/dist/components/tab-panel/UTabPanel.js +3 -3
  84. package/dist/components/tag/UTag.js +2 -2
  85. package/dist/components/text/UText.js +2 -2
  86. package/dist/components/text/UText.styles.js +1 -1
  87. package/dist/components/textarea/UTextarea.d.ts +5 -0
  88. package/dist/components/textarea/UTextarea.js +2 -2
  89. package/dist/components/textarea/UTextarea.styles.js +6 -3
  90. package/dist/components/tooltip/UTooltip.js +2 -2
  91. package/dist/components/tree/UTree.js +2 -2
  92. package/dist/components/tree-item/UTreeItem.js +2 -2
  93. package/dist/components/tree-item/UTreeItem.styles.js +50 -13
  94. package/dist/styles/dark.css +4 -1
  95. package/dist/styles/light.css +7 -4
  96. package/dist/utilities/Locale.d.ts +1 -1
  97. package/dist/utilities/Toast.d.ts +34 -0
  98. package/dist/utilities/Toast.js +57 -0
  99. package/dist/utilities/devWarning.d.ts +17 -0
  100. package/dist/utilities/devWarning.js +5 -0
  101. package/package.json +4 -4
  102. package/skills/iyulab-components/references/components/dialog.md +19 -0
  103. package/skills/iyulab-components/references/components/input.md +17 -0
  104. package/skills/iyulab-components/references/components/panel.md +12 -0
  105. package/skills/iyulab-components/references/components/select.md +9 -0
  106. package/skills/iyulab-components/references/components/slider.md +1 -1
  107. package/skills/iyulab-components/references/components/split-panel.md +41 -3
  108. 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 - 스플리터 크기 (default: 4px)
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.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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
- const offset = this.splitterSize * (this.splitterCount / this.panels.length);
95
- this.panels[aIdx].style[dim] = `calc(${aPercent}% - ${offset}px)`;
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 source = this.ratio.length === this.panels.length ? this.ratio : this.defaultRatio.length === this.panels.length ? this.defaultRatio : [];
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 sizeStr = getComputedStyle(this).getPropertyValue("--splitter-size").trim();
156
- return parseFloat(sizeStr) || 4;
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] = `calc(${percentages[index]}% - ${splitterOffset}px)`;
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
- touch-action: none;
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(--splitter-size);
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(--splitter-size);
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.148.0/helpers/esm/decorateMetadata.js";
2
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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, #757575);
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, #757575);
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, #757575);
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.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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";
@@ -7,7 +7,7 @@ var styles = css`
7
7
  display: inline-flex;
8
8
  font-size: 0.9em;
9
9
  font-weight: 500;
10
- color: var(--u-txt-color-weak, #757575);
10
+ color: var(--u-txt-color-weak, #616161);
11
11
  white-space: nowrap;
12
12
  user-select: none;
13
13
  cursor: pointer;
@@ -1,6 +1,6 @@
1
1
  import { UElement } from "../UElement.js";
2
- import __decorateMetadata from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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 = -1;
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.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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";
@@ -76,7 +76,7 @@ var styles = css`
76
76
  * 콜아웃 박스라 u-text 의 문제가 아니었다.
77
77
  */
78
78
  :host([tone="weak"]) {
79
- color: var(--u-txt-color-weak, #757575);
79
+ color: var(--u-txt-color-weak, #616161);
80
80
  }
81
81
 
82
82
  :host([tone="strong"]) {
@@ -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.148.0/helpers/esm/decorateMetadata.js";
2
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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: inline-block;
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, #757575);
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, #757575);
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.148.0/helpers/esm/decorateMetadata.js";
2
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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.148.0/helpers/esm/decorateMetadata.js";
3
- import __decorate from "../../_virtual/_@oxc-project_runtime@0.148.0/helpers/esm/decorate.js";
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";