@iyulab/components 1.40.3 → 1.41.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 +68 -0
- package/README.md +31 -0
- package/dist/_virtual/{_@oxc-project_runtime@0.149.0 → _@oxc-project_runtime@0.150.0}/helpers/esm/decorate.js +1 -1
- package/dist/_virtual/{_@oxc-project_runtime@0.149.0 → _@oxc-project_runtime@0.150.0}/helpers/esm/decorateMetadata.js +1 -1
- package/dist/components/UFloatingElement.js +2 -2
- package/dist/components/UFormControlElement.d.ts +36 -0
- package/dist/components/UFormControlElement.js +58 -3
- 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-item/UBreadcrumbItem.js +2 -2
- 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 +5 -3
- package/dist/components/chip/UChip.js +2 -2
- package/dist/components/copy-button/UCopyButton.js +2 -2
- package/dist/components/date-picker/UDatePicker.js +4 -4
- package/dist/components/dialog/UDialog.js +2 -2
- package/dist/components/divider/UDivider.js +2 -2
- package/dist/components/drawer/UDrawer.js +2 -2
- package/dist/components/expander/UExpander.js +2 -2
- package/dist/components/field/UField.d.ts +74 -0
- package/dist/components/field/UField.js +138 -5
- package/dist/components/file-input/UFileInput.d.ts +11 -0
- package/dist/components/file-input/UFileInput.js +17 -2
- package/dist/components/form/UForm.js +2 -2
- package/dist/components/icon/UIcon.js +2 -2
- package/dist/components/icon-button/UIconButton.js +2 -2
- package/dist/components/input/UInput.js +4 -4
- 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 +2 -2
- package/dist/components/progress-bar/UProgressBar.js +2 -2
- package/dist/components/progress-ring/UProgressRing.js +2 -2
- package/dist/components/radio/URadio.js +4 -4
- package/dist/components/rating/URating.js +4 -4
- package/dist/components/select/USelect.js +5 -5
- package/dist/components/skeleton/USkeleton.js +2 -2
- package/dist/components/slider/USlider.js +3 -3
- package/dist/components/spinner/USpinner.js +2 -2
- package/dist/components/split-panel/USplitPanel.js +2 -2
- package/dist/components/switch/USwitch.js +11 -3
- package/dist/components/tab/UTab.js +2 -2
- package/dist/components/tab-panel/UTabPanel.js +2 -2
- package/dist/components/tag/UTag.js +2 -2
- package/dist/components/text/UText.js +2 -2
- package/dist/components/textarea/UTextarea.js +4 -4
- 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/utilities/accent.d.ts +1 -1
- package/dist/utilities/accent.js +1 -1
- package/package.json +3 -3
- package/skills/iyulab-components/references/components/field.md +42 -0
- package/skills/iyulab-components/references/components/switch.md +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,73 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.41.1] - 2026-09-16
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **The development-mode warning that reports an unnamed field fired on correctly built forms**
|
|
8
|
+
whenever the field was first rendered inside a hidden container — a closed drawer, a collapsed
|
|
9
|
+
accordion, an inactive tab panel, a wizard step that is not current. The check asked whether the
|
|
10
|
+
slotted subtree held anything *focusable*, and the focusability test it used considers an element
|
|
11
|
+
that is not rendered to be unfocusable. Whether a label has a control to name is a question about
|
|
12
|
+
structure, not about what is on screen right now, so the check now answers it structurally
|
|
13
|
+
(form-associated custom element, native form/focusable tag, `tabindex`, `contenteditable`) and no
|
|
14
|
+
longer consults visibility or `disabled`. Focus delegation still uses the focusability test, which
|
|
15
|
+
is the right question there. Consequently the warning text now reads "has no form control" rather
|
|
16
|
+
than "has no focusable control".
|
|
17
|
+
- **A false warning silenced the real ones.** These warnings de-duplicate per key, and both field
|
|
18
|
+
warnings used one flat key each, so the first occurrence on a page consumed the budget for every
|
|
19
|
+
later field — a spurious warning permanently suppressed genuine ones, and even without any false
|
|
20
|
+
positive only the first of several real violations was ever reported. Both keys now include the
|
|
21
|
+
label, matching `u-icon` and `u-split-panel`, which already key by what distinguishes the case.
|
|
22
|
+
|
|
23
|
+
## [1.41.0] - 2026-09-16
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **`u-field` drew its label but never connected it to the control it wraps** — the shadow `label`
|
|
28
|
+
had no `for`, and the slotted control's `id`, `aria-label` and `aria-labelledby` were all empty.
|
|
29
|
+
Every control in a labelled form was therefore unnamed in the accessibility tree while looking
|
|
30
|
+
completely normal on screen, with no console signal. This is the exact shape this package's own
|
|
31
|
+
reference documentation teaches (`<u-field label="Email"><u-input></u-input></u-field>`), so
|
|
32
|
+
following the docs produced the defect. `u-field` now copies its `label` onto the slotted element
|
|
33
|
+
as `aria-label` (and `description` as `aria-description`); `aria-labelledby` is not usable here
|
|
34
|
+
because it does not cross shadow boundaries.
|
|
35
|
+
- **`u-field.focus()` and clicking its label did nothing when a custom-element control was
|
|
36
|
+
slotted** — the target search used a focusability test that does not look inside shadow roots, so
|
|
37
|
+
it only ever matched native elements. It now also recognizes form-associated custom elements, and
|
|
38
|
+
falls back to searching inside a slotted wrapper.
|
|
39
|
+
- **`u-switch` ignored its inherited `label` property** — unlike its sibling `u-checkbox`, the
|
|
40
|
+
default slot had no fallback, so `<u-switch label="…">` rendered neither a visible label nor an
|
|
41
|
+
accessible name.
|
|
42
|
+
- **A field label did not reach `u-checkbox`, `u-switch` or `u-file-input`.** Those three take
|
|
43
|
+
their accessible name from their own content — the first two wrap the native control in a
|
|
44
|
+
`<label>`, and the third's focusable element is a "choose file" button — so the mechanism that
|
|
45
|
+
works for the other seven controls did nothing for them. An empty checkbox or switch inside a
|
|
46
|
+
labelled field was named by nothing but its required marker. They now take the field's label
|
|
47
|
+
when, and only when, they have no name of their own.
|
|
48
|
+
|
|
49
|
+
### Added
|
|
50
|
+
|
|
51
|
+
- **Form controls now forward a host `aria-label` / `aria-description` to the native control inside
|
|
52
|
+
their shadow root.** Previously only `u-button` did this, so setting `aria-label` directly on
|
|
53
|
+
`u-input`, `u-select`, `u-textarea`, `u-date-picker`, `u-radio`, `u-rating` or `u-slider` had no
|
|
54
|
+
effect on the accessible name. A control's own `label` still wins over the host attribute.
|
|
55
|
+
- **Two development-mode warnings on `u-field`**: a label with nothing focusable in the default
|
|
56
|
+
slot (the label names nothing), and a label set on both the field and the slotted control (the
|
|
57
|
+
label renders twice).
|
|
58
|
+
|
|
59
|
+
### Notes
|
|
60
|
+
|
|
61
|
+
- A control that already carries its own `label`, `aria-label` or `aria-labelledby` is left
|
|
62
|
+
untouched — overriding it would make the visible label and the accessible name disagree
|
|
63
|
+
(WCAG SC 2.5.3 Label in Name).
|
|
64
|
+
- `u-file-input` **composes** rather than overrides: its trigger is named "<visible text>,
|
|
65
|
+
<field label>", so the visible text stays part of the accessible name (SC 2.5.3) while several
|
|
66
|
+
file pickers on one screen remain distinguishable.
|
|
67
|
+
- All ten form controls are covered by a reach gate that drives each one in a real browser
|
|
68
|
+
(`tests/browser/field-name-reach-census.browser.test.ts`). A new form control has to be added to
|
|
69
|
+
that table or it sits outside the gate.
|
|
70
|
+
|
|
3
71
|
## [1.40.3] - 2026-09-13
|
|
4
72
|
|
|
5
73
|
### Fixed
|
package/README.md
CHANGED
|
@@ -128,6 +128,37 @@ Theme.set('system');
|
|
|
128
128
|
|
|
129
129
|
자세한 내용은 [docs/theming.md](./docs/theming.md)를 참고하세요.
|
|
130
130
|
|
|
131
|
+
## Accessibility
|
|
132
|
+
|
|
133
|
+
기준판은 **WCAG 2.2** 입니다. 아래는 이 패키지가 **테스트로 재서 보장하는 것**이고, 그 밖의
|
|
134
|
+
성공 기준까지 포함한 전체 준수 선언이 아닙니다.
|
|
135
|
+
|
|
136
|
+
| 성공 기준 | 보장 | 어디서 재는가 |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| SC 1.4.3 · 1.4.11 명암비 | 역할 토큰의 `-color`·`-color-strong`·`-bg-color` 단계가 텍스트 4.5 / 비텍스트 3.0 을 라이트·다크 양쪽에서 충족 | `tests/build/token-contrast.test.ts` |
|
|
139
|
+
| SC 2.5.8 타깃 크기(최소) | 등록된 모든 컴포넌트의 포인터 타깃이 24×24 CSS px 이상이거나 간격 예외(중심 간 24px)를 충족하고, 그 좌표에서 실제로 눌린다 | `tests/browser/target-size.browser.test.ts`(실제 크로미움) |
|
|
140
|
+
| SC 2.1.1 키보드(포인터 커서 검사) | 픽스처가 그리는 어떤 요소도 포인터 커서를 보이면서 상호작용 요소가 아닌 채로 있지 않다 — 클릭만 받는 `div` 가 들어오지 못한다(키 처리 자체는 컴포넌트 테스트가 잰다) | 같은 파일 |
|
|
141
|
+
| SC 1.3.1 정보와 관계 · SC 4.1.2 이름·역할·값 | `u-field` 의 `label`/`description` 이 슬롯된 컨트롤의 접근성 이름·설명으로 실제로 도달한다(네이티브 엘리먼트 · `u-*` 폼 컨트롤 양쪽) | `tests/browser/field-label-association.browser.test.ts` |
|
|
142
|
+
|
|
143
|
+
🔴**폼 컨트롤의 접근성 이름은 «한 곳에서만» 준다.** `u-field` 는 자기 `label` 을 슬롯된 컨트롤에
|
|
144
|
+
`aria-label` 로 얹고(섀도우 경계를 넘지 못하는 `aria-labelledby` 대신 문자열 복사다), 폼 컨트롤은
|
|
145
|
+
호스트의 `aria-label` 을 내부 네이티브 컨트롤로 내려보낸다. **컨트롤이 자기 `label`·`aria-label`·
|
|
146
|
+
`aria-labelledby` 를 이미 가지면 `u-field` 는 덮지 않는다** — 덮으면 눈에 보이는 라벨과 접근성
|
|
147
|
+
이름이 어긋난다(SC 2.5.3 Label in Name). 양쪽에 `label` 을 주면 라벨이 **두 번 그려지고**, 개발
|
|
148
|
+
모드 콘솔이 그 자리를 지목한다.
|
|
149
|
+
|
|
150
|
+
```html
|
|
151
|
+
<!-- ✅ 라벨은 한 곳 -->
|
|
152
|
+
<u-field label="Keyword"><u-input></u-input></u-field>
|
|
153
|
+
<u-input label="Keyword"></u-input>
|
|
154
|
+
|
|
155
|
+
<!-- ❌ 두 번 그려진다 -->
|
|
156
|
+
<u-field label="Keyword"><u-input label="Keyword"></u-input></u-field>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
⚠ 타깃 크기 보장은 `--u-density` **`14px` 이상**에서 성립합니다 — 컨트롤 패딩이 `em` 이라 그보다
|
|
160
|
+
낮추면 타깃이 함께 줄어듭니다([docs/theming.md](./docs/theming.md)의 밀도 절 참고).
|
|
161
|
+
|
|
131
162
|
## Localization
|
|
132
163
|
|
|
133
164
|
라이브러리가 **스스로 생성하는 문자열**(검증 메시지)은 내장 로케일 14종을 갖고 있으며,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
|
|
2
2
|
function __decorate(decorators, target, key, desc) {
|
|
3
3
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
4
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//#region \0@oxc-project+runtime@0.
|
|
1
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorateMetadata.js
|
|
2
2
|
function __decorateMetadata(k, v) {
|
|
3
3
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
4
4
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { UElement } from "./UElement.js";
|
|
2
2
|
import { getParentElement, querySelectorAllWithin } from "../utilities/elements.js";
|
|
3
3
|
import { styles } from "./UFloatingElement.styles.js";
|
|
4
|
-
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.
|
|
5
|
-
import __decorate from "../_virtual/_@oxc-project_runtime@0.
|
|
4
|
+
import __decorateMetadata from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorateMetadata.js";
|
|
5
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
6
6
|
import { property, state } from "lit/decorators.js";
|
|
7
7
|
import { arrow, autoPlacement, autoUpdate, computePosition, flip, hide, offset, shift } from "@floating-ui/dom";
|
|
8
8
|
//#region src/components/UFloatingElement.ts
|
|
@@ -62,6 +62,42 @@ export declare abstract class UFormControlElement<T> extends UElement {
|
|
|
62
62
|
*/
|
|
63
63
|
protected commit(flags: ValidityStateFlags, message: string, anchor?: HTMLElement): void;
|
|
64
64
|
connectedCallback(): void;
|
|
65
|
+
/**
|
|
66
|
+
* 호스트에 세팅된 `aria-label`/`aria-description` 은 접근성 트리에 노출되는 노드가 아니다 —
|
|
67
|
+
* 그것은 shadow DOM 안쪽의 네이티브 컨트롤이고, 섀도우 경계를 넘지 않으므로 자동으로
|
|
68
|
+
* 반영되지 않는다(속성은 붙어 있는데 접근 가능한 이름이 빈 채로 남는다).
|
|
69
|
+
*
|
|
70
|
+
* ⚠**이 처방은 오랫동안 `u-button` 한 곳에만 있었다.** 폼 컨트롤 열 종이 같은 구조인데
|
|
71
|
+
* 같은 경로가 없어서, 바깥에서 라벨을 소유하는 래퍼(`u-field`)가 슬롯된 컨트롤에 이름을
|
|
72
|
+
* 줄 수단 자체가 없었다 — 라벨은 그려지는데 컨트롤은 이름이 없는 «조용한 결함» 이다.
|
|
73
|
+
* ⇒ 사본을 열 벌 만드는 대신 **공통 기반에 한 번** 둔다.
|
|
74
|
+
*
|
|
75
|
+
* ⚠`aria-label` 은 Lit 리액티브 프로퍼티가 아니라 `observedAttributes` 에 없다 — 그 목록에
|
|
76
|
+
* 없는 속성은 `attributeChangedCallback` 자체가 호출되지 않아(커스텀 엘리먼트 표준 동작)
|
|
77
|
+
* 초기 렌더만 되고 연결 후 변경이 반영되지 않는다. 명시적으로 추가해야 한다.
|
|
78
|
+
*/
|
|
79
|
+
static get observedAttributes(): string[];
|
|
80
|
+
attributeChangedCallback(name: string, old: string | null, value: string | null): void;
|
|
81
|
+
/**
|
|
82
|
+
* 내부 네이티브 컨트롤에 실을 접근성 이름. 자기 `label` 이 우선이고, 없으면 호스트의
|
|
83
|
+
* `aria-label` 을 쓴다 — 후자는 `u-field` 같은 «바깥 라벨 소유자» 가 채우는 경로다.
|
|
84
|
+
*/
|
|
85
|
+
protected get resolvedAriaLabel(): string | undefined;
|
|
86
|
+
/**
|
|
87
|
+
* 이름을 **자기 내용에서** 얻는 컨트롤(`u-checkbox`·`u-switch`)용 축.
|
|
88
|
+
*
|
|
89
|
+
* 그 둘은 네이티브 `<label>` 이 컨트롤을 감싸는 구조라, 감싸개 안의 텍스트가 곧 접근성
|
|
90
|
+
* 이름이다 — 그래서 위 `resolvedAriaLabel` 처럼 **무조건** 얹으면 눈에 보이는 라벨을
|
|
91
|
+
* 덮어쓴다(WCAG SC 2.5.3 Label in Name). ⇒ 자기 `label` 도 슬롯 내용도 없어서 감싸개가
|
|
92
|
+
* **비어 있을 때만** 호스트의 `aria-label` 을 쓴다. 전수 실측에서 라벨을 단 `u-field`
|
|
93
|
+
* 안에 빈 체크박스/스위치를 넣으면 이름이 «별표 하나» 뿐이었다.
|
|
94
|
+
*/
|
|
95
|
+
protected get contentAriaLabel(): string | undefined;
|
|
96
|
+
protected hasSlottedLabel: boolean;
|
|
97
|
+
/** 기본 슬롯에 실제 내용이 들어왔는지 — 공백만 있는 텍스트 노드는 내용이 아니다. */
|
|
98
|
+
protected handleLabelSlotChange: (e: Event) => void;
|
|
99
|
+
/** `resolvedAriaLabel` 과 같은 규칙의 설명 축. */
|
|
100
|
+
protected get resolvedAriaDescription(): string | undefined;
|
|
65
101
|
protected updated(changedProperties: PropertyValues): void;
|
|
66
102
|
/**
|
|
67
103
|
* 어떤 속성이 바뀌었을 때 `setValidity()`를 다시 호출할지 결정합니다.
|
|
@@ -1,8 +1,8 @@
|
|
|
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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { styles } from "./UFormControlElement.styles.js";
|
|
5
|
-
import { property } from "lit/decorators.js";
|
|
5
|
+
import { property, state } from "lit/decorators.js";
|
|
6
6
|
//#region src/components/UFormControlElement.ts
|
|
7
7
|
/**
|
|
8
8
|
* 폼 컨트롤 컴포넌트의 공통 기반 클래스입니다.
|
|
@@ -17,6 +17,11 @@ var UFormControlElement = class extends UElement {
|
|
|
17
17
|
this.invalid = false;
|
|
18
18
|
this.novalidate = false;
|
|
19
19
|
this.customMessage = "";
|
|
20
|
+
this.hasSlottedLabel = false;
|
|
21
|
+
this.handleLabelSlotChange = (e) => {
|
|
22
|
+
const slot = e.target;
|
|
23
|
+
this.hasSlottedLabel = slot.assignedNodes({ flatten: true }).some((n) => n.nodeType === Node.ELEMENT_NODE || !!n.textContent?.trim());
|
|
24
|
+
};
|
|
20
25
|
}
|
|
21
26
|
static {
|
|
22
27
|
this.styles = [super.styles, styles];
|
|
@@ -68,6 +73,55 @@ var UFormControlElement = class extends UElement {
|
|
|
68
73
|
super.connectedCallback();
|
|
69
74
|
if (!this.internals && "attachInternals" in this) this.internals = this.attachInternals();
|
|
70
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* 호스트에 세팅된 `aria-label`/`aria-description` 은 접근성 트리에 노출되는 노드가 아니다 —
|
|
78
|
+
* 그것은 shadow DOM 안쪽의 네이티브 컨트롤이고, 섀도우 경계를 넘지 않으므로 자동으로
|
|
79
|
+
* 반영되지 않는다(속성은 붙어 있는데 접근 가능한 이름이 빈 채로 남는다).
|
|
80
|
+
*
|
|
81
|
+
* ⚠**이 처방은 오랫동안 `u-button` 한 곳에만 있었다.** 폼 컨트롤 열 종이 같은 구조인데
|
|
82
|
+
* 같은 경로가 없어서, 바깥에서 라벨을 소유하는 래퍼(`u-field`)가 슬롯된 컨트롤에 이름을
|
|
83
|
+
* 줄 수단 자체가 없었다 — 라벨은 그려지는데 컨트롤은 이름이 없는 «조용한 결함» 이다.
|
|
84
|
+
* ⇒ 사본을 열 벌 만드는 대신 **공통 기반에 한 번** 둔다.
|
|
85
|
+
*
|
|
86
|
+
* ⚠`aria-label` 은 Lit 리액티브 프로퍼티가 아니라 `observedAttributes` 에 없다 — 그 목록에
|
|
87
|
+
* 없는 속성은 `attributeChangedCallback` 자체가 호출되지 않아(커스텀 엘리먼트 표준 동작)
|
|
88
|
+
* 초기 렌더만 되고 연결 후 변경이 반영되지 않는다. 명시적으로 추가해야 한다.
|
|
89
|
+
*/
|
|
90
|
+
static get observedAttributes() {
|
|
91
|
+
return [
|
|
92
|
+
...super.observedAttributes,
|
|
93
|
+
"aria-label",
|
|
94
|
+
"aria-description"
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
attributeChangedCallback(name, old, value) {
|
|
98
|
+
super.attributeChangedCallback(name, old, value);
|
|
99
|
+
if (name === "aria-label" || name === "aria-description") this.requestUpdate();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 내부 네이티브 컨트롤에 실을 접근성 이름. 자기 `label` 이 우선이고, 없으면 호스트의
|
|
103
|
+
* `aria-label` 을 쓴다 — 후자는 `u-field` 같은 «바깥 라벨 소유자» 가 채우는 경로다.
|
|
104
|
+
*/
|
|
105
|
+
get resolvedAriaLabel() {
|
|
106
|
+
return this.label ?? this.getAttribute("aria-label") ?? void 0;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* 이름을 **자기 내용에서** 얻는 컨트롤(`u-checkbox`·`u-switch`)용 축.
|
|
110
|
+
*
|
|
111
|
+
* 그 둘은 네이티브 `<label>` 이 컨트롤을 감싸는 구조라, 감싸개 안의 텍스트가 곧 접근성
|
|
112
|
+
* 이름이다 — 그래서 위 `resolvedAriaLabel` 처럼 **무조건** 얹으면 눈에 보이는 라벨을
|
|
113
|
+
* 덮어쓴다(WCAG SC 2.5.3 Label in Name). ⇒ 자기 `label` 도 슬롯 내용도 없어서 감싸개가
|
|
114
|
+
* **비어 있을 때만** 호스트의 `aria-label` 을 쓴다. 전수 실측에서 라벨을 단 `u-field`
|
|
115
|
+
* 안에 빈 체크박스/스위치를 넣으면 이름이 «별표 하나» 뿐이었다.
|
|
116
|
+
*/
|
|
117
|
+
get contentAriaLabel() {
|
|
118
|
+
if (this.label || this.hasSlottedLabel) return void 0;
|
|
119
|
+
return this.getAttribute("aria-label") ?? void 0;
|
|
120
|
+
}
|
|
121
|
+
/** `resolvedAriaLabel` 과 같은 규칙의 설명 축. */
|
|
122
|
+
get resolvedAriaDescription() {
|
|
123
|
+
return this.description ?? this.getAttribute("aria-description") ?? void 0;
|
|
124
|
+
}
|
|
71
125
|
updated(changedProperties) {
|
|
72
126
|
super.updated(changedProperties);
|
|
73
127
|
if (this.shouldValidate(changedProperties)) this.setValidity();
|
|
@@ -117,5 +171,6 @@ __decorate([property({ type: String }), __decorateMetadata("design:type", String
|
|
|
117
171
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "description", void 0);
|
|
118
172
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UFormControlElement.prototype, "name", void 0);
|
|
119
173
|
__decorate([property(), __decorateMetadata("design:type", Object)], UFormControlElement.prototype, "value", void 0);
|
|
174
|
+
__decorate([state(), __decorateMetadata("design:type", Object)], UFormControlElement.prototype, "hasSlottedLabel", void 0);
|
|
120
175
|
//#endregion
|
|
121
176
|
export { UFormControlElement };
|
|
@@ -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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { OverlayManager } from "../utilities/OverlayManager.js";
|
|
5
5
|
import { arrayAttrConverter } from "../utilities/converters.js";
|
|
6
6
|
import { styles } from "./UOverlayElement.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
6
6
|
import { styles } from "./UAlert.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { styles } from "./UAvatar.styles.js";
|
|
5
5
|
import { html } from "lit";
|
|
6
6
|
import { customElement, property } from "lit/decorators.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../icon/UIcon.js";
|
|
5
5
|
import { statusIcon } from "../../utilities/statusIcon.js";
|
|
6
6
|
import { styles } from "./UBadge.styles.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { UElement } from "../UElement.js";
|
|
2
|
-
import __decorate from "../../_virtual/_@oxc-project_runtime@0.
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
3
3
|
import "../icon/UIcon.js";
|
|
4
4
|
import { styles } from "./UBreadcrumb.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { styles } from "./UBreadcrumbItem.styles.js";
|
|
5
5
|
import { html } from "lit";
|
|
6
6
|
import { customElement, property } from "lit/decorators.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../spinner/USpinner.js";
|
|
5
5
|
import { styles } from "./UButton.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { UButton } from "../button/UButton.js";
|
|
5
5
|
import { UIconButton } from "../icon-button/UIconButton.js";
|
|
6
6
|
import { styles } from "./UButtonGroup.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { styles } from "./UCard.styles.js";
|
|
5
5
|
import { html } from "lit";
|
|
6
6
|
import { customElement, property } from "lit/decorators.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
6
6
|
import { Locale } from "../../utilities/Locale.js";
|
|
@@ -1,11 +1,12 @@
|
|
|
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.150.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UFormControlElement } from "../UFormControlElement.js";
|
|
4
4
|
import "../icon/UIcon.js";
|
|
5
5
|
import { Locale } from "../../utilities/Locale.js";
|
|
6
6
|
import { styles } from "./UCheckbox.styles.js";
|
|
7
7
|
import { html } from "lit";
|
|
8
8
|
import { customElement, property, query } from "lit/decorators.js";
|
|
9
|
+
import { ifDefined } from "lit/directives/if-defined.js";
|
|
9
10
|
import { live } from "lit/directives/live.js";
|
|
10
11
|
//#region src/components/checkbox/UCheckbox.ts
|
|
11
12
|
var UCheckbox = class UCheckbox extends UFormControlElement {
|
|
@@ -43,6 +44,7 @@ var UCheckbox = class UCheckbox extends UFormControlElement {
|
|
|
43
44
|
<label class="wrapper" part="wrapper">
|
|
44
45
|
<input part="input"
|
|
45
46
|
type="checkbox"
|
|
47
|
+
aria-label=${ifDefined(this.contentAriaLabel)}
|
|
46
48
|
?disabled=${this.disabled || this.readonly}
|
|
47
49
|
?required=${this.required}
|
|
48
50
|
.checked=${live(this.checked)}
|
|
@@ -55,7 +57,7 @@ var UCheckbox = class UCheckbox extends UFormControlElement {
|
|
|
55
57
|
></u-icon>
|
|
56
58
|
</span>
|
|
57
59
|
<span class="label" part="label">
|
|
58
|
-
<slot>${this.label}</slot>
|
|
60
|
+
<slot @slotchange=${this.handleLabelSlotChange}>${this.label}</slot>
|
|
59
61
|
<span class="required" ?hidden=${!this.required}>*</span>
|
|
60
62
|
</span>
|
|
61
63
|
</label>
|
|
@@ -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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
6
6
|
import "../tooltip/UTooltip.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
6
6
|
import { Locale } from "../../utilities/Locale.js";
|
|
@@ -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.150.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UFormControlElement } from "../UFormControlElement.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.js";
|
|
@@ -203,8 +203,8 @@ var UDatePicker = class UDatePicker extends UFormControlElement {
|
|
|
203
203
|
role="combobox"
|
|
204
204
|
aria-haspopup="dialog"
|
|
205
205
|
aria-expanded=${this.open}
|
|
206
|
-
aria-label=${ifDefined(this.
|
|
207
|
-
aria-description=${ifDefined(this.
|
|
206
|
+
aria-label=${ifDefined(this.resolvedAriaLabel)}
|
|
207
|
+
aria-description=${ifDefined(this.resolvedAriaDescription)}
|
|
208
208
|
aria-controls=${this.calendarId}
|
|
209
209
|
>
|
|
210
210
|
<span class="text-content ${!displayText ? "placeholder" : ""}">${displayText || this.placeholder || ""}</span>
|
|
@@ -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.150.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UOverlayElement } from "../UOverlayElement.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import { styles } from "./UDivider.styles.js";
|
|
5
5
|
import { html } from "lit";
|
|
6
6
|
import { customElement, property } from "lit/decorators.js";
|
|
@@ -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.150.0/helpers/esm/decorateMetadata.js";
|
|
2
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
3
3
|
import { UOverlayElement } from "../UOverlayElement.js";
|
|
4
4
|
import "../button/UButton.js";
|
|
5
5
|
import "../icon/UIcon.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.150.0/helpers/esm/decorateMetadata.js";
|
|
3
|
+
import __decorate from "../../_virtual/_@oxc-project_runtime@0.150.0/helpers/esm/decorate.js";
|
|
4
4
|
import "../icon/UIcon.js";
|
|
5
5
|
import { styles } from "./UExpander.styles.js";
|
|
6
6
|
import { html } from "lit";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PropertyValues } from 'lit';
|
|
1
2
|
import { UElement } from '../UElement.js';
|
|
2
3
|
/**
|
|
3
4
|
* 폼 컨트롤의 공통 레이아웃을 제공하는 필드 컴포넌트입니다.
|
|
@@ -33,6 +34,79 @@ export declare class UField extends UElement {
|
|
|
33
34
|
* 공개 API로도 노출해, 소비자가 임의의 폼 컨트롤(자체 웹 컴포넌트가 아닌 것 포함)을
|
|
34
35
|
* 슬롯에 꽂아도 host의 `.focus()`가 `UInput.focus()`와 같은 계약으로 동작하게 한다. */
|
|
35
36
|
focus(options?: FocusOptions): void;
|
|
37
|
+
private get assignedRoots();
|
|
38
|
+
/**
|
|
39
|
+
* 포커스 대상은 **감싸개 안쪽까지** 본다. 이 패키지의 폼 컨트롤들은 자기 내부 `u-field` 에
|
|
40
|
+
* `<div class="container">` 를 슬롯하고 진짜 `<input>` 은 그 안에 있다 — 최상위만 보면
|
|
41
|
+
* *라이브러리 자신의 정상 사용*이 «컨트롤 없음» 이 된다(첫 판이 실제로 그렇게 오탐했다).
|
|
42
|
+
*/
|
|
43
|
+
private get focusTarget();
|
|
44
|
+
/**
|
|
45
|
+
* 라벨이 가리키는 대상 — `focus()` 와 접근성 이름 부여가 **같은 것**을 골라야 한다.
|
|
46
|
+
*
|
|
47
|
+
* 🔴**`isFocusable()` 만으로는 이 리포의 주된 사용 형태를 통째로 놓친다.** `tabbable` 은
|
|
48
|
+
* 기본적으로 섀도우 루트를 들여다보지 않으므로 `<u-input>` 같은 커스텀 엘리먼트 호스트에
|
|
49
|
+
* `false` 를 돌려준다(실측: `isFocusable(u-input)=false` · `isFocusable(<input>)=true`).
|
|
50
|
+
* ⇒ 종전 `focus()` 는 **네이티브 엘리먼트를 슬롯한 경우에만** 동작했고, 레퍼런스 문서가
|
|
51
|
+
* 가르치는 `u-*` 컨트롤 형태에서는 라벨 클릭이 **조용히 아무 일도 하지 않았다.**
|
|
52
|
+
*
|
|
53
|
+
* ⇒ 판정을 «포커스 가능» 하나가 아니라 **«폼 컨트롤인가»** 로 넓힌다: 네이티브로 포커스
|
|
54
|
+
* 가능하거나, **form-associated 커스텀 엘리먼트**(`static formAssociated = true` — 이
|
|
55
|
+
* 패키지의 `UFormControlElement` 전부가 그렇다)이면 대상이다. 섀도우를 파고들어 안쪽
|
|
56
|
+
* 네이티브 노드를 잡지는 않는다 — 그것은 컨트롤 자신의 API 를 우회하는 것이고, 그쪽이
|
|
57
|
+
* 다시 렌더하면 우리가 얹은 속성이 지워진다.
|
|
58
|
+
*/
|
|
59
|
+
private get controlToName();
|
|
60
|
+
/**
|
|
61
|
+
* 🔴**«이 필드가 이름 줄 컨트롤을 가졌는가» 는 «지금 포커스 가능한가» 와 다른 질문이다 —
|
|
62
|
+
* 그 둘을 한 술어로 답한 것이 결함이었다.**
|
|
63
|
+
*
|
|
64
|
+
* 종전 경고는 `focusTarget`(위)의 부재로 판정했는데, 그 게터는 후보를 `isFocusable()` 로
|
|
65
|
+
* 고르고 **`tabbable` 의 기본 `displayCheck` 는 렌더 여부를 본다.** ⇒ 닫힌 `u-drawer`·
|
|
66
|
+
* 접힌 아코디언·비활성 탭 패널·마법사의 다음 단계처럼 **`display:none` 하위에서 처음
|
|
67
|
+
* 렌더되면 정상 컨트롤이 «없는 것» 이 된다**(실측: `<u-input label="X">` 가 숨겨져 있기만
|
|
68
|
+
* 하면 발화 · 같은 마크업이 보이면 침묵). 그 셋은 이 스택이 겨냥한 LOB 화면형 그 자체다.
|
|
69
|
+
*
|
|
70
|
+
* ⚠**그리고 오탐보다 그 다음이 나쁘다** — `devWarnOnce` 는 키당 한 번이라 오탐이 먼저 나면
|
|
71
|
+
* 뒤이은 **진짜 위반이 조용히 억제된다.** 이 리포가 반복 기록한 *«초록으로 틀린 말»* 이
|
|
72
|
+
* 여기서는 «침묵으로 틀린 말» 이 된다. (키 세분화는 아래 `nameSlottedControl` 참조.)
|
|
73
|
+
*
|
|
74
|
+
* ⇒ 판정은 **구조로만** 한다: form-associated 커스텀 엘리먼트 · 네이티브 폼/포커스 태그 ·
|
|
75
|
+
* `tabindex` · `contenteditable`. **가시성도 `disabled` 도 보지 않는다** — 비활성 입력도
|
|
76
|
+
* 라벨이 가리키는 대상이고, 숨겨진 폼도 구조는 같다.
|
|
77
|
+
* ⚠`focusTarget` 은 **그대로 `isFocusable` 을 쓴다** — `focus()` 위임에서는 «지금 포커스
|
|
78
|
+
* 가능한가» 가 맞는 질문이다. 두 게터가 같은 술어를 공유한 것이 원인이었다.
|
|
79
|
+
*/
|
|
80
|
+
private get hasControlInSubtree();
|
|
81
|
+
protected firstUpdated(changed: PropertyValues): void;
|
|
82
|
+
protected updated(changed: PropertyValues): void;
|
|
83
|
+
/**
|
|
84
|
+
* 🔴**이 컴포넌트의 존재 이유가 «라벨과 컨트롤을 한 칸으로 짝짓는 것»인데, 오랫동안
|
|
85
|
+
* 라벨을 «그리기만» 하고 연결하지 않았다** — 섀도의 `label` 에 `for` 가 없고 슬롯된
|
|
86
|
+
* 컨트롤의 `id`·`aria-label`·`aria-labelledby` 가 전부 빈 채였다 — 라벨을 가진 폼 한 장이
|
|
87
|
+
* 통째로 «이름 없는 입력» 이 된다. 화면은 멀쩡하고 콘솔도 조용해서 **시각 사용자에게는
|
|
88
|
+
* 아무 신호가 없다.**
|
|
89
|
+
*
|
|
90
|
+
* ⚠**`aria-labelledby` 로 잇지 않는다 — 섀도우 경계를 넘지 못한다.** 그 대신 «문자열
|
|
91
|
+
* 복사»를 슬롯 호스트의 `aria-label` 로 얹고, 폼 컨트롤 쪽이 그것을 내부 네이티브
|
|
92
|
+
* 컨트롤로 내려보낸다(`UFormControlElement.resolvedAriaLabel` — `u-button` 이 먼저 채택한
|
|
93
|
+
* 처방을 공통 기반으로 올린 것). 네이티브 엘리먼트를 슬롯한
|
|
94
|
+
* 경우에는 그 호스트가 곧 컨트롤이라 같은 한 줄이 그대로 듣는다.
|
|
95
|
+
*
|
|
96
|
+
* ⚠**자기 이름을 이미 가진 컨트롤은 건드리지 않는다** — 그쪽이 더 구체적이고,
|
|
97
|
+
* 덮으면 눈에 보이는 라벨과 접근성 이름이 어긋난다(WCAG 2.5.3 Label in Name).
|
|
98
|
+
*
|
|
99
|
+
* ⚠**경고 키에 라벨을 넣는다 — 형제 경고들이 이미 그렇게 한다.** 종전 키는 평평한
|
|
100
|
+
* `field-no-control` 하나여서 **페이지당 한 번**만 발화했고, 그래서 위반이 여럿이면
|
|
101
|
+
* 첫 하나만 보인다. `u-icon` 은 `icon:${lib}:${name}`, `u-split-panel` 은
|
|
102
|
+
* `split-panel:${id}` 로 이미 구분된 키를 쓴다 — 그리고 `u-icon` 의 경고가 태어난 계기가
|
|
103
|
+
* 정확히 *"메뉴 30개가 한꺼번에 틀렸는데 신호가 0"* 이었다. 같은 부류에 같은 처방을 한다.
|
|
104
|
+
* (메시지 문안은 그대로다 — 키는 중복 제거 단위일 뿐 공개 표면이 아니다.)
|
|
105
|
+
*/
|
|
106
|
+
private nameSlottedControl;
|
|
107
|
+
/** 우리가 얹은 값인지 소비자가 준 값인지 가르기 위한 표식 — 소비자 값을 덮지 않는다. */
|
|
108
|
+
private lastAppliedLabel?;
|
|
109
|
+
private lastAppliedDescription?;
|
|
36
110
|
private handleLabelClick;
|
|
37
111
|
}
|
|
38
112
|
declare global {
|