@iyulab/components 1.32.0 → 1.33.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 +24 -0
- package/dist/components/button/UButton.d.ts +13 -0
- package/dist/components/button/UButton.js +21 -0
- package/dist/components/radio/URadio.d.ts +5 -0
- package/dist/components/radio/URadio.js +9 -0
- package/dist/components/rating/URating.d.ts +7 -0
- package/dist/components/rating/URating.js +12 -0
- package/package.json +1 -1
- package/skills/iyulab-components/references/components/button.md +17 -0
- package/skills/iyulab-components/references/components/card.md +7 -0
- package/skills/iyulab-components/references/components/drawer.md +6 -0
- package/skills/iyulab-components/references/components/radio.md +9 -0
- package/skills/iyulab-components/references/components/rating.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.33.1] - 2026-08-25
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **`aria-label` set on `<u-button>` never reached the accessibility tree.** The host
|
|
8
|
+
attribute was present, but the actual interactive node exposed to assistive technology is
|
|
9
|
+
the native `<button>`/`<a>` rendered inside the shadow root — ARIA content attributes on a
|
|
10
|
+
shadow host do not cross the shadow boundary to label a descendant. Icon-only buttons using
|
|
11
|
+
`aria-label` for their accessible name were announced as unnamed controls. `render()` now
|
|
12
|
+
forwards the host's `aria-label` onto the internal element, and attribute changes made after
|
|
13
|
+
connection are observed and re-rendered (previously only the initial value would have had
|
|
14
|
+
any chance of being picked up).
|
|
15
|
+
|
|
16
|
+
## [1.33.0] - 2026-08-21
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`u-radio` and `u-rating` now support `.focus()`/`.blur()` on the host element too**,
|
|
21
|
+
completing the same contract added to the rest of the form controls in `1.32.0`. Both are
|
|
22
|
+
option/symbol *groups* rather than a single target, so `.focus()` delegates to the first
|
|
23
|
+
option (`u-radio`) or the first symbol (`u-rating`) regardless of the current selection —
|
|
24
|
+
the same "one fixed delegation target" contract every other control in this library now
|
|
25
|
+
shares, rather than adding value-aware branching.
|
|
26
|
+
|
|
3
27
|
## [1.32.0] - 2026-08-21
|
|
4
28
|
|
|
5
29
|
### Added
|
|
@@ -93,6 +93,19 @@ export declare class UButton extends UElement {
|
|
|
93
93
|
get form(): HTMLFormElement | null;
|
|
94
94
|
connectedCallback(): void;
|
|
95
95
|
disconnectedCallback(): void;
|
|
96
|
+
/**
|
|
97
|
+
* 호스트에 세팅된 `aria-label`은 실제 접근 가능한(포커스 대상) 엘리먼트가 아니라 —
|
|
98
|
+
* 그 안쪽 shadow DOM 의 네이티브 `<a>`/`<button>`이다. 섀도우 경계를 넘지 않으므로
|
|
99
|
+
* 접근성 트리에 자동 반영되지 않는다(docket #75 실측 — 속성은 붙어 있는데
|
|
100
|
+
* 접근성 이름이 비어 있음). `render()`가 이 값을 읽어 내부 엘리먼트에 직접 옮긴다.
|
|
101
|
+
*
|
|
102
|
+
* `aria-label`은 Lit 리액티브 프로퍼티로 선언돼 있지 않아 `observedAttributes`에
|
|
103
|
+
* 없다 — 그 목록에 없는 속성은 `attributeChangedCallback` 자체가 호출되지 않는다
|
|
104
|
+
* (커스텀 엘리먼트 표준 동작). 초기 렌더는 되지만 연결 후 동적 변경은 반영되지
|
|
105
|
+
* 않았다 — 목록에 명시적으로 추가해야 한다.
|
|
106
|
+
*/
|
|
107
|
+
static get observedAttributes(): string[];
|
|
108
|
+
attributeChangedCallback(name: string, old: string | null, value: string | null): void;
|
|
96
109
|
render(): TemplateResult<1>;
|
|
97
110
|
private renderContent;
|
|
98
111
|
private renderMask;
|
|
@@ -53,9 +53,29 @@ var UButton = class UButton extends UElement {
|
|
|
53
53
|
this.removeEventListener("click", this.handleClick);
|
|
54
54
|
super.disconnectedCallback();
|
|
55
55
|
}
|
|
56
|
+
/**
|
|
57
|
+
* 호스트에 세팅된 `aria-label`은 실제 접근 가능한(포커스 대상) 엘리먼트가 아니라 —
|
|
58
|
+
* 그 안쪽 shadow DOM 의 네이티브 `<a>`/`<button>`이다. 섀도우 경계를 넘지 않으므로
|
|
59
|
+
* 접근성 트리에 자동 반영되지 않는다(docket #75 실측 — 속성은 붙어 있는데
|
|
60
|
+
* 접근성 이름이 비어 있음). `render()`가 이 값을 읽어 내부 엘리먼트에 직접 옮긴다.
|
|
61
|
+
*
|
|
62
|
+
* `aria-label`은 Lit 리액티브 프로퍼티로 선언돼 있지 않아 `observedAttributes`에
|
|
63
|
+
* 없다 — 그 목록에 없는 속성은 `attributeChangedCallback` 자체가 호출되지 않는다
|
|
64
|
+
* (커스텀 엘리먼트 표준 동작). 초기 렌더는 되지만 연결 후 동적 변경은 반영되지
|
|
65
|
+
* 않았다 — 목록에 명시적으로 추가해야 한다.
|
|
66
|
+
*/
|
|
67
|
+
static get observedAttributes() {
|
|
68
|
+
return [...super.observedAttributes, "aria-label"];
|
|
69
|
+
}
|
|
70
|
+
attributeChangedCallback(name, old, value) {
|
|
71
|
+
super.attributeChangedCallback(name, old, value);
|
|
72
|
+
if (name === "aria-label") this.requestUpdate();
|
|
73
|
+
}
|
|
56
74
|
render() {
|
|
75
|
+
const ariaLabel = this.getAttribute("aria-label") ?? void 0;
|
|
57
76
|
if (this.href) return html`
|
|
58
77
|
<a part="link"
|
|
78
|
+
aria-label=${ifDefined(ariaLabel)}
|
|
59
79
|
?disabled=${this.disabled || this.loading}
|
|
60
80
|
tabindex=${this.disabled || this.loading ? -1 : 0}
|
|
61
81
|
href=${ifDefined(this.disabled || this.loading ? void 0 : this.href)}
|
|
@@ -69,6 +89,7 @@ var UButton = class UButton extends UElement {
|
|
|
69
89
|
`;
|
|
70
90
|
return html`
|
|
71
91
|
<button part="button"
|
|
92
|
+
aria-label=${ifDefined(ariaLabel)}
|
|
72
93
|
type=${this.type}
|
|
73
94
|
?disabled=${this.disabled || this.loading}
|
|
74
95
|
>
|
|
@@ -31,6 +31,11 @@ export declare class URadio extends UFormControlElement<string> {
|
|
|
31
31
|
render(): import('lit-html').TemplateResult<1>;
|
|
32
32
|
protected setValidity(): void;
|
|
33
33
|
reset(): void;
|
|
34
|
+
/** 그룹의 첫 포커스 가능 옵션으로 위임한다(선택된 값과 무관 — 나머지 폼 컨트롤과
|
|
35
|
+
* 같은 "위임 대상이 하나로 고정된 단순 계약"을 유지한다). 옵션 자신이 host에
|
|
36
|
+
* 실제 tabindex를 갖는 커스텀 엘리먼트라 `UOption.focus()`가 이미 동작한다. */
|
|
37
|
+
focus(options?: FocusOptions): void;
|
|
38
|
+
blur(): void;
|
|
34
39
|
private setup;
|
|
35
40
|
private cleanup;
|
|
36
41
|
private onChangeValue;
|
|
@@ -108,6 +108,15 @@ var URadio = class URadio extends UFormControlElement {
|
|
|
108
108
|
this.value = void 0;
|
|
109
109
|
this.invalid = false;
|
|
110
110
|
}
|
|
111
|
+
/** 그룹의 첫 포커스 가능 옵션으로 위임한다(선택된 값과 무관 — 나머지 폼 컨트롤과
|
|
112
|
+
* 같은 "위임 대상이 하나로 고정된 단순 계약"을 유지한다). 옵션 자신이 host에
|
|
113
|
+
* 실제 tabindex를 갖는 커스텀 엘리먼트라 `UOption.focus()`가 이미 동작한다. */
|
|
114
|
+
focus(options) {
|
|
115
|
+
this.options.find((o) => !o.disabled)?.focus(options);
|
|
116
|
+
}
|
|
117
|
+
blur() {
|
|
118
|
+
(this.shadowRoot?.activeElement)?.blur();
|
|
119
|
+
}
|
|
111
120
|
setup(options) {
|
|
112
121
|
for (const option of options) {
|
|
113
122
|
option.removeEventListener("click", this.handleOptionClick);
|
|
@@ -37,6 +37,13 @@ export declare class URating extends UFormControlElement<number> {
|
|
|
37
37
|
protected setValidity(): void;
|
|
38
38
|
private isStepMismatch;
|
|
39
39
|
reset(): void;
|
|
40
|
+
/** 첫(최저 점수) 심볼로 위임한다(선택된 값과 무관 — 나머지 폼 컨트롤과 같은
|
|
41
|
+
* "위임 대상이 하나로 고정된 단순 계약"을 유지한다). 심볼은 shadow DOM 안의
|
|
42
|
+
* `<span>`이라 disabled/readonly일 때 `tabindex="-1"`(=`!interactive`)이고,
|
|
43
|
+
* 다른 컴포넌트의 `.container`/thumb와 같은 이유로 프로그램적 focus는 여전히
|
|
44
|
+
* 통과하므로 직접 가드한다. */
|
|
45
|
+
focus(options?: FocusOptions): void;
|
|
46
|
+
blur(): void;
|
|
40
47
|
private onChangeValue;
|
|
41
48
|
/** 사용자 상호작용으로 값이 바뀐 경로에서만 호출한다 — 프로그램적 value 세팅은
|
|
42
49
|
* 네이티브 폼 컨트롤과 동일하게 change를 발화하지 않는다.
|
|
@@ -175,6 +175,18 @@ var URating = class URating extends UFormControlElement {
|
|
|
175
175
|
this.value = 0;
|
|
176
176
|
this.invalid = false;
|
|
177
177
|
}
|
|
178
|
+
/** 첫(최저 점수) 심볼로 위임한다(선택된 값과 무관 — 나머지 폼 컨트롤과 같은
|
|
179
|
+
* "위임 대상이 하나로 고정된 단순 계약"을 유지한다). 심볼은 shadow DOM 안의
|
|
180
|
+
* `<span>`이라 disabled/readonly일 때 `tabindex="-1"`(=`!interactive`)이고,
|
|
181
|
+
* 다른 컴포넌트의 `.container`/thumb와 같은 이유로 프로그램적 focus는 여전히
|
|
182
|
+
* 통과하므로 직접 가드한다. */
|
|
183
|
+
focus(options) {
|
|
184
|
+
if (!this.interactive) return;
|
|
185
|
+
this.renderRoot.querySelector(".symbol")?.focus(options);
|
|
186
|
+
}
|
|
187
|
+
blur() {
|
|
188
|
+
(this.shadowRoot?.activeElement)?.blur();
|
|
189
|
+
}
|
|
178
190
|
onChangeValue() {
|
|
179
191
|
this.buffer = -1;
|
|
180
192
|
this.internals?.setFormValue(this.value?.toString() || "");
|
package/package.json
CHANGED
|
@@ -72,3 +72,20 @@ Versatile button with multiple visual variants. Renders as an `<a>` element when
|
|
|
72
72
|
| `link` | Inner `<a>` element (when `href` is set) |
|
|
73
73
|
| `content` | Content wrapper (prefix + label + suffix) |
|
|
74
74
|
| `mask` | Loading overlay mask |
|
|
75
|
+
|
|
76
|
+
## CSS Custom Properties
|
|
77
|
+
|
|
78
|
+
| Property | Description |
|
|
79
|
+
|----------|-------------|
|
|
80
|
+
| `--u-primary-color` | Base color when `color="neutral"` — set it and hover/active/surface tones auto-derive via `color-mix()` |
|
|
81
|
+
| `--btn-color` | The button's **fill** color. Every derived token below is `color-mix()`'d from this one — usually the only one you need to override |
|
|
82
|
+
| `--btn-txt-color` | Text color on the fill, read by `variant="solid"` (default `#fff`, or `--u-{role}-txt-color` when a semantic `color` is set) |
|
|
83
|
+
| `--btn-color-strong` | Text color on the surrounding page background, read by `variant="link"` — opposite contrast need from the fill, so it's a separate token (default: same as `--btn-color`, or `--u-{role}-color-strong` for a semantic `color`) |
|
|
84
|
+
| `--btn-color-hover` / `--btn-color-active` | `solid` background hover/active (default: `--btn-color` at 85%/70% + black) |
|
|
85
|
+
| `--btn-color-surface` / `-hover` / `-active` | `surface` background states (default: `--btn-color` at 12%/22%/32%) |
|
|
86
|
+
| `--btn-color-border` / `-hover` / `-active` | Border states (default: `--btn-color` at 45%/60%/75%) |
|
|
87
|
+
| `--btn-color-outline-hover` / `-active` | `outlined`/`ghost` background hover/active (default: 6%/12%) |
|
|
88
|
+
| `--btn-color-strong-hover` / `-active` | `link` text hover/active — the role value itself doesn't move; hover adds an underline instead (default: `--btn-color-strong` at 85%/70% + black) |
|
|
89
|
+
| `--btn-border-color` | Border color read by variant/hover/active rules (default: `transparent`) |
|
|
90
|
+
| `--btn-padding-block` | Vertical inner padding (default `0.5em`) |
|
|
91
|
+
| `--btn-padding-inline` | Horizontal inner padding (default `1em`, `0` for `variant="link"`) — overriding it does not change the min-height, which is derived from `--btn-padding-block` instead |
|
|
@@ -51,3 +51,10 @@ Content card with optional media, header, body, and footer sections.
|
|
|
51
51
|
| `header` | Header slot wrapper |
|
|
52
52
|
| `body` | Body (default slot) wrapper |
|
|
53
53
|
| `footer` | Footer slot wrapper |
|
|
54
|
+
|
|
55
|
+
## CSS Custom Properties
|
|
56
|
+
|
|
57
|
+
| Property | Description |
|
|
58
|
+
|----------|-------------|
|
|
59
|
+
| `--card-border-width` | Border thickness (`0` when `borderless`) |
|
|
60
|
+
| `--card-border-color` | Border color |
|
|
@@ -62,6 +62,12 @@ Side panel that slides in from any screen edge. Extends `UOverlayElement` (focus
|
|
|
62
62
|
| `body` | Body area |
|
|
63
63
|
| `close-btn` | Close button |
|
|
64
64
|
|
|
65
|
+
## CSS Custom Properties
|
|
66
|
+
|
|
67
|
+
| Property | Description |
|
|
68
|
+
|----------|-------------|
|
|
69
|
+
| `--drawer-size` | Panel size along the slide axis — width for `placement="left"`/`"right"` (default `28rem`), height for `"top"`/`"bottom"` (default `16rem`). Auto-shrinks to `max-width`/`max-height: 100%` on narrow viewports |
|
|
70
|
+
|
|
65
71
|
---
|
|
66
72
|
|
|
67
73
|
## Edit-panel pattern
|
|
@@ -58,6 +58,8 @@ Radio group built from `u-option` children. Form-associated.
|
|
|
58
58
|
|--------|-------------|
|
|
59
59
|
| `validate()` | Validate; sets `invalid` |
|
|
60
60
|
| `reset()` | Reset selection |
|
|
61
|
+
| `focus(options?)` | Focus the first option (regardless of selection) |
|
|
62
|
+
| `blur()` | Blur the currently focused option, if any |
|
|
61
63
|
|
|
62
64
|
## CSS Parts
|
|
63
65
|
|
|
@@ -65,3 +67,10 @@ Radio group built from `u-option` children. Form-associated.
|
|
|
65
67
|
|------|-------------|
|
|
66
68
|
| `field` | Outer field wrapper |
|
|
67
69
|
| `container` | Options container |
|
|
70
|
+
|
|
71
|
+
## CSS Custom Properties
|
|
72
|
+
|
|
73
|
+
| Property | Description |
|
|
74
|
+
|----------|-------------|
|
|
75
|
+
| `--radio-color` | Base color of the selected state (default `--u-primary-color`) |
|
|
76
|
+
| `--radio-color-active` | Selected-state active tone (default `--radio-color` at 85% + black) |
|
|
@@ -56,6 +56,8 @@ Star/custom-symbol rating input. Supports fractional precision and custom symbol
|
|
|
56
56
|
|--------|-------------|
|
|
57
57
|
| `validate()` | Validate; sets `invalid` |
|
|
58
58
|
| `reset()` | Reset value |
|
|
59
|
+
| `focus(options?)` | Focus the first symbol (regardless of value) |
|
|
60
|
+
| `blur()` | Blur the currently focused symbol, if any |
|
|
59
61
|
|
|
60
62
|
## CSS Parts
|
|
61
63
|
|