@iyulab/components 1.31.0 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/components/checkbox/UCheckbox.d.ts +2 -0
- package/dist/components/checkbox/UCheckbox.js +6 -0
- package/dist/components/date-picker/UDatePicker.d.ts +5 -0
- package/dist/components/date-picker/UDatePicker.js +10 -0
- package/dist/components/field/UField.d.ts +4 -0
- package/dist/components/field/UField.js +11 -5
- package/dist/components/select/USelect.d.ts +5 -0
- package/dist/components/select/USelect.js +10 -0
- package/dist/components/slider/USlider.d.ts +8 -0
- package/dist/components/slider/USlider.js +11 -0
- package/dist/components/switch/USwitch.d.ts +2 -0
- package/dist/components/switch/USwitch.js +6 -0
- package/dist/components/textarea/UTextarea.d.ts +2 -0
- package/dist/components/textarea/UTextarea.js +6 -0
- package/package.json +1 -1
- package/skills/iyulab-components/references/components/checkbox.md +2 -0
- package/skills/iyulab-components/references/components/date-picker.md +2 -0
- package/skills/iyulab-components/references/components/field.md +6 -0
- package/skills/iyulab-components/references/components/select.md +2 -0
- package/skills/iyulab-components/references/components/slider.md +2 -0
- package/skills/iyulab-components/references/components/switch.md +2 -0
- package/skills/iyulab-components/references/components/textarea.md +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.32.0] - 2026-08-21
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`u-select`, `u-date-picker`, `u-textarea`, `u-checkbox`, `u-switch`, and `u-slider` now
|
|
8
|
+
support `.focus()`/`.blur()` on the host element**, matching `u-input`'s existing contract.
|
|
9
|
+
Previously only `u-input` delegated `.focus()` to its actual interactive element; calling
|
|
10
|
+
`.focus()` on any of the others was a silent no-op, since the host element itself carries no
|
|
11
|
+
`tabindex` — only an internal element does (the container, the native `<input>`/`<textarea>`,
|
|
12
|
+
or, for `u-slider`, the first thumb). Any consumer building a generic "scroll to and focus
|
|
13
|
+
the first invalid field" flow now gets consistent behavior across every form control this
|
|
14
|
+
library ships, instead of having to special-case each one.
|
|
15
|
+
- **`u-field` now exposes `.focus()` publicly**, delegating to the first focusable slotted
|
|
16
|
+
child — the same lookup its label-click handler already used internally, now available to
|
|
17
|
+
consumers slotting an arbitrary form control (not one of this library's own) directly into
|
|
18
|
+
`<u-field>`.
|
|
19
|
+
|
|
3
20
|
## [1.31.0] - 2026-08-20
|
|
4
21
|
|
|
5
22
|
### Added
|
|
@@ -42,6 +42,8 @@ export declare class UCheckbox extends UFormControlElement<string> {
|
|
|
42
42
|
render(): import('lit-html').TemplateResult<1>;
|
|
43
43
|
protected setValidity(): void;
|
|
44
44
|
reset(): void;
|
|
45
|
+
focus(options?: FocusOptions): void;
|
|
46
|
+
blur(): void;
|
|
45
47
|
private handleInputChange;
|
|
46
48
|
}
|
|
47
49
|
declare global {
|
|
@@ -74,6 +74,12 @@ var UCheckbox = class UCheckbox extends UFormControlElement {
|
|
|
74
74
|
this.indeterminate = false;
|
|
75
75
|
this.invalid = false;
|
|
76
76
|
}
|
|
77
|
+
focus(options) {
|
|
78
|
+
this.inputEl?.focus(options);
|
|
79
|
+
}
|
|
80
|
+
blur() {
|
|
81
|
+
this.inputEl?.blur();
|
|
82
|
+
}
|
|
77
83
|
};
|
|
78
84
|
__decorate([property({
|
|
79
85
|
type: String,
|
|
@@ -66,6 +66,11 @@ export declare class UDatePicker extends UFormControlElement<string> {
|
|
|
66
66
|
private emitChange;
|
|
67
67
|
protected setValidity(): void;
|
|
68
68
|
reset(): void;
|
|
69
|
+
/** `.container`는 div라 네이티브 `disabled`가 없다 — disabled일 때 `tabindex="-1"`로만
|
|
70
|
+
* Tab 순서에서 빠지고 프로그램적 `.focus()`는 여전히 통과하므로, `UInput.focus()`가
|
|
71
|
+
* 네이티브 `disabled` `<input>`에서 얻는 것과 같은 no-op을 여기서 직접 재현한다. */
|
|
72
|
+
focus(options?: FocusOptions): void;
|
|
73
|
+
blur(): void;
|
|
69
74
|
}
|
|
70
75
|
declare global {
|
|
71
76
|
interface HTMLElementTagNameMap {
|
|
@@ -297,6 +297,16 @@ var UDatePicker = class UDatePicker extends UFormControlElement {
|
|
|
297
297
|
this.value = void 0;
|
|
298
298
|
this.invalid = false;
|
|
299
299
|
}
|
|
300
|
+
/** `.container`는 div라 네이티브 `disabled`가 없다 — disabled일 때 `tabindex="-1"`로만
|
|
301
|
+
* Tab 순서에서 빠지고 프로그램적 `.focus()`는 여전히 통과하므로, `UInput.focus()`가
|
|
302
|
+
* 네이티브 `disabled` `<input>`에서 얻는 것과 같은 no-op을 여기서 직접 재현한다. */
|
|
303
|
+
focus(options) {
|
|
304
|
+
if (this.disabled) return;
|
|
305
|
+
this.containerEl?.focus(options);
|
|
306
|
+
}
|
|
307
|
+
blur() {
|
|
308
|
+
this.containerEl?.blur();
|
|
309
|
+
}
|
|
300
310
|
};
|
|
301
311
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UDatePicker.prototype, "min", void 0);
|
|
302
312
|
__decorate([property({ type: String }), __decorateMetadata("design:type", String)], UDatePicker.prototype, "max", void 0);
|
|
@@ -29,6 +29,10 @@ export declare class UField extends UElement {
|
|
|
29
29
|
validationMessage?: string;
|
|
30
30
|
render(): import('lit-html').TemplateResult<1>;
|
|
31
31
|
private renderFooter;
|
|
32
|
+
/** 슬롯에 꽂힌 첫 포커스 가능 자식으로 위임한다 — 라벨 클릭과 같은 대상 탐색 로직을
|
|
33
|
+
* 공개 API로도 노출해, 소비자가 임의의 폼 컨트롤(자체 웹 컴포넌트가 아닌 것 포함)을
|
|
34
|
+
* 슬롯에 꽂아도 host의 `.focus()`가 `UInput.focus()`와 같은 계약으로 동작하게 한다. */
|
|
35
|
+
focus(options?: FocusOptions): void;
|
|
32
36
|
private handleLabelClick;
|
|
33
37
|
}
|
|
34
38
|
declare global {
|
|
@@ -13,11 +13,7 @@ var UField = class UField extends UElement {
|
|
|
13
13
|
this.required = false;
|
|
14
14
|
this.invalid = false;
|
|
15
15
|
this.handleLabelClick = () => {
|
|
16
|
-
|
|
17
|
-
for (const node of nodes) if (isFocusable(node)) {
|
|
18
|
-
node.focus();
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
16
|
+
this.focus();
|
|
21
17
|
};
|
|
22
18
|
}
|
|
23
19
|
static {
|
|
@@ -43,6 +39,16 @@ var UField = class UField extends UElement {
|
|
|
43
39
|
if (!message) return nothing;
|
|
44
40
|
return html`<div class="footer">${message}</div>`;
|
|
45
41
|
}
|
|
42
|
+
/** 슬롯에 꽂힌 첫 포커스 가능 자식으로 위임한다 — 라벨 클릭과 같은 대상 탐색 로직을
|
|
43
|
+
* 공개 API로도 노출해, 소비자가 임의의 폼 컨트롤(자체 웹 컴포넌트가 아닌 것 포함)을
|
|
44
|
+
* 슬롯에 꽂아도 host의 `.focus()`가 `UInput.focus()`와 같은 계약으로 동작하게 한다. */
|
|
45
|
+
focus(options) {
|
|
46
|
+
const nodes = (this.shadowRoot?.querySelector("slot:not([name])"))?.assignedElements({ flatten: true }) || [];
|
|
47
|
+
for (const node of nodes) if (isFocusable(node)) {
|
|
48
|
+
node.focus(options);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
46
52
|
};
|
|
47
53
|
__decorate([property({
|
|
48
54
|
type: Boolean,
|
|
@@ -62,6 +62,11 @@ export declare class USelect extends UFormControlElement<string | string[]> {
|
|
|
62
62
|
private renderContent;
|
|
63
63
|
protected setValidity(): void;
|
|
64
64
|
reset(): void;
|
|
65
|
+
/** `.container`는 div라 네이티브 `disabled`가 없다 — disabled일 때 `tabindex="-1"`로만
|
|
66
|
+
* Tab 순서에서 빠지고 프로그램적 `.focus()`는 여전히 통과하므로, `UInput.focus()`가
|
|
67
|
+
* 네이티브 `disabled` `<input>`에서 얻는 것과 같은 no-op을 여기서 직접 재현한다. */
|
|
68
|
+
focus(options?: FocusOptions): void;
|
|
69
|
+
blur(): void;
|
|
65
70
|
private setup;
|
|
66
71
|
private cleanup;
|
|
67
72
|
private onChangeValue;
|
|
@@ -265,6 +265,16 @@ var USelect = class USelect extends UFormControlElement {
|
|
|
265
265
|
this.value = this.multiple ? [] : "";
|
|
266
266
|
this.invalid = false;
|
|
267
267
|
}
|
|
268
|
+
/** `.container`는 div라 네이티브 `disabled`가 없다 — disabled일 때 `tabindex="-1"`로만
|
|
269
|
+
* Tab 순서에서 빠지고 프로그램적 `.focus()`는 여전히 통과하므로, `UInput.focus()`가
|
|
270
|
+
* 네이티브 `disabled` `<input>`에서 얻는 것과 같은 no-op을 여기서 직접 재현한다. */
|
|
271
|
+
focus(options) {
|
|
272
|
+
if (this.disabled) return;
|
|
273
|
+
this.containerEl?.focus(options);
|
|
274
|
+
}
|
|
275
|
+
blur() {
|
|
276
|
+
this.containerEl?.blur();
|
|
277
|
+
}
|
|
268
278
|
setup(options) {
|
|
269
279
|
for (const option of options) {
|
|
270
280
|
option.removeEventListener("click", this.handleOptionClick);
|
|
@@ -60,6 +60,9 @@ export declare class USlider extends UFormControlElement<number | number[]> {
|
|
|
60
60
|
private dragging;
|
|
61
61
|
private trackEl;
|
|
62
62
|
private containerEl?;
|
|
63
|
+
/** `.container`는 포인터 이벤트 좌표 계산용 래퍼일 뿐 tabindex가 없다 — 실제
|
|
64
|
+
* 포커스 가능한 대상은 min thumb(단일 모드의 유일한 thumb, range 모드의 시작값)다. */
|
|
65
|
+
private minThumbEl?;
|
|
63
66
|
protected shouldValidate(changed: PropertyValues): boolean;
|
|
64
67
|
get valueAsNumber(): number;
|
|
65
68
|
get valueAsArray(): number[];
|
|
@@ -74,6 +77,11 @@ export declare class USlider extends UFormControlElement<number | number[]> {
|
|
|
74
77
|
render(): TemplateResult<1>;
|
|
75
78
|
protected setValidity(): void;
|
|
76
79
|
reset(): void;
|
|
80
|
+
/** thumb는 div라 네이티브 `disabled`가 없다 — disabled일 때 `tabindex="-1"`로만 Tab
|
|
81
|
+
* 순서에서 빠지고 프로그램적 `.focus()`는 여전히 통과하므로, `UInput.focus()`가
|
|
82
|
+
* 네이티브 `disabled` `<input>`에서 얻는 것과 같은 no-op을 여기서 직접 재현한다. */
|
|
83
|
+
focus(options?: FocusOptions): void;
|
|
84
|
+
blur(): void;
|
|
77
85
|
private onChangeValue;
|
|
78
86
|
/** 사용자 상호작용으로 값이 확정된 경로에서만 호출한다 — 프로그램적 value 세팅은
|
|
79
87
|
* 네이티브 폼 컨트롤과 동일하게 change를 발화하지 않는다. */
|
|
@@ -200,6 +200,16 @@ var USlider = class USlider extends UFormControlElement {
|
|
|
200
200
|
else this.value = this.offset ?? this.min;
|
|
201
201
|
this.invalid = false;
|
|
202
202
|
}
|
|
203
|
+
/** thumb는 div라 네이티브 `disabled`가 없다 — disabled일 때 `tabindex="-1"`로만 Tab
|
|
204
|
+
* 순서에서 빠지고 프로그램적 `.focus()`는 여전히 통과하므로, `UInput.focus()`가
|
|
205
|
+
* 네이티브 `disabled` `<input>`에서 얻는 것과 같은 no-op을 여기서 직접 재현한다. */
|
|
206
|
+
focus(options) {
|
|
207
|
+
if (this.disabled) return;
|
|
208
|
+
this.minThumbEl?.focus(options);
|
|
209
|
+
}
|
|
210
|
+
blur() {
|
|
211
|
+
this.minThumbEl?.blur();
|
|
212
|
+
}
|
|
203
213
|
onChangeValue() {
|
|
204
214
|
if (Array.isArray(this.value)) this.value = [this.snap(this.value[0]), this.snap(this.value[1])];
|
|
205
215
|
else if (typeof this.value === "number") this.value = this.snap(this.value);
|
|
@@ -300,6 +310,7 @@ __decorate([property({ converter: { fromAttribute: (value) => {
|
|
|
300
310
|
__decorate([state(), __decorateMetadata("design:type", Object)], USlider.prototype, "dragging", void 0);
|
|
301
311
|
__decorate([query(".track"), __decorateMetadata("design:type", typeof HTMLElement === "undefined" ? Object : HTMLElement)], USlider.prototype, "trackEl", void 0);
|
|
302
312
|
__decorate([query(".container"), __decorateMetadata("design:type", typeof HTMLElement === "undefined" ? Object : HTMLElement)], USlider.prototype, "containerEl", void 0);
|
|
313
|
+
__decorate([query(".thumb[data-thumb=\"min\"]"), __decorateMetadata("design:type", typeof HTMLElement === "undefined" ? Object : HTMLElement)], USlider.prototype, "minThumbEl", void 0);
|
|
303
314
|
USlider = __decorate([customElement("u-slider")], USlider);
|
|
304
315
|
//#endregion
|
|
305
316
|
export { USlider };
|
|
@@ -41,6 +41,8 @@ export declare class USwitch extends UFormControlElement<string> {
|
|
|
41
41
|
render(): import('lit-html').TemplateResult<1>;
|
|
42
42
|
protected setValidity(): void;
|
|
43
43
|
reset(): void;
|
|
44
|
+
focus(options?: FocusOptions): void;
|
|
45
|
+
blur(): void;
|
|
44
46
|
private handleInputChange;
|
|
45
47
|
}
|
|
46
48
|
declare global {
|
|
@@ -78,6 +78,12 @@ var USwitch = class USwitch extends UFormControlElement {
|
|
|
78
78
|
this.checked = false;
|
|
79
79
|
this.invalid = false;
|
|
80
80
|
}
|
|
81
|
+
focus(options) {
|
|
82
|
+
this.inputEl?.focus(options);
|
|
83
|
+
}
|
|
84
|
+
blur() {
|
|
85
|
+
this.inputEl?.blur();
|
|
86
|
+
}
|
|
81
87
|
};
|
|
82
88
|
__decorate([property({
|
|
83
89
|
type: Boolean,
|
|
@@ -53,6 +53,8 @@ export declare class UTextarea extends UFormControlElement<string> {
|
|
|
53
53
|
render(): import('lit-html').TemplateResult<1>;
|
|
54
54
|
protected setValidity(): void;
|
|
55
55
|
reset(): void;
|
|
56
|
+
focus(options?: FocusOptions): void;
|
|
57
|
+
blur(): void;
|
|
56
58
|
private resizeTextarea;
|
|
57
59
|
private handleTextareaInput;
|
|
58
60
|
private handleTextareaChange;
|
|
@@ -106,6 +106,12 @@ var UTextarea = class UTextarea extends UFormControlElement {
|
|
|
106
106
|
this.value = void 0;
|
|
107
107
|
this.invalid = false;
|
|
108
108
|
}
|
|
109
|
+
focus(options) {
|
|
110
|
+
this.textareaEl?.focus(options);
|
|
111
|
+
}
|
|
112
|
+
blur() {
|
|
113
|
+
this.textareaEl?.blur();
|
|
114
|
+
}
|
|
109
115
|
resizeTextarea() {
|
|
110
116
|
const textarea = this.textareaEl;
|
|
111
117
|
if (!textarea) return;
|
package/package.json
CHANGED
|
@@ -50,6 +50,8 @@ Checkbox with `indeterminate` state support. Form-associated (`formAssociated =
|
|
|
50
50
|
|--------|---------|-------------|
|
|
51
51
|
| `validate()` | `boolean` | Run validation; sets `invalid` |
|
|
52
52
|
| `reset()` | `void` | Clear value and validation state |
|
|
53
|
+
| `focus(options?)` | `void` | Focus the checkbox input |
|
|
54
|
+
| `blur()` | `void` | Blur the checkbox input |
|
|
53
55
|
|
|
54
56
|
## CSS Parts
|
|
55
57
|
|
|
@@ -49,6 +49,8 @@ Single-date selection with a popover calendar. The value follows the same conven
|
|
|
49
49
|
|--------|--------------|
|
|
50
50
|
| `validate()` | Validate; sets `invalid` |
|
|
51
51
|
| `reset()` | Reset value |
|
|
52
|
+
| `focus(options?)` | Focus the trigger |
|
|
53
|
+
| `blur()` | Blur the trigger |
|
|
52
54
|
|
|
53
55
|
## CSS Parts
|
|
54
56
|
|
|
@@ -40,3 +40,9 @@ Layout wrapper for form controls. Renders label, required marker, description te
|
|
|
40
40
|
| `required` | `boolean` | `false` | ✓ | Show required marker |
|
|
41
41
|
| `invalid` | `boolean` | `false` | ✓ | Show validation error state |
|
|
42
42
|
| `disabled` | `boolean` | `false` | ✓ | Disable state forwarding |
|
|
43
|
+
|
|
44
|
+
## Methods
|
|
45
|
+
|
|
46
|
+
| Method | Description |
|
|
47
|
+
|--------|-------------|
|
|
48
|
+
| `focus(options?)` | Focus the first focusable slotted child |
|
|
@@ -66,6 +66,8 @@ Dropdown select with single or multiple selection, search, and clear support. Fo
|
|
|
66
66
|
|--------|-------------|
|
|
67
67
|
| `validate()` | Validate; sets `invalid` |
|
|
68
68
|
| `reset()` | Reset value |
|
|
69
|
+
| `focus(options?)` | Focus the trigger |
|
|
70
|
+
| `blur()` | Blur the trigger |
|
|
69
71
|
|
|
70
72
|
## CSS Parts
|
|
71
73
|
|
|
@@ -60,6 +60,8 @@ Range slider. Single-thumb or dual-thumb (range) mode. Supports marks, value dis
|
|
|
60
60
|
|--------|-------------|
|
|
61
61
|
| `validate()` | Validate; sets `invalid` |
|
|
62
62
|
| `reset()` | Reset value |
|
|
63
|
+
| `focus(options?)` | Focus the first (min) thumb |
|
|
64
|
+
| `blur()` | Blur the first (min) thumb |
|
|
63
65
|
|
|
64
66
|
## CSS Parts
|
|
65
67
|
|
|
@@ -55,6 +55,8 @@ Toggle switch (on/off). Supports custom track and thumb content via slots. Form-
|
|
|
55
55
|
|--------|-------------|
|
|
56
56
|
| `validate()` | Validate; sets `invalid` |
|
|
57
57
|
| `reset()` | Reset state |
|
|
58
|
+
| `focus(options?)` | Focus the switch input |
|
|
59
|
+
| `blur()` | Blur the switch input |
|
|
58
60
|
|
|
59
61
|
## CSS Parts
|
|
60
62
|
|
|
@@ -61,6 +61,8 @@ Multi-line text input with auto-resize and optional character counter. Form-asso
|
|
|
61
61
|
|--------|-------------|
|
|
62
62
|
| `validate()` | Validate; sets `invalid` |
|
|
63
63
|
| `reset()` | Reset value |
|
|
64
|
+
| `focus(options?)` | Focus the textarea |
|
|
65
|
+
| `blur()` | Blur the textarea |
|
|
64
66
|
|
|
65
67
|
## CSS Parts
|
|
66
68
|
|